diff --git a/.gitignore b/.gitignore index 72ab296f63..6c3cd331f6 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ *.swp *.iml */*.iml +*.ipr +*.iws bin/ build/ @@ -22,7 +24,7 @@ pg/*.bak pg/*.bpg pg/*.txt -.idea +.idea/ codesigning.jks diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 832bffa0fc..f24b068b93 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -55,6 +55,8 @@ test-code: publish: stage: publish + rules: + - if: $CI_COMMIT_BRANCH == "main" script: - "apply_overlay bc-java-pub ./" - "ecr_login" @@ -63,5 +65,7 @@ publish: spongycastle: stage: "sync" + rules: + - if: $CI_COMMIT_BRANCH == "main" script: - "syncpongy.sh" diff --git a/CONTRIBUTORS.html b/CONTRIBUTORS.html index 77652932e5..e8721a6f88 100644 --- a/CONTRIBUTORS.html +++ b/CONTRIBUTORS.html @@ -447,14 +447,14 @@
  • Adam Vartanian <https://github.com/flooey> use of ShortBuffer exception and buffer size pre-check in Cipher.doFinal().
  • Bernd <https://github.com/ecki> Fix to make PGPUtil.pipeFileContents use buffer and not leak file handle.
  • Shartung <https://github.com/shartung> Additional EC Key Agreement algorithms in support of German BSI TR-03111.
  • -
  • Paul Schaub <https://github.com/vanitasvitae> bringing PGPSecretKey.getUserIds() into line with PGPPublicKey.getUserIds(). Exception message fix in BcPublicKeyDataDecryptorFactory. Additional tests on PGP key ring generation. Improved functionality of PGPSignatureSubpacketGenerator, PGPPublicKeyRing. Tweaks to PGPDataEncryptorBuilder interface, fix for JcaPGP/BcPGP Ed25519 private key conversion. Added configurable CRC detection to ArmoredInputStream, additional control character skipping in ArmoredInputStream. Rewind code for PGPPBEEncryptedData, addition of PGPSignature.getDigestPrefix(). Wrong list traversal fix in PGPSecretKeyRing. Further improvement to use of generics in PGP API. General interop improvements. PGP Public / Secure keyring ignore marker packets when reading. Initial work on PGP session key handling, filtering literal data for canoncialization. Addition of direct key identified key-ring construction. PGPSecretKeyRing.insertOrReplacePublicKey addition. Addition of utility methods for joining/merging signatures and public keys. Addition of PGP regexp packet, PolicyURI packet handling, UTF8 comment testing. Efficiency improvements to TruncatedStream. Initial Argon2 support for OpenPGP. General cleanups. Fast CRC24 implementation, SHA3 addtions to BcImplProvider, improvements to One Pass Signature support, signatue validation, read() consistency in BCPGInputStream. Contributions to AEAD support (v6 & v5) in PGP API. Addition of PGP WildCard ID, moving the PGP example code into the 21st century. Security patches for encrypted data generation, initial thread safe certification verification. Support for V6 EC keys, V6 signatures, V6 encryption, V6 PKESK, PGP packet criticality, and Preferred AEAD CipherSuites sigsubpacket support.
  • +
  • Paul Schaub <https://github.com/vanitasvitae> bringing PGPSecretKey.getUserIds() into line with PGPPublicKey.getUserIds(). Exception message fix in BcPublicKeyDataDecryptorFactory. Additional tests on PGP key ring generation. Improved functionality of PGPSignatureSubpacketGenerator, PGPPublicKeyRing. Tweaks to PGPDataEncryptorBuilder interface, fix for JcaPGP/BcPGP Ed25519 private key conversion. Added configurable CRC detection to ArmoredInputStream, additional control character skipping in ArmoredInputStream. Rewind code for PGPPBEEncryptedData, addition of PGPSignature.getDigestPrefix(). Wrong list traversal fix in PGPSecretKeyRing. Further improvement to use of generics in PGP API. General interop improvements. PGP Public / Secure keyring ignore marker packets when reading. Initial work on PGP session key handling, filtering literal data for canoncialization. Addition of direct key identified key-ring construction. PGPSecretKeyRing.insertOrReplacePublicKey addition. Addition of utility methods for joining/merging signatures and public keys. Addition of PGP regexp packet, PolicyURI packet handling, UTF8 comment testing. Efficiency improvements to TruncatedStream. Initial Argon2 support for OpenPGP. General cleanups. Fast CRC24 implementation, SHA3 addtions to BcImplProvider, improvements to One Pass Signature support, signatue validation, read() consistency in BCPGInputStream. Contributions to AEAD support (v6 & v5) in PGP API. Addition of PGP WildCard ID, moving the PGP example code into the 21st century. Security patches for encrypted data generation, initial thread safe certification verification. Support for V6 EC keys, V6 signatures, V6 encryption, V6 PKESK, PGP packet criticality, and Preferred AEAD CipherSuites sigsubpacket support. Introduce high-level OpenPGP API for message creation/consumption and certificate evaluation. OpenPGP fuzz testing. Fix to prevent a null pointer exception on processing a partial stripped key.
  • Nick of Nexxar <https://github.com/nros> update to OpenPGP package to handle a broader range of EC curves.
  • catbref <https://github.com/catbref> sample implementation of RFC 7748/Ed25519 (incorporated work from github users Valodim and str4d as well).
  • gerlion <https://github.com/gerlion> detection of concurrency issue with pre-1.60 EC math library.
  • fgrieu <fgrieu@gmail.com> identification and suggested fixes for possible timing vulnerability in OAEPEncoding and RSACoreEngine.
  • MTG <https://github.com/mtgag> patch for decoding issues in PKIPublicationInfo and CertifiedKeyPair, patch for adding jurisdiction{C,ST,L} to X500 name style.
  • Andreas Gadermaier <up.gadermaier@gmail.com> initial version of Argon2 PBKDF algorithm.
  • -
  • Tony Washer <https://github.com/tonywasher> ECIESKeyEncapsulation fix for use of OldCofactor mode. Submitted ChaCha20Poly1305 prototype. Remove support for maxXofLen in Kangaroo. Police Blake3 output limit. Add LEAEngine. Review of qTesla, Java 1.9 module code, additional test code and debugging for GOST, DSTU, and ECNR algorithms. Initial lightweight implementation of the ZUC ciphers and macs. Additions to LMS/HSS API implementations, fix for truncation issue with big HSS keys, contributions to optimization of LMS/HSS. Patch for XDH/EdDSA key handling and mcEliece decryption using kobaraImai. Initial GCM-SIV, Blake3, and Kangaroo implementation. Corrections to length outputs for getUpdateOutputSize()/doFinal() in ISAP, PhotonBeetle, and Xoodyak.
  • +
  • Tony Washer <https://github.com/tonywasher> ECIESKeyEncapsulation fix for use of OldCofactor mode. Submitted ChaCha20Poly1305 prototype. Remove support for maxXofLen in Kangaroo. Police Blake3 output limit. Add LEAEngine. Review of qTesla, Java 1.9 module code, additional test code and debugging for GOST, DSTU, and ECNR algorithms. Initial lightweight implementation of the ZUC ciphers and macs. Additions to LMS/HSS API implementations, fix for truncation issue with big HSS keys, contributions to optimization of LMS/HSS. Patch for XDH/EdDSA key handling and mcEliece decryption using kobaraImai. Initial GCM-SIV, Blake3, and Kangaroo implementation. Corrections to length outputs for getUpdateOutputSize()/doFinal() in ISAP, PhotonBeetle, and Xoodyak. Fix GCFB reset. Fix Elephant multi-part process. Fix AsconXof support multi-part outputs.
  • Vincent Bouckaert <https://github.com/veebee> initial version of RFC 4998 ASN.1 classes. Debugging and testing of high level RFC 4998 implementation.
  • Aurimas Liutikas <https://github.com/liutikas> JavaDoc patches to ReasonsMask.
  • Gabriel Sroka <https://github.com/gabrielsroka> corrected comments in RSA validation.
  • @@ -557,6 +557,21 @@
  • moonfruit <https://github.com/moonfruit> - Patch to allow for extensions of GMSignatureSpi.
  • Marcono1234 <https://github.com/Marcono1234> - Updates to OpenBSDBCrypt JavaDoc.
  • DawidM <https://github.com/dawmit> - Implementation of EC J-PAKE.
  • +
  • Syed Quasim <https://github.com/HawkItzme> - lint checker fix for EST getTrustAllTrustManager().
  • +
  • winfriedgerlach <https://github.com/winfriedgerlach> - patch to SecretKeyUtil class, patch to DigestFactory cloner for SHA-1, additional patches for dealing with ErrorProne warnings, Java language updates and improvements.
  • +
  • feuxfollets1013 <https://github.com/feuxfollets1013> - Initial add JDK21 KEM API implementation for HQC algorithm.
  • +
  • cragkhit <https://github.com/cragkhit> - addition of null check in some test utility methods to avoid needless exceptions.
  • +
  • zhsnew <https://github.com/zhsnew> - correct AsconCXof128 implementation and add test vectors
  • +
  • mt-johan <https://github.com/mt-johan> - patch to preserve PRF on initializing from protectionAlgorithm with PBMAC1.
  • +
  • oscerd <https://github.com/oscerd> - comment corrections in GMSSRootSig.java.
  • +
  • Léonard Dallot <leonard.dallot@taztag.com> - initial patches for GNU PG Divert to card format support.
  • +
  • Linuka Ratnayake <https://github.com/linukaratnayake> - initial patches for including KEM-type algorithms in TLS key shares.
  • +
  • Rune Flobakk <https://github.com/runeflobakk> - initial gradle mods for BOM (Bill of Materials) creation.
  • +
  • Jon Marius Venstad <https://github.com/jonmv> - Fixed a KangarooTwelve padding bug caused by premature absorption of queued data.
  • +
  • Lomig Mégard <https://github.com/lomigmegard> - BLAKE2 defensive improvements and cleanup.
  • +
  • Prasanth Sundararajan <prasanth.srihari@gmail.com> - identification of the LDAPStoreHelper wildcard bug (see CVE-2023-33201).
  • +
  • XlabAI Team of Tencent Xuanwu Lab, Atuin Automated Vulnerability Discovery Engine, Lili Tang, Guannan Wang, and Guancheng Li<xlabai@tencent.com> - detection of the DSTU4145 random number defect, correction of the G3413BlockCipher class (see CVE-2025-14813).
  • +
  • stevemit <https://github.com/stevemit> - Identified incorrect tagging in the AuthEnvelopedData stream generator.
  • diff --git a/HOWTO.md b/HOWTO.md new file mode 100644 index 0000000000..c728d84096 --- /dev/null +++ b/HOWTO.md @@ -0,0 +1,129 @@ +# Bouncy Castle Java API How To +## Using Bouncy Castle with GraalVM Native Image +### Problem: Provider Not Registered at Build Time with `UnsupportedFeatureError` Exception +#### Error message +```text +Trying to verify a provider that was not registered at build time: BC version... +``` +#### Cause: +Bouncy Castle security provider isn't properly registered during GraalVM native image build process. + +### Solution 1: Static Initializer Approach (No GraalVM SDK) +#### Step 1. Create Initializer Class +```java +package com.yourpackage.crypto; // ← Replace with your actual package + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import java.security.Security; + +public class BCInitializer { + static { + // Force provider registration during image build + Security.addProvider(new BouncyCastleProvider()); + } +} +``` + +#### Step 2. And then in the native-image build configuration +For Maven (`pom.xml`) +```xml + + org.graalvm.buildtools + native-maven-plugin + 0.9.28 + + + + --initialize-at-build-time=org.bouncycastle,com.yourpackage.crypto.BCInitializer + + --initialize-at-run-time=org.bouncycastle.jcajce.provider.drbg.DRBG$Default,org.bouncycastle.jcajce.provider.drbg.DRBG$NonceAndIV + + + +``` + +For Gradle (`build.gradle`), +```gradle + buildArgs.add('--initialize-at-build-time=com.yourpackage.crypto.BCInitializer') + buildArgs.add("--initialize-at-run-time=org.bouncycastle.jcajce.provider.drbg.DRBG\$Default,org.bouncycastle.jcajce.provider.drbg.DRBG\$NonceAndIV") +``` +# Key Configuration + +| Argument | Purpose | +| ------------------------------- |-----------------------------------------------------------------| +| `--initialize-at-build-time` | Forces inclusion of BC classes and triggers static initializer. | +| `--initialize-at-run-time` | Solves stateful SecureRandom initialization issues. | +|`--enable-all-security-services` | (optional) Enables JCE security infrastructure | + + +### Solution 2: GraalVM Feature Approach (With SDK) + +#### Step 1: Create a Native Image Feature +```java +package com.yourpackage.crypto; // ← Replace with your actual package + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.graalvm.nativeimage.hosted.Feature; + +import java.security.Security; + +/** + * A GraalVM Feature that registers the Bouncy Castle provider. + * This is required so that native image builds verify and include the provider. + */ +public class BouncyCastleFeature implements Feature { + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + // Register the Bouncy Castle provider + Security.addProvider(new BouncyCastleProvider()); + } +} +``` + +#### Step 2: Configure Dependencies and Build +##### 2.1 add dependency +```xml + + org.graalvm.sdk + graal-sdk + 21.0.0 + provided + +``` +##### 2.2 add plugin +```xml + + org.graalvm.buildtools + native-maven-plugin + 0.9.28 + + + --features=com.yourpackage.crypto.BouncyCastleFeature + --initialize-at-build-time=org.bouncycastle + --initialize-at-run-time=org.bouncycastle.jcajce.provider.drbg.DRBG$Default,org.bouncycastle.jcajce.provider.drbg.DRBG$NonceAndIV + + + +``` +Key Configuration Explanations: +`--features=...` +- Registers custom feature class that adds BouncyCastle provider at build time +- Required for JCE security provider verification + +### Troubleshooting +#### Common Issues +##### Classpath Conflicts: + +```text +Error: Class-path entry contains class from image builder +``` +Fix: Add `-H:+AllowDeprecatedBuilderClassesOnImageClasspath` (temporary) or ensure graal-sdk has provided scope + +##### Missing Algorithms: +Example of the error message: +```text +No such algorithm: AES/CBC/PKCS5Padding +``` + +Fix: Verify `--initialize-at-build-time` includes `org.bouncycastle` \ No newline at end of file diff --git a/ant/bc+-build.xml b/ant/bc+-build.xml index e931caeb5f..680cff50c0 100644 --- a/ant/bc+-build.xml +++ b/ant/bc+-build.xml @@ -1413,6 +1413,8 @@ + + diff --git a/ant/build.regexp b/ant/build.regexp index 7179075eaa..beace909de 100644 --- a/ant/build.regexp +++ b/ant/build.regexp @@ -1,3 +1,3 @@ -regexp: >|>|]*\\>>|<[A-Z?][^>@]*[a-zA-Z0-9\\]]>|<[A-Z]>|<[a-z][^>@]*[a-z\\]]>|@SuppressWarnings(.*)|@Override|@Deprecated|@FunctionalInterface +regexp: >|>|]*\\>>|<[A-Z?][^>@]*[a-zA-Z0-9\\]]>|<[A-Z]>|<[a-z][^>@]*[a-z\\]]>|@SuppressWarnings(.*)|@Override|@FunctionalInterface diff --git a/ant/jdk14.xml b/ant/jdk14.xml index 70f04c6c8d..f02b1549b3 100644 --- a/ant/jdk14.xml +++ b/ant/jdk14.xml @@ -31,7 +31,7 @@ - + @@ -41,10 +41,14 @@ + + + + @@ -132,10 +136,14 @@ + + + + @@ -157,6 +165,7 @@ + @@ -196,8 +205,6 @@ - - @@ -213,7 +220,10 @@ - + + + + @@ -230,6 +240,11 @@ + + + + + @@ -287,6 +302,7 @@ + diff --git a/ant/jdk15+.xml b/ant/jdk15+.xml index 80412884fc..00be081a3d 100644 --- a/ant/jdk15+.xml +++ b/ant/jdk15+.xml @@ -43,7 +43,6 @@ - @@ -73,6 +72,7 @@ + diff --git a/ant/jdk18+.xml b/ant/jdk18+.xml index 4a37034a93..f099672565 100644 --- a/ant/jdk18+.xml +++ b/ant/jdk18+.xml @@ -43,7 +43,6 @@ - diff --git a/bc-build.properties b/bc-build.properties index 8a6c20e92b..52e1543237 100644 --- a/bc-build.properties +++ b/bc-build.properties @@ -3,9 +3,9 @@ # intended to hold user-specific settings that are *not* committed to # the repository. -release.suffix: 1.80 -release.name: 1.80 -release.version: 1.80 +release.suffix: 1.84-SNAPSHOT +release.name: 1.84-SNAPSHOT +release.version: 1.83.99 release.debug: false mail.jar.home: ./libs/javax.mail-1.4.7.jar diff --git a/bom/build.gradle b/bom/build.gradle new file mode 100644 index 0000000000..b8b528cc8f --- /dev/null +++ b/bom/build.gradle @@ -0,0 +1,55 @@ +plugins { + id("java-platform") + id("maven-publish") +} + + +dependencies { + constraints { + api(project(":prov")) + api(project(":util")) + api(project(":pkix")) + api(project(":pg")) + api(project(":tls")) + api(project(":mls")) + api(project(":mail")) + api(project(":jmail")) + } +} + + +publishing { + publications { + mavenJava(MavenPublication) { + groupId = 'org.bouncycastle' + artifactId = "bc-$vmrange-bom" + from components.javaPlatform + pom { + name = "Bouncy Castle Java 8+ 1.82 (Bill of Materials)" + description = "This Bill of Materials POM can be used to ease dependency management when referencing multiple Bouncy Castle artifacts using Gradle or Maven." + url = 'https://www.bouncycastle.org/download/bouncy-castle-java/' + licenses { + license { + name = 'Bouncy Castle Licence' + url = 'https://www.bouncycastle.org/licence.html' + distribution = 'repo' + } + } + scm { + url = 'https://github.com/bcgit/bc-java' + } + issueManagement { + system = 'GitHub' + url = 'https://github.com/bcgit/bc-java/issues' + } + developers { + developer { + id = 'feedback-crypto' + name = 'The Legion of the Bouncy Castle Inc.' + email = 'feedback-crypto@bouncycastle.org' + } + } + } + } + } +} diff --git a/build.gradle b/build.gradle index 9167ea9e13..7f83fca5d3 100644 --- a/build.gradle +++ b/build.gradle @@ -12,12 +12,12 @@ plugins { id "io.spring.nohttp" version "0.0.11" id "checkstyle" id "jacoco" - id "net.ltgt.errorprone" version "3.1.0" + id "net.ltgt.errorprone" version "4.2.0" id 'maven-publish' } println("Environment setup:") -["BC_JDK8", "BC_JDK11", "BC_JDK17"].each({ it -> +["BC_JDK8", "BC_JDK11", "BC_JDK17","BC_JDK21", "BC_JDK25"].each({ it -> println("Looking for JDK ENV '${it}' found ${System.getenv(it)}"); // if (System.getenv(it) == null) { // throw new RuntimeException("Looking for JDK ENV '${it}' but found null, see README 'Environmental variables'"); @@ -53,7 +53,7 @@ ext { // this needs to go here, otherwise it can't find config apply plugin: 'io.spring.nohttp' -allprojects { +configure(allprojects.findAll {it.name != 'bom'}) { apply plugin: 'java' apply plugin: 'idea' apply plugin: 'checkstyle' @@ -183,8 +183,7 @@ ext { } - -subprojects { +configure(subprojects.findAll {it.name != 'bom'}) { apply plugin: 'eclipse' apply plugin: 'maven-publish' @@ -243,7 +242,7 @@ subprojects { dependencies { checkstyle files("$rootDir/config/checkstyle/lib/methodchecker-1.0.0.jar") checkstyle 'com.puppycrawl.tools:checkstyle:9.0' - errorprone "com.google.errorprone:error_prone_core:2.24.1" + errorprone "com.google.errorprone:error_prone_core:2.43.0" } checkstyle { @@ -253,7 +252,18 @@ subprojects { } nohttp { + source.exclude '**/*.asc' + source.exclude '**/*.class' + source.exclude '**/*.crt' + source.exclude '**/*.crl' + source.exclude '**/*.eml' + source.exclude '**/*.gpg' + source.exclude '**/*.jar' + source.exclude '**/*.message' + source.exclude '**/*.pem' + source.exclude '**/*.*pub' source.exclude '**/*.rsp' + source.exclude 'out/*' } jacocoTestReport { @@ -265,7 +275,7 @@ subprojects { } tasks.withType(JavaCompile).configureEach { - options.debug = true; + options.debug = false; } tasks.withType(Test).configureEach { @@ -274,16 +284,12 @@ subprojects { } } -// tasks.withType(JavaCompile).configureEach { -// javaCompiler = javaToolchains.compilerFor { -// languageVersion = JavaLanguageVersion.of(21) -// } -// } - } -test.dependsOn([':core:test', ':prov:test', ':prov:test11', ':prov:test15', ':prov:test21', ':pkix:test', 'pg:test', ':tls:test', 'mls:test', 'mail:test', 'jmail:test']) +test.dependsOn([':core:test', ':prov:test', ':prov:test11', ':prov:test15', ':prov:test17', ':pkix:test', 'pg:test', ':tls:test', 'mls:test', 'mail:test', 'jmail:test']) + +apply from: "publish.gradle" diff --git a/ci/check_java.sh b/ci/check_java.sh index 0883c084de..9f4e10aa84 100644 --- a/ci/check_java.sh +++ b/ci/check_java.sh @@ -11,14 +11,16 @@ source ci/common.sh -export JAVA_HOME=`openjdk_21` +export JAVA_HOME=`openjdk_25` export PATH=$JAVA_HOME/bin:$PATH # Checkstyle -./gradlew check -x test; +./gradlew clean build check -x test; # OSGI scanner only, no testing -./gradlew clean build -x test ./osgi_scan.sh + +# module tester +./run_mtt.sh \ No newline at end of file diff --git a/ci/pub.sh b/ci/pub.sh index 5241fe311e..bb352ab651 100644 --- a/ci/pub.sh +++ b/ci/pub.sh @@ -11,7 +11,7 @@ source ci/common.sh -export JAVA_HOME=`openjdk_21` +export JAVA_HOME=`openjdk_25` export PATH=$JAVA_HOME/bin:$PATH ./gradlew clean build -x test diff --git a/ci/test.sh b/ci/test.sh index c72b360ee7..54ba806464 100644 --- a/ci/test.sh +++ b/ci/test.sh @@ -13,9 +13,9 @@ export BC_JDK8=`openjdk_8` export BC_JDK11=`openjdk_11` export BC_JDK17=`openjdk_17` export BC_JDK21=`openjdk_21` +export BC_JDK25=`openjdk_25` - -export JAVA_HOME=`openjdk_21` +export JAVA_HOME=`openjdk_25` export PATH=$JAVA_HOME/bin:$PATH ./gradlew -stacktrace clean build diff --git a/core/build.gradle b/core/build.gradle index 2b1efd9e98..acc707d315 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -20,6 +20,26 @@ compileJava { options.release = 8 } +task sourcesJar(type: Jar) { + archiveBaseName="bccore" + archiveAppendix="${vmrange}" + archiveClassifier = 'sources' + from sourceSets.main.allSource + exclude("**/*.so") +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + archiveBaseName="bccore" + archiveAppendix="${vmrange}" + archiveClassifier = 'javadoc' + from javadoc.destinationDir +} + +artifacts { + archives jar + archives javadocJar + archives sourcesJar +} publishing { publications { @@ -27,6 +47,9 @@ publishing { groupId = 'org.bouncycastle' artifactId = "bccore-$vmrange" from components.java + + artifact(javadocJar) + artifact(sourcesJar) } } } diff --git a/core/src/main/j2me/java/math/BigInteger.java b/core/src/main/j2me/java/math/BigInteger.java index 7b33e0ce1c..20cf97c266 100644 --- a/core/src/main/j2me/java/math/BigInteger.java +++ b/core/src/main/j2me/java/math/BigInteger.java @@ -5,6 +5,7 @@ import java.util.Vector; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Integers; public class BigInteger { @@ -978,9 +979,10 @@ private static int compareNoLeadingZeroes(int xIndx, int[] x, int yIndx, int[] y int v1 = x[xIndx++]; int v2 = y[yIndx++]; - if (v1 != v2) + int c = Integers.compareUnsigned(v1, v2); + if (c != 0) { - return (v1 ^ Integer.MIN_VALUE) < (v2 ^ Integer.MIN_VALUE) ? -1 : 1; + return c; } } diff --git a/core/src/main/j2me/org/bouncycastle/asn1/cms/Time.java b/core/src/main/j2me/org/bouncycastle/asn1/cms/Time.java deleted file mode 100644 index 7819d4ca95..0000000000 --- a/core/src/main/j2me/org/bouncycastle/asn1/cms/Time.java +++ /dev/null @@ -1,127 +0,0 @@ -package org.bouncycastle.asn1.cms; - -import java.util.Calendar; -import java.util.Date; - -import org.bouncycastle.asn1.ASN1Choice; -import org.bouncycastle.asn1.ASN1Object; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.ASN1GeneralizedTime; -import org.bouncycastle.asn1.ASN1UTCTime; - -public class Time - extends ASN1Object - implements ASN1Choice -{ - ASN1Primitive time; - - public static Time getInstance( - ASN1TaggedObject obj, - boolean explicit) - { - if (!explicit) - { - throw new IllegalArgumentException("choice item must be explicitly tagged"); - } - - return getInstance(obj.getExplicitBaseObject()); - } - - public Time( - ASN1Primitive time) - { - if (!(time instanceof ASN1UTCTime) - && !(time instanceof ASN1GeneralizedTime)) - { - throw new IllegalArgumentException("unknown object passed to Time"); - } - - this.time = time; - } - - /** - * creates a time object from a given date - if the date is between 1950 - * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime - * is used. - */ - public Time( - Date date) - { - Calendar calendar = Calendar.getInstance(); - - calendar.setTime(date); - - int year = calendar.get(Calendar.YEAR); - - if (year < 1950 || year > 2049) - { - time = new ASN1GeneralizedTime(date); - } - else - { - time = new ASN1UTCTime(date); - } - } - - public static Time getInstance( - Object obj) - { - if (obj == null || obj instanceof Time) - { - return (Time)obj; - } - else if (obj instanceof ASN1UTCTime) - { - return new Time((ASN1UTCTime)obj); - } - else if (obj instanceof ASN1GeneralizedTime) - { - return new Time((ASN1GeneralizedTime)obj); - } - - throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); - } - - public String getTime() - { - if (time instanceof ASN1UTCTime) - { - return ((ASN1UTCTime)time).getAdjustedTime(); - } - else - { - return ((ASN1GeneralizedTime)time).getTime(); - } - } - - public Date getDate() - { - if (time instanceof ASN1UTCTime) - { - return ((ASN1UTCTime)time).getAdjustedDate(); - } - else - { - return ((ASN1GeneralizedTime)time).getDate(); - } - } - - /** - * Produce an object suitable for an ASN1OutputStream. - *
    -     * Time ::= CHOICE {
    -     *             utcTime        UTCTime,
    -     *             generalTime    GeneralizedTime }
    -     * 
    - */ - public ASN1Primitive toASN1Primitive() - { - return time; - } - - public String toString() - { - return getTime(); - } -} diff --git a/core/src/main/j2me/org/bouncycastle/asn1/eac/PackedDate.java b/core/src/main/j2me/org/bouncycastle/asn1/eac/PackedDate.java deleted file mode 100644 index 2259eb894d..0000000000 --- a/core/src/main/j2me/org/bouncycastle/asn1/eac/PackedDate.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.bouncycastle.asn1.eac; - -import org.bouncycastle.util.Arrays; - -/** - * EAC encoding date object - */ -public class PackedDate -{ - private byte[] time; - - public PackedDate( - String time) - { - this.time = convert(time); - } - - private byte[] convert(String sTime) - { - char[] digs = sTime.toCharArray(); - byte[] date = new byte[6]; - - for (int i = 0; i != 6; i++) - { - date[i] = (byte)(digs[i] - '0'); - } - - return date; - } - - PackedDate( - byte[] bytes) - { - this.time = bytes; - } - - public int hashCode() - { - return Arrays.hashCode(time); - } - - public boolean equals(Object o) - { - if (!(o instanceof PackedDate)) - { - return false; - } - - PackedDate other = (PackedDate)o; - - return Arrays.areEqual(time, other.time); - } - - public String toString() - { - char[] dateC = new char[time.length]; - - for (int i = 0; i != dateC.length; i++) - { - dateC[i] = (char)((time[i] & 0xff) + '0'); - } - - return new String(dateC); - } - - public byte[] getEncoding() - { - return time; - } -} diff --git a/core/src/main/j2me/org/bouncycastle/math/ec/ECCurve.java b/core/src/main/j2me/org/bouncycastle/math/ec/ECCurve.java index 41e6cc796f..b580541a51 100644 --- a/core/src/main/j2me/org/bouncycastle/math/ec/ECCurve.java +++ b/core/src/main/j2me/org/bouncycastle/math/ec/ECCurve.java @@ -593,9 +593,14 @@ protected AbstractFp(BigInteger q) super(FiniteFields.getPrimeField(q)); } + public BigInteger getQ() + { + return getField().getCharacteristic(); + } + public boolean isValidFieldElement(BigInteger x) { - return x != null && x.signum() >= 0 && x.compareTo(this.getField().getCharacteristic()) < 0; + return x != null && x.signum() >= 0 && x.compareTo(this.getQ()) < 0; } public ECFieldElement randomFieldElement(SecureRandom r) @@ -604,7 +609,7 @@ public ECFieldElement randomFieldElement(SecureRandom r) * NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we * use the product of two independent elements to mitigate side-channels. */ - BigInteger p = this.getField().getCharacteristic(); + BigInteger p = this.getQ(); ECFieldElement fe1 = this.fromBigInteger(implRandomFieldElement(r, p)); ECFieldElement fe2 = this.fromBigInteger(implRandomFieldElement(r, p)); return fe1.multiply(fe2); @@ -616,7 +621,7 @@ public ECFieldElement randomFieldElementMult(SecureRandom r) * NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we * use the product of two independent elements to mitigate side-channels. */ - BigInteger p = this.getField().getCharacteristic(); + BigInteger p = this.getQ(); ECFieldElement fe1 = this.fromBigInteger(implRandomFieldElementMult(r, p)); ECFieldElement fe2 = this.fromBigInteger(implRandomFieldElementMult(r, p)); return fe1.multiply(fe2); @@ -699,12 +704,11 @@ public Fp(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger if (isInternal) { - this.q = q; knownQs.add(q); } else if (knownQs.contains(q) || validatedQs.contains(q)) { - this.q = q; + // No need to validate } else { @@ -724,10 +728,9 @@ else if (knownQs.contains(q) || validatedQs.contains(q)) } validatedQs.add(q); - - this.q = q; } + this.q = q; this.r = ECFieldElement.Fp.calculateResidue(q); this.infinity = new ECPoint.Fp(this, null, null); diff --git a/core/src/main/j2me/org/bouncycastle/util/Integers.java b/core/src/main/j2me/org/bouncycastle/util/Integers.java index bd53723dc0..5849b2c8fc 100644 --- a/core/src/main/j2me/org/bouncycastle/util/Integers.java +++ b/core/src/main/j2me/org/bouncycastle/util/Integers.java @@ -22,6 +22,16 @@ public static int bitCount(int i) return i; } + public static int compare(int x, int y) + { + return x < y ? -1 : x == y ? 0 : 1; + } + + public static int compareUnsigned(int x, int y) + { + return compare(x + Integer.MIN_VALUE, y + Integer.MIN_VALUE); + } + public static int highestOneBit(int i) { i |= (i >> 1); diff --git a/core/src/main/j2me/org/bouncycastle/util/Longs.java b/core/src/main/j2me/org/bouncycastle/util/Longs.java index 5baea19a67..d1b83b99e2 100644 --- a/core/src/main/j2me/org/bouncycastle/util/Longs.java +++ b/core/src/main/j2me/org/bouncycastle/util/Longs.java @@ -13,6 +13,16 @@ public class Longs 0x3E, 0x33, 0x05, 0x19, 0x24, 0x27, 0x20, 0x2E, 0x3C, 0x2C, 0x2A, 0x14, 0x16, 0x39, 0x10, 0x09, 0x32, 0x18, 0x23, 0x1F, 0x3B, 0x13, 0x38, 0x0F, 0x31, 0x1E, 0x12, 0x0E, 0x1D, 0x0D, 0x0C, 0x0B }; + public static int compare(long x, long y) + { + return x < y ? -1 : x == y ? 0 : 1; + } + + public static int compareUnsigned(long x, long y) + { + return compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE); + } + public static long highestOneBit(long i) { i |= (i >> 1); diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1BMPString.java b/core/src/main/java/org/bouncycastle/asn1/ASN1BMPString.java index 6b1fb1c928..e2dd1f68a8 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1BMPString.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1BMPString.java @@ -64,14 +64,19 @@ public static ASN1BMPString getInstance(Object obj) * Return a BMP String from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly tagged false + * @param declaredExplicit true if the object is meant to be explicitly tagged false * otherwise. * @exception IllegalArgumentException if the tagged object cannot be converted. * @return an ASN1BMPString instance. */ - public static ASN1BMPString getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1BMPString getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1BMPString)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1BMPString)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1BMPString getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1BMPString)TYPE.getTagged(taggedObject, declaredExplicit); } final char[] string; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1BitString.java b/core/src/main/java/org/bouncycastle/asn1/ASN1BitString.java index aff52097a1..a09c31a69d 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1BitString.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1BitString.java @@ -56,9 +56,14 @@ else if (obj instanceof byte[]) throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); } - public static ASN1BitString getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1BitString getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1BitString)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1BitString)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1BitString getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1BitString)TYPE.getTagged(taggedObject, declaredExplicit); } private static final char[] table = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; @@ -247,7 +252,7 @@ public String getString() throw new ASN1ParsingException("Internal error encoding BitString: " + e.getMessage(), e); } - StringBuffer buf = new StringBuffer(1 + string.length * 2); + StringBuilder buf = new StringBuilder(1 + string.length * 2); buf.append('#'); for (int i = 0; i != string.length; i++) @@ -311,6 +316,16 @@ public byte[] getBytes() return rv; } + public int getBytesLength() + { + return contents.length - 1; + } + + public boolean isOctetAligned() + { + return getPadBits() == 0; + } + public int getPadBits() { return contents[0] & 0xFF; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java index 2794e1726f..2ea88193e0 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java @@ -87,15 +87,20 @@ public static ASN1Boolean getInstance(int value) * Return a Boolean from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly + * @param declaredExplicit true if the object is meant to be explicitly * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. * @return an ASN1Boolean instance. */ - public static ASN1Boolean getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1Boolean getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1Boolean)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1Boolean)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1Boolean getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1Boolean)TYPE.getTagged(taggedObject, declaredExplicit); } private ASN1Boolean(byte value) diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java b/core/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java index 0b011c6e01..8d220d9f30 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1EncodableVector.java @@ -48,6 +48,14 @@ public void add(ASN1Encodable element) this.elementCount = minCapacity; } + public void addOptional(ASN1Encodable element) + { + if (element != null) + { + this.add(element); + } + } + public void addAll(ASN1Encodable[] others) { if (null == others) diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java index c2aa7dc7a9..df587ee740 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java @@ -53,15 +53,20 @@ public static ASN1Enumerated getInstance( * return an Enumerated from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly + * @param declaredExplicit true if the object is meant to be explicitly * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. * @return an ASN1Enumerated instance, or null. */ - public static ASN1Enumerated getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1Enumerated getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1Enumerated)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1Enumerated)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1Enumerated getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1Enumerated)TYPE.getTagged(taggedObject, declaredExplicit); } private final byte[] contents; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1External.java b/core/src/main/java/org/bouncycastle/asn1/ASN1External.java index d75ced245b..658fbe41cd 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1External.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1External.java @@ -48,9 +48,14 @@ else if (obj instanceof byte[]) throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); } - public static ASN1External getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1External getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1External)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1External)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1External getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1External)TYPE.getTagged(taggedObject, declaredExplicit); } ASN1ObjectIdentifier directReference; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralString.java b/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralString.java index c527f4dbc3..e6b53b2f3b 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralString.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralString.java @@ -65,14 +65,19 @@ public static ASN1GeneralString getInstance(Object obj) * Return a GeneralString from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly tagged false + * @param declaredExplicit true if the object is meant to be explicitly tagged false * otherwise. * @exception IllegalArgumentException if the tagged object cannot be converted. * @return an ASN1GeneralString instance. */ - public static ASN1GeneralString getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1GeneralString getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1GeneralString)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1GeneralString)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1GeneralString getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1GeneralString)TYPE.getTagged(taggedObject, declaredExplicit); } final byte[] contents; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java b/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java index be41ba56e9..41c4fc21e1 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1GeneralizedTime.java @@ -93,14 +93,19 @@ public static ASN1GeneralizedTime getInstance( * return a Generalized Time object from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly tagged false + * @param declaredExplicit true if the object is meant to be explicitly tagged false * otherwise. * @return an ASN1GeneralizedTime instance. * @throws IllegalArgumentException if the tagged object cannot be converted. */ - public static ASN1GeneralizedTime getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1GeneralizedTime getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1GeneralizedTime)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1GeneralizedTime)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1GeneralizedTime getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1GeneralizedTime)TYPE.getTagged(taggedObject, declaredExplicit); } final byte[] contents; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Generator.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Generator.java index a9b9f5ba56..e012e8980f 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1Generator.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Generator.java @@ -27,4 +27,16 @@ public ASN1Generator(OutputStream out) * @return the stream that is directly encoded to. */ public abstract OutputStream getRawOutputStream(); + + static int inheritConstructedFlag(int intoTag, int fromTag) + { + if ((fromTag & BERTags.CONSTRUCTED) != 0) + { + return intoTag | BERTags.CONSTRUCTED; + } + else + { + return intoTag & ~BERTags.CONSTRUCTED; + } + } } diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1GraphicString.java b/core/src/main/java/org/bouncycastle/asn1/ASN1GraphicString.java index b21142bda9..5f55a7373e 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1GraphicString.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1GraphicString.java @@ -57,14 +57,19 @@ public static ASN1GraphicString getInstance(Object obj) * Return a GraphicString from a tagged object. * * @param taggedObject the tagged object holding the object we want. - * @param explicit true if the object is meant to be explicitly tagged, + * @param declaredExplicit true if the object is meant to be explicitly tagged, * false otherwise. * @exception IllegalArgumentException if the tagged object cannot be converted. * @return an ASN1GraphicString instance, or null. */ - public static ASN1GraphicString getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1GraphicString getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1GraphicString)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1GraphicString)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1GraphicString getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1GraphicString)TYPE.getTagged(taggedObject, declaredExplicit); } final byte[] contents; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1IA5String.java b/core/src/main/java/org/bouncycastle/asn1/ASN1IA5String.java index ecf848f982..b3a5458304 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1IA5String.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1IA5String.java @@ -63,15 +63,20 @@ public static ASN1IA5String getInstance(Object obj) * Return an IA5 String from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly + * @param declaredExplicit true if the object is meant to be explicitly * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. * @return an ASN1IA5String instance, or null. */ - public static ASN1IA5String getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1IA5String getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1IA5String)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1IA5String)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1IA5String getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1IA5String)TYPE.getTagged(taggedObject, declaredExplicit); } final byte[] contents; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java b/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java index 9dc4a45826..c0496d2fda 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java @@ -540,7 +540,10 @@ static ASN1Primitive createPrimitiveDERObject( case INTEGER: return ASN1Integer.createPrimitive(defIn.toByteArray()); case NULL: - return ASN1Null.createPrimitive(defIn.toByteArray()); + { + ASN1Null.checkContentsLength(defIn.getRemaining()); + return ASN1Null.createPrimitive(); + } case NUMERIC_STRING: return ASN1NumericString.createPrimitive(defIn.toByteArray()); case OBJECT_DESCRIPTOR: diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java index cfc4049713..3968aa417d 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java @@ -20,6 +20,15 @@ ASN1Primitive fromImplicitPrimitive(DEROctetString octetString) } }; + private static final ASN1Integer[] SMALL_CONSTANTS = new ASN1Integer[17]; + + public static final ASN1Integer ZERO; + public static final ASN1Integer ONE; + public static final ASN1Integer TWO; + public static final ASN1Integer THREE; + public static final ASN1Integer FOUR; + public static final ASN1Integer FIVE; + static final int SIGN_EXT_SIGNED = 0xFFFFFFFF; static final int SIGN_EXT_UNSIGNED = 0xFF; @@ -60,15 +69,62 @@ public static ASN1Integer getInstance( * Return an Integer from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly + * @param declaredExplicit true if the object is meant to be explicitly * tagged false otherwise. * @return an ASN1Integer instance. * @throws IllegalArgumentException if the tagged object cannot * be converted. */ - public static ASN1Integer getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1Integer getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1Integer)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1Integer getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1Integer)TYPE.getTagged(taggedObject, declaredExplicit); + } + + public static ASN1Integer valueOf(int value) { - return (ASN1Integer)TYPE.getContextInstance(taggedObject, explicit); + if (value >= 0L && value < SMALL_CONSTANTS.length) + return SMALL_CONSTANTS[value]; + + return new ASN1Integer(value); + } + + public static ASN1Integer valueOf(long value) + { + if (value >= 0L && value < SMALL_CONSTANTS.length) + return SMALL_CONSTANTS[(int)value]; + + return new ASN1Integer(value); + } + + static + { + for (int i = 0; i < SMALL_CONSTANTS.length; ++i) + { + SMALL_CONSTANTS[i] = new ASN1Integer(i); + } + + ZERO = SMALL_CONSTANTS[0]; + ONE = SMALL_CONSTANTS[1]; + TWO = SMALL_CONSTANTS[2]; + THREE = SMALL_CONSTANTS[3]; + FOUR = SMALL_CONSTANTS[4]; + FIVE = SMALL_CONSTANTS[5]; + } + + /** + * Construct an INTEGER from the passed in int value. + * + * @param value the int representing the value desired. + */ + public ASN1Integer(int value) + { + this.bytes = BigInteger.valueOf(value).toByteArray(); + this.start = 0; } /** diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Null.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Null.java index bad23470cf..8939a45ca4 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1Null.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Null.java @@ -12,7 +12,8 @@ public abstract class ASN1Null { ASN1Primitive fromImplicitPrimitive(DEROctetString octetString) { - return createPrimitive(octetString.getOctets()); + checkContentsLength(octetString.getOctetsLength()); + return createPrimitive(); } }; @@ -53,9 +54,14 @@ public static ASN1Null getInstance(Object o) return null; } - public static ASN1Null getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1Null getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1Null)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1Null)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1Null getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1Null)TYPE.getTagged(taggedObject, declaredExplicit); } ASN1Null() @@ -83,12 +89,16 @@ public String toString() return "NULL"; } - static ASN1Null createPrimitive(byte[] contents) + static void checkContentsLength(int contentsLength) { - if (0 != contents.length) + if (0 != contentsLength) { throw new IllegalStateException("malformed NULL encoding encountered"); } + } + + static ASN1Null createPrimitive() + { return DERNull.INSTANCE; } } diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1NumericString.java b/core/src/main/java/org/bouncycastle/asn1/ASN1NumericString.java index 3609acaed1..f92357591a 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1NumericString.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1NumericString.java @@ -67,14 +67,19 @@ public static ASN1NumericString getInstance(Object obj) * Return an Numeric String from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly tagged false + * @param declaredExplicit true if the object is meant to be explicitly tagged false * otherwise. * @exception IllegalArgumentException if the tagged object cannot be converted. * @return an ASN1NumericString instance, or null. */ - public static ASN1NumericString getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1NumericString getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1NumericString)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1NumericString)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1NumericString getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1NumericString)TYPE.getTagged(taggedObject, declaredExplicit); } final byte[] contents; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectDescriptor.java b/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectDescriptor.java index 5323d5c48d..261201bcf1 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectDescriptor.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectDescriptor.java @@ -60,14 +60,19 @@ else if (obj instanceof byte[]) * Return an ObjectDescriptor from a tagged object. * * @param taggedObject the tagged object holding the object we want. - * @param explicit true if the object is meant to be explicitly tagged, + * @param declaredExplicit true if the object is meant to be explicitly tagged, * false otherwise. * @exception IllegalArgumentException if the tagged object cannot be converted. * @return an ASN1ObjectDescriptor instance, or null. */ - public static ASN1ObjectDescriptor getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1ObjectDescriptor getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1ObjectDescriptor)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1ObjectDescriptor)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1ObjectDescriptor getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1ObjectDescriptor)TYPE.getTagged(taggedObject, declaredExplicit); } private final ASN1GraphicString baseGraphicString; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java index 61acea41af..e868b716fc 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java @@ -83,20 +83,20 @@ else if (obj instanceof byte[]) * Return an OBJECT IDENTIFIER from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly + * @param declaredExplicit 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. */ - public static ASN1ObjectIdentifier getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1ObjectIdentifier getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { /* * TODO[asn1] This block here is for backward compatibility, but should eventually be removed. * * - see https://github.com/bcgit/bc-java/issues/1015 */ - if (!explicit && !taggedObject.isParsed() && taggedObject.hasContextTag()) + if (!declaredExplicit && !taggedObject.isParsed() && taggedObject.hasContextTag()) { ASN1Primitive base = taggedObject.getBaseObject().toASN1Primitive(); if (!(base instanceof ASN1ObjectIdentifier)) @@ -105,7 +105,12 @@ public static ASN1ObjectIdentifier getInstance(ASN1TaggedObject taggedObject, bo } } - return (ASN1ObjectIdentifier)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1ObjectIdentifier)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1ObjectIdentifier getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1ObjectIdentifier)TYPE.getTagged(taggedObject, declaredExplicit); } public static ASN1ObjectIdentifier tryFromID(String identifier) diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java b/core/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java index 896f56f94d..417f71de0e 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1OctetString.java @@ -117,14 +117,19 @@ ASN1Primitive fromImplicitConstructed(ASN1Sequence sequence) * return an Octet String from a tagged object. * * @param taggedObject the tagged object holding the object we want. - * @param explicit true if the object is meant to be explicitly + * @param declaredExplicit true if the object is meant to be explicitly * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. */ - public static ASN1OctetString getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1OctetString getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1OctetString)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1OctetString)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1OctetString getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1OctetString)TYPE.getTagged(taggedObject, declaredExplicit); } /** diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1PrintableString.java b/core/src/main/java/org/bouncycastle/asn1/ASN1PrintableString.java index a859b7dc97..14acbec1a6 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1PrintableString.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1PrintableString.java @@ -83,15 +83,20 @@ public static ASN1PrintableString getInstance(Object obj) * Return a Printable String from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly + * @param declaredExplicit true if the object is meant to be explicitly * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. * @return an ASN1PrintableString instance, or null. */ - public static ASN1PrintableString getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1PrintableString getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1PrintableString)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1PrintableString)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1PrintableString getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1PrintableString)TYPE.getTagged(taggedObject, declaredExplicit); } final byte[] contents; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1RelativeOID.java b/core/src/main/java/org/bouncycastle/asn1/ASN1RelativeOID.java index 00f980508c..ac98c449f4 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1RelativeOID.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1RelativeOID.java @@ -71,9 +71,14 @@ else if (obj instanceof byte[]) throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); } - public static ASN1RelativeOID getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1RelativeOID getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1RelativeOID)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1RelativeOID)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1RelativeOID getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1RelativeOID)TYPE.getTagged(taggedObject, declaredExplicit); } public static ASN1RelativeOID tryFromID(String identifier) diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java index 66c22ec9f3..f2ce0f0c9a 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Sequence.java @@ -116,15 +116,20 @@ else if (obj instanceof byte[]) * be using this method. * * @param taggedObject the tagged object. - * @param explicit true if the object is meant to be explicitly tagged, + * @param declaredExplicit true if the object is meant to be explicitly tagged, * false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. * @return an ASN1Sequence instance. */ - public static ASN1Sequence getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1Sequence getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1Sequence)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1Sequence)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1Sequence getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1Sequence)TYPE.getTagged(taggedObject, declaredExplicit); } // NOTE: Only non-final to support LazyEncodedSequence @@ -383,7 +388,7 @@ public String toString() return "[]"; } - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append('['); for (int i = 0;;) { diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Set.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Set.java index 8cd3ad583b..a3af7ec1e6 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1Set.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Set.java @@ -154,15 +154,20 @@ else if (obj instanceof byte[]) * be using this method. * * @param taggedObject the tagged object. - * @param explicit true if the object is meant to be explicitly tagged + * @param declaredExplicit true if the object is meant to be explicitly tagged * false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. * @return an ASN1Set instance. */ - public static ASN1Set getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1Set getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1Set)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1Set)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1Set getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1Set)TYPE.getTagged(taggedObject, declaredExplicit); } protected final ASN1Encodable[] elements; @@ -423,7 +428,7 @@ public String toString() return "[]"; } - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append('['); for (int i = 0;;) { diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1T61String.java b/core/src/main/java/org/bouncycastle/asn1/ASN1T61String.java index 2592005ff1..4edbfe5f20 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1T61String.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1T61String.java @@ -61,14 +61,19 @@ public static ASN1T61String getInstance(Object obj) * Return an T61 String from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly tagged false + * @param declaredExplicit true if the object is meant to be explicitly tagged false * otherwise. * @exception IllegalArgumentException if the tagged object cannot be converted. * @return an ASN1T61String instance, or null */ - public static ASN1T61String getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1T61String getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1T61String)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1T61String)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1T61String getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1T61String)TYPE.getTagged(taggedObject, declaredExplicit); } final byte[] contents; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java b/core/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java index efd7fdac28..3e2e4626a8 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1TaggedObject.java @@ -19,6 +19,36 @@ public abstract class ASN1TaggedObject private static final int PARSED_EXPLICIT = 3; private static final int PARSED_IMPLICIT = 4; + public static ASN1TaggedObject getContextInstance(Object obj) + { + return ASN1Util.checkContextTagClass(checkInstance(obj)); + } + + public static ASN1TaggedObject getContextInstance(Object obj, int tagNo) + { + return ASN1Util.checkContextTag(checkInstance(obj), tagNo); + } + + public static ASN1TaggedObject getContextOptional(ASN1Encodable element) + { + ASN1TaggedObject taggedObject = getOptional(element); + if (taggedObject != null && taggedObject.hasContextTag()) + { + return taggedObject; + } + return null; + } + + public static ASN1TaggedObject getContextOptional(ASN1Encodable element, int tagNo) + { + ASN1TaggedObject taggedObject = getOptional(element); + if (taggedObject != null && taggedObject.hasContextTag(tagNo)) + { + return taggedObject; + } + return null; + } + public static ASN1TaggedObject getInstance(Object obj) { if (obj == null || obj instanceof ASN1TaggedObject) @@ -75,6 +105,41 @@ public static ASN1TaggedObject getInstance(ASN1TaggedObject taggedObject, int ta return ASN1Util.getExplicitBaseTagged(checkInstance(taggedObject, declaredExplicit), tagClass, tagNo); } + public static ASN1TaggedObject getOptional(ASN1Encodable element) + { + if (element == null) + { + throw new NullPointerException("'element' cannot be null"); + } + + if (element instanceof ASN1TaggedObject) + { + return (ASN1TaggedObject)element; + } + + return null; + } + + public static ASN1TaggedObject getOptional(ASN1Encodable element, int tagClass) + { + ASN1TaggedObject taggedObject = getOptional(element); + if (taggedObject != null && taggedObject.hasTagClass(tagClass)) + { + return taggedObject; + } + return null; + } + + public static ASN1TaggedObject getOptional(ASN1Encodable element, int tagClass, int tagNo) + { + ASN1TaggedObject taggedObject = getOptional(element); + if (taggedObject != null && taggedObject.hasTag(tagClass, tagNo)) + { + return taggedObject; + } + return null; + } + private static ASN1TaggedObject checkInstance(Object obj) { if (obj == null) diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java b/core/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java index c849a75a50..eb7b2b58f1 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1UTCTime.java @@ -83,14 +83,19 @@ public static ASN1UTCTime getInstance( * Return an UTC Time from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly tagged false + * @param declaredExplicit true if the object is meant to be explicitly tagged false * otherwise. * @exception IllegalArgumentException if the tagged object cannot be converted. * @return an ASN1UTCTime instance, or null. */ - public static ASN1UTCTime getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1UTCTime getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1UTCTime)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1UTCTime)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1UTCTime getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1UTCTime)TYPE.getTagged(taggedObject, declaredExplicit); } final byte[] contents; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1UTF8String.java b/core/src/main/java/org/bouncycastle/asn1/ASN1UTF8String.java index 8f8d00ccde..c0a337f484 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1UTF8String.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1UTF8String.java @@ -57,14 +57,19 @@ public static ASN1UTF8String getInstance(Object obj) * Return an UTF8 String from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly tagged false + * @param declaredExplicit true if the object is meant to be explicitly tagged false * otherwise. * @exception IllegalArgumentException if the tagged object cannot be converted. * @return a DERUTF8String instance, or null */ - public static ASN1UTF8String getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1UTF8String getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1UTF8String)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1UTF8String)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1UTF8String getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1UTF8String)TYPE.getTagged(taggedObject, declaredExplicit); } final byte[] contents; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1UniversalString.java b/core/src/main/java/org/bouncycastle/asn1/ASN1UniversalString.java index fe8addfe57..22fe560759 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1UniversalString.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1UniversalString.java @@ -63,14 +63,19 @@ public static ASN1UniversalString getInstance(Object obj) * Return a Universal String from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly tagged false + * @param declaredExplicit true if the object is meant to be explicitly tagged false * otherwise. * @exception IllegalArgumentException if the tagged object cannot be converted. * @return a ASN1UniversalString instance, or null */ - public static ASN1UniversalString getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1UniversalString getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1UniversalString)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1UniversalString)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1UniversalString getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1UniversalString)TYPE.getTagged(taggedObject, declaredExplicit); } final byte[] contents; @@ -83,7 +88,7 @@ public static ASN1UniversalString getInstance(ASN1TaggedObject taggedObject, boo public final String getString() { int dl = contents.length; - StringBuffer buf = new StringBuffer(3 + 2 * (ASN1OutputStream.getLengthOfDL(dl) + dl)); + StringBuilder buf = new StringBuilder(3 + 2 * (ASN1OutputStream.getLengthOfDL(dl) + dl)); buf.append("#1C"); encodeHexDL(buf, dl); @@ -142,13 +147,13 @@ static ASN1UniversalString createPrimitive(byte[] contents) return new DERUniversalString(contents, false); } - private static void encodeHexByte(StringBuffer buf, int i) + private static void encodeHexByte(StringBuilder buf, int i) { buf.append(table[(i >>> 4) & 0xF]); buf.append(table[i & 0xF]); } - private static void encodeHexDL(StringBuffer buf, int dl) + private static void encodeHexDL(StringBuilder buf, int dl) { if (dl < 128) { diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1UniversalType.java b/core/src/main/java/org/bouncycastle/asn1/ASN1UniversalType.java index 9e720b0ed1..e7cbe4a1cf 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1UniversalType.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1UniversalType.java @@ -39,11 +39,16 @@ final ASN1Primitive fromByteArray(byte[] bytes) throws IOException return checkedCast(ASN1Primitive.fromByteArray(bytes)); } - final ASN1Primitive getContextInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) + final ASN1Primitive getContextTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) { return checkedCast(ASN1Util.checkContextTagClass(taggedObject).getBaseUniversal(declaredExplicit, this)); } + final ASN1Primitive getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return checkedCast(taggedObject.getBaseUniversal(declaredExplicit, this)); + } + final ASN1Tag getTag() { return tag; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Util.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Util.java index 01c689ea54..78be766fa6 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1Util.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Util.java @@ -68,6 +68,42 @@ static ASN1TaggedObjectParser checkTagClass(ASN1TaggedObjectParser taggedObjectP return taggedObjectParser; } + public static Object getInstanceChoiceBaseObject(ASN1TaggedObject taggedObject, boolean declaredExplicit, + String choiceName) + { + if (!declaredExplicit) + { + String message = "Implicit tagging cannot be used with untagged choice type " + choiceName + + " (X.680 30.6, 30.8)."; + + throw new IllegalArgumentException(message); + } + if (taggedObject == null) + { + throw new NullPointerException("'taggedObject' cannot be null"); + } + + return getExplicitContextBaseObject(taggedObject); + } + + public static Object getTaggedChoiceBaseObject(ASN1TaggedObject taggedObject, boolean declaredExplicit, + String choiceName) + { + if (!declaredExplicit) + { + String message = "Implicit tagging cannot be used with untagged choice type " + choiceName + + " (X.680 30.6, 30.8)."; + + throw new IllegalArgumentException(message); + } + if (taggedObject == null) + { + throw new NullPointerException("'taggedObject' cannot be null"); + } + + return taggedObject.getExplicitBaseObject(); + } + /* * Tag text methods @@ -138,16 +174,36 @@ public static String getTagText(int tagClass, int tagNo) * Wrappers for ASN1TaggedObject#getExplicitBaseObject */ + public static ASN1Object getExplicitBaseObject(ASN1TaggedObject taggedObject, int tagClass) + { + return checkTagClass(taggedObject, tagClass).getExplicitBaseObject(); + } + public static ASN1Object getExplicitBaseObject(ASN1TaggedObject taggedObject, int tagClass, int tagNo) { return checkTag(taggedObject, tagClass, tagNo).getExplicitBaseObject(); } + public static ASN1Object getExplicitContextBaseObject(ASN1TaggedObject taggedObject) + { + return getExplicitBaseObject(taggedObject, BERTags.CONTEXT_SPECIFIC); + } + public static ASN1Object getExplicitContextBaseObject(ASN1TaggedObject taggedObject, int tagNo) { return getExplicitBaseObject(taggedObject, BERTags.CONTEXT_SPECIFIC, tagNo); } + public static ASN1Object tryGetExplicitBaseObject(ASN1TaggedObject taggedObject, int tagClass) + { + if (!taggedObject.hasTagClass(tagClass)) + { + return null; + } + + return taggedObject.getExplicitBaseObject(); + } + public static ASN1Object tryGetExplicitBaseObject(ASN1TaggedObject taggedObject, int tagClass, int tagNo) { if (!taggedObject.hasTag(tagClass, tagNo)) @@ -158,6 +214,11 @@ public static ASN1Object tryGetExplicitBaseObject(ASN1TaggedObject taggedObject, return taggedObject.getExplicitBaseObject(); } + public static ASN1Object tryGetExplicitContextBaseObject(ASN1TaggedObject taggedObject) + { + return tryGetExplicitBaseObject(taggedObject, BERTags.CONTEXT_SPECIFIC); + } + public static ASN1Object tryGetExplicitContextBaseObject(ASN1TaggedObject taggedObject, int tagNo) { return tryGetExplicitBaseObject(taggedObject, BERTags.CONTEXT_SPECIFIC, tagNo); diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1VideotexString.java b/core/src/main/java/org/bouncycastle/asn1/ASN1VideotexString.java index ae9c42285f..facbd89e10 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1VideotexString.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1VideotexString.java @@ -57,14 +57,19 @@ public static ASN1VideotexString getInstance(Object obj) * return a Videotex String from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly tagged false + * @param declaredExplicit true if the object is meant to be explicitly tagged false * otherwise. * @exception IllegalArgumentException if the tagged object cannot be converted. * @return an ASN1VideotexString instance, or null. */ - public static ASN1VideotexString getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1VideotexString getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1VideotexString)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1VideotexString)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1VideotexString getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1VideotexString)TYPE.getTagged(taggedObject, declaredExplicit); } final byte[] contents; diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1VisibleString.java b/core/src/main/java/org/bouncycastle/asn1/ASN1VisibleString.java index 6424cfcdaf..bb14e52177 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1VisibleString.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1VisibleString.java @@ -64,15 +64,20 @@ public static ASN1VisibleString getInstance( * Return a Visible String from a tagged object. * * @param taggedObject the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly + * @param declaredExplicit true if the object is meant to be explicitly * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. * @return an ASN1VisibleString instance, or null */ - public static ASN1VisibleString getInstance(ASN1TaggedObject taggedObject, boolean explicit) + public static ASN1VisibleString getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return (ASN1VisibleString)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1VisibleString)TYPE.getContextTagged(taggedObject, declaredExplicit); + } + + public static ASN1VisibleString getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return (ASN1VisibleString)TYPE.getTagged(taggedObject, declaredExplicit); } final byte[] contents; diff --git a/core/src/main/java/org/bouncycastle/asn1/BERBitStringParser.java b/core/src/main/java/org/bouncycastle/asn1/BERBitStringParser.java index 9b2cfaffc2..c9c1855647 100644 --- a/core/src/main/java/org/bouncycastle/asn1/BERBitStringParser.java +++ b/core/src/main/java/org/bouncycastle/asn1/BERBitStringParser.java @@ -10,6 +10,7 @@ * * @deprecated Check for 'ASN1BitStringParser' instead */ +@Deprecated public class BERBitStringParser implements ASN1BitStringParser { diff --git a/core/src/main/java/org/bouncycastle/asn1/BERGenerator.java b/core/src/main/java/org/bouncycastle/asn1/BERGenerator.java index ad2b37ff01..74a59a7b7e 100644 --- a/core/src/main/java/org/bouncycastle/asn1/BERGenerator.java +++ b/core/src/main/java/org/bouncycastle/asn1/BERGenerator.java @@ -41,31 +41,28 @@ private void writeHdr(int tag) throws IOException protected void writeBERHeader(int tag) throws IOException { - if (_tagged) + if (!_tagged) { - int tagNum = _tagNo | BERTags.CONTEXT_SPECIFIC; - - if (_isExplicit) - { - writeHdr(tagNum | BERTags.CONSTRUCTED); - writeHdr(tag); - } - else - { - if ((tag & BERTags.CONSTRUCTED) != 0) - { - writeHdr(tagNum | BERTags.CONSTRUCTED); - } - else - { - writeHdr(tagNum); - } - } + writeHdr(tag); } - else + else if (_isExplicit) { + /* + * X.690-0207 8.14.2. If implicit tagging [..] was not used [..], the encoding shall be constructed + * and the contents octets shall be the complete base encoding. + */ + writeHdr(_tagNo | BERTags.CONTEXT_SPECIFIC | BERTags.CONSTRUCTED); writeHdr(tag); } + else + { + /* + * X.690-0207 8.14.3. If implicit tagging was used [..], then: a) the encoding shall be constructed + * if the base encoding is constructed, and shall be primitive otherwise; and b) the contents octets + * shall be [..] the contents octets of the base encoding. + */ + writeHdr(inheritConstructedFlag(_tagNo | BERTags.CONTEXT_SPECIFIC, tag)); + } } protected void writeBEREnd() throws IOException diff --git a/core/src/main/java/org/bouncycastle/asn1/BEROctetString.java b/core/src/main/java/org/bouncycastle/asn1/BEROctetString.java index dbc8e4b8b9..8132cc7c94 100644 --- a/core/src/main/java/org/bouncycastle/asn1/BEROctetString.java +++ b/core/src/main/java/org/bouncycastle/asn1/BEROctetString.java @@ -2,6 +2,8 @@ import java.io.IOException; +import org.bouncycastle.util.Arrays; + /** * ASN.1 OctetStrings, with indefinite length rules, and constructed form support. *

    @@ -19,10 +21,37 @@ public class BEROctetString extends ASN1OctetString { - private static final int DEFAULT_SEGMENT_LIMIT = 1000; + public static final BEROctetString EMPTY = new BEROctetString(EMPTY_OCTETS); - private final int segmentLimit; - private final ASN1OctetString[] elements; + public static BEROctetString fromContents(byte[] contents) + { + if (contents == null) + { + throw new NullPointerException("'contents' cannot be null"); + } + + return internalFromContents(contents); + } + + public static BEROctetString fromContentsOptional(byte[] contents) + { + return contents == null ? null : internalFromContents(contents); + } + + public static BEROctetString withContents(byte[] contents) + { + if (contents == null) + { + throw new NullPointerException("'contents' cannot be null"); + } + + return internalWithContents(contents); + } + + public static BEROctetString withContentsOptional(byte[] contents) + { + return contents == null ? null : internalWithContents(contents); + } /** * Convert a vector of octet strings into a single byte string @@ -58,6 +87,21 @@ static byte[] flattenOctetStrings(ASN1OctetString[] octetStrings) } } + static BEROctetString internalFromContents(byte[] contents) + { + return contents.length < 1 ? EMPTY : new BEROctetString(Arrays.clone(contents)); + } + + static BEROctetString internalWithContents(byte[] contents) + { + return contents.length < 1 ? EMPTY : new BEROctetString(contents); + } + + private static final int DEFAULT_SEGMENT_LIMIT = 1000; + + private final int segmentLimit; + private final ASN1OctetString[] elements; + /** * Create an OCTET-STRING object from a byte[] * @param string the octets making up the octet string. diff --git a/core/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java b/core/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java index 8be481fc9f..29b4e9edc2 100644 --- a/core/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java +++ b/core/src/main/java/org/bouncycastle/asn1/BEROctetStringGenerator.java @@ -71,14 +71,14 @@ private class BufferedBEROctetStream { private byte[] _buf; private int _off; - private DEROutputStream _derOut; + private ASN1OutputStream _asn1Out; BufferedBEROctetStream( byte[] buf) { _buf = buf; _off = 0; - _derOut = new DEROutputStream(_out); + _asn1Out = ASN1OutputStream.create(_out); } public void write( @@ -89,7 +89,7 @@ public void write( if (_off == _buf.length) { - DEROctetString.encode(_derOut, true, _buf, 0, _buf.length); + DEROctetString.encode(_asn1Out, true, _buf, 0, _buf.length); _off = 0; } } @@ -110,13 +110,13 @@ public void write(byte[] b, int off, int len) throws IOException { System.arraycopy(b, off, _buf, _off, available); count += available; - DEROctetString.encode(_derOut, true, _buf, 0, bufLen); + DEROctetString.encode(_asn1Out, true, _buf, 0, bufLen); } int remaining; while ((remaining = (len - count)) >= bufLen) { - DEROctetString.encode(_derOut, true, b, off + count, bufLen); + DEROctetString.encode(_asn1Out, true, b, off + count, bufLen); count += bufLen; } @@ -129,10 +129,10 @@ public void close() { if (_off != 0) { - DEROctetString.encode(_derOut, true, _buf, 0, _off); + DEROctetString.encode(_asn1Out, true, _buf, 0, _off); } - _derOut.flushInternal(); + _asn1Out.flushInternal(); writeBEREnd(); } diff --git a/core/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java b/core/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java index bce7f0189c..c42a46aa42 100644 --- a/core/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java +++ b/core/src/main/java/org/bouncycastle/asn1/BEROctetStringParser.java @@ -10,6 +10,7 @@ * * @deprecated Check for 'ASN1OctetStringParser' instead */ +@Deprecated public class BEROctetStringParser implements ASN1OctetStringParser { diff --git a/core/src/main/java/org/bouncycastle/asn1/BEROutputStream.java b/core/src/main/java/org/bouncycastle/asn1/BEROutputStream.java deleted file mode 100644 index 6bced5e4dd..0000000000 --- a/core/src/main/java/org/bouncycastle/asn1/BEROutputStream.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bouncycastle.asn1; - -import java.io.OutputStream; - -/** - * A class which writes indefinite and definite length objects. Objects which specify DER will be - * encoded accordingly, but DL or BER objects will be encoded as defined. - */ -class BEROutputStream - extends ASN1OutputStream -{ - /** - * Base constructor. - * - * @param os - * target output stream. - */ - BEROutputStream(OutputStream os) - { - super(os); - } -} diff --git a/core/src/main/java/org/bouncycastle/asn1/BERSequence.java b/core/src/main/java/org/bouncycastle/asn1/BERSequence.java index 93d9783eb0..2c52cd559f 100644 --- a/core/src/main/java/org/bouncycastle/asn1/BERSequence.java +++ b/core/src/main/java/org/bouncycastle/asn1/BERSequence.java @@ -13,6 +13,18 @@ public class BERSequence extends ASN1Sequence { + public static final BERSequence EMPTY = new BERSequence(); + + public static BERSequence fromElementsOptional(ASN1Encodable[] elements) + { + if (elements == null) + { + return null; + } + + return elements.length < 1 ? EMPTY : new BERSequence(elements); + } + /** * Create an empty sequence. */ diff --git a/core/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java b/core/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java index c53b0014ed..7f14a80703 100644 --- a/core/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java +++ b/core/src/main/java/org/bouncycastle/asn1/BERSequenceParser.java @@ -7,6 +7,7 @@ * * @deprecated Check for 'ASN1SequenceParser' instead */ +@Deprecated public class BERSequenceParser implements ASN1SequenceParser { diff --git a/core/src/main/java/org/bouncycastle/asn1/BERSetParser.java b/core/src/main/java/org/bouncycastle/asn1/BERSetParser.java index cc369dfcb9..8cb392fd9e 100644 --- a/core/src/main/java/org/bouncycastle/asn1/BERSetParser.java +++ b/core/src/main/java/org/bouncycastle/asn1/BERSetParser.java @@ -7,6 +7,7 @@ * * @deprecated Check for 'ASN1SetParser' instead */ +@Deprecated public class BERSetParser implements ASN1SetParser { diff --git a/core/src/main/java/org/bouncycastle/asn1/DERExternal.java b/core/src/main/java/org/bouncycastle/asn1/DERExternal.java index fced6d2bac..a075b20aee 100644 --- a/core/src/main/java/org/bouncycastle/asn1/DERExternal.java +++ b/core/src/main/java/org/bouncycastle/asn1/DERExternal.java @@ -20,6 +20,7 @@ public class DERExternal * * @deprecated Use {@link DERExternal#DERExternal(DERSequence)} instead. */ + @Deprecated public DERExternal(ASN1EncodableVector vector) { this(DERFactory.createSequence(vector)); diff --git a/core/src/main/java/org/bouncycastle/asn1/DERGenerator.java b/core/src/main/java/org/bouncycastle/asn1/DERGenerator.java index ecd00e5618..58e5cd10a3 100644 --- a/core/src/main/java/org/bouncycastle/asn1/DERGenerator.java +++ b/core/src/main/java/org/bouncycastle/asn1/DERGenerator.java @@ -83,35 +83,28 @@ void writeDEREncoded( byte[] bytes) throws IOException { - if (_tagged) + if (!_tagged) { - int tagNum = _tagNo | BERTags.CONTEXT_SPECIFIC; - - if (_isExplicit) - { - int newTag = _tagNo | BERTags.CONSTRUCTED | BERTags.CONTEXT_SPECIFIC; - - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - - writeDEREncoded(bOut, tag, bytes); - - writeDEREncoded(_out, newTag, bOut.toByteArray()); - } - else - { - if ((tag & BERTags.CONSTRUCTED) != 0) - { - writeDEREncoded(_out, tagNum | BERTags.CONSTRUCTED, bytes); - } - else - { - writeDEREncoded(_out, tagNum, bytes); - } - } + writeDEREncoded(_out, tag, bytes); + } + else if (_isExplicit) + { + /* + * X.690-0207 8.14.2. If implicit tagging [..] was not used [..], the encoding shall be constructed + * and the contents octets shall be the complete base encoding. + */ + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + writeDEREncoded(bOut, tag, bytes); + writeDEREncoded(_out, _tagNo | BERTags.CONTEXT_SPECIFIC | BERTags.CONSTRUCTED, bOut.toByteArray()); } else { - writeDEREncoded(_out, tag, bytes); + /* + * X.690-0207 8.14.3. If implicit tagging was used [..], then: a) the encoding shall be constructed + * if the base encoding is constructed, and shall be primitive otherwise; and b) the contents octets + * shall be [..] the contents octets of the base encoding. + */ + writeDEREncoded(_out, inheritConstructedFlag(_tagNo | BERTags.CONTEXT_SPECIFIC, tag), bytes); } } } diff --git a/core/src/main/java/org/bouncycastle/asn1/DEROctetString.java b/core/src/main/java/org/bouncycastle/asn1/DEROctetString.java index 6d11821ae0..9acac9f450 100644 --- a/core/src/main/java/org/bouncycastle/asn1/DEROctetString.java +++ b/core/src/main/java/org/bouncycastle/asn1/DEROctetString.java @@ -2,12 +2,56 @@ import java.io.IOException; +import org.bouncycastle.util.Arrays; + /** * Carrier class for a DER encoding OCTET STRING */ public class DEROctetString extends ASN1OctetString { + public static final DEROctetString EMPTY = new DEROctetString(EMPTY_OCTETS); + + public static DEROctetString fromContents(byte[] contents) + { + if (contents == null) + { + throw new NullPointerException("'contents' cannot be null"); + } + + return internalFromContents(contents); + } + + public static DEROctetString fromContentsOptional(byte[] contents) + { + return contents == null ? null : internalFromContents(contents); + } + + public static DEROctetString withContents(byte[] contents) + { + if (contents == null) + { + throw new NullPointerException("'contents' cannot be null"); + } + + return internalWithContents(contents); + } + + public static DEROctetString withContentsOptional(byte[] contents) + { + return contents == null ? null : internalWithContents(contents); + } + + static DEROctetString internalFromContents(byte[] contents) + { + return contents.length < 1 ? EMPTY : new DEROctetString(Arrays.clone(contents)); + } + + static DEROctetString internalWithContents(byte[] contents) + { + return contents.length < 1 ? EMPTY : new DEROctetString(contents); + } + /** * Base constructor. * diff --git a/core/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java b/core/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java index 33e1bca3da..7c537e5e0a 100644 --- a/core/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java +++ b/core/src/main/java/org/bouncycastle/asn1/DEROctetStringParser.java @@ -8,6 +8,7 @@ * * @deprecated Check for 'ASN1OctetStringParser' instead */ +@Deprecated public class DEROctetStringParser implements ASN1OctetStringParser { diff --git a/core/src/main/java/org/bouncycastle/asn1/DERSequence.java b/core/src/main/java/org/bouncycastle/asn1/DERSequence.java index 515aff7246..607ff289d0 100644 --- a/core/src/main/java/org/bouncycastle/asn1/DERSequence.java +++ b/core/src/main/java/org/bouncycastle/asn1/DERSequence.java @@ -11,11 +11,23 @@ public class DERSequence extends ASN1Sequence { + public static final DERSequence EMPTY = new DERSequence(); + public static DERSequence convert(ASN1Sequence seq) { return (DERSequence)seq.toDERObject(); } + public static DERSequence fromElementsOptional(ASN1Encodable[] elements) + { + if (elements == null) + { + return null; + } + + return elements.length < 1 ? EMPTY : new DERSequence(elements); + } + private int contentsLength = -1; /** diff --git a/core/src/main/java/org/bouncycastle/asn1/DLBitStringParser.java b/core/src/main/java/org/bouncycastle/asn1/DLBitStringParser.java index ce92398ebc..c4f4984bd9 100644 --- a/core/src/main/java/org/bouncycastle/asn1/DLBitStringParser.java +++ b/core/src/main/java/org/bouncycastle/asn1/DLBitStringParser.java @@ -8,6 +8,7 @@ * * @deprecated Check for 'ASN1BitStringParser' instead */ +@Deprecated public class DLBitStringParser implements ASN1BitStringParser { diff --git a/core/src/main/java/org/bouncycastle/asn1/DLExternal.java b/core/src/main/java/org/bouncycastle/asn1/DLExternal.java index 8424fc50d0..2b7c814d2a 100644 --- a/core/src/main/java/org/bouncycastle/asn1/DLExternal.java +++ b/core/src/main/java/org/bouncycastle/asn1/DLExternal.java @@ -20,6 +20,7 @@ public class DLExternal * * @deprecated Use {@link DLExternal#DLExternal(DLSequence)} instead. */ + @Deprecated public DLExternal(ASN1EncodableVector vector) { this(DLFactory.createSequence(vector)); diff --git a/core/src/main/java/org/bouncycastle/asn1/DLSequence.java b/core/src/main/java/org/bouncycastle/asn1/DLSequence.java index d510567733..56d525b9ad 100644 --- a/core/src/main/java/org/bouncycastle/asn1/DLSequence.java +++ b/core/src/main/java/org/bouncycastle/asn1/DLSequence.java @@ -8,6 +8,23 @@ public class DLSequence extends ASN1Sequence { + public static final DLSequence EMPTY = new DLSequence(); + + public static DLSequence convert(ASN1Sequence seq) + { + return (DLSequence)seq.toDLObject(); + } + + public static DLSequence fromElementsOptional(ASN1Encodable[] elements) + { + if (elements == null) + { + return null; + } + + return elements.length < 1 ? EMPTY : new DLSequence(elements); + } + private int contentsLength = -1; /** diff --git a/core/src/main/java/org/bouncycastle/asn1/DLSequenceParser.java b/core/src/main/java/org/bouncycastle/asn1/DLSequenceParser.java index 83d1a2c047..a5da9346e3 100644 --- a/core/src/main/java/org/bouncycastle/asn1/DLSequenceParser.java +++ b/core/src/main/java/org/bouncycastle/asn1/DLSequenceParser.java @@ -7,6 +7,7 @@ * * @deprecated Check for 'ASN1SequenceParser' instead */ +@Deprecated public class DLSequenceParser implements ASN1SequenceParser { diff --git a/core/src/main/java/org/bouncycastle/asn1/DLSetParser.java b/core/src/main/java/org/bouncycastle/asn1/DLSetParser.java index 4809f70194..f47357727b 100644 --- a/core/src/main/java/org/bouncycastle/asn1/DLSetParser.java +++ b/core/src/main/java/org/bouncycastle/asn1/DLSetParser.java @@ -7,6 +7,7 @@ * * @deprecated Check for 'ASN1SetParser' instead */ +@Deprecated public class DLSetParser implements ASN1SetParser { diff --git a/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java index 6c5db36169..a472a992f9 100644 --- a/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java +++ b/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java @@ -202,19 +202,63 @@ public interface BCObjectIdentifiers ASN1ObjectIdentifier sphincsPlus_interop = new ASN1ObjectIdentifier("1.3.9999.6"); + /** 1.3.9999.6.4.13 OQS_OID_SPHINCSSHA2128FSIMPLE */ ASN1ObjectIdentifier sphincsPlus_sha2_128f = new ASN1ObjectIdentifier("1.3.9999.6.4.13"); + /** 1.3.9999.6.4.16 OQS_OID_SPHINCSSHA2128SSIMPLE */ ASN1ObjectIdentifier sphincsPlus_sha2_128s = new ASN1ObjectIdentifier("1.3.9999.6.4.16"); + /** 1.3.9999.6.5.10 OQS_OID_SPHINCSSHA2192FSIMPLE */ ASN1ObjectIdentifier sphincsPlus_sha2_192f = new ASN1ObjectIdentifier("1.3.9999.6.5.10"); + /** 1.3.9999.6.5.12 OQS_OID_SPHINCSSHA2192SSIMPLE */ ASN1ObjectIdentifier sphincsPlus_sha2_192s = new ASN1ObjectIdentifier("1.3.9999.6.5.12"); + /** 1.3.9999.6.6.10 OQS_OID_SPHINCSSHA2256FSIMPLE */ ASN1ObjectIdentifier sphincsPlus_sha2_256f = new ASN1ObjectIdentifier("1.3.9999.6.6.10"); + /** 1.3.9999.6.6.12 OQS_OID_SPHINCSSHA2256SSIMPLE */ ASN1ObjectIdentifier sphincsPlus_sha2_256s = new ASN1ObjectIdentifier("1.3.9999.6.6.12"); + /** 1.3.9999.6.7.13 OQS_OID_SPHINCSSHAKE128FSIMPLE */ ASN1ObjectIdentifier sphincsPlus_shake_128f = new ASN1ObjectIdentifier("1.3.9999.6.7.13"); + /** 1.3.9999.6.7.16 OQS_OID_SPHINCSSHAKE128SSIMPLE */ ASN1ObjectIdentifier sphincsPlus_shake_128s = new ASN1ObjectIdentifier("1.3.9999.6.7.16"); + /** 1.3.9999.6.8.10 OQS_OID_SPHINCSSHAKE192FSIMPLE */ ASN1ObjectIdentifier sphincsPlus_shake_192f = new ASN1ObjectIdentifier("1.3.9999.6.8.10"); + /** 1.3.9999.6.8.12 OQS_OID_SPHINCSSHAKE192SSIMPLE */ ASN1ObjectIdentifier sphincsPlus_shake_192s = new ASN1ObjectIdentifier("1.3.9999.6.8.12"); + /** 1.3.9999.6.9.10 OQS_OID_SPHINCSSHAKE256FSIMPLE */ ASN1ObjectIdentifier sphincsPlus_shake_256f = new ASN1ObjectIdentifier("1.3.9999.6.9.10"); + /** 1.3.9999.6.9.12 OQS_OID_SPHINCSSHAKE256SSIMPLE */ ASN1ObjectIdentifier sphincsPlus_shake_256s = new ASN1ObjectIdentifier("1.3.9999.6.9.12"); + /** 1.3.9999.6.4.14 OQS_OID_P256_SPHINCSSHA2128FSIMPLE */ + ASN1ObjectIdentifier p256_sphincs_sha2_128f_simple = new ASN1ObjectIdentifier("1.3.9999.6.4.14"); + /** 1.3.9999.6.4.15 OQS_OID_RSA3072_SPHINCSSHA2128FSIMPLE */ + ASN1ObjectIdentifier rsa_3072_sphincs_sha2_128f_simple = new ASN1ObjectIdentifier("1.3.9999.6.4.15"); + /** 1.3.9999.6.4.17 OQS_OID_P256_SPHINCSSHA2128SSIMPLE */ + ASN1ObjectIdentifier p256_sphincs_sha2_128s_simple = new ASN1ObjectIdentifier("1.3.9999.6.4.17"); + /** 1.3.9999.6.4.18 OQS_OID_RSA3072_SPHINCSSHA2128SSIMPLE */ + ASN1ObjectIdentifier rsa_3072_sphincs_sha2_128s_simple = new ASN1ObjectIdentifier("1.3.9999.6.4.18"); + /** 1.3.9999.6.5.11 OQS_OID_P384_SPHINCSSHA2192FSIMPLE */ + ASN1ObjectIdentifier p384_sphincs_sha2_192f_simple = new ASN1ObjectIdentifier("1.3.9999.6.5.11"); + /** 1.3.9999.6.5.13 OQS_OID_P384_SPHINCSSHA2192SSIMPLE */ + ASN1ObjectIdentifier p384_sphincs_sha2192s_simple = new ASN1ObjectIdentifier("1.3.9999.6.5.13"); + /** 1.3.9999.6.6.11 OQS_OID_P521_SPHINCSSHA2256FSIMPLE */ + ASN1ObjectIdentifier p521_sphincs_sha2_256f_simple = new ASN1ObjectIdentifier("1.3.9999.6.6.11"); + /** 1.3.9999.6.6.13 OQS_OID_P521_SPHINCSSHA2256SSIMPLE */ + ASN1ObjectIdentifier p521_sphincs_sha2_256s_simple = new ASN1ObjectIdentifier("1.3.9999.6.6.13"); + /** 1.3.9999.6.7.14 OQS_OID_P256_SPHINCSSHAKE128FSIMPLE */ + ASN1ObjectIdentifier p256_sphincs_shake_128f_simple = new ASN1ObjectIdentifier("1.3.9999.6.7.14"); + /** 1.3.9999.6.7.15 OQS_OID_RSA3072_SPHINCSSHAKE128FSIMPLE */ + ASN1ObjectIdentifier rsa_3072_sphincs_shake_128f_simple = new ASN1ObjectIdentifier("1.3.9999.6.7.15"); + /** 1.3.9999.6.7.17 OQS_OID_P256_SPHINCSSHAKE128SSIMPLE */ + ASN1ObjectIdentifier p256_sphincs_shake_128s_simple = new ASN1ObjectIdentifier("1.3.9999.6.7.17"); + /** 1.3.9999.6.7.18 OQS_OID_RSA3072_SPHINCSSHAKE128SSIMPLE */ + ASN1ObjectIdentifier rsa_3072_sphincs_shake_128s_simple = new ASN1ObjectIdentifier("1.3.9999.6.7.18"); + /** 1.3.9999.6.8.11 OQS_OID_P384_SPHINCSSHAKE192FSIMPLE */ + ASN1ObjectIdentifier p384_sphincs_shake_192f_simple = new ASN1ObjectIdentifier("1.3.9999.6.8.11"); + /** 1.3.9999.6.8.13 OQS_OID_P384_SPHINCSSHAKE192SSIMPLE */ + ASN1ObjectIdentifier p384_sphincs_shake_192s_simple = new ASN1ObjectIdentifier("1.3.9999.6.8.13"); + /** 1.3.9999.6.9.11 OQS_OID_P521_SPHINCSSHAKE256FSIMPLE */ + ASN1ObjectIdentifier p521_sphincs_shake256f_simple = new ASN1ObjectIdentifier("1.3.9999.6.9.11"); + /** 1.3.9999.6.9.13 OQS_OID_P521_SPHINCSSHAKE256SSIMPLE */ + ASN1ObjectIdentifier p521_sphincs_shake256s_simple = new ASN1ObjectIdentifier("1.3.9999.6.9.13"); /** * Picnic @@ -237,18 +281,39 @@ public interface BCObjectIdentifiers ASN1ObjectIdentifier picnicl5full = picnic_key.branch("12"); ASN1ObjectIdentifier picnic_signature = picnic.branch("2"); + ASN1ObjectIdentifier picnic_with_sha512 = picnic_signature.branch("1"); ASN1ObjectIdentifier picnic_with_shake256 = picnic_signature.branch("2"); ASN1ObjectIdentifier picnic_with_sha3_512 = picnic_signature.branch("3"); - /* * Falcon */ ASN1ObjectIdentifier falcon = bc_sig.branch("7"); - ASN1ObjectIdentifier falcon_512 = new ASN1ObjectIdentifier("1.3.9999.3.6"); // falcon.branch("1"); - ASN1ObjectIdentifier falcon_1024 = new ASN1ObjectIdentifier("1.3.9999.3.9"); // falcon.branch("2"); + ASN1ObjectIdentifier old_falcon_512 = new ASN1ObjectIdentifier("1.3.9999.3.6"); // falcon.branch("1"); + ASN1ObjectIdentifier old_falcon_1024 = new ASN1ObjectIdentifier("1.3.9999.3.9"); // falcon.branch("2"); + + /** 1.3.9999.3.11 OQS_OID_FALCON512 */ + ASN1ObjectIdentifier falcon_512 = new ASN1ObjectIdentifier("1.3.9999.3.11"); + /** 1.3.9999.3.12 OQS_OID_P256_FALCON512 */ + ASN1ObjectIdentifier p256_falcon_512 = new ASN1ObjectIdentifier("1.3.9999.3.12"); + /** 1.3.9999.3.13 OQS_OID_RSA3072_FALCON512 */ + ASN1ObjectIdentifier rsa_3072_falcon_512 = new ASN1ObjectIdentifier("1.3.9999.3.13"); + /** 1.3.9999.3.14 OQS_OID_FALCON1024 */ + ASN1ObjectIdentifier falcon_1024 = new ASN1ObjectIdentifier("1.3.9999.3.14"); + /** 1.3.9999.3.15 OQS_OID_P521_FALCON1024 */ + ASN1ObjectIdentifier p521_falcon1024 = new ASN1ObjectIdentifier("1.3.9999.3.15"); + /** 1.3.9999.3.16 OQS_OID_FALCONPADDED512 */ + ASN1ObjectIdentifier falcon_padded_512 = new ASN1ObjectIdentifier("1.3.9999.3.16"); + /** 1.3.9999.3.17 OQS_OID_P256_FALCONPADDED512 */ + ASN1ObjectIdentifier p256_falcon_padded512 = new ASN1ObjectIdentifier("1.3.9999.3.17"); + /** 1.3.9999.3.18 OQS_OID_RSA3072_FALCONPADDED512 */ + ASN1ObjectIdentifier rsa_3072_falconpadded512 = new ASN1ObjectIdentifier("1.3.9999.3.18"); + /** 1.3.9999.3.19 OQS_OID_FALCONPADDED1024 */ + ASN1ObjectIdentifier falcon_padded_1024 = new ASN1ObjectIdentifier("1.3.9999.3.19"); + /** 1.3.9999.3.20 OQS_OID_P521_FALCONPADDED1024 */ + ASN1ObjectIdentifier p521_falcon_padded_1024 = new ASN1ObjectIdentifier("1.3.9999.3.20"); /* * Dilithium @@ -263,6 +328,84 @@ public interface BCObjectIdentifiers ASN1ObjectIdentifier dilithium3_aes = new ASN1ObjectIdentifier("1.3.6.1.4.1.2.267.11.6.5"); // dilithium.branch("5"); ASN1ObjectIdentifier dilithium5_aes = new ASN1ObjectIdentifier("1.3.6.1.4.1.2.267.11.8.7"); // dilithium.branch("6"); + /* + * ML-DSA + */ + ///** 2.16.840.1.101.3.4.3.17 OQS_OID_MLDSA44 */ + /** 1.3.9999.7.5 OQS_OID_P256_MLDSA44 */ + ASN1ObjectIdentifier p256_mldsa44 = new ASN1ObjectIdentifier("1.3.9999.7.5"); + /** 1.3.9999.7.6 OQS_OID_RSA3072_MLDSA44 */ + ASN1ObjectIdentifier rsa3072_mldsa44 = new ASN1ObjectIdentifier("1.3.9999.7.6"); + /** 2.16.840.1.114027.80.8.1.1 OQS_OID_MLDSA44_pss2048 */ + ASN1ObjectIdentifier mldsa44_pss2048 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1.1"); + /** 2.16.840.1.114027.80.8.1.2 OQS_OID_MLDSA44_rsa2048 */ + ASN1ObjectIdentifier mldsa44_rsa2048 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1.2"); + /** 2.16.840.1.114027.80.8.1.3 OQS_OID_MLDSA44_ed25519 */ + ASN1ObjectIdentifier mldsa44_ed25519 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1.3"); + /** 2.16.840.1.114027.80.8.1.4 OQS_OID_MLDSA44_p256 */ + ASN1ObjectIdentifier mldsa44_p256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1.4"); + /** 2.16.840.1.114027.80.8.1.5 OQS_OID_MLDSA44_bp256 */ + ASN1ObjectIdentifier mldsa44_bp256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1.5"); + ///** 2.16.840.1.101.3.4.3.18 OQS_OID_MLDSA65 */ + /** 1.3.9999.7.7 OQS_OID_P384_MLDSA65 */ + ASN1ObjectIdentifier p384_mldsa65 = new ASN1ObjectIdentifier("1.3.9999.7.7"); + /** 2.16.840.1.114027.80.8.1.6 OQS_OID_MLDSA65_pss3072 */ + ASN1ObjectIdentifier mldsa65_pss3072 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1.6"); + /** 2.16.840.1.114027.80.8.1.7 OQS_OID_MLDSA65_rsa3072 */ + ASN1ObjectIdentifier mldsa65_rsa3072 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1.7"); + /** 2.16.840.1.114027.80.8.1.8 OQS_OID_MLDSA65_p256 */ + ASN1ObjectIdentifier mldsa65_p256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1.8"); + /** 2.16.840.1.114027.80.8.1.9 OQS_OID_MLDSA65_bp256 */ + ASN1ObjectIdentifier mldsa65_bp256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1.9"); + /** 2.16.840.1.114027.80.8.1.10 OQS_OID_MLDSA65_ed25519 */ + ASN1ObjectIdentifier mldsa65_ed25519 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1.10"); + ///** 2.16.840.1.101.3.4.3.19 OQS_OID_MLDSA87 */ + /** 1.3.9999.7.8 OQS_OID_P521_MLDSA87 */ + ASN1ObjectIdentifier p521_mldsa87 = new ASN1ObjectIdentifier("1.3.9999.7.8"); + /** 2.16.840.1.114027.80.8.1.11 OQS_OID_MLDSA87_p384 */ + ASN1ObjectIdentifier mldsa87_p384 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1.11"); + /** 2.16.840.1.114027.80.8.1.12 OQS_OID_MLDSA87_bp384 */ + ASN1ObjectIdentifier mldsa87_bp384 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1.12"); + /** 2.16.840.1.114027.80.8.1.13 OQS_OID_MLDSA87_ed448 */ + ASN1ObjectIdentifier mldsa87_ed448 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1.13"); + + /** 2.16.840.1.114027.80.9.1.0 id-MLDSA44-RSA2048-PSS-SHA256 */ + ASN1ObjectIdentifier id_MLDSA44_RSA2048_PSS_SHA256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.0"); + /** 2.16.840.1.114027.80.9.1.1 id-MLDSA44-RSA2048-PKCS15-SHA256 */ + ASN1ObjectIdentifier id_MLDSA44_RSA2048_PKCS15_SHA256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.1"); + /** 2.16.840.1.114027.80.9.1.2 id-MLDSA44-Ed25519-SHA512 */ + ASN1ObjectIdentifier id_MLDSA44_Ed25519_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.2"); + /** 2.16.840.1.114027.80.9.1.3 id-MLDSA44-ECDSA-P256-SHA256 */ + ASN1ObjectIdentifier id_MLDSA44_ECDSA_P256_SHA256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.3"); + /** 2.16.840.1.114027.80.9.1.4 id-MLDSA65-RSA3072-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA3072_PSS_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.4"); + /** 2.16.840.1.114027.80.9.1.5 id-MLDSA65-RSA3072-PKCS15-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA3072_PKCS15_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.5"); + /** 2.16.840.1.114027.80.9.1.6 id-MLDSA65-RSA4096-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA4096_PSS_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.6"); + /** 2.16.840.1.114027.80.9.1.7 id-MLDSA65-RSA4096-PKCS15-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA4096_PKCS15_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.7"); + /** 2.16.840.1.114027.80.9.1.8 id-MLDSA65-ECDSA-P256-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_ECDSA_P256_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.8"); + /** 2.16.840.1.114027.80.9.1.9 id-MLDSA65-ECDSA-P384-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_ECDSA_P384_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.9"); + /** 2.16.840.1.114027.80.9.1.10 id-MLDSA65-ECDSA-brainpoolP256r1-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_ECDSA_brainpoolP256r1_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.10"); + /** 2.16.840.1.114027.80.9.1.11 id-MLDSA65-Ed25519-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_Ed25519_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.11"); + /** 2.16.840.1.114027.80.9.1.12 id-MLDSA87-ECDSA-P384-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_ECDSA_P384_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.12"); + /** 2.16.840.1.114027.80.9.1.13 id-MLDSA87-ECDSA-brainpoolP384r1-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_ECDSA_brainpoolP384r1_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.13"); + /** 2.16.840.1.114027.80.9.1.14 id-MLDSA87-Ed448-SHAKE256 */ + ASN1ObjectIdentifier id_MLDSA87_Ed448_SHAKE256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.14"); + /** 2.16.840.1.114027.80.9.1.15 id-MLDSA87-RSA3072-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_RSA3072_PSS_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.15"); + /** 2.16.840.1.114027.80.9.1.16 id-MLDSA87-RSA4096-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_RSA4096_PSS_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.16"); + /** 2.16.840.1.114027.80.9.1.17 id-MLDSA87-ECDSA-P521-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_ECDSA_P521_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.17"); + /* * Rainbow */ @@ -316,7 +459,6 @@ public interface BCObjectIdentifiers ASN1ObjectIdentifier mceliece8192128_r3 = pqc_kem_mceliece.branch("9"); ASN1ObjectIdentifier mceliece8192128f_r3 = pqc_kem_mceliece.branch("10"); - /** * Frodo */ @@ -403,7 +545,7 @@ public interface BCObjectIdentifiers ASN1ObjectIdentifier ntrulpr953 = pqc_kem_ntrulprime.branch("4"); ASN1ObjectIdentifier ntrulpr1013 = pqc_kem_ntrulprime.branch("5"); ASN1ObjectIdentifier ntrulpr1277 = pqc_kem_ntrulprime.branch("6"); - + ASN1ObjectIdentifier pqc_kem_sntruprime = pqc_kem_ntruprime.branch("2"); ASN1ObjectIdentifier sntrup653 = pqc_kem_sntruprime.branch("1"); ASN1ObjectIdentifier sntrup761 = pqc_kem_sntruprime.branch("2"); @@ -411,7 +553,7 @@ public interface BCObjectIdentifiers ASN1ObjectIdentifier sntrup953 = pqc_kem_sntruprime.branch("4"); ASN1ObjectIdentifier sntrup1013 = pqc_kem_sntruprime.branch("5"); ASN1ObjectIdentifier sntrup1277 = pqc_kem_sntruprime.branch("6"); - + /** * BIKE **/ @@ -429,4 +571,174 @@ public interface BCObjectIdentifiers ASN1ObjectIdentifier hqc128 = pqc_kem_hqc.branch("1"); ASN1ObjectIdentifier hqc192 = pqc_kem_hqc.branch("2"); ASN1ObjectIdentifier hqc256 = pqc_kem_hqc.branch("3"); + + /** + * Mayo + */ + ASN1ObjectIdentifier mayo = bc_sig.branch("10"); + ASN1ObjectIdentifier mayo1 = mayo.branch("1"); + ASN1ObjectIdentifier mayo2 = mayo.branch("2"); + ASN1ObjectIdentifier mayo3 = mayo.branch("3"); + ASN1ObjectIdentifier mayo5 = mayo.branch("4"); + /** 1.3.9999.8.1.3 OQS_OID_MAYO1 */ + ASN1ObjectIdentifier mayo_1 = new ASN1ObjectIdentifier("1.3.9999.8.1.3"); + /** 1.3.9999.8.1.4 OQS_OID_P256_MAYO1 */ + ASN1ObjectIdentifier p256_mayo1 = new ASN1ObjectIdentifier("1.3.9999.8.1.4"); + /** 1.3.9999.8.2.3 OQS_OID_MAYO2 */ + ASN1ObjectIdentifier mayo_2 = new ASN1ObjectIdentifier("1.3.9999.8.2.3"); + /** 1.3.9999.8.2.4 OQS_OID_P256_MAYO2 */ + ASN1ObjectIdentifier p256_mayo2 = new ASN1ObjectIdentifier("1.3.9999.8.2.4"); + /** 1.3.9999.8.3.3 OQS_OID_MAYO3 */ + ASN1ObjectIdentifier mayo_3 = new ASN1ObjectIdentifier("1.3.9999.8.3.3"); + /** 1.3.9999.8.3.4 OQS_OID_P384_MAYO3 */ + ASN1ObjectIdentifier p384_mayo3 = new ASN1ObjectIdentifier("1.3.9999.8.3.4"); + /** 1.3.9999.8.5.3 OQS_OID_MAYO5 */ + ASN1ObjectIdentifier mayo_5 = new ASN1ObjectIdentifier("1.3.9999.8.5.3"); + /** 1.3.9999.8.5.4 OQS_OID_P521_MAYO5 */ + ASN1ObjectIdentifier p521_mayo5 = new ASN1ObjectIdentifier("1.3.9999.8.5.4"); + + /** + * cross + */ +// /** 1.3.6.1.4.1.62245.2.1.1.2 OQS_OID_CROSSRSDP128BALANCED */ +// ASN1ObjectIdentifier crossrsdp_128balanced = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.1.2"); +// /** 1.3.6.1.4.1.62245.2.1.2.2 OQS_OID_CROSSRSDP128FAST */ +// ASN1ObjectIdentifier crossrsdp_128fast = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.2.2"); +// /** 1.3.6.1.4.1.62245.2.1.3.2 OQS_OID_CROSSRSDP128SMALL */ +// ASN1ObjectIdentifier crossrsdp_128small = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.3.2"); +// /** 1.3.6.1.4.1.62245.2.1.4.2 OQS_OID_CROSSRSDP192BALANCED */ +// ASN1ObjectIdentifier crossrsdp_192balanced = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.4.2"); +// /** 1.3.6.1.4.1.62245.2.1.5.2 OQS_OID_CROSSRSDP192FAST */ +// ASN1ObjectIdentifier crossrsdp_192fast = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.5.2"); +// /** 1.3.6.1.4.1.62245.2.1.6.2 OQS_OID_CROSSRSDP192SMALL */ +// ASN1ObjectIdentifier crossrsdp_192small = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.6.2"); +// /** 1.3.6.1.4.1.62245.2.1.9.2 OQS_OID_CROSSRSDP256SMALL */ +// ASN1ObjectIdentifier crossrsdp256small = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.9.2"); +// /** 1.3.6.1.4.1.62245.2.1.10.2 OQS_OID_CROSSRSDPG128BALANCED */ +// ASN1ObjectIdentifier crossrsdpg_128balanced = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.10.2"); +// /** 1.3.6.1.4.1.62245.2.1.11.2 OQS_OID_CROSSRSDPG128FAST */ +// ASN1ObjectIdentifier crossrsdpg_128fast = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.11.2"); +// /** 1.3.6.1.4.1.62245.2.1.12.2 OQS_OID_CROSSRSDPG128SMALL */ +// ASN1ObjectIdentifier crossrsdpg_128small = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.12.2"); +// /** 1.3.6.1.4.1.62245.2.1.13.2 OQS_OID_CROSSRSDPG192BALANCED */ +// ASN1ObjectIdentifier crossrsdpg_192balanced = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.13.2"); +// /** 1.3.6.1.4.1.62245.2.1.14.2 OQS_OID_CROSSRSDPG192FAST */ +// ASN1ObjectIdentifier crossrsdpg_192fast = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.14.2"); +// /** 1.3.6.1.4.1.62245.2.1.15.2 OQS_OID_CROSSRSDPG192SMALL */ +// ASN1ObjectIdentifier crossrsdpg_192small = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.15.2"); +// /** 1.3.6.1.4.1.62245.2.1.16.2 OQS_OID_CROSSRSDPG256BALANCED */ +// ASN1ObjectIdentifier crossrsdpg_256balanced = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.16.2"); +// /** 1.3.6.1.4.1.62245.2.1.17.2 OQS_OID_CROSSRSDPG256FAST */ +// ASN1ObjectIdentifier crossrsdpg_256fast = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.17.2"); +// /** 1.3.6.1.4.1.62245.2.1.18.2 OQS_OID_CROSSRSDPG256SMALL */ +// ASN1ObjectIdentifier crossrsdpg_256small = new ASN1ObjectIdentifier("1.3.6.1.4.1.62245.2.1.18.2"); + + /** + * OV + * */ +// /** 1.3.9999.9.1.1 OQS_OID_OV_IS */ +// ASN1ObjectIdentifier ov_is = new ASN1ObjectIdentifier("1.3.9999.9.1.1"); +// /** 1.3.9999.9.1.2 OQS_OID_P256_OV_IS */ +// ASN1ObjectIdentifier p256_ov_is = new ASN1ObjectIdentifier("1.3.9999.9.1.2"); +// /** 1.3.9999.9.2.1 OQS_OID_OV_IP */ +// ASN1ObjectIdentifier ov_ip = new ASN1ObjectIdentifier("1.3.9999.9.2.1"); +// /** 1.3.9999.9.2.2 OQS_OID_P256_OV_IP */ +// ASN1ObjectIdentifier p256_ov_ip = new ASN1ObjectIdentifier("1.3.9999.9.2.2"); +// /** 1.3.9999.9.3.1 OQS_OID_OV_III */ +// ASN1ObjectIdentifier ov_iii = new ASN1ObjectIdentifier("1.3.9999.9.3.1"); +// /** 1.3.9999.9.3.2 OQS_OID_P384_OV_III */ +// ASN1ObjectIdentifier p384_ov_iii = new ASN1ObjectIdentifier("1.3.9999.9.3.2"); +// /** 1.3.9999.9.4.1 OQS_OID_OV_V */ +// ASN1ObjectIdentifier ov_v = new ASN1ObjectIdentifier("1.3.9999.9.4.1"); +// /** 1.3.9999.9.4.2 OQS_OID_P521_OV_V */ +// ASN1ObjectIdentifier p521_ov_v = new ASN1ObjectIdentifier("1.3.9999.9.4.2"); +// /** 1.3.9999.9.5.1 OQS_OID_OV_IS_PKC */ +// ASN1ObjectIdentifier ov_is_pkc = new ASN1ObjectIdentifier("1.3.9999.9.5.1"); +// /** 1.3.9999.9.5.2 OQS_OID_P256_OV_IS_PKC */ +// ASN1ObjectIdentifier p256_ov_is_pkc = new ASN1ObjectIdentifier("1.3.9999.9.5.2"); +// /** 1.3.9999.9.6.1 OQS_OID_OV_IP_PKC */ +// ASN1ObjectIdentifier ov_ip_pkc = new ASN1ObjectIdentifier("1.3.9999.9.6.1"); +// /** 1.3.9999.9.6.2 OQS_OID_P256_OV_IP_PKC */ +// ASN1ObjectIdentifier p256_ov_ip_pkc = new ASN1ObjectIdentifier("1.3.9999.9.6.2"); +// /** 1.3.9999.9.7.1 OQS_OID_OV_III_PKC */ +// ASN1ObjectIdentifier ov_iii_pkc = new ASN1ObjectIdentifier("1.3.9999.9.7.1"); +// /** 1.3.9999.9.7.2 OQS_OID_P384_OV_III_PKC */ +// ASN1ObjectIdentifier p384_ov_iii_pkc = new ASN1ObjectIdentifier("1.3.9999.9.7.2"); +// /** 1.3.9999.9.8.1 OQS_OID_OV_V_PKC */ +// ASN1ObjectIdentifier ov_v_pkc = new ASN1ObjectIdentifier("1.3.9999.9.8.1"); +// /** 1.3.9999.9.8.2 OQS_OID_P521_OV_V_PKC */ +// ASN1ObjectIdentifier p521_ov_v_pkc = new ASN1ObjectIdentifier("1.3.9999.9.8.2"); +// /** 1.3.9999.9.9.1 OQS_OID_OV_IS_PKC_SKC */ +// ASN1ObjectIdentifier ov_is_pkc_skc = new ASN1ObjectIdentifier("1.3.9999.9.9.1"); +// /** 1.3.9999.9.9.2 OQS_OID_P256_OV_IS_PKC_SKC */ +// ASN1ObjectIdentifier p256_ov_is_pkc_skc = new ASN1ObjectIdentifier("1.3.9999.9.9.2"); +// /** 1.3.9999.9.10.1 OQS_OID_OV_IP_PKC_SKC */ +// ASN1ObjectIdentifier ov_ip_pkc_skc = new ASN1ObjectIdentifier("1.3.9999.9.10.1"); +// /** 1.3.9999.9.10.2 OQS_OID_P256_OV_IP_PKC_SKC */ +// ASN1ObjectIdentifier p256_ov_ip_pkc_skc = new ASN1ObjectIdentifier("1.3.9999.9.10.2"); +// /** 1.3.9999.9.11.1 OQS_OID_OV_III_PKC_SKC */ +// ASN1ObjectIdentifier ov_iii_pkc_skc = new ASN1ObjectIdentifier("1.3.9999.9.11.1"); +// /** 1.3.9999.9.11.2 OQS_OID_P384_OV_III_PKC_SKC */ +// ASN1ObjectIdentifier p384_ov_iii_pkc_skc = new ASN1ObjectIdentifier("1.3.9999.9.11.2"); +// /** 1.3.9999.9.12.1 OQS_OID_OV_V_PKC_SKC */ +// ASN1ObjectIdentifier ov_v_pkc_skc = new ASN1ObjectIdentifier("1.3.9999.9.12.1"); +// /** 1.3.9999.9.12.2 OQS_OID_P521_OV_V_PKC_SKC */ +// ASN1ObjectIdentifier p521_ov_v_pkc_skc = new ASN1ObjectIdentifier("1.3.9999.9.12.2"); + + /** + * Snova + */ + ASN1ObjectIdentifier snova = bc_sig.branch("11"); + ASN1ObjectIdentifier snova_24_5_4_ssk = snova.branch("1"); + ASN1ObjectIdentifier snova_24_5_4_esk = snova.branch("2"); + ASN1ObjectIdentifier snova_24_5_4_shake_ssk = snova.branch("3"); + ASN1ObjectIdentifier snova_24_5_4_shake_esk = snova.branch("4"); + ASN1ObjectIdentifier snova_24_5_5_ssk = snova.branch("5"); + ASN1ObjectIdentifier snova_24_5_5_esk = snova.branch("6"); + ASN1ObjectIdentifier snova_24_5_5_shake_ssk = snova.branch("7"); + ASN1ObjectIdentifier snova_24_5_5_shake_esk = snova.branch("8"); + ASN1ObjectIdentifier snova_25_8_3_ssk = snova.branch("9"); + ASN1ObjectIdentifier snova_25_8_3_esk = snova.branch("10"); + ASN1ObjectIdentifier snova_25_8_3_shake_ssk = snova.branch("11"); + ASN1ObjectIdentifier snova_25_8_3_shake_esk = snova.branch("12"); + ASN1ObjectIdentifier snova_29_6_5_ssk = snova.branch("13"); + ASN1ObjectIdentifier snova_29_6_5_esk = snova.branch("14"); + ASN1ObjectIdentifier snova_29_6_5_shake_ssk = snova.branch("15"); + ASN1ObjectIdentifier snova_29_6_5_shake_esk = snova.branch("16"); + ASN1ObjectIdentifier snova_37_8_4_ssk = snova.branch("17"); + ASN1ObjectIdentifier snova_37_8_4_esk = snova.branch("18"); + ASN1ObjectIdentifier snova_37_8_4_shake_ssk = snova.branch("19"); + ASN1ObjectIdentifier snova_37_8_4_shake_esk = snova.branch("20"); + ASN1ObjectIdentifier snova_37_17_2_ssk = snova.branch("21"); + ASN1ObjectIdentifier snova_37_17_2_esk = snova.branch("22"); + ASN1ObjectIdentifier snova_37_17_2_shake_ssk = snova.branch("23"); + ASN1ObjectIdentifier snova_37_17_2_shake_esk = snova.branch("24"); + ASN1ObjectIdentifier snova_49_11_3_ssk = snova.branch("25"); + ASN1ObjectIdentifier snova_49_11_3_esk = snova.branch("26"); + ASN1ObjectIdentifier snova_49_11_3_shake_ssk = snova.branch("27"); + ASN1ObjectIdentifier snova_49_11_3_shake_esk = snova.branch("28"); + ASN1ObjectIdentifier snova_56_25_2_ssk = snova.branch("29"); + ASN1ObjectIdentifier snova_56_25_2_esk = snova.branch("30"); + ASN1ObjectIdentifier snova_56_25_2_shake_ssk = snova.branch("31"); + ASN1ObjectIdentifier snova_56_25_2_shake_esk = snova.branch("32"); + ASN1ObjectIdentifier snova_60_10_4_ssk = snova.branch("33"); + ASN1ObjectIdentifier snova_60_10_4_esk = snova.branch("34"); + ASN1ObjectIdentifier snova_60_10_4_shake_ssk = snova.branch("35"); + ASN1ObjectIdentifier snova_60_10_4_shake_esk = snova.branch("36"); + ASN1ObjectIdentifier snova_66_15_3_ssk = snova.branch("37"); + ASN1ObjectIdentifier snova_66_15_3_esk = snova.branch("38"); + ASN1ObjectIdentifier snova_66_15_3_shake_ssk = snova.branch("39"); + ASN1ObjectIdentifier snova_66_15_3_shake_esk = snova.branch("40"); + ASN1ObjectIdentifier snova_75_33_2_ssk = snova.branch("41"); + ASN1ObjectIdentifier snova_75_33_2_esk = snova.branch("42"); + ASN1ObjectIdentifier snova_75_33_2_shake_ssk = snova.branch("43"); + ASN1ObjectIdentifier snova_75_33_2_shake_esk = snova.branch("44"); + + /** + * NTRU+ + * */ + ASN1ObjectIdentifier ntruPlus = bc_sig.branch("15"); + ASN1ObjectIdentifier ntruPlus768 = ntruPlus.branch("1"); + ASN1ObjectIdentifier ntruPlus864 = ntruPlus.branch("2"); + ASN1ObjectIdentifier ntruPlus1152 = ntruPlus.branch("3"); } diff --git a/core/src/main/java/org/bouncycastle/asn1/bc/LinkedCertificate.java b/core/src/main/java/org/bouncycastle/asn1/bc/LinkedCertificate.java index d812087700..8041fe78c9 100644 --- a/core/src/main/java/org/bouncycastle/asn1/bc/LinkedCertificate.java +++ b/core/src/main/java/org/bouncycastle/asn1/bc/LinkedCertificate.java @@ -59,7 +59,7 @@ private LinkedCertificate(ASN1Sequence seq) switch (tagged.getTagNo()) { case 0: - certIssuer = X500Name.getInstance(tagged, false); + certIssuer = X500Name.getInstance(tagged, true); // CHOICE break; case 1: cACerts = GeneralNames.getInstance(tagged, false); @@ -114,7 +114,7 @@ public ASN1Primitive toASN1Primitive() if (certIssuer != null) { - v.add(new DERTaggedObject(false, 0, certIssuer)); + v.add(new DERTaggedObject(true, 0, certIssuer)); // CHOICE } if (cACerts != null) { diff --git a/core/src/main/java/org/bouncycastle/asn1/cryptopro/ECGOST3410ParamSetParameters.java b/core/src/main/java/org/bouncycastle/asn1/cryptopro/ECGOST3410ParamSetParameters.java index d084fa6957..ef750f532d 100644 --- a/core/src/main/java/org/bouncycastle/asn1/cryptopro/ECGOST3410ParamSetParameters.java +++ b/core/src/main/java/org/bouncycastle/asn1/cryptopro/ECGOST3410ParamSetParameters.java @@ -51,7 +51,7 @@ public ECGOST3410ParamSetParameters( this.b = new ASN1Integer(b); this.p = new ASN1Integer(p); this.q = new ASN1Integer(q); - this.x = new ASN1Integer(x); + this.x = ASN1Integer.valueOf(x); this.y = new ASN1Integer(y); } diff --git a/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410NamedParameters.java b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410NamedParameters.java index 6c398b5df4..5ef811c6af 100644 --- a/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410NamedParameters.java +++ b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410NamedParameters.java @@ -15,7 +15,7 @@ public class GOST3410NamedParameters static final Hashtable params = new Hashtable(); static final Hashtable names = new Hashtable(); - static private GOST3410ParamSetParameters cryptoProA = new GOST3410ParamSetParameters( + private static final GOST3410ParamSetParameters cryptoProA = new GOST3410ParamSetParameters( 1024, new BigInteger("127021248288932417465907042777176443525787653508916535812817507265705031260985098497423188333483401180925999995120988934130659205614996724254121049274349357074920312769561451689224110579311248812610229678534638401693520013288995000362260684222750813532307004517341633685004541062586971416883686778842537820383"), new BigInteger("68363196144955700784444165611827252895102170888761442055095051287550314083023"), @@ -32,7 +32,7 @@ public class GOST3410NamedParameters ); - static private GOST3410ParamSetParameters cryptoProB = new GOST3410ParamSetParameters( + private static final GOST3410ParamSetParameters cryptoProB = new GOST3410ParamSetParameters( 1024, new BigInteger("139454871199115825601409655107690713107041707059928031797758001454375765357722984094124368522288239833039114681648076688236921220737322672160740747771700911134550432053804647694904686120113087816240740184800477047157336662926249423571248823968542221753660143391485680840520336859458494803187341288580489525163"), new BigInteger("79885141663410976897627118935756323747307951916507639758300472692338873533959"), @@ -53,7 +53,7 @@ public class GOST3410NamedParameters //} ); - static private GOST3410ParamSetParameters cryptoProXchA = new GOST3410ParamSetParameters( + private static final GOST3410ParamSetParameters cryptoProXchA = new GOST3410ParamSetParameters( 1024, new BigInteger("142011741597563481196368286022318089743276138395243738762872573441927459393512718973631166078467600360848946623567625795282774719212241929071046134208380636394084512691828894000571524625445295769349356752728956831541775441763139384457191755096847107846595662547942312293338483924514339614727760681880609734239"), new BigInteger("91771529896554605945588149018382750217296858393520724172743325725474374979801"), diff --git a/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410ParamSetParameters.java b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410ParamSetParameters.java index 58089e00dc..d915ce138a 100644 --- a/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410ParamSetParameters.java +++ b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410ParamSetParameters.java @@ -95,7 +95,7 @@ public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(4); - v.add(new ASN1Integer(keySize)); + v.add(ASN1Integer.valueOf(keySize)); v.add(p); v.add(q); v.add(a); diff --git a/core/src/main/java/org/bouncycastle/asn1/gm/GMObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/gm/GMObjectIdentifiers.java index fa3048a5dc..7fc55db289 100644 --- a/core/src/main/java/org/bouncycastle/asn1/gm/GMObjectIdentifiers.java +++ b/core/src/main/java/org/bouncycastle/asn1/gm/GMObjectIdentifiers.java @@ -50,18 +50,18 @@ public interface GMObjectIdentifiers /** * <Information security technology — Cryptographic application identifier criterion specification> - * <url>http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=252CF0F72A7BE339A56DEA7D774E8994</url>, + * <url>http://c.gb688.cn/bzgk/gb/showGb?type=online&hcno=252CF0F72A7BE339A56DEA7D774E8994</url>, * Page 21 only cover from 301.1 to 301.3 - * */ - ASN1ObjectIdentifier wapip192v1 = sm_scheme.branch("301.101"); + */ + ASN1ObjectIdentifier wapip192v1 = sm_scheme.branch("301.101"); /** * <WAPI certificate management—Part 5: Example of certificate format (draft)> * <url>http://www.chinabwips.org.cn/zqyjgs1.htm</url> and * <url>http://www.chinabwips.org.cn/doc/101.pdf</url>, * Page 9 and page 10 states the OID of ECDSA-192 algorithm based on SHA-256 is 1.2.156.11235.1.1.1 - * */ - ASN1ObjectIdentifier wapi192v1 = new ASN1ObjectIdentifier("1.2.156.11235.1.1.1"); - ASN1ObjectIdentifier wapi192v1_parameters = new ASN1ObjectIdentifier("1.2.156.11235.1.1.2.1"); + */ + ASN1ObjectIdentifier wapi192v1 = new ASN1ObjectIdentifier("1.2.156.11235.1.1.1"); + ASN1ObjectIdentifier wapi192v1_parameters = new ASN1ObjectIdentifier("1.2.156.11235.1.1.2.1"); ASN1ObjectIdentifier sm2encrypt_recommendedParameters = sm2encrypt.branch("1"); ASN1ObjectIdentifier sm2encrypt_specifiedParameters = sm2encrypt.branch("2"); @@ -71,8 +71,8 @@ public interface GMObjectIdentifiers ASN1ObjectIdentifier sm2encrypt_with_sha256 = sm2encrypt.branch("2.4"); ASN1ObjectIdentifier sm2encrypt_with_sha384 = sm2encrypt.branch("2.5"); ASN1ObjectIdentifier sm2encrypt_with_sha512 = sm2encrypt.branch("2.6"); - ASN1ObjectIdentifier sm2encrypt_with_rmd160 = sm2encrypt.branch("2.7"); - ASN1ObjectIdentifier sm2encrypt_with_whirlpool =sm2encrypt.branch("2.8"); + ASN1ObjectIdentifier sm2encrypt_with_rmd160 = sm2encrypt.branch("2.7"); + ASN1ObjectIdentifier sm2encrypt_with_whirlpool = sm2encrypt.branch("2.8"); ASN1ObjectIdentifier sm2encrypt_with_blake2b512 = sm2encrypt.branch("2.9"); ASN1ObjectIdentifier sm2encrypt_with_blake2s256 = sm2encrypt.branch("2.10"); ASN1ObjectIdentifier sm2encrypt_with_md5 = sm2encrypt.branch("2.11"); diff --git a/core/src/main/java/org/bouncycastle/asn1/nist/KMACwithSHAKE128_params.java b/core/src/main/java/org/bouncycastle/asn1/nist/KMACwithSHAKE128_params.java index 129034b649..15cbc572d0 100644 --- a/core/src/main/java/org/bouncycastle/asn1/nist/KMACwithSHAKE128_params.java +++ b/core/src/main/java/org/bouncycastle/asn1/nist/KMACwithSHAKE128_params.java @@ -101,7 +101,7 @@ public ASN1Primitive toASN1Primitive() if (outputLength != DEF_LENGTH) { - v.add(new ASN1Integer(outputLength)); + v.add(ASN1Integer.valueOf(outputLength)); } if (customizationString.length != 0) diff --git a/core/src/main/java/org/bouncycastle/asn1/nist/KMACwithSHAKE256_params.java b/core/src/main/java/org/bouncycastle/asn1/nist/KMACwithSHAKE256_params.java index 390c9039ac..76963fa35b 100644 --- a/core/src/main/java/org/bouncycastle/asn1/nist/KMACwithSHAKE256_params.java +++ b/core/src/main/java/org/bouncycastle/asn1/nist/KMACwithSHAKE256_params.java @@ -101,7 +101,7 @@ public ASN1Primitive toASN1Primitive() if (outputLength != DEF_LENGTH) { - v.add(new ASN1Integer(outputLength)); + v.add(ASN1Integer.valueOf(outputLength)); } if (customizationString.length != 0) diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java index ed1eec6892..bc4f597737 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/CertStatus.java @@ -104,6 +104,8 @@ public ASN1Encodable getStatus() * good [0] IMPLICIT NULL, * revoked [1] IMPLICIT RevokedInfo, * unknown [2] IMPLICIT UnknownInfo } + * + * UnknownInfo ::= NULL * */ public ASN1Primitive toASN1Primitive() diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/ResponseData.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/ResponseData.java index 9de94728eb..2a05b4c688 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ocsp/ResponseData.java +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/ResponseData.java @@ -26,8 +26,8 @@ public class ResponseData extends ASN1Object { - private static final ASN1Integer V1 = new ASN1Integer(0); - + private static final ASN1Integer V1 = ASN1Integer.ZERO; + private boolean versionPresent; private ASN1Integer version; diff --git a/core/src/main/java/org/bouncycastle/asn1/ocsp/TBSRequest.java b/core/src/main/java/org/bouncycastle/asn1/ocsp/TBSRequest.java index 28c64290c7..7b5f8cce07 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ocsp/TBSRequest.java +++ b/core/src/main/java/org/bouncycastle/asn1/ocsp/TBSRequest.java @@ -15,7 +15,7 @@ public class TBSRequest extends ASN1Object { - private static final ASN1Integer V1 = new ASN1Integer(0); + private static final ASN1Integer V1 = ASN1Integer.ZERO; ASN1Integer version; GeneralName requestorName; diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java index b092bb8d15..b60e44f9bb 100644 --- a/core/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java @@ -36,7 +36,7 @@ public class CertificationRequestInfo extends ASN1Object { - ASN1Integer version = new ASN1Integer(0); + ASN1Integer version = ASN1Integer.ZERO; X500Name subject; SubjectPublicKeyInfo subjectPKInfo; ASN1Set attributes = null; diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java index aeb8f01e6e..bd56af938f 100644 --- a/core/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/DHParameter.java @@ -25,7 +25,7 @@ public DHParameter( if (l != 0) { - this.l = new ASN1Integer(l); + this.l = ASN1Integer.valueOf(l); } else { diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java index d1901fd3c0..5cc30a54fc 100644 --- a/core/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/EncryptedData.java @@ -102,6 +102,6 @@ public ASN1OctetString getContent() public ASN1Primitive toASN1Primitive() { - return new BERSequence(new ASN1Integer(0), data); + return new BERSequence(ASN1Integer.ZERO, data); } } diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java index 055f827b4d..6553430109 100644 --- a/core/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/PBEParameter.java @@ -25,7 +25,7 @@ public PBEParameter( throw new IllegalArgumentException("salt length must be 8"); } this.salt = new DEROctetString(salt); - this.iterations = new ASN1Integer(iterations); + this.iterations = ASN1Integer.valueOf(iterations); } private PBEParameter( diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java index a59d16c653..882e046c4d 100644 --- a/core/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/PBKDF2Params.java @@ -102,11 +102,11 @@ public PBKDF2Params( AlgorithmIdentifier prf) { this.octStr = new DEROctetString(Arrays.clone(salt)); - this.iterationCount = new ASN1Integer(iterationCount); + this.iterationCount = ASN1Integer.valueOf(iterationCount); if (keyLength > 0) { - this.keyLength = new ASN1Integer(keyLength); + this.keyLength = ASN1Integer.valueOf(keyLength); } else { diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java index 2d9c94a2f7..b3fab3fded 100644 --- a/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java @@ -21,7 +21,7 @@ public PKCS12PBEParams( int iterations) { this.iv = new DEROctetString(salt); - this.iterations = new ASN1Integer(iterations); + this.iterations = ASN1Integer.valueOf(iterations); } private PKCS12PBEParams( diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java index ab1d5d25ba..0606ec0a59 100644 --- a/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java @@ -195,6 +195,7 @@ public interface PKCSObjectIdentifiers /** PKCS#9: 1.2.840.113549.1.9.22.1 * @deprecated use x509Certificate instead */ + @Deprecated ASN1ObjectIdentifier x509certType = pkcs_9.branch("22.1"); /** PKCS#9: 1.2.840.113549.1.9.22 */ @@ -224,6 +225,19 @@ public interface PKCSObjectIdentifiers /** PKCS#9: 1.2.840.113549.1.9.15.3 -- smime capability */ ASN1ObjectIdentifier sMIMECapabilitiesVersions = pkcs_9.branch("15.3"); + // + // id-mod OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) + // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) mod(0)} + // + /** RFC 4010: SeedEncryptionAlgorithmInCMS; OID 1.2.840.113549.1.9.16.0.24 */ + ASN1ObjectIdentifier id_mod_cms_seed = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.0.24"); + + /** RFC 9708 MTS-HashSig-2013; OID 1.2.840.113549.1.9.16.0.64 */ + ASN1ObjectIdentifier id_mod_mts_hashsig_2013 = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.0.64"); + + /** RFC 8103 id-mod-CMS-AEADChaCha20Poly1305; OID 1.2.840.113549.1.9.16.0.66 */ + ASN1ObjectIdentifier id_mod_CMS_AEADChaCha20Poly1305 = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.0.66"); + // // id-ct OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1)} @@ -246,6 +260,7 @@ public interface PKCSObjectIdentifiers /** S/MIME: Algorithm Identifiers ; 1.2.840.113549.1.9.16.3 */ ASN1ObjectIdentifier smime_alg = id_smime.branch("3"); /** @deprecated use smime_alg instead */ + @Deprecated ASN1ObjectIdentifier id_alg = id_smime.branch("3"); /** PKCS#9: 1.2.840.113549.1.9.16.3.5 */ @@ -261,6 +276,8 @@ public interface PKCSObjectIdentifiers /** PKCS#9: 1.2.840.113549.1.9.16.3.10 */ ASN1ObjectIdentifier id_alg_SSDH = smime_alg.branch("10"); + + /** *

          * -- RSA-KEM Key Transport Algorithm  RFC 5990
    @@ -278,6 +295,7 @@ public interface PKCSObjectIdentifiers
          * id-alg-hss-lms-hashsig OBJECT IDENTIFIER ::= { iso(1)
          *     member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs9(9)
          *    smime(16) alg(3) 17 }
    +     *    1.2.840.113549.1.9.16.3.17
          */
         public static final ASN1ObjectIdentifier id_alg_hss_lms_hashsig = smime_alg.branch("17");
     
    @@ -417,12 +435,16 @@ public interface PKCSObjectIdentifiers
         ASN1ObjectIdentifier id_aa_communityIdentifiers = id_aa.branch("40");
     
         /** @deprecated use id_aa_ets_sigPolicyId instead */
    +    @Deprecated
         ASN1ObjectIdentifier id_aa_sigPolicyId    = id_aa_ets_sigPolicyId;
         /** @deprecated use id_aa_ets_commitmentType instead */
    +    @Deprecated
         ASN1ObjectIdentifier id_aa_commitmentType = id_aa_ets_commitmentType;
         /** @deprecated use id_aa_ets_signerLocation instead */
    +    @Deprecated
         ASN1ObjectIdentifier id_aa_signerLocation = id_aa_ets_signerLocation;
         /** @deprecated use id_aa_ets_otherSigCert instead */
    +    @Deprecated
         ASN1ObjectIdentifier id_aa_otherSigCert   = id_aa_ets_otherSigCert;
         
         /**
    @@ -431,6 +453,7 @@ public interface PKCSObjectIdentifiers
          * 1.2.840.113549.1.9.16.5
          * @deprecated use id_spq_oid instead
          */
    +    @Deprecated
         final String id_spq = "1.2.840.113549.1.9.16.5";
         ASN1ObjectIdentifier id_spq_oid = id_smime.branch("5");
     
    @@ -481,6 +504,7 @@ public interface PKCSObjectIdentifiers
          * PKCS#12: 1.2.840.113549.1.12.1.6
          * @deprecated use pbeWithSHAAnd40BitRC2_CBC
          */
    +    @Deprecated
         ASN1ObjectIdentifier    pbewithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6");
     }
     
    diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java
    index 8d51197178..809d7f1636 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/Pfx.java
    @@ -72,7 +72,7 @@ public ASN1Primitive toASN1Primitive()
         {
             ASN1EncodableVector v = new ASN1EncodableVector(3);
     
    -        v.add(new ASN1Integer(3));
    +        v.add(ASN1Integer.THREE);
             v.add(contentInfo);
     
             if (macData != null)
    diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/RC2CBCParameter.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/RC2CBCParameter.java
    index 61bc110f1a..7f5875519e 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/pkcs/RC2CBCParameter.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/RC2CBCParameter.java
    @@ -43,7 +43,7 @@ public RC2CBCParameter(
             int     parameterVersion,
             byte[]  iv)
         {
    -        this.version = new ASN1Integer(parameterVersion);
    +        this.version = ASN1Integer.valueOf(parameterVersion);
             this.iv = new DEROctetString(iv);
         }
     
    diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
    index 3aecefff09..b29b7c306e 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
    @@ -100,7 +100,17 @@ public AlgorithmIdentifier getPSourceAlgorithm()
         {
             return pSourceAlgorithm;
         }
    -    
    +
    +    public RSAESOAEPparams withDefaultPSource()
    +    {
    +        if (DEFAULT_P_SOURCE_ALGORITHM == pSourceAlgorithm)
    +        {
    +            return this;
    +        }
    +
    +        return new RSAESOAEPparams(hashAlgorithm, maskGenAlgorithm, DEFAULT_P_SOURCE_ALGORITHM);
    +    }
    +
         /**
          * 
          *  RSAES-OAEP-params ::= SEQUENCE {
    @@ -145,7 +155,7 @@ public ASN1Primitive toASN1Primitive()
             {
                 v.add(new DERTaggedObject(true, 2, pSourceAlgorithm));
             }
    -        
    +
             return new DERSequence(v);
         }
     }
    diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java
    index 8e654cc0f2..4bd2bf9311 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java
    @@ -170,7 +170,7 @@ public ASN1Primitive toASN1Primitive()
         {
             ASN1EncodableVector  v = new ASN1EncodableVector(10);
     
    -        v.add(new ASN1Integer(version));                       // version
    +        v.add(ASN1Integer.valueOf(version));                       // version
             v.add(new ASN1Integer(getModulus()));
             v.add(new ASN1Integer(getPublicExponent()));
             v.add(new ASN1Integer(getPrivateExponent()));
    diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
    index 713f83720e..d711216d54 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
    @@ -24,9 +24,9 @@ public class RSASSAPSSparams
         
         public final static AlgorithmIdentifier DEFAULT_HASH_ALGORITHM = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE);
         public final static AlgorithmIdentifier DEFAULT_MASK_GEN_FUNCTION = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, DEFAULT_HASH_ALGORITHM);
    -    public final static ASN1Integer          DEFAULT_SALT_LENGTH = new ASN1Integer(20);
    -    public final static ASN1Integer          DEFAULT_TRAILER_FIELD = new ASN1Integer(1);
    -    
    +    public final static ASN1Integer         DEFAULT_SALT_LENGTH = ASN1Integer.valueOf(20);
    +    public final static ASN1Integer         DEFAULT_TRAILER_FIELD = ASN1Integer.ONE;
    +
         public static RSASSAPSSparams getInstance(
             Object  obj)
         {
    diff --git a/core/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java b/core/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java
    index 890fba67bb..7ac98a19b4 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKey.java
    @@ -1,7 +1,6 @@
     package org.bouncycastle.asn1.sec;
     
     import java.math.BigInteger;
    -import java.util.Enumeration;
     
     import org.bouncycastle.asn1.ASN1BitString;
     import org.bouncycastle.asn1.ASN1Encodable;
    @@ -24,16 +23,7 @@
     public class ECPrivateKey
         extends ASN1Object
     {
    -    private ASN1Sequence seq;
    -
    -    private ECPrivateKey(
    -        ASN1Sequence seq)
    -    {
    -        this.seq = seq;
    -    }
    -
    -    public static ECPrivateKey getInstance(
    -        Object obj)
    +    public static ECPrivateKey getInstance(Object obj)
         {
             if (obj instanceof ECPrivateKey)
             {
    @@ -48,70 +38,48 @@ public static ECPrivateKey getInstance(
             return null;
         }
     
    -    /**
    -     * @deprecated use constructor which takes orderBitLength to guarantee correct encoding.
    -     */
    -    public ECPrivateKey(
    -        BigInteger key)
    +    public static ECPrivateKey getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit)
         {
    -        this(key.bitLength(), key);
    +        return new ECPrivateKey(ASN1Sequence.getInstance(taggedObject, declaredExplicit));
         }
     
    -    /**
    -     * Base constructor.
    -     *
    -     * @param orderBitLength the bitLength of the order of the curve.
    -     * @param key the private key value.
    -     */
    -    public ECPrivateKey(
    -        int        orderBitLength,
    -        BigInteger key)
    +    public static ECPrivateKey getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit)
         {
    -        byte[] bytes = BigIntegers.asUnsignedByteArray((orderBitLength + 7) / 8, key);
    -
    -        seq = new DERSequence(new ASN1Integer(1), new DEROctetString(bytes));
    +        return new ECPrivateKey(ASN1Sequence.getTagged(taggedObject, declaredExplicit));
         }
     
    -    /**
    -     * @deprecated use constructor which takes orderBitLength to guarantee correct encoding.
    -     */
    -    public ECPrivateKey(
    -        BigInteger key,
    -        ASN1Encodable parameters)
    +    private final ASN1Sequence seq;
    +
    +    private ECPrivateKey(ASN1Sequence seq)
         {
    -        this(key, null, parameters);
    +        this.seq = seq;
         }
     
         /**
    -     * @deprecated use constructor which takes orderBitLength to guarantee correct encoding.
    +     * Base constructor.
    +     *
    +     * @param orderBitLength the bitLength of the order of the curve.
    +     * @param key the private key value.
          */
    -    public ECPrivateKey(
    -        BigInteger key,
    -        ASN1BitString publicKey,
    -        ASN1Encodable parameters)
    +    public ECPrivateKey(int orderBitLength, BigInteger key)
         {
    -        this(key.bitLength(), key, publicKey, parameters);
    +        byte[] bytes = BigIntegers.asUnsignedByteArray((orderBitLength + 7) / 8, key);
    +
    +        seq = new DERSequence(ASN1Integer.ONE, new DEROctetString(bytes));
         }
     
    -    public ECPrivateKey(
    -        int orderBitLength,
    -        BigInteger key,
    -        ASN1Encodable parameters)
    +    public ECPrivateKey(int orderBitLength, BigInteger key, ASN1Encodable parameters)
         {
             this(orderBitLength, key, null, parameters);
         }
     
    -    public ECPrivateKey(
    -        int orderBitLength,
    -        BigInteger key,
    -        ASN1BitString publicKey,
    -        ASN1Encodable parameters)
    +    public ECPrivateKey(int orderBitLength, BigInteger key, ASN1BitString publicKey, ASN1Encodable parameters)
         {
             byte[] bytes = BigIntegers.asUnsignedByteArray((orderBitLength + 7) / 8, key);
     
             ASN1EncodableVector v = new ASN1EncodableVector(4);
     
    -        v.add(new ASN1Integer(1));
    +        v.add(ASN1Integer.ONE);
             v.add(new DEROctetString(bytes));
     
             if (parameters != null)
    @@ -127,25 +95,39 @@ public ECPrivateKey(
             seq = new DERSequence(v);
         }
     
    -    public BigInteger getKey()
    +    public ECPrivateKey(ASN1OctetString privateKey, ASN1Encodable parameters, ASN1BitString publicKey)
         {
    -        ASN1OctetString octs = (ASN1OctetString)seq.getObjectAt(1);
    +        ASN1EncodableVector v = new ASN1EncodableVector(4);
    +
    +        v.add(ASN1Integer.ONE);
    +        v.add(privateKey);
    +
    +        if (parameters != null)
    +        {
    +            v.add(new DERTaggedObject(true, 0, parameters));
    +        }
    +
    +        if (publicKey != null)
    +        {
    +            v.add(new DERTaggedObject(true, 1, publicKey));
    +        }
    +
    +        seq = new DERSequence(v);
    +    }
     
    -        return new BigInteger(1, octs.getOctets());
    +    public BigInteger getKey()
    +    {
    +        return new BigInteger(1, getPrivateKey().getOctets());
         }
    -    
    -    public ASN1BitString getPublicKey()
    +
    +    public ASN1OctetString getPrivateKey()
         {
    -        return (ASN1BitString)getObjectInTag(1, BERTags.BIT_STRING);
    +        return (ASN1OctetString)seq.getObjectAt(1);
         }
     
    -    /**
    -     * @deprecated Use {@link #getParametersObject()} instead and getInstance
    -     *             methods or similar to get the object at the desired type.
    -     */
    -    public ASN1Primitive getParameters()
    +    public ASN1BitString getPublicKey()
         {
    -        return getParametersObject().toASN1Primitive();
    +        return (ASN1BitString)getObjectInTag(1, BERTags.BIT_STRING);
         }
     
         public ASN1Object getParametersObject()
    @@ -155,21 +137,15 @@ public ASN1Object getParametersObject()
     
         private ASN1Object getObjectInTag(int tagNo, int baseTagNo)
         {
    -        Enumeration e = seq.getObjects();
    -
    -        while (e.hasMoreElements())
    +        for (int i = 0, count = seq.size(); i < count; ++i)
             {
    -            ASN1Encodable obj = (ASN1Encodable)e.nextElement();
    -
    -            if (obj instanceof ASN1TaggedObject)
    +            ASN1Encodable element = seq.getObjectAt(i);
    +            ASN1TaggedObject taggedObject = ASN1TaggedObject.getContextOptional(element, tagNo);
    +            if (taggedObject != null)
                 {
    -                ASN1TaggedObject tag = (ASN1TaggedObject)obj;
    -                if (tag.hasContextTag(tagNo))
    -                {
    -                    return baseTagNo < 0
    -                        ?   tag.getExplicitBaseObject().toASN1Primitive()
    -                        :   tag.getBaseUniversal(true, baseTagNo);
    -                }
    +                return baseTagNo < 0
    +                    ? taggedObject.getExplicitBaseObject().toASN1Primitive()
    +                    : taggedObject.getBaseUniversal(true, baseTagNo);
                 }
             }
             return null;
    diff --git a/core/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java b/core/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java
    index 5ed882ef84..fbe7dbd9e7 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java
    @@ -37,7 +37,7 @@ public ECPrivateKeyStructure(
         {
             byte[] bytes = BigIntegers.asUnsignedByteArray(key);
     
    -        seq = new DERSequence(new ASN1Integer(1), new DEROctetString(bytes));
    +        seq = new DERSequence(ASN1Integer.ONE, new DEROctetString(bytes));
         }
     
         public ECPrivateKeyStructure(
    @@ -56,7 +56,7 @@ public ECPrivateKeyStructure(
     
             ASN1EncodableVector v = new ASN1EncodableVector(4);
     
    -        v.add(new ASN1Integer(1));
    +        v.add(ASN1Integer.ONE);
             v.add(new DEROctetString(bytes));
     
             if (parameters != null)
    diff --git a/core/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
    index bb215bee6e..023c7b80c5 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java
    @@ -15,8 +15,9 @@
      */
     public interface SECObjectIdentifiers
     {
    -    /** Base OID: 1.3.132.0 */
    -    static final ASN1ObjectIdentifier ellipticCurve = new ASN1ObjectIdentifier("1.3.132.0");
    +    static final ASN1ObjectIdentifier certicom = new ASN1ObjectIdentifier("1.3.132");
    +
    +    static final ASN1ObjectIdentifier ellipticCurve = certicom.branch("0");
     
         /**  sect163k1 OID: 1.3.132.0.1 */
         static final ASN1ObjectIdentifier sect163k1 = ellipticCurve.branch("1");
    @@ -86,25 +87,52 @@ public interface SECObjectIdentifiers
         /**  secp256r1 OID: 1.3.132.0.prime256v1 */
         static final ASN1ObjectIdentifier secp256r1 = X9ObjectIdentifiers.prime256v1;
     
    -    static final ASN1ObjectIdentifier secg_scheme = new ASN1ObjectIdentifier("1.3.132.1");
    +    static final ASN1ObjectIdentifier secg_scheme = certicom.branch("1");
    +
    +    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_recommendedKDF = secg_scheme.branch("1");
    +    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_specifiedKDF = secg_scheme.branch("2");
    +    static final ASN1ObjectIdentifier mqvSinglePass_recommendedKDF = secg_scheme.branch("3");
    +    static final ASN1ObjectIdentifier mqvSinglePass_specifiedKDF = secg_scheme.branch("4");
    +    static final ASN1ObjectIdentifier mqvFull_recommendedKDF = secg_scheme.branch("5");
    +    static final ASN1ObjectIdentifier mqvFull_specifiedKDF = secg_scheme.branch("6");
    +    static final ASN1ObjectIdentifier ecies_recommendedParameters = secg_scheme.branch("7");
    +    static final ASN1ObjectIdentifier ecies_specifiedParameters = secg_scheme.branch("8");
    +
    +    static final ASN1ObjectIdentifier dhSinglePass_stdDH_kdf_schemes = secg_scheme.branch("11");
    +
    +    static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha224kdf_scheme = dhSinglePass_stdDH_kdf_schemes.branch("0");
    +    static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha256kdf_scheme = dhSinglePass_stdDH_kdf_schemes.branch("1");
    +    static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha384kdf_scheme = dhSinglePass_stdDH_kdf_schemes.branch("2");
    +    static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha512kdf_scheme = dhSinglePass_stdDH_kdf_schemes.branch("3");
    +
    +    static final ASN1ObjectIdentifier ecdh = secg_scheme.branch("12");
    +    static final ASN1ObjectIdentifier ecmqv = secg_scheme.branch("13");
    +
    +    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_kdf_schemes = secg_scheme.branch("14");
    +
    +    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha224kdf_scheme = dhSinglePass_cofactorDH_kdf_schemes.branch("0");
    +    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha256kdf_scheme = dhSinglePass_cofactorDH_kdf_schemes.branch("1");
    +    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha384kdf_scheme = dhSinglePass_cofactorDH_kdf_schemes.branch("2");
    +    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha512kdf_scheme = dhSinglePass_cofactorDH_kdf_schemes.branch("3");
    +
    +    static final ASN1ObjectIdentifier mqvSinglePass_kdf_schemes = secg_scheme.branch("15");
    +
    +    static final ASN1ObjectIdentifier mqvSinglePass_sha224kdf_scheme = mqvSinglePass_kdf_schemes.branch("0");
    +    static final ASN1ObjectIdentifier mqvSinglePass_sha256kdf_scheme = mqvSinglePass_kdf_schemes.branch("1");
    +    static final ASN1ObjectIdentifier mqvSinglePass_sha384kdf_scheme = mqvSinglePass_kdf_schemes.branch("2");
    +    static final ASN1ObjectIdentifier mqvSinglePass_sha512kdf_scheme = mqvSinglePass_kdf_schemes.branch("3");
     
    -    static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha224kdf_scheme = secg_scheme.branch("11.0");
    -    static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha256kdf_scheme = secg_scheme.branch("11.1");
    -    static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha384kdf_scheme = secg_scheme.branch("11.2");
    -    static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha512kdf_scheme = secg_scheme.branch("11.3");
    +    static final ASN1ObjectIdentifier mqvFull_kdf_schemes = secg_scheme.branch("16");
     
    -    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha224kdf_scheme = secg_scheme.branch("14.0");
    -    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha256kdf_scheme = secg_scheme.branch("14.1");
    -    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha384kdf_scheme = secg_scheme.branch("14.2");
    -    static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha512kdf_scheme = secg_scheme.branch("14.3");
    +    static final ASN1ObjectIdentifier mqvFull_sha224kdf_scheme = mqvFull_kdf_schemes.branch("0");
    +    static final ASN1ObjectIdentifier mqvFull_sha256kdf_scheme = mqvFull_kdf_schemes.branch("1");
    +    static final ASN1ObjectIdentifier mqvFull_sha384kdf_scheme = mqvFull_kdf_schemes.branch("2");
    +    static final ASN1ObjectIdentifier mqvFull_sha512kdf_scheme = mqvFull_kdf_schemes.branch("3");
     
    -    static final ASN1ObjectIdentifier mqvSinglePass_sha224kdf_scheme = secg_scheme.branch("15.0");
    -    static final ASN1ObjectIdentifier mqvSinglePass_sha256kdf_scheme = secg_scheme.branch("15.1");
    -    static final ASN1ObjectIdentifier mqvSinglePass_sha384kdf_scheme = secg_scheme.branch("15.2");
    -    static final ASN1ObjectIdentifier mqvSinglePass_sha512kdf_scheme = secg_scheme.branch("15.3");
    +    static final ASN1ObjectIdentifier kdf_algorithms = secg_scheme.branch("17");
     
    -    static final ASN1ObjectIdentifier mqvFull_sha224kdf_scheme = secg_scheme.branch("16.0");
    -    static final ASN1ObjectIdentifier mqvFull_sha256kdf_scheme = secg_scheme.branch("16.1");
    -    static final ASN1ObjectIdentifier mqvFull_sha384kdf_scheme = secg_scheme.branch("16.2");
    -    static final ASN1ObjectIdentifier mqvFull_sha512kdf_scheme = secg_scheme.branch("16.3");
    +    static final ASN1ObjectIdentifier x9_63_kdf = kdf_algorithms.branch("0");
    +    static final ASN1ObjectIdentifier nist_concatenation_kdf = kdf_algorithms.branch("1");
    +    static final ASN1ObjectIdentifier tls_kdf = kdf_algorithms.branch("2");
    +    static final ASN1ObjectIdentifier ikev2_kdf = kdf_algorithms.branch("3");
     }
    diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java
    index 825ea960d3..cb98e8921e 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java
    @@ -96,17 +96,17 @@ public ASN1Primitive toASN1Primitive()
         {
             ASN1EncodableVector v = new ASN1EncodableVector(2);
     
    -        v.add(new ASN1Integer(m));
    +        v.add(ASN1Integer.valueOf(m));
             if (j == 0) //Trinomial
             {
    -            v.add(new ASN1Integer(k));
    +            v.add(ASN1Integer.valueOf(k));
             }
             else
             {
                 ASN1EncodableVector coefs = new ASN1EncodableVector(3);
    -            coefs.add(new ASN1Integer(k));
    -            coefs.add(new ASN1Integer(j));
    -            coefs.add(new ASN1Integer(l));
    +            coefs.add(ASN1Integer.valueOf(k));
    +            coefs.add(ASN1Integer.valueOf(j));
    +            coefs.add(ASN1Integer.valueOf(l));
     
                 v.add(new DERSequence(coefs));
             }
    diff --git a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145NamedCurves.java b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145NamedCurves.java
    index b18953a806..b3b28224f6 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145NamedCurves.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/ua/DSTU4145NamedCurves.java
    @@ -6,18 +6,28 @@
     import org.bouncycastle.crypto.params.ECDomainParameters;
     import org.bouncycastle.math.ec.ECCurve;
     import org.bouncycastle.math.ec.ECPoint;
    +import org.bouncycastle.math.ec.WNafUtil;
     
     public class DSTU4145NamedCurves
     {
         private static final BigInteger ZERO = BigInteger.valueOf(0);
         private static final BigInteger ONE = BigInteger.valueOf(1);
    +    private static final BigInteger TWO = BigInteger.valueOf(2);
    +    private static final BigInteger FOUR = BigInteger.valueOf(4);
     
    -    static final ECDomainParameters[] params = new ECDomainParameters[10];
    -    static final ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[10];
    +    private static final ECDomainParameters[] DOMAIN_PARAMETERS = new ECDomainParameters[10];
    +    private static final ASN1ObjectIdentifier[] OIDS = new ASN1ObjectIdentifier[10];
     
         //All named curves have the following oid format: 1.2.804.2.1.1.1.1.3.1.1.2.X
         //where X is the curve number 0-9
    -    static final String oidBase = UAObjectIdentifiers.dstu4145le.getId() + ".2.";
    +    private static final ASN1ObjectIdentifier OID_BASE = UAObjectIdentifiers.dstu4145le.branch("2");
    +
    +    private static ECPoint configureBasepoint(ECCurve curve, BigInteger x, BigInteger y)
    +    {
    +        ECPoint G = curve.createPoint(x, y);
    +        WNafUtil.configureBasepoint(G);
    +        return G;
    +    }
     
         static
         {
    @@ -34,16 +44,16 @@ public class DSTU4145NamedCurves
             n_s[9] = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA3175458009A8C0A724F02F81AA8A1FCBAF80D90C7A95110504CF", 16);
     
             BigInteger[] h_s = new BigInteger[10];
    -        h_s[0] = BigInteger.valueOf(2);
    -        h_s[1] = BigInteger.valueOf(2);
    -        h_s[2] = BigInteger.valueOf(4);
    -        h_s[3] = BigInteger.valueOf(2);
    -        h_s[4] = BigInteger.valueOf(2);
    -        h_s[5] = BigInteger.valueOf(2);
    -        h_s[6] = BigInteger.valueOf(4);
    -        h_s[7] = BigInteger.valueOf(2);
    -        h_s[8] = BigInteger.valueOf(2);
    -        h_s[9] = BigInteger.valueOf(2);
    +        h_s[0] = TWO;
    +        h_s[1] = TWO;
    +        h_s[2] = FOUR;
    +        h_s[3] = TWO;
    +        h_s[4] = TWO;
    +        h_s[5] = TWO;
    +        h_s[6] = FOUR;
    +        h_s[7] = TWO;
    +        h_s[8] = TWO;
    +        h_s[9] = TWO;
     
             ECCurve.F2m[] curves = new ECCurve.F2m[10];
             curves[0] = new ECCurve.F2m(163, 3, 6, 7, ONE, new BigInteger("5FF6108462A2DC8210AB403925E638A19C1455D21", 16), n_s[0], h_s[0]);
    @@ -58,25 +68,21 @@ public class DSTU4145NamedCurves
             curves[9] = new ECCurve.F2m(431, 1, 3, 5, ONE, new BigInteger("03CE10490F6A708FC26DFE8C3D27C4F94E690134D5BFF988D8D28AAEAEDE975936C66BAC536B18AE2DC312CA493117DAA469C640CAF3", 16), n_s[9], h_s[9]);
     
             ECPoint[] points = new ECPoint[10];
    -        points[0] = curves[0].createPoint(new BigInteger("2E2F85F5DD74CE983A5C4237229DAF8A3F35823BE", 16), new BigInteger("3826F008A8C51D7B95284D9D03FF0E00CE2CD723A", 16));
    -        points[1] = curves[1].createPoint(new BigInteger("7A1F6653786A68192803910A3D30B2A2018B21CD54", 16), new BigInteger("5F49EB26781C0EC6B8909156D98ED435E45FD59918", 16));
    -        points[2] = curves[2].createPoint(new BigInteger("4D41A619BCC6EADF0448FA22FAD567A9181D37389CA", 16), new BigInteger("10B51CC12849B234C75E6DD2028BF7FF5C1CE0D991A1", 16));
    -        points[3] = curves[3].createPoint(new BigInteger("6BA06FE51464B2BD26DC57F48819BA9954667022C7D03", 16), new BigInteger("25FBC363582DCEC065080CA8287AAFF09788A66DC3A9E", 16));
    -        points[4] = curves[4].createPoint(new BigInteger("714114B762F2FF4A7912A6D2AC58B9B5C2FCFE76DAEB7129", 16), new BigInteger("29C41E568B77C617EFE5902F11DB96FA9613CD8D03DB08DA", 16));
    -        points[5] = curves[5].createPoint(new BigInteger("3FCDA526B6CDF83BA1118DF35B3C31761D3545F32728D003EEB25EFE96", 16), new BigInteger("9CA8B57A934C54DEEDA9E54A7BBAD95E3B2E91C54D32BE0B9DF96D8D35", 16));
    -        points[6] = curves[6].createPoint(new BigInteger("02A29EF207D0E9B6C55CD260B306C7E007AC491CA1B10C62334A9E8DCD8D20FB7", 16), new BigInteger("10686D41FF744D4449FCCF6D8EEA03102E6812C93A9D60B978B702CF156D814EF", 16));
    -        points[7] = curves[7].createPoint(new BigInteger("216EE8B189D291A0224984C1E92F1D16BF75CCD825A087A239B276D3167743C52C02D6E7232AA", 16), new BigInteger("5D9306BACD22B7FAEB09D2E049C6E2866C5D1677762A8F2F2DC9A11C7F7BE8340AB2237C7F2A0", 16));
    -        points[8] = curves[8].createPoint(new BigInteger("324A6EDDD512F08C49A99AE0D3F961197A76413E7BE81A400CA681E09639B5FE12E59A109F78BF4A373541B3B9A1", 16), new BigInteger("1AB597A5B4477F59E39539007C7F977D1A567B92B043A49C6B61984C3FE3481AAF454CD41BA1F051626442B3C10", 16));
    -        points[9] = curves[9].createPoint(new BigInteger("1A62BA79D98133A16BBAE7ED9A8E03C32E0824D57AEF72F88986874E5AAE49C27BED49A2A95058068426C2171E99FD3B43C5947C857D", 16), new BigInteger("70B5E1E14031C1F70BBEFE96BDDE66F451754B4CA5F48DA241F331AA396B8D1839A855C1769B1EA14BA53308B5E2723724E090E02DB9", 16));
    -
    -        for (int i = 0; i < params.length; i++)
    -        {
    -            params[i] = new ECDomainParameters(curves[i], points[i], n_s[i], h_s[i]);
    -        }
    +        points[0] = configureBasepoint(curves[0], new BigInteger("2E2F85F5DD74CE983A5C4237229DAF8A3F35823BE", 16), new BigInteger("3826F008A8C51D7B95284D9D03FF0E00CE2CD723A", 16));
    +        points[1] = configureBasepoint(curves[1], new BigInteger("7A1F6653786A68192803910A3D30B2A2018B21CD54", 16), new BigInteger("5F49EB26781C0EC6B8909156D98ED435E45FD59918", 16));
    +        points[2] = configureBasepoint(curves[2], new BigInteger("4D41A619BCC6EADF0448FA22FAD567A9181D37389CA", 16), new BigInteger("10B51CC12849B234C75E6DD2028BF7FF5C1CE0D991A1", 16));
    +        points[3] = configureBasepoint(curves[3], new BigInteger("6BA06FE51464B2BD26DC57F48819BA9954667022C7D03", 16), new BigInteger("25FBC363582DCEC065080CA8287AAFF09788A66DC3A9E", 16));
    +        points[4] = configureBasepoint(curves[4], new BigInteger("714114B762F2FF4A7912A6D2AC58B9B5C2FCFE76DAEB7129", 16), new BigInteger("29C41E568B77C617EFE5902F11DB96FA9613CD8D03DB08DA", 16));
    +        points[5] = configureBasepoint(curves[5], new BigInteger("3FCDA526B6CDF83BA1118DF35B3C31761D3545F32728D003EEB25EFE96", 16), new BigInteger("9CA8B57A934C54DEEDA9E54A7BBAD95E3B2E91C54D32BE0B9DF96D8D35", 16));
    +        points[6] = configureBasepoint(curves[6], new BigInteger("02A29EF207D0E9B6C55CD260B306C7E007AC491CA1B10C62334A9E8DCD8D20FB7", 16), new BigInteger("10686D41FF744D4449FCCF6D8EEA03102E6812C93A9D60B978B702CF156D814EF", 16));
    +        points[7] = configureBasepoint(curves[7], new BigInteger("216EE8B189D291A0224984C1E92F1D16BF75CCD825A087A239B276D3167743C52C02D6E7232AA", 16), new BigInteger("5D9306BACD22B7FAEB09D2E049C6E2866C5D1677762A8F2F2DC9A11C7F7BE8340AB2237C7F2A0", 16));
    +        points[8] = configureBasepoint(curves[8], new BigInteger("324A6EDDD512F08C49A99AE0D3F961197A76413E7BE81A400CA681E09639B5FE12E59A109F78BF4A373541B3B9A1", 16), new BigInteger("1AB597A5B4477F59E39539007C7F977D1A567B92B043A49C6B61984C3FE3481AAF454CD41BA1F051626442B3C10", 16));
    +        points[9] = configureBasepoint(curves[9], new BigInteger("1A62BA79D98133A16BBAE7ED9A8E03C32E0824D57AEF72F88986874E5AAE49C27BED49A2A95058068426C2171E99FD3B43C5947C857D", 16), new BigInteger("70B5E1E14031C1F70BBEFE96BDDE66F451754B4CA5F48DA241F331AA396B8D1839A855C1769B1EA14BA53308B5E2723724E090E02DB9", 16));
     
    -        for (int i = 0; i < oids.length; i++)
    +        for (int i = 0; i < 10; i++)
             {
    -            oids[i] = new ASN1ObjectIdentifier(oidBase + i);
    +            DOMAIN_PARAMETERS[i] = new ECDomainParameters(curves[i], points[i], n_s[i], h_s[i]);
    +            OIDS[i] = OID_BASE.branch("" + i);
             }
         }
     
    @@ -86,7 +92,9 @@ public class DSTU4145NamedCurves
          */
         public static ASN1ObjectIdentifier[] getOIDs()
         {
    -        return oids;
    +        ASN1ObjectIdentifier[] result = new ASN1ObjectIdentifier[OIDS.length];
    +        System.arraycopy(OIDS, 0, result, 0, OIDS.length);
    +        return result;
         }
     
         /**
    @@ -95,11 +103,15 @@ public static ASN1ObjectIdentifier[] getOIDs()
          */
         public static ECDomainParameters getByOID(ASN1ObjectIdentifier oid)
         {
    -        String oidStr = oid.getId();
    -        if (oidStr.startsWith(oidBase))
    +        if (oid.on(OID_BASE))
             {
    -            int index = Integer.parseInt(oidStr.substring(oidStr.lastIndexOf('.') + 1));
    -            return (index >= 0 && index < params.length) ? params[index] : null;
    +            for (int i = 0; i < 10; ++i)
    +            {
    +                if (OIDS[i].equals(oid))
    +                {
    +                    return DOMAIN_PARAMETERS[i];
    +                }
    +            }
             }
             return null;
         }
    diff --git a/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java b/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
    index 4ff5e2dcd9..dc0583b6b9 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java
    @@ -52,22 +52,18 @@ public class ASN1Dump
          *
          * @param obj the ASN1Primitive to be dumped out.
          */
    -    static void _dumpAsString(
    -        String      indent,
    -        boolean     verbose,
    -        ASN1Primitive obj,
    -        StringBuffer    buf)
    +    static void _dumpAsString(String indent, boolean verbose, ASN1Primitive obj, StringBuilder buf)
         {
             String nl = Strings.lineSeparator();
    +        buf.append(indent);
    +
             if (obj instanceof ASN1Null)
             {
    -            buf.append(indent);
                 buf.append("NULL");
                 buf.append(nl);
             }
             else if (obj instanceof ASN1Sequence)
             {
    -            buf.append(indent);
                 if (obj instanceof BERSequence)
                 {
                     buf.append("BER Sequence");
    @@ -92,7 +88,6 @@ else if (obj instanceof DERSequence)
             }
             else if (obj instanceof ASN1Set)
             {
    -            buf.append(indent);
                 if (obj instanceof BERSet)
                 {
                     buf.append("BER Set");
    @@ -117,7 +112,6 @@ else if (obj instanceof DERSet)
             }
             else if (obj instanceof ASN1TaggedObject)
             {
    -            buf.append(indent);
                 if (obj instanceof BERTaggedObject)
                 {
                     buf.append("BER Tagged ");
    @@ -137,7 +131,7 @@ else if (obj instanceof DERTaggedObject)
     
                 if (!o.isExplicit())
                 {
    -                buf.append(" IMPLICIT ");
    +                buf.append(" IMPLICIT");
                 }
     
                 buf.append(nl);
    @@ -146,130 +140,124 @@ else if (obj instanceof DERTaggedObject)
     
                 _dumpAsString(baseIndent, verbose, o.getBaseObject().toASN1Primitive(), buf);
             }
    +        else if (obj instanceof ASN1ObjectIdentifier)
    +        {
    +            buf.append("ObjectIdentifier(" + ((ASN1ObjectIdentifier)obj).getId() + ")" + nl);
    +        }
    +        else if (obj instanceof ASN1RelativeOID)
    +        {
    +            buf.append("RelativeOID(" + ((ASN1RelativeOID)obj).getId() + ")" + nl);
    +        }
    +        else if (obj instanceof ASN1Boolean)
    +        {
    +            buf.append("Boolean(" + ((ASN1Boolean)obj).isTrue() + ")" + nl);
    +        }
    +        else if (obj instanceof ASN1Integer)
    +        {
    +            buf.append("Integer(" + ((ASN1Integer)obj).getValue() + ")" + nl);
    +        }
             else if (obj instanceof ASN1OctetString)
             {
                 ASN1OctetString oct = (ASN1OctetString)obj;
     
                 if (obj instanceof BEROctetString)
                 {
    -                buf.append(indent + "BER Constructed Octet String" + "[" + oct.getOctets().length + "] ");
    +                buf.append("BER Constructed Octet String[");
                 }
                 else
                 {
    -                buf.append(indent + "DER Octet String" + "[" + oct.getOctets().length + "] ");
    +                buf.append("DER Octet String[");
                 }
    +
    +            buf.append(oct.getOctetsLength() + "]" + nl);
    +
                 if (verbose)
                 {
    -                buf.append(dumpBinaryDataAsString(indent, oct.getOctets()));
    +                dumpBinaryDataAsString(buf, indent, oct.getOctets());
                 }
    -            else
    -            {
    -                buf.append(nl);
    -            }
    -        }
    -        else if (obj instanceof ASN1ObjectIdentifier)
    -        {
    -            buf.append(indent + "ObjectIdentifier(" + ((ASN1ObjectIdentifier)obj).getId() + ")" + nl);
    -        }
    -        else if (obj instanceof ASN1RelativeOID)
    -        {
    -            buf.append(indent + "RelativeOID(" + ((ASN1RelativeOID)obj).getId() + ")" + nl);
    -        }
    -        else if (obj instanceof ASN1Boolean)
    -        {
    -            buf.append(indent + "Boolean(" + ((ASN1Boolean)obj).isTrue() + ")" + nl);
    -        }
    -        else if (obj instanceof ASN1Integer)
    -        {
    -            buf.append(indent + "Integer(" + ((ASN1Integer)obj).getValue() + ")" + nl);
             }
             else if (obj instanceof ASN1BitString)
             {
                 ASN1BitString bitString = (ASN1BitString)obj;
     
    -            byte[] bytes = bitString.getBytes();
    -            int padBits = bitString.getPadBits();
    -
                 if (bitString instanceof DERBitString)
                 {
    -                buf.append(indent + "DER Bit String" + "[" + bytes.length + ", " + padBits + "] ");
    +                buf.append("DER Bit String[");
                 }
                 else if (bitString instanceof DLBitString)
                 {
    -                buf.append(indent + "DL Bit String" + "[" + bytes.length + ", " + padBits + "] ");
    +                buf.append("DL Bit String[");
                 }
                 else
                 {
    -                buf.append(indent + "BER Bit String" + "[" + bytes.length + ", " + padBits + "] ");
    +                buf.append("BER Bit String[");
                 }
     
    +            buf.append(bitString.getBytesLength() + ", " + bitString.getPadBits() + "]" + nl);
    +
                 if (verbose)
                 {
    -                buf.append(dumpBinaryDataAsString(indent, bytes));
    -            }
    -            else
    -            {
    -                buf.append(nl);
    +                dumpBinaryDataAsString(buf, indent, bitString.getBytes());
                 }
             }
             else if (obj instanceof ASN1IA5String)
             {
    -            buf.append(indent + "IA5String(" + ((ASN1IA5String)obj).getString() + ") " + nl);
    +            buf.append("IA5String(" + ((ASN1IA5String)obj).getString() + ") " + nl);
             }
             else if (obj instanceof ASN1UTF8String)
             {
    -            buf.append(indent + "UTF8String(" + ((ASN1UTF8String)obj).getString() + ") " + nl);
    +            buf.append("UTF8String(" + ((ASN1UTF8String)obj).getString() + ") " + nl);
             }
             else if (obj instanceof ASN1NumericString)
             {
    -            buf.append(indent + "NumericString(" + ((ASN1NumericString)obj).getString() + ") " + nl);
    +            buf.append("NumericString(" + ((ASN1NumericString)obj).getString() + ") " + nl);
             }
             else if (obj instanceof ASN1PrintableString)
             {
    -            buf.append(indent + "PrintableString(" + ((ASN1PrintableString)obj).getString() + ") " + nl);
    +            buf.append("PrintableString(" + ((ASN1PrintableString)obj).getString() + ") " + nl);
             }
             else if (obj instanceof ASN1VisibleString)
             {
    -            buf.append(indent + "VisibleString(" + ((ASN1VisibleString)obj).getString() + ") " + nl);
    +            buf.append("VisibleString(" + ((ASN1VisibleString)obj).getString() + ") " + nl);
             }
             else if (obj instanceof ASN1BMPString)
             {
    -            buf.append(indent + "BMPString(" + ((ASN1BMPString)obj).getString() + ") " + nl);
    +            buf.append("BMPString(" + ((ASN1BMPString)obj).getString() + ") " + nl);
             }
             else if (obj instanceof ASN1T61String)
             {
    -            buf.append(indent + "T61String(" + ((ASN1T61String)obj).getString() + ") " + nl);
    +            buf.append("T61String(" + ((ASN1T61String)obj).getString() + ") " + nl);
             }
             else if (obj instanceof ASN1GraphicString)
             {
    -            buf.append(indent + "GraphicString(" + ((ASN1GraphicString)obj).getString() + ") " + nl);
    +            buf.append("GraphicString(" + ((ASN1GraphicString)obj).getString() + ") " + nl);
             }
             else if (obj instanceof ASN1VideotexString)
             {
    -            buf.append(indent + "VideotexString(" + ((ASN1VideotexString)obj).getString() + ") " + nl);
    +            buf.append("VideotexString(" + ((ASN1VideotexString)obj).getString() + ") " + nl);
             }
             else if (obj instanceof ASN1UTCTime)
             {
    -            buf.append(indent + "UTCTime(" + ((ASN1UTCTime)obj).getTime() + ") " + nl);
    +            buf.append("UTCTime(" + ((ASN1UTCTime)obj).getTime() + ") " + nl);
             }
             else if (obj instanceof ASN1GeneralizedTime)
             {
    -            buf.append(indent + "GeneralizedTime(" + ((ASN1GeneralizedTime)obj).getTime() + ") " + nl);
    +            buf.append("GeneralizedTime(" + ((ASN1GeneralizedTime)obj).getTime() + ") " + nl);
             }
             else if (obj instanceof ASN1Enumerated)
             {
                 ASN1Enumerated en = (ASN1Enumerated) obj;
    -            buf.append(indent + "DER Enumerated(" + en.getValue() + ")" + nl);
    +            buf.append("DER Enumerated(" + en.getValue() + ")" + nl);
             }
             else if (obj instanceof ASN1ObjectDescriptor)
             {
                 ASN1ObjectDescriptor od = (ASN1ObjectDescriptor)obj;
    -            buf.append(indent + "ObjectDescriptor(" + od.getBaseGraphicString().getString() + ") " + nl);
    +            buf.append("ObjectDescriptor(" + od.getBaseGraphicString().getString() + ") " + nl);
             }
             else if (obj instanceof ASN1External)
             {
                 ASN1External ext = (ASN1External) obj;
    -            buf.append(indent + "External " + nl);
    +            buf.append("External " + nl);
                 String          tab = indent + TAB;
                 if (ext.getDirectReference() != null)
                 {
    @@ -288,7 +276,7 @@ else if (obj instanceof ASN1External)
             }
             else
             {
    -            buf.append(indent + obj.toString() + nl);
    +            buf.append(obj.toString() + nl);
             }
         }
     
    @@ -329,50 +317,42 @@ else if (obj instanceof ASN1Encodable)
                 return "unknown object type " + obj.toString();
             }
     
    -        StringBuffer buf = new StringBuffer();
    +        StringBuilder buf = new StringBuilder();
             _dumpAsString("", verbose, primitive, buf);
             return buf.toString();
         }
     
    -    private static String dumpBinaryDataAsString(String indent, byte[] bytes)
    +    private static void dumpBinaryDataAsString(StringBuilder buf, String indent, byte[] bytes)
         {
    +        if (bytes.length < 1)
    +        {
    +            return;
    +        }
    +
             String nl = Strings.lineSeparator();
    -        StringBuffer buf = new StringBuffer();
     
             indent += TAB;
    -        
    -        buf.append(nl);
    +
             for (int i = 0; i < bytes.length; i += SAMPLE_SIZE)
             {
    -            if (bytes.length - i > SAMPLE_SIZE)
    -            {
    -                buf.append(indent);
    -                buf.append(Strings.fromByteArray(Hex.encode(bytes, i, SAMPLE_SIZE)));
    -                buf.append(TAB);
    -                buf.append(calculateAscString(bytes, i, SAMPLE_SIZE));
    -                buf.append(nl);
    -            }
    -            else
    +            int remaining = bytes.length - i;
    +            int chunk = Math.min(remaining, SAMPLE_SIZE);
    +
    +            buf.append(indent);
    +            // -DM Hex.toHexString
    +            buf.append(Hex.toHexString(bytes, i, chunk));
    +            for (int j = chunk; j < SAMPLE_SIZE; ++j)
                 {
    -                buf.append(indent);
    -                buf.append(Strings.fromByteArray(Hex.encode(bytes, i, bytes.length - i)));
    -                for (int j = bytes.length - i; j != SAMPLE_SIZE; j++)
    -                {
    -                    buf.append("  ");
    -                }
    -                buf.append(TAB);
    -                buf.append(calculateAscString(bytes, i, bytes.length - i));
    -                buf.append(nl);
    +                buf.append("  ");
                 }
    +            buf.append(TAB);
    +            appendAscString(buf, bytes, i, chunk);
    +            buf.append(nl);
             }
    -        
    -        return buf.toString();
         }
     
    -    private static String calculateAscString(byte[] bytes, int off, int len)
    +    private static void appendAscString(StringBuilder buf, byte[] bytes, int off, int len)
         {
    -        StringBuffer buf = new StringBuffer();
    -
             for (int i = off; i != off + len; i++)
             {
                 if (bytes[i] >= ' ' && bytes[i] <= '~')
    @@ -380,7 +360,5 @@ private static String calculateAscString(byte[] bytes, int off, int len)
                     buf.append((char)bytes[i]);
                 }
             }
    -
    -        return buf.toString();
         }
     }
    diff --git a/core/src/main/java/org/bouncycastle/asn1/util/DERDump.java b/core/src/main/java/org/bouncycastle/asn1/util/DERDump.java
    index 372009fe6c..2e89d9dac0 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/util/DERDump.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/util/DERDump.java
    @@ -17,7 +17,7 @@ public class DERDump
         public static String dumpAsString(
             ASN1Primitive obj)
         {
    -        StringBuffer buf = new StringBuffer();
    +        StringBuilder buf = new StringBuilder();
     
             _dumpAsString("", false, obj, buf);
     
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java b/core/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java
    index d019aaac75..29949b79bb 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x500/X500NameBuilder.java
    @@ -11,7 +11,7 @@
      */
     public class X500NameBuilder
     {
    -    private X500NameStyle template;
    +    private X500NameStyle style;
         private Vector rdns = new Vector();
     
         /**
    @@ -25,13 +25,18 @@ public X500NameBuilder()
         /**
          * Constructor using a specified style.
          *
    -     * @param template the style template for string to DN conversion.
    +     * @param style the X500NameStyle for string to DN conversion.
          */
    -    public X500NameBuilder(X500NameStyle template)
    +    public X500NameBuilder(X500NameStyle style)
         {
    -        this.template = template;
    +        this.style = style;
         }
     
    +    public X500NameStyle getStyle()
    +    {
    +        return style;
    +    }
    +    
         /**
          * Add an RDN based on a single OID and a string representation of its value.
          *
    @@ -41,7 +46,7 @@ public X500NameBuilder(X500NameStyle template)
          */
         public X500NameBuilder addRDN(ASN1ObjectIdentifier oid, String value)
         {
    -        this.addRDN(oid, template.stringToValue(oid, value));
    +        this.addRDN(oid, style.stringToValue(oid, value));
     
             return this;
         }
    @@ -86,7 +91,7 @@ public X500NameBuilder addMultiValuedRDN(ASN1ObjectIdentifier[] oids, String[] v
     
             for (int i = 0; i != vals.length; i++)
             {
    -            vals[i] = template.stringToValue(oids[i], values[i]);
    +            vals[i] = style.stringToValue(oids[i], values[i]);
             }
     
             return addMultiValuedRDN(oids, vals);
    @@ -130,6 +135,11 @@ public X500NameBuilder addMultiValuedRDN(AttributeTypeAndValue[] attrTAndVs)
          * @return a new X.500 name.
          */
         public X500Name build()
    +    {
    +        return new X500Name(style, buildRDNs());
    +    }
    +
    +    public RDN[] buildRDNs()
         {
             RDN[] vals = new RDN[rdns.size()];
     
    @@ -138,6 +148,6 @@ public X500Name build()
                 vals[i] = (RDN)rdns.elementAt(i);
             }
     
    -        return new X500Name(template, vals);
    +        return vals;
         }
    -}
    \ No newline at end of file
    +}
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java
    index 6f20e2309d..abb757d28d 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java
    @@ -68,8 +68,9 @@ public int calculateHashCode(X500Name name)
                 }
                 else
                 {
    -                hashCodeValue ^= rdns[i].getFirst().getType().hashCode();
    -                hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue());
    +                AttributeTypeAndValue first = rdns[i].getFirst(); 
    +                hashCodeValue ^= first.getType().hashCode();
    +                hashCodeValue ^= calcHashCode(first.getValue());
                 }
             }
     
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
    index f27f221e8c..2c462263fd 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java
    @@ -351,7 +351,7 @@ public RDN[] fromString(String dirName)
     
         public String toString(X500Name name)
         {
    -        StringBuffer buf = new StringBuffer();
    +        StringBuilder buf = new StringBuilder();
             boolean first = true;
     
             RDN[] rdns = name.getRDNs();
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
    index 958de0c2ad..1c0367870d 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
    @@ -33,7 +33,7 @@ private static String unescape(String elt)
     
             boolean escaped = false;
             boolean quoted = false;
    -        StringBuffer buf = new StringBuffer(elt.length());
    +        StringBuilder buf = new StringBuilder(elt.length());
             int start = 0;
     
             // if it's an escaped hash string and not an actual encoding in string form
    @@ -48,8 +48,8 @@ private static String unescape(String elt)
             }
     
             boolean nonWhiteSpaceEncountered = false;
    -        int     lastEscaped = 0;
    -        char    hex1 = 0;
    +        int lastEscaped = 0;
    +        char hex1 = 0;
     
             for (int i = start; i != elt.length(); i++)
             {
    @@ -131,32 +131,30 @@ private static int convertHex(char c)
     
         public static RDN[] rDNsFromString(String name, X500NameStyle x500Style)
         {
    -        X500NameTokenizer tokenizer = new X500NameTokenizer(name);
             X500NameBuilder builder = new X500NameBuilder(x500Style);
     
    -        addRDNs(x500Style, builder, tokenizer);
    +        addRDNs(builder, new X500NameTokenizer(name));
     
    -        // TODO There's an unnecessary clone of the RDNs array happening here
    -        return builder.build().getRDNs();
    +        return builder.buildRDNs();
         }
     
    -    private static void addRDNs(X500NameStyle style, X500NameBuilder builder, X500NameTokenizer tokenizer)
    +    private static void addRDNs(X500NameBuilder builder, X500NameTokenizer tokenizer)
         {
             String token;
             while ((token = tokenizer.nextToken()) != null)
             {
                 if (token.indexOf('+') >= 0)
                 {
    -                addMultiValuedRDN(style, builder, new X500NameTokenizer(token, '+'));
    +                addMultiValuedRDN(builder, new X500NameTokenizer(token, '+'));
                 }
                 else
                 {
    -                addRDN(style, builder, token);
    +                addRDN(builder, token);
                 }
             }
         }
     
    -    private static void addMultiValuedRDN(X500NameStyle style, X500NameBuilder builder, X500NameTokenizer tokenizer)
    +    private static void addMultiValuedRDN(X500NameBuilder builder, X500NameTokenizer tokenizer)
         {
             String token = tokenizer.nextToken();
             if (token == null)
    @@ -166,13 +164,14 @@ private static void addMultiValuedRDN(X500NameStyle style, X500NameBuilder build
     
             if (!tokenizer.hasMoreTokens())
             {
    -            addRDN(style, builder, token);
    +            addRDN(builder, token);
                 return;
             }
     
             Vector oids = new Vector();
             Vector values = new Vector();
     
    +        X500NameStyle style = builder.getStyle();
             do
             {
                 collectAttributeTypeAndValue(style, oids, values, token);
    @@ -183,14 +182,14 @@ private static void addMultiValuedRDN(X500NameStyle style, X500NameBuilder build
             builder.addMultiValuedRDN(toOIDArray(oids), toValueArray(values));
         }
     
    -    private static void addRDN(X500NameStyle style, X500NameBuilder builder, String token)
    +    private static void addRDN(X500NameBuilder builder, String token)
         {
             X500NameTokenizer tokenizer = new X500NameTokenizer(token, '=');
     
             String typeToken = nextToken(tokenizer, true);
             String valueToken = nextToken(tokenizer, false);
     
    -        ASN1ObjectIdentifier oid = style.attrNameToOID(typeToken.trim());
    +        ASN1ObjectIdentifier oid = builder.getStyle().attrNameToOID(typeToken.trim());
             String value = unescape(valueToken);
     
             builder.addRDN(oid, value);
    @@ -246,10 +245,10 @@ private static ASN1ObjectIdentifier[] toOIDArray(Vector oids)
     
         public static String[] findAttrNamesForOID(
             ASN1ObjectIdentifier oid,
    -        Hashtable            lookup)
    +        Hashtable lookup)
         {
             int count = 0;
    -        for (Enumeration en = lookup.elements(); en.hasMoreElements();)
    +        for (Enumeration en = lookup.elements(); en.hasMoreElements(); )
             {
                 if (oid.equals(en.nextElement()))
                 {
    @@ -260,7 +259,7 @@ public static String[] findAttrNamesForOID(
             String[] aliases = new String[count];
             count = 0;
     
    -        for (Enumeration en = lookup.keys(); en.hasMoreElements();)
    +        for (Enumeration en = lookup.keys(); en.hasMoreElements(); )
             {
                 String key = (String)en.nextElement();
                 if (oid.equals(lookup.get(key)))
    @@ -295,8 +294,8 @@ public static ASN1ObjectIdentifier decodeAttrName(String name, Hashtable lookUp)
         }
     
         public static ASN1Encodable valueFromHexString(
    -        String  str,
    -        int     off)
    +        String str,
    +        int off)
             throws IOException
         {
             byte[] data = new byte[(str.length() - off) / 2];
    @@ -312,9 +311,9 @@ public static ASN1Encodable valueFromHexString(
         }
     
         public static void appendRDN(
    -        StringBuffer          buf,
    -        RDN                   rdn,
    -        Hashtable             oidSymbols)
    +        StringBuilder buf,
    +        RDN rdn,
    +        Hashtable oidSymbols)
         {
             if (rdn.isMultiValued())
             {
    @@ -337,19 +336,75 @@ public static void appendRDN(
             }
             else
             {
    -            if (rdn.getFirst() != null)
    +            AttributeTypeAndValue first = rdn.getFirst();
    +            if (first != null)
                 {
    -                IETFUtils.appendTypeAndValue(buf, rdn.getFirst(), oidSymbols);
    +                IETFUtils.appendTypeAndValue(buf, first, oidSymbols);
    +            }
    +        }
    +    }
    +
    +    public static void appendRDN(
    +        StringBuffer buf,
    +        RDN rdn,
    +        Hashtable oidSymbols)
    +    {
    +        if (rdn.isMultiValued())
    +        {
    +            AttributeTypeAndValue[] atv = rdn.getTypesAndValues();
    +            boolean firstAtv = true;
    +
    +            for (int j = 0; j != atv.length; j++)
    +            {
    +                if (firstAtv)
    +                {
    +                    firstAtv = false;
    +                }
    +                else
    +                {
    +                    buf.append('+');
    +                }
    +
    +                IETFUtils.appendTypeAndValue(buf, atv[j], oidSymbols);
    +            }
    +        }
    +        else
    +        {
    +            AttributeTypeAndValue first = rdn.getFirst();
    +            if (first != null)
    +            {
    +                IETFUtils.appendTypeAndValue(buf, first, oidSymbols);
                 }
             }
         }
     
         public static void appendTypeAndValue(
    -        StringBuffer          buf,
    +        StringBuilder buf,
             AttributeTypeAndValue typeAndValue,
    -        Hashtable             oidSymbols)
    +        Hashtable oidSymbols)
         {
    -        String  sym = (String)oidSymbols.get(typeAndValue.getType());
    +        String sym = (String)oidSymbols.get(typeAndValue.getType());
    +
    +        if (sym != null)
    +        {
    +            buf.append(sym);
    +        }
    +        else
    +        {
    +            buf.append(typeAndValue.getType().getId());
    +        }
    +
    +        buf.append('=');
    +
    +        buf.append(valueToString(typeAndValue.getValue()));
    +    }
    +
    +    public static void appendTypeAndValue(
    +        StringBuffer buf,
    +        AttributeTypeAndValue typeAndValue,
    +        Hashtable oidSymbols)
    +    {
    +        String sym = (String)oidSymbols.get(typeAndValue.getType());
     
             if (sym != null)
             {
    @@ -367,7 +422,7 @@ public static void appendTypeAndValue(
     
         public static String valueToString(ASN1Encodable value)
         {
    -        StringBuffer vBuf = new StringBuffer();
    +        StringBuilder vBuf = new StringBuilder();
     
             if (value instanceof ASN1String && !(value instanceof ASN1UniversalString))
             {
    @@ -405,25 +460,25 @@ public static String valueToString(ASN1Encodable value)
             {
                 switch (vBuf.charAt(index))
                 {
    -                case ',':
    -                case '"':
    -                case '\\':
    -                case '+':
    -                case '=':
    -                case '<':
    -                case '>':
    -                case ';':
    -                {
    -                    vBuf.insert(index, "\\");
    -                    index += 2;
    -                    ++end;
    -                    break;
    -                }
    -                default:
    -                {
    -                    ++index;
    -                    break;
    -                }
    +            case ',':
    +            case '"':
    +            case '\\':
    +            case '+':
    +            case '=':
    +            case '<':
    +            case '>':
    +            case ';':
    +            {
    +                vBuf.insert(index, "\\");
    +                index += 2;
    +                ++end;
    +                break;
    +            }
    +            default:
    +            {
    +                ++index;
    +                break;
    +            }
                 }
             }
     
    @@ -512,7 +567,7 @@ public static String stripInternalSpaces(
                 return str;
             }
     
    -        StringBuffer res = new StringBuffer();
    +        StringBuilder res = new StringBuilder();
     
             char c1 = str.charAt(0);
             res.append(c1);
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java
    index f07112f4a9..13ff8967fa 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java
    @@ -222,7 +222,7 @@ public RDN[] fromString(String dirName)
         // convert in reverse
         public String toString(X500Name name)
         {
    -        StringBuffer buf = new StringBuffer();
    +        StringBuilder buf = new StringBuilder();
             boolean first = true;
     
             RDN[] rdns = name.getRDNs();
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
    index 53333d9532..12b9270327 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
    @@ -12,18 +12,7 @@
     public class AlgorithmIdentifier
         extends ASN1Object
     {
    -    private ASN1ObjectIdentifier algorithm;
    -    private ASN1Encodable       parameters;
    -
    -    public static AlgorithmIdentifier getInstance(
    -        ASN1TaggedObject obj,
    -        boolean          explicit)
    -    {
    -        return getInstance(ASN1Sequence.getInstance(obj, explicit));
    -    }
    -    
    -    public static AlgorithmIdentifier getInstance(
    -        Object  obj)
    +    public static AlgorithmIdentifier getInstance(Object obj)
         {
             if (obj instanceof AlgorithmIdentifier)
             {
    @@ -37,6 +26,19 @@ else if (obj != null)
             return null;
         }
     
    +    public static AlgorithmIdentifier getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit)
    +    {
    +        return new AlgorithmIdentifier(ASN1Sequence.getInstance(taggedObject, declaredExplicit));
    +    }
    +
    +    public static AlgorithmIdentifier getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit)
    +    {
    +        return new AlgorithmIdentifier(ASN1Sequence.getTagged(taggedObject, declaredExplicit));
    +    }
    +
    +    private ASN1ObjectIdentifier algorithm;
    +    private ASN1Encodable       parameters;
    +
         public AlgorithmIdentifier(
             ASN1ObjectIdentifier algorithm)
         {
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java b/core/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
    index a494d62b43..9b0a88766a 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
    @@ -61,7 +61,7 @@ private AttributeCertificateInfo(
             }
             else
             {
    -            this.version = new ASN1Integer(0);
    +            this.version = ASN1Integer.ZERO;
                 start = 0;
             }
     
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
    index b0196c368e..570747a501 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
    @@ -35,15 +35,13 @@
     public class AuthorityKeyIdentifier
         extends ASN1Object
     {
    -    ASN1OctetString keyidentifier = null;
    +    ASN1OctetString keyIdentifier = null;
         GeneralNames certissuer = null;
         ASN1Integer certserno = null;
     
    -    public static AuthorityKeyIdentifier getInstance(
    -        ASN1TaggedObject obj,
    -        boolean          explicit)
    +    public static AuthorityKeyIdentifier getInstance(ASN1TaggedObject obj, boolean explicit)
         {
    -        return getInstance(ASN1Sequence.getInstance(obj, explicit));
    +        return new AuthorityKeyIdentifier(ASN1Sequence.getInstance(obj, explicit));
         }
     
         public static AuthorityKeyIdentifier getInstance(
    @@ -78,7 +76,7 @@ protected AuthorityKeyIdentifier(
                 switch (o.getTagNo())
                 {
                 case 0:
    -                this.keyidentifier = ASN1OctetString.getInstance(o, false);
    +                this.keyIdentifier = ASN1OctetString.getInstance(o, false);
                     break;
                 case 1:
                     this.certissuer = GeneralNames.getInstance(o, false);
    @@ -128,7 +126,7 @@ public AuthorityKeyIdentifier(
             digest.update(bytes, 0, bytes.length);
             digest.doFinal(resBuf, 0);
     
    -        this.keyidentifier = new DEROctetString(resBuf);
    +        this.keyIdentifier = new DEROctetString(resBuf);
             this.certissuer = name;
             this.certserno = (serialNumber != null) ? new ASN1Integer(serialNumber) : null;
         }
    @@ -162,21 +160,34 @@ public AuthorityKeyIdentifier(
             GeneralNames            name,
             BigInteger              serialNumber)
         {
    -        this.keyidentifier = (keyIdentifier != null) ? new DEROctetString(Arrays.clone(keyIdentifier)) : null;
    +        this.keyIdentifier = (keyIdentifier != null) ? new DEROctetString(Arrays.clone(keyIdentifier)) : null;
             this.certissuer = name;
             this.certserno = (serialNumber != null) ? new ASN1Integer(serialNumber) : null;
         }
    -    
    +
    +    /**
    +     * @deprecated Use {@link #getKeyIdentifierOctets()} instead. 
    +     */
         public byte[] getKeyIdentifier()
         {
    -        if (keyidentifier != null)
    +        return getKeyIdentifierOctets();
    +    }
    +
    +    public byte[] getKeyIdentifierOctets()
    +    {
    +        if (keyIdentifier != null)
             {
    -            return keyidentifier.getOctets();
    +            return keyIdentifier.getOctets();
             }
     
             return null;
         }
     
    +    public ASN1OctetString getKeyIdentifierObject()
    +    {
    +        return keyIdentifier;
    +    }
    +
         public GeneralNames getAuthorityCertIssuer()
         {
             return certissuer;
    @@ -199,9 +210,9 @@ public ASN1Primitive toASN1Primitive()
         {
             ASN1EncodableVector v = new ASN1EncodableVector(3);
     
    -        if (keyidentifier != null)
    +        if (keyIdentifier != null)
             {
    -            v.add(new DERTaggedObject(false, 0, keyidentifier));
    +            v.add(new DERTaggedObject(false, 0, keyIdentifier));
             }
     
             if (certissuer != null)
    @@ -220,7 +231,7 @@ public ASN1Primitive toASN1Primitive()
         public String toString()
         {
             // -DM Hex.toHexString
    -        String keyID = (keyidentifier != null) ? Hex.toHexString(keyidentifier.getOctets()) : "null";
    +        String keyID = (keyIdentifier != null) ? Hex.toHexString(keyIdentifier.getOctets()) : "null";
     
             return "AuthorityKeyIdentifier: KeyID(" + keyID + ")";
         }
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java b/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java
    index 4773c7f863..0bbd61b3c6 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java
    @@ -104,7 +104,7 @@ public BasicConstraints(
             int     pathLenConstraint)
         {
             this.cA = ASN1Boolean.getInstance(true);
    -        this.pathLenConstraint = new ASN1Integer(pathLenConstraint);
    +        this.pathLenConstraint = ASN1Integer.valueOf(pathLenConstraint);
         }
     
         public boolean isCA()
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java b/core/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java
    index 1aa3f38d04..4c1425a18c 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/CRLDistPoint.java
    @@ -81,7 +81,7 @@ public ASN1Primitive toASN1Primitive()
     
         public String toString()
         {
    -        StringBuffer buf = new StringBuffer();
    +        StringBuilder buf = new StringBuilder();
             String       sep = Strings.lineSeparator();
     
             buf.append("CRLDistPoint:");
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java b/core/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
    index c4c14d9947..dc848c6519 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/CertificateList.java
    @@ -117,6 +117,11 @@ public Time getNextUpdate()
             return tbsCertList.getNextUpdate();
         }
     
    +    public Extensions getExtensions()
    +    {
    +        return tbsCertList.getExtensions();
    +    }
    +
         public ASN1Primitive toASN1Primitive()
         {
             ASN1EncodableVector v = new ASN1EncodableVector(3);
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/CertificatePolicies.java b/core/src/main/java/org/bouncycastle/asn1/x509/CertificatePolicies.java
    index 5b4385a24f..aac282796a 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/CertificatePolicies.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/CertificatePolicies.java
    @@ -112,7 +112,7 @@ public ASN1Primitive toASN1Primitive()
     
         public String toString()
         {
    -        StringBuffer p = new StringBuffer();
    +        StringBuilder p = new StringBuilder();
             for (int i = 0; i < policyInformation.length; i++)
             {
                 if (p.length() != 0)
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java b/core/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java
    index 368b12af1d..a21e869c69 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/DistributionPoint.java
    @@ -127,7 +127,7 @@ public ASN1Primitive toASN1Primitive()
         public String toString()
         {
             String       sep = Strings.lineSeparator();
    -        StringBuffer buf = new StringBuffer();
    +        StringBuilder buf = new StringBuilder();
             buf.append("DistributionPoint: [");
             buf.append(sep);
             if (distributionPoint != null)
    @@ -147,7 +147,7 @@ public String toString()
             return buf.toString();
         }
     
    -    private void appendObject(StringBuffer buf, String sep, String name, String value)
    +    private void appendObject(StringBuilder buf, String sep, String name, String value)
         {
             String       indent = "    ";
     
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java b/core/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java
    index f69ccb3a40..8570259388 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/DistributionPointName.java
    @@ -6,6 +6,7 @@
     import org.bouncycastle.asn1.ASN1Primitive;
     import org.bouncycastle.asn1.ASN1Set;
     import org.bouncycastle.asn1.ASN1TaggedObject;
    +import org.bouncycastle.asn1.ASN1Util;
     import org.bouncycastle.asn1.DERTaggedObject;
     import org.bouncycastle.util.Strings;
     
    @@ -22,21 +23,10 @@ public class DistributionPointName
         extends ASN1Object
         implements ASN1Choice
     {
    -    ASN1Encodable        name;
    -    int                 type;
    -
         public static final int FULL_NAME = 0;
         public static final int NAME_RELATIVE_TO_CRL_ISSUER = 1;
     
    -    public static DistributionPointName getInstance(
    -        ASN1TaggedObject obj,
    -        boolean          explicit)
    -    {
    -        return getInstance(ASN1TaggedObject.getInstance(obj, true));
    -    }
    -
    -    public static DistributionPointName getInstance(
    -        Object  obj)
    +    public static DistributionPointName getInstance(Object obj)
         {
             if (obj == null || obj instanceof DistributionPointName)
             {
    @@ -50,6 +40,19 @@ else if (obj instanceof ASN1TaggedObject)
             throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
         }
     
    +    public static DistributionPointName getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit)
    +    {
    +        return getInstance(ASN1Util.getInstanceChoiceBaseObject(taggedObject, declaredExplicit, "DistributionPointName"));
    +    }
    +
    +    public static DistributionPointName getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit)
    +    {
    +        return getInstance(ASN1Util.getTaggedChoiceBaseObject(taggedObject, declaredExplicit, "DistributionPointName"));
    +    }
    +
    +    private final ASN1Encodable name;
    +    private final int type;
    +
         public DistributionPointName(
             int             type,
             ASN1Encodable   name)
    @@ -83,22 +86,25 @@ public ASN1Encodable getName()
         {
             return (ASN1Encodable)name;
         }
    -    
    -    public DistributionPointName(
    -        ASN1TaggedObject    obj)
    +
    +    public DistributionPointName(ASN1TaggedObject obj)
         {
             this.type = obj.getTagNo();
    -        
    -        if (type == 0)
    +
    +        if (obj.hasContextTag(FULL_NAME))
             {
                 this.name = GeneralNames.getInstance(obj, false);
             }
    -        else
    +        else if (obj.hasContextTag(NAME_RELATIVE_TO_CRL_ISSUER))
             {
                 this.name = ASN1Set.getInstance(obj, false);
             }
    +        else
    +        {
    +            throw new IllegalArgumentException("unknown tag: " + ASN1Util.getTagText(obj));
    +        }
         }
    -    
    +
         public ASN1Primitive toASN1Primitive()
         {
             return new DERTaggedObject(false, type, name);
    @@ -107,7 +113,7 @@ public ASN1Primitive toASN1Primitive()
         public String toString()
         {
             String       sep = Strings.lineSeparator();
    -        StringBuffer buf = new StringBuffer();
    +        StringBuilder buf = new StringBuilder();
             buf.append("DistributionPointName: [");
             buf.append(sep);
             if (type == FULL_NAME)
    @@ -123,7 +129,7 @@ public String toString()
             return buf.toString();
         }
     
    -    private void appendObject(StringBuffer buf, String sep, String name, String value)
    +    private void appendObject(StringBuilder buf, String sep, String name, String value)
         {
             String       indent = "    ";
     
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/Extensions.java b/core/src/main/java/org/bouncycastle/asn1/x509/Extensions.java
    index c552d370b7..4434183613 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/Extensions.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/Extensions.java
    @@ -8,6 +8,7 @@
     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.ASN1TaggedObject;
    @@ -40,6 +41,11 @@ public static ASN1Encodable getExtensionParsedValue(Extensions extensions, ASN1O
             return null == extensions ? null : extensions.getExtensionParsedValue(oid);
         }
     
    +    public static ASN1OctetString getExtensionValue(Extensions extensions, ASN1ObjectIdentifier oid)
    +    {
    +        return null == extensions ? null : extensions.getExtensionValue(oid);
    +    }
    +
         public static Extensions getInstance(
             ASN1TaggedObject obj,
             boolean explicit)
    @@ -141,8 +147,7 @@ public Enumeration oids()
          *
          * @return the extension if it's present, null otherwise.
          */
    -    public Extension getExtension(
    -        ASN1ObjectIdentifier oid)
    +    public Extension getExtension(ASN1ObjectIdentifier oid)
         {
             return (Extension)extensions.get(oid);
         }
    @@ -155,14 +160,19 @@ public Extension getExtension(
          */
         public ASN1Encodable getExtensionParsedValue(ASN1ObjectIdentifier oid)
         {
    -        Extension ext = this.getExtension(oid);
    -
    -        if (ext != null)
    -        {
    -            return ext.getParsedValue();
    -        }
    +        Extension ext = getExtension(oid);
    +        return ext == null ? null : ext.getParsedValue();
    +    }
     
    -        return null;
    +    /**
    +     * return the value of the extension represented by the object identifier passed in.
    +     *
    +     * @return the value of the extension if it's present, null otherwise.
    +     */
    +    public ASN1OctetString getExtensionValue(ASN1ObjectIdentifier oid)
    +    {
    +        Extension ext = getExtension(oid);
    +        return ext == null ? null : ext.getExtnValue();
         }
     
         /**
    @@ -229,6 +239,21 @@ public ASN1ObjectIdentifier[] getCriticalExtensionOIDs()
             return getExtensionOIDs(true);
         }
     
    +    public boolean hasAnyCriticalExtensions()
    +    {
    +        for (int i = 0; i != ordering.size(); i++)
    +        {
    +            Object oid = ordering.elementAt(i);
    +
    +            if (((Extension)extensions.get(oid)).isCritical())
    +            {
    +                return true;
    +            }
    +        }
    +
    +        return false;
    +    }
    +
         private ASN1ObjectIdentifier[] getExtensionOIDs(boolean isCritical)
         {
             Vector oidVec = new Vector();
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java b/core/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java
    index 20c19100e4..521745562e 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/GeneralName.java
    @@ -248,7 +248,7 @@ public ASN1Encodable getName()
     
         public String toString()
         {
    -        StringBuffer buf = new StringBuffer();
    +        StringBuilder buf = new StringBuilder();
     
             buf.append(tag);
             buf.append(": ");
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java b/core/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java
    index 5ba472bf84..6308f5f6b2 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/GeneralNames.java
    @@ -95,7 +95,7 @@ public ASN1Primitive toASN1Primitive()
     
         public String toString()
         {
    -        StringBuffer  buf = new StringBuffer();
    +        StringBuilder buf = new StringBuilder();
             String        sep = Strings.lineSeparator();
     
             buf.append("GeneralNames:");
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java b/core/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
    index ef78f62aa7..2adb17c5be 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java
    @@ -84,6 +84,12 @@ public IssuingDistributionPoint(
             boolean indirectCRL,
             boolean onlyContainsAttributeCerts)
         {
    +        if ((onlyContainsCACerts && (onlyContainsUserCerts || onlyContainsAttributeCerts))
    +            || (onlyContainsUserCerts && onlyContainsAttributeCerts))
    +        {
    +            throw new IllegalArgumentException("only one of onlyContainsCACerts, onlyContainsUserCerts, or onlyContainsAttributeCerts can be true");
    +        }
    +
             this.distributionPoint = distributionPoint;
             this.indirectCRL = indirectCRL;
             this.onlyContainsAttributeCerts = onlyContainsAttributeCerts;
    @@ -222,7 +228,7 @@ public ASN1Primitive toASN1Primitive()
         public String toString()
         {
             String       sep = Strings.lineSeparator();
    -        StringBuffer buf = new StringBuffer();
    +        StringBuilder buf = new StringBuilder();
     
             buf.append("IssuingDistributionPoint: [");
             buf.append(sep);
    @@ -255,7 +261,7 @@ public String toString()
             return buf.toString();
         }
     
    -    private void appendObject(StringBuffer buf, String sep, String name, String value)
    +    private void appendObject(StringBuilder buf, String sep, String name, String value)
         {
             String       indent = "    ";
     
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/NoticeReference.java b/core/src/main/java/org/bouncycastle/asn1/x509/NoticeReference.java
    index 5e95972185..c8aff8120f 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/NoticeReference.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/NoticeReference.java
    @@ -48,7 +48,7 @@ private static ASN1EncodableVector convertVector(Vector numbers)
                 }
                 else if (o instanceof Integer)
                 {
    -                di = new ASN1Integer(((Integer)o).intValue());
    +                di = ASN1Integer.valueOf(((Integer)o).intValue());
                 }
                 else
                 {
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java b/core/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java
    index 3b584a8b60..f2d74d5cac 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/PolicyInformation.java
    @@ -89,14 +89,14 @@ public ASN1Primitive toASN1Primitive()
     
         public String toString()
         {
    -        StringBuffer sb = new StringBuffer();
    +        StringBuilder sb = new StringBuilder();
     
             sb.append("Policy information: ");
             sb.append(policyIdentifier);
     
             if (policyQualifiers != null)
             {
    -            StringBuffer p = new StringBuffer();
    +            StringBuilder p = new StringBuilder();
                 for (int i = 0; i < policyQualifiers.size(); i++)
                 {
                     if (p.length() != 0)
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/PrivateKeyPossessionStatement.java b/core/src/main/java/org/bouncycastle/asn1/x509/PrivateKeyPossessionStatement.java
    new file mode 100644
    index 0000000000..004a7455b7
    --- /dev/null
    +++ b/core/src/main/java/org/bouncycastle/asn1/x509/PrivateKeyPossessionStatement.java
    @@ -0,0 +1,91 @@
    +package org.bouncycastle.asn1.x509;
    +
    +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.IssuerAndSerialNumber;
    +
    +/**
    + * 
    + * PrivateKeyPossessionStatement ::= SEQUENCE {
    + *       signer  IssuerAndSerialNumber,
    + *       cert    Certificate OPTIONAL }
    + * 
    + */ +public class PrivateKeyPossessionStatement + extends ASN1Object +{ + private final IssuerAndSerialNumber signer; + private final Certificate cert; + + public static PrivateKeyPossessionStatement getInstance(Object obj) + { + if (obj instanceof PrivateKeyPossessionStatement) + { + return (PrivateKeyPossessionStatement)obj; + } + + if (obj != null) + { + return new PrivateKeyPossessionStatement(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private PrivateKeyPossessionStatement(ASN1Sequence seq) + { + if (seq.size() == 1) + { + this.signer = IssuerAndSerialNumber.getInstance(seq.getObjectAt(0)); + this.cert = null; + } + else if (seq.size() == 2) + { + this.signer = IssuerAndSerialNumber.getInstance(seq.getObjectAt(0)); + this.cert = Certificate.getInstance(seq.getObjectAt(1)); + } + else + { + throw new IllegalArgumentException("unknown sequence in PrivateKeyStatement"); + } + } + + public PrivateKeyPossessionStatement(IssuerAndSerialNumber signer) + { + this.signer = signer; + this.cert = null; + } + + public PrivateKeyPossessionStatement(Certificate cert) + { + this.signer = new IssuerAndSerialNumber(cert.getIssuer(), cert.getSerialNumber().getValue()); + this.cert = cert; + } + + public IssuerAndSerialNumber getSigner() + { + return signer; + } + + public Certificate getCert() + { + return cert; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(2); + + v.add(signer); + + if (cert != null) + { + v.add(cert); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/PrivateKeyStatement.java b/core/src/main/java/org/bouncycastle/asn1/x509/PrivateKeyStatement.java new file mode 100644 index 0000000000..07050647ac --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x509/PrivateKeyStatement.java @@ -0,0 +1,93 @@ +package org.bouncycastle.asn1.x509; + +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.IssuerAndSerialNumber; + +/** + *
    + * PrivateKeyStatement ::= SEQUENCE {
    + *       signer  IssuerAndSerialNumber,
    + *       cert    Certificate OPTIONAL }
    + * 
    + * @deprecated use PrivateKeyPossessionStatement + */ +@Deprecated +public class PrivateKeyStatement + extends ASN1Object +{ + private final IssuerAndSerialNumber signer; + private final Certificate cert; + + public static PrivateKeyStatement getInstance(Object obj) + { + if (obj instanceof PrivateKeyStatement) + { + return (PrivateKeyStatement)obj; + } + + if (obj != null) + { + return new PrivateKeyStatement(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private PrivateKeyStatement(ASN1Sequence seq) + { + if (seq.size() == 1) + { + this.signer = IssuerAndSerialNumber.getInstance(seq.getObjectAt(0)); + this.cert = null; + } + else if (seq.size() == 2) + { + this.signer = IssuerAndSerialNumber.getInstance(seq.getObjectAt(0)); + this.cert = Certificate.getInstance(seq.getObjectAt(1)); + } + else + { + throw new IllegalArgumentException("unknown sequence in PrivateKeyStatement"); + } + } + + public PrivateKeyStatement(IssuerAndSerialNumber signer) + { + this.signer = signer; + this.cert = null; + } + + public PrivateKeyStatement(Certificate cert) + { + this.signer = new IssuerAndSerialNumber(cert.getIssuer(), cert.getSerialNumber().getValue()); + this.cert = cert; + } + + public IssuerAndSerialNumber getSigner() + { + return signer; + } + + public Certificate getCert() + { + return cert; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(2); + + v.add(signer); + + if (cert != null) + { + v.add(cert); + } + + return new DERSequence(v); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/RoleSyntax.java b/core/src/main/java/org/bouncycastle/asn1/x509/RoleSyntax.java index d6926bddd5..d043d1a308 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/RoleSyntax.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/RoleSyntax.java @@ -216,7 +216,7 @@ public ASN1Primitive toASN1Primitive() public String toString() { - StringBuffer buff = new StringBuffer("Name: " + this.getRoleNameAsString() + + StringBuilder buff = new StringBuilder("Name: " + this.getRoleNameAsString() + " - Auth: "); if(this.roleAuthority == null || roleAuthority.getNames().length == 0) { diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java b/core/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java index 2e8dad1a60..a8b51780a9 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java @@ -74,6 +74,7 @@ public SubjectPublicKeyInfo( /** @deprecated use SubjectPublicKeyInfo.getInstance() */ + @Deprecated public SubjectPublicKeyInfo( ASN1Sequence seq) { @@ -98,6 +99,7 @@ public AlgorithmIdentifier getAlgorithm() * @deprecated use getAlgorithm() * @return alg ID. */ + @Deprecated public AlgorithmIdentifier getAlgorithmId() { return algId; @@ -126,6 +128,7 @@ public ASN1Primitive parsePublicKey() * @deprecated use parsePublicKey * @return the public key as an ASN.1 primitive. */ + @Deprecated public ASN1Primitive getPublicKey() throws IOException { diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java b/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java index 66716c0247..6b87cc1a68 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertificate.java @@ -87,7 +87,7 @@ private TBSCertificate( else { seqStart = -1; // field 0 is missing! - version = new ASN1Integer(0); + version = ASN1Integer.ZERO; } boolean isV1 = false; @@ -175,7 +175,7 @@ public TBSCertificate(ASN1Integer version, ASN1Integer serialNumber, AlgorithmId throw new NullPointerException("'subjectPublicKeyInfo' cannot be null"); } - this.version = version != null ? version : new ASN1Integer(0); + this.version = version != null ? version : ASN1Integer.ZERO; this.serialNumber = serialNumber; this.signature = signature; this.issuer = issuer; diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java b/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java index 3125c7b6b9..00ccdb41d9 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/TBSCertificateStructure.java @@ -86,7 +86,7 @@ public TBSCertificateStructure( else { seqStart = -1; // field 0 is missing! - version = new ASN1Integer(0); + version = ASN1Integer.ZERO; } serialNumber = ASN1Integer.getInstance(seq.getObjectAt(seqStart + 1)); diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java b/core/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java index 4d871eeb45..079ac551c7 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java @@ -22,7 +22,7 @@ */ public class V1TBSCertificateGenerator { - DERTaggedObject version = new DERTaggedObject(true, 0, new ASN1Integer(0)); + DERTaggedObject version = new DERTaggedObject(true, 0, ASN1Integer.ZERO); ASN1Integer serialNumber; AlgorithmIdentifier signature; @@ -122,7 +122,7 @@ public TBSCertificate generateTBSCertificate() throw new IllegalStateException("not all mandatory fields set in V1 TBScertificate generator"); } - return new TBSCertificate(new ASN1Integer(0), serialNumber, signature, issuer, + return new TBSCertificate(ASN1Integer.ZERO, serialNumber, signature, issuer, validity != null ? validity : new Validity(startDate, endDate), subject, subjectPublicKeyInfo, null, null, null); } diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java b/core/src/main/java/org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java index b4c1693145..2d29419888 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java @@ -43,8 +43,8 @@ public class V2AttributeCertificateInfoGenerator public V2AttributeCertificateInfoGenerator() { - this.version = new ASN1Integer(1); - attributes = new ASN1EncodableVector(); + this.version = ASN1Integer.ONE; + this.attributes = new ASN1EncodableVector(); } public void setHolder(Holder holder) diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java b/core/src/main/java/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java index 0939a1f940..afd52a9898 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java @@ -37,7 +37,7 @@ */ public class V2TBSCertListGenerator { - private ASN1Integer version = new ASN1Integer(1); + private ASN1Integer version = ASN1Integer.ONE; private AlgorithmIdentifier signature; private X500Name issuer; private Time thisUpdate, nextUpdate=null; @@ -195,6 +195,10 @@ public void addCRLEntry(ASN1Integer userCertificate, Time revocationDate, Extens addCRLEntry(new DERSequence(v)); } + /** + * @deprecated use the method taking Extensions + */ + @Deprecated public void setExtensions( X509Extensions extensions) { diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java b/core/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java index fea58c93b5..12fe4a1b0b 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java @@ -29,7 +29,7 @@ */ public class V3TBSCertificateGenerator { - private static final DERTaggedObject VERSION = new DERTaggedObject(true, 0, new ASN1Integer(2)); + private static final DERTaggedObject VERSION = new DERTaggedObject(true, 0, ASN1Integer.TWO); ASN1Integer serialNumber; AlgorithmIdentifier signature; @@ -212,7 +212,7 @@ public TBSCertificate generateTBSCertificate() throw new IllegalStateException("not all mandatory fields set in V3 TBScertificate generator"); } - return new TBSCertificate(new ASN1Integer(2), serialNumber, signature, issuer, + return new TBSCertificate(ASN1Integer.TWO, serialNumber, signature, issuer, validity != null ? validity : new Validity(startDate, endDate), subject != null ? subject : X500Name.getInstance(new DERSequence()), subjectPublicKeyInfo, issuerUniqueID, subjectUniqueID, extensions); diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509AttributeIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509AttributeIdentifiers.java index 0ed12f7eb6..a7a36cbfb9 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/X509AttributeIdentifiers.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509AttributeIdentifiers.java @@ -7,23 +7,31 @@ public interface X509AttributeIdentifiers /** * @deprecated use id_at_role */ - static final ASN1ObjectIdentifier RoleSyntax = new ASN1ObjectIdentifier("2.5.4.72"); + @Deprecated + ASN1ObjectIdentifier RoleSyntax = new ASN1ObjectIdentifier("2.5.4.72"); - static final ASN1ObjectIdentifier id_pe_ac_auditIdentity = X509ObjectIdentifiers.id_pe.branch("4"); - static final ASN1ObjectIdentifier id_pe_aaControls = X509ObjectIdentifiers.id_pe.branch("6"); - static final ASN1ObjectIdentifier id_pe_ac_proxying = X509ObjectIdentifiers.id_pe.branch("10"); + ASN1ObjectIdentifier id_pe_ac_auditIdentity = X509ObjectIdentifiers.id_pe.branch("4"); + ASN1ObjectIdentifier id_pe_aaControls = X509ObjectIdentifiers.id_pe.branch("6"); + ASN1ObjectIdentifier id_pe_ac_proxying = X509ObjectIdentifiers.id_pe.branch("10"); - static final ASN1ObjectIdentifier id_ce_targetInformation= X509ObjectIdentifiers.id_ce.branch("55"); + ASN1ObjectIdentifier id_ce_targetInformation = X509ObjectIdentifiers.id_ce.branch("55"); - static final ASN1ObjectIdentifier id_aca = X509ObjectIdentifiers.id_pkix.branch("10"); + ASN1ObjectIdentifier id_aca = X509ObjectIdentifiers.id_pkix.branch("10"); - static final ASN1ObjectIdentifier id_aca_authenticationInfo = id_aca.branch("1"); - static final ASN1ObjectIdentifier id_aca_accessIdentity = id_aca.branch("2"); - static final ASN1ObjectIdentifier id_aca_chargingIdentity = id_aca.branch("3"); - static final ASN1ObjectIdentifier id_aca_group = id_aca.branch("4"); + ASN1ObjectIdentifier id_aca_authenticationInfo = id_aca.branch("1"); + ASN1ObjectIdentifier id_aca_accessIdentity = id_aca.branch("2"); + ASN1ObjectIdentifier id_aca_chargingIdentity = id_aca.branch("3"); + ASN1ObjectIdentifier id_aca_group = id_aca.branch("4"); // { id-aca 5 } is reserved - static final ASN1ObjectIdentifier id_aca_encAttrs = id_aca.branch("6"); + ASN1ObjectIdentifier id_aca_encAttrs = id_aca.branch("6"); - static final ASN1ObjectIdentifier id_at_role = new ASN1ObjectIdentifier("2.5.4.72"); - static final ASN1ObjectIdentifier id_at_clearance = new ASN1ObjectIdentifier("2.5.1.5.55"); + ASN1ObjectIdentifier id_at_role = new ASN1ObjectIdentifier("2.5.4.72"); + ASN1ObjectIdentifier id_at_clearance = new ASN1ObjectIdentifier("2.5.1.5.55"); + + /** + * @deprecated use statementOfPossession + */ + @Deprecated + ASN1ObjectIdentifier id_at_privateKeyStatement = new ASN1ObjectIdentifier("1.3.6.1.4.1.22112.2.1"); + ASN1ObjectIdentifier id_at_statementOfPossession = new ASN1ObjectIdentifier("1.3.6.1.4.1.22112.2.1"); } diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java index b43ecd3103..c597f14108 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java @@ -12,7 +12,6 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERSequence; /** @@ -237,7 +236,7 @@ public static X509Extensions getInstance( if (obj instanceof ASN1TaggedObject) { - ASN1TaggedObject taggedObject = ASN1TaggedObject.getInstance(obj, BERTags.CONTEXT_SPECIFIC); + ASN1TaggedObject taggedObject = ASN1TaggedObject.getContextInstance(obj); return getInstance(taggedObject.getBaseObject().toASN1Primitive()); } diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509Name.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509Name.java index 031ff10dd0..69e67f662c 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/X509Name.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509Name.java @@ -1079,6 +1079,11 @@ public boolean equals(Object obj) { return false; } + + if (orderingSize == 0) + { + return true; + } boolean[] indexes = new boolean[orderingSize]; int start, end, delta; diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java index 7f99235bf9..773390e4cf 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509NameTokenizer.java @@ -25,18 +25,18 @@ public X509NameTokenizer( char separator) { this.value = oid; - this.index = -1; + this.index = oid.length() < 1 ? 0 : -1; this.separator = separator; } public boolean hasMoreTokens() { - return (index != value.length()); + return index < value.length(); } public String nextToken() { - if (index == value.length()) + if (index >= value.length()) { return null; } diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java index a6bc6e531c..c05382363d 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509ObjectIdentifiers.java @@ -31,7 +31,7 @@ public interface X509ObjectIdentifiers * id-SHA1 OBJECT IDENTIFIER ::= * {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } *

    - * OID: 1.3.14.3.2.27 + * OID: 1.3.14.3.2.26 */ static final ASN1ObjectIdentifier id_SHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.26").intern(); @@ -95,6 +95,16 @@ public interface X509ObjectIdentifiers */ static final ASN1ObjectIdentifier id_ecdsa_with_shake256 = pkix_algorithms.branch("33"); + /** + * id-alg-noSignature OBJECT IDENTIFIER ::= {id-pkix id-alg(6) 2} + */ + ASN1ObjectIdentifier id_alg_noSignature = pkix_algorithms.branch("2"); + + /** + * id-alg-unsigned OBJECT IDENTIFIER ::= {id-pkix id-alg(6) 36} + */ + ASN1ObjectIdentifier id_alg_unsigned = pkix_algorithms.branch("36"); + /** 1.3.6.1.5.5.7.9 */ static final ASN1ObjectIdentifier id_pda = id_pkix.branch("9"); diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/qualified/Iso4217CurrencyCode.java b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/Iso4217CurrencyCode.java index 3e18e1fe39..9fa9e2d664 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/qualified/Iso4217CurrencyCode.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/Iso4217CurrencyCode.java @@ -59,7 +59,7 @@ public Iso4217CurrencyCode( { throw new IllegalArgumentException("wrong size in numeric code : not in (" +NUMERIC_MINSIZE +".."+ NUMERIC_MAXSIZE +")"); } - obj = new ASN1Integer(numeric); + obj = ASN1Integer.valueOf(numeric); } public Iso4217CurrencyCode( diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/qualified/MonetaryValue.java b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/MonetaryValue.java index ecc8c17886..51fae96d7c 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/qualified/MonetaryValue.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/MonetaryValue.java @@ -61,8 +61,8 @@ public MonetaryValue( int exponent) { this.currency = currency; - this.amount = new ASN1Integer(amount); - this.exponent = new ASN1Integer(exponent); + this.amount = ASN1Integer.valueOf(amount); + this.exponent = ASN1Integer.valueOf(exponent); } public Iso4217CurrencyCode getCurrency() diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/qualified/TypeOfBiometricData.java b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/TypeOfBiometricData.java index 6b9f2e2f4a..0c63846162 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/qualified/TypeOfBiometricData.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/qualified/TypeOfBiometricData.java @@ -55,7 +55,7 @@ public TypeOfBiometricData(int predefinedBiometricType) { if (predefinedBiometricType == PICTURE || predefinedBiometricType == HANDWRITTEN_SIGNATURE) { - obj = new ASN1Integer(predefinedBiometricType); + obj = ASN1Integer.valueOf(predefinedBiometricType); } else { diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/KeySpecificInfo.java b/core/src/main/java/org/bouncycastle/asn1/x9/KeySpecificInfo.java index 7495567cb9..a89f290b98 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x9/KeySpecificInfo.java +++ b/core/src/main/java/org/bouncycastle/asn1/x9/KeySpecificInfo.java @@ -1,12 +1,11 @@ package org.bouncycastle.asn1.x9; -import java.util.Enumeration; - 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.ASN1TaggedObject; import org.bouncycastle.asn1.DERSequence; /** @@ -22,23 +21,6 @@ public class KeySpecificInfo extends ASN1Object { - private ASN1ObjectIdentifier algorithm; - private ASN1OctetString counter; - - /** - * Base constructor. - * - * @param algorithm algorithm identifier for the CEK. - * @param counter initial counter value for key derivation. - */ - public KeySpecificInfo( - ASN1ObjectIdentifier algorithm, - ASN1OctetString counter) - { - this.algorithm = algorithm; - this.counter = counter; - } - /** * Return a KeySpecificInfo object from the passed in object. * @@ -59,13 +41,50 @@ else if (obj != null) return null; } - private KeySpecificInfo( - ASN1Sequence seq) + public static KeySpecificInfo getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return new KeySpecificInfo(ASN1Sequence.getInstance(taggedObject, declaredExplicit)); + } + + public static KeySpecificInfo getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return new KeySpecificInfo(ASN1Sequence.getTagged(taggedObject, declaredExplicit)); + } + + private final ASN1ObjectIdentifier algorithm; + private final ASN1OctetString counter; + + private KeySpecificInfo(ASN1Sequence seq) { - Enumeration e = seq.getObjects(); + int count = seq.size(); + if (count != 2) + { + throw new IllegalArgumentException("Bad sequence size: " + count); + } + + this.algorithm = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + this.counter = ASN1OctetString.getInstance(seq.getObjectAt(1)); + } - algorithm = (ASN1ObjectIdentifier)e.nextElement(); - counter = (ASN1OctetString)e.nextElement(); + /** + * Base constructor. + * + * @param algorithm algorithm identifier for the CEK. + * @param counter initial counter value for key derivation. + */ + public KeySpecificInfo(ASN1ObjectIdentifier algorithm, ASN1OctetString counter) + { + if (algorithm == null) + { + throw new NullPointerException("'algorithm' cannot be null"); + } + if (counter == null) + { + throw new NullPointerException("'counter' cannot be null"); + } + + this.algorithm = algorithm; + this.counter = counter; } /** diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/OtherInfo.java b/core/src/main/java/org/bouncycastle/asn1/x9/OtherInfo.java index 0ec5c6faf1..f5aa1a64ce 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x9/OtherInfo.java +++ b/core/src/main/java/org/bouncycastle/asn1/x9/OtherInfo.java @@ -1,7 +1,5 @@ package org.bouncycastle.asn1.x9; -import java.util.Enumeration; - import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1OctetString; @@ -25,20 +23,6 @@ public class OtherInfo extends ASN1Object { - private KeySpecificInfo keyInfo; - private ASN1OctetString partyAInfo; - private ASN1OctetString suppPubInfo; - - public OtherInfo( - KeySpecificInfo keyInfo, - ASN1OctetString partyAInfo, - ASN1OctetString suppPubInfo) - { - this.keyInfo = keyInfo; - this.partyAInfo = partyAInfo; - this.suppPubInfo = suppPubInfo; - } - /** * Return a OtherInfo object from the passed in object. * @@ -59,26 +43,66 @@ else if (obj != null) return null; } - private OtherInfo( - ASN1Sequence seq) + public static OtherInfo getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - Enumeration e = seq.getObjects(); + return new OtherInfo(ASN1Sequence.getInstance(taggedObject, declaredExplicit)); + } - keyInfo = KeySpecificInfo.getInstance(e.nextElement()); + public static OtherInfo getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return new OtherInfo(ASN1Sequence.getTagged(taggedObject, declaredExplicit)); + } + + private final KeySpecificInfo keyInfo; + private final ASN1OctetString partyAInfo; + private final ASN1OctetString suppPubInfo; - while (e.hasMoreElements()) + private OtherInfo(ASN1Sequence seq) + { + int count = seq.size(), pos = 0; + if (count < 2 || count > 3) { - ASN1TaggedObject o = (ASN1TaggedObject)e.nextElement(); + throw new IllegalArgumentException("Bad sequence size: " + count); + } - if (o.hasContextTag(0)) - { - partyAInfo = (ASN1OctetString)o.getExplicitBaseObject(); - } - else if (o.hasContextTag(2)) + this.keyInfo = KeySpecificInfo.getInstance(seq.getObjectAt(pos++)); + + // partyAInfo [0] OCTET STRING OPTIONAL + ASN1OctetString partyAInfo = null; + if (pos < count) + { + ASN1TaggedObject tag0 = ASN1TaggedObject.getContextOptional(seq.getObjectAt(pos), 0); + if (tag0 != null) { - suppPubInfo = (ASN1OctetString)o.getExplicitBaseObject(); + pos++; + partyAInfo = ASN1OctetString.getTagged(tag0, true); } } + this.partyAInfo = partyAInfo; + + ASN1TaggedObject tag2 = ASN1TaggedObject.getContextInstance(seq.getObjectAt(pos++), 2); + this.suppPubInfo = ASN1OctetString.getTagged(tag2, true); + + if (pos != count) + { + throw new IllegalArgumentException("Unexpected elements in sequence"); + } + } + + public OtherInfo(KeySpecificInfo keyInfo, ASN1OctetString partyAInfo, ASN1OctetString suppPubInfo) + { + if (keyInfo == null) + { + throw new NullPointerException("'keyInfo' cannot be null"); + } + if (suppPubInfo == null) + { + throw new NullPointerException("'suppPubInfo' cannot be null"); + } + + this.keyInfo = keyInfo; + this.partyAInfo = partyAInfo; + this.suppPubInfo = suppPubInfo; } /** diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/ValidationParams.java b/core/src/main/java/org/bouncycastle/asn1/x9/ValidationParams.java index f640cac0f3..cebab707ec 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x9/ValidationParams.java +++ b/core/src/main/java/org/bouncycastle/asn1/x9/ValidationParams.java @@ -53,7 +53,7 @@ public ValidationParams(byte[] seed, int pgenCounter) } this.seed = new DERBitString(seed); - this.pgenCounter = new ASN1Integer(pgenCounter); + this.pgenCounter = ASN1Integer.valueOf(pgenCounter); } public ValidationParams(DERBitString seed, ASN1Integer pgenCounter) diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java b/core/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java index f0c7ffc0f8..567997c699 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java +++ b/core/src/main/java/org/bouncycastle/asn1/x9/X9Curve.java @@ -115,16 +115,21 @@ else if (ECAlgorithms.isF2mCurve(curve)) } } - public ECCurve getCurve() + public ECCurve getCurve() { return curve; } - public byte[] getSeed() + public byte[] getSeed() { return Arrays.clone(seed); } + public boolean hasSeed() + { + return seed != null; + } + /** * Produce an object suitable for an ASN1OutputStream. *

    diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java b/core/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java
    index 31f5d429eb..bb05755265 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x9/X9ECParameters.java
    @@ -12,8 +12,8 @@
     import org.bouncycastle.math.ec.ECAlgorithms;
     import org.bouncycastle.math.ec.ECCurve;
     import org.bouncycastle.math.ec.ECPoint;
    +import org.bouncycastle.math.field.FiniteField;
     import org.bouncycastle.math.field.PolynomialExtensionField;
    -import org.bouncycastle.util.Arrays;
     
     /**
      * ASN.1 def for Elliptic-Curve ECParameters structure. See
    @@ -26,11 +26,10 @@ public class X9ECParameters
         private static final BigInteger   ONE = BigInteger.valueOf(1);
     
         private X9FieldID           fieldID;
    -    private ECCurve             curve;
    +    private X9Curve             curve;
         private X9ECPoint           g;
         private BigInteger          n;
         private BigInteger          h;
    -    private byte[]              seed;
     
         private X9ECParameters(
             ASN1Sequence  seq)
    @@ -48,11 +47,10 @@ private X9ECParameters(
                 this.h = ((ASN1Integer)seq.getObjectAt(5)).getValue();
             }
     
    -        X9Curve x9c = new X9Curve(
    -            X9FieldID.getInstance(seq.getObjectAt(1)), n, h,
    -            ASN1Sequence.getInstance(seq.getObjectAt(2)));
    +        this.fieldID = X9FieldID.getInstance(seq.getObjectAt(1));
    +
    +        this.curve = new X9Curve(fieldID, n, h, ASN1Sequence.getInstance(seq.getObjectAt(2)));
     
    -        this.curve = x9c.getCurve();
             Object p = seq.getObjectAt(3);
     
             if (p instanceof X9ECPoint)
    @@ -61,10 +59,8 @@ private X9ECParameters(
             }
             else
             {
    -            this.g = new X9ECPoint(curve, (ASN1OctetString)p);
    +            this.g = new X9ECPoint(curve.getCurve(), (ASN1OctetString)p);
             }
    -
    -        this.seed = x9c.getSeed();
         }
     
         public static X9ECParameters getInstance(Object obj)
    @@ -106,20 +102,20 @@ public X9ECParameters(
             BigInteger  h,
             byte[]      seed)
         {
    -        this.curve = curve;
    +        this.curve = new X9Curve(curve, seed);
             this.g = g;
             this.n = n;
             this.h = h;
    -        this.seed = Arrays.clone(seed);
     
    -        if (ECAlgorithms.isFpCurve(curve))
    +        FiniteField field = curve.getField();
    +        if (ECAlgorithms.isFpField(field))
             {
    -            this.fieldID = new X9FieldID(curve.getField().getCharacteristic());
    +            this.fieldID = new X9FieldID(field.getCharacteristic());
             }
    -        else if (ECAlgorithms.isF2mCurve(curve))
    +        else if (ECAlgorithms.isF2mField(field))
             {
    -            PolynomialExtensionField field = (PolynomialExtensionField)curve.getField();
    -            int[] exponents = field.getMinimalPolynomial().getExponentsPresent();
    +            PolynomialExtensionField f2mField = (PolynomialExtensionField)field;
    +            int[] exponents = f2mField.getMinimalPolynomial().getExponentsPresent();
                 if (exponents.length == 3)
                 {
                     this.fieldID = new X9FieldID(exponents[2], exponents[1]);
    @@ -141,7 +137,7 @@ else if (exponents.length == 5)
     
         public ECCurve getCurve()
         {
    -        return curve;
    +        return curve.getCurve();
         }
     
         public ECPoint getG()
    @@ -161,12 +157,12 @@ public BigInteger getH()
     
         public byte[] getSeed()
         {
    -        return Arrays.clone(seed);
    +        return curve.getSeed();
         }
     
         public boolean hasSeed()
         {
    -        return null != seed;
    +        return curve.hasSeed();
         }
     
         /**
    @@ -176,7 +172,7 @@ public boolean hasSeed()
          */
         public X9Curve getCurveEntry()
         {
    -        return new X9Curve(curve, seed);
    +        return curve;
         }
     
         /**
    @@ -218,7 +214,7 @@ public ASN1Primitive toASN1Primitive()
     
             v.add(new ASN1Integer(ONE));
             v.add(fieldID);
    -        v.add(new X9Curve(curve, seed));
    +        v.add(curve);
             v.add(g);
             v.add(new ASN1Integer(n));
     
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java b/core/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
    index 194e080e31..68786f81c0 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x9/X9FieldID.java
    @@ -65,7 +65,7 @@ public X9FieldID(int m, int k1, int k2, int k3)
         {
             this.id = characteristic_two_field;
             ASN1EncodableVector fieldIdParams = new ASN1EncodableVector(3);
    -        fieldIdParams.add(new ASN1Integer(m));
    +        fieldIdParams.add(ASN1Integer.valueOf(m));
             
             if (k2 == 0) 
             {
    @@ -75,7 +75,7 @@ public X9FieldID(int m, int k1, int k2, int k3)
                 }
     
                 fieldIdParams.add(tpBasis);
    -            fieldIdParams.add(new ASN1Integer(k1));
    +            fieldIdParams.add(ASN1Integer.valueOf(k1));
             } 
             else 
             {
    @@ -86,9 +86,9 @@ public X9FieldID(int m, int k1, int k2, int k3)
     
                 fieldIdParams.add(ppBasis);
                 ASN1EncodableVector pentanomialParams = new ASN1EncodableVector(3);
    -            pentanomialParams.add(new ASN1Integer(k1));
    -            pentanomialParams.add(new ASN1Integer(k2));
    -            pentanomialParams.add(new ASN1Integer(k3));
    +            pentanomialParams.add(ASN1Integer.valueOf(k1));
    +            pentanomialParams.add(ASN1Integer.valueOf(k2));
    +            pentanomialParams.add(ASN1Integer.valueOf(k3));
                 fieldIdParams.add(new DERSequence(pentanomialParams));
             }
             
    diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
    index ce6f86dff4..b2416efd74 100644
    --- a/core/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
    +++ b/core/src/main/java/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java
    @@ -161,6 +161,7 @@ public interface X9ObjectIdentifiers
          * 

    * Base OID: 1.3.133.16.840.63.0 */ + // TODO Seems this ought to be be 1.3.133.16.840.9.63.0, but may be in common use ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier("1.3.133.16.840.63.0"); /** OID: 1.3.133.16.840.63.0.2 */ ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme = x9_63_scheme.branch("2"); diff --git a/core/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java b/core/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java index ddee701914..b129ed57db 100644 --- a/core/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java +++ b/core/src/main/java/org/bouncycastle/crypto/AsymmetricCipherKeyPair.java @@ -31,6 +31,7 @@ public AsymmetricCipherKeyPair( * @param privateParam the corresponding private key parameters. * @deprecated use AsymmetricKeyParameter */ + @Deprecated public AsymmetricCipherKeyPair( CipherParameters publicParam, CipherParameters privateParam) diff --git a/core/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java index 6a2974147c..c1ba585c98 100644 --- a/core/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/BufferedBlockCipher.java @@ -1,6 +1,5 @@ package org.bouncycastle.crypto; - /** * A wrapper class that allows block ciphers to be used to process data in * a piecemeal fashion. The BufferedBlockCipher outputs a block only when the @@ -11,15 +10,15 @@ */ public class BufferedBlockCipher { - protected byte[] buf; - protected int bufOff; + protected byte[] buf; + protected int bufOff; - protected boolean forEncryption; - protected BlockCipher cipher; + protected boolean forEncryption; + protected BlockCipher cipher; protected MultiBlockCipher mbCipher; - protected boolean partialBlockOkay; - protected boolean pgpCFB; + protected boolean partialBlockOkay; + protected boolean pgpCFB; /** * constructor for subclasses @@ -35,7 +34,7 @@ public class BufferedBlockCipher * @deprecated use the constructor on DefaultBufferedBlockCipher. */ public BufferedBlockCipher( - BlockCipher cipher) + BlockCipher cipher) { this.cipher = cipher; @@ -55,8 +54,8 @@ public BufferedBlockCipher( // // check if we can handle partial blocks on doFinal. // - String name = cipher.getAlgorithmName(); - int idx = name.indexOf('/') + 1; + String name = cipher.getAlgorithmName(); + int idx = name.indexOf('/') + 1; pgpCFB = (idx > 0 && name.startsWith("PGP", idx)); @@ -84,14 +83,14 @@ public BlockCipher getUnderlyingCipher() * initialise the cipher. * * @param forEncryption if true the cipher is initialised for - * encryption, if false for decryption. - * @param params the key and other data required by the cipher. - * @exception IllegalArgumentException if the params argument is - * inappropriate. + * encryption, if false for decryption. + * @param params the key and other data required by the cipher. + * @throws IllegalArgumentException if the params argument is + * inappropriate. */ public void init( - boolean forEncryption, - CipherParameters params) + boolean forEncryption, + CipherParameters params) throws IllegalArgumentException { this.forEncryption = forEncryption; @@ -112,7 +111,7 @@ public int getBlockSize() } /** - * return the size of the output buffer required for an update + * return the size of the output buffer required for an update * an input of len bytes. * * @param len the length of the input. @@ -122,7 +121,7 @@ public int getBlockSize() public int getUpdateOutputSize( int len) { - int total = len + bufOff; + int total = len + bufOff; int leftOver; if (pgpCFB) @@ -138,7 +137,7 @@ public int getUpdateOutputSize( } else { - leftOver = total % buf.length; + leftOver = total % buf.length; } return total - leftOver; @@ -186,8 +185,7 @@ public int processByte( if (bufOff == buf.length) { - resultLen = cipher.processBlock(buf, 0, out, outOff); - bufOff = 0; + resultLen = processBuffer(out, outOff); } return resultLen; @@ -220,7 +218,7 @@ public int processBytes( int blockSize = getBlockSize(); int length = getUpdateOutputSize(len); - + if (length > 0) { if ((outOff + length) > out.length) @@ -234,23 +232,35 @@ public int processBytes( if (len > gapLen) { - System.arraycopy(in, inOff, buf, bufOff, gapLen); + if (bufOff != 0) + { + System.arraycopy(in, inOff, buf, bufOff, gapLen); + inOff += gapLen; + len -= gapLen; + } - resultLen += cipher.processBlock(buf, 0, out, outOff); + if (in == out) + { + in = new byte[len]; + System.arraycopy(out, inOff, in, 0, len); + inOff = 0; + } - bufOff = 0; - len -= gapLen; - inOff += gapLen; + // if bufOff non-zero buffer must now be full + if (bufOff != 0) + { + resultLen += processBuffer(out, outOff); + } if (mbCipher != null) { - int blockCount = len / mbCipher.getMultiBlockSize(); + int blockCount = (len / mbCipher.getMultiBlockSize()) * (mbCipher.getMultiBlockSize() / blockSize); if (blockCount > 0) { resultLen += mbCipher.processBlocks(in, inOff, blockCount, out, outOff + resultLen); - int processed = blockCount * mbCipher.getMultiBlockSize(); + int processed = blockCount * blockSize; len -= processed; inOff += processed; @@ -274,30 +284,42 @@ public int processBytes( if (bufOff == buf.length) { - resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen); - bufOff = 0; + resultLen += processBuffer(out, outOff + resultLen); } return resultLen; } + private int processBuffer(byte[] out, int outOff) + { + bufOff = 0; + if (mbCipher != null) + { + return mbCipher.processBlocks(buf, 0, buf.length / mbCipher.getBlockSize(), out, outOff); + } + else + { + return cipher.processBlock(buf, 0, out, outOff); + } + } + /** * Process the last block in the buffer. * - * @param out the array the block currently being held is copied into. + * @param out the array the block currently being held is copied into. * @param outOff the offset at which the copying starts. * @return the number of output bytes copied to out. - * @exception DataLengthException if there is insufficient space in out for - * the output, or the input is not block size aligned and should be. - * @exception IllegalStateException if the underlying cipher is not - * initialised. - * @exception InvalidCipherTextException if padding is expected and not found. - * @exception DataLengthException if the input is not block size - * aligned. + * @throws DataLengthException if there is insufficient space in out for + * the output, or the input is not block size aligned and should be. + * @throws IllegalStateException if the underlying cipher is not + * initialised. + * @throws InvalidCipherTextException if padding is expected and not found. + * @throws DataLengthException if the input is not block size + * aligned. */ public int doFinal( - byte[] out, - int outOff) + byte[] out, + int outOff) throws DataLengthException, IllegalStateException, InvalidCipherTextException { try @@ -311,15 +333,26 @@ public int doFinal( if (bufOff != 0) { - if (!partialBlockOkay) + int index = 0; + if (mbCipher != null) { - throw new DataLengthException("data not block size aligned"); + int nBlocks = bufOff / mbCipher.getBlockSize(); + resultLen += mbCipher.processBlocks(buf, 0, nBlocks, out, outOff); + index = nBlocks * mbCipher.getBlockSize(); } - cipher.processBlock(buf, 0, buf, 0); - resultLen = bufOff; - bufOff = 0; - System.arraycopy(buf, 0, out, outOff, resultLen); + if (bufOff != index) + { + if (!partialBlockOkay) + { + throw new DataLengthException("data not block size aligned"); + } + + cipher.processBlock(buf, index, buf, index); + System.arraycopy(buf, index, out, outOff + resultLen, bufOff - index); + resultLen += bufOff - index; + bufOff = 0; + } } return resultLen; diff --git a/core/src/main/java/org/bouncycastle/crypto/DefaultBufferedBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/DefaultBufferedBlockCipher.java index 662a23a011..1b0f8267b1 100644 --- a/core/src/main/java/org/bouncycastle/crypto/DefaultBufferedBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/DefaultBufferedBlockCipher.java @@ -1,6 +1,5 @@ package org.bouncycastle.crypto; - /** * A wrapper class that allows block ciphers to be used to process data in * a piecemeal fashion. The BufferedBlockCipher outputs a block only when the @@ -188,8 +187,7 @@ public int processByte( if (bufOff == buf.length) { - resultLen = cipher.processBlock(buf, 0, out, outOff); - bufOff = 0; + resultLen = processBuffer(out, outOff); } return resultLen; @@ -222,7 +220,7 @@ public int processBytes( int blockSize = getBlockSize(); int length = getUpdateOutputSize(len); - + if (length > 0) { if ((outOff + length) > out.length) @@ -236,23 +234,35 @@ public int processBytes( if (len > gapLen) { - System.arraycopy(in, inOff, buf, bufOff, gapLen); + if (bufOff != 0) + { + System.arraycopy(in, inOff, buf, bufOff, gapLen); + inOff += gapLen; + len -= gapLen; + } - resultLen += cipher.processBlock(buf, 0, out, outOff); + if (in == out) + { + in = new byte[len]; + System.arraycopy(out, inOff, in, 0, len); + inOff = 0; + } - bufOff = 0; - len -= gapLen; - inOff += gapLen; + // if bufOff non-zero buffer must now be full + if (bufOff != 0) + { + resultLen += processBuffer(out, outOff); + } if (mbCipher != null) { - int blockCount = len / mbCipher.getMultiBlockSize(); + int blockCount = (len / mbCipher.getMultiBlockSize()) * (mbCipher.getMultiBlockSize() / blockSize); if (blockCount > 0) { resultLen += mbCipher.processBlocks(in, inOff, blockCount, out, outOff + resultLen); - int processed = blockCount * mbCipher.getMultiBlockSize(); + int processed = blockCount * blockSize; len -= processed; inOff += processed; @@ -276,13 +286,25 @@ public int processBytes( if (bufOff == buf.length) { - resultLen += cipher.processBlock(buf, 0, out, outOff + resultLen); - bufOff = 0; + resultLen += processBuffer(out, outOff + resultLen); } return resultLen; } + private int processBuffer(byte[] out, int outOff) + { + bufOff = 0; + if (mbCipher != null) + { + return mbCipher.processBlocks(buf, 0, buf.length / mbCipher.getBlockSize(), out, outOff); + } + else + { + return cipher.processBlock(buf, 0, out, outOff); + } + } + /** * Process the last block in the buffer. * @@ -313,15 +335,26 @@ public int doFinal( if (bufOff != 0) { - if (!partialBlockOkay) + int index = 0; + if (mbCipher != null) { - throw new DataLengthException("data not block size aligned"); + int nBlocks = bufOff / mbCipher.getBlockSize(); + resultLen += mbCipher.processBlocks(buf, 0, nBlocks, out, outOff); + index = nBlocks * mbCipher.getBlockSize(); } - cipher.processBlock(buf, 0, buf, 0); - resultLen = bufOff; - bufOff = 0; - System.arraycopy(buf, 0, out, outOff, resultLen); + if (bufOff != index) + { + if (!partialBlockOkay) + { + throw new DataLengthException("data not block size aligned"); + } + + cipher.processBlock(buf, index, buf, index); + System.arraycopy(buf, index, out, outOff + resultLen, bufOff - index); + resultLen += bufOff - index; + bufOff = 0; + } } return resultLen; diff --git a/core/src/main/java/org/bouncycastle/crypto/DefaultMultiBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/DefaultMultiBlockCipher.java index 3bc565cf0e..5f9019053b 100644 --- a/core/src/main/java/org/bouncycastle/crypto/DefaultMultiBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/DefaultMultiBlockCipher.java @@ -19,8 +19,14 @@ public int processBlocks(byte[] in, int inOff, int blockCount, byte[] out, int o // TODO check if the underlying cipher supports the multiblock interface and call it directly? int resultLen = 0; - int blockSize = this.getMultiBlockSize(); - + int blockSize = this.getBlockSize(); + int len = blockCount * blockSize; + if (in == out) + { + in = new byte[len]; + System.arraycopy(out, inOff, in, 0, len); + inOff = 0; + } for (int i = 0; i != blockCount; i++) { resultLen += this.processBlock(in, inOff, out, outOff + resultLen); diff --git a/core/src/main/java/org/bouncycastle/crypto/EncodableService.java b/core/src/main/java/org/bouncycastle/crypto/EncodableService.java new file mode 100644 index 0000000000..ec13fadf36 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/EncodableService.java @@ -0,0 +1,17 @@ +package org.bouncycastle.crypto; + +/** + * Encodable services allow you to download an encoded copy of their internal state. This is useful for the situation where + * you need to generate a signature on an external device and it allows for "sign with last round", so a copy of the + * internal state of the digest, plus the last few blocks of the message are all that needs to be sent, rather than the + * entire message. + */ +public interface EncodableService +{ + /** + * Return an encoded byte array for the services's internal state + * + * @return an encoding of the services internal state. + */ + byte[] getEncodedState(); +} diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/BasicRawAgreement.java b/core/src/main/java/org/bouncycastle/crypto/agreement/BasicRawAgreement.java new file mode 100644 index 0000000000..1309fbf696 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/agreement/BasicRawAgreement.java @@ -0,0 +1,40 @@ +package org.bouncycastle.crypto.agreement; + +import java.math.BigInteger; + +import org.bouncycastle.crypto.BasicAgreement; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.RawAgreement; +import org.bouncycastle.util.BigIntegers; + +public final class BasicRawAgreement + implements RawAgreement +{ + public final BasicAgreement basicAgreement; + + public BasicRawAgreement(BasicAgreement basicAgreement) + { + if (basicAgreement == null) + { + throw new NullPointerException("'basicAgreement' cannot be null"); + } + + this.basicAgreement = basicAgreement; + } + + public void init(CipherParameters parameters) + { + basicAgreement.init(parameters); + } + + public int getAgreementSize() + { + return basicAgreement.getFieldSize(); + } + + public void calculateAgreement(CipherParameters publicKey, byte[] buf, int off) + { + BigInteger z = basicAgreement.calculateAgreement(publicKey); + BigIntegers.asUnsignedByteArray(z, buf, off, getAgreementSize()); + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/SM2KeyExchange.java b/core/src/main/java/org/bouncycastle/crypto/agreement/SM2KeyExchange.java index 2d1ee6552e..44c845899e 100644 --- a/core/src/main/java/org/bouncycastle/crypto/agreement/SM2KeyExchange.java +++ b/core/src/main/java/org/bouncycastle/crypto/agreement/SM2KeyExchange.java @@ -52,7 +52,7 @@ public void init( if (privParam instanceof ParametersWithID) { baseParam = (SM2KeyExchangePrivateParameters)((ParametersWithID)privParam).getParameters(); - userID = ((ParametersWithID)privParam).getID(); + userID = checkUserID(((ParametersWithID)privParam).getID()); } else { @@ -80,7 +80,7 @@ public byte[] calculateKey(int kLen, CipherParameters pubParam) if (pubParam instanceof ParametersWithID) { otherPub = (SM2KeyExchangePublicParameters)((ParametersWithID)pubParam).getParameters(); - otherUserID = ((ParametersWithID)pubParam).getID(); + otherUserID = checkUserID(((ParametersWithID)pubParam).getID()); } else { @@ -114,7 +114,7 @@ public byte[][] calculateKeyWithConfirmation(int kLen, byte[] confirmationTag, C if (pubParam instanceof ParametersWithID) { otherPub = (SM2KeyExchangePublicParameters)((ParametersWithID)pubParam).getParameters(); - otherUserID = ((ParametersWithID)pubParam).getID(); + otherUserID = checkUserID(((ParametersWithID)pubParam).getID()); } else { @@ -276,6 +276,7 @@ private byte[] getZ(Digest digest, byte[] userID, ECPoint pubPoint) private void addUserID(Digest digest, byte[] userID) { int len = userID.length * 8; +// assert len >>> 16 == 0; digest.update((byte)(len >>> 8)); digest.update((byte)len); @@ -294,4 +295,15 @@ private byte[] digestDoFinal() digest.doFinal(result, 0); return result; } + + private static byte[] checkUserID(byte[] userID) + { + // The length in bits must be expressible in two bytes + if (userID.length >= 8192) + { + throw new IllegalArgumentException("SM2 user ID must be less than 2^16 bits long"); + } + + return userID; + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKECurve.java b/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKECurve.java index 90edecb756..cf1a9d7a5b 100644 --- a/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKECurve.java +++ b/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKECurve.java @@ -18,7 +18,7 @@ */ public class ECJPAKECurve { - private final ECCurve.Fp curve; + private final ECCurve.AbstractFp curve; private final ECPoint g; /** @@ -99,16 +99,8 @@ public ECJPAKECurve(BigInteger q, BigInteger a, BigInteger b, BigInteger n, BigI */ // BigInteger totalPoints = n.multiply(h); - ECCurve.Fp curve = new ECCurve.Fp(q, a, b, n, h); - ECPoint g = curve.createPoint(g_x, g_y); - - if (!g.isValid()) - { - throw new IllegalArgumentException("The base point G does not lie on the curve."); - } - - this.curve = curve; - this.g = g; + this.curve = new ECCurve.Fp(q, a, b, n, h); + this.g = curve.validatePoint(g_x, g_y); } /** @@ -116,7 +108,7 @@ public ECJPAKECurve(BigInteger q, BigInteger a, BigInteger b, BigInteger n, BigI * groups in {@link ECJPAKECurves}. * These pre-approved curves can avoid the expensive checks. */ - ECJPAKECurve(ECCurve.Fp curve, ECPoint g) + ECJPAKECurve(ECCurve.AbstractFp curve, ECPoint g) { ECJPAKEUtil.validateNotNull(curve, "curve"); ECJPAKEUtil.validateNotNull(g, "g"); @@ -127,7 +119,7 @@ public ECJPAKECurve(BigInteger q, BigInteger a, BigInteger b, BigInteger n, BigI this.g = g; } - public ECCurve.Fp getCurve() + public ECCurve.AbstractFp getCurve() { return curve; } diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKECurves.java b/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKECurves.java index 3a4c04b724..ef72b3345f 100644 --- a/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKECurves.java +++ b/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKECurves.java @@ -1,7 +1,7 @@ package org.bouncycastle.crypto.agreement.ecjpake; -import org.bouncycastle.asn1.nist.NISTNamedCurves; import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.ec.CustomNamedCurves; import org.bouncycastle.math.ec.ECCurve; /** @@ -37,13 +37,14 @@ public class ECJPAKECurves static { - NIST_P256 = fromX9ECParameters(NISTNamedCurves.getByName("P-256")); - NIST_P384 = fromX9ECParameters(NISTNamedCurves.getByName("P-384")); - NIST_P521 = fromX9ECParameters(NISTNamedCurves.getByName("P-521")); + NIST_P256 = getCurve("P-256"); + NIST_P384 = getCurve("P-384"); + NIST_P521 = getCurve("P-521"); } - private static ECJPAKECurve fromX9ECParameters(X9ECParameters x9) + private static ECJPAKECurve getCurve(String curveName) { - return new ECJPAKECurve((ECCurve.Fp)x9.getCurve(), x9.getG()); + X9ECParameters x9 = CustomNamedCurves.getByName(curveName); + return new ECJPAKECurve((ECCurve.AbstractFp)x9.getCurve(), x9.getG()); } } diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKEParticipant.java b/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKEParticipant.java index e2b323b9c6..66c5bcb986 100644 --- a/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKEParticipant.java +++ b/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKEParticipant.java @@ -107,9 +107,7 @@ public class ECJPAKEParticipant */ private String partnerParticipantId; - private ECCurve.Fp ecCurve; - private BigInteger ecca; - private BigInteger eccb; + private ECCurve.AbstractFp ecCurve; private BigInteger q; private BigInteger h; private BigInteger n; @@ -255,8 +253,6 @@ public ECJPAKEParticipant( this.password = Arrays.copyOf(password, password.length); this.ecCurve = curve.getCurve(); - this.ecca = curve.getA(); - this.eccb = curve.getB(); this.g = curve.getG(); this.h = curve.getH(); this.n = curve.getN(); diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKEUtil.java b/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKEUtil.java index bc103cf597..02714873d2 100644 --- a/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKEUtil.java +++ b/core/src/main/java/org/bouncycastle/crypto/agreement/ecjpake/ECJPAKEUtil.java @@ -219,10 +219,10 @@ public static void validateZeroKnowledgeProof( ECPoint x_normalized = X.normalize(); // 2. Check x and y coordinates are in Fq, i.e., x, y in [0, q-1] - if (x_normalized.getAffineXCoord().toBigInteger().compareTo(BigInteger.ZERO) == -1 || - x_normalized.getAffineXCoord().toBigInteger().compareTo(q.subtract(BigInteger.ONE)) == 1 || - x_normalized.getAffineYCoord().toBigInteger().compareTo(BigInteger.ZERO) == -1 || - x_normalized.getAffineYCoord().toBigInteger().compareTo(q.subtract(BigInteger.ONE)) == 1) + if (x_normalized.getAffineXCoord().toBigInteger().signum() < 0 || + x_normalized.getAffineXCoord().toBigInteger().compareTo(q) >= 0 || + x_normalized.getAffineYCoord().toBigInteger().signum() < 0 || + x_normalized.getAffineYCoord().toBigInteger().compareTo(q) >= 0) { throw new CryptoException("Zero-knowledge proof validation failed: x and y are not in the field"); } diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/jpake/JPAKEPrimeOrderGroup.java b/core/src/main/java/org/bouncycastle/crypto/agreement/jpake/JPAKEPrimeOrderGroup.java index c3c9561fdf..e39b3fc6bd 100644 --- a/core/src/main/java/org/bouncycastle/crypto/agreement/jpake/JPAKEPrimeOrderGroup.java +++ b/core/src/main/java/org/bouncycastle/crypto/agreement/jpake/JPAKEPrimeOrderGroup.java @@ -70,7 +70,7 @@ public JPAKEPrimeOrderGroup(BigInteger p, BigInteger q, BigInteger g) { throw new IllegalArgumentException("p-1 must be evenly divisible by q"); } - if (g.compareTo(BigInteger.valueOf(2)) == -1 || g.compareTo(p.subtract(JPAKEUtil.ONE)) == 1) + if (g.compareTo(BigInteger.valueOf(2)) < 0 || g.compareTo(p) >= 0) { throw new IllegalArgumentException("g must be in [2, p-1]"); } diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/jpake/JPAKEUtil.java b/core/src/main/java/org/bouncycastle/crypto/agreement/jpake/JPAKEUtil.java index 3639f5c4b6..f2942556a6 100644 --- a/core/src/main/java/org/bouncycastle/crypto/agreement/jpake/JPAKEUtil.java +++ b/core/src/main/java/org/bouncycastle/crypto/agreement/jpake/JPAKEUtil.java @@ -252,15 +252,15 @@ public static void validateZeroKnowledgeProof( BigInteger r = zeroKnowledgeProof[1]; BigInteger h = calculateHashForZeroKnowledgeProof(g, gv, gx, participantId, digest); - if (!(gx.compareTo(ZERO) == 1 && // g^x > 0 - gx.compareTo(p) == -1 && // g^x < p - gx.modPow(q, p).compareTo(ONE) == 0 && // g^x^q mod q = 1 + if (!(gx.signum() > 0 && // g^x > 0 + gx.compareTo(p) < 0 && // g^x < p + gx.modPow(q, p).equals(ONE) && // g^x^q mod q = 1 /* * Below, I took an straightforward way to compute g^r * g^x^h, * which needs 2 exp. Using a simultaneous computation technique * would only need 1 exp. */ - g.modPow(r, p).multiply(gx.modPow(h, p)).mod(p).compareTo(gv) == 0)) // g^v=g^r * g^x^h + g.modPow(r, p).multiply(gx.modPow(h, p)).mod(p).equals(gv))) // g^v=g^r * g^x^h { throw new CryptoException("Zero-knowledge proof validation failed"); } diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java b/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java index 7b7d870285..6fe9bb0e64 100644 --- a/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java +++ b/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java @@ -2,17 +2,18 @@ import java.io.IOException; -import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.x9.KeySpecificInfo; +import org.bouncycastle.asn1.x9.OtherInfo; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.DerivationFunction; import org.bouncycastle.crypto.DerivationParameters; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.OutputLengthException; +import org.bouncycastle.crypto.io.DigestOutputStream; import org.bouncycastle.util.Pack; /** @@ -26,10 +27,9 @@ public class DHKEKGenerator private ASN1ObjectIdentifier algorithm; private int keySize; private byte[] z; - private byte[] partyAInfo; + private byte[] extraInfo; - public DHKEKGenerator( - Digest digest) + public DHKEKGenerator(Digest digest) { this.digest = digest; } @@ -41,7 +41,7 @@ public void init(DerivationParameters param) this.algorithm = params.getAlgorithm(); this.keySize = params.getKeySize(); this.z = params.getZ(); - this.partyAInfo = params.getExtraInfo(); + this.extraInfo = params.getExtraInfo(); } public Digest getDigest() @@ -57,76 +57,56 @@ public int generateBytes(byte[] out, int outOff, int len) throw new OutputLengthException("output buffer too small"); } - long oBytes = len; - int outLen = digest.getDigestSize(); + digest.reset(); + + int outputLength = len; + int digestSize = digest.getDigestSize(); - // - // this is at odds with the standard implementation, the - // maximum value should be hBits * (2^32 - 1) where hBits - // is the digest output size in bits. We can't have an - // array with a long index at the moment... - // - if (oBytes > ((2L << 32) - 1)) + // NOTE: This limit isn't reachable for current array lengths + if (outputLength > ((1L << 32) - 1) * digestSize) { throw new IllegalArgumentException("Output length too large"); } - int cThreshold = (int)((oBytes + outLen - 1) / outLen); + int counter32 = 0; + byte[] counterOctets = new byte[4]; - byte[] dig = new byte[digest.getDigestSize()]; + ASN1OctetString counter = DEROctetString.withContents(counterOctets); + KeySpecificInfo keyInfo = new KeySpecificInfo(algorithm, counter); + ASN1OctetString partyAInfo = DEROctetString.withContentsOptional(extraInfo); + ASN1OctetString suppPubInfo = DEROctetString.withContents(Pack.intToBigEndian(keySize)); + OtherInfo otherInfo = new OtherInfo(keyInfo, partyAInfo, suppPubInfo); - int counter = 1; + DigestOutputStream digestSink = new DigestOutputStream(digest); - for (int i = 0; i < cThreshold; i++) + while (len > 0) { digest.update(z, 0, z.length); - // OtherInfo - ASN1EncodableVector v1 = new ASN1EncodableVector(); - // KeySpecificInfo - ASN1EncodableVector v2 = new ASN1EncodableVector(); - - v2.add(algorithm); - v2.add(new DEROctetString(Pack.intToBigEndian(counter))); - - v1.add(new DERSequence(v2)); - - if (partyAInfo != null) - { - v1.add(new DERTaggedObject(true, 0, new DEROctetString(partyAInfo))); - } - - v1.add(new DERTaggedObject(true, 2, new DEROctetString(Pack.intToBigEndian(keySize)))); - try { - byte[] other = new DERSequence(v1).getEncoded(ASN1Encoding.DER); - - digest.update(other, 0, other.length); + // NOTE: Modify counterOctets in-situ since counter is private to this method + Pack.intToBigEndian(++counter32, counterOctets); + otherInfo.encodeTo(digestSink, ASN1Encoding.DER); } catch (IOException e) { throw new IllegalArgumentException("unable to encode parameter info: " + e.getMessage()); } - digest.doFinal(dig, 0); - - if (len > outLen) + if (len < digestSize) { - System.arraycopy(dig, 0, out, outOff, outLen); - outOff += outLen; - len -= outLen; - } - else - { - System.arraycopy(dig, 0, out, outOff, len); + byte[] tmp = new byte[digestSize]; + digest.doFinal(tmp, 0); + System.arraycopy(tmp, 0, out, outOff, len); + break; } - counter++; + digest.doFinal(out, outOff); + outOff += digestSize; + len -= digestSize; } - digest.reset(); - - return (int)oBytes; + return outputLength; } } diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/ECDHKEKGenerator.java b/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/ECDHKEKGenerator.java index 1e50fc1034..a06d13d9a4 100644 --- a/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/ECDHKEKGenerator.java +++ b/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/ECDHKEKGenerator.java @@ -2,9 +2,10 @@ import java.io.IOException; -import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; @@ -58,16 +59,18 @@ public int generateBytes(byte[] out, int outOff, int len) throw new DataLengthException("output buffer too small"); } - // TODO Create an ASN.1 class for this (RFC3278) - // ECC-CMS-SharedInfo - ASN1EncodableVector v = new ASN1EncodableVector(); + AlgorithmIdentifier keyInfo = new AlgorithmIdentifier(algorithm, DERNull.INSTANCE); + ASN1OctetString suppPubInfo = DEROctetString.withContents(Pack.intToBigEndian(keySize)); - v.add(new AlgorithmIdentifier(algorithm, DERNull.INSTANCE)); - v.add(new DERTaggedObject(true, 2, new DEROctetString(Pack.intToBigEndian(keySize)))); + // TODO org.bouncycastle.asn1.cms.ecc.ECCCMSSharedInfo exists, but is located in the 'util' jar. + // TODO Should the optional DHKDFParameters.getExtraInfo be used for ECCCMSSharedInfo.entityUInfo? + ASN1Sequence eccCMSSharedInfo = new DERSequence(keyInfo, new DERTaggedObject(2, suppPubInfo)); try { - kdf.init(new KDFParameters(z, new DERSequence(v).getEncoded(ASN1Encoding.DER))); + byte[] iv = eccCMSSharedInfo.getEncoded(ASN1Encoding.DER); + + kdf.init(new KDFParameters(z, iv)); } catch (IOException e) { diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java index cfe6f466df..872655f1cd 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconBaseDigest.java @@ -1,60 +1,28 @@ package org.bouncycastle.crypto.digests; -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.ExtendedDigest; import org.bouncycastle.crypto.OutputLengthException; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Longs; +import org.bouncycastle.crypto.engines.AsconPermutationFriend; abstract class AsconBaseDigest - implements ExtendedDigest + extends BufferBaseDigest { - protected long x0; - protected long x1; - protected long x2; - protected long x3; - protected long x4; - protected final int CRYPTO_BYTES = 32; - protected final int ASCON_HASH_RATE = 8; - protected int ASCON_PB_ROUNDS = 12; - protected final byte[] m_buf = new byte[ASCON_HASH_RATE]; - protected int m_bufPos = 0; - - - private void round(long C) + public static class Friend { - long t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C)); - long t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3)); - long t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4); - long t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4)); - long t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1); - x0 = t0 ^ Longs.rotateRight(t0, 19) ^ Longs.rotateRight(t0, 28); - x1 = t1 ^ Longs.rotateRight(t1, 39) ^ Longs.rotateRight(t1, 61); - x2 = ~(t2 ^ Longs.rotateRight(t2, 1) ^ Longs.rotateRight(t2, 6)); - x3 = t3 ^ Longs.rotateRight(t3, 10) ^ Longs.rotateRight(t3, 17); - x4 = t4 ^ Longs.rotateRight(t4, 7) ^ Longs.rotateRight(t4, 41); - } + private static final Friend INSTANCE = new Friend(); - protected void p(int nr) - { - if (nr == 12) + private Friend() { - round(0xf0L); - round(0xe1L); - round(0xd2L); - round(0xc3L); } - if (nr >= 8) - { - round(0xb4L); - round(0xa5L); - } - round(0x96L); - round(0x87L); - round(0x78L); - round(0x69L); - round(0x5aL); - round(0x4bL); + } + + AsconPermutationFriend.AsconPermutation p; + protected int ASCON_PB_ROUNDS = 12; + + protected AsconBaseDigest() + { + super(ProcessingBufferType.Immediate, 8); + p = AsconPermutationFriend.getAsconPermutation(ISAPDigest.Friend.getFriend(Friend.INSTANCE)); + DigestSize = 32; } protected abstract long pad(int i); @@ -67,106 +35,53 @@ protected void p(int nr) protected abstract void setBytes(long w, byte[] bytes, int inOff, int n); - @Override - public int getDigestSize() - { - return CRYPTO_BYTES; - } - - @Override - public int getByteLength() + protected void processBytes(byte[] input, int inOff) { - return ASCON_HASH_RATE; - } - - @Override - public void update(byte in) - { - m_buf[m_bufPos] = in; - if (++m_bufPos == ASCON_HASH_RATE) - { - x0 ^= loadBytes(m_buf, 0); - p(ASCON_PB_ROUNDS); - m_bufPos = 0; - } + p.x0 ^= loadBytes(input, inOff); + p.p(ASCON_PB_ROUNDS); } - @Override - public void update(byte[] input, int inOff, int len) + protected void finish(byte[] output, int outOff) { - if ((inOff + len) > input.length) - { - throw new DataLengthException("input buffer too short"); - } - int available = 8 - m_bufPos; - if (len < available) - { - System.arraycopy(input, inOff, m_buf, m_bufPos, len); - m_bufPos += len; - return; - } - int inPos = 0; - if (m_bufPos > 0) - { - System.arraycopy(input, inOff, m_buf, m_bufPos, available); - inPos += available; - x0 ^= loadBytes(m_buf, 0); - p(ASCON_PB_ROUNDS); - } - int remaining; - while ((remaining = len - inPos) >= 8) - { - x0 ^= loadBytes(input, inOff + inPos); - p(ASCON_PB_ROUNDS); - inPos += 8; - } - System.arraycopy(input, inOff + inPos, m_buf, 0, remaining); - m_bufPos = remaining; - } - - @Override - public int doFinal(byte[] output, int outOff) - { - return hash(output, outOff, CRYPTO_BYTES); + padAndAbsorb(); + /* squeeze full output blocks */ + squeeze(output, outOff, DigestSize); } protected void padAndAbsorb() { - x0 ^= loadBytes(m_buf, 0, m_bufPos); - x0 ^= pad(m_bufPos); - p(12); + p.x0 ^= loadBytes(m_buf, 0, m_bufPos) ^ pad(m_bufPos); + p.p(12); } protected void squeeze(byte[] output, int outOff, int len) { /* squeeze full output blocks */ - while (len > ASCON_HASH_RATE) + while (len > BlockSize) { - setBytes(x0, output, outOff); - p(ASCON_PB_ROUNDS); - outOff += ASCON_HASH_RATE; - len -= ASCON_HASH_RATE; + setBytes(p.x0, output, outOff); + p.p(ASCON_PB_ROUNDS); + outOff += BlockSize; + len -= BlockSize; } /* squeeze final output block */ - setBytes(x0, output, outOff, len); - reset(); + setBytes(p.x0, output, outOff, len); } protected int hash(byte[] output, int outOff, int outLen) { - if (CRYPTO_BYTES + outOff > output.length) - { - throw new OutputLengthException("output buffer is too short"); - } + ensureSufficientOutputBuffer(output, outOff, outLen); padAndAbsorb(); /* squeeze full output blocks */ squeeze(output, outOff, outLen); return outLen; } - public void reset() + protected void ensureSufficientOutputBuffer(byte[] output, int outOff, int len) { - Arrays.clear(m_buf); - m_bufPos = 0; + if (outOff + len > output.length) + { + throw new OutputLengthException("output buffer is too short"); + } } } diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconCXof128.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconCXof128.java index f54c622675..5c860e17bb 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/AsconCXof128.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconCXof128.java @@ -1,26 +1,22 @@ package org.bouncycastle.crypto.digests; import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.OutputLengthException; -import org.bouncycastle.crypto.Xof; import org.bouncycastle.util.Pack; /** * Ascon-CXOF128 was introduced in NIST Special Publication (SP) 800-232 - * (Initial Public Draft). *

    * Additional details and the specification can be found in: - * NIST SP 800-232 (Initial Public Draft). + * NIST SP 800-232 + * Ascon-Based Lightweight Cryptography Standards for Constrained Devices. * For reference source code and implementation details, please see: * Reference, highly optimized, masked C and * ASM implementations of Ascon (NIST SP 800-232). *

    */ public class AsconCXof128 - extends AsconBaseDigest - implements Xof + extends AsconXofBase { - private boolean m_squeezing = false; private final long z0, z1, z2, z3, z4; public AsconCXof128() @@ -35,41 +31,19 @@ public AsconCXof128(byte[] s) public AsconCXof128(byte[] s, int off, int len) { - if ((off + len) > s.length) - { - throw new DataLengthException("input buffer too short"); - } + algorithmName = "Ascon-CXOF128"; + ensureSufficientInputBuffer(s, off, len); if (len > 256) { throw new DataLengthException("customized string is too long"); } initState(s, off, len); // NOTE: Cache the initialized state - z0 = x0; - z1 = x1; - z2 = x2; - z3 = x3; - z4 = x4; - } - - @Override - public void update(byte in) - { - if (m_squeezing) - { - throw new IllegalArgumentException("attempt to absorb while squeezing"); - } - super.update(in); - } - - @Override - public void update(byte[] input, int inOff, int len) - { - if (m_squeezing) - { - throw new IllegalArgumentException("attempt to absorb while squeezing"); - } - super.update(input, inOff, len); + z0 = p.x0; + z1 = p.x1; + z2 = p.x2; + z3 = p.x3; + z4 = p.x4; } protected long pad(int i) @@ -84,7 +58,7 @@ protected long loadBytes(final byte[] bytes, int inOff) protected long loadBytes(final byte[] bytes, int inOff, int n) { - return Pack.littleEndianToLong(bytes, inOff, n); + return n <= 0 ? 0L : Pack.littleEndianToLong_Low(bytes, inOff, n); } protected void setBytes(long w, byte[] bytes, int inOff) @@ -94,69 +68,34 @@ protected void setBytes(long w, byte[] bytes, int inOff) protected void setBytes(long w, byte[] bytes, int inOff, int n) { - Pack.longToLittleEndian(w, bytes, inOff, n); - } - - protected void padAndAbsorb() - { - m_squeezing = true; - super.padAndAbsorb(); - } - - @Override - public String getAlgorithmName() - { - return "Ascon-CXOF128"; - } - - @Override - public int doOutput(byte[] output, int outOff, int outLen) - { - if (CRYPTO_BYTES + outOff > output.length) + if (n > 0) { - throw new OutputLengthException("output buffer is too short"); + Pack.longToLittleEndian_Low(w, bytes, inOff, n); } - padAndAbsorb(); - /* squeeze full output blocks */ - squeeze(output, outOff, outLen); - return outLen; - } - - - @Override - public int doFinal(byte[] output, int outOff, int outLen) - { - int rlt = doOutput(output, outOff, outLen); - reset(); - return rlt; } @Override public void reset() { super.reset(); - m_squeezing = false; /* initialize */ - x0 = z0; - x1 = z1; - x2 = z2; - x3 = z3; - x4 = z4; + p.set(z0, z1, z2, z3, z4); } private void initState(byte[] z, int zOff, int zLen) { - x0 = 7445901275803737603L; - x1 = 4886737088792722364L; - x2 = -1616759365661982283L; - x3 = 3076320316797452470L; - x4 = -8124743304765850554L; - long bitLength = ((long)zLen) << 3; - Pack.longToLittleEndian(bitLength, m_buf, 0); - p(12); - update(z, zOff, zLen); - padAndAbsorb(); - m_squeezing = false; + if (zLen == 0) + { + p.set(0x500cccc894e3c9e8L, 0x5bed06f28f71248dL, 0x3b03a0f930afd512L, 0x112ef093aa5c698bL, 0x00c8356340a347f0L); + } + else + { + p.set(0x675527c2a0e8de03L, 0x43d12d7dc0377bbcL, 0xe9901dec426e81b5L, 0x2ab14907720780b6L, 0x8f3f1d02d432bc46L); + p.x0 ^= ((long)zLen) << 3; + p.p(12); + update(z, zOff, zLen); + padAndAbsorb(); + } + super.reset(); } } - diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconDigest.java index 1063df56c0..77cdb8a797 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/AsconDigest.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconDigest.java @@ -3,11 +3,11 @@ import org.bouncycastle.util.Pack; /** - * ASCON v1.2 Digest, https://ascon.iaik.tugraz.at/ . + * ASCON v1.2 Digest, ... . *

    - * https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/ascon-spec-final.pdf + * ... *

    - * ASCON v1.2 Digest with reference to C Reference Impl from: https://github.com/ascon/ascon-c . + * ASCON v1.2 Digest with reference to C Reference Impl from: ... . * * @deprecated use Ascon Hash 256 Digest */ @@ -41,8 +41,6 @@ public AsconDigest(AsconParameters parameters) reset(); } - private final String algorithmName; - protected long pad(int i) { return 0x80L << (56 - (i << 3)); @@ -55,7 +53,7 @@ protected long loadBytes(final byte[] bytes, int inOff) protected long loadBytes(final byte[] bytes, int inOff, int n) { - return Pack.bigEndianToLong(bytes, inOff, n); + return n <= 0 ? 0L : Pack.bigEndianToLong_High(bytes, inOff, n); } protected void setBytes(long w, byte[] bytes, int inOff) @@ -65,13 +63,10 @@ protected void setBytes(long w, byte[] bytes, int inOff) protected void setBytes(long w, byte[] bytes, int inOff, int n) { - Pack.longToBigEndian(w, bytes, inOff, n); - } - - @Override - public String getAlgorithmName() - { - return algorithmName; + if (n > 0) + { + Pack.longToBigEndian_High(w, bytes, inOff, n); + } } @Override @@ -82,18 +77,10 @@ public void reset() switch (asconParameters) { case AsconHashA: - x0 = 92044056785660070L; - x1 = 8326807761760157607L; - x2 = 3371194088139667532L; - x3 = -2956994353054992515L; - x4 = -6828509670848688761L; + p.set(92044056785660070L, 8326807761760157607L, 3371194088139667532L, -2956994353054992515L, -6828509670848688761L); break; case AsconHash: - x0 = -1255492011513352131L; - x1 = -8380609354527731710L; - x2 = -5437372128236807582L; - x3 = 4834782570098516968L; - x4 = 3787428097924915520L; + p.set(-1255492011513352131L, -8380609354527731710L, -5437372128236807582L, 4834782570098516968L, 3787428097924915520L); break; } } diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconHash256.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconHash256.java index 842346e155..ed080d9ce9 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/AsconHash256.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconHash256.java @@ -4,13 +4,13 @@ /** * Ascon-Hash256 was introduced in NIST Special Publication (SP) 800-232 - * (Initial Public Draft). *

    * Additional details and the specification can be found in: - * NIST SP 800-232 (Initial Public Draft). + * NIST SP 800-232 + * Ascon-Based Lightweight Cryptography Standards for Constrained Devices. * For reference source code and implementation details, please see: * Reference, highly optimized, masked C and - * ASM implementations of Ascon (NIST SP 800-232). + * ASM implementations of Ascon (NIST SP 800-232). *

    */ public class AsconHash256 @@ -18,6 +18,7 @@ public class AsconHash256 { public AsconHash256() { + algorithmName = "Ascon-Hash256"; reset(); } @@ -33,7 +34,7 @@ protected long loadBytes(final byte[] bytes, int inOff) protected long loadBytes(final byte[] bytes, int inOff, int n) { - return Pack.littleEndianToLong(bytes, inOff, n); + return n <= 0 ? 0L : Pack.littleEndianToLong_Low(bytes, inOff, n); } protected void setBytes(long w, byte[] bytes, int inOff) @@ -43,26 +44,17 @@ protected void setBytes(long w, byte[] bytes, int inOff) protected void setBytes(long w, byte[] bytes, int inOff, int n) { - Pack.longToLittleEndian(w, bytes, inOff, n); + if (n > 0) + { + Pack.longToLittleEndian_Low(w, bytes, inOff, n); + } } - @Override - public String getAlgorithmName() - { - return "Ascon-Hash256"; - } - - - @Override public void reset() { super.reset(); /* initialize */ - x0 = -7269279749984954751L; - x1 = 5459383224871899602L; - x2 = -5880230600644446182L; - x3 = 4359436768738168243L; - x4 = 1899470422303676269L; + p.set(-7269279749984954751L, 5459383224871899602L, -5880230600644446182L, 4359436768738168243L, 1899470422303676269L); } } diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof.java index cb9241d6e9..4122cc87b6 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof.java @@ -1,20 +1,18 @@ package org.bouncycastle.crypto.digests; -import org.bouncycastle.crypto.Xof; import org.bouncycastle.util.Pack; /** - * ASCON v1.2 XOF, https://ascon.iaik.tugraz.at/ . + * ASCON v1.2 XOF, ... . *

    - * https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/ascon-spec-final.pdf + * ... *

    - * ASCON v1.2 XOF with reference to C Reference Impl from: https://github.com/ascon/ascon-c . + * ASCON v1.2 XOF with reference to C Reference Impl from: ... . * * @deprecated Now superseded - please use AsconXof128 */ public class AsconXof - extends AsconBaseDigest - implements Xof + extends AsconXofBase { public enum AsconParameters { @@ -26,6 +24,7 @@ public enum AsconParameters public AsconXof(AsconXof.AsconParameters parameters) { + BlockSize = 8; this.asconParameters = parameters; switch (parameters) { @@ -43,35 +42,6 @@ public AsconXof(AsconXof.AsconParameters parameters) reset(); } - private final String algorithmName; - private boolean m_squeezing = false; - - @Override - public void update(byte in) - { - if (m_squeezing) - { - throw new IllegalArgumentException("attempt to absorb while squeezing"); - } - super.update(in); - } - - @Override - public void update(byte[] input, int inOff, int len) - { - if (m_squeezing) - { - throw new IllegalArgumentException("attempt to absorb while squeezing"); - } - super.update(input, inOff, len); - } - - protected void padAndAbsorb() - { - m_squeezing = true; - super.padAndAbsorb(); - } - protected long pad(int i) { return 0x80L << (56 - (i << 3)); @@ -84,7 +54,7 @@ protected long loadBytes(final byte[] bytes, int inOff) protected long loadBytes(final byte[] bytes, int inOff, int n) { - return Pack.bigEndianToLong(bytes, inOff, n); + return n <= 0 ? 0L : Pack.bigEndianToLong_High(bytes, inOff, n); } protected void setBytes(long w, byte[] bytes, int inOff) @@ -94,56 +64,24 @@ protected void setBytes(long w, byte[] bytes, int inOff) protected void setBytes(long w, byte[] bytes, int inOff, int n) { - Pack.longToBigEndian(w, bytes, inOff, n); - } - - @Override - public String getAlgorithmName() - { - return algorithmName; - } - - @Override - public int doOutput(byte[] output, int outOff, int outLen) - { - return hash(output, outOff, outLen); - } - - @Override - public int doFinal(byte[] output, int outOff, int outLen) - { - int rlt = doOutput(output, outOff, outLen); - reset(); - return rlt; - } - - @Override - public int getByteLength() - { - return 8; + if (n > 0) + { + Pack.longToBigEndian_High(w, bytes, inOff, n); + } } @Override public void reset() { super.reset(); - m_squeezing = false; /* initialize */ switch (asconParameters) { case AsconXof: - x0 = -5368810569253202922L; - x1 = 3121280575360345120L; - x2 = 7395939140700676632L; - x3 = 6533890155656471820L; - x4 = 5710016986865767350L; + p.set(-5368810569253202922L, 3121280575360345120L, 7395939140700676632L, 6533890155656471820L, 5710016986865767350L); break; case AsconXofA: - x0 = 4940560291654768690L; - x1 = -3635129828240960206L; - x2 = -597534922722107095L; - x3 = 2623493988082852443L; - x4 = -6283826724160825537L; + p.set(4940560291654768690L, -3635129828240960206L, -597534922722107095L, 2623493988082852443L, -6283826724160825537L); break; } } diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java index 31fe0f64a9..ca523f9616 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconXof128.java @@ -1,27 +1,25 @@ package org.bouncycastle.crypto.digests; -import org.bouncycastle.crypto.Xof; import org.bouncycastle.util.Pack; /** * Ascon-XOF128 was introduced in NIST Special Publication (SP) 800-232 - * (Initial Public Draft). *

    * Additional details and the specification can be found in: - * NIST SP 800-232 (Initial Public Draft). + * NIST SP 800-232 + * Ascon-Based Lightweight Cryptography Standards for Constrained Devices. * For reference source code and implementation details, please see: * Reference, highly optimized, masked C and * ASM implementations of Ascon (NIST SP 800-232). *

    */ public class AsconXof128 - extends AsconBaseDigest - implements Xof + extends AsconXofBase { - private boolean m_squeezing = false; public AsconXof128() { + algorithmName = "Ascon-XOF-128"; reset(); } @@ -37,7 +35,7 @@ protected long loadBytes(final byte[] bytes, int inOff) protected long loadBytes(final byte[] bytes, int inOff, int n) { - return Pack.littleEndianToLong(bytes, inOff, n); + return n <= 0 ? 0L : Pack.littleEndianToLong_Low(bytes, inOff, n); } protected void setBytes(long w, byte[] bytes, int inOff) @@ -47,72 +45,18 @@ protected void setBytes(long w, byte[] bytes, int inOff) protected void setBytes(long w, byte[] bytes, int inOff, int n) { - Pack.longToLittleEndian(w, bytes, inOff, n); - } - - protected void padAndAbsorb() - { - m_squeezing = true; - super.padAndAbsorb(); - } - - @Override - public String getAlgorithmName() - { - return "Ascon-XOF-128"; - } - - @Override - public void update(byte in) - { - if (m_squeezing) - { - throw new IllegalArgumentException("attempt to absorb while squeezing"); - } - super.update(in); - } - - @Override - public void update(byte[] input, int inOff, int len) - { - if (m_squeezing) + if (n > 0) { - throw new IllegalArgumentException("attempt to absorb while squeezing"); + Pack.longToLittleEndian_Low(w, bytes, inOff, n); } - super.update(input, inOff, len); - } - - @Override - public int doOutput(byte[] output, int outOff, int outLen) - { - return hash(output, outOff, outLen); - } - - @Override - public int doFinal(byte[] output, int outOff, int outLen) - { - int rlt = doOutput(output, outOff, outLen); - reset(); - return rlt; - } - - @Override - public int getByteLength() - { - return 8; } @Override public void reset() { - m_squeezing = false; super.reset(); /* initialize */ - x0 = -2701369817892108309L; - x1 = -3711838248891385495L; - x2 = -1778763697082575311L; - x3 = 1072114354614917324L; - x4 = -2282070310009238562L; + p.set(-2701369817892108309L, -3711838248891385495L, -1778763697082575311L, 1072114354614917324L, -2282070310009238562L); } } diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/AsconXofBase.java b/core/src/main/java/org/bouncycastle/crypto/digests/AsconXofBase.java new file mode 100644 index 0000000000..2e28b2b01e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/digests/AsconXofBase.java @@ -0,0 +1,106 @@ +package org.bouncycastle.crypto.digests; + +import org.bouncycastle.crypto.Xof; + +abstract class AsconXofBase + extends AsconBaseDigest + implements Xof +{ + private boolean m_squeezing; + private final byte[] buffer = new byte[BlockSize]; + private int bytesInBuffer; + + @Override + public void update(byte in) + { + ensureNoAbsorbWhileSqueezing(m_squeezing); + super.update(in); + } + + @Override + public void update(byte[] input, int inOff, int len) + { + ensureNoAbsorbWhileSqueezing(m_squeezing); + super.update(input, inOff, len); + } + + @Override + public int doOutput(byte[] output, int outOff, int outLen) + { + ensureSufficientOutputBuffer(output, outOff, outLen); + + /* Use buffered output first */ + int bytesOutput = 0; + if (bytesInBuffer != 0) + { + int startPos = BlockSize - bytesInBuffer; + int bytesToOutput = Math.min(outLen, bytesInBuffer); + System.arraycopy(buffer, startPos, output, outOff, bytesToOutput); + bytesInBuffer -= bytesToOutput; + bytesOutput += bytesToOutput; + } + + int available = outLen - bytesOutput; + /* If we still need to output data */ + if (available >= BlockSize) + { + /* Output full blocks */ + int bytesToOutput = available - available % BlockSize; + bytesOutput += hash(output, outOff + bytesOutput, bytesToOutput); + } + + /* If we need to output a partial buffer */ + if (bytesOutput < outLen) + { + /* Access the next buffer's worth of data */ + hash(buffer, 0, BlockSize); + + /* Copy required length of data */ + int bytesToOutput = outLen - bytesOutput; + System.arraycopy(buffer, 0, output, outOff + bytesOutput, bytesToOutput); + bytesInBuffer = buffer.length - bytesToOutput; + bytesOutput += bytesToOutput; + } + + /* return the length of data output */ + return bytesOutput; + } + + @Override + public int doFinal(byte[] output, int outOff, int outLen) + { + int rlt = doOutput(output, outOff, outLen); + reset(); + return rlt; + } + + @Override + public void reset() + { + m_squeezing = false; + bytesInBuffer = 0; + super.reset(); + } + + @Override + protected void padAndAbsorb() + { + if (!m_squeezing) + { + m_squeezing = true; + super.padAndAbsorb(); + } + else + { + p.p(ASCON_PB_ROUNDS); + } + } + + private void ensureNoAbsorbWhileSqueezing(boolean m_squeezing) + { + if (m_squeezing) + { + throw new IllegalStateException("attempt to absorb while squeezing"); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/Blake2bDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/Blake2bDigest.java index 964c5d5833..3ddec91a35 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/Blake2bDigest.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/Blake2bDigest.java @@ -1,26 +1,26 @@ package org.bouncycastle.crypto.digests; - -/* The BLAKE2 cryptographic hash function was designed by Jean- - Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and Christian - Winnerlein. - - Reference Implementation and Description can be found at: https://blake2.net/ - Internet Draft: https://tools.ietf.org/html/draft-saarinen-blake2-02 - - This implementation does not support the Tree Hashing Mode. - - For unkeyed hashing, developers adapting BLAKE2 to ASN.1 - based - message formats SHOULD use the OID tree at x = 1.3.6.1.4.1.1722.12.2. - - Algorithm | Target | Collision | Hash | Hash ASN.1 | - Identifier | Arch | Security | nn | OID Suffix | - ---------------+--------+-----------+------+------------+ - id-blake2b160 | 64-bit | 2**80 | 20 | x.1.20 | - id-blake2b256 | 64-bit | 2**128 | 32 | x.1.32 | - id-blake2b384 | 64-bit | 2**192 | 48 | x.1.48 | - id-blake2b512 | 64-bit | 2**256 | 64 | x.1.64 | - ---------------+--------+-----------+------+------------+ +/* + * The BLAKE2 cryptographic hash function was designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, + * and Christian Winnerlein. + * + * Reference Implementation and Description can be found at: https://blake2.net/ + * RFC: https://tools.ietf.org/html/rfc7693 + * + * This implementation does not support the Tree Hashing Mode. + * + * For unkeyed hashing, developers adapting BLAKE2 to ASN.1-based message formats SHOULD use the OID tree at: + * x = 1.3.6.1.4.1.1722.12.2. + * + * +---------------+--------+-----------+------+------------+ + * | Algorithm | Target | Collision | Hash | Hash ASN.1 | + * | Identifier | Arch | Security | nn | OID Suffix | + * +---------------+--------+-----------+------+------------+ + * | id-blake2b160 | 64-bit | 2**80 | 20 | x.1.20 | + * | id-blake2b256 | 64-bit | 2**128 | 32 | x.1.32 | + * | id-blake2b384 | 64-bit | 2**192 | 48 | x.1.48 | + * | id-blake2b512 | 64-bit | 2**256 | 64 | x.1.64 | + * +---------------+--------+-----------+------+------------+ */ import org.bouncycastle.crypto.CryptoServicePurpose; @@ -31,57 +31,55 @@ import org.bouncycastle.util.Longs; import org.bouncycastle.util.Pack; - /** - * Implementation of the cryptographic hash function Blakbe2b. - *

    - * Blake2b offers a built-in keying mechanism to be used directly - * for authentication ("Prefix-MAC") rather than a HMAC construction. + * Implementation of the cryptographic hash function BLAKE2b. BLAKE2b is optimized for 64-bit platforms and produces + * digests of any size between 1 and 64 bytes. *

    - * Blake2b offers a built-in support for a salt for randomized hashing - * and a personal string for defining a unique hash function for each application. + * BLAKE2b offers a built-in keying mechanism to be used directly for authentication ("Prefix-MAC") rather than an HMAC + * construction. *

    - * BLAKE2b is optimized for 64-bit platforms and produces digests of any size - * between 1 and 64 bytes. + * BLAKE2b offers built-in support for a salt for randomized hashing and a personal string for defining a unique hash + * function for each application. */ public class Blake2bDigest implements ExtendedDigest { - // Blake2b Initialization Vector: + /* + * BLAKE2b Initialization Vector (the same as SHA-512 IV). + * + * Produced from the square root of primes 2, 3, 5, 7, 11, 13, 17, 19. + */ private final static long[] blake2b_IV = - // Produced from the square root of primes 2, 3, 5, 7, 11, 13, 17, 19. - // The same as SHA-512 IV. - { - 0x6a09e667f3bcc908L, 0xbb67ae8584caa73bL, 0x3c6ef372fe94f82bL, - 0xa54ff53a5f1d36f1L, 0x510e527fade682d1L, 0x9b05688c2b3e6c1fL, - 0x1f83d9abfb41bd6bL, 0x5be0cd19137e2179L - }; + { + 0x6a09e667f3bcc908L, 0xbb67ae8584caa73bL, 0x3c6ef372fe94f82bL, 0xa54ff53a5f1d36f1L, + 0x510e527fade682d1L, 0x9b05688c2b3e6c1fL, 0x1f83d9abfb41bd6bL, 0x5be0cd19137e2179L + }; // Message word permutations: private final static byte[][] blake2b_sigma = - { - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, - {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, - {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, - {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, - {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, - {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, - {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, - {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, - {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, - {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, - {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3} - }; - - private static int ROUNDS = 12; // to use for Catenas H' + { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3} + }; + + private final static int ROUNDS = 12; // to use for Catenas H' private final static int BLOCK_LENGTH_BYTES = 128;// bytes // General parameters: - private int digestLength = 64; // 1- 64 bytes + private int digestLength = 64; // 1 - 64 bytes private int keyLength = 0; // 0 - 64 bytes for keyed hashing for MAC - private byte[] salt = null;// new byte[16]; - private byte[] personalization = null;// new byte[16]; + private byte[] salt = null; + private byte[] personalization = null; // the key private byte[] key = null; @@ -90,33 +88,32 @@ public class Blake2bDigest // Because this class does not implement the Tree Hashing Mode, // these parameters can be treated as constants (see init() function) - private int fanout = 1; // 0-255 - private int depth = 1; // 1 - 255 - private int leafLength= 0; - private long nodeOffset = 0L; - private int nodeDepth = 0; - private int innerHashLength = 0; + private int fanout = 1; // 0 - 255 + private int depth = 1; // 1 - 255 + private int leafLength= 0; + private long nodeOffset = 0L; + private int nodeDepth = 0; + private int innerHashLength = 0; - private boolean isLastNode = false; + private boolean isLastNode = false; // whenever this buffer overflows, it will be processed // in the compress() function. // For performance issues, long messages will not use this buffer. - private byte[] buffer = null;// new byte[BLOCK_LENGTH_BYTES]; + private final byte[] buffer = new byte[BLOCK_LENGTH_BYTES]; + // Position of last inserted byte: - private int bufferPos = 0;// a value from 0 up to 128 + private int bufferPos = 0; // a value from 0 up to BLOCK_LENGTH_BYTES - private long[] internalState = new long[16]; // In the Blake2b paper it is - // called: v - private long[] chainValue = null; // state vector, in the Blake2b paper it - // is called: h + private final long[] internalState = new long[16]; // In the BLAKE2 paper it is called: v + private final long[] chainValue = new long[8]; // state vector, in the BLAKE2 paper it is called: h private long t0 = 0L; // holds last significant bits, counter (counts bytes) private long t1 = 0L; // counter: Length up to 2^128 are supported private long f0 = 0L; // finalization flag, for last block: ~0L // For Tree Hashing Mode, not used here: - private long f1 = 0L; // finalization flag, for last node: ~0L + private long f1 = 0L; // finalization flag, for last node: ~0L // digest purpose private final CryptoServicePurpose purpose; @@ -126,7 +123,6 @@ public Blake2bDigest() this(512, CryptoServicePurpose.ANY); } - /** * Basic sized constructor - size in bits. * @@ -137,22 +133,21 @@ public Blake2bDigest(int digestSize) this(digestSize, CryptoServicePurpose.ANY); } - public Blake2bDigest(Blake2bDigest digest) { + System.arraycopy(digest.chainValue, 0, chainValue, 0, 8); + System.arraycopy(digest.buffer, 0, buffer, 0, BLOCK_LENGTH_BYTES); + this.bufferPos = digest.bufferPos; - this.buffer = Arrays.clone(digest.buffer); this.keyLength = digest.keyLength; this.key = Arrays.clone(digest.key); this.digestLength = digest.digestLength; - this.chainValue = Arrays.clone(digest.chainValue); this.personalization = Arrays.clone(digest.personalization); this.salt = Arrays.clone(digest.salt); this.t0 = digest.t0; this.t1 = digest.t1; this.f0 = digest.f0; this.purpose = digest.purpose; - } /** @@ -169,7 +164,6 @@ public Blake2bDigest(int digestSize, CryptoServicePurpose purpose) "BLAKE2b digest bit length must be a multiple of 8 and not greater than 512"); } - buffer = new byte[BLOCK_LENGTH_BYTES]; keyLength = 0; this.digestLength = digestSize / 8; CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties(this, digestSize, purpose)); @@ -177,7 +171,7 @@ public Blake2bDigest(int digestSize, CryptoServicePurpose purpose) } /** - * Blake2b for authentication ("Prefix-MAC mode"). + * BLAKE2b for authentication ("Prefix-MAC mode"). * After calling the doFinal() method, the key will * remain to be used for further computations of * this instance. @@ -190,19 +184,17 @@ public Blake2bDigest(byte[] key) { this(key, CryptoServicePurpose.ANY); } + public Blake2bDigest(byte[] key, CryptoServicePurpose purpose) { - buffer = new byte[BLOCK_LENGTH_BYTES]; if (key != null) { - this.key = new byte[key.length]; - System.arraycopy(key, 0, this.key, 0, key.length); - if (key.length > 64) { - throw new IllegalArgumentException( - "Keys > 64 are not supported"); + throw new IllegalArgumentException("Keys > 64 bytes are not supported"); } + this.key = new byte[key.length]; + System.arraycopy(key, 0, this.key, 0, key.length); keyLength = key.length; System.arraycopy(key, 0, buffer, 0, key.length); bufferPos = BLOCK_LENGTH_BYTES; // zero padding @@ -215,7 +207,7 @@ public Blake2bDigest(byte[] key, CryptoServicePurpose purpose) } /** - * Blake2b with key, required digest length (in bytes), 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) @@ -234,7 +226,7 @@ public Blake2bDigest(byte[] key, int digestLength, byte[] salt, byte[] personali public Blake2bDigest(byte[] key, int digestLength, byte[] salt, byte[] personalization, CryptoServicePurpose purpose) { this.purpose = purpose; - buffer = new byte[BLOCK_LENGTH_BYTES]; + if (digestLength < 1 || digestLength > 64) { throw new IllegalArgumentException( @@ -264,14 +256,13 @@ public Blake2bDigest(byte[] key, int digestLength, byte[] salt, byte[] personali } if (key != null) { - this.key = new byte[key.length]; - System.arraycopy(key, 0, this.key, 0, key.length); - if (key.length > 64) { throw new IllegalArgumentException( - "Keys > 64 are not supported"); + "Keys > 64 bytes are not supported"); } + this.key = new byte[key.length]; + System.arraycopy(key, 0, this.key, 0, key.length); keyLength = key.length; System.arraycopy(key, 0, buffer, 0, key.length); bufferPos = BLOCK_LENGTH_BYTES; // zero padding @@ -281,9 +272,8 @@ public Blake2bDigest(byte[] key, int digestLength, byte[] salt, byte[] personali init(); } - public Blake2bDigest (byte[] key, byte[] param) + public Blake2bDigest(byte[] key, byte[] param) { - buffer = new byte[BLOCK_LENGTH_BYTES]; // if (key != null) // { // this.key = new byte[key.length]; @@ -292,7 +282,7 @@ public Blake2bDigest (byte[] key, byte[] param) // if (key.length > 64) // { // throw new IllegalArgumentException( -// "Keys > 64 are not supported"); +// "Keys > 64 bytes are not supported"); // } // keyLength = key.length; // System.arraycopy(key, 0, buffer, 0, key.length); @@ -319,32 +309,27 @@ public Blake2bDigest (byte[] key, byte[] param) // initialize chainValue private void init() { - if (chainValue == null) - { - chainValue = new long[8]; + chainValue[0] = blake2b_IV[0] + ^ (digestLength | (keyLength << 8) | ((fanout << 16) | (depth << 24) | (leafLength << 32))); + chainValue[1] = blake2b_IV[1] ^ nodeOffset; + chainValue[2] = blake2b_IV[2] ^ ( nodeDepth | (innerHashLength << 8) ); - chainValue[0] = blake2b_IV[0] - ^ (digestLength | (keyLength << 8) | ((fanout << 16) | (depth << 24) | (leafLength << 32))); - chainValue[1] = blake2b_IV[1] ^ nodeOffset; - chainValue[2] = blake2b_IV[2] ^ ( nodeDepth | (innerHashLength << 8) ); + chainValue[3] = blake2b_IV[3]; - chainValue[3] = blake2b_IV[3]; - - chainValue[4] = blake2b_IV[4]; - chainValue[5] = blake2b_IV[5]; - if (salt != null) - { - chainValue[4] ^= Pack.littleEndianToLong(salt, 0); - chainValue[5] ^= Pack.littleEndianToLong(salt, 8); - } + chainValue[4] = blake2b_IV[4]; + chainValue[5] = blake2b_IV[5]; + if (salt != null) + { + chainValue[4] ^= Pack.littleEndianToLong(salt, 0); + chainValue[5] ^= Pack.littleEndianToLong(salt, 8); + } - chainValue[6] = blake2b_IV[6]; - chainValue[7] = blake2b_IV[7]; - if (personalization != null) - { - chainValue[6] ^= Pack.littleEndianToLong(personalization, 0); - chainValue[7] ^= Pack.littleEndianToLong(personalization, 8); - } + chainValue[6] = blake2b_IV[6]; + chainValue[7] = blake2b_IV[7]; + if (personalization != null) + { + chainValue[6] ^= Pack.littleEndianToLong(personalization, 0); + chainValue[7] ^= Pack.littleEndianToLong(personalization, 8); } } @@ -366,17 +351,12 @@ private void initializeInternalState() */ public void update(byte b) { - int remainingLength = 0; // left bytes of buffer - // process the buffer if full else add to buffer: - remainingLength = BLOCK_LENGTH_BYTES - bufferPos; + int remainingLength = BLOCK_LENGTH_BYTES - bufferPos; if (remainingLength == 0) - { // full buffer - t0 += BLOCK_LENGTH_BYTES; - if (t0 == 0) - { // if message > 2^64 - t1++; - } + { + // full buffer + incrementCounter(BLOCK_LENGTH_BYTES); compress(buffer, 0); Arrays.fill(buffer, (byte)0);// clear buffer buffer[0] = b; @@ -384,9 +364,7 @@ public void update(byte b) } else { - buffer[bufferPos] = b; - bufferPos++; - return; + buffer[bufferPos++] = b; } } @@ -399,7 +377,6 @@ public void update(byte b) */ public void update(byte[] message, int offset, int len) { - if (message == null || len == 0) { return; @@ -408,54 +385,44 @@ public void update(byte[] message, int offset, int len) int remainingLength = 0; // left bytes of buffer if (bufferPos != 0) - { // commenced, incomplete buffer + { + // commenced, incomplete buffer // complete the buffer: remainingLength = BLOCK_LENGTH_BYTES - bufferPos; - if (remainingLength < len) - { // full buffer + at least 1 byte - System.arraycopy(message, offset, buffer, bufferPos, - remainingLength); - t0 += BLOCK_LENGTH_BYTES; - if (t0 == 0) - { // if message > 2^64 - t1++; - } - compress(buffer, 0); - bufferPos = 0; - Arrays.fill(buffer, (byte)0);// clear buffer - } - else + if (remainingLength >= len) { System.arraycopy(message, offset, buffer, bufferPos, len); bufferPos += len; return; } + + // full buffer + at least 1 byte + System.arraycopy(message, offset, buffer, bufferPos, remainingLength); + incrementCounter(BLOCK_LENGTH_BYTES); + compress(buffer, 0); + bufferPos = 0; + Arrays.fill(buffer, (byte)0);// clear buffer } // process blocks except last block (also if last block is full) - int messagePos; int blockWiseLastPos = offset + len - BLOCK_LENGTH_BYTES; - for (messagePos = offset + remainingLength; messagePos < blockWiseLastPos; messagePos += BLOCK_LENGTH_BYTES) - { // block wise 128 bytes - // without buffer: - t0 += BLOCK_LENGTH_BYTES; - if (t0 == 0) - { - t1++; - } + int messagePos = offset + remainingLength; + while (messagePos < blockWiseLastPos) + { + // block wise 128 bytes without buffer: + incrementCounter(BLOCK_LENGTH_BYTES); compress(message, messagePos); + messagePos += BLOCK_LENGTH_BYTES; } // fill the buffer with left bytes, this might be a full block - System.arraycopy(message, messagePos, buffer, 0, offset + len - - messagePos); + System.arraycopy(message, messagePos, buffer, 0, offset + len - messagePos); bufferPos += offset + len - messagePos; } /** - * close the digest, producing the final digest value. The doFinal - * call leaves the digest reset. + * Close the digest, producing the final digest value. The doFinal() call leaves the digest reset. * Key, salt and personal string remain. * * @param out the array the digest is to be copied into. @@ -471,53 +438,50 @@ public int doFinal(byte[] out, int outOffset) f0 = 0xFFFFFFFFFFFFFFFFL; if(isLastNode) { - f1 = 0xFFFFFFFF; + f1 = 0xFFFFFFFFFFFFFFFFL; } - t0 += bufferPos; - if (bufferPos > 0 && t0 == 0) + + if (bufferPos > 0) { - t1++; + incrementCounter(bufferPos); } + compress(buffer, 0); - Arrays.fill(buffer, (byte)0);// Holds eventually the key if input is null - Arrays.fill(internalState, 0L); int full = digestLength >>> 3, partial = digestLength & 7; Pack.longToLittleEndian(chainValue, 0, full, out, outOffset); if (partial > 0) { - byte[] bytes = new byte[8]; - Pack.longToLittleEndian(chainValue[full], bytes, 0); - System.arraycopy(bytes, 0, out, outOffset + digestLength - partial, partial); + Pack.longToLittleEndian_Low(chainValue[full], out, outOffset + digestLength - partial, partial); } - Arrays.fill(chainValue, 0L); - reset(); return digestLength; } /** - * Reset the digest back to it's initial state. - * The key, the salt and the personal string will - * remain for further computations. + * Reset the digest back to it's initial state. The key, the salt and the personal string will remain for further + * computations. */ public void reset() { bufferPos = 0; f0 = 0L; - f1 = 0; + f1 = 0L; t0 = 0L; t1 = 0L; isLastNode = false; - chainValue = null; + + Arrays.fill(internalState, 0L); + Arrays.fill(buffer, (byte)0); if (key != null) { System.arraycopy(key, 0, buffer, 0, key.length); bufferPos = BLOCK_LENGTH_BYTES; // zero padding } + init(); } @@ -530,9 +494,7 @@ private void compress(byte[] message, int messagePos) for (int round = 0; round < ROUNDS; round++) { - - // G apply to columns of internalState:m[blake2b_sigma[round][2 * - // blockPos]] /+1 + // G apply to columns of internalState:m[blake2b_sigma[round][2 * blockPos]] /+1 G(m[blake2b_sigma[round][0]], m[blake2b_sigma[round][1]], 0, 4, 8, 12); G(m[blake2b_sigma[round][2]], m[blake2b_sigma[round][3]], 1, 5, 9, 13); G(m[blake2b_sigma[round][4]], m[blake2b_sigma[round][5]], 2, 6, 10, 14); @@ -553,7 +515,6 @@ private void compress(byte[] message, int messagePos) private void G(long m1, long m2, int posA, int posB, int posC, int posD) { - internalState[posA] = internalState[posA] + internalState[posB] + m1; internalState[posD] = Longs.rotateRight(internalState[posD] ^ internalState[posA], 32); internalState[posC] = internalState[posC] + internalState[posD]; @@ -590,8 +551,7 @@ public int getDigestSize() } /** - * Return the size in bytes of the internal buffer the digest applies it's compression - * function to. + * Return the size in bytes of the internal buffer the digest applies it's compression function to. * * @return byte length of the digests internal buffer. */ @@ -601,8 +561,7 @@ public int getByteLength() } /** - * Overwrite the key - * if it is no longer used (zeroization) + * Overwrite the key if it is no longer used (zeroization) */ public void clearKey() { @@ -614,8 +573,7 @@ public void clearKey() } /** - * Overwrite the salt (pepper) if it - * is secret and no longer used (zeroization) + * Overwrite the salt (pepper) if it is secret and no longer used (zeroization) */ public void clearSalt() { @@ -624,4 +582,16 @@ public void clearSalt() Arrays.fill(salt, (byte)0); } } + + private void incrementCounter(int count) + { +// assert count > 0; + + long count64 = (long)count; + t0 += count64; + if (Longs.compareUnsigned(t0, count64) < 0) + { + ++t1; + } + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/Blake2sDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/Blake2sDigest.java index 09140d9b97..36879e4dfa 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/Blake2sDigest.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/Blake2sDigest.java @@ -1,26 +1,26 @@ package org.bouncycastle.crypto.digests; /* - The BLAKE2 cryptographic hash function was designed by Jean- - Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and Christian - Winnerlein. - - Reference Implementation and Description can be found at: https://blake2.net/ - RFC: https://tools.ietf.org/html/rfc7693 - - This implementation does not support the Tree Hashing Mode. - - For unkeyed hashing, developers adapting BLAKE2 to ASN.1 - based - message formats SHOULD use the OID tree at x = 1.3.6.1.4.1.1722.12.2. - - Algorithm | Target | Collision | Hash | Hash ASN.1 | - Identifier | Arch | Security | nn | OID Suffix | - ---------------+--------+-----------+------+------------+ - id-blake2s128 | 32-bit | 2**64 | 16 | x.2.4 | - id-blake2s160 | 32-bit | 2**80 | 20 | x.2.5 | - id-blake2s224 | 32-bit | 2**112 | 28 | x.2.7 | - id-blake2s256 | 32-bit | 2**128 | 32 | x.2.8 | - ---------------+--------+-----------+------+------------+ + * The BLAKE2 cryptographic hash function was designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, + * and Christian Winnerlein. + * + * Reference Implementation and Description can be found at: https://blake2.net/ + * RFC: https://tools.ietf.org/html/rfc7693 + * + * This implementation does not support the Tree Hashing Mode. + * + * For unkeyed hashing, developers adapting BLAKE2 to ASN.1-based message formats SHOULD use the OID tree at: + * x = 1.3.6.1.4.1.1722.12.2. + * + * +---------------+--------+-----------+------+------------+ + * | Algorithm | Target | Collision | Hash | Hash ASN.1 | + * | Identifier | Arch | Security | nn | OID Suffix | + * +---------------+--------+-----------+------+------------+ + * | id-blake2s128 | 32-bit | 2**64 | 16 | x.2.4 | + * | id-blake2s160 | 32-bit | 2**80 | 20 | x.2.5 | + * | id-blake2s224 | 32-bit | 2**112 | 28 | x.2.7 | + * | id-blake2s256 | 32-bit | 2**128 | 32 | x.2.8 | + * +---------------+--------+-----------+------+------------+ */ import org.bouncycastle.crypto.CryptoServicePurpose; @@ -32,54 +32,50 @@ import org.bouncycastle.util.Pack; /** - * Implementation of the cryptographic hash function BLAKE2s. - *

    - * BLAKE2s offers a built-in keying mechanism to be used directly - * for authentication ("Prefix-MAC") rather than a HMAC construction. - *

    - * BLAKE2s offers a built-in support for a salt for randomized hashing - * and a personal string for defining a unique hash function for each application. - *

    - * BLAKE2s is optimized for 32-bit platforms and produces digests of any size - * between 1 and 32 bytes. + * Implementation of the cryptographic hash function BLAKE2s. BLAKE2s is optimized for 32-bit platforms and produces + * digests of any size between 1 and 32 bytes. + *

    + * BLAKE2s offers a built-in keying mechanism to be used directly for authentication ("Prefix-MAC") rather than an HMAC + * construction. + *

    + * BLAKE2s offers built-in support for a salt for randomized hashing and a personal string for defining a unique hash + * function for each application. */ public class Blake2sDigest implements ExtendedDigest { - /** - * BLAKE2s Initialization Vector - **/ + /* + * BLAKE2s Initialization Vector (the same as SHA-256 IV). + * + * Produced from the square root of primes 2, 3, 5, 7, 11, 13, 17, 19. + */ private static final int[] blake2s_IV = - // Produced from the square root of primes 2, 3, 5, 7, 11, 13, 17, 19. - // The same as SHA-256 IV. - { - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, - 0xa54ff53a, 0x510e527f, 0x9b05688c, - 0x1f83d9ab, 0x5be0cd19 - }; + { + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 + }; /** * Message word permutations **/ private static final byte[][] blake2s_sigma = - { - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, - {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, - {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, - {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, - {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, - {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, - {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, - {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, - {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, - {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0} - }; + { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0} + }; private static final int ROUNDS = 10; // to use for Catenas H' private static final int BLOCK_LENGTH_BYTES = 64;// bytes // General parameters: - private int digestLength = 32; // 1- 32 bytes + private int digestLength = 32; // 1 - 32 bytes private int keyLength = 0; // 0 - 32 bytes for keyed hashing for MAC private byte[] salt = null; private byte[] personalization = null; @@ -88,34 +84,34 @@ public class Blake2sDigest // Tree hashing parameters: // The Tree Hashing Mode is not supported but these are used for // the XOF implementation - private int fanout = 1; // 0-255 - private int depth = 1; // 0-255 + private int fanout = 1; // 0 - 255 + private int depth = 1; // 1 - 255 private int leafLength = 0; private long nodeOffset = 0L; private int nodeDepth = 0; private int innerHashLength = 0; - private boolean isLastNode = false; - /** * Whenever this buffer overflows, it will be processed in the compress() * function. For performance issues, long messages will not use this buffer. */ - private byte[] buffer = null; + private final byte[] buffer = new byte[BLOCK_LENGTH_BYTES]; + /** * Position of last inserted byte **/ - private int bufferPos = 0;// a value from 0 up to BLOCK_LENGTH_BYTES + private int bufferPos = 0; // a value from 0 up to BLOCK_LENGTH_BYTES /** * Internal state, in the BLAKE2 paper it is called v **/ - private int[] internalState = new int[16]; + private final int[] internalState = new int[16]; + /** * State vector, in the BLAKE2 paper it is called h **/ - private int[] chainValue = null; + private final int[] chainValue = new int[8]; // counter (counts bytes): Length up to 2^64 are supported /** @@ -158,13 +154,13 @@ public Blake2sDigest(int digestSize) public Blake2sDigest(Blake2sDigest digest) { + System.arraycopy(digest.chainValue, 0, chainValue, 0, 8); + System.arraycopy(digest.buffer, 0, buffer, 0, BLOCK_LENGTH_BYTES); + this.bufferPos = digest.bufferPos; - this.buffer = Arrays.clone(digest.buffer); this.keyLength = digest.keyLength; this.key = Arrays.clone(digest.key); this.digestLength = digest.digestLength; - this.internalState = Arrays.clone(digest.internalState); - this.chainValue = Arrays.clone(digest.chainValue); this.t0 = digest.t0; this.t1 = digest.t1; this.f0 = digest.f0; @@ -238,6 +234,7 @@ public Blake2sDigest(byte[] key, int digestBytes, byte[] salt, { this(key, digestBytes, salt, personalization, CryptoServicePurpose.ANY); } + public Blake2sDigest(byte[] key, int digestBytes, byte[] salt, byte[] personalization, CryptoServicePurpose purpose) { @@ -268,6 +265,7 @@ public Blake2sDigest(byte[] key, int digestBytes, byte[] salt, { this(digestBytes, hashLength, offset, CryptoServicePurpose.ANY); } + Blake2sDigest(int digestBytes, int hashLength, long offset, CryptoServicePurpose purpose) { digestLength = digestBytes; @@ -282,7 +280,8 @@ public Blake2sDigest(byte[] key, int digestBytes, byte[] salt, CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties(this, digestBytes*8, purpose)); init(null, null, null); } - Blake2sDigest (byte[] key, byte[] param) + + Blake2sDigest(byte[] key, byte[] param) { this.purpose = CryptoServicePurpose.ANY; digestLength = param[0]; @@ -304,8 +303,6 @@ public Blake2sDigest(byte[] key, int digestBytes, byte[] salt, // initialize the digest's parameters private void init(byte[] salt, byte[] personalization, byte[] key) { - buffer = new byte[BLOCK_LENGTH_BYTES]; - if (key != null && key.length > 0) { keyLength = key.length; @@ -319,47 +316,42 @@ private void init(byte[] salt, byte[] personalization, byte[] key) bufferPos = BLOCK_LENGTH_BYTES; // zero padding } - if (chainValue == null) - { - chainValue = new int[8]; - - chainValue[0] = blake2s_IV[0] ^ (digestLength | (keyLength << 8) | ((fanout << 16) | (depth << 24))); - chainValue[1] = blake2s_IV[1] ^ leafLength; + chainValue[0] = blake2s_IV[0] ^ (digestLength | (keyLength << 8) | ((fanout << 16) | (depth << 24))); + chainValue[1] = blake2s_IV[1] ^ leafLength; - int nofHi = (int)(nodeOffset >> 32); - int nofLo = (int)nodeOffset; - chainValue[2] = blake2s_IV[2] ^ nofLo; - chainValue[3] = blake2s_IV[3] ^ (nofHi | (nodeDepth << 16) | (innerHashLength << 24)); + int nofHi = (int)(nodeOffset >> 32); + int nofLo = (int)nodeOffset; + chainValue[2] = blake2s_IV[2] ^ nofLo; + chainValue[3] = blake2s_IV[3] ^ (nofHi | (nodeDepth << 16) | (innerHashLength << 24)); - chainValue[4] = blake2s_IV[4]; - chainValue[5] = blake2s_IV[5]; - if (salt != null) + chainValue[4] = blake2s_IV[4]; + chainValue[5] = blake2s_IV[5]; + if (salt != null) + { + if (salt.length != 8) { - if (salt.length != 8) - { - throw new IllegalArgumentException("Salt length must be exactly 8 bytes"); - } - this.salt = new byte[8]; - System.arraycopy(salt, 0, this.salt, 0, salt.length); - - chainValue[4] ^= Pack.littleEndianToInt(salt, 0); - chainValue[5] ^= Pack.littleEndianToInt(salt, 4); + throw new IllegalArgumentException("Salt length must be exactly 8 bytes"); } + this.salt = new byte[8]; + System.arraycopy(salt, 0, this.salt, 0, salt.length); + + chainValue[4] ^= Pack.littleEndianToInt(salt, 0); + chainValue[5] ^= Pack.littleEndianToInt(salt, 4); + } - chainValue[6] = blake2s_IV[6]; - chainValue[7] = blake2s_IV[7]; - if (personalization != null) + chainValue[6] = blake2s_IV[6]; + chainValue[7] = blake2s_IV[7]; + if (personalization != null) + { + if (personalization.length != 8) { - if (personalization.length != 8) - { - throw new IllegalArgumentException("Personalization length must be exactly 8 bytes"); - } - this.personalization = new byte[8]; - System.arraycopy(personalization, 0, this.personalization, 0, personalization.length); - - chainValue[6] ^= Pack.littleEndianToInt(personalization, 0); - chainValue[7] ^= Pack.littleEndianToInt(personalization, 4); + throw new IllegalArgumentException("Personalization length must be exactly 8 bytes"); } + this.personalization = new byte[8]; + System.arraycopy(personalization, 0, this.personalization, 0, personalization.length); + + chainValue[6] ^= Pack.littleEndianToInt(personalization, 0); + chainValue[7] ^= Pack.littleEndianToInt(personalization, 4); } } @@ -381,17 +373,12 @@ private void initializeInternalState() */ public void update(byte b) { - int remainingLength; // left bytes of buffer - // process the buffer if full else add to buffer: - remainingLength = BLOCK_LENGTH_BYTES - bufferPos; + int remainingLength = BLOCK_LENGTH_BYTES - bufferPos; if (remainingLength == 0) - { // full buffer - t0 += BLOCK_LENGTH_BYTES; - if (t0 == 0) - { // if message > 2^32 - t1++; - } + { + // full buffer + incrementCounter(BLOCK_LENGTH_BYTES); compress(buffer, 0); Arrays.fill(buffer, (byte)0);// clear buffer buffer[0] = b; @@ -399,8 +386,7 @@ public void update(byte b) } else { - buffer[bufferPos] = b; - bufferPos++; + buffer[bufferPos++] = b; } } @@ -421,56 +407,45 @@ public void update(byte[] message, int offset, int len) int remainingLength = 0; // left bytes of buffer if (bufferPos != 0) - { // commenced, incomplete buffer + { + // commenced, incomplete buffer // complete the buffer: remainingLength = BLOCK_LENGTH_BYTES - bufferPos; - if (remainingLength < len) - { // full buffer + at least 1 byte - System.arraycopy(message, offset, buffer, bufferPos, - remainingLength); - t0 += BLOCK_LENGTH_BYTES; - if (t0 == 0) - { // if message > 2^32 - t1++; - } - compress(buffer, 0); - bufferPos = 0; - Arrays.fill(buffer, (byte)0);// clear buffer - } - else + if (remainingLength >= len) { System.arraycopy(message, offset, buffer, bufferPos, len); bufferPos += len; return; } + + // full buffer + at least 1 byte + System.arraycopy(message, offset, buffer, bufferPos, remainingLength); + incrementCounter(BLOCK_LENGTH_BYTES); + compress(buffer, 0); + bufferPos = 0; + Arrays.fill(buffer, (byte)0);// clear buffer } // process blocks except last block (also if last block is full) - int messagePos; int blockWiseLastPos = offset + len - BLOCK_LENGTH_BYTES; - for (messagePos = offset + remainingLength; - messagePos < blockWiseLastPos; - messagePos += BLOCK_LENGTH_BYTES) - { // block wise 64 bytes - // without buffer: - t0 += BLOCK_LENGTH_BYTES; - if (t0 == 0) - { - t1++; - } + int messagePos = offset + remainingLength; + while (messagePos < blockWiseLastPos) + { + // block wise 64 bytes without buffer: + incrementCounter(BLOCK_LENGTH_BYTES); compress(message, messagePos); + messagePos += BLOCK_LENGTH_BYTES; } // fill the buffer with left bytes, this might be a full block - System.arraycopy(message, messagePos, buffer, 0, offset + len - - messagePos); + System.arraycopy(message, messagePos, buffer, 0, offset + len - messagePos); bufferPos += offset + len - messagePos; } /** - * Close the digest, producing the final digest value. The doFinal() call - * leaves the digest reset. Key, salt and personal string remain. + * Close the digest, producing the final digest value. The doFinal() call leaves the digest reset. + * Key, salt and personal string remain. * * @param out the array the digest is to be copied into. * @param outOffset the offset into the out array the digest is to start at. @@ -487,36 +462,29 @@ public int doFinal(byte[] out, int outOffset) { f1 = 0xFFFFFFFF; } - t0 += bufferPos; - // bufferPos may be < 64, so (t0 == 0) does not work - // for 2^32 < message length > 2^32 - 63 - if ((t0 < 0) && (bufferPos > -t0)) + + if (bufferPos > 0) { - t1++; + incrementCounter(bufferPos); } + compress(buffer, 0); - Arrays.fill(buffer, (byte)0);// Holds eventually the key if input is null - Arrays.fill(internalState, 0); int full = digestLength >>> 2, partial = digestLength & 3; Pack.intToLittleEndian(chainValue, 0, full, out, outOffset); if (partial > 0) { - byte[] bytes = new byte[4]; - Pack.intToLittleEndian(chainValue[full], bytes, 0); - System.arraycopy(bytes, 0, out, outOffset + digestLength - partial, partial); + Pack.intToLittleEndian_Low(chainValue[full], out, outOffset + digestLength - partial, partial); } - Arrays.fill(chainValue, 0); - reset(); return digestLength; } /** - * Reset the digest back to its initial state. The key, the salt and the - * personal string will remain for further computations. + * Reset the digest back to its initial state. The key, the salt and the personal string will remain for further + * computations. */ public void reset() { @@ -526,7 +494,9 @@ public void reset() t0 = 0; t1 = 0; isLastNode = false; - chainValue = null; + + Arrays.fill(internalState, 0); + Arrays.fill(buffer, (byte)0); if (key != null) { @@ -546,8 +516,7 @@ private void compress(byte[] message, int messagePos) for (int round = 0; round < ROUNDS; round++) { - // G apply to columns of internalState:m[blake2s_sigma[round][2 * - // blockPos]] /+1 + // G apply to columns of internalState:m[blake2s_sigma[round][2 * blockPos]] /+1 G(m[blake2s_sigma[round][0]], m[blake2s_sigma[round][1]], 0, 4, 8, 12); G(m[blake2s_sigma[round][2]], m[blake2s_sigma[round][3]], 1, 5, 9, 13); G(m[blake2s_sigma[round][4]], m[blake2s_sigma[round][5]], 2, 6, 10, 14); @@ -604,8 +573,7 @@ public int getDigestSize() } /** - * Return the size in bytes of the internal buffer the digest applies its - * compression function to. + * Return the size in bytes of the internal buffer the digest applies its compression function to. * * @return byte length of the digest's internal buffer. */ @@ -627,8 +595,7 @@ public void clearKey() } /** - * Overwrite the salt (pepper) if it is secret and no longer used - * (zeroization). + * Overwrite the salt (pepper) if it is secret and no longer used (zeroization). */ public void clearSalt() { @@ -637,4 +604,15 @@ public void clearSalt() Arrays.fill(salt, (byte)0); } } + + private void incrementCounter(int count) + { +// assert count > 0; + + t0 += count; + if (Integers.compareUnsigned(t0, count) < 0) + { + ++t1; + } + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/BufferBaseDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/BufferBaseDigest.java new file mode 100644 index 0000000000..c6cdaed6f2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/digests/BufferBaseDigest.java @@ -0,0 +1,196 @@ +package org.bouncycastle.crypto.digests; + +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.ExtendedDigest; +import org.bouncycastle.crypto.OutputLengthException; +import org.bouncycastle.util.Arrays; + +abstract class BufferBaseDigest + implements ExtendedDigest +{ + protected static class ProcessingBufferType + { + public static final int BUFFERED = 0; + public static final int IMMEDIATE = 1; + + public static final ProcessingBufferType Buffered = new ProcessingBufferType(BUFFERED); + public static final ProcessingBufferType Immediate = new ProcessingBufferType(IMMEDIATE); + + private final int ord; + + ProcessingBufferType(int ord) + { + this.ord = ord; + } + } + + protected int DigestSize; + protected int BlockSize; + protected byte[] m_buf; + protected int m_bufPos; + protected String algorithmName; + protected ProcessingBuffer processor; + + protected BufferBaseDigest(ProcessingBufferType type, int BlockSize) + { + this.BlockSize = BlockSize; + m_buf = new byte[BlockSize]; + switch (type.ord) + { + case ProcessingBufferType.BUFFERED: + processor = new BufferedProcessor(); + break; + case ProcessingBufferType.IMMEDIATE: + processor = new ImmediateProcessor(); + break; + } + } + + protected interface ProcessingBuffer + { + void update(byte input); + + boolean isLengthWithinAvailableSpace(int len, int available); + + boolean isLengthExceedingBlockSize(int len, int size); + } + + private class BufferedProcessor + implements ProcessingBuffer + { + public void update(byte input) + { + if (m_bufPos == BlockSize) + { + processBytes(m_buf, 0); + m_bufPos = 0; + } + m_buf[m_bufPos++] = input; + } + + @Override + public boolean isLengthWithinAvailableSpace(int len, int available) + { + return len <= available; + } + + @Override + public boolean isLengthExceedingBlockSize(int len, int size) + { + return len > size; + } + } + + private class ImmediateProcessor + implements ProcessingBuffer + { + public void update(byte input) + { + m_buf[m_bufPos] = input; + if (++m_bufPos == BlockSize) + { + processBytes(m_buf, 0); + m_bufPos = 0; + } + } + + @Override + public boolean isLengthWithinAvailableSpace(int len, int available) + { + return len < available; + } + + @Override + public boolean isLengthExceedingBlockSize(int len, int size) + { + return len >= size; + } + } + + @Override + public String getAlgorithmName() + { + return algorithmName; + } + + @Override + public int getDigestSize() + { + return DigestSize; + } + + @Override + public int getByteLength() + { + return BlockSize; + } + + @Override + public void update(byte in) + { + processor.update(in); + } + + @Override + public void update(byte[] input, int inOff, int len) + { + ensureSufficientInputBuffer(input, inOff, len); + int available = BlockSize - m_bufPos; + if (processor.isLengthWithinAvailableSpace(len, available)) + { + System.arraycopy(input, inOff, m_buf, m_bufPos, len); + m_bufPos += len; + return; + } + if (m_bufPos > 0) + { + System.arraycopy(input, inOff, m_buf, m_bufPos, available); + inOff += available; + len -= available; + processBytes(m_buf, 0); + } + while (processor.isLengthExceedingBlockSize(len, BlockSize)) + { + processBytes(input, inOff); + inOff += BlockSize; + len -= BlockSize; + } + System.arraycopy(input, inOff, m_buf, 0, len); + m_bufPos = len; + } + + @Override + public int doFinal(byte[] output, int outOff) + { + ensureSufficientOutputBuffer(output, outOff); + finish(output, outOff); + reset(); + return DigestSize; + } + + public void reset() + { + Arrays.clear(m_buf); + m_bufPos = 0; + } + + protected void ensureSufficientInputBuffer(byte[] input, int inOff, int len) + { + if (inOff + len > input.length) + { + throw new DataLengthException("input buffer too short"); + } + } + + protected void ensureSufficientOutputBuffer(byte[] output, int outOff) + { + if (DigestSize + outOff > output.length) + { + throw new OutputLengthException("output buffer is too short"); + } + } + + protected abstract void processBytes(byte[] input, int inOff); + + protected abstract void finish(byte[] output, int outOff); +} diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/CSHAKEDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/CSHAKEDigest.java index 387bc8f732..e3bc609dc9 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/CSHAKEDigest.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/CSHAKEDigest.java @@ -2,6 +2,7 @@ import org.bouncycastle.crypto.CryptoServicePurpose; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Memoable; /** * Customizable SHAKE function. @@ -10,7 +11,8 @@ public class CSHAKEDigest extends SHAKEDigest { private static final byte[] padding = new byte[100]; - private final byte[] diff; + + private byte[] diff; /** * Base constructor. @@ -54,6 +56,29 @@ public CSHAKEDigest(CSHAKEDigest source) this.diff = Arrays.clone(source.diff); } + public CSHAKEDigest(byte[] encodedState) + { + super(encodedState); + + int sha3StateLength = state.length * 8 + dataQueue.length + 12 + 2; + if (encodedState.length != sha3StateLength) + { + this.diff = new byte[encodedState.length - sha3StateLength]; + System.arraycopy(encodedState, sha3StateLength, diff, 0, diff.length); + } + else + { + this.diff = null; + } + } + + private void copyIn(CSHAKEDigest source) + { + super.copyIn(source); + + this.diff = Arrays.clone(source.diff); + } + // bytepad in SP 800-185 private void diffPadAndAbsorb() { @@ -120,4 +145,36 @@ public void reset() diffPadAndAbsorb(); } } + + public byte[] getEncodedState() + { + int sha3StateLength = state.length * 8 + dataQueue.length + 12 + 2; + byte[] encState; + + if (diff == null) + { + encState = new byte[sha3StateLength]; + super.getEncodedState(encState); + } + else + { + encState = new byte[sha3StateLength + diff.length]; + super.getEncodedState(encState); + System.arraycopy(diff, 0, encState, sha3StateLength, diff.length); + } + + return encState; + } + + public Memoable copy() + { + return new CSHAKEDigest(this); + } + + public void reset(Memoable other) + { + CSHAKEDigest d = (CSHAKEDigest)other; + + copyIn(d); + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java index d79fece88a..badaa642ef 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/EncodableDigest.java @@ -1,5 +1,7 @@ package org.bouncycastle.crypto.digests; +import org.bouncycastle.crypto.EncodableService; + /** * Encodable digests allow you to download an encoded copy of their internal state. This is useful for the situation where * you need to generate a signature on an external device and it allows for "sign with last round", so a copy of the @@ -7,6 +9,7 @@ * entire message. */ public interface EncodableDigest + extends EncodableService { /** * Return an encoded byte array for the digest's internal state diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/ISAPDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/ISAPDigest.java index 9120e7592d..853db0b309 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/ISAPDigest.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/ISAPDigest.java @@ -1,10 +1,6 @@ package org.bouncycastle.crypto.digests; -import java.io.ByteArrayOutputStream; - -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.OutputLengthException; +import org.bouncycastle.crypto.engines.AsconPermutationFriend; import org.bouncycastle.util.Pack; /** @@ -16,131 +12,68 @@ */ public class ISAPDigest - implements Digest + extends BufferBaseDigest { - private long x0, x1, x2, x3, x4; - private long t0, t1, t2, t3, t4; - private ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - - private void ROUND(long C) - { - t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C)); - t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3)); - t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4); - t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4)); - t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1); - x0 = t0 ^ ROTR(t0, 19) ^ ROTR(t0, 28); - x1 = t1 ^ ROTR(t1, 39) ^ ROTR(t1, 61); - x2 = ~(t2 ^ ROTR(t2, 1) ^ ROTR(t2, 6)); - x3 = t3 ^ ROTR(t3, 10) ^ ROTR(t3, 17); - x4 = t4 ^ ROTR(t4, 7) ^ ROTR(t4, 41); - } - - private void P12() - { - ROUND(0xf0); - ROUND(0xe1); - ROUND(0xd2); - ROUND(0xc3); - ROUND(0xb4); - ROUND(0xa5); - ROUND(0x96); - ROUND(0x87); - ROUND(0x78); - ROUND(0x69); - ROUND(0x5a); - ROUND(0x4b); - } - - private long ROTR(long x, long n) + public static class Friend { - return (x >>> n) | (x << (64 - n)); - } + private static final Friend INSTANCE = new Friend(); - protected long U64BIG(long x) - { - return ((ROTR(x, 8) & (0xFF000000FF000000L)) | (ROTR(x, 24) & (0x00FF000000FF0000L)) | - (ROTR(x, 40) & (0x0000FF000000FF00L)) | (ROTR(x, 56) & (0x000000FF000000FFL))); - } + private Friend() + { + } - @Override - public String getAlgorithmName() - { - return "ISAP Hash"; + static Friend getFriend(AsconBaseDigest.Friend friend) + { + if (null == friend) + { + throw new NullPointerException("This method is only for use by AsconBaseDigest"); + } + return INSTANCE; + } } - @Override - public int getDigestSize() - { - return 32; - } + private final AsconPermutationFriend.AsconPermutation p; - @Override - public void update(byte input) + public ISAPDigest() { - buffer.write(input); + super(ProcessingBufferType.Immediate, 8); + p = AsconPermutationFriend.getAsconPermutation(Friend.INSTANCE); + DigestSize = 32; + algorithmName = "ISAP Hash"; + reset(); } @Override - public void update(byte[] input, int inOff, int len) + protected void processBytes(byte[] input, int inOff) { - if ((inOff + len) > input.length) - { - throw new DataLengthException("input buffer too short"); - } - buffer.write(input, inOff, len); + /* absorb */ + p.x0 ^= Pack.bigEndianToLong(input, inOff); + p.p(12); } @Override - public int doFinal(byte[] out, int outOff) + protected void finish(byte[] output, int outOff) { - if (32 + outOff > out.length) - { - throw new OutputLengthException("output buffer is too short"); - } - t0 = t1 = t2 = t3 = t4 = 0; - /* init state */ - x0 = -1255492011513352131L; - x1 = -8380609354527731710L; - x2 = -5437372128236807582L; - x3 = 4834782570098516968L; - x4 = 3787428097924915520L; - /* absorb */ - byte[] input = buffer.toByteArray(); - int len = input.length; - long[] in64 = new long[len >> 3]; - Pack.littleEndianToLong(input, 0, in64, 0, in64.length); - int idx = 0; - while (len >= 8) - { - x0 ^= U64BIG(in64[idx++]); - P12(); - len -= 8; - } /* absorb final input block */ - x0 ^= 0x80L << ((7 - len) << 3); - while (len > 0) + p.x0 ^= 0x80L << ((7 - m_bufPos) << 3); + while (m_bufPos > 0) { - x0 ^= (input[(idx << 3) + --len] & 0xFFL) << ((7 - len) << 3); + p.x0 ^= (m_buf[--m_bufPos] & 0xFFL) << ((7 - m_bufPos) << 3); } - P12(); // squeeze - long[] out64 = new long[4]; - for (idx = 0; idx < 3; ++idx) + for (int i = 0; i < 4; ++i) { - out64[idx] = U64BIG(x0); - P12(); + p.p(12); + Pack.longToBigEndian(p.x0, output, outOff); + outOff += 8; } - /* squeeze final output block */ - out64[idx] = U64BIG(x0); - Pack.longToLittleEndian(out64, out, outOff); - buffer.reset(); - return 32; } @Override public void reset() { - buffer.reset(); + super.reset(); + /* init state */ + p.set(-1255492011513352131L, -8380609354527731710L, -5437372128236807582L, 4834782570098516968L, 3787428097924915520L); } } diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/Kangaroo.java b/core/src/main/java/org/bouncycastle/crypto/digests/Kangaroo.java index c4ba8c3854..a4033c5105 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/Kangaroo.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/Kangaroo.java @@ -1,6 +1,10 @@ package org.bouncycastle.crypto.digests; -import org.bouncycastle.crypto.*; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoServicePurpose; +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.crypto.ExtendedDigest; +import org.bouncycastle.crypto.Xof; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Bytes; import org.bouncycastle.util.Pack; @@ -220,8 +224,6 @@ abstract static class KangarooBase */ private int theProcessed; - private final CryptoServicePurpose purpose; - /** * Constructor. * @@ -241,7 +243,6 @@ abstract static class KangarooBase /* Build personalisation */ buildPersonal(null); - this.purpose = purpose; CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties(this, pStrength, purpose)); @@ -542,7 +543,7 @@ private static class KangarooSponge /** * The round constants. */ - private static long[] KeccakRoundConstants = new long[]{0x0000000000000001L, 0x0000000000008082L, + private static final long[] KeccakRoundConstants = new long[]{0x0000000000000001L, 0x0000000000008082L, 0x800000000000808aL, 0x8000000080008000L, 0x000000000000808bL, 0x0000000080000001L, 0x8000000080008081L, 0x8000000000008009L, 0x000000000000008aL, 0x0000000000000088L, 0x0000000080008009L, 0x000000008000000aL, 0x000000008000808bL, 0x800000000000008bL, 0x8000000000008089L, 0x8000000000008003L, 0x8000000000008002L, @@ -625,6 +626,12 @@ private void absorb(final byte[] data, int count = 0; while (count < len) { + if (bytesInQueue == theRateBytes) + { + KangarooAbsorb(theQueue, 0); + bytesInQueue = 0; + } + if (bytesInQueue == 0 && count <= (len - theRateBytes)) { do @@ -642,12 +649,6 @@ private void absorb(final byte[] data, bytesInQueue += partialBlock; count += partialBlock; - - if (bytesInQueue == theRateBytes) - { - KangarooAbsorb(theQueue, 0); - bytesInQueue = 0; - } } } } diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/KeccakDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/KeccakDigest.java index f53552e550..bdb23d0238 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/KeccakDigest.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/KeccakDigest.java @@ -21,7 +21,7 @@ public class KeccakDigest 0x000000008000808bL, 0x800000000000008bL, 0x8000000000008089L, 0x8000000000008003L, 0x8000000000008002L, 0x8000000000000080L, 0x000000000000800aL, 0x800000008000000aL, 0x8000000080008081L, 0x8000000000008080L, 0x0000000080000001L, 0x8000000080008008L }; - protected final CryptoServicePurpose purpose; + protected CryptoServicePurpose purpose; protected long[] state = new long[25]; protected byte[] dataQueue = new byte[192]; @@ -66,6 +66,56 @@ public KeccakDigest(KeccakDigest source) CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties()); } + protected KeccakDigest(byte[] encodedState) + { + purpose = getCryptoServicePurpose(encodedState[0]); + + int encOff = 1; + Pack.bigEndianToLong(encodedState, encOff, state, 0, state.length); + encOff += state.length * 8; + System.arraycopy(encodedState, encOff, dataQueue, 0, dataQueue.length); + encOff += dataQueue.length; + rate = Pack.bigEndianToInt(encodedState, encOff); + encOff += 4; + bitsInQueue = Pack.bigEndianToInt(encodedState, encOff); + encOff += 4; + fixedOutputLength = Pack.bigEndianToInt(encodedState, encOff); + encOff += 4; + squeezing = encodedState[encOff] != 0; + } + + protected KeccakDigest(byte[] encodedState, CryptoServicePurpose purpose) + { + this(encodedState); + if (!this.purpose.equals(purpose)) + { + throw new IllegalStateException("digest encoded for a different purpose"); + } + } + + private static CryptoServicePurpose getCryptoServicePurpose(byte b) + { + CryptoServicePurpose[] values = CryptoServicePurpose.values(); + return values[b]; + } + + protected void copyIn(KeccakDigest source) + { + if (this.purpose != source.purpose) + { + throw new IllegalArgumentException("attempt to copy digest of different purpose"); + } + + System.arraycopy(source.state, 0, this.state, 0, source.state.length); + System.arraycopy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.length); + this.rate = source.rate; + this.bitsInQueue = source.bitsInQueue; + this.fixedOutputLength = source.fixedOutputLength; + this.squeezing = source.squeezing; + + CryptoServicesRegistrar.checkConstraints(cryptoServiceProperties()); + } + public String getAlgorithmName() { return "Keccak-" + fixedOutputLength; @@ -440,4 +490,29 @@ protected CryptoServiceProperties cryptoServiceProperties() { return Utils.getDefaultProperties(this, getDigestSize() * 8, purpose); } + + protected byte[] getEncodedState(byte[] encState) + { + encState[0] = (byte)purpose.ordinal(); + + int sOff = 1; + for (int i = 0; i != state.length; i++) + { + Pack.longToBigEndian(state[i], encState, sOff); + sOff += 8; + } + + System.arraycopy(dataQueue, 0, encState, sOff, dataQueue.length); + + sOff += dataQueue.length; + Pack.intToBigEndian(rate, encState, sOff); + sOff += 4; + Pack.intToBigEndian(bitsInQueue, encState, sOff); + sOff += 4; + Pack.intToBigEndian(fixedOutputLength, encState, sOff); + sOff += 4; + encState[sOff] = squeezing ? (byte)1 : (byte)0; + + return encState; + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/ParallelHash.java b/core/src/main/java/org/bouncycastle/crypto/digests/ParallelHash.java index 5ac7f120d0..7b05eb52ca 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/ParallelHash.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/ParallelHash.java @@ -38,8 +38,8 @@ public class ParallelHash * Base constructor. * * @param bitLength security strength (bits) of the underlying SHAKE function, 128 or 256. - * @param S the customization string - available for local use. - * @param B the blocksize (in bytes) for hashing. + * @param S the customization string - available for local use. + * @param B the blocksize (in bytes) for hashing. */ public ParallelHash(int bitLength, byte[] S, int B) { @@ -50,12 +50,18 @@ public ParallelHash(int bitLength, byte[] S, int B, int outputSize) { this(bitLength, S, B, outputSize, CryptoServicePurpose.ANY); } + public ParallelHash(int bitLength, byte[] S, int B, int outputSize, CryptoServicePurpose purpose) { + if (B <= 0) + { + throw new IllegalArgumentException("block size should be greater than 0"); + } this.cshake = new CSHAKEDigest(bitLength, N_PARALLEL_HASH, S); this.compressor = new CSHAKEDigest(bitLength, new byte[0], new byte[0]); this.bitLength = bitLength; this.B = B; + this.outputLength = (outputSize + 7) / 8; this.buffer = new byte[B]; this.compressorBuffer = new byte[bitLength * 2 / 8]; @@ -112,7 +118,7 @@ public void update(byte in) public void update(byte[] in, int inOff, int len) throws DataLengthException, IllegalStateException { - len = Math.max(0, len); + len = Math.max(0, len); // // fill the current word @@ -198,7 +204,7 @@ public int doFinal(byte[] out, int outOff, int outLen) { wrapUp(outputLength); } - + int rv = cshake.doFinal(out, outOff, outLen); reset(); diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/PhotonBeetleDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/PhotonBeetleDigest.java index cdf424f18b..62e04624e5 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/PhotonBeetleDigest.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/PhotonBeetleDigest.java @@ -1,10 +1,6 @@ package org.bouncycastle.crypto.digests; -import java.io.ByteArrayOutputStream; - -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.OutputLengthException; +import org.bouncycastle.crypto.engines.PhotonBeetleEngine; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Bytes; @@ -16,201 +12,85 @@ *

    */ public class PhotonBeetleDigest - implements Digest + extends BufferBaseDigest { - private byte[] state; - private byte[][] state_2d; - private ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - private final int INITIAL_RATE_INBYTES = 16; - private int RATE_INBYTES = 4; - private int SQUEEZE_RATE_INBYTES = 16; - private int STATE_INBYTES = 32; - private int TAG_INBYTES = 32; - private int LAST_THREE_BITS_OFFSET = 5; - private int ROUND = 12; - private int D = 8; - private int Dq = 3; - private int Dr = 7; - private int DSquare = 64; - private int S = 4; - private int S_1 = 3; - private byte[][] RC = {//[D][12] - {1, 3, 7, 14, 13, 11, 6, 12, 9, 2, 5, 10}, - {0, 2, 6, 15, 12, 10, 7, 13, 8, 3, 4, 11}, - {2, 0, 4, 13, 14, 8, 5, 15, 10, 1, 6, 9}, - {6, 4, 0, 9, 10, 12, 1, 11, 14, 5, 2, 13}, - {14, 12, 8, 1, 2, 4, 9, 3, 6, 13, 10, 5}, - {15, 13, 9, 0, 3, 5, 8, 2, 7, 12, 11, 4}, - {13, 15, 11, 2, 1, 7, 10, 0, 5, 14, 9, 6}, - {9, 11, 15, 6, 5, 3, 14, 4, 1, 10, 13, 2} - }; - private byte[][] MixColMatrix = { //[D][D] - {2, 4, 2, 11, 2, 8, 5, 6}, - {12, 9, 8, 13, 7, 7, 5, 2}, - {4, 4, 13, 13, 9, 4, 13, 9}, - {1, 6, 5, 1, 12, 13, 15, 14}, - {15, 12, 9, 13, 14, 5, 14, 13}, - {9, 14, 5, 15, 4, 12, 9, 6}, - {12, 2, 2, 10, 3, 1, 1, 14}, - {15, 1, 13, 10, 5, 10, 2, 3} - }; - - private byte[] sbox = {12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2}; - - public PhotonBeetleDigest() + public static class Friend { - state = new byte[STATE_INBYTES]; - state_2d = new byte[D][D]; - } + private static final Friend INSTANCE = new Friend(); - @Override - public String getAlgorithmName() - { - return "Photon-Beetle Hash"; + private Friend() + { + } } - @Override - public int getDigestSize() - { - return TAG_INBYTES; - } + private final byte[] state; + private static final int SQUEEZE_RATE_INBYTES = 16; + private static final int D = 8; + private int blockCount; - @Override - public void update(byte input) + public PhotonBeetleDigest() { - buffer.write(input); + super(ProcessingBufferType.Buffered, 4); + DigestSize = 32; + state = new byte[DigestSize]; + algorithmName = "Photon-Beetle Hash"; + blockCount = 0; } @Override - public void update(byte[] input, int inOff, int len) + protected void processBytes(byte[] input, int inOff) { - if ((inOff + len) > input.length) + if (blockCount < 4) + { + System.arraycopy(input, inOff, state, blockCount << 2, BlockSize); + } + else { - throw new DataLengthException("input buffer too short"); + PhotonBeetleEngine.photonPermutation(Friend.INSTANCE, state); + Bytes.xorTo(BlockSize, input, inOff, state); } - buffer.write(input, inOff, len); + blockCount++; } @Override - public int doFinal(byte[] output, int outOff) + protected void finish(byte[] output, int outOff) { - if (32 + outOff > output.length) + int LAST_THREE_BITS_OFFSET = 5; + if (m_bufPos == 0 && blockCount == 0) { - throw new OutputLengthException("output buffer is too short"); + state[DigestSize - 1] ^= 1 << LAST_THREE_BITS_OFFSET; } - byte[] input = buffer.toByteArray(); - int inlen = input.length; - if (inlen == 0) + else if (blockCount < 4) { - state[STATE_INBYTES - 1] ^= 1 << LAST_THREE_BITS_OFFSET; + System.arraycopy(m_buf, 0, state, blockCount << 2, m_bufPos); + state[(blockCount << 2) + m_bufPos] ^= 0x01; // ozs + state[DigestSize - 1] ^= (byte)1 << LAST_THREE_BITS_OFFSET; } - else if (inlen <= INITIAL_RATE_INBYTES) + else if (blockCount == 4 && m_bufPos == 0) { - System.arraycopy(input, 0, state, 0, inlen); - if (inlen < INITIAL_RATE_INBYTES) - { - state[inlen] ^= 0x01; // ozs - } - state[STATE_INBYTES - 1] ^= (inlen < INITIAL_RATE_INBYTES ? (byte)1 : (byte)2) << LAST_THREE_BITS_OFFSET; + state[DigestSize - 1] ^= (byte)2 << LAST_THREE_BITS_OFFSET; } else { - System.arraycopy(input, 0, state, 0, INITIAL_RATE_INBYTES); - inlen -= INITIAL_RATE_INBYTES; - int Dlen_inblocks = (inlen + RATE_INBYTES - 1) / RATE_INBYTES; - int i, LastDBlocklen; - for (i = 0; i < Dlen_inblocks - 1; i++) + PhotonBeetleEngine.photonPermutation(Friend.INSTANCE, state); + Bytes.xorTo(m_bufPos, m_buf, state); + if (m_bufPos < BlockSize) { - PHOTON_Permutation(); - Bytes.xorTo(RATE_INBYTES, input, INITIAL_RATE_INBYTES + i * RATE_INBYTES, state, 0); + state[m_bufPos] ^= 0x01; // ozs } - PHOTON_Permutation(); - LastDBlocklen = inlen - i * RATE_INBYTES; - Bytes.xorTo(LastDBlocklen, input, INITIAL_RATE_INBYTES + i * RATE_INBYTES, state, 0); - if (LastDBlocklen < RATE_INBYTES) - { - state[LastDBlocklen] ^= 0x01; // ozs - } - state[STATE_INBYTES - 1] ^= (inlen % RATE_INBYTES == 0 ? (byte)1 : (byte)2) << LAST_THREE_BITS_OFFSET; + state[DigestSize - 1] ^= (m_bufPos % BlockSize == 0 ? (byte)1 : (byte)2) << LAST_THREE_BITS_OFFSET; } - PHOTON_Permutation(); + PhotonBeetleEngine.photonPermutation(Friend.INSTANCE, state); System.arraycopy(state, 0, output, outOff, SQUEEZE_RATE_INBYTES); - PHOTON_Permutation(); - System.arraycopy(state, 0, output, outOff + SQUEEZE_RATE_INBYTES, TAG_INBYTES - SQUEEZE_RATE_INBYTES); - reset(); - return TAG_INBYTES; + PhotonBeetleEngine.photonPermutation(Friend.INSTANCE, state); + System.arraycopy(state, 0, output, outOff + SQUEEZE_RATE_INBYTES, SQUEEZE_RATE_INBYTES); } @Override public void reset() { - buffer.reset(); + super.reset(); Arrays.fill(state, (byte)0); + blockCount = 0; } - - void PHOTON_Permutation() - { - int i, j, k; - for (i = 0; i < DSquare; i++) - { - state_2d[i >>> Dq][i & Dr] = (byte)(((state[i >> 1] & 0xFF) >>> (4 * (i & 1))) & 0xf); - } - for (int round = 0; round < ROUND; round++) - { - //AddKey - for (i = 0; i < D; i++) - { - state_2d[i][0] ^= RC[i][round]; - } - //SubCell - for (i = 0; i < D; i++) - { - for (j = 0; j < D; j++) - { - state_2d[i][j] = sbox[state_2d[i][j]]; - } - } - //ShiftRow - for (i = 1; i < D; i++) - { - System.arraycopy(state_2d[i], 0, state, 0, D); - System.arraycopy(state, i, state_2d[i], 0, D - i); - System.arraycopy(state, 0, state_2d[i], D - i, i); - } - //MixColumn - for (j = 0; j < D; j++) - { - for (i = 0; i < D; i++) - { - int sum = 0; - - for (k = 0; k < D; k++) - { - int x = MixColMatrix[i][k], b = state_2d[k][j]; - - sum ^= x * (b & 1); - sum ^= x * (b & 2); - sum ^= x * (b & 4); - sum ^= x * (b & 8); - } - - int t0 = sum >>> 4; - sum = (sum & 15) ^ t0 ^ (t0 << 1); - - int t1 = sum >>> 4; - sum = (sum & 15) ^ t1 ^ (t1 << 1); - - state[i] = (byte)sum; - } - for (i = 0; i < D; i++) - { - state_2d[i][j] = state[i]; - } - } - } - for (i = 0; i < DSquare; i += 2) - { - state[i >>> 1] = (byte)(((state_2d[i >>> Dq][i & Dr] & 0xf)) | ((state_2d[i >>> Dq][(i + 1) & Dr] & 0xf) << 4)); - } - } -} +} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/RomulusDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/RomulusDigest.java new file mode 100644 index 0000000000..4d5a722198 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/digests/RomulusDigest.java @@ -0,0 +1,67 @@ +package org.bouncycastle.crypto.digests; + +import org.bouncycastle.crypto.engines.RomulusEngine; +import org.bouncycastle.util.Arrays; + +/** + * Romulus v1.3, based on the current round 3 submission, https://romulusae.github.io/romulus/ + * Reference C implementation: https://github.com/romulusae/romulus + * Specification: https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/romulus-spec-final.pdf + */ + +public class RomulusDigest + extends BufferBaseDigest +{ + public static class Friend + { + private static final Friend INSTANCE = new Friend(); + + private Friend() + { + } + } + + private final byte[] h = new byte[16]; + private final byte[] g = new byte[16]; + /* + * This file includes only the encryption function of SKINNY-128-384+ as required by Romulus-v1.3 + */ +// Packing of data is done as follows (state[i][j] stands for row i and column j): +// 0 1 2 3 +// 4 5 6 7 +// 8 9 10 11 +//12 13 14 15 + + public RomulusDigest() + { + super(ProcessingBufferType.Immediate, 32); + DigestSize = 32; + algorithmName = "Romulus Hash"; + } + + @Override + protected void processBytes(byte[] input, int inOff) + { + RomulusEngine.hirose_128_128_256(Friend.INSTANCE, h, g, input, inOff); + } + + @Override + protected void finish(byte[] output, int outOff) + { + Arrays.fill(m_buf, m_bufPos, 31, (byte)0); + m_buf[31] = (byte)(m_bufPos & 0x1f); + h[0] ^= 2; + RomulusEngine.hirose_128_128_256(Friend.INSTANCE, h, g, m_buf, 0); + // Assign the output tag + System.arraycopy(h, 0, output, outOff, 16); + System.arraycopy(g, 0, output, 16 + outOff, 16); + } + + @Override + public void reset() + { + super.reset(); + Arrays.clear(h); + Arrays.clear(g); + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/SHA3Digest.java b/core/src/main/java/org/bouncycastle/crypto/digests/SHA3Digest.java index 8c93fb0282..4dcf41b426 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/SHA3Digest.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/SHA3Digest.java @@ -1,7 +1,8 @@ package org.bouncycastle.crypto.digests; - import org.bouncycastle.crypto.CryptoServicePurpose; +import org.bouncycastle.crypto.SavableDigest; +import org.bouncycastle.util.Memoable; /** * implementation of SHA-3 based on following KeccakNISTInterface.c from https://keccak.noekeon.org/ @@ -10,6 +11,7 @@ */ public class SHA3Digest extends KeccakDigest + implements SavableDigest { private static int checkBitLength(int bitLength) { @@ -45,6 +47,11 @@ public SHA3Digest(int bitLength, CryptoServicePurpose purpose) super(checkBitLength(bitLength), purpose); } + public SHA3Digest(byte[] encodedState) + { + super(encodedState); + } + public SHA3Digest(SHA3Digest source) { super(source); @@ -84,4 +91,25 @@ protected int doFinal(byte[] out, int outOff, byte partialByte, int partialBits) return super.doFinal(out, outOff, (byte)finalInput, finalBits); } + + public byte[] getEncodedState() + { + byte[] encState = new byte[state.length * 8 + dataQueue.length + 12 + 2]; + + super.getEncodedState(encState); + + return encState; + } + + public Memoable copy() + { + return new SHA3Digest(this); + } + + public void reset(Memoable other) + { + SHA3Digest d = (SHA3Digest)other; + + copyIn(d); + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/SHAKEDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/SHAKEDigest.java index 4b30c0e150..5acbb87654 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/SHAKEDigest.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/SHAKEDigest.java @@ -2,7 +2,9 @@ import org.bouncycastle.crypto.CryptoServiceProperties; import org.bouncycastle.crypto.CryptoServicePurpose; +import org.bouncycastle.crypto.SavableDigest; import org.bouncycastle.crypto.Xof; +import org.bouncycastle.util.Memoable; /** @@ -12,7 +14,7 @@ */ public class SHAKEDigest extends KeccakDigest - implements Xof + implements Xof, SavableDigest { private static int checkBitLength(int bitStrength) { @@ -67,6 +69,11 @@ public SHAKEDigest(SHAKEDigest source) super(source); } + public SHAKEDigest(byte[] encodedState) + { + super(encodedState); + } + public String getAlgorithmName() { return "SHAKE" + fixedOutputLength; @@ -147,4 +154,25 @@ protected CryptoServiceProperties cryptoServiceProperties() { return Utils.getDefaultProperties(this, purpose); } + + public byte[] getEncodedState() + { + byte[] encState = new byte[state.length * 8 + dataQueue.length + 12 + 2]; + + super.getEncodedState(encState); + + return encState; + } + + public Memoable copy() + { + return new SHAKEDigest(this); + } + + public void reset(Memoable other) + { + SHAKEDigest d = (SHAKEDigest)other; + + copyIn(d); + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/SparkleDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/SparkleDigest.java index 90c17f62ea..7cabb2df28 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/SparkleDigest.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/SparkleDigest.java @@ -1,8 +1,5 @@ package org.bouncycastle.crypto.digests; -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.ExtendedDigest; -import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.engines.SparkleEngine; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Integers; @@ -14,12 +11,15 @@ * Specification: https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/sparkle-spec-final.pdf */ public class SparkleDigest - implements ExtendedDigest + extends BufferBaseDigest { public static class Friend { private static final Friend INSTANCE = new Friend(); - private Friend() {} + + private Friend() + { + } } public enum SparkleParameters @@ -28,33 +28,27 @@ public enum SparkleParameters ESCH384 } - private static final int RATE_BYTES = 16; private static final int RATE_WORDS = 4; - - private String algorithmName; private final int[] state; - private final byte[] m_buf = new byte[RATE_BYTES]; - private final int DIGEST_BYTES; private final int SPARKLE_STEPS_SLIM; private final int SPARKLE_STEPS_BIG; private final int STATE_WORDS; - private int m_bufPos = 0; - public SparkleDigest(SparkleParameters sparkleParameters) { + super(ProcessingBufferType.Buffered, 16); switch (sparkleParameters) { case ESCH256: algorithmName = "ESCH-256"; - DIGEST_BYTES = 32; + DigestSize = 32; SPARKLE_STEPS_SLIM = 7; SPARKLE_STEPS_BIG = 11; STATE_WORDS = 12; break; case ESCH384: algorithmName = "ESCH-384"; - DIGEST_BYTES = 48; + DigestSize = 48; SPARKLE_STEPS_SLIM = 8; SPARKLE_STEPS_BIG = 12; STATE_WORDS = 16; @@ -62,97 +56,26 @@ public SparkleDigest(SparkleParameters sparkleParameters) default: throw new IllegalArgumentException("Invalid definition of SCHWAEMM instance"); } - state = new int[STATE_WORDS]; } @Override - public String getAlgorithmName() - { - return algorithmName; - } - - @Override - public int getDigestSize() - { - return DIGEST_BYTES; - } - - @Override - public int getByteLength() - { - return RATE_BYTES; - } - - @Override - public void update(byte input) - { - if (m_bufPos == RATE_BYTES) - { - processBlock(m_buf, 0, SPARKLE_STEPS_SLIM); - m_bufPos = 0; - } - - m_buf[m_bufPos++] = input; - } - - @Override - public void update(byte[] in, int inOff, int len) + protected void processBytes(byte[] input, int inOff) { - if (inOff > in.length - len) - { - throw new DataLengthException(algorithmName + " input buffer too short"); - } - - if (len < 1) - return; - - int available = RATE_BYTES - m_bufPos; - if (len <= available) - { - System.arraycopy(in, inOff, m_buf, m_bufPos, len); - m_bufPos += len; - return; - } - - int inPos = 0; - if (m_bufPos > 0) - { - System.arraycopy(in, inOff, m_buf, m_bufPos, available); - processBlock(m_buf, 0, SPARKLE_STEPS_SLIM); - inPos += available; - } - - int remaining; - while ((remaining = len - inPos) > RATE_BYTES) - { - processBlock(in, inOff + inPos, SPARKLE_STEPS_SLIM); - inPos += RATE_BYTES; - } - - System.arraycopy(in, inOff + inPos, m_buf, 0, remaining); - m_bufPos = remaining; + processBlock(input, inOff, SPARKLE_STEPS_SLIM); } @Override - public int doFinal(byte[] output, int outOff) + protected void finish(byte[] output, int outOff) { - if (outOff > output.length - DIGEST_BYTES) - { - throw new OutputLengthException(algorithmName + " input buffer too short"); - } - // addition of constant M1 or M2 to the state - if (m_bufPos < RATE_BYTES) + if (m_bufPos < BlockSize) { state[(STATE_WORDS >> 1) - 1] ^= 1 << 24; // padding - m_buf[m_bufPos] = (byte)0x80; - while(++m_bufPos < RATE_BYTES) - { - m_buf[m_bufPos] = 0x00; - } + m_buf[m_bufPos++] = (byte)0x80; + Arrays.fill(m_buf, m_bufPos, BlockSize, (byte)0); } else { @@ -175,24 +98,20 @@ public int doFinal(byte[] output, int outOff) SparkleEngine.sparkle_opt12(Friend.INSTANCE, state, SPARKLE_STEPS_SLIM); Pack.intToLittleEndian(state, 0, RATE_WORDS, output, outOff + 16); } - - reset(); - return DIGEST_BYTES; } @Override public void reset() { + super.reset(); Arrays.fill(state, 0); - Arrays.fill(m_buf, (byte)0); - m_bufPos = 0; } private void processBlock(byte[] buf, int off, int steps) { - int t0 = Pack.littleEndianToInt(buf, off ); - int t1 = Pack.littleEndianToInt(buf, off + 4); - int t2 = Pack.littleEndianToInt(buf, off + 8); + int t0 = Pack.littleEndianToInt(buf, off); + int t1 = Pack.littleEndianToInt(buf, off + 4); + int t2 = Pack.littleEndianToInt(buf, off + 8); int t3 = Pack.littleEndianToInt(buf, off + 12); // addition of a buffer block to the state @@ -220,4 +139,4 @@ private static int ELL(int x) { return Integers.rotateRight(x, 16) ^ (x & 0xFFFF); } -} +} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/TupleHash.java b/core/src/main/java/org/bouncycastle/crypto/digests/TupleHash.java index 02626ac23e..635b5296a9 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/TupleHash.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/TupleHash.java @@ -1,8 +1,11 @@ package org.bouncycastle.crypto.digests; import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.SavableDigest; import org.bouncycastle.crypto.Xof; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Memoable; +import org.bouncycastle.util.Pack; import org.bouncycastle.util.Strings; /** @@ -13,14 +16,14 @@ *

    */ public class TupleHash - implements Xof, Digest + implements Xof, SavableDigest { private static final byte[] N_TUPLE_HASH = Strings.toByteArray("TupleHash"); private final CSHAKEDigest cshake; - private final int bitLength; - private final int outputLength; + private int bitLength; + private int outputLength; private boolean firstOutput; /** @@ -46,11 +49,27 @@ public TupleHash(int bitLength, byte[] S, int outputSize) public TupleHash(TupleHash original) { this.cshake = new CSHAKEDigest(original.cshake); + this.bitLength = original.bitLength; + this.outputLength = original.outputLength; + this.firstOutput = original.firstOutput; + } + + public TupleHash(byte[] state) + { + this.cshake = new CSHAKEDigest(Arrays.copyOfRange(state, 0, state.length - 9)); + this.bitLength = Pack.bigEndianToInt(state, state.length - 9); + this.outputLength = Pack.bigEndianToInt(state, state.length - 5); + this.firstOutput = state[state.length - 1] != 0; + } + + private void copyIn(TupleHash original) + { + this.cshake.reset(original.cshake); this.bitLength = cshake.fixedOutputLength; this.outputLength = bitLength * 2 / 8; this.firstOutput = original.firstOutput; } - + public String getAlgorithmName() { return "TupleHash" + cshake.getAlgorithmName().substring(6); @@ -133,4 +152,26 @@ public void reset() cshake.reset(); firstOutput = true; } + + public byte[] getEncodedState() + { + byte[] cshakeState = this.cshake.getEncodedState(); + byte[] extraState = new byte[4 + 4 + 1]; + + Pack.intToBigEndian(this.bitLength, extraState, 0); + Pack.intToBigEndian(this.outputLength, extraState, 4); + extraState[8] = this.firstOutput ? (byte)1 : (byte)0; + + return Arrays.concatenate(cshakeState, extraState); + } + + public Memoable copy() + { + return new TupleHash(this); + } + + public void reset(Memoable other) + { + copyIn((TupleHash)other); + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/digests/XoodyakDigest.java b/core/src/main/java/org/bouncycastle/crypto/digests/XoodyakDigest.java index d771a38738..ee099c4b9b 100644 --- a/core/src/main/java/org/bouncycastle/crypto/digests/XoodyakDigest.java +++ b/core/src/main/java/org/bouncycastle/crypto/digests/XoodyakDigest.java @@ -1,13 +1,7 @@ package org.bouncycastle.crypto.digests; -import java.io.ByteArrayOutputStream; - -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.OutputLengthException; +import org.bouncycastle.crypto.engines.XoodyakEngine; import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Integers; -import org.bouncycastle.util.Pack; /** * Xoodyak v1, https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/xoodyak-spec-final.pdf @@ -17,232 +11,71 @@ */ public class XoodyakDigest - implements Digest + extends BufferBaseDigest { - private byte[] state; - private int phase; - private MODE mode; - private int Rabsorb; - private final int f_bPrime = 48; - private final int Rhash = 16; - private final int PhaseDown = 1; - private final int PhaseUp = 2; -// private final int NLANES = 12; -// private final int NROWS = 3; -// private final int NCOLUMS = 4; - private final int MAXROUNDS = 12; - private final int TAGLEN = 16; - private final int[] RC = {0x00000058, 0x00000038, 0x000003C0, 0x000000D0, 0x00000120, 0x00000014, 0x00000060, - 0x0000002C, 0x00000380, 0x000000F0, 0x000001A0, 0x00000012}; - private final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - - enum MODE + public static class Friend { - ModeHash, - ModeKeyed + private static final Friend INSTANCE = new Friend(); + + private Friend() + { + } } + private final byte[] state; + private int phase; + private static final int mode = 1; // set as ModeHash + private static final int PhaseUp = 2; + private static final int PhaseDown = 1; + private static final int TAGLEN = 16; + private int Cd; + public XoodyakDigest() { + super(ProcessingBufferType.Immediate, 16); + DigestSize = 32; state = new byte[48]; + algorithmName = "Xoodyak Hash"; reset(); } @Override - public String getAlgorithmName() + protected void processBytes(byte[] input, int inOff) { - return "Xoodyak Hash"; - } - - @Override - public int getDigestSize() - { - return 32; - } - - @Override - public void update(byte input) - { - buffer.write(input); - } - - @Override - public void update(byte[] input, int inOff, int len) - { - if ((inOff + len) > input.length) + if (phase != PhaseUp) { - throw new DataLengthException("input buffer too short"); + XoodyakEngine.up(Friend.INSTANCE, mode, state, 0); } - buffer.write(input, inOff, len); - + XoodyakEngine.down(Friend.INSTANCE, mode, state, input, inOff, BlockSize, Cd); + phase = PhaseDown; + Cd = 0; } @Override - public int doFinal(byte[] output, int outOff) + protected void finish(byte[] output, int outOff) { - if (32 + outOff > output.length) - { - throw new OutputLengthException("output buffer is too short"); - } - byte[] input = buffer.toByteArray(); - int inOff = 0; - int len = buffer.size(); - int Cd = 0x03; - int splitLen; - do + if (m_bufPos != 0) { if (phase != PhaseUp) { - Up(null, 0, 0, 0); + XoodyakEngine.up(Friend.INSTANCE, mode, state, 0); } - splitLen = Math.min(len, Rabsorb); - Down(input, inOff, splitLen, Cd); - Cd = 0; - inOff += splitLen; - len -= splitLen; + XoodyakEngine.down(Friend.INSTANCE, mode, state, m_buf, 0, m_bufPos, Cd); } - while (len != 0); - Up(output, outOff, TAGLEN, 0x40); - Down(null, 0, 0, 0); - Up(output, outOff + TAGLEN, TAGLEN, 0); - reset(); - return 32; + XoodyakEngine.up(Friend.INSTANCE, mode, state, 0x40); + System.arraycopy(state, 0, output, outOff, TAGLEN); + XoodyakEngine.down(Friend.INSTANCE, mode, state, null, 0, 0, 0); + XoodyakEngine.up(Friend.INSTANCE, mode, state, 0); + System.arraycopy(state, 0, output, outOff + TAGLEN, TAGLEN); + phase = PhaseDown; } @Override public void reset() { + super.reset(); Arrays.fill(state, (byte)0); phase = PhaseUp; - mode = MODE.ModeHash; - Rabsorb = Rhash; - buffer.reset(); - } - - private void Up(byte[] Yi, int YiOff, int YiLen, int Cu) - { - if (mode != MODE.ModeHash) - { - state[f_bPrime - 1] ^= Cu; - } - - int a0 = Pack.littleEndianToInt(state, 0); - int a1 = Pack.littleEndianToInt(state, 4); - int a2 = Pack.littleEndianToInt(state, 8); - int a3 = Pack.littleEndianToInt(state, 12); - int a4 = Pack.littleEndianToInt(state, 16); - int a5 = Pack.littleEndianToInt(state, 20); - int a6 = Pack.littleEndianToInt(state, 24); - int a7 = Pack.littleEndianToInt(state, 28); - int a8 = Pack.littleEndianToInt(state, 32); - int a9 = Pack.littleEndianToInt(state, 36); - int a10 = Pack.littleEndianToInt(state, 40); - int a11 = Pack.littleEndianToInt(state, 44); - - for (int i = 0; i < MAXROUNDS; ++i) - { - /* Theta: Column Parity Mixer */ - int p0 = a0 ^ a4 ^ a8; - int p1 = a1 ^ a5 ^ a9; - int p2 = a2 ^ a6 ^ a10; - int p3 = a3 ^ a7 ^ a11; - - int e0 = Integers.rotateLeft(p3, 5) ^ Integers.rotateLeft(p3, 14); - int e1 = Integers.rotateLeft(p0, 5) ^ Integers.rotateLeft(p0, 14); - int e2 = Integers.rotateLeft(p1, 5) ^ Integers.rotateLeft(p1, 14); - int e3 = Integers.rotateLeft(p2, 5) ^ Integers.rotateLeft(p2, 14); - - a0 ^= e0; - a4 ^= e0; - a8 ^= e0; - - a1 ^= e1; - a5 ^= e1; - a9 ^= e1; - - a2 ^= e2; - a6 ^= e2; - a10 ^= e2; - - a3 ^= e3; - a7 ^= e3; - a11 ^= e3; - - /* Rho-west: plane shift */ - int b0 = a0; - int b1 = a1; - int b2 = a2; - int b3 = a3; - - int b4 = a7; - int b5 = a4; - int b6 = a5; - int b7 = a6; - - int b8 = Integers.rotateLeft(a8, 11); - int b9 = Integers.rotateLeft(a9, 11); - int b10 = Integers.rotateLeft(a10, 11); - int b11 = Integers.rotateLeft(a11, 11); - - /* Iota: round ant */ - b0 ^= RC[i]; - - /* Chi: non linear layer */ - a0 = b0 ^ (~b4 & b8); - a1 = b1 ^ (~b5 & b9); - a2 = b2 ^ (~b6 & b10); - a3 = b3 ^ (~b7 & b11); - - a4 = b4 ^ (~b8 & b0); - a5 = b5 ^ (~b9 & b1); - a6 = b6 ^ (~b10 & b2); - a7 = b7 ^ (~b11 & b3); - - b8 ^= (~b0 & b4); - b9 ^= (~b1 & b5); - b10 ^= (~b2 & b6); - b11 ^= (~b3 & b7); - - /* Rho-east: plane shift */ - a4 = Integers.rotateLeft(a4, 1); - a5 = Integers.rotateLeft(a5, 1); - a6 = Integers.rotateLeft(a6, 1); - a7 = Integers.rotateLeft(a7, 1); - - a8 = Integers.rotateLeft(b10, 8); - a9 = Integers.rotateLeft(b11, 8); - a10 = Integers.rotateLeft(b8, 8); - a11 = Integers.rotateLeft(b9, 8); - } - - Pack.intToLittleEndian(a0, state, 0); - Pack.intToLittleEndian(a1, state, 4); - Pack.intToLittleEndian(a2, state, 8); - Pack.intToLittleEndian(a3, state, 12); - Pack.intToLittleEndian(a4, state, 16); - Pack.intToLittleEndian(a5, state, 20); - Pack.intToLittleEndian(a6, state, 24); - Pack.intToLittleEndian(a7, state, 28); - Pack.intToLittleEndian(a8, state, 32); - Pack.intToLittleEndian(a9, state, 36); - Pack.intToLittleEndian(a10, state, 40); - Pack.intToLittleEndian(a11, state, 44); - - phase = PhaseUp; - if (Yi != null) - { - System.arraycopy(state, 0, Yi, YiOff, YiLen); - } - } - - void Down(byte[] Xi, int XiOff, int XiLen, int Cd) - { - for (int i = 0; i < XiLen; i++) - { - state[i] ^= Xi[XiOff++]; - } - state[XiLen] ^= 0x01; - state[f_bPrime - 1] ^= (mode == MODE.ModeHash) ? (Cd & 0x01) : Cd; - phase = PhaseDown; + Cd = 0x03; } -} +} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java index 25cff6b482..454cf6bb9b 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBaseEngine.java @@ -1,24 +1,132 @@ package org.bouncycastle.crypto.engines; +import java.io.ByteArrayOutputStream; + import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.constraints.DefaultServiceProperties; import org.bouncycastle.crypto.modes.AEADCipher; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.Arrays; abstract class AEADBaseEngine implements AEADCipher { + protected static class ProcessingBufferType + { + public static final int BUFFERED = 0; // Store a (aad) block size of input and process after the input size exceeds the buffer size + public static final int IMMEDIATE = 1; //process the input immediately when the input size is equal or greater than the block size + + public static final ProcessingBufferType Buffered = new ProcessingBufferType(BUFFERED); + public static final ProcessingBufferType Immediate = new ProcessingBufferType(IMMEDIATE); + + private final int ord; + + ProcessingBufferType(int ord) + { + this.ord = ord; + } + } + + protected static class AADOperatorType + { + public static final int DEFAULT = 0; + public static final int COUNTER = 1;//add a counter to count the size of AAD + public static final int STREAM = 2; //process AAD data during the process data, used for elephant + public static final int DATA_LIMIT = 3;// count AAD data to the counter, used for AsconAEAD128 + + public static final AADOperatorType Default = new AADOperatorType(DEFAULT); + public static final AADOperatorType Counter = new AADOperatorType(COUNTER); + public static final AADOperatorType Stream = new AADOperatorType(STREAM); + public static final AADOperatorType DataLimit = new AADOperatorType(DATA_LIMIT); + + private final int ord; + + AADOperatorType(int ord) + { + this.ord = ord; + } + } + + protected static class DataOperatorType + { + public static final int DEFAULT = 0; + public static final int COUNTER = 1; + public static final int STREAM = 2; + public static final int STREAM_CIPHER = 3; + public static final int DATA_LIMIT = 4; // count AAD data to the counter, used for AsconAEAD128 + + public static final DataOperatorType Default = new DataOperatorType(DEFAULT); + public static final DataOperatorType Counter = new DataOperatorType(COUNTER); + public static final DataOperatorType Stream = new DataOperatorType(STREAM); + public static final DataOperatorType StreamCipher = new DataOperatorType(STREAM_CIPHER); + public static final DataOperatorType DataLimit = new DataOperatorType(DATA_LIMIT); + + private final int ord; + + DataOperatorType(int ord) + { + this.ord = ord; + } + } + + protected static class State + { + public static final int UNINITIALIZED = 0; + public static final int ENC_INIT = 1; + public static final int ENC_AAD = 2; // can process AAD + public static final int ENC_DATA = 3; // cannot process AAD + public static final int ENC_FINAL = 4; + public static final int DEC_INIT = 5; + public static final int DEC_AAD = 6; // can process AAD + public static final int DEC_DATA = 7; // cannot process AAD + public static final int DEC_FINAL = 8; + + public static final State Uninitialized = new State(UNINITIALIZED); + public static final State EncInit = new State(ENC_INIT); + public static final State EncAad = new State(ENC_AAD); + public static final State EncData = new State(ENC_DATA); + public static final State EncFinal = new State(ENC_FINAL); + public static final State DecInit = new State(DEC_INIT); + public static final State DecAad = new State(DEC_AAD); + public static final State DecData = new State(DEC_DATA); + public static final State DecFinal = new State(DEC_FINAL); + + final int ord; + + State(int ord) + { + this.ord = ord; + } + } + protected boolean forEncryption; protected String algorithmName; protected int KEY_SIZE; protected int IV_SIZE; protected int MAC_SIZE; + protected int macSizeLowerBound = 0; protected byte[] initialAssociatedText; protected byte[] mac; + protected byte[] m_buf; + protected byte[] m_aad; + protected int m_bufPos; + protected int m_aadPos; + protected int AADBufferSize; + protected int BlockSize; + protected State m_state = State.Uninitialized; + protected int m_bufferSizeDecrypt; + protected AADProcessingBuffer processor; + protected AADOperator aadOperator; + protected DataOperator dataOperator; + //Only AsconAEAD128 uses this counter; + protected DecryptionFailureCounter decryptionFailureCounter = null; + protected DataLimitCounter dataLimitCounter = null; @Override public String getAlgorithmName() @@ -41,17 +149,7 @@ public byte[] getMac() return mac; } - public void reset() - { - reset(true); - } - - public int processByte(byte in, byte[] out, int outOff) - throws DataLengthException - { - return processBytes(new byte[]{in}, 0, 1, out, outOff); - } - + @Override public void init(boolean forEncryption, CipherParameters params) { this.forEncryption = forEncryption; @@ -67,9 +165,22 @@ public void init(boolean forEncryption, CipherParameters params) initialAssociatedText = aeadParameters.getAssociatedText(); int macSizeBits = aeadParameters.getMacSize(); - if (macSizeBits != MAC_SIZE * 8) + if (macSizeLowerBound == 0) + { + if (macSizeBits != (MAC_SIZE << 3)) + { + throw new IllegalArgumentException("Invalid value for MAC size: " + macSizeBits); + } + } + else { - throw new IllegalArgumentException("Invalid value for MAC size: " + macSizeBits); + //TODO: set macSizeUpperBound instead of 128 fix value if necessary + if (macSizeBits > 128 || macSizeBits < (macSizeLowerBound << 3) || (macSizeBits & 7) != 0) + { + throw new IllegalArgumentException("MAC size must be between " + (macSizeLowerBound << 3) + + " and 128 bits for " + algorithmName); + } + MAC_SIZE = macSizeBits >>> 3; } } else if (params instanceof ParametersWithIV) @@ -102,20 +213,1110 @@ else if (params instanceof ParametersWithIV) CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties( this.getAlgorithmName(), 128, params, Utils.getPurpose(forEncryption))); + m_state = forEncryption ? State.EncInit : State.DecInit; init(k, npub); + if (dataLimitCounter != null) + { + dataLimitCounter.increment(npub.length); + } + reset(true); if (initialAssociatedText != null) { processAADBytes(initialAssociatedText, 0, initialAssociatedText.length); } } - protected abstract void init(byte[] key, byte[] iv); + @Override + public void reset() + { + reset(true); + } protected void reset(boolean clearMac) { + ensureInitialized(); if (clearMac) { mac = null; } + if (m_buf != null) + { + Arrays.fill(m_buf, (byte)0); + m_bufPos = 0; + } + if (m_aad != null) + { + Arrays.fill(m_aad, (byte)0); + m_aadPos = 0; + } + switch (m_state.ord) + { + case State.DEC_INIT: + case State.ENC_INIT: + break; + case State.DEC_AAD: + case State.DEC_DATA: + case State.DEC_FINAL: + m_state = State.DecFinal; + break; + case State.ENC_AAD: + case State.ENC_DATA: + case State.ENC_FINAL: + m_state = State.EncFinal; + return; + default: + throw new IllegalStateException(getAlgorithmName() + " needs to be initialized"); + } + aadOperator.reset(); + dataOperator.reset(); + } + + protected void setInnerMembers(ProcessingBufferType type, AADOperatorType aadOperatorType, DataOperatorType dataOperatorType) + { + switch (type.ord) + { + case ProcessingBufferType.BUFFERED: + processor = new BufferedAADProcessor(); + break; + case ProcessingBufferType.IMMEDIATE: + processor = new ImmediateAADProcessor(); + break; + } + + m_bufferSizeDecrypt = BlockSize + MAC_SIZE; + + switch (aadOperatorType.ord) + { + case AADOperatorType.DEFAULT: + m_aad = new byte[AADBufferSize]; + aadOperator = new DefaultAADOperator(); + break; + case AADOperatorType.COUNTER: + m_aad = new byte[AADBufferSize]; + aadOperator = new CounterAADOperator(); + break; + case AADOperatorType.STREAM: + AADBufferSize = 0; + aadOperator = new StreamAADOperator(); + break; + case AADOperatorType.DATA_LIMIT: + m_aad = new byte[AADBufferSize]; + dataLimitCounter = new DataLimitCounter(); + aadOperator = new DataLimitAADOperator(); + break; + } + + switch (dataOperatorType.ord) + { + case DataOperatorType.DEFAULT: + m_buf = new byte[m_bufferSizeDecrypt]; + dataOperator = new DefaultDataOperator(); + break; + case DataOperatorType.COUNTER: + m_buf = new byte[m_bufferSizeDecrypt]; + dataOperator = new CounterDataOperator(); + break; + case DataOperatorType.STREAM: + m_buf = new byte[MAC_SIZE]; + dataOperator = new StreamDataOperator(); + break; + case DataOperatorType.STREAM_CIPHER: + BlockSize = 0; + m_buf = new byte[m_bufferSizeDecrypt]; + dataOperator = new StreamCipherOperator(); + break; + case DataOperatorType.DATA_LIMIT: + m_buf = new byte[m_bufferSizeDecrypt]; + dataOperator = new DataLimitDataOperator(); + break; + } + } + + private interface AADProcessingBuffer + { + void processAADByte(byte input); + + int processByte(byte input, byte[] output, int outOff); + + int getUpdateOutputSize(int len); + + boolean isLengthWithinAvailableSpace(int len, int available); + + boolean isLengthExceedingBlockSize(int len, int size); + } + + private class BufferedAADProcessor + implements AADProcessingBuffer + { + public void processAADByte(byte input) + { + if (m_aadPos == AADBufferSize) + { + processBufferAAD(m_aad, 0); + m_aadPos = 0; + } + m_aad[m_aadPos++] = input; + } + + @Override + public int processByte(byte input, byte[] output, int outOff) + { + checkData(false); + int rlt = processEncDecByte(output, outOff); + m_buf[m_bufPos++] = input; + return rlt; + } + + @Override + public boolean isLengthWithinAvailableSpace(int len, int available) + { + return len <= available; + } + + @Override + public boolean isLengthExceedingBlockSize(int len, int size) + { + return len > size; + } + + @Override + public int getUpdateOutputSize(int len) + { + // The -1 is to account for the lazy processing of a full buffer + return Math.max(0, len) - 1; + } + } + + private class ImmediateAADProcessor + implements AADProcessingBuffer + { + public void processAADByte(byte input) + { + m_aad[m_aadPos++] = input; + if (m_aadPos == AADBufferSize) + { + processBufferAAD(m_aad, 0); + m_aadPos = 0; + } + } + + @Override + public int processByte(byte input, byte[] output, int outOff) + { + checkData(false); + m_buf[m_bufPos++] = input; + return processEncDecByte(output, outOff); + } + + @Override + public int getUpdateOutputSize(int len) + { + return Math.max(0, len); + } + + @Override + public boolean isLengthWithinAvailableSpace(int len, int available) + { + return len < available; + } + + @Override + public boolean isLengthExceedingBlockSize(int len, int size) + { + return len >= size; + } + } + + protected interface AADOperator + { + void processAADByte(byte input); + + void processAADBytes(byte[] input, int inOff, int len); + + void reset(); + + int getLen(); + } + + private class DefaultAADOperator + implements AADOperator + { + @Override + public void processAADByte(byte input) + { + processor.processAADByte(input); + } + + @Override + public void processAADBytes(byte[] input, int inOff, int len) + { + processAadBytes(input, inOff, len); + } + + public void reset() + { + } + + @Override + public int getLen() + { + return m_aadPos; + } + } + + private class CounterAADOperator + implements AADOperator + { + private int aadLen; + + @Override + public void processAADByte(byte input) + { + aadLen++; + processor.processAADByte(input); + } + + @Override + public void processAADBytes(byte[] input, int inOff, int len) + { + aadLen += len; + processAadBytes(input, inOff, len); + } + + public int getLen() + { + return aadLen; + } + + public void reset() + { + aadLen = 0; + } + } + + protected static class StreamAADOperator + implements AADOperator + { + private final ErasableOutputStream stream = new ErasableOutputStream(); + + @Override + public void processAADByte(byte input) + { + stream.write(input); + } + + @Override + public void processAADBytes(byte[] input, int inOff, int len) + { + stream.write(input, inOff, len); + } + + public byte[] getBytes() + { + return stream.getBuf(); + } + + @Override + public void reset() + { + stream.reset(); + } + + @Override + public int getLen() + { + return stream.size(); + } + } + + private class DataLimitAADOperator + implements AADOperator + { + @Override + public void processAADByte(byte input) + { + dataLimitCounter.increment(); + processor.processAADByte(input); + } + + @Override + public void processAADBytes(byte[] input, int inOff, int len) + { + dataLimitCounter.increment(len); + processAadBytes(input, inOff, len); + } + + public void reset() + { + } + + @Override + public int getLen() + { + return m_aadPos; + } + } + + protected interface DataOperator + { + int processByte(byte input, byte[] output, int outOff); + + int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff); + + int getLen(); + + void reset(); + } + + private class DefaultDataOperator + implements DataOperator + { + public int processByte(byte input, byte[] output, int outOff) + { + return processor.processByte(input, output, outOff); + } + + public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) + { + return processEncDecBytes(input, inOff, len, output, outOff); + } + + @Override + public int getLen() + { + return m_bufPos; + } + + @Override + public void reset() + { + } + } + + private class CounterDataOperator + implements DataOperator + { + private int messegeLen; + + public int processByte(byte input, byte[] output, int outOff) + { + messegeLen++; + return processor.processByte(input, output, outOff); + } + + public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) + { + messegeLen += len; + return processEncDecBytes(input, inOff, len, output, outOff); + } + + @Override + public int getLen() + { + return messegeLen; + } + + @Override + public void reset() + { + messegeLen = 0; + } + } + + protected class StreamDataOperator + implements DataOperator + { + private final ErasableOutputStream stream = new ErasableOutputStream(); + + public int processByte(byte input, byte[] output, int outOff) + { + checkData(false); + ensureInitialized(); + stream.write(input); + m_bufPos = stream.size(); + return 0; + } + + @Override + public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) + { + checkData(false); + ensureInitialized(); + stream.write(input, inOff, len); + m_bufPos = stream.size(); + return 0; + } + + public byte[] getBytes() + { + return stream.getBuf(); + } + + @Override + public int getLen() + { + return stream.size(); + } + + @Override + public void reset() + { + stream.reset(); + } + } + + private class StreamCipherOperator + implements DataOperator + { + //TODO: shift index instead of arraycopy + private int len; + + public int processByte(byte input, byte[] output, int outOff) + { + boolean forEncryption = checkData(false); + if (forEncryption) + { + this.len = 1; + processBufferEncrypt(new byte[]{input}, 0, output, outOff); + return 1; + } + else + { + if (m_bufPos == MAC_SIZE) + { + this.len = 1; + processBufferDecrypt(m_buf, 0, output, outOff); + System.arraycopy(m_buf, 1, m_buf, 0, m_bufPos - 1); + m_buf[m_bufPos - 1] = input; + return 1; + } + else + { + m_buf[m_bufPos++] = input; + return 0; + } + } + } + + @Override + public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) + { + if (input == output && Arrays.segmentsOverlap(inOff, len, outOff, processor.getUpdateOutputSize(len))) + { + input = new byte[len]; + System.arraycopy(output, inOff, input, 0, len); + inOff = 0; + } + boolean forEncryption = checkData(false); + if (forEncryption) + { + this.len = len; + processBufferEncrypt(input, inOff, output, outOff); + return len; + } + else + { + // keep last mac size bytes + int available = Math.max(m_bufPos + len - MAC_SIZE, 0); + int rlt = 0; + if (m_bufPos > 0) + { + this.len = Math.min(available, m_bufPos); + rlt = this.len; + processBufferDecrypt(m_buf, 0, output, outOff); + available -= rlt; + m_bufPos -= rlt; + System.arraycopy(m_buf, rlt, m_buf, 0, m_bufPos); + } + if (available > 0) + { + this.len = available; + processBufferDecrypt(input, inOff, output, outOff); + rlt += available; + len -= available; + inOff += available; + } + + System.arraycopy(input, inOff, m_buf, m_bufPos, len); + m_bufPos += len; + return rlt; + } + } + + @Override + public int getLen() + { + return len; + } + + @Override + public void reset() + { + } + } + + private class DataLimitDataOperator + implements DataOperator + { + public int processByte(byte input, byte[] output, int outOff) + { + dataLimitCounter.increment(); + return processor.processByte(input, output, outOff); + } + + public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) + { + dataLimitCounter.increment(len); + return processEncDecBytes(input, inOff, len, output, outOff); + } + + @Override + public int getLen() + { + return m_bufPos; + } + + @Override + public void reset() + { + } + } + + protected static class DecryptionFailureCounter + { + private int n; + private int[] counter; + + public void init(int n) + { + if (this.n != n) + { + this.n = n; + int len = (n + 31) >>> 5; + if (counter == null || len != counter.length) + { + counter = new int[len]; + } + else + { + reset(); + } + } + } + + public boolean increment() + { + int i = counter.length; + while (--i >= 0) + { + if (++counter[i] != 0) + { + break; + } + } + int r = n & 31; + return i <= 0 && counter[0] == (r == 0 ? 0 : (1 << r)); + } + + // In case when we need to use this counter to count data limit +// public boolean increment(int delta) +// { +// // Convert to long to handle unsigned arithmetic +// long carry = delta & 0xFFFFFFFFL; +// // Process each word starting from LSB +// int i = counter.length; +// while (carry != 0 && --i >= 0) +// { +// long sum = (counter[i] & 0xFFFFFFFFL) + carry; +// counter[i] = (int)sum; +// carry = sum >>> 32; +// } +// +// // Final limit check if we didn't overflow +// return carry != 0 || checkLimit(); +// } +// +// private boolean checkLimit() +// { +// int bitIndex = ((n - 1) & 31) + 1; +// long bound = 1L << bitIndex; +// long val = counter[0] & 0xFFFFFFFFL; +// if (val > bound) +// { +// return true; +// } +// if (val < bound) +// { +// return false; +// } +// // Check if we've reached/exceeded 2^n +// for (int i = 1; i < counter.length; ++i) +// { +// val = counter[i] & 0xFFFFFFFFL; +// if (val > 0) +// { +// return true; +// } +// } +// return true; // Exactly equal to 2^n +// } + + public void reset() + { + Arrays.fill(counter, 0); + } + } + + protected static class DataLimitCounter + { + //if the maximum exceed Long.MAX_VALUE, Improve DecryptionFailureCounter and use it instead + private long count; + private long max; + private int n; + + public void init(int n) + { + this.n = n; + this.max = 1L << n; + } + + public void increment() + { + if (++count > max) + { + throw new IllegalStateException("Total data limit exceeded: maximum 2^" + n + " bytes per key (including nonce, AAD, and message)"); + } + } + + public void increment(int n) + { + count += n; + if (count > max) + { + throw new IllegalStateException("Total data limit exceeded: maximum 2^" + n + " bytes per key (including nonce, AAD, and message)"); + } + } + + public void reset() + { + count = 0; + } + } + + @Override + public void processAADByte(byte input) + { + checkAAD(); + aadOperator.processAADByte(input); + } + + @Override + public void processAADBytes(byte[] input, int inOff, int len) + { + ensureSufficientInputBuffer(input, inOff, len); + // Don't enter AAD state until we actually get input + if (len <= 0) + { + return; + } + + checkAAD(); + aadOperator.processAADBytes(input, inOff, len); + } + + private void processAadBytes(byte[] input, int inOff, int len) + { + if (m_aadPos > 0) + { + int available = AADBufferSize - m_aadPos; + if (processor.isLengthWithinAvailableSpace(len, available)) + { + System.arraycopy(input, inOff, m_aad, m_aadPos, len); + m_aadPos += len; + return; + } + + System.arraycopy(input, inOff, m_aad, m_aadPos, available); + inOff += available; + len -= available; + + processBufferAAD(m_aad, 0); + } + while (processor.isLengthExceedingBlockSize(len, AADBufferSize)) + { + processBufferAAD(input, inOff); + inOff += AADBufferSize; + len -= AADBufferSize; + } + System.arraycopy(input, inOff, m_aad, 0, len); + m_aadPos = len; + } + + @Override + public int processByte(byte in, byte[] out, int outOff) + throws DataLengthException + { + return dataOperator.processByte(in, out, outOff); + } + + protected int processEncDecByte(byte[] output, int outOff) + { + int rlt = 0; + int available = (forEncryption ? BlockSize : m_bufferSizeDecrypt) - m_bufPos; + if (available == 0) + { + ensureSufficientOutputBuffer(output, outOff, BlockSize); + if (forEncryption) + { + processBufferEncrypt(m_buf, 0, output, outOff); + } + else + { + processBufferDecrypt(m_buf, 0, output, outOff); + System.arraycopy(m_buf, BlockSize, m_buf, 0, m_bufPos - BlockSize); + } + m_bufPos -= BlockSize; + rlt = BlockSize; + } + return rlt; + } + + @Override + public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) + throws DataLengthException + { + ensureSufficientInputBuffer(input, inOff, len); + return dataOperator.processBytes(input, inOff, len, output, outOff); + } + + protected int processEncDecBytes(byte[] input, int inOff, int len, byte[] output, int outOff) + { + boolean forEncryption = checkData(false); + int available, resultLength; + available = (forEncryption ? BlockSize : m_bufferSizeDecrypt) - m_bufPos; + // The function is just an operator < or <= + if (processor.isLengthWithinAvailableSpace(len, available)) + { + System.arraycopy(input, inOff, m_buf, m_bufPos, len); + m_bufPos += len; + return 0; + } + int length = processor.getUpdateOutputSize(len); + resultLength = length + m_bufPos - (forEncryption ? 0 : MAC_SIZE); + ensureSufficientOutputBuffer(output, outOff, resultLength - resultLength % BlockSize); + resultLength = 0; + if (input == output && Arrays.segmentsOverlap(inOff, len, outOff, length)) + { + input = new byte[len]; + System.arraycopy(output, inOff, input, 0, len); + inOff = 0; + } + if (forEncryption) + { + if (m_bufPos > 0) + { + System.arraycopy(input, inOff, m_buf, m_bufPos, available); + inOff += available; + len -= available; + processBufferEncrypt(m_buf, 0, output, outOff); + resultLength = BlockSize; + } + + // The function is just an operator >= or > + while (processor.isLengthExceedingBlockSize(len, BlockSize)) + { + processBufferEncrypt(input, inOff, output, outOff + resultLength); + inOff += BlockSize; + len -= BlockSize; + resultLength += BlockSize; + } + } + else + { + // loop will run more than once for the following situation: pb128, ascon80pq, ascon128, ISAP_A_128(A) + while (processor.isLengthExceedingBlockSize(m_bufPos, BlockSize) + && processor.isLengthExceedingBlockSize(len + m_bufPos, m_bufferSizeDecrypt)) + { + processBufferDecrypt(m_buf, resultLength, output, outOff + resultLength); + m_bufPos -= BlockSize; + resultLength += BlockSize; + } + if (m_bufPos > 0) + { + System.arraycopy(m_buf, resultLength, m_buf, 0, m_bufPos); + if (processor.isLengthWithinAvailableSpace(m_bufPos + len, m_bufferSizeDecrypt)) + { + System.arraycopy(input, inOff, m_buf, m_bufPos, len); + m_bufPos += len; + return resultLength; + } + available = Math.max(BlockSize - m_bufPos, 0); + System.arraycopy(input, inOff, m_buf, m_bufPos, available); + inOff += available; + len -= available; + processBufferDecrypt(m_buf, 0, output, outOff + resultLength); + resultLength += BlockSize; + } + while (processor.isLengthExceedingBlockSize(len, m_bufferSizeDecrypt)) + { + processBufferDecrypt(input, inOff, output, outOff + resultLength); + inOff += BlockSize; + len -= BlockSize; + resultLength += BlockSize; + } + } + System.arraycopy(input, inOff, m_buf, 0, len); + m_bufPos = len; + return resultLength; + } + + @Override + public int doFinal(byte[] output, int outOff) + throws IllegalStateException, InvalidCipherTextException + { + boolean forEncryption = checkData(true); + int resultLength; + if (forEncryption) + { + resultLength = m_bufPos + MAC_SIZE; + } + else + { + if (m_bufPos < MAC_SIZE) + { + throw new InvalidCipherTextException("data too short"); + } + + m_bufPos -= MAC_SIZE; + + resultLength = m_bufPos; + } + + ensureSufficientOutputBuffer(output, outOff, resultLength); + mac = new byte[MAC_SIZE]; + processFinalBlock(output, outOff); + if (forEncryption) + { + System.arraycopy(mac, 0, output, outOff + resultLength - MAC_SIZE, MAC_SIZE); + } + else + { + if (!Arrays.constantTimeAreEqual(MAC_SIZE, mac, 0, m_buf, m_bufPos)) + { + if (decryptionFailureCounter != null && decryptionFailureCounter.increment()) + { + throw new InvalidCipherTextException(algorithmName + " decryption failure limit exceeded"); + } + throw new InvalidCipherTextException(algorithmName + " mac does not match"); + } + } + reset(!forEncryption); + return resultLength; + } + + public final int getBlockSize() + { + return BlockSize; + } + + public int getUpdateOutputSize(int len) + { + int total = getTotalBytesForUpdate(len); + return total - total % BlockSize; + } + + protected int getTotalBytesForUpdate(int len) + { + int total = processor.getUpdateOutputSize(len); + switch (m_state.ord) + { + case State.DEC_INIT: + case State.DEC_AAD: + case State.DEC_DATA: + case State.DEC_FINAL: + total = Math.max(0, total + m_bufPos - MAC_SIZE); + break; + case State.ENC_DATA: + case State.ENC_FINAL: + total = Math.max(0, total + m_bufPos); + break; + default: + break; + } + return total; + } + + public int getOutputSize(int len) + { + int total = Math.max(0, len); + + switch (m_state.ord) + { + case State.DEC_INIT: + case State.DEC_AAD: + case State.DEC_DATA: + case State.DEC_FINAL: + return Math.max(0, total + m_bufPos - MAC_SIZE); + case State.ENC_DATA: + case State.ENC_FINAL: + return total + m_bufPos + MAC_SIZE; + default: + return total + MAC_SIZE; + } + } + + protected void checkAAD() + { + switch (m_state.ord) + { + case State.DEC_INIT: + m_state = State.DecAad; + break; + case State.ENC_INIT: + m_state = State.EncAad; + break; + case State.DEC_AAD: + case State.ENC_AAD: + break; + case State.ENC_FINAL: + throw new IllegalStateException(getAlgorithmName() + " cannot be reused for encryption"); + default: + throw new IllegalStateException(getAlgorithmName() + " needs to be initialized"); + } + } + + protected boolean checkData(boolean isDoFinal) + { + switch (m_state.ord) + { + case State.DEC_INIT: + case State.DEC_AAD: + finishAAD(State.DecData, isDoFinal); + return false; + case State.ENC_INIT: + case State.ENC_AAD: + finishAAD(State.EncData, isDoFinal); + return true; + case State.DEC_DATA: + return false; + case State.ENC_DATA: + return true; + case State.ENC_FINAL: + throw new IllegalStateException(getAlgorithmName() + " cannot be reused for encryption"); + default: + throw new IllegalStateException(getAlgorithmName() + " needs to be initialized"); + } + } + + protected final void ensureSufficientOutputBuffer(byte[] output, int outOff, int len) + { + if (outOff + len > output.length) + { + throw new OutputLengthException("output buffer too short"); + } + } + + protected final void ensureSufficientInputBuffer(byte[] input, int inOff, int len) + { + if (inOff + len > input.length) + { + throw new DataLengthException("input buffer too short"); + } + } + + protected final void ensureInitialized() + { + if (m_state == State.Uninitialized) + { + throw new IllegalStateException("Need to call init function before operation"); + } + } + + // Used for Grain128 AEAD and Romulus Engine + protected void finishAAD1(State nextState) + { + switch (m_state.ord) + { + case State.DEC_INIT: + case State.DEC_AAD: + case State.ENC_INIT: + case State.ENC_AAD: + { + processFinalAAD(); + break; + } + default: + break; + } + m_state = nextState; + } + + // Use for Elephant and Sparkle + protected void finishAAD2(State nextState) + { + // State indicates whether we ever received AAD + switch (m_state.ord) + { + case State.DEC_AAD: + case State.ENC_AAD: + { + processFinalAAD(); + break; + } + default: + break; + } + + m_aadPos = 0; + m_state = nextState; + } + + // Used for Gift-Cofb, ISAP, PhotonBeetle and Xoodyak + protected void finishAAD3(State nextState, boolean isDoFinal) + { + // State indicates whether we ever received AAD + switch (m_state.ord) + { + case State.DEC_INIT: + case State.DEC_AAD: + if (!isDoFinal && dataOperator.getLen() <= MAC_SIZE) + { + return; + } + case State.ENC_INIT: + case State.ENC_AAD: + processFinalAAD(); + break; + } + + m_aadPos = 0; + m_state = nextState; + } + + protected abstract void finishAAD(State nextState, boolean isDoFinal); + + protected abstract void init(byte[] key, byte[] iv); + + protected abstract void processFinalBlock(byte[] output, int outOff); + + protected abstract void processBufferAAD(byte[] input, int inOff); + + protected abstract void processFinalAAD(); + + protected abstract void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff); + + protected abstract void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff); + + protected static final class ErasableOutputStream + extends ByteArrayOutputStream + { + public ErasableOutputStream() + { + } + + public byte[] getBuf() + { + return buf; + } } } diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java deleted file mode 100644 index ed2e40ec19..0000000000 --- a/core/src/main/java/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java +++ /dev/null @@ -1,403 +0,0 @@ -package org.bouncycastle.crypto.engines; - -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.OutputLengthException; -import org.bouncycastle.util.Arrays; - -abstract class AEADBufferBaseEngine - extends AEADBaseEngine -{ - protected enum State - { - Uninitialized, - EncInit, - EncAad, - EncData, - EncFinal, - DecInit, - DecAad, - DecData, - DecFinal, - } - - protected byte[] m_buf; - protected byte[] m_aad; - protected int m_bufPos; - protected int m_aadPos; - protected boolean aadFinished; - protected boolean initialised = false; - protected int AADBufferSize; - protected int BlockSize; - protected State m_state = State.Uninitialized; - - @Override - public void processAADByte(byte input) - { - checkAAD(); - if (m_aadPos == AADBufferSize) - { - processBufferAAD(m_aad, 0); - m_aadPos = 0; - } - m_aad[m_aadPos++] = input; - } - - @Override - public void processAADBytes(byte[] input, int inOff, int len) - { - if ((inOff + len) > input.length) - { - throw new DataLengthException("input buffer too short"); - } - // Don't enter AAD state until we actually get input - if (len <= 0) - { - return; - } - - checkAAD(); - if (m_aadPos > 0) - { - int available = AADBufferSize - m_aadPos; - if (len <= available) - { - System.arraycopy(input, inOff, m_aad, m_aadPos, len); - m_aadPos += len; - return; - } - - System.arraycopy(input, inOff, m_aad, m_aadPos, available); - inOff += available; - len -= available; - - processBufferAAD(m_aad, 0); - m_aadPos = 0; - } - while (len > AADBufferSize) - { - processBufferAAD(input, inOff); - inOff += AADBufferSize; - len -= AADBufferSize; - } - System.arraycopy(input, inOff, m_aad, m_aadPos, len); - m_aadPos += len; - } - - @Override - public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) - throws DataLengthException - { - if (inOff + len > input.length) - { - throw new DataLengthException("input buffer too short"); - } - - boolean forEncryption = checkData(); - - int resultLength = 0; - - if (forEncryption) - { - if (m_bufPos > 0) - { - int available = BlockSize - m_bufPos; - if (len <= available) - { - System.arraycopy(input, inOff, m_buf, m_bufPos, len); - m_bufPos += len; - return 0; - } - - System.arraycopy(input, inOff, m_buf, m_bufPos, available); - inOff += available; - len -= available; - - validateAndProcessBuffer(m_buf, 0, output, outOff); - resultLength = BlockSize; - //m_bufPos = 0; - } - - while (len > BlockSize) - { - validateAndProcessBuffer(input, inOff, output, outOff + resultLength); - inOff += BlockSize; - len -= BlockSize; - resultLength += BlockSize; - } - } - else - { - int available = BlockSize + MAC_SIZE - m_bufPos; - if (len <= available) - { - System.arraycopy(input, inOff, m_buf, m_bufPos, len); - m_bufPos += len; - return 0; - } - if (BlockSize >= MAC_SIZE) - { - if (m_bufPos > BlockSize) - { - validateAndProcessBuffer(m_buf, 0, output, outOff); - m_bufPos -= BlockSize; - System.arraycopy(m_buf, BlockSize, m_buf, 0, m_bufPos); - resultLength = BlockSize; - - available += BlockSize; - if (len <= available) - { - System.arraycopy(input, inOff, m_buf, m_bufPos, len); - m_bufPos += len; - return resultLength; - } - } - - available = BlockSize - m_bufPos; - System.arraycopy(input, inOff, m_buf, m_bufPos, available); - inOff += available; - len -= available; - validateAndProcessBuffer(m_buf, 0, output, outOff + resultLength); - resultLength += BlockSize; - //m_bufPos = 0; - } - else - { - while (m_bufPos > BlockSize && len + m_bufPos > BlockSize + MAC_SIZE) - { - validateAndProcessBuffer(m_buf, resultLength, output, outOff + resultLength); - m_bufPos -= BlockSize; - resultLength += BlockSize; - } - if (m_bufPos != 0) - { - System.arraycopy(m_buf, resultLength, m_buf, 0, m_bufPos); - if (m_bufPos + len > BlockSize + MAC_SIZE) - { - available = Math.max(BlockSize - m_bufPos, 0); - System.arraycopy(input, inOff, m_buf, m_bufPos, available); - inOff += available; - validateAndProcessBuffer(m_buf, 0, output, outOff + resultLength); - resultLength += BlockSize; - len -= available; - } - else - { - System.arraycopy(input, inOff, m_buf, m_bufPos, len); - m_bufPos += len; - return resultLength; - } - } - } - while (len > BlockSize + MAC_SIZE) - { - validateAndProcessBuffer(input, inOff, output, outOff + resultLength); - inOff += BlockSize; - len -= BlockSize; - resultLength += BlockSize; - } - } - - System.arraycopy(input, inOff, m_buf, 0, len); - m_bufPos = len; - - return resultLength; - } - - @Override - public int doFinal(byte[] output, int outOff) - throws IllegalStateException, InvalidCipherTextException - { - boolean forEncryption = checkData(); - int resultLength; - if (forEncryption) - { - resultLength = m_bufPos + MAC_SIZE; - } - else - { - if (m_bufPos < MAC_SIZE) - { - throw new InvalidCipherTextException("data too short"); - } - - m_bufPos -= MAC_SIZE; - - resultLength = m_bufPos; - } - - if (outOff > output.length - resultLength) - { - throw new OutputLengthException("output buffer too short"); - } - processFinalBlock(output, outOff); - if (forEncryption) - { - System.arraycopy(mac, 0, output, outOff + resultLength - MAC_SIZE, MAC_SIZE); - } - else - { - if (!Arrays.constantTimeAreEqual(MAC_SIZE, mac, 0, m_buf, m_bufPos)) - { - throw new InvalidCipherTextException(algorithmName + " mac does not match"); - } - } - reset(!forEncryption); - return resultLength; - } - - public int getBlockSize() - { - return BlockSize; - } - - public int getUpdateOutputSize(int len) - { - // The -1 is to account for the lazy processing of a full buffer - int total = Math.max(0, len) - 1; - - switch (m_state) - { - case DecInit: - case DecAad: - total = Math.max(0, total - MAC_SIZE); - break; - case DecData: - case DecFinal: - total = Math.max(0, total + m_bufPos - MAC_SIZE); - break; - case EncData: - case EncFinal: - total = Math.max(0, total + m_bufPos); - break; - default: - break; - } - return total - total % BlockSize; - } - - public int getOutputSize(int len) - { - int total = Math.max(0, len); - - switch (m_state) - { - case DecInit: - case DecAad: - return Math.max(0, total - MAC_SIZE); - case DecData: - case DecFinal: - return Math.max(0, total + m_bufPos - MAC_SIZE); - case EncData: - case EncFinal: - return total + m_bufPos + MAC_SIZE; - default: - return total + MAC_SIZE; - } - } - - protected void checkAAD() - { - switch (m_state) - { - case DecInit: - m_state = State.DecAad; - break; - case EncInit: - m_state = State.EncAad; - break; - case DecAad: - case EncAad: - break; - case EncFinal: - throw new IllegalStateException(getAlgorithmName() + " cannot be reused for encryption"); - default: - throw new IllegalStateException(getAlgorithmName() + " needs to be initialized"); - } - } - - protected boolean checkData() - { - switch (m_state) - { - case DecInit: - case DecAad: - finishAAD(State.DecData); - return false; - case EncInit: - case EncAad: - finishAAD(State.EncData); - return true; - case DecData: - return false; - case EncData: - return true; - case EncFinal: - throw new IllegalStateException(getAlgorithmName() + " cannot be reused for encryption"); - default: - throw new IllegalStateException(getAlgorithmName() + " needs to be initialized"); - } - } - - private void finishAAD(State nextState) - { - // State indicates whether we ever received AAD - switch (m_state) - { - case DecAad: - case EncAad: - { - processFinalAAD(); - break; - } - default: - break; - } - - m_aadPos = 0; - m_state = nextState; - } - - protected void bufferReset() - { - Arrays.fill(m_buf, (byte)0); - Arrays.fill(m_aad, (byte)0); - m_bufPos = 0; - m_aadPos = 0; - switch (m_state) - { - case DecInit: - case EncInit: - break; - case DecAad: - case DecData: - case DecFinal: - m_state = State.DecInit; - break; - case EncAad: - case EncData: - case EncFinal: - m_state = State.EncFinal; - return; - default: - throw new IllegalStateException(getAlgorithmName() + " needs to be initialized"); - } - } - - protected void validateAndProcessBuffer(byte[] input, int inOff, byte[] output, int outOff) - { - if (outOff > output.length - BlockSize) - { - throw new OutputLengthException("output buffer too short"); - } - processBuffer(input, inOff, output, outOff); - } - - protected abstract void processFinalBlock(byte[] output, int outOff); - - protected abstract void processBufferAAD(byte[] input, int inOff); - - protected abstract void processFinalAAD(); - - protected abstract void processBuffer(byte[] input, int inOff, byte[] output, int outOff); -} diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java index ac2eb9aa6a..9e200318f4 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/AESEngine.java @@ -435,6 +435,7 @@ public static MultiBlockCipher newInstance() * default constructor - 128 bit block size. * @deprecated use AESEngine.newInstance() */ + @Deprecated public AESEngine() { CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties(getAlgorithmName(), 256)); diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AsconAEAD128.java b/core/src/main/java/org/bouncycastle/crypto/engines/AsconAEAD128.java index 7c32bd12eb..947dee7ce5 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/AsconAEAD128.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/AsconAEAD128.java @@ -4,15 +4,15 @@ import org.bouncycastle.util.Pack; /** - * Ascon-AEAD128 was introduced as part of the NIST Lightweight Cryptography - * competition and described in the NIST Special Publication SP 800-232 (Initial - * Public Draft). - * For additional details, see: - * + * Ascon-AEAD128 was introduced in NIST Special Publication (SP) 800-232 + *

    + * Additional details and the specification can be found in: + * NIST SP 800-232 + * Ascon-Based Lightweight Cryptography Standards for Constrained Devices. + * For reference source code and implementation details, please see: + * Reference, highly optimized, masked C and + * ASM implementations of Ascon (NIST SP 800-232). + *

    * * @version 1.3 */ @@ -21,16 +21,15 @@ public class AsconAEAD128 { public AsconAEAD128() { - KEY_SIZE = 16; - IV_SIZE = 16; - MAC_SIZE = 16; - ASCON_AEAD_RATE = 16; + KEY_SIZE = IV_SIZE = MAC_SIZE = AADBufferSize = BlockSize = 16; ASCON_IV = 0x00001000808c0001L; algorithmName = "Ascon-AEAD128"; nr = 8; - m_bufferSizeDecrypt = ASCON_AEAD_RATE + MAC_SIZE; - m_buf = new byte[m_bufferSizeDecrypt]; dsep = -9223372036854775808L; //0x80L << 56 + macSizeLowerBound = 4; + setInnerMembers(ProcessingBufferType.Immediate, AADOperatorType.DataLimit, DataOperatorType.DataLimit); + dataLimitCounter.init(54); + decryptionFailureCounter = new DecryptionFailureCounter(); } protected long pad(int i) @@ -53,27 +52,30 @@ protected void setBytes(long n, byte[] bs, int off) protected void ascon_aeadinit() { /* initialize */ - x0 = ASCON_IV; - x1 = K0; - x2 = K1; - x3 = N0; - x4 = N1; - p(12); - x3 ^= K0; - x4 ^= K1; + p.set(ASCON_IV, K0, K1, N0, N1); + p.p(12); + p.x3 ^= K0; + p.x4 ^= K1; } - protected void processFinalAadBlock() + protected void processFinalAAD() { - Arrays.fill(m_buf, m_bufPos, m_buf.length, (byte) 0); - if (m_bufPos >= 8) // ASCON_AEAD_RATE == 16 is implied + if (m_aadPos == BlockSize) { - x0 ^= Pack.littleEndianToLong(m_buf, 0); - x1 ^= Pack.littleEndianToLong(m_buf, 8) ^ pad(m_bufPos); + p.x0 ^= loadBytes(m_aad, 0); + p.x1 ^= loadBytes(m_aad, 8); + m_aadPos -= BlockSize; + p.p(nr); + } + Arrays.fill(m_aad, m_aadPos, AADBufferSize, (byte)0); + if (m_aadPos >= 8) // ASCON_AEAD_RATE == 16 is implied + { + p.x0 ^= Pack.littleEndianToLong(m_aad, 0); + p.x1 ^= Pack.littleEndianToLong(m_aad, 8) ^ pad(m_aadPos); } else { - x0 ^= Pack.littleEndianToLong(m_buf, 0) ^ pad(m_bufPos); + p.x0 ^= Pack.littleEndianToLong(m_aad, 0) ^ pad(m_aadPos); } } @@ -83,24 +85,28 @@ protected void processFinalDecrypt(byte[] input, int inLen, byte[] output, int o { long c0 = Pack.littleEndianToLong(input, 0); inLen -= 8; - long c1 = Pack.littleEndianToLong(input, 8, inLen); - Pack.longToLittleEndian(x0 ^ c0, output, outOff); - Pack.longToLittleEndian(x1 ^ c1, output, outOff + 8, inLen); - x0 = c0; - x1 &= -(1L << (inLen << 3)); - x1 |= c1; - x1 ^= pad(inLen); + Pack.longToLittleEndian(p.x0 ^ c0, output, outOff); + p.x0 = c0; + + if (inLen > 0) + { + long c1 = Pack.littleEndianToLong_Low(input, 8, inLen); + Pack.longToLittleEndian_Low(p.x1 ^ c1, output, outOff + 8, inLen); + p.x1 &= -(1L << (inLen << 3)); + p.x1 |= c1; + } + p.x1 ^= pad(inLen); } else { - if (inLen != 0) + if (inLen > 0) { - long c0 = Pack.littleEndianToLong(input, 0, inLen); - Pack.longToLittleEndian(x0 ^ c0, output, outOff, inLen); - x0 &= -(1L << (inLen << 3)); - x0 |= c0; + long c0 = Pack.littleEndianToLong_Low(input, 0, inLen); + Pack.longToLittleEndian_Low(p.x0 ^ c0, output, outOff, inLen); + p.x0 &= -(1L << (inLen << 3)); + p.x0 |= c0; } - x0 ^= pad(inLen); + p.x0 ^= pad(inLen); } finishData(State.DecFinal); } @@ -109,51 +115,59 @@ protected void processFinalEncrypt(byte[] input, int inLen, byte[] output, int o { if (inLen >= 8) // ASCON_AEAD_RATE == 16 is implied { - x0 ^= Pack.littleEndianToLong(input, 0); + p.x0 ^= Pack.littleEndianToLong(input, 0); inLen -= 8; - x1 ^= Pack.littleEndianToLong(input, 8, inLen); - Pack.longToLittleEndian(x0, output, outOff); - Pack.longToLittleEndian(x1, output, outOff + 8); - x1 ^= pad(inLen); + Pack.longToLittleEndian(p.x0, output, outOff); + + if (inLen > 0) + { + p.x1 ^= Pack.littleEndianToLong_Low(input, 8, inLen); + Pack.longToLittleEndian_Low(p.x1, output, outOff + 8, inLen); + } + p.x1 ^= pad(inLen); } else { - if (inLen != 0) + if (inLen > 0) { - x0 ^= Pack.littleEndianToLong(input, 0, inLen); - Pack.longToLittleEndian(x0, output, outOff, inLen); + p.x0 ^= Pack.littleEndianToLong_Low(input, 0, inLen); + Pack.longToLittleEndian_Low(p.x0, output, outOff, inLen); } - x0 ^= pad(inLen); + p.x0 ^= pad(inLen); } finishData(State.EncFinal); } private void finishData(State nextState) { - x2 ^= K0; - x3 ^= K1; - p(12); - x3 ^= K0; - x4 ^= K1; + p.x2 ^= K0; + p.x3 ^= K1; + p.p(12); + p.x3 ^= K0; + p.x4 ^= K1; m_state = nextState; } protected void init(byte[] key, byte[] iv) throws IllegalArgumentException { - K0 = Pack.littleEndianToLong(key, 0); - K1 = Pack.littleEndianToLong(key, 8); + int lambda = (MAC_SIZE << 3) - 32; + long K0 = Pack.littleEndianToLong(key, 0); + long K1 = Pack.littleEndianToLong(key, 8); + decryptionFailureCounter.init(lambda); + if (this.K0 != K0 || this.K1 != K1) + { + dataLimitCounter.reset(); + decryptionFailureCounter.reset(); + this.K0 = K0; + this.K1 = K1; + } N0 = Pack.littleEndianToLong(iv, 0); N1 = Pack.littleEndianToLong(iv, 8); - - m_state = forEncryption ? State.EncInit : State.DecInit; - - reset(true); } public String getAlgorithmVersion() { return "v1.3"; } -} - +} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AsconBaseEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AsconBaseEngine.java index 37832c9af8..6f4792c428 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/AsconBaseEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/AsconBaseEngine.java @@ -1,44 +1,15 @@ package org.bouncycastle.crypto.engines; -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.OutputLengthException; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Longs; - abstract class AsconBaseEngine extends AEADBaseEngine { - protected enum State - { - Uninitialized, - EncInit, - EncAad, - EncData, - EncFinal, - DecInit, - DecAad, - DecData, - DecFinal, - } - - - protected State m_state = State.Uninitialized; protected int nr; - protected int ASCON_AEAD_RATE; protected long K0; protected long K1; protected long N0; protected long N1; protected long ASCON_IV; - protected long x0; - protected long x1; - protected long x2; - protected long x3; - protected long x4; - protected int m_bufferSizeDecrypt; - protected byte[] m_buf; - protected int m_bufPos = 0; + AsconPermutationFriend.AsconPermutation p = new AsconPermutationFriend.AsconPermutation(); protected long dsep; //domain separation protected abstract long pad(int i); @@ -47,408 +18,88 @@ protected enum State protected abstract void setBytes(long n, byte[] bs, int off); - private void round(long C) - { - long t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C)); - long t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3)); - long t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4); - long t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4)); - long t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1); - x0 = t0 ^ Longs.rotateRight(t0, 19) ^ Longs.rotateRight(t0, 28); - x1 = t1 ^ Longs.rotateRight(t1, 39) ^ Longs.rotateRight(t1, 61); - x2 = ~(t2 ^ Longs.rotateRight(t2, 1) ^ Longs.rotateRight(t2, 6)); - x3 = t3 ^ Longs.rotateRight(t3, 10) ^ Longs.rotateRight(t3, 17); - x4 = t4 ^ Longs.rotateRight(t4, 7) ^ Longs.rotateRight(t4, 41); - } - - protected void p(int nr) - { - if (nr == 12) - { - round(0xf0L); - round(0xe1L); - round(0xd2L); - round(0xc3L); - } - if (nr >= 8) - { - round(0xb4L); - round(0xa5L); - } - round(0x96L); - round(0x87L); - round(0x78L); - round(0x69L); - round(0x5aL); - round(0x4bL); - } - protected abstract void ascon_aeadinit(); - protected void checkAAD() - { - switch (m_state) - { - case DecInit: - m_state = State.DecAad; - break; - case EncInit: - m_state = State.EncAad; - break; - case DecAad: - case EncAad: - break; - case EncFinal: - throw new IllegalStateException(getAlgorithmName() + " cannot be reused for encryption"); - default: - throw new IllegalStateException(getAlgorithmName() + " needs to be initialized"); - } - } - - protected boolean checkData() - { - switch (m_state) - { - case DecInit: - case DecAad: - finishAAD(State.DecData); - return false; - case EncInit: - case EncAad: - finishAAD(State.EncData); - return true; - case DecData: - return false; - case EncData: - return true; - case EncFinal: - throw new IllegalStateException(getAlgorithmName() + " cannot be reused for encryption"); - default: - throw new IllegalStateException(getAlgorithmName() + " needs to be initialized"); - } - } - - private void finishAAD(State nextState) + protected void finishAAD(State nextState, boolean isDofinal) { // State indicates whether we ever received AAD - switch (m_state) + switch (m_state.ord) { - case DecAad: - case EncAad: - processFinalAadBlock(); - p(nr); + case State.DEC_AAD: + case State.ENC_AAD: + this.processFinalAAD(); + p.p(nr); break; default: break; } // domain separation - x4 ^= dsep; - m_bufPos = 0; + p.x4 ^= dsep; + m_aadPos = 0; m_state = nextState; } - protected abstract void processFinalAadBlock(); - protected abstract void processFinalDecrypt(byte[] input, int inLen, byte[] output, int outOff); protected abstract void processFinalEncrypt(byte[] input, int inLen, byte[] output, int outOff); protected void processBufferAAD(byte[] buffer, int inOff) { - x0 ^= loadBytes(buffer, inOff); - if (ASCON_AEAD_RATE == 16) + p.x0 ^= loadBytes(buffer, inOff); + if (BlockSize == 16) { - x1 ^= loadBytes(buffer, 8 + inOff); + p.x1 ^= loadBytes(buffer, 8 + inOff); } - p(nr); + p.p(nr); } - - protected void processBufferDecrypt(byte[] buffer, int bufOff, byte[] output, int outOff) + @Override + protected void processFinalBlock(byte[] output, int outOff) { - if (outOff + ASCON_AEAD_RATE > output.length) - { - throw new OutputLengthException("output buffer too short"); - } - long t0 = loadBytes(buffer, bufOff); - setBytes(x0 ^ t0, output, outOff); - x0 = t0; - - if (ASCON_AEAD_RATE == 16) - { - long t1 = loadBytes(buffer, bufOff + 8); - setBytes(x1 ^ t1, output, outOff + 8); - x1 = t1; - } - p(nr); - } - - protected void processBufferEncrypt(byte[] buffer, int bufOff, byte[] output, int outOff) - { - if (outOff + ASCON_AEAD_RATE > output.length) - { - throw new OutputLengthException("output buffer too short"); - } - x0 ^= loadBytes(buffer, bufOff); - setBytes(x0, output, outOff); - - if (ASCON_AEAD_RATE == 16) - { - x1 ^= loadBytes(buffer, bufOff + 8); - setBytes(x1, output, outOff + 8); - } - p(nr); - } - - public void processAADByte(byte in) - { - checkAAD(); - m_buf[m_bufPos] = in; - if (++m_bufPos == ASCON_AEAD_RATE) - { - processBufferAAD(m_buf, 0); - m_bufPos = 0; - } - } - - public void processAADBytes(byte[] inBytes, int inOff, int len) - { - if ((inOff + len) > inBytes.length) - { - throw new DataLengthException("input buffer too short"); - } - // Don't enter AAD state until we actually get input - if (len <= 0) - { - return; - } - checkAAD(); - if (m_bufPos > 0) - { - int available = ASCON_AEAD_RATE - m_bufPos; - if (len < available) - { - System.arraycopy(inBytes, inOff, m_buf, m_bufPos, len); - m_bufPos += len; - return; - } - System.arraycopy(inBytes, inOff, m_buf, m_bufPos, available); - inOff += available; - len -= available; - processBufferAAD(m_buf, 0); - //m_bufPos = 0; - } - while (len >= ASCON_AEAD_RATE) - { - processBufferAAD(inBytes, inOff); - inOff += ASCON_AEAD_RATE; - len -= ASCON_AEAD_RATE; - } - System.arraycopy(inBytes, inOff, m_buf, 0, len); - m_bufPos = len; - } - - public int processBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff) - throws DataLengthException - { - if ((inOff + len) > inBytes.length) - { - throw new DataLengthException("input buffer too short"); - } - boolean forEncryption = checkData(); - int resultLength = 0; - if (forEncryption) { - if (m_bufPos > 0) - { - int available = ASCON_AEAD_RATE - m_bufPos; - if (len < available) - { - System.arraycopy(inBytes, inOff, m_buf, m_bufPos, len); - m_bufPos += len; - return 0; - } - - System.arraycopy(inBytes, inOff, m_buf, m_bufPos, available); - inOff += available; - len -= available; - - processBufferEncrypt(m_buf, 0, outBytes, outOff); - resultLength = ASCON_AEAD_RATE; - //m_bufPos = 0; - } - - while (len >= ASCON_AEAD_RATE) - { - processBufferEncrypt(inBytes, inOff, outBytes, outOff + resultLength); - inOff += ASCON_AEAD_RATE; - len -= ASCON_AEAD_RATE; - resultLength += ASCON_AEAD_RATE; - } + processFinalEncrypt(m_buf, m_bufPos, output, outOff); } else { - int available = m_bufferSizeDecrypt - m_bufPos; - if (len < available) - { - System.arraycopy(inBytes, inOff, m_buf, m_bufPos, len); - m_bufPos += len; - return 0; - } - - // NOTE: Need 'while' here because ASCON_AEAD_RATE < CRYPTO_ABYTES in some parameter sets - while (m_bufPos >= ASCON_AEAD_RATE) - { - processBufferDecrypt(m_buf, 0, outBytes, outOff + resultLength); - m_bufPos -= ASCON_AEAD_RATE; - System.arraycopy(m_buf, ASCON_AEAD_RATE, m_buf, 0, m_bufPos); - resultLength += ASCON_AEAD_RATE; - - available += ASCON_AEAD_RATE; - if (len < available) - { - System.arraycopy(inBytes, inOff, m_buf, m_bufPos, len); - m_bufPos += len; - return resultLength; - } - } - - available = ASCON_AEAD_RATE - m_bufPos; - System.arraycopy(inBytes, inOff, m_buf, m_bufPos, available); - inOff += available; - len -= available; - processBufferDecrypt(m_buf, 0, outBytes, outOff + resultLength); - resultLength += ASCON_AEAD_RATE; - //m_bufPos = 0; - - while (len >= m_bufferSizeDecrypt) - { - processBufferDecrypt(inBytes, inOff, outBytes, outOff + resultLength); - inOff += ASCON_AEAD_RATE; - len -= ASCON_AEAD_RATE; - resultLength += ASCON_AEAD_RATE; - } + processFinalDecrypt(m_buf, m_bufPos, output, outOff); } - - System.arraycopy(inBytes, inOff, m_buf, 0, len); - m_bufPos = len; - - return resultLength; + setBytes(p.x3, mac, 0); + setBytes(p.x4, mac, 8); } - public int doFinal(byte[] outBytes, int outOff) - throws IllegalStateException, InvalidCipherTextException, DataLengthException + protected void processBufferDecrypt(byte[] buffer, int bufOff, byte[] output, int outOff) { - boolean forEncryption = checkData(); - int resultLength; - if (forEncryption) - { - resultLength = m_bufPos + MAC_SIZE; - if (outOff + resultLength > outBytes.length) - { - throw new OutputLengthException("output buffer too short"); - } - processFinalEncrypt(m_buf, m_bufPos, outBytes, outOff); - mac = new byte[MAC_SIZE]; - setBytes(x3, mac, 0); - setBytes(x4, mac, 8); - System.arraycopy(mac, 0, outBytes, outOff + m_bufPos, MAC_SIZE); - reset(false); - } - else - { - if (m_bufPos < MAC_SIZE) - { - throw new InvalidCipherTextException("data too short"); - } - m_bufPos -= MAC_SIZE; - resultLength = m_bufPos; - if (outOff + resultLength > outBytes.length) - { - throw new OutputLengthException("output buffer too short"); - } - processFinalDecrypt(m_buf, m_bufPos, outBytes, outOff); - x3 ^= loadBytes(m_buf, m_bufPos); - x4 ^= loadBytes(m_buf, m_bufPos + 8); - if ((x3 | x4) != 0L) - { - throw new InvalidCipherTextException("mac check in " + getAlgorithmName() + " failed"); - } - reset(true); - } - return resultLength; - } + long t0 = loadBytes(buffer, bufOff); + setBytes(p.x0 ^ t0, output, outOff); + p.x0 = t0; - public int getUpdateOutputSize(int len) - { - int total = Math.max(0, len); - switch (m_state) + if (BlockSize == 16) { - case DecInit: - case DecAad: - total = Math.max(0, total - MAC_SIZE); - break; - case DecData: - case DecFinal: - total = Math.max(0, total + m_bufPos - MAC_SIZE); - break; - case EncData: - case EncFinal: - total += m_bufPos; - break; - default: - break; + long t1 = loadBytes(buffer, bufOff + 8); + setBytes(p.x1 ^ t1, output, outOff + 8); + p.x1 = t1; } - return total - total % ASCON_AEAD_RATE; + p.p(nr); } - public int getOutputSize(int len) + protected void processBufferEncrypt(byte[] buffer, int bufOff, byte[] output, int outOff) { - int total = Math.max(0, len); + p.x0 ^= loadBytes(buffer, bufOff); + setBytes(p.x0, output, outOff); - switch (m_state) + if (BlockSize == 16) { - case DecInit: - case DecAad: - return Math.max(0, total - MAC_SIZE); - case DecData: - case DecFinal: - return Math.max(0, total + m_bufPos - MAC_SIZE); - case EncData: - case EncFinal: - return total + m_bufPos + MAC_SIZE; - default: - return total + MAC_SIZE; + p.x1 ^= loadBytes(buffer, bufOff + 8); + setBytes(p.x1, output, outOff + 8); } + p.p(nr); } - protected void reset(boolean clearMac) { - Arrays.clear(m_buf); - m_bufPos = 0; - - switch (m_state) - { - case DecInit: - case EncInit: - break; - case DecAad: - case DecData: - case DecFinal: - m_state = State.DecInit; - break; - case EncAad: - case EncData: - case EncFinal: - m_state = State.EncFinal; - return; - default: - throw new IllegalStateException(getAlgorithmName() + " needs to be initialized"); - } - ascon_aeadinit(); super.reset(clearMac); + ascon_aeadinit(); } public abstract String getAlgorithmVersion(); diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java index 17fb2a6a73..ca73c20f82 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/AsconEngine.java @@ -1,6 +1,5 @@ package org.bouncycastle.crypto.engines; -import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.util.Pack; /** @@ -17,6 +16,7 @@ * ASCON C Reference Implementation (NIST Round 2) * . *

    + * * @deprecated Now superseded. Please refer to {@code AsconAEAD128Engine} for future implementations. */ @@ -36,35 +36,34 @@ public enum AsconParameters public AsconEngine(AsconParameters asconParameters) { this.asconParameters = asconParameters; - IV_SIZE = 16; - MAC_SIZE = 16; + IV_SIZE = MAC_SIZE = 16; switch (asconParameters) { case ascon80pq: KEY_SIZE = 20; - ASCON_AEAD_RATE = 8; + BlockSize = 8; ASCON_IV = 0xa0400c0600000000L; algorithmName = "Ascon-80pq AEAD"; break; case ascon128a: KEY_SIZE = 16; - ASCON_AEAD_RATE = 16; + BlockSize = 16; ASCON_IV = 0x80800c0800000000L; algorithmName = "Ascon-128a AEAD"; break; case ascon128: KEY_SIZE = 16; - ASCON_AEAD_RATE = 8; + BlockSize = 8; ASCON_IV = 0x80400c0600000000L; algorithmName = "Ascon-128 AEAD"; break; default: throw new IllegalArgumentException("invalid parameter setting for ASCON AEAD"); } - nr = (ASCON_AEAD_RATE == 8) ? 6 : 8; - m_bufferSizeDecrypt = ASCON_AEAD_RATE + MAC_SIZE; - m_buf = new byte[m_bufferSizeDecrypt]; + nr = (BlockSize == 8) ? 6 : 8; + AADBufferSize = BlockSize; dsep = 1L; + setInnerMembers(ProcessingBufferType.Immediate, AADOperatorType.Default, DataOperatorType.Default); } protected long pad(int i) @@ -83,38 +82,35 @@ protected void setBytes(long n, byte[] bs, int off) { Pack.longToBigEndian(n, bs, off); } + protected void ascon_aeadinit() { /* initialize */ - x0 = ASCON_IV; + p.set(ASCON_IV, K1, K2, N0, N1); if (KEY_SIZE == 20) { - x0 ^= K0; + p.x0 ^= K0; } - x1 = K1; - x2 = K2; - x3 = N0; - x4 = N1; - p(12); + p.p(12); if (KEY_SIZE == 20) { - x2 ^= K0; + p.x2 ^= K0; } - x3 ^= K1; - x4 ^= K2; + p.x3 ^= K1; + p.x4 ^= K2; } - protected void processFinalAadBlock() + protected void processFinalAAD() { - m_buf[m_bufPos] = (byte)0x80; - if (m_bufPos >= 8) // ASCON_AEAD_RATE == 16 is implied + m_aad[m_aadPos] = (byte)0x80; + if (m_aadPos >= 8) // ASCON_AEAD_RATE == 16 is implied { - x0 ^= Pack.bigEndianToLong(m_buf, 0); - x1 ^= Pack.bigEndianToLong(m_buf, 8) & (-1L << (56 - ((m_bufPos - 8) << 3))); + p.x0 ^= Pack.bigEndianToLong(m_aad, 0); + p.x1 ^= Pack.bigEndianToLong(m_aad, 8) & (-1L << (56 - ((m_aadPos - 8) << 3))); } else { - x0 ^= Pack.bigEndianToLong(m_buf, 0) & (-1L << (56 - (m_bufPos << 3))); + p.x0 ^= Pack.bigEndianToLong(m_aad, 0) & (-1L << (56 - (m_aadPos << 3))); } } @@ -123,32 +119,32 @@ protected void processFinalDecrypt(byte[] input, int inLen, byte[] output, int o if (inLen >= 8) // ASCON_AEAD_RATE == 16 is implied { long c0 = Pack.bigEndianToLong(input, 0); - x0 ^= c0; - Pack.longToBigEndian(x0, output, outOff); - x0 = c0; + p.x0 ^= c0; + Pack.longToBigEndian(p.x0, output, outOff); + p.x0 = c0; outOff += 8; inLen -= 8; - x1 ^= pad(inLen); - if (inLen != 0) + p.x1 ^= pad(inLen); + if (inLen > 0) { - long c1 = Pack.littleEndianToLong_High(input, 8, inLen); - x1 ^= c1; - Pack.longToLittleEndian_High(x1, output, outOff, inLen); - x1 &= -1L >>> (inLen << 3); - x1 ^= c1; + long c1 = Pack.bigEndianToLong_High(input, 8, inLen); + p.x1 ^= c1; + Pack.longToBigEndian_High(p.x1, output, outOff, inLen); + p.x1 &= -1L >>> (inLen << 3); + p.x1 ^= c1; } } else { - x0 ^= pad(inLen); - if (inLen != 0) + p.x0 ^= pad(inLen); + if (inLen > 0) { - long c0 = Pack.littleEndianToLong_High(input, 0, inLen); - x0 ^= c0; - Pack.longToLittleEndian_High(x0, output, outOff, inLen); - x0 &= -1L >>> (inLen << 3); - x0 ^= c0; + long c0 = Pack.bigEndianToLong_High(input, 0, inLen); + p.x0 ^= c0; + Pack.longToBigEndian_High(p.x0, output, outOff, inLen); + p.x0 &= -1L >>> (inLen << 3); + p.x0 ^= c0; } } @@ -159,52 +155,52 @@ protected void processFinalEncrypt(byte[] input, int inLen, byte[] output, int o { if (inLen >= 8) // ASCON_AEAD_RATE == 16 is implied { - x0 ^= Pack.bigEndianToLong(input, 0); - Pack.longToBigEndian(x0, output, outOff); + p.x0 ^= Pack.bigEndianToLong(input, 0); + Pack.longToBigEndian(p.x0, output, outOff); outOff += 8; inLen -= 8; - x1 ^= pad(inLen); - if (inLen != 0) + p.x1 ^= pad(inLen); + if (inLen > 0) { - x1 ^= Pack.littleEndianToLong_High(input, 8, inLen); - Pack.longToLittleEndian_High(x1, output, outOff, inLen); + p.x1 ^= Pack.bigEndianToLong_High(input, 8, inLen); + Pack.longToBigEndian_High(p.x1, output, outOff, inLen); } } else { - x0 ^= pad(inLen); - if (inLen != 0) + p.x0 ^= pad(inLen); + if (inLen > 0) { - x0 ^= Pack.littleEndianToLong_High(input, 0, inLen); - Pack.longToLittleEndian_High(x0, output, outOff, inLen); + p.x0 ^= Pack.bigEndianToLong_High(input, 0, inLen); + Pack.longToBigEndian_High(p.x0, output, outOff, inLen); } } finishData(State.EncFinal); } - private void finishData(State nextState) + protected void finishData(State nextState) { switch (asconParameters) { case ascon128: - x1 ^= K1; - x2 ^= K2; + p.x1 ^= K1; + p.x2 ^= K2; break; case ascon128a: - x2 ^= K1; - x3 ^= K2; + p.x2 ^= K1; + p.x3 ^= K2; break; case ascon80pq: - x1 ^= (K0 << 32 | K1 >> 32); - x2 ^= (K1 << 32 | K2 >> 32); - x3 ^= K2 << 32; + p.x1 ^= (K0 << 32 | K1 >> 32); + p.x2 ^= (K1 << 32 | K2 >> 32); + p.x3 ^= K2 << 32; break; default: throw new IllegalStateException(); } - p(12); - x3 ^= K1; - x4 ^= K2; + p.p(12); + p.x3 ^= K1; + p.x4 ^= K2; m_state = nextState; } @@ -212,7 +208,6 @@ private void finishData(State nextState) protected void init(byte[] key, byte[] iv) throws IllegalArgumentException { - N0 = Pack.bigEndianToLong(iv, 0); N1 = Pack.bigEndianToLong(iv, 8); if (KEY_SIZE == 16) @@ -230,14 +225,10 @@ else if (KEY_SIZE == 20) { throw new IllegalStateException(); } - - m_state = forEncryption ? State.EncInit : State.DecInit; - - reset(true); } public String getAlgorithmVersion() { return "v1.2"; } -} +} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/AsconPermutationFriend.java b/core/src/main/java/org/bouncycastle/crypto/engines/AsconPermutationFriend.java new file mode 100644 index 0000000000..3d7b8d037e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/engines/AsconPermutationFriend.java @@ -0,0 +1,82 @@ +package org.bouncycastle.crypto.engines; + +import org.bouncycastle.crypto.digests.ISAPDigest; +import org.bouncycastle.util.Longs; + +public class AsconPermutationFriend +{ + public static AsconPermutation getAsconPermutation(ISAPDigest.Friend friend) + { + if (null == friend) + { + throw new NullPointerException("This method is only for use by ISAPDigest or Ascon Digest"); + } + return new AsconPermutation(); + } + + public static class AsconPermutation + { + AsconPermutation() + { + } + + public long x0; + public long x1; + public long x2; + public long x3; + public long x4; + + public void round(long C) + { + x2 ^= C; + long x0x4 = x0 ^ x4; + //long x0x2c = x0 ^ x2; + long x1x2c = x1 ^ x2; + long x1orx2c = x1 | x2; + long t0 = x3 ^ x1orx2c ^ x0 ^ (x1 & x0x4); + //long t1 = x0x4 ^ x2 ^ x3 ^ (x1x2c & (x1 ^ x3)); + long t1 = x0x4 ^ (x1orx2c | x3) ^ (x1 & x2 & x3); + long t2 = x1x2c ^ (x4 & (~x3));//x4 ^ (x3 & x4); + //long t3 = x0 ^ x1x2c ^ ((~x0) & (x3 ^ x4)); + long t3 = (x0 | (x3 ^ x4)) ^ x1x2c; + //long t4 = x1 ^ x3 ^ x4 ^ (x0x4 & x1); + long t4 = x3 ^ (x1 | x4) ^ (x0 & x1); + x0 = t0 ^ Longs.rotateRight(t0, 19) ^ Longs.rotateRight(t0, 28); + x1 = t1 ^ Longs.rotateRight(t1, 39) ^ Longs.rotateRight(t1, 61); + x2 = ~(t2 ^ Longs.rotateRight(t2, 1) ^ Longs.rotateRight(t2, 6)); + x3 = t3 ^ Longs.rotateRight(t3, 10) ^ Longs.rotateRight(t3, 17); + x4 = t4 ^ Longs.rotateRight(t4, 7) ^ Longs.rotateRight(t4, 41); + } + + public void p(int nr) + { + if (nr == 12) + { + round(0xf0L); + round(0xe1L); + round(0xd2L); + round(0xc3L); + } + if (nr >= 8) + { + round(0xb4L); + round(0xa5L); + } + round(0x96L); + round(0x87L); + round(0x78L); + round(0x69L); + round(0x5aL); + round(0x4bL); + } + + public void set(long x0, long x1, long x2, long x3, long x4) + { + this.x0 = x0; + this.x1 = x1; + this.x2 = x2; + this.x3 = x3; + this.x4 = x4; + } + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/CramerShoupCiphertext.java b/core/src/main/java/org/bouncycastle/crypto/engines/CramerShoupCiphertext.java index edf1bd23ac..6aa017a016 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/CramerShoupCiphertext.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/CramerShoupCiphertext.java @@ -96,7 +96,7 @@ public void setV(BigInteger v) public String toString() { - StringBuffer result = new StringBuffer(); + StringBuilder result = new StringBuilder(); result.append("u1: " + u1.toString()); result.append("\nu2: " + u2.toString()); diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java index 86c1823459..fa5e7a1b4f 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/ElephantEngine.java @@ -1,11 +1,8 @@ package org.bouncycastle.crypto.engines; -import java.io.ByteArrayOutputStream; import java.util.Arrays; -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.OutputLengthException; +import org.bouncycastle.util.Bytes; /** * Elephant AEAD v2, based on the current round 3 submission, https://www.esat.kuleuven.be/cosic/elephant/ @@ -22,27 +19,8 @@ public enum ElephantParameters elephant200 } - private enum State - { - Uninitialized, - EncInit, - EncAad, // can process AAD - EncData, // cannot process AAD - EncFinal, - DecInit, - DecAad, // can process AAD - DecData, // cannot process AAD - DecFinal, - } - private final ElephantParameters parameters; - private final int BLOCK_SIZE; - private int nBits; - private int nSBox; - private final int nRounds; - private byte lfsrIV; private byte[] npub; private byte[] expanded_key; - private boolean initialised; private int nb_its; private byte[] ad; private int adOff; @@ -53,37 +31,7 @@ private enum State private byte[] next_mask; private final byte[] buffer; private final byte[] previous_outputMessage; - private State m_state = State.Uninitialized; - private final ByteArrayOutputStream aadData = new ByteArrayOutputStream(); - private int inputOff; - private byte[] inputMessage; - private int messageLen; - - private final byte[] sBoxLayer = { - (byte)0xee, (byte)0xed, (byte)0xeb, (byte)0xe0, (byte)0xe2, (byte)0xe1, (byte)0xe4, (byte)0xef, (byte)0xe7, (byte)0xea, (byte)0xe8, (byte)0xe5, (byte)0xe9, (byte)0xec, (byte)0xe3, (byte)0xe6, - (byte)0xde, (byte)0xdd, (byte)0xdb, (byte)0xd0, (byte)0xd2, (byte)0xd1, (byte)0xd4, (byte)0xdf, (byte)0xd7, (byte)0xda, (byte)0xd8, (byte)0xd5, (byte)0xd9, (byte)0xdc, (byte)0xd3, (byte)0xd6, - (byte)0xbe, (byte)0xbd, (byte)0xbb, (byte)0xb0, (byte)0xb2, (byte)0xb1, (byte)0xb4, (byte)0xbf, (byte)0xb7, (byte)0xba, (byte)0xb8, (byte)0xb5, (byte)0xb9, (byte)0xbc, (byte)0xb3, (byte)0xb6, - (byte)0x0e, (byte)0x0d, (byte)0x0b, (byte)0x00, (byte)0x02, (byte)0x01, (byte)0x04, (byte)0x0f, (byte)0x07, (byte)0x0a, (byte)0x08, (byte)0x05, (byte)0x09, (byte)0x0c, (byte)0x03, (byte)0x06, - (byte)0x2e, (byte)0x2d, (byte)0x2b, (byte)0x20, (byte)0x22, (byte)0x21, (byte)0x24, (byte)0x2f, (byte)0x27, (byte)0x2a, (byte)0x28, (byte)0x25, (byte)0x29, (byte)0x2c, (byte)0x23, (byte)0x26, - (byte)0x1e, (byte)0x1d, (byte)0x1b, (byte)0x10, (byte)0x12, (byte)0x11, (byte)0x14, (byte)0x1f, (byte)0x17, (byte)0x1a, (byte)0x18, (byte)0x15, (byte)0x19, (byte)0x1c, (byte)0x13, (byte)0x16, - (byte)0x4e, (byte)0x4d, (byte)0x4b, (byte)0x40, (byte)0x42, (byte)0x41, (byte)0x44, (byte)0x4f, (byte)0x47, (byte)0x4a, (byte)0x48, (byte)0x45, (byte)0x49, (byte)0x4c, (byte)0x43, (byte)0x46, - (byte)0xfe, (byte)0xfd, (byte)0xfb, (byte)0xf0, (byte)0xf2, (byte)0xf1, (byte)0xf4, (byte)0xff, (byte)0xf7, (byte)0xfa, (byte)0xf8, (byte)0xf5, (byte)0xf9, (byte)0xfc, (byte)0xf3, (byte)0xf6, - (byte)0x7e, (byte)0x7d, (byte)0x7b, (byte)0x70, (byte)0x72, (byte)0x71, (byte)0x74, (byte)0x7f, (byte)0x77, (byte)0x7a, (byte)0x78, (byte)0x75, (byte)0x79, (byte)0x7c, (byte)0x73, (byte)0x76, - (byte)0xae, (byte)0xad, (byte)0xab, (byte)0xa0, (byte)0xa2, (byte)0xa1, (byte)0xa4, (byte)0xaf, (byte)0xa7, (byte)0xaa, (byte)0xa8, (byte)0xa5, (byte)0xa9, (byte)0xac, (byte)0xa3, (byte)0xa6, - (byte)0x8e, (byte)0x8d, (byte)0x8b, (byte)0x80, (byte)0x82, (byte)0x81, (byte)0x84, (byte)0x8f, (byte)0x87, (byte)0x8a, (byte)0x88, (byte)0x85, (byte)0x89, (byte)0x8c, (byte)0x83, (byte)0x86, - (byte)0x5e, (byte)0x5d, (byte)0x5b, (byte)0x50, (byte)0x52, (byte)0x51, (byte)0x54, (byte)0x5f, (byte)0x57, (byte)0x5a, (byte)0x58, (byte)0x55, (byte)0x59, (byte)0x5c, (byte)0x53, (byte)0x56, - (byte)0x9e, (byte)0x9d, (byte)0x9b, (byte)0x90, (byte)0x92, (byte)0x91, (byte)0x94, (byte)0x9f, (byte)0x97, (byte)0x9a, (byte)0x98, (byte)0x95, (byte)0x99, (byte)0x9c, (byte)0x93, (byte)0x96, - (byte)0xce, (byte)0xcd, (byte)0xcb, (byte)0xc0, (byte)0xc2, (byte)0xc1, (byte)0xc4, (byte)0xcf, (byte)0xc7, (byte)0xca, (byte)0xc8, (byte)0xc5, (byte)0xc9, (byte)0xcc, (byte)0xc3, (byte)0xc6, - (byte)0x3e, (byte)0x3d, (byte)0x3b, (byte)0x30, (byte)0x32, (byte)0x31, (byte)0x34, (byte)0x3f, (byte)0x37, (byte)0x3a, (byte)0x38, (byte)0x35, (byte)0x39, (byte)0x3c, (byte)0x33, (byte)0x36, - (byte)0x6e, (byte)0x6d, (byte)0x6b, (byte)0x60, (byte)0x62, (byte)0x61, (byte)0x64, (byte)0x6f, (byte)0x67, (byte)0x6a, (byte)0x68, (byte)0x65, (byte)0x69, (byte)0x6c, (byte)0x63, (byte)0x66 - }; - - private final byte[] KeccakRoundConstants = { - (byte)0x01, (byte)0x82, (byte)0x8a, (byte)0x00, (byte)0x8b, (byte)0x01, (byte)0x81, (byte)0x09, (byte)0x8a, - (byte)0x88, (byte)0x09, (byte)0x0a, (byte)0x8b, (byte)0x8b, (byte)0x89, (byte)0x03, (byte)0x02, (byte)0x80 - }; - - private final int[] KeccakRhoOffsets = {0, 1, 6, 4, 3, 4, 4, 6, 7, 4, 3, 2, 3, 1, 7, 1, 5, 7, 5, 0, 2, 2, 5, 0, 6}; + private final Permutation instance; public ElephantEngine(ElephantParameters parameters) { @@ -92,49 +40,78 @@ public ElephantEngine(ElephantParameters parameters) switch (parameters) { case elephant160: - BLOCK_SIZE = 20; - nBits = 160; - nSBox = 20; - nRounds = 80; - lfsrIV = 0x75; + BlockSize = 20; + instance = new Dumbo(); MAC_SIZE = 8; algorithmName = "Elephant 160 AEAD"; break; case elephant176: - BLOCK_SIZE = 22; - nBits = 176; - nSBox = 22; - nRounds = 90; - lfsrIV = 0x45; + BlockSize = 22; + instance = new Jumbo(); algorithmName = "Elephant 176 AEAD"; MAC_SIZE = 8; break; case elephant200: - BLOCK_SIZE = 25; - nRounds = 18; + BlockSize = 25; + instance = new Delirium(); algorithmName = "Elephant 200 AEAD"; MAC_SIZE = 16; break; default: throw new IllegalArgumentException("Invalid parameter settings for Elephant"); } - this.parameters = parameters; - tag_buffer = new byte[BLOCK_SIZE]; - previous_mask = new byte[BLOCK_SIZE]; - current_mask = new byte[BLOCK_SIZE]; - next_mask = new byte[BLOCK_SIZE]; - buffer = new byte[BLOCK_SIZE]; - previous_outputMessage = new byte[BLOCK_SIZE]; - initialised = false; - reset(false); + tag_buffer = new byte[BlockSize]; + previous_mask = new byte[BlockSize]; + current_mask = new byte[BlockSize]; + next_mask = new byte[BlockSize]; + buffer = new byte[BlockSize]; + previous_outputMessage = new byte[BlockSize]; + setInnerMembers(ProcessingBufferType.Immediate, AADOperatorType.Stream, DataOperatorType.Counter); } - private void permutation(byte[] state) + private interface Permutation { - switch (parameters) + void permutation(byte[] state); + + void lfsr_step(); + } + + private abstract static class Spongent + implements Permutation + { + private final byte lfsrIV; + private final int nRounds; + private final int nBits; + private final int nSBox; + private final byte[] sBoxLayer = { + (byte)0xee, (byte)0xed, (byte)0xeb, (byte)0xe0, (byte)0xe2, (byte)0xe1, (byte)0xe4, (byte)0xef, (byte)0xe7, (byte)0xea, (byte)0xe8, (byte)0xe5, (byte)0xe9, (byte)0xec, (byte)0xe3, (byte)0xe6, + (byte)0xde, (byte)0xdd, (byte)0xdb, (byte)0xd0, (byte)0xd2, (byte)0xd1, (byte)0xd4, (byte)0xdf, (byte)0xd7, (byte)0xda, (byte)0xd8, (byte)0xd5, (byte)0xd9, (byte)0xdc, (byte)0xd3, (byte)0xd6, + (byte)0xbe, (byte)0xbd, (byte)0xbb, (byte)0xb0, (byte)0xb2, (byte)0xb1, (byte)0xb4, (byte)0xbf, (byte)0xb7, (byte)0xba, (byte)0xb8, (byte)0xb5, (byte)0xb9, (byte)0xbc, (byte)0xb3, (byte)0xb6, + (byte)0x0e, (byte)0x0d, (byte)0x0b, (byte)0x00, (byte)0x02, (byte)0x01, (byte)0x04, (byte)0x0f, (byte)0x07, (byte)0x0a, (byte)0x08, (byte)0x05, (byte)0x09, (byte)0x0c, (byte)0x03, (byte)0x06, + (byte)0x2e, (byte)0x2d, (byte)0x2b, (byte)0x20, (byte)0x22, (byte)0x21, (byte)0x24, (byte)0x2f, (byte)0x27, (byte)0x2a, (byte)0x28, (byte)0x25, (byte)0x29, (byte)0x2c, (byte)0x23, (byte)0x26, + (byte)0x1e, (byte)0x1d, (byte)0x1b, (byte)0x10, (byte)0x12, (byte)0x11, (byte)0x14, (byte)0x1f, (byte)0x17, (byte)0x1a, (byte)0x18, (byte)0x15, (byte)0x19, (byte)0x1c, (byte)0x13, (byte)0x16, + (byte)0x4e, (byte)0x4d, (byte)0x4b, (byte)0x40, (byte)0x42, (byte)0x41, (byte)0x44, (byte)0x4f, (byte)0x47, (byte)0x4a, (byte)0x48, (byte)0x45, (byte)0x49, (byte)0x4c, (byte)0x43, (byte)0x46, + (byte)0xfe, (byte)0xfd, (byte)0xfb, (byte)0xf0, (byte)0xf2, (byte)0xf1, (byte)0xf4, (byte)0xff, (byte)0xf7, (byte)0xfa, (byte)0xf8, (byte)0xf5, (byte)0xf9, (byte)0xfc, (byte)0xf3, (byte)0xf6, + (byte)0x7e, (byte)0x7d, (byte)0x7b, (byte)0x70, (byte)0x72, (byte)0x71, (byte)0x74, (byte)0x7f, (byte)0x77, (byte)0x7a, (byte)0x78, (byte)0x75, (byte)0x79, (byte)0x7c, (byte)0x73, (byte)0x76, + (byte)0xae, (byte)0xad, (byte)0xab, (byte)0xa0, (byte)0xa2, (byte)0xa1, (byte)0xa4, (byte)0xaf, (byte)0xa7, (byte)0xaa, (byte)0xa8, (byte)0xa5, (byte)0xa9, (byte)0xac, (byte)0xa3, (byte)0xa6, + (byte)0x8e, (byte)0x8d, (byte)0x8b, (byte)0x80, (byte)0x82, (byte)0x81, (byte)0x84, (byte)0x8f, (byte)0x87, (byte)0x8a, (byte)0x88, (byte)0x85, (byte)0x89, (byte)0x8c, (byte)0x83, (byte)0x86, + (byte)0x5e, (byte)0x5d, (byte)0x5b, (byte)0x50, (byte)0x52, (byte)0x51, (byte)0x54, (byte)0x5f, (byte)0x57, (byte)0x5a, (byte)0x58, (byte)0x55, (byte)0x59, (byte)0x5c, (byte)0x53, (byte)0x56, + (byte)0x9e, (byte)0x9d, (byte)0x9b, (byte)0x90, (byte)0x92, (byte)0x91, (byte)0x94, (byte)0x9f, (byte)0x97, (byte)0x9a, (byte)0x98, (byte)0x95, (byte)0x99, (byte)0x9c, (byte)0x93, (byte)0x96, + (byte)0xce, (byte)0xcd, (byte)0xcb, (byte)0xc0, (byte)0xc2, (byte)0xc1, (byte)0xc4, (byte)0xcf, (byte)0xc7, (byte)0xca, (byte)0xc8, (byte)0xc5, (byte)0xc9, (byte)0xcc, (byte)0xc3, (byte)0xc6, + (byte)0x3e, (byte)0x3d, (byte)0x3b, (byte)0x30, (byte)0x32, (byte)0x31, (byte)0x34, (byte)0x3f, (byte)0x37, (byte)0x3a, (byte)0x38, (byte)0x35, (byte)0x39, (byte)0x3c, (byte)0x33, (byte)0x36, + (byte)0x6e, (byte)0x6d, (byte)0x6b, (byte)0x60, (byte)0x62, (byte)0x61, (byte)0x64, (byte)0x6f, (byte)0x67, (byte)0x6a, (byte)0x68, (byte)0x65, (byte)0x69, (byte)0x6c, (byte)0x63, (byte)0x66 + }; + + public Spongent(int nBits, int nSBox, int nRounds, byte lfsrIV) + { + this.nRounds = nRounds; + this.nSBox = nSBox; + this.lfsrIV = lfsrIV; + this.nBits = nBits; + } + + public void permutation(byte[] state) { - case elephant160: - case elephant176: byte IV = lfsrIV; byte[] tmp = new byte[nSBox]; for (int i = 0; i < nRounds; i++) @@ -166,113 +143,145 @@ private void permutation(byte[] state) } System.arraycopy(tmp, 0, state, 0, nSBox); } - break; - case elephant200: - for (int i = 0; i < nRounds; i++) - { - KeccakP200Round(state, i); - } - break; } } - private byte rotl(byte b) + private class Dumbo + extends Spongent { - return (byte)(((b & 0xFF) << 1) | ((b & 0xFF) >>> 7)); - } + public Dumbo() + { + super(160, 20, 80, (byte)0x75); + } - private byte ROL8(byte a, int offset) - { - return (byte)((offset != 0) ? (((a & 0xFF) << offset) ^ ((a & 0xFF) >>> (8 - offset))) : a); + @Override + public void lfsr_step() + { + next_mask[BlockSize - 1] = (byte)((((current_mask[0] & 0xFF) << 3) | ((current_mask[0] & 0xFF) >>> 5)) ^ + ((current_mask[3] & 0xFF) << 7) ^ ((current_mask[13] & 0xFF) >>> 7)); + } } - private int index(int x, int y) + private class Jumbo + extends Spongent { - return x + y * 5; + public Jumbo() + { + super(176, 22, 90, (byte)0x45); + } + + @Override + public void lfsr_step() + { + next_mask[BlockSize - 1] = (byte)(rotl(current_mask[0]) ^ ((current_mask[3] & 0xFF) << 7) ^ ((current_mask[19] & 0xFF) >>> 7)); + } } - private void KeccakP200Round(byte[] state, int indexRound) + private class Delirium + implements Permutation { - int x, y; - byte[] tempA = new byte[25]; - //theta - for (x = 0; x < 5; x++) + private static final int nRounds = 18; + private final byte[] KeccakRoundConstants = { + (byte)0x01, (byte)0x82, (byte)0x8a, (byte)0x00, (byte)0x8b, (byte)0x01, (byte)0x81, (byte)0x09, (byte)0x8a, + (byte)0x88, (byte)0x09, (byte)0x0a, (byte)0x8b, (byte)0x8b, (byte)0x89, (byte)0x03, (byte)0x02, (byte)0x80 + }; + + private final int[] KeccakRhoOffsets = {0, 1, 6, 4, 3, 4, 4, 6, 7, 4, 3, 2, 3, 1, 7, 1, 5, 7, 5, 0, 2, 2, 5, 0, 6}; + + @Override + public void permutation(byte[] state) { - for (y = 0; y < 5; y++) + for (int i = 0; i < nRounds; i++) { - tempA[x] ^= state[index(x, y)]; + KeccakP200Round(state, i); } } - for (x = 0; x < 5; x++) + + @Override + public void lfsr_step() { - tempA[x + 5] = (byte)(ROL8(tempA[(x + 1) % 5], 1) ^ tempA[(x + 4) % 5]); + next_mask[BlockSize - 1] = (byte)(rotl(current_mask[0]) ^ rotl(current_mask[2]) ^ (current_mask[13] << 1)); } - for (x = 0; x < 5; x++) + + private void KeccakP200Round(byte[] state, int indexRound) { - for (y = 0; y < 5; y++) + int x, y; + byte[] tempA = new byte[25]; + //theta + for (x = 0; x < 5; x++) { - state[index(x, y)] ^= tempA[x + 5]; + for (y = 0; y < 5; y++) + { + tempA[x] ^= state[index(x, y)]; + } } - } - //rho - for (x = 0; x < 5; x++) - { - for (y = 0; y < 5; y++) + for (x = 0; x < 5; x++) { - tempA[index(x, y)] = ROL8(state[index(x, y)], KeccakRhoOffsets[index(x, y)]); + tempA[x + 5] = (byte)(ROL8(tempA[(x + 1) % 5], 1) ^ tempA[(x + 4) % 5]); } - } - //pi - for (x = 0; x < 5; x++) - { - for (y = 0; y < 5; y++) + for (x = 0; x < 5; x++) { - state[index(y, (2 * x + 3 * y) % 5)] = tempA[index(x, y)]; + for (y = 0; y < 5; y++) + { + state[index(x, y)] ^= tempA[x + 5]; + } } - } - //chi - for (y = 0; y < 5; y++) - { + //rho for (x = 0; x < 5; x++) { - tempA[x] = (byte)(state[index(x, y)] ^ ((~state[index((x + 1) % 5, y)]) & state[index((x + 2) % 5, y)])); + for (y = 0; y < 5; y++) + { + tempA[index(x, y)] = ROL8(state[index(x, y)], KeccakRhoOffsets[index(x, y)]); + } } + //pi for (x = 0; x < 5; x++) { - state[index(x, y)] = tempA[x]; + for (y = 0; y < 5; y++) + { + state[index(y, (2 * x + 3 * y) % 5)] = tempA[index(x, y)]; + } } + //chi + for (y = 0; y < 5; y++) + { + for (x = 0; x < 5; x++) + { + tempA[x] = (byte)(state[index(x, y)] ^ ((~state[index((x + 1) % 5, y)]) & state[index((x + 2) % 5, y)])); + } + for (x = 0; x < 5; x++) + { + state[index(x, y)] = tempA[x]; + } + } + //iota + state[0] ^= KeccakRoundConstants[indexRound];//index(0,0) } - //iota - state[0] ^= KeccakRoundConstants[indexRound];//index(0,0) - } + //TODO: search for " >>> (8 - " merge with with CamelliaLightEngine.lRot8, + // code in OCBBlockCipher.init, DualECSP800DRBG.pad8, + private byte ROL8(byte a, int offset) + { + return (byte)((a << offset) | ((a & 0xff) >>> (8 - offset))); + } - // State should be BLOCK_SIZE bytes long - // Note: input may be equal to output - private void lfsr_step(byte[] output, byte[] input) - { - switch (parameters) + private int index(int x, int y) { - case elephant160: - output[BLOCK_SIZE - 1] = (byte)((((input[0] & 0xFF) << 3) | ((input[0] & 0xFF) >>> 5)) ^ - ((input[3] & 0xFF) << 7) ^ ((input[13] & 0xFF) >>> 7)); - break; - case elephant176: - output[BLOCK_SIZE - 1] = (byte)(rotl(input[0]) ^ ((input[3] & 0xFF) << 7) ^ ((input[19] & 0xFF) >>> 7)); - break; - case elephant200: - output[BLOCK_SIZE - 1] = (byte)(rotl(input[0]) ^ rotl(input[2]) ^ (input[13] << 1)); - break; + return x + y * 5; } - System.arraycopy(input, 1, output, 0, BLOCK_SIZE - 1); } - private void xor_block(byte[] state, byte[] block, int bOff, int size) + private byte rotl(byte b) { - for (int i = 0; i < size; ++i) - { - state[i] ^= block[i + bOff]; - } + return (byte)((b << 1) | ((b & 0xFF) >>> 7)); + } + + // State should be BLOCK_SIZE bytes long + // Note: input may be equal to output + private void lfsr_step() + { + instance.lfsr_step(); + System.arraycopy(current_mask, 1, next_mask, 0, BlockSize - 1); } @Override @@ -281,256 +290,251 @@ protected void init(byte[] k, byte[] iv) { npub = iv; // Storage for the expanded key L - expanded_key = new byte[BLOCK_SIZE]; + expanded_key = new byte[BlockSize]; System.arraycopy(k, 0, expanded_key, 0, KEY_SIZE); - permutation(expanded_key); - initialised = true; - m_state = forEncryption ? State.EncInit : State.DecInit; - inputMessage = new byte[BLOCK_SIZE * 2 + (forEncryption ? 0 : MAC_SIZE)]; - reset(false); + instance.permutation(expanded_key); } - @Override - public void processAADByte(byte input) + protected void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff) { - aadData.write(input); + processBuffer(input, inOff, output, outOff, State.EncData); + System.arraycopy(output, outOff, previous_outputMessage, 0, BlockSize); } - @Override - public void processAADBytes(byte[] input, int inOff, int len) + private void processBuffer(byte[] input, int inOff, byte[] output, int outOff, State encData) { - if (inOff + len > input.length) + if (m_state == State.DecInit || m_state == State.EncInit) { - throw new DataLengthException("input buffer too short"); + processFinalAAD(); } - aadData.write(input, inOff, len); - } + // Compute mask for the next message + lfsr_step(); - @Override - public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) - throws DataLengthException - { - if (inOff + len > input.length) - { - throw new DataLengthException("input buffer too short"); - } + // Compute ciphertext block + computeCipherBlock(input, inOff, BlockSize, output, outOff); - if (inputOff + len - (forEncryption ? 0 : MAC_SIZE) >= BLOCK_SIZE) + if (nb_its > 0) { - int mlen = inputOff + messageLen + len - (forEncryption ? 0 : MAC_SIZE); - int adlen = processAADBytes(); - int nblocks_c = 1 + mlen / BLOCK_SIZE; - int nblocks_m = ((mlen % BLOCK_SIZE) != 0 ? nblocks_c : nblocks_c - 1); - int nblocks_ad = 1 + (IV_SIZE + adlen) / BLOCK_SIZE; - int nb_it = Math.max(nblocks_c + 1, nblocks_ad - 1); - byte[] tempInput = new byte[Math.max(nblocks_c, 1) * BLOCK_SIZE]; - System.arraycopy(inputMessage, 0, tempInput, 0, inputOff); - System.arraycopy(input, inOff, tempInput, inputOff, Math.min(len, tempInput.length - inputOff)); - int rv = processBytes(tempInput, output, outOff, nb_it, nblocks_m, nblocks_c, mlen, nblocks_ad, false); - int copyLen = rv - inputOff; - if (copyLen >= 0) - { - inputOff = inputOff + len - rv; - System.arraycopy(input, inOff + copyLen, inputMessage, 0, inputOff); - } - else - { - System.arraycopy(inputMessage, inputOff + copyLen, inputMessage, 0, -copyLen); - System.arraycopy(input, inOff, inputMessage, -copyLen, len); - inputOff = len - copyLen; - } - messageLen += rv; - return rv; + // enough ciphertext + System.arraycopy(previous_outputMessage, 0, buffer, 0, BlockSize); + absorbCiphertext(); } - else + // If there is any AD left, compute tag for AD block + if (m_state != encData) { - System.arraycopy(input, inOff, inputMessage, inputOff, len); - inputOff += len; - return 0; + absorbAAD(); } + // Cyclically shift the mask buffers + // Value of next_mask will be computed in the next iteration + swapMasks(); + nb_its++; } - @Override - public int doFinal(byte[] output, int outOff) - throws IllegalStateException, InvalidCipherTextException + protected void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff) { - if (!initialised) - { - throw new IllegalArgumentException(algorithmName + " needs call init function before doFinal"); - } - int len = inputOff; - if ((forEncryption && len + outOff + MAC_SIZE > output.length) || - (!forEncryption && len + outOff - MAC_SIZE > output.length)) - { - throw new OutputLengthException("output buffer is too short"); - } - int mlen = len + messageLen - (forEncryption ? 0 : MAC_SIZE); - int rv = mlen - messageLen; - int adlen = processAADBytes(); - int nblocks_c = 1 + mlen / BLOCK_SIZE; - int nblocks_m = (mlen % BLOCK_SIZE) != 0 ? nblocks_c : nblocks_c - 1; - int nblocks_ad = 1 + (IV_SIZE + adlen) / BLOCK_SIZE; + processBuffer(input, inOff, output, outOff, State.DecData); + System.arraycopy(input, inOff, previous_outputMessage, 0, BlockSize); + } + + private void computeCipherBlock(byte[] input, int inOff, int blockSize, byte[] output, int outOff) + { + System.arraycopy(npub, 0, buffer, 0, IV_SIZE); + Arrays.fill(buffer, IV_SIZE, BlockSize, (byte)0); + xorTo(BlockSize, current_mask, next_mask, buffer); + instance.permutation(buffer); + xorTo(BlockSize, current_mask, next_mask, buffer); + + Bytes.xorTo(blockSize, input, inOff, buffer); + System.arraycopy(buffer, 0, output, outOff, blockSize); + } + + private void swapMasks() + { + byte[] temp = previous_mask; + previous_mask = current_mask; + current_mask = next_mask; + next_mask = temp; + } + + private void absorbAAD() + { + processAADBytes(buffer); + Bytes.xorTo(BlockSize, next_mask, buffer); + instance.permutation(buffer); + Bytes.xorTo(BlockSize, next_mask, buffer); + Bytes.xorTo(BlockSize, buffer, tag_buffer); + } + + private void absorbCiphertext() + { + xorTo(BlockSize, previous_mask, next_mask, buffer); + instance.permutation(buffer); + xorTo(BlockSize, previous_mask, next_mask, buffer); + Bytes.xorTo(BlockSize, buffer, tag_buffer); + } + + protected void processFinalBlock(byte[] output, int outOff) + { + int mlen = dataOperator.getLen() - (forEncryption ? 0 : MAC_SIZE); + processFinalAAD(); + int nblocks_c = 1 + mlen / BlockSize; + int nblocks_m = (mlen % BlockSize) != 0 ? nblocks_c : nblocks_c - 1; + int nblocks_ad = 1 + (IV_SIZE + adlen) / BlockSize; int nb_it = Math.max(nblocks_c + 1, nblocks_ad - 1); - outOff += processBytes(inputMessage, output, outOff, nb_it, nblocks_m, nblocks_c, mlen, nblocks_ad, true); - mac = new byte[MAC_SIZE]; - xor_block(tag_buffer, expanded_key, 0, BLOCK_SIZE); - permutation(tag_buffer); - xor_block(tag_buffer, expanded_key, 0, BLOCK_SIZE); - if (forEncryption) - { - System.arraycopy(tag_buffer, 0, mac, 0, MAC_SIZE); - System.arraycopy(mac, 0, output, outOff, mac.length); - rv += MAC_SIZE; - } - else - { - inputOff -= MAC_SIZE; - for (int i = 0; i < MAC_SIZE; ++i) - { - if (tag_buffer[i] != inputMessage[inputOff + i]) - { - throw new IllegalArgumentException("Mac does not match"); - } - } - } - reset(false); - return rv; + processBytes(m_buf, output, outOff, nb_it, nblocks_m, nblocks_c, mlen, nblocks_ad); + Bytes.xorTo(BlockSize, expanded_key, tag_buffer); + instance.permutation(tag_buffer); + Bytes.xorTo(BlockSize, expanded_key, tag_buffer); + System.arraycopy(tag_buffer, 0, mac, 0, MAC_SIZE); + } + + @Override + protected void processBufferAAD(byte[] input, int inOff) + { } @Override public int getUpdateOutputSize(int len) { - switch (m_state) + switch (m_state.ord) { - case Uninitialized: + case State.UNINITIALIZED: throw new IllegalArgumentException(algorithmName + " needs call init function before getUpdateOutputSize"); - case DecFinal: - case EncFinal: + case State.DEC_FINAL: + case State.ENC_FINAL: return 0; - case EncAad: - case EncData: - case EncInit: + case State.ENC_AAD: + case State.ENC_DATA: + case State.ENC_INIT: { - int total = inputOff + len; - return total - total % BLOCK_SIZE; + int total = m_bufPos + len; + return total - total % BlockSize; } - case DecAad: - case DecData: - case DecInit: + case State.DEC_AAD: + case State.DEC_DATA: + case State.DEC_INIT: { - int total = Math.max(0, inputOff + len - MAC_SIZE); - return total - total % BLOCK_SIZE; + int total = Math.max(0, m_bufPos + len - MAC_SIZE); + return total - total % BlockSize; } } - return Math.max(0, len + inputOff - MAC_SIZE); + return Math.max(0, len + m_bufPos - MAC_SIZE); } @Override public int getOutputSize(int len) { - switch (m_state) + switch (m_state.ord) { - case Uninitialized: + case State.UNINITIALIZED: throw new IllegalArgumentException(algorithmName + " needs call init function before getUpdateOutputSize"); - case DecFinal: - case EncFinal: + case State.DEC_FINAL: + case State.ENC_FINAL: return 0; - case EncAad: - case EncData: - case EncInit: - return len + inputOff + MAC_SIZE; + case State.ENC_AAD: + case State.ENC_DATA: + case State.ENC_INIT: + return len + m_bufPos + MAC_SIZE; } - return Math.max(0, len + inputOff - MAC_SIZE); + return Math.max(0, len + m_bufPos - MAC_SIZE); } - private int processAADBytes() + protected void finishAAD(State nextState, boolean isDoFinal) { - byte[] ad = aadData.toByteArray(); - switch (m_state) + finishAAD2(nextState); + } + + @Override + protected void processFinalAAD() + { + if (adOff == -1) + { + ad = ((StreamAADOperator)aadOperator).getBytes(); + adOff = 0; + adlen = aadOperator.getLen(); + aadOperator.reset(); + } + switch (m_state.ord) { - case EncInit: - case DecInit: + case State.ENC_INIT: + case State.DEC_INIT: processAADBytes(tag_buffer); break; } - return ad.length; } protected void reset(boolean clearMac) { - aadData.reset(); + super.reset(clearMac); Arrays.fill(tag_buffer, (byte)0); Arrays.fill(previous_outputMessage, (byte)0); - inputOff = 0; nb_its = 0; adOff = -1; - messageLen = 0; - super.reset(clearMac); - } - - public int getBlockSize() - { - return BLOCK_SIZE; } - private void checkAad() + protected void checkAAD() { - switch (m_state) + switch (m_state.ord) { - case DecData: + case State.DEC_DATA: throw new IllegalArgumentException(algorithmName + " cannot process AAD when the length of the plaintext to be processed exceeds the a block size"); - case EncData: + case State.ENC_DATA: throw new IllegalArgumentException(algorithmName + " cannot process AAD when the length of the ciphertext to be processed exceeds the a block size"); - case EncFinal: + case State.ENC_FINAL: throw new IllegalArgumentException(algorithmName + " cannot be reused for encryption"); default: break; } } - private void processAADBytes(byte[] output) + protected boolean checkData(boolean isDofinal) { - checkAad(); - - if (adOff == -1) + switch (m_state.ord) { - adlen = aadData.size(); - ad = aadData.toByteArray(); - adOff = 0; + case State.DEC_INIT: + case State.DEC_AAD: + case State.DEC_DATA: + return false; + case State.ENC_INIT: + case State.ENC_AAD: + case State.ENC_DATA: + return true; + case State.ENC_FINAL: + throw new IllegalStateException(getAlgorithmName() + " cannot be reused for encryption"); + default: + throw new IllegalStateException(getAlgorithmName() + " needs to be initialized"); } + } + + private void processAADBytes(byte[] output) + { int len = 0; - switch (m_state) + switch (m_state.ord) { - case DecInit: - System.arraycopy(expanded_key, 0, current_mask, 0, BLOCK_SIZE); + case State.DEC_INIT: + System.arraycopy(expanded_key, 0, current_mask, 0, BlockSize); System.arraycopy(npub, 0, output, 0, IV_SIZE); len += IV_SIZE; m_state = State.DecAad; break; - case EncInit: - System.arraycopy(expanded_key, 0, current_mask, 0, BLOCK_SIZE); + case State.ENC_INIT: + System.arraycopy(expanded_key, 0, current_mask, 0, BlockSize); System.arraycopy(npub, 0, output, 0, IV_SIZE); len += IV_SIZE; m_state = State.EncAad; break; - case DecAad: - case EncAad: + case State.DEC_AAD: + case State.ENC_AAD: // If adlen is divisible by BLOCK_SIZE, add an additional padding block if (adOff == adlen) { - Arrays.fill(output, 0, BLOCK_SIZE, (byte)0); + Arrays.fill(output, 0, BlockSize, (byte)0); output[0] = 0x01; return; } break; - case DecData: - throw new IllegalArgumentException(algorithmName + " cannot process AAD when the length of the plaintext to be processed exceeds the a block size"); - case EncData: - throw new IllegalArgumentException(algorithmName + " cannot process AAD when the length of the ciphertext to be processed exceeds the a block size"); - case EncFinal: - throw new IllegalArgumentException(algorithmName + " cannot be reused for encryption"); } - int r_outlen = BLOCK_SIZE - len; + int r_outlen = BlockSize - len; int r_adlen = adlen - adOff; // Fill with associated data if available if (r_outlen <= r_adlen) @@ -547,46 +551,33 @@ private void processAADBytes(byte[] output) } Arrays.fill(output, len + r_adlen, len + r_outlen, (byte)0); output[len + r_adlen] = 0x01; - switch (m_state) + switch (m_state.ord) { - case DecAad: + case State.DEC_AAD: m_state = State.DecData; break; - case EncAad: + case State.ENC_AAD: m_state = State.EncData; break; } } } - private int processBytes(byte[] m, byte[] output, int outOff, int nb_it, int nblocks_m, int nblocks_c, int mlen, - int nblocks_ad, boolean isDofinal) + private void processBytes(byte[] m, byte[] output, int outOff, int nb_it, int nblocks_m, int nblocks_c, int mlen, + int nblocks_ad) { int rv = 0; - byte[] outputMessage = new byte[BLOCK_SIZE]; + byte[] outputMessage = new byte[BlockSize]; int i; for (i = nb_its; i < nb_it; ++i) { - int r_size = (i == nblocks_m - 1) ? mlen - i * BLOCK_SIZE : BLOCK_SIZE; - if (!isDofinal && (mlen <= i * BLOCK_SIZE || r_size % BLOCK_SIZE != 0)) - { - break; - } + int r_size = (i == nblocks_m - 1) ? mlen - i * BlockSize : BlockSize; // Compute mask for the next message - lfsr_step(next_mask, current_mask); + lfsr_step(); if (i < nblocks_m) { // Compute ciphertext block - System.arraycopy(npub, 0, buffer, 0, IV_SIZE); - Arrays.fill(buffer, IV_SIZE, BLOCK_SIZE, (byte)0); - xor_block(buffer, current_mask, 0, BLOCK_SIZE); - xor_block(buffer, next_mask, 0, BLOCK_SIZE); - permutation(buffer); - xor_block(buffer, current_mask, 0, BLOCK_SIZE); - xor_block(buffer, next_mask, 0, BLOCK_SIZE); - - xor_block(buffer, m, rv, r_size); - System.arraycopy(buffer, 0, output, outOff, r_size); + computeCipherBlock(m, rv, r_size, output, outOff); if (forEncryption) { System.arraycopy(buffer, 0, outputMessage, 0, r_size); @@ -602,57 +593,52 @@ private int processBytes(byte[] m, byte[] output, int outOff, int nb_it, int nbl if (i > 0 && i <= nblocks_c) { //get_c_block: Compute tag for ciphertext block - int block_offset = (i - 1) * BLOCK_SIZE; + int block_offset = (i - 1) * BlockSize; // If clen is divisible by BLOCK_SIZE, add an additional padding block if (block_offset == mlen) { - Arrays.fill(buffer, 0, BLOCK_SIZE, (byte)0); + Arrays.fill(buffer, 1, BlockSize, (byte)0); buffer[0] = 0x01; } else { int r_clen = mlen - block_offset; // Fill with ciphertext if available - if (BLOCK_SIZE <= r_clen) + if (BlockSize <= r_clen) { // enough ciphertext - System.arraycopy(previous_outputMessage, 0, buffer, 0, BLOCK_SIZE); + System.arraycopy(previous_outputMessage, 0, buffer, 0, BlockSize); } else { // not enough ciphertext, need to pad if (r_clen > 0) // c might be nullptr { System.arraycopy(previous_outputMessage, 0, buffer, 0, r_clen); - Arrays.fill(buffer, r_clen, BLOCK_SIZE, (byte)0); + Arrays.fill(buffer, r_clen, BlockSize, (byte)0); buffer[r_clen] = 0x01; } } } - xor_block(buffer, previous_mask, 0, BLOCK_SIZE); - xor_block(buffer, next_mask, 0, BLOCK_SIZE); - permutation(buffer); - xor_block(buffer, previous_mask, 0, BLOCK_SIZE); - xor_block(buffer, next_mask, 0, BLOCK_SIZE); - xor_block(tag_buffer, buffer, 0, BLOCK_SIZE); + absorbCiphertext(); } // If there is any AD left, compute tag for AD block if (i + 1 < nblocks_ad) { - processAADBytes(buffer); - xor_block(buffer, next_mask, 0, BLOCK_SIZE); - permutation(buffer); - xor_block(buffer, next_mask, 0, BLOCK_SIZE); - xor_block(tag_buffer, buffer, 0, BLOCK_SIZE); + absorbAAD(); } // Cyclically shift the mask buffers // Value of next_mask will be computed in the next iteration - byte[] temp = previous_mask; - previous_mask = current_mask; - current_mask = next_mask; - next_mask = temp; - System.arraycopy(outputMessage, 0, previous_outputMessage, 0, BLOCK_SIZE); + swapMasks(); + System.arraycopy(outputMessage, 0, previous_outputMessage, 0, BlockSize); } nb_its = i; - return rv; + } + + public static void xorTo(int len, byte[] x, byte[] y, byte[] z) + { + for (int i = 0; i < len; ++i) + { + z[i] ^= x[i] ^ y[i]; + } } } diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/EthereumIESEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/EthereumIESEngine.java index 09a41db9ea..7bb3643c5f 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/EthereumIESEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/EthereumIESEngine.java @@ -559,13 +559,8 @@ public int generateBytes(byte[] out, int outOff, int len) long oBytes = len; int outLen = digest.getDigestSize(); - // - // this is at odds with the standard implementation, the - // maximum value should be hBits * (2^32 - 1) where hBits - // is the digest output size in bits. We can't have an - // array with a long index at the moment... - // - if (oBytes > ((2L << 32) - 1)) + // NOTE: This limit isn't reachable for current array lengths + if (oBytes > ((1L << 32) - 1) * outLen) { throw new IllegalArgumentException("output length too large"); } diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/GiftCofbEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/GiftCofbEngine.java new file mode 100644 index 0000000000..a5ac0ae3db --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/engines/GiftCofbEngine.java @@ -0,0 +1,293 @@ +package org.bouncycastle.crypto.engines; + +import org.bouncycastle.util.Bytes; + +/** + * GIFT-COFB v1.1, based on the current round 3 submission, https://www.isical.ac.in/~lightweight/COFB/ + * Reference C implementation: https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-submissions/elephant.zip + * Specification: https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/gift-cofb-spec-final.pdf + */ + +public class GiftCofbEngine + extends AEADBaseEngine +{ + private byte[] npub; + private byte[] k; + private byte[] Y; + private byte[] input; + private byte[] offset; + /*Round constants*/ + private static final byte[] GIFT_RC = { + (byte)0x01, (byte)0x03, (byte)0x07, (byte)0x0F, (byte)0x1F, (byte)0x3E, (byte)0x3D, (byte)0x3B, (byte)0x37, (byte)0x2F, + (byte)0x1E, (byte)0x3C, (byte)0x39, (byte)0x33, (byte)0x27, (byte)0x0E, (byte)0x1D, (byte)0x3A, (byte)0x35, (byte)0x2B, + (byte)0x16, (byte)0x2C, (byte)0x18, (byte)0x30, (byte)0x21, (byte)0x02, (byte)0x05, (byte)0x0B, (byte)0x17, (byte)0x2E, + (byte)0x1C, (byte)0x38, (byte)0x31, (byte)0x23, (byte)0x06, (byte)0x0D, (byte)0x1B, (byte)0x36, (byte)0x2D, (byte)0x1A + }; + + public GiftCofbEngine() + { + AADBufferSize = BlockSize = MAC_SIZE = IV_SIZE = KEY_SIZE = 16; + algorithmName = "GIFT-COFB AEAD"; + setInnerMembers(ProcessingBufferType.Buffered, AADOperatorType.Default, DataOperatorType.Counter); + } + + private int rowperm(int S, int B0_pos, int B1_pos, int B2_pos, int B3_pos) + { + int T = 0; + int b; + for (b = 0; b < 8; b++) + { + T |= ((S >>> (4 * b)) & 0x1) << (b + 8 * B0_pos); + T |= ((S >>> (4 * b + 1)) & 0x1) << (b + 8 * B1_pos); + T |= ((S >>> (4 * b + 2)) & 0x1) << (b + 8 * B2_pos); + T |= ((S >>> (4 * b + 3)) & 0x1) << (b + 8 * B3_pos); + } + return T; + } + + private void giftb128(byte[] P, byte[] K, byte[] C) + { + int round, T; + int[] S = new int[4]; + short[] W = new short[8]; + short T6, T7; + S[0] = ((P[0] & 0xFF) << 24) | ((P[1] & 0xFF) << 16) | ((P[2] & 0xFF) << 8) | (P[3] & 0xFF); + S[1] = ((P[4] & 0xFF) << 24) | ((P[5] & 0xFF) << 16) | ((P[6] & 0xFF) << 8) | (P[7] & 0xFF); + S[2] = ((P[8] & 0xFF) << 24) | ((P[9] & 0xFF) << 16) | ((P[10] & 0xFF) << 8) | (P[11] & 0xFF); + S[3] = ((P[12] & 0xFF) << 24) | ((P[13] & 0xFF) << 16) | ((P[14] & 0xFF) << 8) | (P[15] & 0xFF); + W[0] = (short)(((K[0] & 0xFF) << 8) | (K[1] & 0xFF)); + W[1] = (short)(((K[2] & 0xFF) << 8) | (K[3] & 0xFF)); + W[2] = (short)(((K[4] & 0xFF) << 8) | (K[5] & 0xFF)); + W[3] = (short)(((K[6] & 0xFF) << 8) | (K[7] & 0xFF)); + W[4] = (short)(((K[8] & 0xFF) << 8) | (K[9] & 0xFF)); + W[5] = (short)(((K[10] & 0xFF) << 8) | (K[11] & 0xFF)); + W[6] = (short)(((K[12] & 0xFF) << 8) | (K[13] & 0xFF)); + W[7] = (short)(((K[14] & 0xFF) << 8) | (K[15] & 0xFF)); + for (round = 0; round < 40; round++) + { + /*===SubCells===*/ + S[1] ^= S[0] & S[2]; + S[0] ^= S[1] & S[3]; + S[2] ^= S[0] | S[1]; + S[3] ^= S[2]; + S[1] ^= S[3]; + S[3] ^= 0xffffffff; + S[2] ^= S[0] & S[1]; + T = S[0]; + S[0] = S[3]; + S[3] = T; + /*===PermBits===*/ + S[0] = rowperm(S[0], 0, 3, 2, 1); + S[1] = rowperm(S[1], 1, 0, 3, 2); + S[2] = rowperm(S[2], 2, 1, 0, 3); + S[3] = rowperm(S[3], 3, 2, 1, 0); + /*===AddRoundKey===*/ + S[2] ^= ((W[2] & 0xFFFF) << 16) | (W[3] & 0xFFFF); + S[1] ^= ((W[6] & 0xFFFF) << 16) | (W[7] & 0xFFFF); + /*Add round constant*/ + S[3] ^= 0x80000000 ^ (GIFT_RC[round] & 0xFF); + /*===Key state update===*/ + T6 = (short)(((W[6] & 0xFFFF) >>> 2) | ((W[6] & 0xFFFF) << 14)); + T7 = (short)(((W[7] & 0xFFFF) >>> 12) | ((W[7] & 0xFFFF) << 4)); + W[7] = W[5]; + W[6] = W[4]; + W[5] = W[3]; + W[4] = W[2]; + W[3] = W[1]; + W[2] = W[0]; + W[1] = T7; + W[0] = T6; + } + C[0] = (byte)(S[0] >>> 24); + C[1] = (byte)(S[0] >>> 16); + C[2] = (byte)(S[0] >>> 8); + C[3] = (byte)(S[0]); + C[4] = (byte)(S[1] >>> 24); + C[5] = (byte)(S[1] >>> 16); + C[6] = (byte)(S[1] >>> 8); + C[7] = (byte)(S[1]); + C[8] = (byte)(S[2] >>> 24); + C[9] = (byte)(S[2] >>> 16); + C[10] = (byte)(S[2] >>> 8); + C[11] = (byte)(S[2]); + C[12] = (byte)(S[3] >>> 24); + C[13] = (byte)(S[3] >>> 16); + C[14] = (byte)(S[3] >>> 8); + C[15] = (byte)(S[3]); + } + + private void double_half_block(byte[] s) + { + int mask = ((s[0] & 0xFF) >>> 7) * 27; + /*x^{64} + x^4 + x^3 + x + 1*/ + for (int i = 0; i < 7; i++) + { + s[i] = (byte)(((s[i] & 0xFF) << 1) | ((s[i + 1] & 0xFF) >>> 7)); + } + s[7] = (byte)(((s[7] & 0xFF) << 1) ^ mask); + } + + private void triple_half_block(byte[] s) + { + byte[] tmp = new byte[8]; + /*x^{64} + x^4 + x^3 + x + 1*/ + for (int i = 0; i < 7; i++) + { + tmp[i] = (byte)(((s[i] & 0xFF) << 1) | ((s[i + 1] & 0xFF) >>> 7)); + } + tmp[7] = (byte)(((s[7] & 0xFF) << 1) ^ (((s[0] & 0xFF) >>> 7) * 27)); + Bytes.xorTo(8, tmp, s); + } + + private void pho1(byte[] d, byte[] Y, byte[] M, int mOff, int no_of_bytes) + { + byte[] tmpM = new byte[16]; + byte[] tmp = new byte[16]; + if (no_of_bytes == 0) + { + tmpM[0] = (byte)0x80; + } + else if (no_of_bytes < 16) + { + System.arraycopy(M, mOff, tmpM, 0, no_of_bytes); + tmpM[no_of_bytes] = (byte)0x80; + } + else + { + System.arraycopy(M, mOff, tmpM, 0, no_of_bytes); + } + //G(Y, Y); + /*Y[1],Y[2] -> Y[2],Y[1]<<<1*/ + System.arraycopy(Y, 8, tmp, 0, 8); + for (int i = 0; i < 7; i++) + { + tmp[i + 8] = (byte)((Y[i] & 0xFF) << 1 | (Y[i + 1] & 0xFF) >>> 7); + } + tmp[15] = (byte)((Y[7] & 0xFF) << 1 | (Y[0] & 0xFF) >>> 7); + System.arraycopy(tmp, 0, Y, 0, 16); + Bytes.xor(16, Y, tmpM, d); + } + + @Override + protected void processBufferAAD(byte[] in, int inOff) + { + pho1(input, Y, in, inOff, 16); + /* offset = 2*offset */ + double_half_block(offset); + Bytes.xorTo(8, offset, input); + /* Y[i] = E(X[i]) */ + giftb128(input, k, Y); + } + + @Override + protected void processFinalAAD() + { + int len = dataOperator.getLen() - (forEncryption ? 0 : MAC_SIZE); + /* last byte[] */ + /* full byte[]: offset = 3*offset */ + /* partial byte[]: offset = 3^2*offset */ + triple_half_block(offset); + if (((m_aadPos & 15) != 0) || m_state == State.DecInit || m_state == State.EncInit) + { + triple_half_block(offset); + } + if (len == 0) + { + /* empty M: offset = 3^2*offset */ + triple_half_block(offset); + triple_half_block(offset); + } + /* X[i] = (pad(A[i]) + G(Y[i-1])) + offset */ + pho1(input, Y, m_aad, 0, m_aadPos); + Bytes.xorTo(8, offset, input); + /* Y[a] = E(X[a]) */ + giftb128(input, k, Y); + } + + @Override + protected void finishAAD(State nextState, boolean isDoFinal) + { + finishAAD3(nextState, isDoFinal); + } + + @Override + protected void init(byte[] key, byte[] iv) + { + npub = iv; + k = key; + Y = new byte[BlockSize]; + input = new byte[16]; + offset = new byte[8]; + } + + @Override + protected void processFinalBlock(byte[] output, int outOff) + { + int len = dataOperator.getLen() - (forEncryption ? 0 : MAC_SIZE); + if (len != 0) + { + /* full block: offset = 3*offset */ + /* empty data / partial block: offset = 3^2*offset */ + triple_half_block(offset); + if ((len & 15) != 0) + { + triple_half_block(offset); + } + /* last block */ + /* C[m] = Y[m+a-1] + M[m]*/ + /* X[a+m] = M[m] + G(Y[m+a-1]) + offset */ + Bytes.xor(m_bufPos, Y, m_buf, 0, output, outOff); + if (forEncryption) + { + pho1(input, Y, m_buf, 0, m_bufPos); + } + else + { + pho1(input, Y, output, outOff, m_bufPos); + } + Bytes.xorTo(8, offset, input); + /* T = E(X[m+a]) */ + giftb128(input, k, Y); + } + System.arraycopy(Y, 0, mac, 0, BlockSize); + } + + @Override + protected void processBufferEncrypt(byte[] inputM, int inOff, byte[] output, int outOff) + { + /* Process M */ + /* full byte[]s */ + double_half_block(offset); + /* C[i] = Y[i+a-1] + M[i]*/ + /* X[i] = M[i] + G(Y[i+a-1]) + offset */ + Bytes.xor(BlockSize, Y, inputM, inOff, output, outOff); + pho1(input, Y, inputM, inOff, BlockSize); + Bytes.xorTo(8, offset, input); + /* Y[i] = E(X[i+a]) */ + giftb128(input, k, Y); + } + + @Override + protected void processBufferDecrypt(byte[] inputM, int inOff, byte[] output, int outOff) + { + /* Process M */ + /* full byte[]s */ + double_half_block(offset); + /* C[i] = Y[i+a-1] + M[i]*/ + /* X[i] = M[i] + G(Y[i+a-1]) + offset */ + Bytes.xor(BlockSize, Y, inputM, inOff, output, outOff); + pho1(input, Y, output, outOff, BlockSize); + Bytes.xorTo(8, offset, input); + /* Y[i] = E(X[i+a]) */ + giftb128(input, k, Y); + } + + protected void reset(boolean clearMac) + { + super.reset(clearMac); + /*nonce is 128-bit*/ + System.arraycopy(npub, 0, input, 0, IV_SIZE); + giftb128(input, k, Y); + System.arraycopy(Y, 0, offset, 0, 8); + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java index f15056de89..d81fd59045 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128AEADEngine.java @@ -1,10 +1,6 @@ package org.bouncycastle.crypto.engines; -import java.io.ByteArrayOutputStream; - -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.OutputLengthException; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; /** @@ -24,74 +20,40 @@ public class Grain128AEADEngine */ private byte[] workingKey; private byte[] workingIV; - private int[] lfsr; - private int[] nfsr; - private int[] authAcc; - private int[] authSr; - - private boolean initialised = false; - private boolean aadFinished = false; - private final ErasableOutputStream aadData = new ErasableOutputStream(); + private final int[] lfsr; + private final int[] nfsr; + private final int[] authAcc; + private final int[] authSr; public Grain128AEADEngine() { - algorithmName = "Grain-128AEAD"; + algorithmName = "Grain-128 AEAD"; KEY_SIZE = 16; IV_SIZE = 12; MAC_SIZE = 8; + lfsr = new int[STATE_SIZE]; + nfsr = new int[STATE_SIZE]; + authAcc = new int[2]; + authSr = new int[2]; + setInnerMembers(ProcessingBufferType.Immediate, AADOperatorType.Stream, DataOperatorType.StreamCipher); } /** * Initialize a Grain-128AEAD cipher. - * - * @throws IllegalArgumentException If the params argument is inappropriate. */ protected void init(byte[] key, byte[] iv) throws IllegalArgumentException { - /* - * Grain encryption and decryption is completely symmetrical, so the - * 'forEncryption' is irrelevant. - */ - /* * Initialize variables. */ workingIV = new byte[16]; workingKey = key; - lfsr = new int[STATE_SIZE]; - nfsr = new int[STATE_SIZE]; - authAcc = new int[2]; - authSr = new int[2]; - System.arraycopy(iv, 0, workingIV, 0, IV_SIZE); - - reset(); - } - - /** - * 320 clocks initialization phase. - */ - private void initGrain() - { - for (int i = 0; i < 320; ++i) - { - int output = getOutput(); - nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0] ^ output) & 1); - lfsr = shift(lfsr, (getOutputLFSR() ^ output) & 1); - } - for (int quotient = 0; quotient < 8; ++quotient) - { - for (int remainder = 0; remainder < 8; ++remainder) - { - int output = getOutput(); - nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0] ^ output ^ ((workingKey[quotient]) >> remainder)) & 1); - lfsr = shift(lfsr, (getOutputLFSR() ^ output ^ ((workingKey[quotient + 8]) >> remainder)) & 1); - } - } - initGrain(authAcc); - initGrain(authSr); - initialised = true; + workingIV[12] = (byte)0xFF; + workingIV[13] = (byte)0xFF; + workingIV[14] = (byte)0xFF; + workingIV[15] = (byte)0x7F; } private void initGrain(int[] auth) @@ -100,10 +62,7 @@ private void initGrain(int[] auth) { for (int remainder = 0; remainder < 32; ++remainder) { - int output = getOutput(); - nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1); - lfsr = shift(lfsr, (getOutputLFSR()) & 1); - auth[quotient] |= output << remainder; + auth[quotient] |= getByteKeyStream() << remainder; } } } @@ -196,252 +155,174 @@ private int getOutput() } /** - * Shift array 1 bit and add val to index.length - 1. + * Shift array 1 bit and add val to index - 1. * * @param array The array to shift. * @param val The value to shift in. - * @return The shifted array with val added to index.length - 1. */ - private int[] shift(int[] array, int val) + private void shift(int[] array, int val) { array[0] = (array[0] >>> 1) | (array[1] << 31); array[1] = (array[1] >>> 1) | (array[2] << 31); array[2] = (array[2] >>> 1) | (array[3] << 31); array[3] = (array[3] >>> 1) | (val << 31); - return array; } - /** - * Set keys, reset cipher. - * - * @param keyBytes The key. - * @param ivBytes The IV. - */ - private void setKey(byte[] keyBytes, byte[] ivBytes) + private void shift() { - ivBytes[12] = (byte)0xFF; - ivBytes[13] = (byte)0xFF; - ivBytes[14] = (byte)0xFF; - ivBytes[15] = (byte)0x7F; - workingKey = keyBytes; - workingIV = ivBytes; - - /* - * Load NFSR and LFSR - */ - Pack.littleEndianToInt(workingKey, 0, nfsr); - Pack.littleEndianToInt(workingIV, 0, lfsr); + shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1); + shift(lfsr, (getOutputLFSR()) & 1); } - public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) - throws DataLengthException + protected void reset(boolean clearMac) { - if (!initialised) - { - throw new IllegalStateException(getAlgorithmName() + " not initialised"); - } - - if (!aadFinished) - { - doProcessAADBytes(aadData.getBuf(), aadData.size()); - aadFinished = true; - } - - if ((inOff + len) > input.length) + super.reset(clearMac); + Pack.littleEndianToInt(workingKey, 0, nfsr); + Pack.littleEndianToInt(workingIV, 0, lfsr); + Arrays.clear(authAcc); + Arrays.clear(authSr); + int output; + // 320 clocks initialization phase. + for (int i = 0; i < 320; ++i) { - throw new DataLengthException("input buffer too short"); + output = getOutput(); + shift(nfsr, (getOutputNFSR() ^ lfsr[0] ^ output) & 1); + shift(lfsr, (getOutputLFSR() ^ output) & 1); } - - if ((outOff + len) > output.length) + for (int quotient = 0; quotient < 8; ++quotient) { - throw new OutputLengthException("output buffer too short"); + for (int remainder = 0; remainder < 8; ++remainder) + { + output = getOutput(); + shift(nfsr, (getOutputNFSR() ^ lfsr[0] ^ output ^ ((workingKey[quotient]) >> remainder)) & 1); + shift(lfsr, (getOutputLFSR() ^ output ^ ((workingKey[quotient + 8]) >> remainder)) & 1); + } } - getKeyStream(input, inOff, len, output, outOff); - return len; + initGrain(authAcc); + initGrain(authSr); } - protected void reset(boolean clearMac) + private void updateInternalState(int mask) { - this.aadData.reset(); - this.aadFinished = false; - - setKey(workingKey, workingIV); - initGrain(); - super.reset(clearMac); + mask = -mask; + authAcc[0] ^= authSr[0] & mask; + authAcc[1] ^= authSr[1] & mask; + mask = getByteKeyStream(); + authSr[0] = (authSr[0] >>> 1) | (authSr[1] << 31); + authSr[1] = (authSr[1] >>> 1) | (mask << 31); } - private void getKeyStream(byte[] input, int inOff, int len, byte[] ciphertext, int outOff) + public int getUpdateOutputSize(int len) { - for (int i = 0; i < len; ++i) - { - byte cc = 0, input_i = input[inOff + i]; - for (int j = 0; j < 8; ++j) - { - int output = getOutput(); - nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1); - lfsr = shift(lfsr, (getOutputLFSR()) & 1); - - int input_i_j = (input_i >> j) & 1; - cc |= (input_i_j ^ output) << j; - - updateInternalState(input_i_j); - } - ciphertext[outOff + i] = cc; - } - + return getTotalBytesForUpdate(len); } - private void updateInternalState(int input_i_j) + @Override + protected void finishAAD(State nextState, boolean isDoFinal) { - int mask = -input_i_j; - authAcc[0] ^= authSr[0] & mask; - authAcc[1] ^= authSr[1] & mask; - - authShift(getOutput()); - nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1); - lfsr = shift(lfsr, (getOutputLFSR()) & 1); + finishAAD1(nextState); } - public void processAADByte(byte in) + @Override + protected void processFinalBlock(byte[] output, int outOff) { - if (aadFinished) - { - throw new IllegalStateException("associated data must be added before plaintext/ciphertext"); - } - aadData.write(in); + authAcc[0] ^= authSr[0]; + authAcc[1] ^= authSr[1]; + Pack.intToLittleEndian(authAcc, mac, 0); } - public void processAADBytes(byte[] input, int inOff, int len) + @Override + protected void processBufferAAD(byte[] input, int inOff) { - if (aadFinished) - { - throw new IllegalStateException("associated data must be added before plaintext/ciphertext"); - } - aadData.write(input, inOff, len); } - private void doProcessAADBytes(byte[] input, int len) + @Override + protected void processFinalAAD() { - byte[] ader; - int aderlen; - //encodeDer + // Encode(ad length) denotes the message length encoded in the DER format. + + int len = aadOperator.getLen(); + byte[] input = ((StreamAADOperator)aadOperator).getBytes(); + + // Need up to 5 bytes for the DER length as an 'int' + byte[] ader = new byte[5]; + + int pos; if (len < 128) { - ader = new byte[1 + len]; - ader[0] = (byte)len; - aderlen = 0; + pos = ader.length - 1; + ader[pos] = (byte)len; } else { - // aderlen is the highest bit position divided by 8 - aderlen = len_length(len); - ader = new byte[1 + aderlen + len]; - ader[0] = (byte)(0x80 | aderlen); - int tmp = len; - for (int i = 0; i < aderlen; ++i) - { - ader[1 + i] = (byte)tmp; - tmp >>>= 8; - } - } - for (int i = 0; i < len; ++i) - { - ader[1 + aderlen + i] = input[i]; - } + pos = ader.length; - for (int i = 0; i < ader.length; ++i) - { - byte ader_i = ader[i]; - for (int j = 0; j < 8; ++j) + int dl = len; + do { - nfsr = shift(nfsr, (getOutputNFSR() ^ lfsr[0]) & 1); - lfsr = shift(lfsr, (getOutputLFSR()) & 1); - - int ader_i_j = (ader_i >> j) & 1; - - updateInternalState(ader_i_j); + ader[--pos] = (byte)dl; + dl >>>= 8; } - } - } + while (dl != 0); - private void accumulate() - { - authAcc[0] ^= authSr[0]; - authAcc[1] ^= authSr[1]; - } + int count = ader.length - pos; + ader[--pos] = (byte)(0x80 | count); + } - private void authShift(int val) - { - authSr[0] = (authSr[0] >>> 1) | (authSr[1] << 31); - authSr[1] = (authSr[1] >>> 1) | (val << 31); + absorbAadData(ader, pos, ader.length - pos); + absorbAadData(input, 0, len); } - public int doFinal(byte[] out, int outOff) - throws IllegalStateException, InvalidCipherTextException + private void absorbAadData(byte[] buf, int off, int len) { - if (!aadFinished) + for (int i = 0; i < len; ++i) { - doProcessAADBytes(aadData.getBuf(), aadData.size()); - aadFinished = true; + byte b = buf[off + i]; + for (int j = 0; j < 8; ++j) + { + shift(); + updateInternalState((b >> j) & 1); + } } - - accumulate(); - - this.mac = Pack.intToLittleEndian(authAcc); - - System.arraycopy(mac, 0, out, outOff, mac.length); - - reset(false); - - return mac.length; - } - - public int getUpdateOutputSize(int len) - { - return len; } - public int getOutputSize(int len) + private int getByteKeyStream() { - //the last 8 bytes are from AD - return len + 8; + int rlt = getOutput(); + shift(); + return rlt; } - private static int len_length(int v) + @Override + protected void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff) { - if ((v & 0xff) == v) - { - return 1; - } - if ((v & 0xffff) == v) - { - return 2; - } - if ((v & 0xffffff) == v) + int len = dataOperator.getLen(); + for (int i = 0; i < len; ++i) { - return 3; + byte cc = 0, input_i = input[inOff + i]; + for (int j = 0; j < 8; ++j) + { + int input_i_j = (input_i >> j) & 1; + cc |= (input_i_j ^ getByteKeyStream()) << j; + updateInternalState(input_i_j); + } + output[outOff + i] = cc; } - - return 4; } - private static final class ErasableOutputStream - extends ByteArrayOutputStream + @Override + protected void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff) { - public ErasableOutputStream() - { - } - - public byte[] getBuf() + int len = dataOperator.getLen(); + for (int i = 0; i < len; ++i) { - return buf; + byte cc = 0, input_i = input[inOff + i]; + for (int j = 0; j < 8; ++j) + { + cc |= (((input_i >> j) & 1) ^ getByteKeyStream()) << j; + updateInternalState((cc >> j) & 1); + } + output[outOff + i] = cc; } - -// public void erase() -// { -// Arrays.fill(this.buf, (byte)0); -// // this for JVM compatibility -// this.reset(); -// } } } diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128Engine.java b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128Engine.java index b4eb8b0a69..819ad06f93 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/Grain128Engine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/Grain128Engine.java @@ -188,7 +188,7 @@ private int getOutput() int s60 = lfsr[1] >>> 28 | lfsr[2] << 4; int s79 = lfsr[2] >>> 15 | lfsr[3] << 17; int s93 = lfsr[2] >>> 29 | lfsr[3] << 3; - int s94 = lfsr[2] >>> 31 | lfsr[3] << 1; + int s94 = lfsr[2] >>> 30 | lfsr[3] << 2; return b12 & s8 ^ s13 & s20 ^ b95 & s42 ^ s60 & s79 ^ b12 & b95 & s94 ^ s93 ^ b2 ^ b15 ^ b36 ^ b45 ^ b64 ^ b73 ^ b89; diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java index 52d2f841a3..5a404540d9 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/ISAPEngine.java @@ -1,6 +1,7 @@ package org.bouncycastle.crypto.engines; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Bytes; import org.bouncycastle.util.Pack; /** @@ -11,7 +12,7 @@ *

    */ public class ISAPEngine - extends AEADBufferBaseEngine + extends AEADBaseEngine { public enum IsapType @@ -24,9 +25,7 @@ public enum IsapType public ISAPEngine(IsapType isapType) { - KEY_SIZE = 16; - IV_SIZE = 16; - MAC_SIZE = 16; + KEY_SIZE = IV_SIZE = MAC_SIZE = 16; switch (isapType) { case ISAP_A_128A: @@ -45,16 +44,18 @@ public ISAPEngine(IsapType isapType) ISAPAEAD = new ISAPAEAD_K_128(); algorithmName = "ISAP-K-128 AEAD"; break; + default: + throw new IllegalArgumentException("Incorrect ISAP parameter"); } AADBufferSize = BlockSize; - m_aad = new byte[AADBufferSize]; + setInnerMembers(ProcessingBufferType.Immediate, AADOperatorType.Default, DataOperatorType.Counter); } - final int ISAP_STATE_SZ = 40; + private static final int ISAP_STATE_SZ = 40; private byte[] k; private byte[] npub; private int ISAP_rH; - private ISAP_AEAD ISAPAEAD; + private final ISAP_AEAD ISAPAEAD; private interface ISAP_AEAD { @@ -66,8 +67,6 @@ private interface ISAP_AEAD void absorbFinalAADBlock(); - void swapInternalState(); - void processEncBlock(byte[] input, int inOff, byte[] output, int outOff); void processEncFinalBlock(byte[] output, int outOff); @@ -83,12 +82,15 @@ private abstract class ISAPAEAD_A protected long ISAP_IV1_64; protected long ISAP_IV2_64; protected long ISAP_IV3_64; - protected long x0, x1, x2, x3, x4, t0, t1, t2, t3, t4, macx0, macx1, macx2, macx3, macx4; + AsconPermutationFriend.AsconPermutation p; + AsconPermutationFriend.AsconPermutation mac; public ISAPAEAD_A() { ISAP_rH = 64; BlockSize = (ISAP_rH + 7) >> 3; + p = new AsconPermutationFriend.AsconPermutation(); + mac = new AsconPermutationFriend.AsconPermutation(); } public void init() @@ -97,196 +99,94 @@ public void init() k64 = new long[getLongSize(k.length)]; Pack.bigEndianToLong(npub, 0, npub64); Pack.bigEndianToLong(k, 0, k64); - //reset(); } - protected abstract void PX1(); + protected abstract void PX1(AsconPermutationFriend.AsconPermutation p); - protected abstract void PX2(); - - public void swapInternalState() - { - t0 = x0; - t1 = x1; - t2 = x2; - t3 = x3; - t4 = x4; - x0 = macx0; - x1 = macx1; - x2 = macx2; - x3 = macx3; - x4 = macx4; - macx0 = t0; - macx1 = t1; - macx2 = t2; - macx3 = t3; - macx4 = t4; - } + protected abstract void PX2(AsconPermutationFriend.AsconPermutation p); public void absorbMacBlock(byte[] input, int inOff) { - x0 ^= Pack.bigEndianToLong(input, inOff); - P12(); + mac.x0 ^= Pack.bigEndianToLong(input, inOff); + mac.p(12); } public void absorbFinalAADBlock() { - if (m_aadPos == AADBufferSize) + for (int i = 0; i < m_aadPos; ++i) { - absorbMacBlock(m_aad, 0); - m_aadPos = 0; + mac.x0 ^= (m_aad[i] & 0xFFL) << ((7 - i) << 3); } - else - { - for (int i = 0; i < m_aadPos; ++i) - { - x0 ^= (m_aad[i] & 0xFFL) << ((7 - i) << 3); - } - } - x0 ^= 0x80L << ((7 - m_aadPos) << 3); - P12(); - x4 ^= 1L; + mac.x0 ^= 0x80L << ((7 - m_aadPos) << 3); + mac.p(12); + mac.x4 ^= 1L; } public void processMACFinal(byte[] input, int inOff, int len, byte[] tag) { - if (len == BlockSize) - { - absorbMacBlock(input, inOff); - len = 0; - } - else + for (int i = 0; i < len; ++i) { - for (int i = 0; i < len; ++i) - { - x0 ^= (input[inOff++] & 0xFFL) << ((7 - i) << 3); - } + mac.x0 ^= (input[inOff++] & 0xFFL) << ((7 - i) << 3); } - x0 ^= 0x80L << ((7 - len) << 3); - P12(); + mac.x0 ^= 0x80L << ((7 - len) << 3); + mac.p(12); // Derive K* - Pack.longToBigEndian(x0, tag, 0); - Pack.longToBigEndian(x1, tag, 8); - long tmp_x2 = x2, tmp_x3 = x3, tmp_x4 = x4; - isap_rk(ISAP_IV2_64, tag, KEY_SIZE); - x2 = tmp_x2; - x3 = tmp_x3; - x4 = tmp_x4; + Pack.longToBigEndian(mac.x0, tag, 0); + Pack.longToBigEndian(mac.x1, tag, 8); + long tmp_x2 = mac.x2, tmp_x3 = mac.x3, tmp_x4 = mac.x4; + isap_rk(mac, ISAP_IV2_64, tag, KEY_SIZE); + mac.x2 = tmp_x2; + mac.x3 = tmp_x3; + mac.x4 = tmp_x4; // Squeeze tag - P12(); - Pack.longToBigEndian(x0, tag, 0); - Pack.longToBigEndian(x1, tag, 8); + mac.p(12); + Pack.longToBigEndian(mac.x0, tag, 0); + Pack.longToBigEndian(mac.x1, tag, 8); } - public void isap_rk(long iv64, byte[] y, int ylen) + private void isap_rk(AsconPermutationFriend.AsconPermutation p, long iv64, byte[] y, int ylen) { // Init state - x0 = k64[0]; - x1 = k64[1]; - x2 = iv64; - x3 = x4 = 0; - P12(); + p.set(k64[0], k64[1], iv64, 0L, 0L); + p.p(12); // Absorb Y for (int i = 0; i < (ylen << 3) - 1; i++) { - x0 ^= ((((y[i >>> 3] >>> (7 - (i & 7))) & 0x01) << 7) & 0xFFL) << 56; - PX2(); + p.x0 ^= ((((y[i >>> 3] >>> (7 - (i & 7))) & 0x01) << 7) & 0xFFL) << 56; + PX2(p); } - x0 ^= (((y[ylen - 1]) & 0x01L) << 7) << 56; - P12(); + p.x0 ^= (((y[ylen - 1]) & 0x01L) << 7) << 56; + p.p(12); } public void processEncBlock(byte[] input, int inOff, byte[] output, int outOff) { - long m64 = Pack.littleEndianToLong(input, inOff); - long c64 = U64BIG(x0) ^ m64; - PX1(); - Pack.longToLittleEndian(c64, output, outOff); + Pack.longToBigEndian(Pack.bigEndianToLong(input, inOff) ^ p.x0, output, outOff); + PX1(p); } public void processEncFinalBlock(byte[] output, int outOff) { - if (m_bufPos == BlockSize) - { - processEncBlock(m_buf, 0, output, outOff); - } - else - { - /* Encrypt final m block */ - byte[] xo = Pack.longToLittleEndian(x0); - int mlen = m_bufPos; - while (mlen > 0) - { - output[outOff + mlen - 1] = (byte)(xo[BlockSize - mlen] ^ m_buf[--mlen]); - } - } + /* Encrypt final m block */ + byte[] xo = Pack.longToLittleEndian(p.x0); + Bytes.xor(m_bufPos, xo, BlockSize - m_bufPos, m_buf, 0, output, outOff); } public void reset() { // Init state - isap_rk(ISAP_IV3_64, npub, IV_SIZE); - x3 = npub64[0]; - x4 = npub64[1]; - PX1(); - swapInternalState(); + isap_rk(p, ISAP_IV3_64, npub, IV_SIZE); + p.x3 = npub64[0]; + p.x4 = npub64[1]; + PX1(p); // Init State for mac - x0 = npub64[0]; - x1 = npub64[1]; - x2 = ISAP_IV1_64; - x3 = x4 = 0; - P12(); + mac.set(npub64[0], npub64[1], ISAP_IV1_64, 0L, 0L); + mac.p(12); } private int getLongSize(int x) { - return (x >>> 3) + ((x & 7) != 0 ? 1 : 0); - } - - private long ROTR(long x, long n) - { - return (x >>> n) | (x << (64 - n)); - } - - protected long U64BIG(long x) - { - return ((ROTR(x, 8) & (0xFF000000FF000000L)) | (ROTR(x, 24) & (0x00FF000000FF0000L)) | - (ROTR(x, 40) & (0x0000FF000000FF00L)) | (ROTR(x, 56) & (0x000000FF000000FFL))); - } - - protected void ROUND(long C) - { - t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C)); - t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3)); - t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4); - t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4)); - t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1); - x0 = t0 ^ ROTR(t0, 19) ^ ROTR(t0, 28); - x1 = t1 ^ ROTR(t1, 39) ^ ROTR(t1, 61); - x2 = ~(t2 ^ ROTR(t2, 1) ^ ROTR(t2, 6)); - x3 = t3 ^ ROTR(t3, 10) ^ ROTR(t3, 17); - x4 = t4 ^ ROTR(t4, 7) ^ ROTR(t4, 41); - } - - public void P12() - { - ROUND(0xf0); - ROUND(0xe1); - ROUND(0xd2); - ROUND(0xc3); - ROUND(0xb4); - ROUND(0xa5); - P6(); - } - - protected void P6() - { - ROUND(0x96); - ROUND(0x87); - ROUND(0x78); - ROUND(0x69); - ROUND(0x5a); - ROUND(0x4b); + return ((x + 7) >>> 3); } } @@ -300,14 +200,14 @@ public ISAPAEAD_A_128A() ISAP_IV3_64 = 252271952373286412L; } - protected void PX1() + protected void PX1(AsconPermutationFriend.AsconPermutation p) { - P6(); + p.p(6); } - protected void PX2() + protected void PX2(AsconPermutationFriend.AsconPermutation p) { - ROUND(0x4b); + p.round(0x4bL); } } @@ -321,21 +221,21 @@ public ISAPAEAD_A_128() ISAP_IV3_64 = 252271952374008844L; } - protected void PX1() + protected void PX1(AsconPermutationFriend.AsconPermutation p) { - P12(); + p.p(12); } - protected void PX2() + protected void PX2(AsconPermutationFriend.AsconPermutation p) { - P12(); + p.p(12); } } private abstract class ISAPAEAD_K implements ISAP_AEAD { - final int ISAP_STATE_SZ_CRYPTO_NPUBBYTES = ISAP_STATE_SZ - IV_SIZE; + protected final int ISAP_STATE_SZ_CRYPTO_NPUBBYTES = ISAP_STATE_SZ - IV_SIZE; protected short[] ISAP_IV1_16; protected short[] ISAP_IV2_16; protected short[] ISAP_IV3_16; @@ -359,10 +259,9 @@ public ISAPAEAD_K() public void init() { k16 = new short[k.length >> 1]; - byteToShort(k, k16, k16.length); + Pack.littleEndianToShort(k, 0, k16, 0, k16.length); iv16 = new short[npub.length >> 1]; - byteToShort(npub, iv16, iv16.length); - //reset(); + Pack.littleEndianToShort(npub, 0, iv16, 0, iv16.length); } public void reset() @@ -373,24 +272,10 @@ public void reset() System.arraycopy(iv16, 0, SX, 17, 8); PermuteRoundsKX(SX, E, C); // Init state for mac - swapInternalState(); - Arrays.fill(SX, 12, 25, (short)0); - System.arraycopy(iv16, 0, SX, 0, 8); - System.arraycopy(ISAP_IV1_16, 0, SX, 8, 4); - PermuteRoundsHX(SX, E, C); - } - - public void swapInternalState() - { - short[] tmp = SX; - SX = macSX; - macSX = tmp; - tmp = E; - E = macE; - macE = tmp; - tmp = C; - C = macC; - macC = tmp; + Arrays.fill(macSX, 12, 25, (short)0); + System.arraycopy(iv16, 0, macSX, 0, 8); + System.arraycopy(ISAP_IV1_16, 0, macSX, 8, 4); + PermuteRoundsHX(macSX, macE, macC); } protected abstract void PermuteRoundsHX(short[] SX, short[] E, short[] C); @@ -401,29 +286,21 @@ public void swapInternalState() public void absorbMacBlock(byte[] input, int inOff) { - byteToShortXor(input, inOff, SX, BlockSize >> 1); - PermuteRoundsHX(SX, E, C); + byteToShortXor(input, inOff, macSX, BlockSize >> 1); + PermuteRoundsHX(macSX, macE, macC); } public void absorbFinalAADBlock() { - if (m_aadPos == AADBufferSize) + for (int i = 0; i < m_aadPos; i++) { - absorbMacBlock(m_aad, 0); - m_aadPos = 0; + macSX[i >> 1] ^= (m_aad[i] & 0xFF) << ((i & 1) << 3); } - else - { - for (int i = 0; i < m_aadPos; i++) - { - SX[i >> 1] ^= (m_aad[i] & 0xFF) << ((i & 1) << 3); - } - } - SX[m_aadPos >> 1] ^= 0x80 << ((m_aadPos & 1) << 3); - PermuteRoundsHX(SX, E, C); + macSX[m_aadPos >> 1] ^= 0x80 << ((m_aadPos & 1) << 3); + PermuteRoundsHX(macSX, macE, macC); // Domain seperation - SX[24] ^= 0x0100; + macSX[24] ^= 0x0100; } public void isap_rk(short[] iv16, byte[] y, int ylen, short[] out16, int outlen, short[] C) @@ -448,27 +325,20 @@ public void isap_rk(short[] iv16, byte[] y, int ylen, short[] out16, int outlen, public void processMACFinal(byte[] input, int inOff, int len, byte[] tag) { - if (len == BlockSize) - { - absorbMacBlock(input, inOff); - len = 0; - } - else + // Absorb C final block + for (int i = 0; i < len; i++) { - // Absorb C final block - for (int i = 0; i < len; i++) - { - SX[i >> 1] ^= (input[inOff++] & 0xFF) << ((i & 1) << 3); - } + macSX[i >> 1] ^= (input[inOff++] & 0xFF) << ((i & 1) << 3); } - SX[len >> 1] ^= 0x80 << ((len & 1) << 3); - PermuteRoundsHX(SX, E, C); + + macSX[len >> 1] ^= 0x80 << ((len & 1) << 3); + PermuteRoundsHX(macSX, macE, macC); // Derive K* - shortToByte(SX, tag); - isap_rk(ISAP_IV2_16, tag, KEY_SIZE, SX, KEY_SIZE, C); + Pack.shortToLittleEndian(macSX, 0, 8, tag, 0); + isap_rk(ISAP_IV2_16, tag, KEY_SIZE, macSX, KEY_SIZE, macC); // Squeeze tag - PermuteRoundsHX(SX, E, C); - shortToByte(SX, tag); + PermuteRoundsHX(macSX, macE, macC); + Pack.shortToLittleEndian(macSX, 0, 8, tag, 0); } public void processEncBlock(byte[] input, int inOff, byte[] output, int outOff) @@ -483,8 +353,7 @@ public void processEncBlock(byte[] input, int inOff, byte[] output, int outOff) public void processEncFinalBlock(byte[] output, int outOff) { // Squeeze full or partial lane and stop - int len = m_bufPos; - for (int i = 0; i < len; ++i) + for (int i = 0; i < m_bufPos; ++i) { output[outOff++] = (byte)((SX[i >> 1] >>> ((i & 1) << 3)) ^ m_buf[i]); } @@ -498,22 +367,6 @@ private void byteToShortXor(byte[] input, int inOff, short[] output, int outLen) } } - private void byteToShort(byte[] input, short[] output, int outLen) - { - for (int i = 0; i < outLen; ++i) - { - output[i] = Pack.littleEndianToShort(input, (i << 1)); - } - } - - private void shortToByte(short[] input, byte[] output) - { - for (int i = 0; i < 8; ++i) - { - Pack.shortToLittleEndian(input[i], output, (i << 1)); - } - } - protected void rounds12X(short[] SX, short[] E, short[] C) { prepareThetaX(SX, C); @@ -828,11 +681,7 @@ protected void init(byte[] key, byte[] iv) { npub = iv; k = key; - m_buf = new byte[BlockSize + (forEncryption ? 0 : MAC_SIZE)]; ISAPAEAD.init(); - initialised = true; - m_state = forEncryption ? State.EncInit : State.DecInit; - reset(); } protected void processBufferAAD(byte[] input, int inOff) @@ -842,61 +691,44 @@ protected void processBufferAAD(byte[] input, int inOff) protected void processFinalAAD() { - if (!aadFinished) - { - ISAPAEAD.absorbFinalAADBlock(); - ISAPAEAD.swapInternalState(); - m_aadPos = 0; - aadFinished = true; - } + ISAPAEAD.absorbFinalAADBlock(); + } + + @Override + protected void finishAAD(State nextState, boolean isDoFinal) + { + finishAAD3(nextState, isDoFinal); } - protected void processBuffer(byte[] input, int inOff, byte[] output, int outOff) + protected void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff) { - processFinalAAD(); ISAPAEAD.processEncBlock(input, inOff, output, outOff); - ISAPAEAD.swapInternalState(); - if (forEncryption) - { - ISAPAEAD.absorbMacBlock(output, outOff); - } - else - { - ISAPAEAD.absorbMacBlock(input, inOff); - } - ISAPAEAD.swapInternalState(); + ISAPAEAD.absorbMacBlock(output, outOff); + } + + protected void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff) + { + ISAPAEAD.processEncBlock(input, inOff, output, outOff); + ISAPAEAD.absorbMacBlock(input, inOff); } @Override protected void processFinalBlock(byte[] output, int outOff) { - processFinalAAD(); - int len = m_bufPos; - mac = new byte[MAC_SIZE]; ISAPAEAD.processEncFinalBlock(output, outOff); - ISAPAEAD.swapInternalState(); if (forEncryption) { - ISAPAEAD.processMACFinal(output, outOff, len, mac); + ISAPAEAD.processMACFinal(output, outOff, m_bufPos, mac); } else { - ISAPAEAD.processMACFinal(m_buf, 0, len, mac); + ISAPAEAD.processMACFinal(m_buf, 0, m_bufPos, mac); } } protected void reset(boolean clearMac) { - if (!initialised) - { - throw new IllegalStateException("Need call init function before encryption/decryption"); - } - Arrays.fill(m_buf, (byte)0); - Arrays.fill(m_aad, (byte)0); - ISAPAEAD.reset(); - m_bufPos = 0; - m_aadPos = 0; - aadFinished = false; super.reset(clearMac); + ISAPAEAD.reset(); } } diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java index 6a43f59890..29a299da8a 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/PhotonBeetleEngine.java @@ -1,6 +1,7 @@ package org.bouncycastle.crypto.engines; -import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.digests.PhotonBeetleDigest; +import org.bouncycastle.util.Bytes; /** * Photon-Beetle, @@ -11,7 +12,7 @@ */ public class PhotonBeetleEngine - extends AEADBufferBaseEngine + extends AEADBaseEngine { public enum PhotonBeetleParameters { @@ -23,14 +24,11 @@ public enum PhotonBeetleParameters private byte[] K; private byte[] N; private byte[] state; - private byte[][] state_2d; - private int aadLen; - private int messageLen; private final int RATE_INBYTES_HALF; private final int STATE_INBYTES; private final int LAST_THREE_BITS_OFFSET; - private final int D = 8; - private final byte[][] RC = { + private static final int D = 8; + private static final byte[][] RC = { {1, 3, 7, 14, 13, 11, 6, 12, 9, 2, 5, 10}, {0, 2, 6, 15, 12, 10, 7, 13, 8, 3, 4, 11}, {2, 0, 4, 13, 14, 8, 5, 15, 10, 1, 6, 9}, @@ -40,7 +38,7 @@ public enum PhotonBeetleParameters {13, 15, 11, 2, 1, 7, 10, 0, 5, 14, 9, 6}, {9, 11, 15, 6, 5, 3, 14, 4, 1, 10, 13, 2} }; - private final byte[][] MixColMatrix = { + private static final byte[][] MixColMatrix = { {2, 4, 2, 11, 2, 8, 5, 6}, {12, 9, 8, 13, 7, 7, 5, 2}, {4, 4, 13, 13, 9, 4, 13, 9}, @@ -51,13 +49,11 @@ public enum PhotonBeetleParameters {15, 1, 13, 10, 5, 10, 2, 3} }; - private final byte[] sbox = {12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2}; + private static final byte[] sbox = {12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2}; public PhotonBeetleEngine(PhotonBeetleParameters pbp) { - KEY_SIZE = 16; - IV_SIZE = 16; - MAC_SIZE = 16; + KEY_SIZE = IV_SIZE = MAC_SIZE = 16; int CAPACITY_INBITS = 0, RATE_INBITS = 0; switch (pbp) { @@ -75,9 +71,9 @@ public PhotonBeetleEngine(PhotonBeetleParameters pbp) int STATE_INBITS = RATE_INBITS + CAPACITY_INBITS; STATE_INBYTES = (STATE_INBITS + 7) >>> 3; LAST_THREE_BITS_OFFSET = (STATE_INBITS - ((STATE_INBYTES - 1) << 3) - 3); - initialised = false; algorithmName = "Photon-Beetle AEAD"; - m_aad = new byte[AADBufferSize]; + state = new byte[STATE_INBYTES]; + setInnerMembers(ProcessingBufferType.Buffered, AADOperatorType.Counter, DataOperatorType.Counter); } @Override @@ -86,54 +82,57 @@ protected void init(byte[] key, byte[] iv) { K = key; N = iv; - state = new byte[STATE_INBYTES]; - state_2d = new byte[D][D]; - mac = new byte[MAC_SIZE]; - initialised = true; - m_buf = new byte[BlockSize + (forEncryption ? 0 : MAC_SIZE)]; - m_state = forEncryption ? State.EncInit : State.DecInit; - reset(false); } protected void processBufferAAD(byte[] input, int inOff) { - PHOTON_Permutation(); - XOR(input, inOff, BlockSize); + photonPermutation(state); + Bytes.xorTo(BlockSize, input, inOff, state); } - protected void processBuffer(byte[] input, int inOff, byte[] output, int outOff) + @Override + protected void finishAAD(State nextState, boolean isDoFinal) { - PHOTON_Permutation(); - rhoohr(output, outOff, input, inOff, BlockSize); + finishAAD3(nextState, isDoFinal); } - @Override - public void processAADByte(byte input) + protected void processFinalAAD() { - aadLen++; - super.processAADByte(input); + int aadLen = aadOperator.getLen(); + if (aadLen != 0) + { + if (m_aadPos != 0) + { + photonPermutation(state); + Bytes.xorTo(m_aadPos, m_aad, state); + if (m_aadPos < BlockSize) + { + state[m_aadPos] ^= 0x01; // ozs + } + } + state[STATE_INBYTES - 1] ^= select(dataOperator.getLen() - (forEncryption ? 0 : MAC_SIZE) > 0, + ((aadLen % BlockSize) == 0), (byte)3, (byte)4) << LAST_THREE_BITS_OFFSET; + } } - @Override - public void processAADBytes(byte[] input, int inOff, int len) + protected void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff) { - aadLen += len; - super.processAADBytes(input, inOff, len); + rhoohr(output, outOff, input, inOff, BlockSize); + Bytes.xorTo(BlockSize, input, inOff, state); } - @Override - public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) - throws DataLengthException + protected void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff) { - messageLen += len; - return super.processBytes(input, inOff, len, output, outOff); + rhoohr(output, outOff, input, inOff, BlockSize); + Bytes.xorTo(BlockSize, output, outOff, state); } @Override protected void processFinalBlock(byte[] output, int outOff) { - int len = messageLen - (forEncryption ? 0 : MAC_SIZE); + int len = dataOperator.getLen() - (forEncryption ? 0 : MAC_SIZE); int bufferLen = m_bufPos;// - (forEncryption ? 0 : MAC_SIZE); + int aadLen = aadOperator.getLen(); if (aadLen != 0 || len != 0) { input_empty = false; @@ -144,69 +143,45 @@ protected void processFinalBlock(byte[] output, int outOff) { if (bufferLen != 0) { - PHOTON_Permutation(); rhoohr(output, outOff, m_buf, 0, bufferLen); - if(bufferLen < BlockSize) + if (forEncryption) + { + Bytes.xorTo(bufferLen, m_buf, state); + } + else + { + Bytes.xorTo(bufferLen, output, outOff, state); + } + if (bufferLen < BlockSize) { state[bufferLen] ^= 0x01; // ozs } } state[STATE_INBYTES - 1] ^= c1 << LAST_THREE_BITS_OFFSET; } - if (input_empty) + else if (input_empty) { state[STATE_INBYTES - 1] ^= 1 << LAST_THREE_BITS_OFFSET; } - PHOTON_Permutation(); - mac = new byte[MAC_SIZE]; + photonPermutation(state); System.arraycopy(state, 0, mac, 0, MAC_SIZE); } - protected void processFinalAAD() - { - if (!aadFinished) - { - if (aadLen != 0) - { - if (m_aadPos != 0) - { - PHOTON_Permutation(); - XOR(m_aad, 0, m_aadPos); - if (m_aadPos < BlockSize) - { - state[m_aadPos] ^= 0x01; // ozs - } - } - state[STATE_INBYTES - 1] ^= select(messageLen - (forEncryption ? 0 : MAC_SIZE) > 0, - ((aadLen % BlockSize) == 0), (byte)3, (byte)4) << LAST_THREE_BITS_OFFSET; - } - m_aadPos = 0; - aadFinished = true; - } - } - protected void reset(boolean clearMac) { - if (!initialised) - { - throw new IllegalArgumentException("Need call init function before encryption/decryption"); - } - bufferReset(); + super.reset(clearMac); input_empty = true; - aadLen = 0; - aadFinished = false; - messageLen = 0; System.arraycopy(K, 0, state, 0, K.length); System.arraycopy(N, 0, state, K.length, N.length); - super.reset(clearMac); } - private void PHOTON_Permutation() + private static void photonPermutation(byte[] state) { int i, j, k; int dq = 3; int dr = 7; int DSquare = 64; + byte[][] state_2d = new byte[D][D]; for (i = 0; i < DSquare; i++) { state_2d[i >>> dq][i & dr] = (byte)(((state[i >> 1] & 0xFF) >>> (4 * (i & 1))) & 0xf); @@ -290,37 +265,26 @@ private byte select(boolean condition1, boolean condition2, byte option3, byte o private void rhoohr(byte[] ciphertext, int outOff, byte[] plaintext, int inOff, int DBlen_inbytes) { - byte[] OuterState_part1_ROTR1 = state_2d[0]; + photonPermutation(state); + byte[] OuterState_part1_ROTR1 = new byte[D]; int i, loop_end = Math.min(DBlen_inbytes, RATE_INBYTES_HALF); for (i = 0; i < RATE_INBYTES_HALF - 1; i++) { OuterState_part1_ROTR1[i] = (byte)(((state[i] & 0xFF) >>> 1) | ((state[(i + 1)] & 1) << 7)); } OuterState_part1_ROTR1[RATE_INBYTES_HALF - 1] = (byte)(((state[i] & 0xFF) >>> 1) | ((state[0] & 1) << 7)); - i = 0; - while (i < loop_end) - { - ciphertext[i + outOff] = (byte)(state[i + RATE_INBYTES_HALF] ^ plaintext[i++ + inOff]); - } - while (i < DBlen_inbytes) - { - ciphertext[i + outOff] = (byte)(OuterState_part1_ROTR1[i - RATE_INBYTES_HALF] ^ plaintext[i++ + inOff]); - } - if (forEncryption) - { - XOR(plaintext, inOff, DBlen_inbytes); - } - else - { - XOR(ciphertext, outOff, DBlen_inbytes); - } + Bytes.xor(loop_end, state, RATE_INBYTES_HALF, plaintext, inOff, ciphertext, outOff); + Bytes.xor(DBlen_inbytes - loop_end, OuterState_part1_ROTR1, loop_end - RATE_INBYTES_HALF, plaintext, + inOff + loop_end, ciphertext, outOff + loop_end); } - private void XOR(byte[] in_right, int rOff, int iolen_inbytes) + public static void photonPermutation(PhotonBeetleDigest.Friend friend, byte[] state) { - for (int i = 0; i < iolen_inbytes; i++) + if (null == friend) { - state[i] ^= in_right[rOff++]; + throw new NullPointerException("This method is only for use by PhotonBeetleDigest"); } + + photonPermutation(state); } -} +} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java index 4ce1fccedd..36103654a1 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java @@ -28,7 +28,7 @@ public class RSABlindedEngine * initialise the RSA engine. * * @param forEncryption true if we are encrypting, false otherwise. - * @param param the necessary RSA key parameters. + * @param parameters the necessary RSA key parameters. */ public void init(boolean forEncryption, CipherParameters parameters) { diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java index cfc0913212..32274e6cd5 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java @@ -12,12 +12,15 @@ import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Properties; /** * this does your basic RSA algorithm. */ class RSACoreEngine { + static final String NO_LENSTRA_CHECK = "org.bouncycastle.rsa.no_lenstra_check"; + private RSAKeyParameters key; private boolean forEncryption; @@ -182,7 +185,7 @@ public BigInteger processBlock(BigInteger input) RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters)key; BigInteger e = crtKey.getPublicExponent(); - if (e != null) // can't apply fault-attack countermeasure without public exponent + if (e != null || Properties.isOverrideSet(NO_LENSTRA_CHECK)) // can't apply fault-attack countermeasure without public exponent { BigInteger p = crtKey.getP(); BigInteger q = crtKey.getQ(); @@ -206,15 +209,25 @@ public BigInteger processBlock(BigInteger input) // m = h * q + mQ m = h.multiply(q).add(mQ); - // defence against Arjen Lenstra’s CRT attack - BigInteger check = m.modPow(e, crtKey.getModulus()); - if (!check.equals(input)) + if (e != null) { - throw new IllegalStateException("RSA engine faulty decryption/signing detected"); + // defence against Arjen Lenstra’s CRT attack + BigInteger check = m.modPow(e, crtKey.getModulus()); + if (!check.equals(input)) + { + throw new IllegalStateException("RSA engine faulty decryption/signing detected"); + } } return m; } + else + { + if (key.getExponent() == null) + { + throw new IllegalStateException("null exponent, should \"org.bouncycastle.rsa.no_lenstra_check\" be enabled?"); + } + } } return input.modPow(key.getExponent(), key.getModulus()); diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java new file mode 100644 index 0000000000..06535cf482 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/engines/RomulusEngine.java @@ -0,0 +1,915 @@ +package org.bouncycastle.crypto.engines; + +import org.bouncycastle.crypto.digests.RomulusDigest; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Bytes; + +/** + * Romulus v1.3, based on the current round 3 submission, https://romulusae.github.io/romulus/ + * Reference C implementation: https://github.com/romulusae/romulus + * Specification: https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/romulus-spec-final.pdf + */ + +public class RomulusEngine + extends AEADBaseEngine +{ + public static class RomulusParameters + { + public static final int ROMULUS_M = 0; + public static final int ROMULUS_N = 1; + public static final int ROMULUS_T = 2; + + public static final RomulusParameters RomulusM = new RomulusParameters(ROMULUS_M); + public static final RomulusParameters RomulusN = new RomulusParameters(ROMULUS_N); + public static final RomulusParameters RomulusT = new RomulusParameters(ROMULUS_T); + + private final int ord; + + RomulusParameters(int ord) + { + this.ord = ord; + } + } + + private byte[] k; + private byte[] npub; + private static final int AD_BLK_LEN_HALF = 16; + private Instance instance; + private final byte[] CNT; + + // Packing of data is done as follows (state[i][j] stands for row i and column j): + // 0 1 2 3 + // 4 5 6 7 + // 8 9 10 11 + //12 13 14 15 + + // 8-bit Sbox + private static final byte[] sbox_8 = + { + (byte)0x65, (byte)0x4c, (byte)0x6a, (byte)0x42, (byte)0x4b, (byte)0x63, (byte)0x43, (byte)0x6b, (byte)0x55, + (byte)0x75, (byte)0x5a, (byte)0x7a, (byte)0x53, (byte)0x73, (byte)0x5b, (byte)0x7b, (byte)0x35, (byte)0x8c, + (byte)0x3a, (byte)0x81, (byte)0x89, (byte)0x33, (byte)0x80, (byte)0x3b, (byte)0x95, (byte)0x25, (byte)0x98, + (byte)0x2a, (byte)0x90, (byte)0x23, (byte)0x99, (byte)0x2b, (byte)0xe5, (byte)0xcc, (byte)0xe8, (byte)0xc1, + (byte)0xc9, (byte)0xe0, (byte)0xc0, (byte)0xe9, (byte)0xd5, (byte)0xf5, (byte)0xd8, (byte)0xf8, (byte)0xd0, + (byte)0xf0, (byte)0xd9, (byte)0xf9, (byte)0xa5, (byte)0x1c, (byte)0xa8, (byte)0x12, (byte)0x1b, (byte)0xa0, + (byte)0x13, (byte)0xa9, (byte)0x05, (byte)0xb5, (byte)0x0a, (byte)0xb8, (byte)0x03, (byte)0xb0, (byte)0x0b, + (byte)0xb9, (byte)0x32, (byte)0x88, (byte)0x3c, (byte)0x85, (byte)0x8d, (byte)0x34, (byte)0x84, (byte)0x3d, + (byte)0x91, (byte)0x22, (byte)0x9c, (byte)0x2c, (byte)0x94, (byte)0x24, (byte)0x9d, (byte)0x2d, (byte)0x62, + (byte)0x4a, (byte)0x6c, (byte)0x45, (byte)0x4d, (byte)0x64, (byte)0x44, (byte)0x6d, (byte)0x52, (byte)0x72, + (byte)0x5c, (byte)0x7c, (byte)0x54, (byte)0x74, (byte)0x5d, (byte)0x7d, (byte)0xa1, (byte)0x1a, (byte)0xac, + (byte)0x15, (byte)0x1d, (byte)0xa4, (byte)0x14, (byte)0xad, (byte)0x02, (byte)0xb1, (byte)0x0c, (byte)0xbc, + (byte)0x04, (byte)0xb4, (byte)0x0d, (byte)0xbd, (byte)0xe1, (byte)0xc8, (byte)0xec, (byte)0xc5, (byte)0xcd, + (byte)0xe4, (byte)0xc4, (byte)0xed, (byte)0xd1, (byte)0xf1, (byte)0xdc, (byte)0xfc, (byte)0xd4, (byte)0xf4, + (byte)0xdd, (byte)0xfd, (byte)0x36, (byte)0x8e, (byte)0x38, (byte)0x82, (byte)0x8b, (byte)0x30, (byte)0x83, + (byte)0x39, (byte)0x96, (byte)0x26, (byte)0x9a, (byte)0x28, (byte)0x93, (byte)0x20, (byte)0x9b, (byte)0x29, + (byte)0x66, (byte)0x4e, (byte)0x68, (byte)0x41, (byte)0x49, (byte)0x60, (byte)0x40, (byte)0x69, (byte)0x56, + (byte)0x76, (byte)0x58, (byte)0x78, (byte)0x50, (byte)0x70, (byte)0x59, (byte)0x79, (byte)0xa6, (byte)0x1e, + (byte)0xaa, (byte)0x11, (byte)0x19, (byte)0xa3, (byte)0x10, (byte)0xab, (byte)0x06, (byte)0xb6, (byte)0x08, + (byte)0xba, (byte)0x00, (byte)0xb3, (byte)0x09, (byte)0xbb, (byte)0xe6, (byte)0xce, (byte)0xea, (byte)0xc2, + (byte)0xcb, (byte)0xe3, (byte)0xc3, (byte)0xeb, (byte)0xd6, (byte)0xf6, (byte)0xda, (byte)0xfa, (byte)0xd3, + (byte)0xf3, (byte)0xdb, (byte)0xfb, (byte)0x31, (byte)0x8a, (byte)0x3e, (byte)0x86, (byte)0x8f, (byte)0x37, + (byte)0x87, (byte)0x3f, (byte)0x92, (byte)0x21, (byte)0x9e, (byte)0x2e, (byte)0x97, (byte)0x27, (byte)0x9f, + (byte)0x2f, (byte)0x61, (byte)0x48, (byte)0x6e, (byte)0x46, (byte)0x4f, (byte)0x67, (byte)0x47, (byte)0x6f, + (byte)0x51, (byte)0x71, (byte)0x5e, (byte)0x7e, (byte)0x57, (byte)0x77, (byte)0x5f, (byte)0x7f, (byte)0xa2, + (byte)0x18, (byte)0xae, (byte)0x16, (byte)0x1f, (byte)0xa7, (byte)0x17, (byte)0xaf, (byte)0x01, (byte)0xb2, + (byte)0x0e, (byte)0xbe, (byte)0x07, (byte)0xb7, (byte)0x0f, (byte)0xbf, (byte)0xe2, (byte)0xca, (byte)0xee, + (byte)0xc6, (byte)0xcf, (byte)0xe7, (byte)0xc7, (byte)0xef, (byte)0xd2, (byte)0xf2, (byte)0xde, (byte)0xfe, + (byte)0xd7, (byte)0xf7, (byte)0xdf, (byte)0xff + }; + + // Tweakey permutation + private static final byte[] TWEAKEY_P = {9, 15, 8, 13, 10, 14, 12, 11, 0, 1, 2, 3, 4, 5, 6, 7}; + + // round constants + private static final byte[] RC = { + 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3E, 0x3D, 0x3B, 0x37, 0x2F, + 0x1E, 0x3C, 0x39, 0x33, 0x27, 0x0E, 0x1D, 0x3A, 0x35, 0x2B, + 0x16, 0x2C, 0x18, 0x30, 0x21, 0x02, 0x05, 0x0B, 0x17, 0x2E, + 0x1C, 0x38, 0x31, 0x23, 0x06, 0x0D, 0x1B, 0x36, 0x2D, 0x1A + }; + + public RomulusEngine(RomulusParameters romulusParameters) + { + KEY_SIZE = IV_SIZE = MAC_SIZE = BlockSize = AADBufferSize = 16; + CNT = new byte[7]; + switch (romulusParameters.ord) + { + case RomulusParameters.ROMULUS_M: + algorithmName = "Romulus-M"; + instance = new RomulusM(); + break; + case RomulusParameters.ROMULUS_N: + algorithmName = "Romulus-N"; + instance = new RomulusN(); + break; + case RomulusParameters.ROMULUS_T: + algorithmName = "Romulus-T"; + AADBufferSize = 32; + instance = new RomulusT(); + break; + } + setInnerMembers(romulusParameters == RomulusParameters.RomulusN ? ProcessingBufferType.Buffered : ProcessingBufferType.Immediate, + AADOperatorType.Counter, + romulusParameters == RomulusParameters.RomulusM ? DataOperatorType.Stream : DataOperatorType.Counter); + } + + private interface Instance + { + void processFinalBlock(byte[] output, int outOff); + + void processBufferAAD(byte[] input, int inOff); + + void processFinalAAD(); + + void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff); + + void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff); + + void reset(); + } + + private class RomulusM + implements Instance + { + private final byte[] mac_s = new byte[16]; + private final byte[] mac_CNT = new byte[7]; + private final byte[] s = new byte[16]; + private int offset; + private boolean twist = true; + + public RomulusM() + { + } + + @Override + public void processFinalBlock(byte[] output, int outOff) + { + byte w = 48; + int adlen = aadOperator.getLen(); + int mlen = dataOperator.getLen() - (forEncryption ? 0 : MAC_SIZE); + byte[] m = ((StreamDataOperator)dataOperator).getBytes(); + int xlen, mOff = 0, mauth = outOff; + xlen = mlen; + if ((adlen & 31) == 0 && adlen != 0) + { + w ^= 8; + } + else if ((adlen & 31) < AD_BLK_LEN_HALF) + { + w ^= 2; + } + else if ((adlen & 31) != AD_BLK_LEN_HALF) + { + w ^= 10; + } + if ((mlen & 31) == 0 && mlen != 0) + { + w ^= 4; + } + else if ((mlen & 31) < AD_BLK_LEN_HALF) + { + w ^= 1; + } + else if ((mlen & 31) != AD_BLK_LEN_HALF) + { + w ^= 5; + } + if (forEncryption) + { + if ((w & 8) == 0) + { + byte[] Temp = new byte[16]; + int len8 = Math.min(xlen, AD_BLK_LEN_HALF); + xlen -= len8; + pad(m, mOff, Temp, AD_BLK_LEN_HALF, len8); + block_cipher(mac_s, k, Temp, 0, mac_CNT, (byte)44); + lfsr_gf56(mac_CNT); + mOff += len8; + } + else if (mlen == 0) + { + lfsr_gf56(mac_CNT); + } + while (xlen > 0) + { + offset = mOff; + xlen = ad_encryption(m, mOff, mac_s, k, xlen, mac_CNT); + mOff = offset; + } + block_cipher(mac_s, k, npub, 0, mac_CNT, w); + // Tag generation + g8A(mac_s, mac, 0); + mOff -= mlen; + } + else + { + System.arraycopy(m, mlen, mac, 0, MAC_SIZE); + } + reset_lfsr_gf56(CNT); + System.arraycopy(mac, 0, s, 0, AD_BLK_LEN_HALF); + if (mlen > 0) + { + block_cipher(s, k, npub, 0, CNT, (byte)36); + while (mlen > AD_BLK_LEN_HALF) + { + mlen = mlen - AD_BLK_LEN_HALF; + rho(m, mOff, output, outOff, s, AD_BLK_LEN_HALF); + outOff += AD_BLK_LEN_HALF; + mOff += AD_BLK_LEN_HALF; + lfsr_gf56(CNT); + block_cipher(s, k, npub, 0, CNT, (byte)36); + } + rho(m, mOff, output, outOff, s, mlen); + } + if (!forEncryption) + { + if ((w & 8) == 0) + { + byte[] Temp = new byte[16]; + int len8 = Math.min(xlen, AD_BLK_LEN_HALF); + xlen -= len8; + pad(output, mauth, Temp, AD_BLK_LEN_HALF, len8); + block_cipher(mac_s, k, Temp, 0, mac_CNT, (byte)44); + lfsr_gf56(mac_CNT); + mauth += len8; + } + else if (mlen == 0) + { + lfsr_gf56(mac_CNT); + } + while (xlen > 0) + { + offset = mauth; + xlen = ad_encryption(output, mauth, mac_s, k, xlen, mac_CNT); + mauth = offset; + } + block_cipher(mac_s, k, npub, 0, mac_CNT, w); + // Tag generation + g8A(mac_s, mac, 0); + System.arraycopy(m, dataOperator.getLen() - MAC_SIZE, m_buf, 0, MAC_SIZE); + m_bufPos = 0; + } + } + + int ad_encryption(byte[] A, int AOff, byte[] s, byte[] k, int adlen, byte[] CNT) + { + byte[] T = new byte[16]; + byte[] mp = new byte[16]; + int n = 16; + int len8; + len8 = Math.min(adlen, n); + adlen -= len8; + // Rho(S,A) pads an A block and XORs it to the internal state. + pad(A, AOff, mp, n, len8); + Bytes.xorTo(n, mp, s); + offset = AOff += len8; + lfsr_gf56(CNT); + if (adlen != 0) + { + len8 = Math.min(adlen, n); + adlen -= len8; + pad(A, AOff, T, n, len8); + offset = AOff + len8; + block_cipher(s, k, T, 0, CNT, (byte)44); + lfsr_gf56(CNT); + } + return adlen; + } + + @Override + public void processBufferAAD(byte[] input, int inOff) + { + if (twist) + { + Bytes.xorTo(MAC_SIZE, input, inOff, mac_s); + } + else + { + block_cipher(mac_s, k, input, inOff, mac_CNT, (byte)40); + } + twist = !twist; + lfsr_gf56(mac_CNT); + } + + @Override + public void processFinalAAD() + { + if (aadOperator.getLen() == 0) + { + // AD is an empty string + lfsr_gf56(mac_CNT); + } + else if (m_aadPos != 0) + { + Arrays.fill(m_aad, m_aadPos, BlockSize - 1, (byte)0); + m_aad[BlockSize - 1] = (byte)(m_aadPos & 0x0f); + if (twist) + { + Bytes.xorTo(BlockSize, m_aad, mac_s); + } + else + { + block_cipher(mac_s, k, m_aad, 0, mac_CNT, (byte)40); + } + lfsr_gf56(mac_CNT); + } + m_aadPos = 0; + m_bufPos = dataOperator.getLen(); + } + + @Override + public void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff) + { + } + + @Override + public void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff) + { + } + + @Override + public void reset() + { + Arrays.clear(s); + Arrays.clear(mac_s); + reset_lfsr_gf56(mac_CNT); + reset_lfsr_gf56(CNT); + twist = true; + } + } + + private class RomulusN + implements Instance + { + private final byte[] s; + boolean twist; + + public RomulusN() + { + s = new byte[AD_BLK_LEN_HALF]; + } + + @Override + public void processFinalBlock(byte[] output, int outOff) + { + int messegeLen = dataOperator.getLen() - (forEncryption ? 0 : MAC_SIZE); + if (messegeLen == 0) + { + lfsr_gf56(CNT); + block_cipher(s, k, npub, 0, CNT, (byte)0x15); + } + else if (m_bufPos != 0) + { + int len8 = Math.min(m_bufPos, AD_BLK_LEN_HALF); + rho(m_buf, 0, output, outOff, s, len8); + lfsr_gf56(CNT); + block_cipher(s, k, npub, 0, CNT, m_bufPos == AD_BLK_LEN_HALF ? (byte)0x14 : (byte)0x15); + } + g8A(s, mac, 0); + } + + @Override + public void processBufferAAD(byte[] input, int inOff) + { + if (twist) + { + Bytes.xorTo(AD_BLK_LEN_HALF, input, inOff, s); + } + else + { + block_cipher(s, k, input, inOff, CNT, (byte)0x08); + } + lfsr_gf56(CNT); + twist = !twist; + } + + @Override + public void processFinalAAD() + { + if (m_aadPos != 0) + { + byte[] mp = new byte[AD_BLK_LEN_HALF]; + int len8 = Math.min(m_aadPos, AD_BLK_LEN_HALF); + pad(m_aad, 0, mp, AD_BLK_LEN_HALF, len8); + if (twist) + { + Bytes.xorTo(AD_BLK_LEN_HALF, mp, s); + } + else + { + block_cipher(s, k, mp, 0, CNT, (byte)0x08); + } + lfsr_gf56(CNT); + } + if (aadOperator.getLen() == 0) + { + lfsr_gf56(CNT); + block_cipher(s, k, npub, 0, CNT, (byte)0x1a); + } + else if ((m_aadPos & 15) != 0) + { + block_cipher(s, k, npub, 0, CNT, (byte)0x1a); + } + else + { + block_cipher(s, k, npub, 0, CNT, (byte)0x18); + } + reset_lfsr_gf56(CNT); + } + + @Override + public void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff) + { + g8A(s, output, outOff); + for (int i = 0; i < AD_BLK_LEN_HALF; i++) + { + s[i] ^= input[i + inOff]; + output[i + outOff] ^= input[i + inOff]; + } + lfsr_gf56(CNT); + block_cipher(s, k, npub, 0, CNT, (byte)0x04); + } + + @Override + public void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff) + { + g8A(s, output, outOff); + for (int i = 0; i < AD_BLK_LEN_HALF; i++) + { + output[i + outOff] ^= input[i + inOff]; + s[i] ^= output[i + outOff]; + } + lfsr_gf56(CNT); + block_cipher(s, k, npub, 0, CNT, (byte)0x04); + } + + @Override + public void reset() + { + Arrays.clear(s); + reset_lfsr_gf56(CNT); + twist = true; + } + } + + private class RomulusT + implements Instance + { + private final byte[] h = new byte[16]; + private final byte[] g = new byte[16]; + byte[] Z = new byte[16]; + byte[] CNT_Z = new byte[7]; + byte[] LR = new byte[32]; + byte[] T = new byte[16]; + // Initialization function: KDF + byte[] S = new byte[16]; + + @Override + public void processFinalBlock(byte[] output, int outOff) + { + int n = 16; + int messegeLen = dataOperator.getLen() - (forEncryption ? 0 : MAC_SIZE); + if (m_bufPos != 0) + { + int len8 = Math.min(m_bufPos, 16); + System.arraycopy(npub, 0, S, 0, 16); + block_cipher(S, Z, T, 0, CNT, (byte)64); + Bytes.xor(len8, m_buf, S, output, outOff); + System.arraycopy(npub, 0, S, 0, 16); + + lfsr_gf56(CNT); + + byte[] macIn; + int macInOff; + if (forEncryption) + { + macIn = output; + macInOff = outOff; + } + else + { + macIn = m_buf; + macInOff = 0; + } + System.arraycopy(macIn, macInOff, m_aad, m_aadPos, m_bufPos); + Arrays.fill(m_aad, m_aadPos + m_bufPos, AADBufferSize - 1, (byte)0); + m_aad[m_aadPos + BlockSize - 1] = (byte)(m_bufPos & 0xf); + if (m_aadPos == 0) + { + System.arraycopy(npub, 0, m_aad, BlockSize, BlockSize); + n = 0; + } + hirose_128_128_256(h, g, m_aad, 0); + lfsr_gf56(CNT_Z); + } + else if (m_aadPos != 0) + { + if (messegeLen > 0) + { + Arrays.fill(m_aad, BlockSize, AADBufferSize, (byte)0); + } + else if (aadOperator.getLen() != 0) + { + System.arraycopy(npub, 0, m_aad, m_aadPos, 16); + n = 0; + m_aadPos = 0; + } + hirose_128_128_256(h, g, m_aad, 0); + } + else if (messegeLen > 0) + { + Arrays.fill(m_aad, 0, BlockSize, (byte)0); + System.arraycopy(npub, 0, m_aad, BlockSize, BlockSize); + n = 0; + hirose_128_128_256(h, g, m_aad, 0); + } + + if (n == 16) + { + // Pad the nonce and counter + System.arraycopy(npub, 0, m_aad, 0, 16); + System.arraycopy(CNT, 0, m_aad, 16, 7); + Arrays.fill(m_aad, 23, 31, (byte)0); + m_aad[31] = (byte)(23 & 0x1f); + } + else + { + System.arraycopy(CNT_Z, 0, m_aad, 0, 7); + Arrays.fill(m_aad, 7, 31, (byte)0); + m_aad[31] = (byte)(7 & 0x1f); + } + h[0] ^= 2; + hirose_128_128_256(h, g, m_aad, 0); + // Assign the output tag + System.arraycopy(h, 0, LR, 0, 16); + System.arraycopy(g, 0, LR, 16, 16); + Arrays.clear(CNT_Z); + block_cipher(LR, k, LR, 16, CNT_Z, (byte)68); + System.arraycopy(LR, 0, mac, 0, MAC_SIZE); + } + + @Override + public void processBufferAAD(byte[] input, int inOff) + { + hirose_128_128_256(h, g, input, inOff); + } + + @Override + public void processFinalAAD() + { + // Partial block (or in case there is no partial block we add a 0^2n block + Arrays.fill(m_aad, m_aadPos, AADBufferSize - 1, (byte)0); + if (m_aadPos >= 16) + { + m_aad[AADBufferSize - 1] = (byte)(m_aadPos & 0xf); + hirose_128_128_256(h, g, m_aad, 0); + m_aadPos = 0; + } + else if ((m_aadPos >= 0) && (aadOperator.getLen() != 0)) + { + m_aad[BlockSize - 1] = (byte)(m_aadPos & 0xf); + m_aadPos = BlockSize; + } + } + + private void processBuffer(byte[] input, int inOff, byte[] output, int outOff) + { + System.arraycopy(npub, 0, S, 0, 16); + block_cipher(S, Z, T, 0, CNT, (byte)64); + Bytes.xor(AD_BLK_LEN_HALF, S, input, inOff, output, outOff); + System.arraycopy(npub, 0, S, 0, 16); + block_cipher(S, Z, T, 0, CNT, (byte)65); + System.arraycopy(S, 0, Z, 0, 16); + lfsr_gf56(CNT); + } + + private void processAfterAbsorbCiphertext() + { + if (m_aadPos == BlockSize) + { + hirose_128_128_256(h, g, m_aad, 0); + m_aadPos = 0; + } + else + { + m_aadPos = BlockSize; + } + lfsr_gf56(CNT_Z); + } + + @Override + public void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff) + { + processBuffer(input, inOff, output, outOff); + // ipad_256(ipad*_128(A)||ipad*_128(C)||N|| CNT + System.arraycopy(output, outOff, m_aad, m_aadPos, BlockSize); + processAfterAbsorbCiphertext(); + } + + @Override + public void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff) + { + processBuffer(input, inOff, output, outOff); + // ipad_256(ipad*_128(A)||ipad*_128(C)||N|| CNT + System.arraycopy(input, inOff, m_aad, m_aadPos, BlockSize); + processAfterAbsorbCiphertext(); + } + + @Override + public void reset() + { + Arrays.clear(h); + Arrays.clear(g); + Arrays.clear(LR); + Arrays.clear(T); + Arrays.clear(S); + Arrays.clear(CNT_Z); + reset_lfsr_gf56(CNT); + System.arraycopy(npub, 0, Z, 0, IV_SIZE); + block_cipher(Z, k, T, 0, CNT_Z, (byte)66); + reset_lfsr_gf56(CNT_Z); + } + } + + private static void skinny_128_384_plus_enc(byte[] input, byte[] userkey) + { + byte[][] state = new byte[4][4]; + byte[][][] keyCells = new byte[3][4][4]; + int i, j, q, r; + byte pos, tmp; + byte[][][] keyCells_tmp = new byte[3][4][4]; + for (i = 0; i < 4; ++i) + { + q = i << 2; + System.arraycopy(input, q, state[i], 0, 4); + System.arraycopy(userkey, q, keyCells[0][i], 0, 4); + System.arraycopy(userkey, q + 16, keyCells[1][i], 0, 4); + System.arraycopy(userkey, q + 32, keyCells[2][i], 0, 4); + } + for (int round = 0; round < 40; round++) + { + //SubCell8; + for (i = 0; i < 4; i++) + { + for (j = 0; j < 4; j++) + { + state[i][j] = sbox_8[state[i][j] & 0xFF]; + } + } + //AddConstants + state[0][0] ^= (RC[round] & 0xf); + state[1][0] ^= ((RC[round] >>> 4) & 0x3); + state[2][0] ^= 0x2; + //AddKey + // apply the subtweakey to the internal state + for (i = 0; i <= 1; i++) + { + for (j = 0; j < 4; j++) + { + state[i][j] ^= keyCells[0][i][j] ^ keyCells[1][i][j] ^ keyCells[2][i][j]; + } + } + for (i = 0; i < 4; i++) + { + for (j = 0; j < 4; j++) + { + //application of the TWEAKEY permutation + pos = TWEAKEY_P[j + (i << 2)]; + q = pos >>> 2; + r = pos & 3; + keyCells_tmp[0][i][j] = keyCells[0][q][r]; + keyCells_tmp[1][i][j] = keyCells[1][q][r]; + keyCells_tmp[2][i][j] = keyCells[2][q][r]; + } + } + // update the subtweakey states with the LFSRs + for (i = 0; i <= 1; i++) + { + for (j = 0; j < 4; j++) + { + //application of LFSRs for TK updates + keyCells[0][i][j] = keyCells_tmp[0][i][j]; + tmp = keyCells_tmp[1][i][j]; + keyCells[1][i][j] = (byte)(((tmp << 1) & 0xFE) ^ ((tmp >>> 7) & 0x01) ^ ((tmp >>> 5) & 0x01)); + tmp = keyCells_tmp[2][i][j]; + keyCells[2][i][j] = (byte)(((tmp >>> 1) & 0x7F) ^ ((tmp << 7) & 0x80) ^ ((tmp << 1) & 0x80)); + } + } + for (; i < 4; ++i) + { + for (j = 0; j < 4; j++) + { + keyCells[0][i][j] = keyCells_tmp[0][i][j]; + keyCells[1][i][j] = keyCells_tmp[1][i][j]; + keyCells[2][i][j] = keyCells_tmp[2][i][j]; + } + } + //ShiftRows(state); + tmp = state[1][3]; + state[1][3] = state[1][2]; + state[1][2] = state[1][1]; + state[1][1] = state[1][0]; + state[1][0] = tmp; + tmp = state[2][0]; + state[2][0] = state[2][2]; + state[2][2] = tmp; + tmp = state[2][1]; + state[2][1] = state[2][3]; + state[2][3] = tmp; + tmp = state[3][0]; + state[3][0] = state[3][1]; + state[3][1] = state[3][2]; + state[3][2] = state[3][3]; + state[3][3] = tmp; + //MixColumn(state); + for (j = 0; j < 4; j++) + { + state[1][j] ^= state[2][j]; + state[2][j] ^= state[0][j]; + state[3][j] ^= state[2][j]; + tmp = state[3][j]; + state[3][j] = state[2][j]; + state[2][j] = state[1][j]; + state[1][j] = state[0][j]; + state[0][j] = tmp; + } + } //The last subtweakey should not be added + for (i = 0; i < 16; i++) + { + input[i] = (byte)(state[i >>> 2][i & 0x3] & 0xFF); + } + } + + + // Padding function: pads the byte length of the message mod 16 to the last incomplete block. +// For complete blocks it returns the same block. + void pad(byte[] m, int mOff, byte[] mp, int l, int len8) + { + mp[l - 1] = (byte)(len8 & 0x0f); + System.arraycopy(m, mOff, mp, 0, len8); + } + + // G(S): generates the key stream from the internal state by multiplying the state S by the constant matrix G + void g8A(byte[] s, byte[] c, int cOff) + { + int len = Math.min(c.length - cOff, 16); + for (int i = 0; i < len; i++) + { + c[i + cOff] = (byte)(((s[i] & 0xFF) >>> 1) ^ (s[i] & 0x80) ^ ((s[i] & 0x01) << 7)); + } + } + + // Rho(S,M): pads an M block and outputs S'= M xor S and C = M xor G(S) + // Inverse-Rho(S,M): pads a C block and outputs S'= C xor G(S) xor S and M = C xor G(S) + void rho(byte[] m, int mOff, byte[] c, int cOff, byte[] s, int len8) + { + byte[] mp = new byte[16]; + pad(m, mOff, mp, AD_BLK_LEN_HALF, len8); + g8A(s, c, cOff); + if (forEncryption) + { + for (int i = 0; i < AD_BLK_LEN_HALF; i++) + { + s[i] ^= mp[i]; + if (i < len8) + { + c[i + cOff] ^= mp[i]; + } + else + { + c[i + cOff] = 0; + } + } + } + else + { + for (int i = 0; i < AD_BLK_LEN_HALF; i++) + { + s[i] ^= mp[i]; + if (i < len8 && i + cOff < c.length) + { + s[i] ^= c[i + cOff]; + c[i + cOff] ^= mp[i]; + } + } + } + } + + // Applies CNT'=2 * CNT (mod GF(2^56)), where GF(2^56) is defined using the irreducible polynomial +// x^56 + x^7 + x^4 + x^2 + 1 + void lfsr_gf56(byte[] CNT) + { + byte fb0 = (byte)((CNT[6] & 0xFF) >>> 7); + CNT[6] = (byte)(((CNT[6] & 0xFF) << 1) | ((CNT[5] & 0xFF) >>> 7)); + CNT[5] = (byte)(((CNT[5] & 0xFF) << 1) | ((CNT[4] & 0xFF) >>> 7)); + CNT[4] = (byte)((((CNT[4] & 0xFF) << 1) | ((CNT[3] & 0xFF) >>> 7))); + CNT[3] = (byte)(((CNT[3] & 0xFF) << 1) | ((CNT[2] & 0xFF) >>> 7)); + CNT[2] = (byte)(((CNT[2] & 0xFF) << 1) | ((CNT[1] & 0xFF) >>> 7)); + CNT[1] = (byte)(((CNT[1] & 0xFF) << 1) | ((CNT[0] & 0xFF) >>> 7)); + if (fb0 == 1) + { + CNT[0] = (byte)(((CNT[0] & 0xFF) << 1) ^ 0x95); + } + else + { + CNT[0] = (byte)(((CNT[0] & 0xFF) << 1)); + } + } + + // An interface between Romulus and the underlying TBC + void block_cipher(byte[] s, byte[] K, byte[] T, int tOff, byte[] CNT, byte D) + { + byte[] KT = new byte[48]; + // Combines the secret key, counter and domain bits to form the full 384-bit tweakey + System.arraycopy(CNT, 0, KT, 0, 7); + KT[7] = D; + System.arraycopy(T, tOff, KT, 16, 16); + System.arraycopy(K, 0, KT, 32, 16); + skinny_128_384_plus_enc(s, KT); + } + + private void reset_lfsr_gf56(byte[] CNT) + { + CNT[0] = 0x01; + Arrays.fill(CNT, 1, 7, (byte)0); + } + + public static void hirose_128_128_256(RomulusDigest.Friend friend, byte[] h, byte[] g, byte[] m, int mOff) + { + if (null == friend) + { + throw new NullPointerException("This method is only for use by RomulusDigest"); + } + hirose_128_128_256(h, g, m, mOff); + } + + // The hirose double-block length (DBL) compression function. + static void hirose_128_128_256(byte[] h, byte[] g, byte[] m, int mOff) + { + byte[] key = new byte[48]; + byte[] hh = new byte[16]; + int i; + // assign the key for the hirose compresison function + System.arraycopy(g, 0, key, 0, 16); + System.arraycopy(h, 0, g, 0, 16); + System.arraycopy(h, 0, hh, 0, 16); + g[0] ^= 0x01; + System.arraycopy(m, mOff, key, 16, 32); + skinny_128_384_plus_enc(h, key); + skinny_128_384_plus_enc(g, key); + for (i = 0; i < 16; i++) + { + h[i] ^= hh[i]; + g[i] ^= hh[i]; + } + g[0] ^= 0x01; + } + + @Override + protected void init(byte[] key, byte[] iv) + throws IllegalArgumentException + { + npub = iv; + k = key; + } + + protected void finishAAD(State nextState, boolean isDoFinal) + { + // State indicates whether we ever received AAD + finishAAD1(nextState); + } + + protected void processBufferAAD(byte[] input, int inOff) + { + instance.processBufferAAD(input, inOff); + } + + protected void processFinalAAD() + { + instance.processFinalAAD(); + } + + @Override + protected void processFinalBlock(byte[] output, int outOff) + { + instance.processFinalBlock(output, outOff); + } + + @Override + protected void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff) + { + instance.processBufferEncrypt(input, inOff, output, outOff); + } + + @Override + protected void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff) + { + instance.processBufferDecrypt(input, inOff, output, outOff); + } + + protected void reset(boolean clearMac) + { + super.reset(clearMac); + instance.reset(); + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/SparkleEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/SparkleEngine.java index 3557aac603..6e71b16b7b 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/SparkleEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/SparkleEngine.java @@ -1,6 +1,7 @@ package org.bouncycastle.crypto.engines; import org.bouncycastle.crypto.digests.SparkleDigest; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Integers; import org.bouncycastle.util.Pack; @@ -10,7 +11,7 @@ * Specification: https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/sparkle-spec-final.pdf */ public class SparkleEngine - extends AEADBufferBaseEngine + extends AEADBaseEngine { public enum SparkleParameters { @@ -27,8 +28,6 @@ public enum SparkleParameters private final int[] k; private final int[] npub; private boolean encrypted; - private final int m_bufferSizeDecrypt; - private final int SPARKLE_STEPS_SLIM; private final int SPARKLE_STEPS_BIG; private final int KEY_WORDS; @@ -111,12 +110,7 @@ public SparkleEngine(SparkleParameters sparkleParameters) k = new int[KEY_WORDS]; npub = new int[RATE_WORDS]; AADBufferSize = BlockSize = IV_SIZE; - m_bufferSizeDecrypt = IV_SIZE + MAC_SIZE; - m_buf = new byte[m_bufferSizeDecrypt]; - m_aad = new byte[BlockSize]; - - // Relied on by processBytes method for decryption -// assert RATE_BYTES >= TAG_BYTES; + setInnerMembers(ProcessingBufferType.Buffered, AADOperatorType.Default, DataOperatorType.Default); } protected void init(byte[] key, byte[] iv) @@ -124,10 +118,11 @@ protected void init(byte[] key, byte[] iv) { Pack.littleEndianToInt(key, 0, k); Pack.littleEndianToInt(iv, 0, npub); - initialised = true; - m_state = forEncryption ? State.EncInit : State.DecInit; + } - reset(); + protected void finishAAD(State nextState, boolean isDoFinal) + { + finishAAD2(nextState); } @Override @@ -188,7 +183,6 @@ protected void processFinalBlock(byte[] output, int outOff) { state[RATE_WORDS + i] ^= k[i]; } - mac = new byte[MAC_SIZE]; Pack.intToLittleEndian(state, RATE_WORDS, TAG_WORDS, mac, 0); } @@ -212,10 +206,8 @@ protected void processBufferAAD(byte[] buffer, int bufOff) sparkle_opt(state, SPARKLE_STEPS_SLIM); } - private void processBufferDecrypt(byte[] buffer, int bufOff, byte[] output, int outOff) + protected void processBufferDecrypt(byte[] buffer, int bufOff, byte[] output, int outOff) { -// assert bufOff <= buffer.length - RATE_BYTES; - for (int i = 0; i < RATE_WORDS / 2; ++i) { int j = i + (RATE_WORDS / 2); @@ -238,23 +230,8 @@ private void processBufferDecrypt(byte[] buffer, int bufOff, byte[] output, int encrypted = true; } - @Override - protected void processBuffer(byte[] input, int inOff, byte[] output, int outOff) + protected void processBufferEncrypt(byte[] buffer, int bufOff, byte[] output, int outOff) { - if (forEncryption) - { - processBufferEncrypt(input, inOff, output, outOff); - } - else - { - processBufferDecrypt(input, inOff, output, outOff); - } - } - - private void processBufferEncrypt(byte[] buffer, int bufOff, byte[] output, int outOff) - { -// assert bufOff <= buffer.length - RATE_BYTES; - for (int i = 0; i < RATE_WORDS / 2; ++i) { int j = i + (RATE_WORDS / 2); @@ -285,11 +262,8 @@ protected void processFinalAAD() state[STATE_WORDS - 1] ^= _A0; // padding - m_aad[m_aadPos] = (byte)0x80; - while (++m_aadPos < BlockSize) - { - m_aad[m_aadPos] = 0x00; - } + m_aad[m_aadPos++] = (byte)0x80; + Arrays.fill(m_aad, m_aadPos, BlockSize, (byte)0); } else { @@ -316,7 +290,6 @@ protected void processFinalAAD() protected void reset(boolean clearMac) { - bufferReset(); encrypted = false; // The Initialize function loads nonce and key into the state and executes the // SPARKLE permutation with the big number of steps. diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java index 08dfa3f1e5..b22e39eeea 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/XoodyakEngine.java @@ -1,6 +1,8 @@ package org.bouncycastle.crypto.engines; +import org.bouncycastle.crypto.digests.XoodyakDigest; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Bytes; import org.bouncycastle.util.Integers; import org.bouncycastle.util.Pack; @@ -12,49 +14,39 @@ */ public class XoodyakEngine - extends AEADBufferBaseEngine + extends AEADBaseEngine { - private byte[] state; + private final byte[] state; private int phase; - private MODE mode; - private final int f_bPrime_1 = 47; + private int mode; + private static final int f_bPrime_1 = 47; private byte[] K; private byte[] iv; - private final int PhaseUp = 2; - private final int[] RC = {0x00000058, 0x00000038, 0x000003C0, 0x000000D0, 0x00000120, 0x00000014, 0x00000060, + private static final int PhaseUp = 2; + private static final int PhaseDown = 1; + private static final int[] RC = {0x00000058, 0x00000038, 0x000003C0, 0x000000D0, 0x00000120, 0x00000014, 0x00000060, 0x0000002C, 0x00000380, 0x000000F0, 0x000001A0, 0x00000012}; private boolean encrypted; private byte aadcd; - - enum MODE - { - ModeHash, - ModeKeyed - } + private static final int ModeKeyed = 0; + private static final int ModeHash = 1; public XoodyakEngine() { algorithmName = "Xoodyak AEAD"; - KEY_SIZE = 16; - IV_SIZE = 16; - MAC_SIZE = 16; + KEY_SIZE = IV_SIZE = MAC_SIZE = 16; BlockSize = 24; AADBufferSize = 44; - m_aad = new byte[AADBufferSize]; + state = new byte[48]; + setInnerMembers(ProcessingBufferType.Immediate, AADOperatorType.Default, DataOperatorType.Counter); } @Override - public void init(byte[] key, byte[] iv) + protected void init(byte[] key, byte[] iv) throws IllegalArgumentException { K = key; this.iv = iv; - state = new byte[48]; - mac = new byte[MAC_SIZE]; - m_buf = new byte[BlockSize + (forEncryption ? 0 : MAC_SIZE)]; - initialised = true; - m_state = forEncryption ? State.EncInit : State.DecInit; - reset(); } protected void processBufferAAD(byte[] input, int inOff) @@ -65,109 +57,88 @@ protected void processBufferAAD(byte[] input, int inOff) protected void processFinalAAD() { - if (mode != MODE.ModeKeyed) - { - throw new IllegalArgumentException("Xoodyak has not been initialised"); - } - if (!aadFinished) - { - AbsorbAny(m_aad, 0, m_aadPos, aadcd); - aadFinished = true; - m_aadPos = 0; - } + AbsorbAny(m_aad, 0, m_aadPos, aadcd); } - protected void processBuffer(byte[] input, int inOff, byte[] output, int outOff) + @Override + protected void finishAAD(State nextState, boolean isDoFinal) { - processFinalAAD(); - encrypt(input, inOff, BlockSize, output, outOff); + finishAAD3(nextState, isDoFinal); } - private void encrypt(byte[] input, int inOff, int len, byte[] output, int outOff) + protected void processBufferEncrypt(byte[] input, int inOff, byte[] output, int outOff) { - int IOLen = len; - int splitLen; - byte[] P = new byte[BlockSize]; - int Cu = encrypted ? 0 : 0x80; - while (IOLen != 0 || !encrypted) + up(mode, state, encrypted ? 0 : 0x80); /* Up without extract */ + /* Extract from Up and Add */ + Bytes.xor(BlockSize, state, input, inOff, output, outOff); + down(mode, state, input, inOff, BlockSize, 0x00); + phase = PhaseDown; + encrypted = true; + } + + protected void processBufferDecrypt(byte[] input, int inOff, byte[] output, int outOff) + { + up(mode, state, encrypted ? 0 : 0x80); /* Up without extract */ + /* Extract from Up and Add */ + Bytes.xor(BlockSize, state, input, inOff, output, outOff); + down(mode, state, output, outOff, BlockSize, 0x00); + phase = PhaseDown; + encrypted = true; + } + + @Override + protected void processFinalBlock(byte[] output, int outOff) + { + if (m_bufPos != 0 || !encrypted) { - splitLen = Math.min(IOLen, BlockSize); /* use Rkout instead of Rsqueeze, this function is only called in keyed mode */ - if (forEncryption) - { - System.arraycopy(input, inOff, P, 0, splitLen); - } - Up(null, 0, Cu); /* Up without extract */ + up(mode, state, encrypted ? 0 : 0x80); /* Up without extract */ /* Extract from Up and Add */ - for (int i = 0; i < splitLen; i++) - { - output[outOff + i] = (byte)(input[inOff++] ^ state[i]); - } + Bytes.xor(m_bufPos, state, m_buf, 0, output, outOff); if (forEncryption) { - Down(P, 0, splitLen, 0x00); + down(mode, state, m_buf, 0, m_bufPos, 0x00); } else { - Down(output, outOff, splitLen, 0x00); + down(mode, state, output, outOff, m_bufPos, 0x00); } - Cu = 0x00; - outOff += splitLen; - IOLen -= splitLen; - encrypted = true; - } - } - - @Override - protected void processFinalBlock(byte[] output, int outOff) - { - processFinalAAD(); - if (forEncryption) - { - Arrays.fill(m_buf, m_bufPos, BlockSize, (byte)0); + phase = PhaseDown; } - encrypt(m_buf, 0, m_bufPos, output, outOff); - mac = new byte[MAC_SIZE]; - Up(mac, MAC_SIZE, 0x40); + up(mode, state, 0x40); + System.arraycopy(state, 0, mac, 0, MAC_SIZE); + phase = PhaseUp; } protected void reset(boolean clearMac) { - if (!initialised) - { - throw new IllegalArgumentException("Need call init function before encryption/decryption"); - } + super.reset(clearMac); Arrays.fill(state, (byte)0); - aadFinished = false; encrypted = false; phase = PhaseUp; - Arrays.fill(m_buf, (byte)0); - Arrays.fill(m_aad, (byte)0); - m_bufPos = 0; - m_aadPos = 0; aadcd = (byte)0x03; //Absorb key int KLen = K.length; int IDLen = iv.length; byte[] KID = new byte[AADBufferSize]; - mode = MODE.ModeKeyed; + mode = ModeKeyed; System.arraycopy(K, 0, KID, 0, KLen); System.arraycopy(iv, 0, KID, KLen, IDLen); KID[KLen + IDLen] = (byte)IDLen; AbsorbAny(KID, 0, KLen + IDLen + 1, 0x02); - super.reset(clearMac); } private void AbsorbAny(byte[] X, int Xoff, int XLen, int Cd) { int splitLen; + if (phase != PhaseUp) + { + up(mode, state, 0); + } do { - if (phase != PhaseUp) - { - Up(null, 0, 0); - } splitLen = Math.min(XLen, AADBufferSize); - Down(X, Xoff, splitLen, Cd); + down(mode, state, X, Xoff, splitLen, Cd); + phase = PhaseDown; Cd = 0; Xoff += splitLen; XLen -= splitLen; @@ -175,9 +146,18 @@ private void AbsorbAny(byte[] X, int Xoff, int XLen, int Cd) while (XLen != 0); } - private void Up(byte[] Yi, int YiLen, int Cu) + public static void up(XoodyakDigest.Friend friend, int mode, byte[] state, int Cu) + { + if (null == friend) + { + throw new NullPointerException("This method is only for use by XoodyakDigest"); + } + up(mode, state, Cu); + } + + private static void up(int mode, byte[] state, int Cu) { - if (mode != MODE.ModeHash) + if (mode != ModeHash) { state[f_bPrime_1] ^= Cu; } @@ -283,22 +263,21 @@ private void Up(byte[] Yi, int YiLen, int Cu) Pack.intToLittleEndian(a9, state, 36); Pack.intToLittleEndian(a10, state, 40); Pack.intToLittleEndian(a11, state, 44); + } - phase = PhaseUp; - if (Yi != null) + public static void down(XoodyakDigest.Friend friend, int mode, byte[] state, byte[] Xi, int XiOff, int XiLen, int Cd) + { + if (null == friend) { - System.arraycopy(state, 0, Yi, 0, YiLen); + throw new NullPointerException("This method is only for use by XoodyakDigest"); } + down(mode, state, Xi, XiOff, XiLen, Cd); } - void Down(byte[] Xi, int XiOff, int XiLen, int Cd) + private static void down(int mode, byte[] state, byte[] Xi, int XiOff, int XiLen, int Cd) { - for (int i = 0; i < XiLen; i++) - { - state[i] ^= Xi[XiOff++]; - } + Bytes.xorTo(XiLen, Xi, XiOff, state); state[XiLen] ^= 0x01; - state[f_bPrime_1] ^= (mode == MODE.ModeHash) ? (Cd & 0x01) : Cd; - phase = 1; + state[f_bPrime_1] ^= (mode == ModeHash) ? (Cd & 0x01) : Cd; } } diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java b/core/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java index bc09ab9915..ef32d41994 100644 --- a/core/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java +++ b/core/src/main/java/org/bouncycastle/crypto/generators/BaseKDFBytesGenerator.java @@ -84,61 +84,47 @@ public int generateBytes(byte[] out, int outOff, int len) throws DataLengthExcep throw new OutputLengthException("output buffer too small"); } - long oBytes = len; - int outLen = digest.getDigestSize(); - - // - // this is at odds with the standard implementation, the - // maximum value should be hBits * (2^32 - 1) where hBits - // is the digest output size in bits. We can't have an - // array with a long index at the moment... - // - if (oBytes > ((2L << 32) - 1)) + digest.reset(); + + int outputLength = len; + int digestSize = digest.getDigestSize(); + + // NOTE: This limit isn't reachable for current array lengths + if (outputLength > ((1L << 32) - 1) * digestSize) { throw new IllegalArgumentException("Output length too large"); } - int cThreshold = (int)((oBytes + outLen - 1) / outLen); - - byte[] dig = new byte[digest.getDigestSize()]; - + int counter32 = counterStart; byte[] C = new byte[4]; - Pack.intToBigEndian(counterStart, C, 0); - - int counterBase = counterStart & ~0xFF; - for (int i = 0; i < cThreshold; i++) + while (len > 0) { + Pack.intToBigEndian(counter32, C); + digest.update(shared, 0, shared.length); - digest.update(C, 0, C.length); + digest.update(C, 0, 4); if (iv != null) { digest.update(iv, 0, iv.length); } - digest.doFinal(dig, 0); - - if (len > outLen) + if (len < digestSize) { - System.arraycopy(dig, 0, out, outOff, outLen); - outOff += outLen; - len -= outLen; - } - else - { - System.arraycopy(dig, 0, out, outOff, len); + byte[] tmp = new byte[digestSize]; + digest.doFinal(tmp, 0); + System.arraycopy(tmp, 0, out, outOff, len); + break; } - if (++C[3] == 0) - { - counterBase += 0x100; - Pack.intToBigEndian(counterBase, C, 0); - } - } + digest.doFinal(out, outOff); + outOff += digestSize; + len -= digestSize; - digest.reset(); + ++counter32; + } - return (int)oBytes; + return outputLength; } } diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java new file mode 100644 index 0000000000..321c020abd --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java @@ -0,0 +1,82 @@ +package org.bouncycastle.crypto.generators; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import org.bouncycastle.crypto.CryptoServicePurpose; +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.KeyGenerationParameters; +import org.bouncycastle.crypto.constraints.DefaultServiceProperties; +import org.bouncycastle.crypto.params.ECCSIKeyGenerationParameters; +import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.BigIntegers; + +/** + * A key pair generator for the ECCSI scheme (Elliptic Curve-based Certificateless Signatures + * for Identity-based Encryption) as defined in RFC 6507. + * + * @see + * RFC 6507: Elliptic Curve-Based Certificateless Signatures for Identity-based Encryption (ECCSI) + * + */ + +public class ECCSIKeyPairGenerator + implements AsymmetricCipherKeyPairGenerator +{ + private BigInteger q; + private ECPoint G; + private Digest digest; + private ECCSIKeyGenerationParameters parameters; + + /** + * Initializes the key pair generator with the specified parameters. + * + * @param parameters an instance of {@link ECCSIKeyGenerationParameters} which encapsulates the elliptic + * curve domain parameters, the digest algorithm, and an associated identifier. + */ + @Override + public void init(KeyGenerationParameters parameters) + { + this.parameters = (ECCSIKeyGenerationParameters)parameters; + this.q = this.parameters.getQ(); + this.G = this.parameters.getG(); + this.digest = this.parameters.getDigest(); + + CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties("ECCSI", this.parameters.getN(), null, CryptoServicePurpose.KEYGEN)); + } + + @Override + public AsymmetricCipherKeyPair generateKeyPair() + { + SecureRandom random = parameters.getRandom(); + this.digest.reset(); + byte[] id = parameters.getId(); + ECPoint kpak = parameters.getKPAK(); + // 1) Choose v, a random (ephemeral) non-zero element of F_q; + BigInteger v = BigIntegers.createRandomBigInteger(256, random).mod(q); + // 2) Compute PVT = [v]G + ECPoint pvt = G.multiply(v).normalize(); + + // 3) Compute a hash value HS = hash( G || KPAK || ID || PVT ), an N-octet integer; + byte[] tmp = G.getEncoded(false); + digest.update(tmp, 0, tmp.length); + tmp = kpak.getEncoded(false); + digest.update(tmp, 0, tmp.length); + digest.update(id, 0, id.length); + tmp = pvt.getEncoded(false); + digest.update(tmp, 0, tmp.length); + tmp = new byte[digest.getDigestSize()]; + digest.doFinal(tmp, 0); + BigInteger HS = new BigInteger(1, tmp).mod(q); + + // 4) Compute SSK = ( KSAK + HS * v ) modulo q; + BigInteger ssk = parameters.computeSSK(HS.multiply(v)); + ECCSIPublicKeyParameters pub = new ECCSIPublicKeyParameters(pvt); + return new AsymmetricCipherKeyPair(new ECCSIPublicKeyParameters(pvt), new ECCSIPrivateKeyParameters(ssk, pub)); + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/KDFCounterBytesGenerator.java b/core/src/main/java/org/bouncycastle/crypto/generators/KDFCounterBytesGenerator.java index 549dd921ea..323ee91c18 100644 --- a/core/src/main/java/org/bouncycastle/crypto/generators/KDFCounterBytesGenerator.java +++ b/core/src/main/java/org/bouncycastle/crypto/generators/KDFCounterBytesGenerator.java @@ -1,13 +1,12 @@ package org.bouncycastle.crypto.generators; -import java.math.BigInteger; - import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.DerivationParameters; import org.bouncycastle.crypto.Mac; import org.bouncycastle.crypto.MacDerivationFunction; import org.bouncycastle.crypto.params.KDFCounterParameters; import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.util.Integers; /** * This KDF has been defined by the publicly available NIST SP 800-108 specification. @@ -39,10 +38,6 @@ public class KDFCounterBytesGenerator implements MacDerivationFunction { - - private static final BigInteger INTEGER_MAX = BigInteger.valueOf(Integer.MAX_VALUE); - private static final BigInteger TWO = BigInteger.valueOf(2); - // please refer to the standard for the meaning of the variable names // all field lengths are in bytes, not in bits as specified by the standard @@ -92,9 +87,7 @@ public void init(DerivationParameters param) int r = kdfParams.getR(); this.ios = new byte[r / 8]; - BigInteger maxSize = TWO.pow(r).multiply(BigInteger.valueOf(h)); - this.maxSizeExcl = maxSize.compareTo(INTEGER_MAX) == 1 ? - Integer.MAX_VALUE : maxSize.intValue(); + this.maxSizeExcl = r >= Integers.numberOfLeadingZeros(h) ? Integer.MAX_VALUE : h << r; // --- set operational state --- diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/KDFDoublePipelineIterationBytesGenerator.java b/core/src/main/java/org/bouncycastle/crypto/generators/KDFDoublePipelineIterationBytesGenerator.java index 6115a1a399..b325b3dde4 100644 --- a/core/src/main/java/org/bouncycastle/crypto/generators/KDFDoublePipelineIterationBytesGenerator.java +++ b/core/src/main/java/org/bouncycastle/crypto/generators/KDFDoublePipelineIterationBytesGenerator.java @@ -1,13 +1,12 @@ package org.bouncycastle.crypto.generators; -import java.math.BigInteger; - import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.DerivationParameters; import org.bouncycastle.crypto.Mac; import org.bouncycastle.crypto.MacDerivationFunction; import org.bouncycastle.crypto.params.KDFDoublePipelineIterationParameters; import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.util.Integers; /** * This KDF has been defined by the publicly available NIST SP 800-108 specification. @@ -15,10 +14,6 @@ public class KDFDoublePipelineIterationBytesGenerator implements MacDerivationFunction { - - private static final BigInteger INTEGER_MAX = BigInteger.valueOf(Integer.MAX_VALUE); - private static final BigInteger TWO = BigInteger.valueOf(2); - // please refer to the standard for the meaning of the variable names // all field lengths are in bytes, not in bits as specified by the standard @@ -71,9 +66,7 @@ public void init(DerivationParameters params) if (dpiParams.useCounter()) { // this is more conservative than the spec - BigInteger maxSize = TWO.pow(r).multiply(BigInteger.valueOf(h)); - this.maxSizeExcl = maxSize.compareTo(INTEGER_MAX) == 1 ? - Integer.MAX_VALUE : maxSize.intValue(); + this.maxSizeExcl = r >= Integers.numberOfLeadingZeros(h) ? Integer.MAX_VALUE : h << r; } else { diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/KDFFeedbackBytesGenerator.java b/core/src/main/java/org/bouncycastle/crypto/generators/KDFFeedbackBytesGenerator.java index 6003037642..6d1c01e18c 100644 --- a/core/src/main/java/org/bouncycastle/crypto/generators/KDFFeedbackBytesGenerator.java +++ b/core/src/main/java/org/bouncycastle/crypto/generators/KDFFeedbackBytesGenerator.java @@ -1,13 +1,12 @@ package org.bouncycastle.crypto.generators; -import java.math.BigInteger; - import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.DerivationParameters; import org.bouncycastle.crypto.Mac; import org.bouncycastle.crypto.MacDerivationFunction; import org.bouncycastle.crypto.params.KDFFeedbackParameters; import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.util.Integers; /** * This KDF has been defined by the publicly available NIST SP 800-108 specification. @@ -15,10 +14,6 @@ public class KDFFeedbackBytesGenerator implements MacDerivationFunction { - - private static final BigInteger INTEGER_MAX = BigInteger.valueOf(Integer.MAX_VALUE); - private static final BigInteger TWO = BigInteger.valueOf(2); - // please refer to the standard for the meaning of the variable names // all field lengths are in bytes, not in bits as specified by the standard @@ -70,9 +65,7 @@ public void init(DerivationParameters params) if (feedbackParams.useCounter()) { // this is more conservative than the spec - BigInteger maxSize = TWO.pow(r).multiply(BigInteger.valueOf(h)); - this.maxSizeExcl = maxSize.compareTo(INTEGER_MAX) == 1 ? - Integer.MAX_VALUE : maxSize.intValue(); + this.maxSizeExcl = r >= Integers.numberOfLeadingZeros(h) ? Integer.MAX_VALUE : h << r; } else { diff --git a/core/src/main/java/org/bouncycastle/crypto/hpke/AEAD.java b/core/src/main/java/org/bouncycastle/crypto/hpke/AEAD.java index e4e840bec1..a6d93cab1b 100644 --- a/core/src/main/java/org/bouncycastle/crypto/hpke/AEAD.java +++ b/core/src/main/java/org/bouncycastle/crypto/hpke/AEAD.java @@ -9,11 +9,11 @@ import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Bytes; import org.bouncycastle.util.Pack; public class AEAD { - private final short aeadId; private final byte[] key; private final byte[] baseNonce; @@ -32,7 +32,7 @@ public AEAD(short aeadId, byte[] key, byte[] baseNonce) { case HPKE.aead_AES_GCM128: case HPKE.aead_AES_GCM256: - cipher = new GCMBlockCipher(new AESEngine()); + cipher = GCMBlockCipher.newInstance(AESEngine.newInstance()); break; case HPKE.aead_CHACHA20_POLY1305: cipher = new ChaCha20Poly1305(); @@ -42,106 +42,73 @@ public AEAD(short aeadId, byte[] key, byte[] baseNonce) } } + // used by Sender + public byte[] seal(byte[] aad, byte[] pt) + throws InvalidCipherTextException + { + return process(true, aad, pt, 0, pt.length); + } // used by Sender public byte[] seal(byte[] aad, byte[] pt, int ptOffset, int ptLength) throws InvalidCipherTextException { - if (ptOffset < 0 || ptOffset > pt.length) - { - throw new IndexOutOfBoundsException("Invalid offset"); - } - if (ptOffset + ptLength > pt.length) - { - throw new IndexOutOfBoundsException("Invalid length"); - } - - CipherParameters params; - switch (aeadId) - { - case HPKE.aead_AES_GCM128: - case HPKE.aead_AES_GCM256: - case HPKE.aead_CHACHA20_POLY1305: - params = new ParametersWithIV(new KeyParameter(key), ComputeNonce()); - break; - case HPKE.aead_EXPORT_ONLY: - default: - throw new IllegalStateException("Export only mode, cannot be used to seal/open"); - } - cipher.init(true, params); - cipher.processAADBytes(aad, 0, aad.length); - byte[] ct = new byte[cipher.getOutputSize(ptLength)]; - int len = cipher.processBytes(pt, ptOffset, ptLength, ct, 0); - cipher.doFinal(ct, len); + Arrays.validateSegment(pt, ptOffset, ptLength); - seq++; - return ct; + return process(true, aad, pt, ptOffset, ptLength); } - // used by Sender - public byte[] seal(byte[] aad, byte[] pt) + // used by Receiver + public byte[] open(byte[] aad, byte[] ct) throws InvalidCipherTextException { - return this.seal(aad, pt, 0, pt.length); + return process(false, aad, ct, 0, ct.length); } // used by Receiver public byte[] open(byte[] aad, byte[] ct, int ctOffset, int ctLength) throws InvalidCipherTextException { - if (ctOffset < 0 || ctOffset > ct.length) - { - throw new IndexOutOfBoundsException("Invalid offset"); - } - if (ctOffset + ctLength > ct.length) - { - throw new IndexOutOfBoundsException("Invalid length"); - } + Arrays.validateSegment(ct, ctOffset, ctLength); + + return process(false, aad, ct, ctOffset, ctLength); + } + + private byte[] computeNonce() + { + byte[] seq_bytes = Pack.longToBigEndian(seq++); + byte[] nonce = Arrays.clone(baseNonce); + Bytes.xorTo(8, seq_bytes, 0, nonce, nonce.length - 8); + return nonce; + } + private byte[] process(boolean forEncryption, byte[] aad, byte[] buf, int off, int len) + throws InvalidCipherTextException + { CipherParameters params; switch (aeadId) { case HPKE.aead_AES_GCM128: case HPKE.aead_AES_GCM256: case HPKE.aead_CHACHA20_POLY1305: - params = new ParametersWithIV(new KeyParameter(key), ComputeNonce()); + params = new ParametersWithIV(new KeyParameter(key), computeNonce()); break; case HPKE.aead_EXPORT_ONLY: default: throw new IllegalStateException("Export only mode, cannot be used to seal/open"); } - cipher.init(false, params); + cipher.init(forEncryption, params); cipher.processAADBytes(aad, 0, aad.length); - byte[] pt = new byte[cipher.getOutputSize(ctLength)]; - int len = cipher.processBytes(ct, ctOffset, ctLength, pt, 0); - len += cipher.doFinal(pt, len); - - seq++; - return pt; - } - - // used by Receiver - public byte[] open(byte[] aad, byte[] ct) - throws InvalidCipherTextException - { - return this.open(aad, ct, 0, ct.length); - } - - private byte[] ComputeNonce() - { - byte[] seq_bytes = Pack.longToBigEndian(seq); - int Nn = baseNonce.length; - byte[] nonce = Arrays.clone(baseNonce); - //xor - for (int i = 0; i < 8; i++) + byte[] output = new byte[cipher.getOutputSize(len)]; + int pos = cipher.processBytes(buf, off, len, output, 0); + pos += cipher.doFinal(output, pos); + if (pos != output.length) { - nonce[Nn - 8 + i] ^= seq_bytes[i]; + // Existing AEAD modes should return exact value for getOutputSize. + throw new IllegalStateException(); } - return nonce; + return output; } - - } - diff --git a/core/src/main/java/org/bouncycastle/crypto/hpke/DHKEM.java b/core/src/main/java/org/bouncycastle/crypto/hpke/DHKEM.java index 44a46d6a47..84f40ba68a 100644 --- a/core/src/main/java/org/bouncycastle/crypto/hpke/DHKEM.java +++ b/core/src/main/java/org/bouncycastle/crypto/hpke/DHKEM.java @@ -5,9 +5,13 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.BasicAgreement; +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.crypto.RawAgreement; +import org.bouncycastle.crypto.agreement.BasicRawAgreement; import org.bouncycastle.crypto.agreement.ECDHCBasicAgreement; -import org.bouncycastle.crypto.agreement.XDHBasicAgreement; +import org.bouncycastle.crypto.agreement.X25519Agreement; +import org.bouncycastle.crypto.agreement.X448Agreement; +import org.bouncycastle.crypto.ec.CustomNamedCurves; import org.bouncycastle.crypto.generators.ECKeyPairGenerator; import org.bouncycastle.crypto.generators.X25519KeyPairGenerator; import org.bouncycastle.crypto.generators.X448KeyPairGenerator; @@ -22,25 +26,22 @@ import org.bouncycastle.crypto.params.X448KeyGenerationParameters; import org.bouncycastle.crypto.params.X448PrivateKeyParameters; import org.bouncycastle.crypto.params.X448PublicKeyParameters; -import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.math.ec.FixedPointCombMultiplier; import org.bouncycastle.math.ec.WNafUtil; -import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve; -import org.bouncycastle.math.ec.custom.sec.SecP384R1Curve; -import org.bouncycastle.math.ec.custom.sec.SecP521R1Curve; +import org.bouncycastle.math.ec.rfc7748.X25519; +import org.bouncycastle.math.ec.rfc7748.X448; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.BigIntegers; import org.bouncycastle.util.Pack; import org.bouncycastle.util.Strings; -import org.bouncycastle.util.encoders.Hex; - class DHKEM extends KEM { private AsymmetricCipherKeyPairGenerator kpGen; - private BasicAgreement agreement; + private RawAgreement rawAgreement; // kem ids private final short kemId; @@ -56,97 +57,68 @@ class DHKEM protected DHKEM(short kemid) { this.kemId = kemid; - ECCurve curve; + switch (kemid) { case HPKE.kem_P256_SHA256: this.hkdf = new HKDF(HPKE.kdf_HKDF_SHA256); - curve = new SecP256R1Curve(); - domainParams = new ECDomainParameters( - curve, - curve.createPoint( - new BigInteger(1, Hex.decode("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")), - new BigInteger(1, Hex.decode("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5")) - ), - curve.getOrder(), - curve.getCofactor(), - Hex.decode("c49d360886e704936a6678e1139d26b7819f7e90") - ); - this.agreement = new ECDHCBasicAgreement(); + domainParams = getDomainParameters("P-256"); + rawAgreement = new BasicRawAgreement(new ECDHCBasicAgreement()); bitmask = (byte)0xff; Nsk = 32; Nsecret = 32; Nenc = 65; + this.kpGen = new ECKeyPairGenerator(); - this.kpGen.init(new ECKeyGenerationParameters(domainParams, new SecureRandom())); + this.kpGen.init(new ECKeyGenerationParameters(domainParams, getSecureRandom())); break; - case HPKE.kem_P384_SHA348: + case HPKE.kem_P384_SHA384: this.hkdf = new HKDF(HPKE.kdf_HKDF_SHA384); - curve = new SecP384R1Curve(); - domainParams = new ECDomainParameters( - curve, - curve.createPoint( - new BigInteger(1, Hex.decode("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7")), - new BigInteger(1, Hex.decode("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f")) - ), - curve.getOrder(), - curve.getCofactor(), - Hex.decode("a335926aa319a27a1d00896a6773a4827acdac73") - ); - this.agreement = new ECDHCBasicAgreement(); + domainParams = getDomainParameters("P-384"); + rawAgreement = new BasicRawAgreement(new ECDHCBasicAgreement()); bitmask = (byte)0xff; Nsk = 48; Nsecret = 48; Nenc = 97; this.kpGen = new ECKeyPairGenerator(); - this.kpGen.init(new ECKeyGenerationParameters(domainParams, new SecureRandom())); + this.kpGen.init(new ECKeyGenerationParameters(domainParams, getSecureRandom())); break; case HPKE.kem_P521_SHA512: this.hkdf = new HKDF(HPKE.kdf_HKDF_SHA512); - - curve = new SecP521R1Curve(); - domainParams = new ECDomainParameters( - curve, - curve.createPoint( - new BigInteger("c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", 16), - new BigInteger("11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", 16) - ), - curve.getOrder(), - curve.getCofactor(), - Hex.decode("d09e8800291cb85396cc6717393284aaa0da64ba") - ); - this.agreement = new ECDHCBasicAgreement(); + domainParams = getDomainParameters("P-521"); + rawAgreement = new BasicRawAgreement(new ECDHCBasicAgreement()); bitmask = 0x01; Nsk = 66; Nsecret = 64; Nenc = 133; this.kpGen = new ECKeyPairGenerator(); - this.kpGen.init(new ECKeyGenerationParameters(domainParams, new SecureRandom())); + this.kpGen.init(new ECKeyGenerationParameters(domainParams, getSecureRandom())); break; case HPKE.kem_X25519_SHA256: this.hkdf = new HKDF(HPKE.kdf_HKDF_SHA256); - this.agreement = new XDHBasicAgreement(); + rawAgreement = new X25519Agreement(); Nsecret = 32; Nsk = 32; Nenc = 32; + this.kpGen = new X25519KeyPairGenerator(); - this.kpGen.init(new X25519KeyGenerationParameters(new SecureRandom())); + this.kpGen.init(new X25519KeyGenerationParameters(getSecureRandom())); break; case HPKE.kem_X448_SHA512: this.hkdf = new HKDF(HPKE.kdf_HKDF_SHA512); - this.agreement = new XDHBasicAgreement(); + rawAgreement = new X448Agreement(); Nsecret = 64; Nsk = 56; Nenc = 56; this.kpGen = new X448KeyPairGenerator(); - this.kpGen.init(new X448KeyGenerationParameters(new SecureRandom())); + this.kpGen.init(new X448KeyGenerationParameters(getSecureRandom())); break; default: @@ -156,12 +128,15 @@ protected DHKEM(short kemid) public byte[] SerializePublicKey(AsymmetricKeyParameter key) { - switch (kemId) { case HPKE.kem_P256_SHA256: - case HPKE.kem_P384_SHA348: + case HPKE.kem_P384_SHA384: case HPKE.kem_P521_SHA512: + /* + * RFC 9180 7.1.1. For P-256, P-384, and P-521, the SerializePublicKey() function of the KEM performs + * the uncompressed Elliptic-Curve-Point-to-Octet-String conversion according to [SECG]. + */ return ((ECPublicKeyParameters)key).getQ().getEncoded(false); case HPKE.kem_X448_SHA512: return ((X448PublicKeyParameters)key).getEncoded(); @@ -171,43 +146,98 @@ public byte[] SerializePublicKey(AsymmetricKeyParameter key) throw new IllegalStateException("invalid kem id"); } } + public byte[] SerializePrivateKey(AsymmetricKeyParameter key) { switch (kemId) { case HPKE.kem_P256_SHA256: - case HPKE.kem_P384_SHA348: + case HPKE.kem_P384_SHA384: case HPKE.kem_P521_SHA512: - return formatBigIntegerBytes(((ECPrivateKeyParameters)key).getD().toByteArray(), Nsk); + { + /* + * RFC 9180 7.1.2. For P-256, P-384, and P-521, the SerializePrivateKey() function of the KEM + * performs the Field-Element-to-Octet-String conversion according to [SECG]. + */ + return BigIntegers.asUnsignedByteArray(Nsk, ((ECPrivateKeyParameters)key).getD()); + } case HPKE.kem_X448_SHA512: - return ((X448PrivateKeyParameters)key).getEncoded(); + { + /* + * RFC 9180 7.1.2. For [..] X448 [..]. The SerializePrivateKey() function MUST clamp its output + * [..]. + * + * NOTE: Our X448 implementation clamps generated keys, but de-serialized keys are preserved as is + * (clamping applied only during usage). + */ + byte[] encoded = ((X448PrivateKeyParameters)key).getEncoded(); + X448.clampPrivateKey(encoded); + return encoded; + } case HPKE.kem_X25519_SHA256: - return ((X25519PrivateKeyParameters)key).getEncoded(); + { + /* + * RFC 9180 7.1.2. For X25519 [..]. The SerializePrivateKey() function MUST clamp its output [..]. + * + * NOTE: Our X25519 implementation clamps generated keys, but de-serialized keys are preserved as + * is (clamping applied only during usage). + */ + byte[] encoded = ((X25519PrivateKeyParameters)key).getEncoded(); + X25519.clampPrivateKey(encoded); + return encoded; + } default: throw new IllegalStateException("invalid kem id"); } } - public AsymmetricKeyParameter DeserializePublicKey(byte[] encoded) + public AsymmetricKeyParameter DeserializePublicKey(byte[] pkEncoded) { + if (pkEncoded == null) + { + throw new NullPointerException("'pkEncoded' cannot be null"); + } + if (pkEncoded.length != Nenc) + { + throw new IllegalArgumentException("'pkEncoded' has invalid length"); + } + switch (kemId) { - case HPKE.kem_P256_SHA256: - case HPKE.kem_P384_SHA348: - case HPKE.kem_P521_SHA512: - ECPoint G = domainParams.getCurve().decodePoint(encoded); - return new ECPublicKeyParameters(G, domainParams); - case HPKE.kem_X448_SHA512: - return new X448PublicKeyParameters(encoded); - case HPKE.kem_X25519_SHA256: - return new X25519PublicKeyParameters(encoded); - default: - throw new IllegalStateException("invalid kem id"); + case HPKE.kem_P256_SHA256: + case HPKE.kem_P384_SHA384: + case HPKE.kem_P521_SHA512: + /* + * RFC 9180 7.1.1. For P-256, P-384, and P-521 [..]. DeserializePublicKey() performs the + * uncompressed Octet-String-to-Elliptic-Curve-Point conversion. + */ + if (pkEncoded[0] != 0x04) // "0x04" is the marker for an uncompressed encoding + { + throw new IllegalArgumentException("'pkEncoded' has invalid format"); + } + + ECPoint G = domainParams.getCurve().decodePoint(pkEncoded); + return new ECPublicKeyParameters(G, domainParams); + case HPKE.kem_X448_SHA512: + return new X448PublicKeyParameters(pkEncoded); + case HPKE.kem_X25519_SHA256: + return new X25519PublicKeyParameters(pkEncoded); + default: + throw new IllegalStateException("invalid kem id"); } } public AsymmetricCipherKeyPair DeserializePrivateKey(byte[] skEncoded, byte[] pkEncoded) { + if (skEncoded == null) + { + throw new NullPointerException("'skEncoded' cannot be null"); + } + if (skEncoded.length != Nsk) + { + throw new IllegalArgumentException("'skEncoded' has invalid length"); + } + AsymmetricKeyParameter pubParam = null; if (pkEncoded != null) @@ -217,34 +247,38 @@ public AsymmetricCipherKeyPair DeserializePrivateKey(byte[] skEncoded, byte[] pk switch (kemId) { - case HPKE.kem_P256_SHA256: - case HPKE.kem_P384_SHA348: - case HPKE.kem_P521_SHA512: - BigInteger d = new BigInteger(1, skEncoded); - ECPrivateKeyParameters ec = new ECPrivateKeyParameters(d, domainParams); - - if (pubParam == null) - { - ECPoint Q = new FixedPointCombMultiplier().multiply(domainParams.getG(), ((ECPrivateKeyParameters)ec).getD()); - pubParam = new ECPublicKeyParameters(Q, domainParams); - } - return new AsymmetricCipherKeyPair(pubParam, ec); - case HPKE.kem_X448_SHA512: - X448PrivateKeyParameters x448 = new X448PrivateKeyParameters(skEncoded); - if (pubParam == null) - { - pubParam = x448.generatePublicKey(); - } - return new AsymmetricCipherKeyPair(pubParam, x448); - case HPKE.kem_X25519_SHA256: - X25519PrivateKeyParameters x25519 = new X25519PrivateKeyParameters(skEncoded); - if (pubParam == null) - { - pubParam = x25519.generatePublicKey(); - } - return new AsymmetricCipherKeyPair(pubParam, x25519); - default: - throw new IllegalStateException("invalid kem id"); + case HPKE.kem_P256_SHA256: + case HPKE.kem_P384_SHA384: + case HPKE.kem_P521_SHA512: + /* + * RFC 9180 7.1.2. For P-256, P-384, and P-521 [..]. DeserializePrivateKey() performs the Octet- + * String-to-Field-Element conversion according to [SECG]. + */ + BigInteger d = new BigInteger(1, skEncoded); + ECPrivateKeyParameters ec = new ECPrivateKeyParameters(d, domainParams); + + if (pubParam == null) + { + ECPoint Q = new FixedPointCombMultiplier().multiply(domainParams.getG(), ((ECPrivateKeyParameters)ec).getD()); + pubParam = new ECPublicKeyParameters(Q, domainParams); + } + return new AsymmetricCipherKeyPair(pubParam, ec); + case HPKE.kem_X448_SHA512: + X448PrivateKeyParameters x448 = new X448PrivateKeyParameters(skEncoded); + if (pubParam == null) + { + pubParam = x448.generatePublicKey(); + } + return new AsymmetricCipherKeyPair(pubParam, x448); + case HPKE.kem_X25519_SHA256: + X25519PrivateKeyParameters x25519 = new X25519PrivateKeyParameters(skEncoded); + if (pubParam == null) + { + pubParam = x25519.generatePublicKey(); + } + return new AsymmetricCipherKeyPair(pubParam, x25519); + default: + throw new IllegalStateException("invalid kem id"); } } @@ -253,7 +287,7 @@ int getEncryptionSize() return Nenc; } - private boolean ValidateSk(BigInteger d) + private boolean validateSk(BigInteger d) { BigInteger n = domainParams.getN(); int nBitLength = n.bitLength(); @@ -287,46 +321,43 @@ public AsymmetricCipherKeyPair DeriveKeyPair(byte[] ikm) switch (kemId) { case HPKE.kem_P256_SHA256: - case HPKE.kem_P384_SHA348: + case HPKE.kem_P384_SHA384: case HPKE.kem_P521_SHA512: + { byte[] dkp_prk = hkdf.LabeledExtract(null, suiteID, "dkp_prk", ikm); - int counter = 0; byte[] counterArray = new byte[1]; - while (true) + for (int counter = 0; counter < 256; ++counter) { - if (counter > 255) - { - throw new IllegalStateException("DeriveKeyPairError"); - } counterArray[0] = (byte)counter; byte[] bytes = hkdf.LabeledExpand(dkp_prk, suiteID, "candidate", counterArray, Nsk); bytes[0] = (byte)(bytes[0] & bitmask); - // generating keypair BigInteger d = new BigInteger(1, bytes); - if (ValidateSk(d)) + if (validateSk(d)) { ECPoint Q = new FixedPointCombMultiplier().multiply(domainParams.getG(), d); ECPrivateKeyParameters sk = new ECPrivateKeyParameters(d, domainParams); ECPublicKeyParameters pk = new ECPublicKeyParameters(Q, domainParams); return new AsymmetricCipherKeyPair(pk, sk); } - - counter++; } + throw new IllegalStateException("DeriveKeyPairError"); + } case HPKE.kem_X448_SHA512: - dkp_prk = hkdf.LabeledExtract(null, suiteID, "dkp_prk", ikm); + { + byte[] dkp_prk = hkdf.LabeledExtract(null, suiteID, "dkp_prk", ikm); byte[] x448sk = hkdf.LabeledExpand(dkp_prk, suiteID, "sk", null, Nsk); X448PrivateKeyParameters x448params = new X448PrivateKeyParameters(x448sk); return new AsymmetricCipherKeyPair(x448params.generatePublicKey(), x448params); - + } case HPKE.kem_X25519_SHA256: - dkp_prk = hkdf.LabeledExtract(null, suiteID, "dkp_prk", ikm); + { + byte[] dkp_prk = hkdf.LabeledExtract(null, suiteID, "dkp_prk", ikm); byte[] skBytes = hkdf.LabeledExpand(dkp_prk, suiteID, "sk", null, Nsk); X25519PrivateKeyParameters sk = new X25519PrivateKeyParameters(skBytes); - return new AsymmetricCipherKeyPair(sk.generatePublicKey(), sk); + } default: throw new IllegalStateException("invalid kem id"); } @@ -341,11 +372,8 @@ protected byte[][] Encap(AsymmetricKeyParameter pkR, AsymmetricCipherKeyPair kpE { byte[][] output = new byte[2][]; - //DH - agreement.init(kpE.getPrivate()); - - byte[] temp = agreement.calculateAgreement(pkR).toByteArray(); - byte[] secret = formatBigIntegerBytes(temp, agreement.getFieldSize()); + // DH + byte[] secret = calculateRawAgreement(rawAgreement, kpE.getPrivate(), pkR); byte[] enc = SerializePublicKey(kpE.getPublic()); byte[] pkRm = SerializePublicKey(pkR); @@ -362,17 +390,13 @@ protected byte[] Decap(byte[] enc, AsymmetricCipherKeyPair kpR) { AsymmetricKeyParameter pkE = DeserializePublicKey(enc); - //DH - agreement.init(kpR.getPrivate()); - - byte[] temp = agreement.calculateAgreement(pkE).toByteArray(); // add leading zeros - byte[] secret = formatBigIntegerBytes(temp, agreement.getFieldSize()); + // DH + byte[] secret = calculateRawAgreement(rawAgreement, kpR.getPrivate(), pkE); byte[] pkRm = SerializePublicKey(kpR.getPublic()); byte[] KEMContext = Arrays.concatenate(enc, pkRm); - byte[] sharedSecret = ExtractAndExpand(secret, KEMContext); - return sharedSecret; + return ExtractAndExpand(secret, KEMContext); } protected byte[][] AuthEncap(AsymmetricKeyParameter pkR, AsymmetricCipherKeyPair kpS) @@ -381,18 +405,23 @@ protected byte[][] AuthEncap(AsymmetricKeyParameter pkR, AsymmetricCipherKeyPair AsymmetricCipherKeyPair kpE = kpGen.generateKeyPair(); // todo: can be replaced with deriveKeyPair(random) - // DH(skE, pkR) - agreement.init(kpE.getPrivate()); - byte[] temp = agreement.calculateAgreement(pkR).toByteArray(); - byte[] secret1 = formatBigIntegerBytes(temp, agreement.getFieldSize()); + rawAgreement.init(kpE.getPrivate()); + int agreementSize = rawAgreement.getAgreementSize(); + + byte[] secret = new byte[agreementSize * 2]; + + rawAgreement.calculateAgreement(pkR, secret, 0); // DH(skS, pkR) - agreement.init(kpS.getPrivate()); - temp = agreement.calculateAgreement(pkR).toByteArray(); - byte[] secret2 = formatBigIntegerBytes(temp, agreement.getFieldSize()); + rawAgreement.init(kpS.getPrivate()); + if (agreementSize != rawAgreement.getAgreementSize()) + { + throw new IllegalStateException(); + } + + rawAgreement.calculateAgreement(pkR, secret, agreementSize); - byte[] secret = Arrays.concatenate(secret1, secret2); byte[] enc = SerializePublicKey(kpE.getPublic()); byte[] pkRm = SerializePublicKey(pkR); @@ -410,25 +439,22 @@ protected byte[] AuthDecap(byte[] enc, AsymmetricCipherKeyPair kpR, AsymmetricKe { AsymmetricKeyParameter pkE = DeserializePublicKey(enc); - // DH(skR, pkE) - agreement.init(kpR.getPrivate()); + rawAgreement.init(kpR.getPrivate()); - byte[] temp = agreement.calculateAgreement(pkE).toByteArray(); // add leading zeros - byte[] secret1 = formatBigIntegerBytes(temp, agreement.getFieldSize()); + int agreementSize = rawAgreement.getAgreementSize(); + byte[] secret = new byte[agreementSize * 2]; - // DH(skR, pkS) - agreement.init(kpR.getPrivate()); - temp = agreement.calculateAgreement(pkS).toByteArray(); - byte[] secret2 = formatBigIntegerBytes(temp, agreement.getFieldSize()); + // DH(skR, pkE) + rawAgreement.calculateAgreement(pkE, secret, 0); - byte[] secret = Arrays.concatenate(secret1, secret2); + // DH(skR, pkS) + rawAgreement.calculateAgreement(pkS, secret, agreementSize); byte[] pkRm = SerializePublicKey(kpR.getPublic()); byte[] pkSm = SerializePublicKey(pkS); byte[] KEMContext = Arrays.concatenate(enc, pkRm, pkSm); - byte[] sharedSecret = ExtractAndExpand(secret, KEMContext); - return sharedSecret; + return ExtractAndExpand(secret, KEMContext); } private byte[] ExtractAndExpand(byte[] dh, byte[] kemContext) @@ -437,21 +463,25 @@ private byte[] ExtractAndExpand(byte[] dh, byte[] kemContext) byte[] eae_prk = hkdf.LabeledExtract(null, suiteID, "eae_prk", dh); - byte[] sharedSecret = hkdf.LabeledExpand(eae_prk, suiteID, "shared_secret", kemContext, Nsecret); - return sharedSecret; + return hkdf.LabeledExpand(eae_prk, suiteID, "shared_secret", kemContext, Nsecret); } - private byte[] formatBigIntegerBytes(byte[] bigIntBytes, int outputSize) + private static byte[] calculateRawAgreement(RawAgreement rawAgreement, AsymmetricKeyParameter privateKey, + AsymmetricKeyParameter publicKey) { - byte[] output = new byte[outputSize]; - if (bigIntBytes.length <= outputSize) - { - System.arraycopy(bigIntBytes, 0, output, outputSize - bigIntBytes.length, bigIntBytes.length); - } - else - { - System.arraycopy(bigIntBytes, bigIntBytes.length - outputSize, output, 0, outputSize); - } - return output; + rawAgreement.init(privateKey); + byte[] z = new byte[rawAgreement.getAgreementSize()]; + rawAgreement.calculateAgreement(publicKey, z, 0); + return z; + } + + private static ECDomainParameters getDomainParameters(String curveName) + { + return new ECDomainParameters(CustomNamedCurves.getByName(curveName)); + } + + private static SecureRandom getSecureRandom() + { + return CryptoServicesRegistrar.getSecureRandom(); } } diff --git a/core/src/main/java/org/bouncycastle/crypto/hpke/HKDF.java b/core/src/main/java/org/bouncycastle/crypto/hpke/HKDF.java index a9e0ef8d37..f69cc8e398 100644 --- a/core/src/main/java/org/bouncycastle/crypto/hpke/HKDF.java +++ b/core/src/main/java/org/bouncycastle/crypto/hpke/HKDF.java @@ -8,10 +8,11 @@ import org.bouncycastle.crypto.params.HKDFParameters; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; +import org.bouncycastle.util.Strings; class HKDF { - private final static String versionLabel = "HPKE-v1"; + private final static byte[] VERSION_LABEL = getBytes("HPKE-v1"); private final HKDFBytesGenerator kdf; private final int hashLength; @@ -50,7 +51,7 @@ protected byte[] LabeledExtract(byte[] salt, byte[] suiteID, String label, byte[ salt = new byte[hashLength]; } - byte[] labeledIKM = Arrays.concatenate(versionLabel.getBytes(), suiteID, label.getBytes(), ikm); + byte[] labeledIKM = Arrays.concatenate(VERSION_LABEL, suiteID, getBytes(label), ikm); return kdf.extractPRK(salt, labeledIKM); } @@ -61,7 +62,9 @@ protected byte[] LabeledExpand(byte[] prk, byte[] suiteID, String label, byte[] { throw new IllegalArgumentException("Expand length cannot be larger than 2^16"); } - byte[] labeledInfo = Arrays.concatenate(Pack.shortToBigEndian((short)L), versionLabel.getBytes(), suiteID, label.getBytes()); + + byte[] labeledInfo = Arrays.concatenate(Pack.shortToBigEndian((short)L), VERSION_LABEL, suiteID, + getBytes(label)); kdf.init(HKDFParameters.skipExtractParameters(prk, Arrays.concatenate(labeledInfo, info))); @@ -97,4 +100,14 @@ protected byte[] Expand(byte[] prk, byte[] info, int L) return rv; } + + private static byte[] getBytes(String label) + { + /* + * RFC 9180 seems silent about this conversion, but all given labels are ASCII anyway. + * + * NOTE: String#getBytes not reliable because it depends on the platform's default charset. + */ + return Strings.toByteArray(label); + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/hpke/HPKE.java b/core/src/main/java/org/bouncycastle/crypto/hpke/HPKE.java index 6841f62dfc..1caf25a31b 100644 --- a/core/src/main/java/org/bouncycastle/crypto/hpke/HPKE.java +++ b/core/src/main/java/org/bouncycastle/crypto/hpke/HPKE.java @@ -17,7 +17,11 @@ public class HPKE // kems public static final short kem_P256_SHA256 = 16; + /** + * @deprecated use kem_P384_SHA384 + */ public static final short kem_P384_SHA348 = 17; + public static final short kem_P384_SHA384 = 17; public static final short kem_P521_SHA512 = 18; public static final short kem_X25519_SHA256 = 32; public static final short kem_X448_SHA512 = 33; diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java new file mode 100644 index 0000000000..d91184101a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMExtractor.java @@ -0,0 +1,224 @@ +package org.bouncycastle.crypto.kems; + +import java.math.BigInteger; + +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.EncapsulatedSecretExtractor; +import org.bouncycastle.crypto.params.SAKKEPrivateKeyParameters; +import org.bouncycastle.crypto.params.SAKKEPublicKeyParameters; +import org.bouncycastle.math.ec.ECAlgorithms; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.BigIntegers; + +/** + * Implements the receiver side of the SAKKE (Sakai-Kasahara Key Encryption) protocol + * as defined in RFC 6508. This class extracts the shared secret value (SSV) from + * encapsulated data using the receiver's private key. + *

    + * The extraction process follows these steps (RFC 6508, Section 6.2.2): + *

      + *
    1. Parse encapsulated data into R_(b,S) and H
    2. + *
    3. Compute pairing result w = <R_(b,S), K_(b,S)>
    4. + *
    5. Recover SSV via SSV = H XOR HashToIntegerRange(w, 2^n)
    6. + *
    7. Validate R_(b,S) by recomputing it with derived parameters
    8. + *
    + *

    + * + * @see Sakai-Kasahara Key Encryption (SAKKE) + */ +public class SAKKEKEMExtractor + implements EncapsulatedSecretExtractor +{ + private final ECCurve curve; + private final BigInteger p; + private final BigInteger q; + private final ECPoint P; + private final ECPoint Z_S; + private final ECPoint K_bs; + private final int n; // Security parameter + private final BigInteger identifier; + private final Digest digest; + + /** + * Initializes the extractor with cryptographic parameters from the receiver's private key. + * + * @param privateKey The receiver's private key containing public parameters + * (curve, prime, generator, etc.) and the Receiver Secret Key (RSK). + * Must not be {@code null}. + */ + public SAKKEKEMExtractor(SAKKEPrivateKeyParameters privateKey) + { + SAKKEPublicKeyParameters publicKey = privateKey.getPublicParams(); + this.curve = publicKey.getCurve(); + this.q = publicKey.getQ(); + this.P = publicKey.getPoint(); + this.p = publicKey.getPrime(); + this.Z_S = publicKey.getZ(); + this.identifier = publicKey.getIdentifier(); + this.K_bs = P.multiply(this.identifier.add(privateKey.getMasterSecret()).modInverse(q)).normalize(); + this.n = publicKey.getN(); + + this.digest = publicKey.getDigest(); + } + + /** + * Extracts the shared secret value (SSV) from encapsulated data as per RFC 6508. + * + * @param encapsulation The encapsulated data containing: + *
      + *
    • R_(b,S): Elliptic curve point (uncompressed format, 257 bytes)
    • + *
    • H: Integer value (n/8 bytes)
    • + *
    + * @return The extracted SSV as a byte array. + * @throws IllegalStateException If: Validation of R_(b,S) fails + */ + @Override + public byte[] extractSecret(byte[] encapsulation) + { + // Step 1: Parse Encapsulated Data (R_bS, H) + ECPoint R_bS = curve.decodePoint(Arrays.copyOfRange(encapsulation, 0, 257)); + BigInteger H = BigIntegers.fromUnsignedByteArray(encapsulation, 257, 16); + + // Step 2: Compute w = using pairing + BigInteger w = computePairing(R_bS, K_bs, p, q); + + // Step 3: Compute SSV = H XOR HashToIntegerRange(w, 2^n) + BigInteger twoToN = BigInteger.ONE.shiftLeft(n); + BigInteger mask = SAKKEKEMSGenerator.hashToIntegerRange(w.toByteArray(), twoToN, digest); + BigInteger ssv = H.xor(mask).mod(p); + + // Step 4: Compute r = HashToIntegerRange(SSV || b) + BigInteger b = identifier; + BigInteger r = SAKKEKEMSGenerator.hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), q, digest); + + // Step 5: Validate R_bS + ECPoint Test; + + BigInteger order = curve.getOrder(); + if (order == null) + { + Test = P.multiply(b).add(Z_S).multiply(r); + } + else + { + BigInteger a = b.multiply(r).mod(order); + Test = ECAlgorithms.sumOfTwoMultiplies(P, a, Z_S, r); + } + + Test = Test.subtract(R_bS); + + if (!Test.isInfinity()) + { + throw new IllegalStateException("Validation of R_bS failed"); + } + + return BigIntegers.asUnsignedByteArray(n / 8, ssv); + } + + @Override + public int getEncapsulationLength() + { + return 273; //257 (length of ECPoint) + 16 (length of Hash) + } + + /** + * Computes the Tate-Lichtenbaum pairing <R, Q> for SAKKE validation. + * Follows the pairing algorithm described in RFC 6508, Section 3.2. + * + * @param R First pairing input (elliptic curve point) + * @param Q Second pairing input (elliptic curve point) + * @param p Prime field characteristic + * @param q Subgroup order + * @return Pairing result in PF_p[q], represented as a field element + */ + static BigInteger computePairing(ECPoint R, ECPoint Q, BigInteger p, BigInteger q) + { + // v = (1,0) in F_p^2 + BigInteger[] v = new BigInteger[]{ BigInteger.ONE, BigInteger.ZERO }; + ECPoint C = R; + + BigInteger qMinusOne = q.subtract(BigInteger.ONE); + int numBits = qMinusOne.bitLength(); + BigInteger Qx = Q.getAffineXCoord().toBigInteger(); + BigInteger Qy = Q.getAffineYCoord().toBigInteger(); + BigInteger Rx = R.getAffineXCoord().toBigInteger(); + BigInteger Ry = R.getAffineYCoord().toBigInteger(); + final BigInteger three = BigInteger.valueOf(3); + + // Miller loop + for (int i = numBits - 2; i >= 0; i--) + { + BigInteger Cx = C.getAffineXCoord().toBigInteger(); + BigInteger Cy = C.getAffineYCoord().toBigInteger(); + + // Compute l = (3 * (Cx^2 - 1)) / (2 * Cy) mod p + BigInteger l = Cx.multiply(Cx).mod(p).subtract(BigInteger.ONE).multiply(three) + .multiply(BigIntegers.modOddInverse(p, Cy.shiftLeft(1))).mod(p); + + // Compute v = v^2 * ( l*( Q_x + C_x ) + ( i*Q_y - C_y ) ) + v = fp2PointSquare(v[0], v[1], p); + v = fp2Multiply(v[0], v[1], l.multiply(Qx.add(Cx)).subtract(Cy).mod(p), Qy, p); + + C = C.twice().normalize(); // C = [2]C + + if (qMinusOne.testBit(i)) + { + Cx = C.getAffineXCoord().toBigInteger(); + Cy = C.getAffineYCoord().toBigInteger(); + + // Compute l = (Cy - Ry) / (Cx - Rx) mod p + l = Cy.subtract(Ry).multiply(BigIntegers.modOddInverse(p, Cx.subtract(Rx))).mod(p); + + // Compute v = v * ( l*( Q_x + C_x ) + ( i*Q_y - C_y ) ) + v = fp2Multiply(v[0], v[1], l.multiply(Qx.add(Cx)).subtract(Cy).mod(p), Qy, p); + + if (i > 0) + { + C = C.add(R).normalize(); + } + } + } + + // Final exponentiation: t = v^c + v = fp2PointSquare(v[0], v[1], p); + v = fp2PointSquare(v[0], v[1], p); + BigInteger v0Inv = BigIntegers.modOddInverse(p, v[0]); + return v[1].multiply(v0Inv).mod(p); + } + + /** + * Performs multiplication in F_p^2 field. + * + * @param a0 Real component of first operand + * @param b0 Imaginary component of first operand + * @param a1 Real component of second operand + * @param b1 Imaginary component of second operand + * @param p Prime field characteristic + * @return Result of multiplication in F_p^2 as [real, imaginary] array + */ + static BigInteger[] fp2Multiply(BigInteger a0, BigInteger b0, BigInteger a1, BigInteger b1, BigInteger p) + { + return new BigInteger[]{ + a0.multiply(a1).subtract(b0.multiply(b1)).mod(p), + a0.multiply(b1).add(b0.multiply(a1)).mod(p) + }; + } + + /** + * Computes squaring operation in F_p^2 field. + * + * @param a Real component of input + * @param b Imaginary component of input + * @param p Prime field characteristic + * @return Squared result in F_p^2 as [newX, newY] array + */ + static BigInteger[] fp2PointSquare(BigInteger a, BigInteger b, BigInteger p) + { + return new BigInteger[]{ + a.add(b).multiply(a.subtract(b)).mod(p), + a.multiply(b).shiftLeft(1).mod(p) + }; + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java new file mode 100644 index 0000000000..06d4b7760d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/kems/SAKKEKEMSGenerator.java @@ -0,0 +1,179 @@ +package org.bouncycastle.crypto.kems; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.EncapsulatedSecretGenerator; +import org.bouncycastle.crypto.SecretWithEncapsulation; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.SAKKEPublicKeyParameters; +import org.bouncycastle.math.ec.ECAlgorithms; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.BigIntegers; + +/** + * This class implements the SAKKE (Sakai-Kasahara Key Encryption) Key Encapsulation Mechanism + * as defined in RFC 6508. It generates an encapsulated shared secret value (SSV) using + * Identity-Based Encryption (IBE) for secure transmission from a Sender to a Receiver. + *

    + * The algorithm follows these steps (as per RFC 6508, Section 6.2.1): + *

      + *
    1. Generate a random SSV in the range [0, 2^n - 1].
    2. + *
    3. Compute r = HashToIntegerRange(SSV || b, q).
    4. + *
    5. Compute R_(b,S) = [r]([b]P + Z_S) on the elliptic curve.
    6. + *
    7. Compute H = SSV XOR HashToIntegerRange(g^r, 2^n).
    8. + *
    9. Encode the encapsulated data (R_(b,S), H).
    10. + *
    + *

    + * + * @see RFC 6508: Sakai-Kasahara Key Encryption (SAKKE) + */ +public class SAKKEKEMSGenerator + implements EncapsulatedSecretGenerator +{ + private final SecureRandom random; + + /** + * Constructs a SAKKEKEMSGenerator with the specified source of randomness. + * + * @param random a {@link SecureRandom} instance for generating cryptographically secure random values. + * Must not be {@code null}. + */ + public SAKKEKEMSGenerator(SecureRandom random) + { + this.random = random; + } + + /** + * Generates an encapsulated shared secret value (SSV) using the recipient's public key parameters + * as specified in RFC 6508, Section 6.2.1. + *

    + * This method performs the following operations: + *

      + *
    • Derives cryptographic parameters from the recipient's public key.
    • + *
    • Generates a random SSV and computes the encapsulation components (R_(b,S), H).
    • + *
    • Encodes the encapsulated data as specified in RFC 6508, Section 4.
    • + *
    + *

    + * + * @param recipientKey the recipient's public key parameters. Must be an instance of + * {@link SAKKEPublicKeyParameters}. Must not be {@code null}. + * @return a {@link SecretWithEncapsulation} containing the SSV and the encapsulated data. + */ + @Override + public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recipientKey) + { + // Extract public parameters from the recipient's key + SAKKEPublicKeyParameters keyParameters = (SAKKEPublicKeyParameters)recipientKey; + ECPoint Z = keyParameters.getZ(); + BigInteger b = keyParameters.getIdentifier(); + BigInteger p = keyParameters.getPrime(); + BigInteger q = keyParameters.getQ(); + BigInteger g = keyParameters.getG(); + int n = keyParameters.getN(); + ECCurve curve = keyParameters.getCurve(); + ECPoint P = keyParameters.getPoint(); + Digest digest = keyParameters.getDigest(); + + // 1. Generate random SSV in range [0, 2^n - 1] + BigInteger ssv = BigIntegers.createRandomBigInteger(n, random); + + // 2. Compute r = HashToIntegerRange(SSV || b, q) + BigInteger r = hashToIntegerRange(Arrays.concatenate(ssv.toByteArray(), b.toByteArray()), q, digest); + + + // 3. Compute R_(b,S) = [r]([b]P + Z_S) + ECPoint R_bS; + + BigInteger order = curve.getOrder(); + if (order == null) + { + R_bS = P.multiply(b).add(Z).multiply(r).normalize(); + } + else + { + BigInteger a = b.multiply(r).mod(order); + R_bS = ECAlgorithms.sumOfTwoMultiplies(P, a, Z, r).normalize(); + } + + // 4. Compute H = SSV XOR HashToIntegerRange( g^r, 2^n ) + BigInteger pointX = BigInteger.ONE; + BigInteger pointY = g; + + // Initialize result with the original point + BigInteger v0 = BigInteger.ONE; + BigInteger v1 = g; + ECPoint current = curve.createPoint(v0, v1); + + // Process bits from MSB-1 down to 0 + for (int i = r.bitLength() - 2; i >= 0; i--) + { + // Square the current point + BigInteger[] rlt = SAKKEKEMExtractor.fp2PointSquare(v0, v1, p); + current = current.timesPow2(2); + v0 = rlt[0]; + v1 = rlt[1]; + // Multiply if bit is set + if (r.testBit(i)) + { + rlt = SAKKEKEMExtractor.fp2Multiply(v0, v1, pointX, pointY, p); + + v0 = rlt[0]; + v1 = rlt[1]; + } + } + + BigInteger v0Inv = BigIntegers.modOddInverse(p, v0); + BigInteger g_r = v1.multiply(v0Inv).mod(p); + + BigInteger mask = hashToIntegerRange(g_r.toByteArray(), BigInteger.ONE.shiftLeft(n), digest); // 2^n + + BigInteger H = ssv.xor(mask); + // 5. Encode encapsulated data (R_bS, H) + byte[] encapsulated = Arrays.concatenate(R_bS.getEncoded(false), BigIntegers.asUnsignedByteArray(16, H)); + + return new SecretWithEncapsulationImpl( + BigIntegers.asUnsignedByteArray(n / 8, ssv), // Output SSV as key material + encapsulated + ); + } + + static BigInteger hashToIntegerRange(byte[] input, BigInteger q, Digest digest) + { + // RFC 6508 Section 5.1: Hashing to an Integer Range + byte[] A = new byte[digest.getDigestSize()]; + + // Step 1: Compute A = hashfn(s) + digest.update(input, 0, input.length); + digest.doFinal(A, 0); + + // Step 2: Initialize h_0 to all-zero bytes of hashlen size + byte[] h = new byte[digest.getDigestSize()]; + + // Step 3: Compute l = Ceiling(lg(n)/hashlen) + // FIXME Seems hardcoded to 256 bit digest? + int l = q.bitLength() >> 8; + + BigInteger v = BigInteger.ZERO; + byte[] v_i = new byte[digest.getDigestSize()]; + + // Step 4: Compute h_i and v_i + for (int i = 0; i <= l; i++) + { + // h_i = hashfn(h_{i-1}) + digest.update(h, 0, h.length); + digest.doFinal(h, 0); + // v_i = hashfn(h_i || A) + digest.update(h, 0, h.length); + digest.update(A, 0, A.length); + digest.doFinal(v_i, 0); + // Append v_i to v' + v = v.shiftLeft(v_i.length * 8).add(new BigInteger(1, v_i)); + } + // Step 6: v = v' mod n + return v.mod(q); + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/macs/KMAC.java b/core/src/main/java/org/bouncycastle/crypto/macs/KMAC.java index ba7d82c05d..bbc8dd645f 100644 --- a/core/src/main/java/org/bouncycastle/crypto/macs/KMAC.java +++ b/core/src/main/java/org/bouncycastle/crypto/macs/KMAC.java @@ -5,9 +5,12 @@ import org.bouncycastle.crypto.Mac; import org.bouncycastle.crypto.Xof; import org.bouncycastle.crypto.digests.CSHAKEDigest; +import org.bouncycastle.crypto.digests.EncodableDigest; import org.bouncycastle.crypto.digests.XofUtils; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Memoable; +import org.bouncycastle.util.Pack; import org.bouncycastle.util.Strings; /** @@ -17,13 +20,14 @@ *

    */ public class KMAC - implements Mac, Xof + implements Mac, Xof, Memoable, EncodableDigest { private static final byte[] padding = new byte[100]; private final CSHAKEDigest cshake; - private final int bitLength; - private final int outputLength; + + private int bitLength; + private int outputLength; private byte[] key; private boolean initialised; @@ -42,12 +46,48 @@ public KMAC(int bitLength, byte[] S) this.outputLength = bitLength * 2 / 8; } + public KMAC(KMAC original) + { + this.cshake = new CSHAKEDigest(original.cshake); + this.bitLength = original.bitLength; + this.outputLength = original.outputLength; + this.key = original.key; + this.initialised = original.initialised; + this.firstOutput = original.firstOutput; + } + + public KMAC(byte[] state) + { + this.key = new byte[state[0] & 0xff]; + System.arraycopy(state, 1, key, 0, key.length); + this.cshake = new CSHAKEDigest(Arrays.copyOfRange(state, 1 + key.length, state.length - 10)); + + this.bitLength = Pack.bigEndianToInt(state, state.length - 10); + this.outputLength = Pack.bigEndianToInt(state, state.length - 6); + this.initialised = state[state.length - 2] != 0; + this.firstOutput = state[state.length - 1] != 0; + } + + private void copyIn(KMAC original) + { + this.cshake.reset(original.cshake); + this.bitLength = original.bitLength; + this.outputLength = original.outputLength; + this.initialised = original.initialised; + this.firstOutput = original.firstOutput; + } + public void init(CipherParameters params) throws IllegalArgumentException { KeyParameter kParam = (KeyParameter)params; this.key = Arrays.clone(kParam.getKey()); + if (this.key.length > 255) // 2^2040 + { + throw new IllegalArgumentException("key length must be between 0 and 2040 bits"); + } + this.initialised = true; reset(); @@ -201,4 +241,39 @@ private static byte[] encode(byte[] X) { return Arrays.concatenate(XofUtils.leftEncode(X.length * 8), X); } + + public byte[] getEncodedState() + { + if (!this.initialised) + { + throw new IllegalStateException("KMAC not initialised"); + } + + byte[] cshakeState = this.cshake.getEncodedState(); + byte[] extraState = new byte[4 + 4 + 2]; + + Pack.intToBigEndian(this.bitLength, extraState, 0); + Pack.intToBigEndian(this.outputLength, extraState, 4); + extraState[8] = this.initialised ? (byte)1 : (byte)0; + extraState[9] = this.firstOutput ? (byte)1 : (byte)0; + + byte[] enc = new byte[1 + key.length + cshakeState.length + extraState.length]; + + enc[0] = (byte)key.length; // key capped at 255 bytes. + System.arraycopy(key, 0, enc, 1, key.length); + System.arraycopy(cshakeState, 0, enc, 1 + key.length, cshakeState.length); + System.arraycopy(extraState, 0, enc, 1 + key.length + cshakeState.length, extraState.length); + + return enc; + } + + public Memoable copy() + { + return new KMAC(this); + } + + public void reset(Memoable other) + { + copyIn((KMAC)other); + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/CCMModeCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/CCMModeCipher.java index d96ac05aee..54b1e371fb 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/CCMModeCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/CCMModeCipher.java @@ -3,4 +3,10 @@ public interface CCMModeCipher extends AEADBlockCipher { + // TODO Add these so that all usages of CCMBlockCipher can be replaced by CCMModeCipher +// byte[] processPacket(byte[] in, int inOff, int inLen) +// throws IllegalStateException, InvalidCipherTextException; +// +// int processPacket(byte[] in, int inOff, int inLen, byte[] output, int outOff) +// throws IllegalStateException, InvalidCipherTextException, DataLengthException; } diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java index af1fa46ded..0671ee4495 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/CTSBlockCipher.java @@ -6,6 +6,7 @@ import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.StreamBlockCipher; +import org.bouncycastle.util.Arrays; /** * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to @@ -146,15 +147,19 @@ public int processBytes( if (len > gapLen) { System.arraycopy(in, inOff, buf, bufOff, gapLen); - + inOff += gapLen; + len -= gapLen; + if (in == out && Arrays.segmentsOverlap(inOff, len, outOff, length)) + { + in = new byte[len]; + System.arraycopy(out, inOff, in, 0, len); + inOff = 0; + } resultLen += cipher.processBlock(buf, 0, out, outOff); System.arraycopy(buf, blockSize, buf, 0, blockSize); bufOff = blockSize; - len -= gapLen; - inOff += gapLen; - while (len > blockSize) { System.arraycopy(in, inOff, buf, bufOff, blockSize); diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/ChaCha20Poly1305.java b/core/src/main/java/org/bouncycastle/crypto/modes/ChaCha20Poly1305.java index 2425dec220..41f703fe38 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/ChaCha20Poly1305.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/ChaCha20Poly1305.java @@ -11,6 +11,7 @@ import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Longs; import org.bouncycastle.util.Pack; public class ChaCha20Poly1305 @@ -307,6 +308,12 @@ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) t { throw new IllegalArgumentException("'outOff' cannot be negative"); } + if (in == out && Arrays.segmentsOverlap(inOff, len, outOff, getUpdateOutputSize(len))) + { + in = new byte[len]; + System.arraycopy(out, inOff, in, 0, len); + inOff = 0; + } checkData(); @@ -524,7 +531,7 @@ private void finishData(int nextState) private long incrementCount(long count, int increment, long limit) { - if (count + Long.MIN_VALUE > (limit - increment) + Long.MIN_VALUE) + if (Longs.compareUnsigned(count, limit - increment) > 0) { throw new IllegalStateException("Limit exceeded"); } diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java index 6eb5ca4fb1..80d766a5d7 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java @@ -224,6 +224,12 @@ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) { throw new DataLengthException("Input buffer too short"); } + if (in == out && Arrays.segmentsOverlap(inOff, len, outOff, getUpdateOutputSize(len))) + { + in = new byte[len]; + System.arraycopy(out, inOff, in, 0, len); + inOff = 0; + } int resultLen = 0; diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/G3413CTRBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/G3413CTRBlockCipher.java index 9e4a677d37..e3dad4ec75 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/G3413CTRBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/G3413CTRBlockCipher.java @@ -13,8 +13,6 @@ public class G3413CTRBlockCipher extends StreamBlockCipher { - - private final int s; private byte[] CTR; private byte[] IV; @@ -24,7 +22,6 @@ public class G3413CTRBlockCipher private int byteCount = 0; private boolean initialized; - /** * Basic constructor. * @@ -76,7 +73,6 @@ public void init( CipherParameters params) throws IllegalArgumentException { - if (params instanceof ParametersWithIV) { ParametersWithIV ivParam = (ParametersWithIV)params; @@ -95,7 +91,7 @@ public void init( { CTR[i] = 0; } - + // if null it's an IV changed only. if (ivParam.getParameters() != null) { @@ -184,27 +180,33 @@ protected byte calculateByte(byte in) if (byteCount == s) { byteCount = 0; - generateCRT(); + generateCTR(); } return rv; } - private void generateCRT() + private void generateCTR() { - CTR[CTR.length - 1]++; + int start = CTR.length - 1; + while (++CTR[start] == 0) + { + start--; + if (start == IV.length - 1) + { + throw new IllegalStateException("attempt to process too many blocks"); + } + } } private byte[] generateBuf() { - byte[] encryptedCTR = new byte[CTR.length]; cipher.processBlock(CTR, 0, encryptedCTR, 0); return GOST3413CipherUtil.MSB(encryptedCTR, s); - } diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java index 017847ef8d..42c0c23528 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java @@ -383,7 +383,12 @@ public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) { throw new DataLengthException("Input buffer too short"); } - + if (in == out && Arrays.segmentsOverlap(inOff, len, outOff, getUpdateOutputSize(len))) + { + in = new byte[len]; + System.arraycopy(out, inOff, in, 0, len); + inOff = 0; + } int resultLen = 0; if (forEncryption) diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/GCMSIVBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/GCMSIVBlockCipher.java index 404629bc4a..bc17c1bff3 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/GCMSIVBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/GCMSIVBlockCipher.java @@ -257,8 +257,7 @@ private void checkAEADStatus(final int pLen) } /* Make sure that we haven't breached AEAD data limit */ - if (theAEADHasher.getBytesProcessed() + Long.MIN_VALUE - > (MAX_DATALEN - pLen) + Long.MIN_VALUE) + if (Longs.compareUnsigned(theAEADHasher.getBytesProcessed(), MAX_DATALEN - pLen) > 0) { throw new IllegalStateException("AEAD byte count exceeded"); } @@ -291,8 +290,7 @@ private void checkStatus(final int pLen) dataLimit += BUFLEN; currBytes = theEncData.size(); } - if (currBytes + Long.MIN_VALUE - > (dataLimit - pLen) + Long.MIN_VALUE) + if (Longs.compareUnsigned(currBytes, dataLimit - pLen) > 0) { throw new IllegalStateException("byte count exceeded"); } diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/KCCMBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/KCCMBlockCipher.java index 18238ca706..a1384fc706 100755 --- a/core/src/main/java/org/bouncycastle/crypto/modes/KCCMBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/KCCMBlockCipher.java @@ -455,7 +455,7 @@ private void intToBytes( private byte getFlag(boolean authTextPresents, int macSize) { - StringBuffer flagByte = new StringBuffer(); + StringBuilder flagByte = new StringBuilder(); if (authTextPresents) { @@ -489,7 +489,7 @@ private byte getFlag(boolean authTextPresents, int macSize) String binaryNb = Integer.toBinaryString(Nb_ - 1); while (binaryNb.length() < 4) { - binaryNb = new StringBuffer(binaryNb).insert(0, "0").toString(); + binaryNb = new StringBuilder(binaryNb).insert(0, "0").toString(); } flagByte.append(binaryNb); diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/KXTSBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/KXTSBlockCipher.java index 2062fea183..62ece62b53 100755 --- a/core/src/main/java/org/bouncycastle/crypto/modes/KXTSBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/KXTSBlockCipher.java @@ -6,6 +6,7 @@ import org.bouncycastle.crypto.DefaultBufferedBlockCipher; import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; /** @@ -123,16 +124,21 @@ public int processBytes(byte[] input, int inOff, int len, byte[] output, int out { throw new IllegalArgumentException("Partial blocks not supported"); } - + if (input == output && Arrays.segmentsOverlap(inOff, len, outOff, len)) + { + input = new byte[len]; + System.arraycopy(output, inOff, input, 0, len); + inOff = 0; + } for (int pos = 0; pos < len; pos += blockSize) { - processBlocks(input, inOff + pos, output, outOff + pos); + processBlock(input, inOff + pos, output, outOff + pos); } return len; } - private void processBlocks(byte[] input, int inOff, byte[] output, int outOff) + private void processBlock(byte[] input, int inOff, byte[] output, int outOff) { /* * A somewhat arbitrary limit of 2^32 - 1 blocks diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/NISTCTSBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/NISTCTSBlockCipher.java index e13c6ea9a5..66df8ddf0e 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/NISTCTSBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/NISTCTSBlockCipher.java @@ -9,6 +9,7 @@ import org.bouncycastle.crypto.DefaultBufferedBlockCipher; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.OutputLengthException; +import org.bouncycastle.util.Arrays; /** * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to @@ -155,15 +156,19 @@ public int processBytes( if (len > gapLen) { System.arraycopy(in, inOff, buf, bufOff, gapLen); - + inOff += gapLen; + len -= gapLen; + if (in == out && Arrays.segmentsOverlap(inOff, len, outOff, length)) + { + in = new byte[len]; + System.arraycopy(out, inOff, in, 0, len); + inOff = 0; + } resultLen += cipher.processBlock(buf, 0, out, outOff); System.arraycopy(buf, blockSize, buf, 0, blockSize); bufOff = blockSize; - len -= gapLen; - inOff += gapLen; - while (len > blockSize) { System.arraycopy(in, inOff, buf, bufOff, blockSize); diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java index 93854eadc1..fd03272a4f 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java @@ -333,7 +333,12 @@ public int processBytes(byte[] input, int inOff, int len, byte[] output, int out throw new DataLengthException("Input buffer too short"); } int resultLen = 0; - + if (input == output && Arrays.segmentsOverlap(inOff, len, outOff, getUpdateOutputSize(len))) + { + input = new byte[len]; + System.arraycopy(output, inOff, input, 0, len); + inOff = 0; + } for (int i = 0; i < len; ++i) { mainBlock[mainBlockPos] = input[inOff + i]; diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/OldCTSBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/OldCTSBlockCipher.java index 13ba147753..3b09bf3ab2 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/OldCTSBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/OldCTSBlockCipher.java @@ -5,6 +5,7 @@ import org.bouncycastle.crypto.DefaultBufferedBlockCipher; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.OutputLengthException; +import org.bouncycastle.util.Arrays; /** * A Cipher Text Stealing (CTS) mode cipher. CTS allows block ciphers to @@ -149,15 +150,19 @@ public int processBytes( if (len > gapLen) { System.arraycopy(in, inOff, buf, bufOff, gapLen); - + inOff += gapLen; + len -= gapLen; + if (in == out && Arrays.segmentsOverlap(inOff, len, outOff, length)) + { + in = new byte[len]; + System.arraycopy(out, inOff, in, 0, len); + inOff = 0; + } resultLen += cipher.processBlock(buf, 0, out, outOff); System.arraycopy(buf, blockSize, buf, 0, blockSize); bufOff = blockSize; - len -= gapLen; - inOff += gapLen; - while (len > blockSize) { System.arraycopy(in, inOff, buf, bufOff, blockSize); diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java index 95f386b9a5..f9a606a2b3 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/SICBlockCipher.java @@ -41,6 +41,7 @@ public static CTRModeCipher newInstance(BlockCipher cipher) * @param c the block cipher to be used. * @deprecated use newInstance() method. */ + @Deprecated public SICBlockCipher(BlockCipher c) { super(c); diff --git a/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java index 28ec78bff9..9250a649cf 100644 --- a/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java @@ -7,6 +7,7 @@ import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.util.Arrays; /** * A wrapper class that allows block ciphers to be used to process data in @@ -202,12 +203,18 @@ public int processBytes( if (len > gapLen) { System.arraycopy(in, inOff, buf, bufOff, gapLen); + inOff += gapLen; + len -= gapLen; + if (in == out && Arrays.segmentsOverlap(inOff, len, outOff, length)) + { + in = new byte[len]; + System.arraycopy(out, inOff, in, 0, len); + inOff = 0; + } resultLen += cipher.processBlock(buf, 0, out, outOff); bufOff = 0; - len -= gapLen; - inOff += gapLen; while (len > buf.length) { diff --git a/core/src/main/java/org/bouncycastle/crypto/params/DESParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/DESParameters.java index 061d134f6f..c568001db4 100644 --- a/core/src/main/java/org/bouncycastle/crypto/params/DESParameters.java +++ b/core/src/main/java/org/bouncycastle/crypto/params/DESParameters.java @@ -1,5 +1,7 @@ package org.bouncycastle.crypto.params; +import org.bouncycastle.util.Arrays; + public class DESParameters extends KeyParameter { @@ -17,14 +19,14 @@ public DESParameters( /* * DES Key length in bytes. */ - static public final int DES_KEY_LENGTH = 8; + public static final int DES_KEY_LENGTH = 8; /* * Table of weak and semi-weak keys taken from Schneier pp281 */ - static private final int N_DES_WEAK_KEYS = 16; + private static final int N_DES_WEAK_KEYS = 16; - static private byte[] DES_weak_keys = + private static byte[] DES_weak_keys = { /* weak keys */ (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, @@ -58,27 +60,21 @@ public DESParameters( * @return true if the given DES key material is weak or semi-weak, * false otherwise. */ - public static boolean isWeakKey( - byte[] key, - int offset) + public static boolean isWeakKey(byte[] key, int offset) { - if (key.length - offset < DES_KEY_LENGTH) + if (offset > (key.length - DES_KEY_LENGTH)) { throw new IllegalArgumentException("key material too short."); } - nextkey: for (int i = 0; i < N_DES_WEAK_KEYS; i++) + for (int i = 0; i < N_DES_WEAK_KEYS; i++) { - for (int j = 0; j < DES_KEY_LENGTH; j++) + if (Arrays.constantTimeAreEqual(DES_KEY_LENGTH, key, offset, DES_weak_keys, i * DES_KEY_LENGTH)) { - if (key[j + offset] != DES_weak_keys[i * DES_KEY_LENGTH + j]) - { - continue nextkey; - } + return true; } - - return true; } + return false; } diff --git a/core/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java index 5b2d0d46a6..c6984342ac 100644 --- a/core/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java +++ b/core/src/main/java/org/bouncycastle/crypto/params/DESedeParameters.java @@ -6,7 +6,7 @@ public class DESedeParameters /* * DES-EDE Key length in bytes. */ - static public final int DES_EDE_KEY_LENGTH = 24; + public static final int DES_EDE_KEY_LENGTH = 24; public DESedeParameters( byte[] key) diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java new file mode 100644 index 0000000000..4df70d28bd --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java @@ -0,0 +1,159 @@ +package org.bouncycastle.crypto.params; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.KeyGenerationParameters; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.BigIntegers; + +/** + * Parameters for ECCSI key generation. + * + *

    + * This class encapsulates the parameters required for ECCSI (Elliptic Curve + * Certificateless Signatures for Identity-based encryption) key generation. + * It holds the elliptic curve domain parameters and computes the key pair + * components used in ECCSI. + *

    + * + *

    + * The secret component {@code ksak} is generated randomly and reduced modulo + * {@code q}, while {@code kpak} is derived from {@code ksak} by multiplying the + * generator point. + *

    + */ +public class ECCSIKeyGenerationParameters + extends KeyGenerationParameters +{ + /** + * The order of the elliptic curve. + */ + private final BigInteger q; + + /** + * The generator (base point) of the elliptic curve. + */ + private final ECPoint G; + + /** + * The digest algorithm used in key generation. + */ + private final Digest digest; + + /** + * The identifier (e.g. user identity) used in key generation. + */ + private final byte[] id; + + /** + * The secret key component (ksak) used in ECCSI, generated randomly. + */ + private final BigInteger ksak; + + /** + * The public key component (kpak), computed as G * ksak. + */ + private final ECPoint kpak; + + /** + * The bit length used for key generation (typically the bit length of the curve's parameter A). + */ + private final int n; + + /** + * Constructs an instance of {@code ECCSIKeyGenerationParameters} with the specified + * source of randomness, elliptic curve parameters, digest algorithm, and identifier. + * + * @param random the source of randomness. + * @param params the elliptic curve parameters (in X9.62 format) providing the curve, order, and generator. + * @param digest the digest algorithm to be used. + * @param id the identifier associated with the key generation (e.g. a user or device ID). + */ + public ECCSIKeyGenerationParameters(SecureRandom random, X9ECParameters params, Digest digest, byte[] id) + { + super(random, params.getCurve().getA().bitLength()); + this.q = params.getCurve().getOrder(); + this.G = params.getG(); + this.digest = digest; + this.id = Arrays.clone(id); + this.n = params.getCurve().getA().bitLength(); + this.ksak = BigIntegers.createRandomBigInteger(n, random).mod(q); + this.kpak = G.multiply(ksak).normalize(); + } + + /** + * Returns a copy of the identifier used in these parameters. + * + * @return a byte array containing the identifier. + */ + public byte[] getId() + { + return Arrays.clone(id); + } + + /** + * Returns the public key component (kpak) corresponding to the secret key. + * + * @return the public key point. + */ + public ECPoint getKPAK() + { + return kpak; + } + + /** + * Computes the session secret key (SSK) by adding the provided value to the secret key component + * and reducing modulo the curve order. + * + * @param hs_v a BigInteger value (typically derived from a hash) to be added to the secret. + * @return the computed session secret key. + */ + public BigInteger computeSSK(BigInteger hs_v) + { + return ksak.add(hs_v).mod(q); + } + + /** + * Returns the order of the elliptic curve. + * + * @return the curve order. + */ + public BigInteger getQ() + { + return q; + } + + /** + * Returns the generator (base point) of the elliptic curve. + * + * @return the generator point. + */ + public ECPoint getG() + { + return G; + } + + /** + * Returns the digest algorithm used for key generation. + * + * @return the digest. + */ + public Digest getDigest() + { + return digest; + } + + /** + * Returns the bit length used in key generation. + * + * @return the bit length. + */ + public int getN() + { + return n; + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java new file mode 100644 index 0000000000..bc37f5f839 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPrivateKeyParameters.java @@ -0,0 +1,72 @@ +package org.bouncycastle.crypto.params; + +import java.math.BigInteger; + +/** + * Represents the private key parameters for the Elliptic Curve-based Certificateless + * Signature Infrastructure (ECCSI) scheme as defined in RFC 6507. + * + *

    + * This class encapsulates the secret signing key (SSK) used in ECCSI. The SSK is generated by + * the Key Management Service (KMS) and is a random integer modulo the order of the elliptic curve. + * It is paired with the corresponding public key parameters, represented by an instance of + * {@link ECCSIPublicKeyParameters}, to form the complete key material required for generating + * and verifying ECCSI signatures without the use of traditional certificates. + *

    + * + *

    + * Per RFC 6507 Section 5.1: + *

      + *
    • The SSK is generated as a random value in the appropriate range.
    • + *
    • It is used in conjunction with the public validation token (PVT) to perform signature + * operations.
    • + *
    • The combination of the SSK and the public key parameters enables certificateless + * signature generation and verification.
    • + *
    + *

    + * + * @see ECCSIPublicKeyParameters + * @see + * RFC 6507: Elliptic Curve-Based Certificateless Signatures for Identity-Based Encryption (ECCSI) + * + */ +public class ECCSIPrivateKeyParameters + extends AsymmetricKeyParameter +{ + private final BigInteger ssk; + private final ECCSIPublicKeyParameters pub; + + /** + * Constructs {@code ECCSIPrivateKeyParameters} with the specified secret signing key + * and associated public key parameters. + * + * @param ssk the secret signing key (SSK) as a BigInteger. + * @param pub the corresponding public key parameters, which encapsulate the public validation token. + */ + public ECCSIPrivateKeyParameters(BigInteger ssk, ECCSIPublicKeyParameters pub) + { + super(true); + this.ssk = ssk; + this.pub = pub; + } + + /** + * Returns the public key parameters associated with this private key. + * + * @return the {@link ECCSIPublicKeyParameters} containing the public validation token (PVT). + */ + public ECCSIPublicKeyParameters getPublicKeyParameters() + { + return pub; + } + + /** + * Returns the secret signing key (SSK) used in ECCSI. + * + * @return the SSK as a BigInteger. + */ + public BigInteger getSSK() + { + return ssk; + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java new file mode 100644 index 0000000000..15269a0b46 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/params/ECCSIPublicKeyParameters.java @@ -0,0 +1,50 @@ +package org.bouncycastle.crypto.params; + +import org.bouncycastle.math.ec.ECPoint; + +/** + * Represents the public key parameters for the Elliptic Curve-based Certificateless + * Signature Infrastructure (ECCSI) scheme as defined in RFC 6507. + *

    + * This class encapsulates the Public Validation Token (PVT) required for verifying + * ECCSI signatures. The PVT is cryptographically bound to a user's identity and + * generated by the Key Management Service (KMS) as part of the key material. + * + *

    Per RFC 6507 Section 5.1: + *

      + *
    • The PVT is derived from the user's identity and KMS secret material
    • + *
    • Used during signature verification to validate the signer's identity
    • + *
    • Does not require certificates for authentication
    • + *
    + * + * @see RFC 6507: Elliptic Curve-Based Certificateless + * * Signatures for Identity-Based Encryption (ECCSI) + */ + +public class ECCSIPublicKeyParameters + extends AsymmetricKeyParameter +{ + private final ECPoint pvt; + + /** + * Constructs {@code ECCSIPublicKeyParameters} with the provided Public Validation Token (PVT). + */ + public ECCSIPublicKeyParameters(ECPoint pvt) + { + super(false); + this.pvt = pvt; + } + + /** + * Returns the Public Validation Token (PVT) for signature verification. + *

    + * The PVT is used in conjunction with the KMS Public Authentication Key (KPAK) + * to verify signatures per RFC 6507 Section 5.2.2. + * + * @return The PVT as an elliptic curve point in uncompressed format + */ + public final ECPoint getPVT() + { + return pvt; + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/params/HKDFParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/HKDFParameters.java index 2db3ce613f..6374e90932 100644 --- a/core/src/main/java/org/bouncycastle/crypto/params/HKDFParameters.java +++ b/core/src/main/java/org/bouncycastle/crypto/params/HKDFParameters.java @@ -10,7 +10,7 @@ public class HKDFParameters implements DerivationParameters { private final byte[] ikm; - private final boolean skipExpand; + private final boolean skipExtract; private final byte[] salt; private final byte[] info; @@ -25,7 +25,7 @@ private HKDFParameters(final byte[] ikm, final boolean skip, this.ikm = Arrays.clone(ikm); - this.skipExpand = skip; + this.skipExtract = skip; if (salt == null || salt.length == 0) { @@ -91,13 +91,13 @@ public byte[] getIKM() } /** - * Returns if step 1: extract has to be skipped or not + * Returns if step 1: expand has to be skipped or not * * @return true for skipping, false for no skipping of step 1 */ public boolean skipExtract() { - return skipExpand; + return skipExtract; } /** diff --git a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java new file mode 100644 index 0000000000..9e3be92c3f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPrivateKeyParameters.java @@ -0,0 +1,91 @@ +package org.bouncycastle.crypto.params; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.BigIntegers; + +/** + * Represents a private key for the Sakai-Kasahara Key Encryption (SAKKE) scheme, as defined in RFC 6508. + * + *

    SAKKE is an identity-based public key encryption scheme designed for one-pass key establishment. + * It is used in MIKEY-SAKKE for secure communication key distribution.

    + * + *

    This class generates and manages a SAKKE private key, which consists of a randomly generated + * scalar {@code z}. The corresponding public key is computed as {@code Z = [z]P}, where {@code P} + * is a publicly known generator point on the elliptic curve.

    + * + *

    The private key is used to derive the master secret in the key exchange process.

    + * + * @see RFC 6508: Sakai-Kasahara Key Encryption (SAKKE) + */ +public class SAKKEPrivateKeyParameters + extends AsymmetricKeyParameter +{ + private static final BigInteger qMinOne = SAKKEPublicKeyParameters.q.subtract(BigInteger.ONE); + /** + * The associated public key parameters. + */ + private final SAKKEPublicKeyParameters publicParams; + /** + * The private key scalar (master secret). + */ + private final BigInteger z; // KMS Public Key: Z = [z]P + + /** + * Constructs a SAKKE private key with a given private value and associated public parameters. + * + * @param z The private key scalar. + * @param publicParams The associated public key parameters. + */ + public SAKKEPrivateKeyParameters(BigInteger z, SAKKEPublicKeyParameters publicParams) + { + super(true); + this.z = z; + this.publicParams = publicParams; + ECPoint computed_Z = publicParams.getPoint().multiply(z).normalize(); + if (!computed_Z.equals(publicParams.getZ())) + { + throw new IllegalStateException("public key and private key of SAKKE do not match"); + } + } + + /** + * Generates a random SAKKE private key and its corresponding public key. + * + *

    The private key scalar {@code z} is chosen randomly in the range [2, q-1], + * where {@code q} is the order of the subgroup. The public key is computed as + * {@code Z = [z]P}, where {@code P} is the public generator.

    + * + * @param random A cryptographic random number generator. + */ + public SAKKEPrivateKeyParameters(SecureRandom random) + { + super(true); + this.z = BigIntegers.createRandomInRange(BigIntegers.TWO, qMinOne, random); + BigInteger identifier = BigIntegers.createRandomInRange(BigIntegers.TWO, qMinOne, random); + this.publicParams = new SAKKEPublicKeyParameters(identifier, + SAKKEPublicKeyParameters.P.multiply(z).normalize()); + } + + /** + * Retrieves the public key parameters associated with this private key. + * + * @return The corresponding SAKKE public key parameters. + */ + public SAKKEPublicKeyParameters getPublicParams() + { + return publicParams; + } + + /** + * Retrieves the private key scalar (master secret). + * + * @return The private key scalar {@code z}. + */ + public BigInteger getMasterSecret() + { + return z; + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java new file mode 100644 index 0000000000..044d716cdd --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/params/SAKKEPublicKeyParameters.java @@ -0,0 +1,208 @@ +package org.bouncycastle.crypto.params; + +import java.math.BigInteger; + +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.WNafUtil; +import org.bouncycastle.util.encoders.Hex; + +/** + * Represents the public parameters for the SAKKE (Sakai-Kasahara Key Encryption) scheme + * as defined in RFC 6508. This class encapsulates the cryptographic domain parameters + * and public key components required for SAKKE operations. + *

    + * Contains the following public parameters (RFC 6508, Section 2.3): + *

      + *
    • Prime modulus {@code p} defining the field F_p
    • + *
    • Subgroup order {@code q} (divides p+1)
    • + *
    • Base point {@code P} on the elliptic curve E(F_p)
    • + *
    • Pairing result {@code g = }
    • + *
    • KMS Public Key {@code Z_S = [z_S]P}
    • + *
    • Security parameter {@code n} (SSV bit length)
    • + *
    • User Identifier
    • + *
    • Elliptic curve parameters (a = -3, b = 0)
    • + *
    + *

    + *

    + * The predefined parameters in this implementation correspond to the 128-bit security + * level example from RFC 6509 Appendix A. + *

    + * + * @see RFC 6508: Sakai-Kasahara Key Encryption + * @see RFC 6509: MIKEY-SAKKE + */ +public class SAKKEPublicKeyParameters + extends AsymmetricKeyParameter +{ + private static ECPoint configureBasepoint(ECCurve curve, BigInteger x, BigInteger y) + { + ECPoint G = curve.createPoint(x, y); + WNafUtil.configureBasepoint(G); + return G; + } + + /** + * Prime modulus p defining the finite field F_p (RFC 6508, Section 2.1). + * Value from RFC 6509 Appendix A. + */ + static final BigInteger p = new BigInteger( + "997ABB1F0A563FDA65C61198DAD0657A416C0CE19CB48261BE9AE358B3E01A2E" + + "F40AAB27E2FC0F1B228730D531A59CB0E791B39FF7C88A19356D27F4A666A6D0" + + "E26C6487326B4CD4512AC5CD65681CE1B6AFF4A831852A82A7CF3C521C3C09AA" + + "9F94D6AF56971F1FFCE3E82389857DB080C5DF10AC7ACE87666D807AFEA85FEB", 16 + ); + + /** + * Subgroup order q (divides p+1) (RFC 6508, Section 2.1). + * Value from RFC 6509 Appendix A. + */ + static final BigInteger q = new BigInteger( + "265EAEC7C2958FF69971846636B4195E905B0338672D20986FA6B8D62CF8068B" + + "BD02AAC9F8BF03C6C8A1CC354C69672C39E46CE7FDF222864D5B49FD2999A9B4" + + "389B1921CC9AD335144AB173595A07386DABFD2A0C614AA0A9F3CF14870F026A" + + "A7E535ABD5A5C7C7FF38FA08E2615F6C203177C42B1EB3A1D99B601EBFAA17FB", 16 + ); + + private static final BigInteger Px = new BigInteger( + "53FC09EE332C29AD0A7990053ED9B52A2B1A2FD60AEC69C698B2F204B6FF7CBF" + + "B5EDB6C0F6CE2308AB10DB9030B09E1043D5F22CDB9DFA55718BD9E7406CE890" + + "9760AF765DD5BCCB337C86548B72F2E1A702C3397A60DE74A7C1514DBA66910D" + + "D5CFB4CC80728D87EE9163A5B63F73EC80EC46C4967E0979880DC8ABEAE63895", 16 + ); + + + private static final BigInteger Py = new BigInteger( + "0A8249063F6009F1F9F1F0533634A135D3E82016029906963D778D821E141178" + + "F5EA69F4654EC2B9E7F7F5E5F0DE55F66B598CCF9A140B2E416CFF0CA9E032B9" + + "70DAE117AD547C6CCAD696B5B7652FE0AC6F1E80164AA989492D979FC5A4D5F2" + + "13515AD7E9CB99A980BDAD5AD5BB4636ADB9B5706A67DCDE75573FD71BEF16D7", 16 + ); + + /** + * Pairing result g = computed using the Tate-Lichtenbaum pairing + * (RFC 6508, Section 3.2). Value from RFC 6509 Appendix A. + */ + private static final BigInteger g = new BigInteger(1, Hex.decode("66FC2A43 2B6EA392 148F1586 7D623068\n" + + " C6A87BD1 FB94C41E 27FABE65 8E015A87\n" + + " 371E9474 4C96FEDA 449AE956 3F8BC446\n" + + " CBFDA85D 5D00EF57 7072DA8F 541721BE\n" + + " EE0FAED1 828EAB90 B99DFB01 38C78433\n" + + " 55DF0460 B4A9FD74 B4F1A32B CAFA1FFA\n" + + " D682C033 A7942BCC E3720F20 B9B7B040\n" + + " 3C8CAE87 B7A0042A CDE0FAB3 6461EA46")); + + /** + * The elliptic curve E: y² = x³ - 3x over F_p (RFC 6508, Section 3.1). + * Uses parameters from RFC 6509 Appendix A. + */ + private static final ECCurve.Fp curve = new ECCurve.Fp( + p, // Prime p + p.subtract(BigInteger.valueOf(3)), // a = -3 + BigInteger.ZERO, + q, // Order of the subgroup (from RFC 6509) + BigInteger.valueOf(4) // Cofactor = 1 + ); + + /** + * Base point P on the elliptic curve E(F_p) (RFC 6508, Section 3.1). + * Coordinates from RFC 6509 Appendix A. + */ + static final ECPoint P = configureBasepoint(curve, Px, Py); + /** KMS Public Key Z_S = [z_S]P (RFC 6508, Section 2.2) */ + private final ECPoint Z; + /** User's Identifier (RFC 6508, Section 2.2) */ + private final BigInteger identifier; // User's identity + /** Security parameter: SSV bit length (n = 128 bits) */ + private static final int n = 128; // SSV bit length + /** Hash function (SHA-256) used in SAKKE operations */ + private final Digest digest = new SHA256Digest(); + /** + * Constructs SAKKE public key parameters with the specified identifier and KMS Public Key. + * + * @param identifier The user's identifier as defined in RFC 6508, Section 2.2. + * Must be a valid integer in [2, q-1]. + * @param Z The KMS Public Key Z_S = [z_S]P (RFC 6508, Section 2.2). + * Must be a valid point on the curve E(F_p). + */ + public SAKKEPublicKeyParameters(BigInteger identifier, ECPoint Z) + { + super(false); + this.identifier = identifier; + this.Z = Z; + } + + /** + * @return The user's identifier (RFC 6508, Section 2.2) + */ + public BigInteger getIdentifier() + { + return identifier; + } + + /** + * @return The KMS Public Key Z_S = [z_S]P (RFC 6508, Section 2.2) + */ + public ECPoint getZ() + { + return Z; + } + + /** + * @return The elliptic curve E(F_p) with parameters from RFC 6509 Appendix A + */ + public ECCurve getCurve() + { + return curve; + } + + /** + * @return The base point P on E(F_p) (RFC 6508, Section 3.1) + */ + public ECPoint getPoint() + { + return P; + } + + /** + * @return Prime modulus p defining the field F_p (RFC 6508, Section 2.1) + */ + public BigInteger getPrime() + { + return p; + } + + /** + * @return Subgroup order q (divides p+1) (RFC 6508, Section 2.1) + */ + public BigInteger getQ() + { + return q; + } + + /** + * @return Security parameter n (SSV bit length = 128 bits) + */ + public int getN() + { + return n; + } + + /** + * @return The hash function (SHA-256) used in SAKKE operations + */ + public Digest getDigest() + { + return digest; + } + + /** + * @return The pairing result {@code g = } (RFC 6508, Section 3.2) + */ + public BigInteger getG() + { + return g; + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java index 83fa545e58..2d3aaba7d9 100644 --- a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java +++ b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java @@ -2,8 +2,8 @@ import java.math.BigInteger; -import org.bouncycastle.asn1.nist.NISTNamedCurves; import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.ec.CustomNamedCurves; import org.bouncycastle.crypto.prng.EntropySource; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECMultiplier; @@ -36,23 +36,18 @@ public class DualECSP800DRBG private static final BigInteger p521_Qx = new BigInteger("1b9fa3e518d683c6b65763694ac8efbaec6fab44f2276171a42726507dd08add4c3b3f4c1ebc5b1222ddba077f722943b24c3edfa0f85fe24d0c8c01591f0be6f63", 16); private static final BigInteger p521_Qy = new BigInteger("1f3bdba585295d9a1110d1df1f9430ef8442c5018976ff3437ef91b81dc0b8132c8d5c39c32d0e004a3092b7d327c0e7a4d26d2c7b69b58f9066652911e457779de", 16); - private static final DualECPoints[] nistPoints; - - static + private static final DualECPoints[] nistPoints = new DualECPoints[] { - nistPoints = new DualECPoints[3]; - - ECCurve.Fp curve = (ECCurve.Fp)NISTNamedCurves.getByNameLazy("P-256").getCurve(); - - nistPoints[0] = new DualECPoints(128, curve.createPoint(p256_Px, p256_Py), curve.createPoint(p256_Qx, p256_Qy), 1); - - curve = (ECCurve.Fp)NISTNamedCurves.getByNameLazy("P-384").getCurve(); - - nistPoints[1] = new DualECPoints(192, curve.createPoint(p384_Px, p384_Py), curve.createPoint(p384_Qx, p384_Qy), 1); + createDualECPoints("P-256", 128, p256_Px, p256_Py, p256_Qx, p256_Qy, 1), + createDualECPoints("P-384", 192, p384_Px, p384_Py, p384_Qx, p384_Qy, 1), + createDualECPoints("P-521", 256, p521_Px, p521_Py, p521_Qx, p521_Qy, 1), + }; - curve = (ECCurve.Fp)NISTNamedCurves.getByNameLazy("P-521").getCurve(); - - nistPoints[2] = new DualECPoints(256, curve.createPoint(p521_Px, p521_Py), curve.createPoint(p521_Qx, p521_Qy), 1); + private static DualECPoints createDualECPoints(String curveName, int securityStrength, BigInteger Px, + BigInteger Py, BigInteger Qx, BigInteger Qy, int cofactor) + { + ECCurve.AbstractFp c = (ECCurve.AbstractFp)CustomNamedCurves.getByNameLazy(curveName).getCurve(); + return new DualECPoints(securityStrength, c.createPoint(Px, Py), c.createPoint(Qx, Qy), cofactor); } @@ -67,7 +62,6 @@ public class DualECSP800DRBG private int _securityStrength; private int _seedlen; private int _outlen; - private ECCurve.Fp _curve; private ECPoint _P; private ECPoint _Q; private byte[] _s; @@ -210,11 +204,9 @@ public int generate(byte[] output, byte[] additionalInput, boolean predictionRes { s = getScalarMultipleXCoord(_P, s); - //System.err.println("S: " + new String(Hex.encode(_s))); - byte[] r = getScalarMultipleXCoord(_Q, s).toByteArray(); - if (r.length > _outlen) + if (r.length >= _outlen) { System.arraycopy(r, r.length - _outlen, output, outOffset, _outlen); } @@ -223,7 +215,6 @@ public int generate(byte[] output, byte[] additionalInput, boolean predictionRes System.arraycopy(r, 0, output, outOffset + (_outlen - r.length), r.length); } - //System.err.println("R: " + new String(Hex.encode(r))); outOffset += _outlen; _reseedCounter++; @@ -237,13 +228,17 @@ public int generate(byte[] output, byte[] additionalInput, boolean predictionRes int required = output.length - outOffset; - if (r.length > _outlen) + if (r.length >= _outlen) { System.arraycopy(r, r.length - _outlen, output, outOffset, required); } else { - System.arraycopy(r, 0, output, outOffset + (_outlen - r.length), required); + int outPos = _outlen - r.length; + if (outPos < required) + { + System.arraycopy(r, 0, output, outOffset + outPos, required - outPos); + } } _reseedCounter++; diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java b/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java index d83dbf4822..94ed99c6ab 100644 --- a/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java +++ b/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java @@ -38,23 +38,21 @@ public void init(boolean forSigning, CipherParameters param) { if (forSigning) { + SecureRandom providedRandom = null; if (param instanceof ParametersWithRandom) { ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.random = rParam.getRandom(); + providedRandom = rParam.getRandom(); param = rParam.getParameters(); } - else - { - this.random = CryptoServicesRegistrar.getSecureRandom(); - } this.key = (ECPrivateKeyParameters)param; + this.random = CryptoServicesRegistrar.getSecureRandom(providedRandom); } else { this.key = (ECPublicKeyParameters)param; + this.random = null; } CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties("DSTU4145", key, forSigning)); @@ -91,7 +89,7 @@ public BigInteger[] generateSignature(byte[] message) { do { - e = generateRandomInteger(n, random); + e = BigIntegers.createRandomInRange(BigInteger.ONE, n.subtract(BigInteger.ONE), random); Fe = basePointMultiplier.multiply(ec.getG(), e).normalize().getAffineXCoord(); } while (Fe.isZero()); @@ -148,14 +146,6 @@ protected ECMultiplier createBasePointMultiplier() return new FixedPointCombMultiplier(); } - /** - * Generates random integer such, than its bit length is less than that of n - */ - private static BigInteger generateRandomInteger(BigInteger n, SecureRandom random) - { - return BigIntegers.createRandomBigInteger(n.bitLength() - 1, random); - } - private static ECFieldElement hash2FieldElement(ECCurve curve, byte[] hash) { byte[] data = Arrays.reverse(hash); diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java new file mode 100644 index 0000000000..bec1461a8a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java @@ -0,0 +1,235 @@ +package org.bouncycastle.crypto.signers; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoException; +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.Signer; +import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.BigIntegers; + +/** + * Implementation of Elliptic Curve-based Certificateless Signatures for Identity-Based Encryption (ECCSI) + * as defined in RFC 6507. + * + * @see RFC 6507: Elliptic Curve-Based Certificateless + * Signatures for Identity-Based Encryption (ECCSI) + */ +public class ECCSISigner + implements Signer +{ + private final BigInteger q; + private final ECPoint G; + private final Digest digest; + private BigInteger j; + private BigInteger r; + private ECPoint Y; + private final ECPoint kpak; + private final byte[] id; + private CipherParameters param; + private ByteArrayOutputStream stream; + private boolean forSigning; + private final int N; + + /** + * Constructs an ECCSI signer/verifier with KMS Public Authentication Key and user identity. + * + * @param kpak KMS Public Authentication Key (KPAK) from RFC 6507 Section 2 + * @param id User identity byte array formatted + */ + public ECCSISigner(ECPoint kpak, X9ECParameters params, Digest digest, byte[] id) + { + this.kpak = kpak; + this.id = id; + this.q = params.getCurve().getOrder(); + this.G = params.getG(); + this.digest = digest; + this.digest.reset(); + this.N = (params.getCurve().getOrder().bitLength() + 7) >> 3; + } + + /** + * Initializes the signer for either signature generation or verification. + * + * @param forSigning true for signing, false for verification + * @param param Key parameters: + * - For signing: {@code ParametersWithRandom} containing {@code ECCSIPrivateKeyParameters} + * - For verification: {@code ECCSIPublicKeyParameters} + * @throws IllegalArgumentException if invalid parameters are provided + */ + @Override + public void init(boolean forSigning, CipherParameters param) + { + this.forSigning = forSigning; + this.param = param; + reset(); + } + + @Override + public void update(byte b) + { + if (forSigning) + { + digest.update(b); + } + else + { + stream.write(b); + } + } + + @Override + public void update(byte[] in, int off, int len) + { + if (forSigning) + { + digest.update(in, off, len); + } + else + { + stream.write(in, off, len); + } + } + + /** + * Generates an ECCSI signature according to RFC 6507 Section 5.2.1. + * + * @return Signature structure containing: + * - r (N bytes) + * - s (N bytes) + * - PVT (Public Validation Token) + * @throws CryptoException if cryptographic operations fail + * @throws DataLengthException if input data is invalid + * @throws IllegalArgumentException if invalid SSK or j parameter is detected + */ + @Override + public byte[] generateSignature() + throws CryptoException, DataLengthException + { + byte[] heBytes = new byte[digest.getDigestSize()]; + digest.doFinal(heBytes, 0); + + //Compute s' = ( (( HE + r * SSK )^-1) * j ) modulo q + ECCSIPrivateKeyParameters params = (ECCSIPrivateKeyParameters)(((ParametersWithRandom)param).getParameters()); + BigInteger ssk = params.getSSK(); + BigInteger denominator = new BigInteger(1, heBytes).add(r.multiply(ssk)).mod(q); + if (denominator.equals(BigInteger.ZERO)) + { + throw new IllegalArgumentException("Invalid j, retry"); + } + + BigInteger sPrime = denominator.modInverse(q).multiply(j).mod(q); + + return Arrays.concatenate(BigIntegers.asUnsignedByteArray(this.N, r), BigIntegers.asUnsignedByteArray(this.N, sPrime), + params.getPublicKeyParameters().getPVT().getEncoded(false)); + } + + /** + * Verifies an ECCSI signature according to RFC 6507 Section 5.2.2. + * + * @param signature Signature to verify (r || s || PVT) + * @return true if signature is valid, false otherwise + * @throws IllegalArgumentException if signature format is invalid + */ + @Override + public boolean verifySignature(byte[] signature) + { + byte[] bytes = Arrays.copyOf(signature, this.N); + BigInteger s = new BigInteger(1, Arrays.copyOfRange(signature, this.N, this.N << 1)); + r = new BigInteger(1, bytes).mod(q); + digest.update(bytes, 0, this.N); + bytes = stream.toByteArray(); + digest.update(bytes, 0, bytes.length); + bytes = new byte[digest.getDigestSize()]; + digest.doFinal(bytes, 0); + + BigInteger HE = new BigInteger(1, bytes).mod(q); + + // Compute J = s*(HE*G + r*Y) + ECPoint HE_G = G.multiply(HE).normalize(); + ECPoint rY = Y.multiply(r).normalize(); + ECPoint sum = HE_G.add(rY).normalize(); + ECPoint J = sum.multiply(s).normalize(); + + BigInteger rComputed = J.getAffineXCoord().toBigInteger(); + + return rComputed.mod(q).equals(r.mod(q)); + } + + /** + * Resets the signer/verifier state and performs initial computations: + * - For signing: Validates KPAK consistency (RFC 6507 Section 5.1.2) + * - For verification: Computes Y = HS·PVT + KPAK + * + * Also computes HS = hash(G || KPAK || ID || PVT) as per RFC 6507 Section 5.1.1 + */ + @Override + public void reset() + { + digest.reset(); + CipherParameters param = this.param; + SecureRandom random = null; + if (param instanceof ParametersWithRandom) + { + random = ((ParametersWithRandom)param).getRandom(); + param = ((ParametersWithRandom)param).getParameters(); + } + ECPoint kpak_computed = null; + ECPoint pvt; + if (forSigning) + { + ECCSIPrivateKeyParameters parameters = (ECCSIPrivateKeyParameters)param; + pvt = parameters.getPublicKeyParameters().getPVT(); + j = BigIntegers.createRandomBigInteger(q.bitLength(), random); + ECPoint J = G.multiply(j).normalize(); + r = J.getAffineXCoord().toBigInteger().mod(q); + + kpak_computed = G.multiply(parameters.getSSK()); + } + else + { + ECCSIPublicKeyParameters parameters = (ECCSIPublicKeyParameters)param; + pvt = parameters.getPVT(); + stream = new ByteArrayOutputStream(); + } + + // compute HS + byte[] tmp = G.getEncoded(false); + digest.update(tmp, 0, tmp.length); + tmp = kpak.getEncoded(false); + digest.update(tmp, 0, tmp.length); + digest.update(id, 0, id.length); + tmp = pvt.getEncoded(false); + digest.update(tmp, 0, tmp.length); + tmp = new byte[digest.getDigestSize()]; + digest.doFinal(tmp, 0); + BigInteger HS = new BigInteger(1, tmp).mod(q); + + //HE = hash( HS || r || M ); + digest.update(tmp, 0, tmp.length); + if (forSigning) + { + kpak_computed = kpak_computed.subtract(pvt.multiply(HS)).normalize(); + if (!kpak_computed.equals(kpak)) + { + throw new IllegalArgumentException("Invalid KPAK"); + } + byte[] rBytes = BigIntegers.asUnsignedByteArray(this.N, r); + digest.update(rBytes, 0, rBytes.length); + } + else + { + // Compute Y = HS*PVT + KPAK + Y = pvt.multiply(HS).add(kpak).normalize(); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ECGOST3410Signer.java b/core/src/main/java/org/bouncycastle/crypto/signers/ECGOST3410Signer.java index e064308a1a..2e3bea76eb 100644 --- a/core/src/main/java/org/bouncycastle/crypto/signers/ECGOST3410Signer.java +++ b/core/src/main/java/org/bouncycastle/crypto/signers/ECGOST3410Signer.java @@ -29,28 +29,25 @@ public class ECGOST3410Signer SecureRandom random; - public void init( - boolean forSigning, - CipherParameters param) + public void init(boolean forSigning, CipherParameters param) { if (forSigning) { + SecureRandom providedRandom = null; if (param instanceof ParametersWithRandom) { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.random = rParam.getRandom(); - this.key = (ECPrivateKeyParameters)rParam.getParameters(); - } - else - { - this.random = CryptoServicesRegistrar.getSecureRandom(); - this.key = (ECPrivateKeyParameters)param; + ParametersWithRandom withRandom = (ParametersWithRandom)param; + providedRandom = withRandom.getRandom(); + param = withRandom.getParameters(); } + + this.key = (ECPrivateKeyParameters)param; + this.random = CryptoServicesRegistrar.getSecureRandom(providedRandom); } else { this.key = (ECPublicKeyParameters)param; + this.random = null; } CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties("ECGOST3410", key, forSigning)); diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ECNRSigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/ECNRSigner.java index 8523abcdf2..f7b601d13e 100644 --- a/core/src/main/java/org/bouncycastle/crypto/signers/ECNRSigner.java +++ b/core/src/main/java/org/bouncycastle/crypto/signers/ECNRSigner.java @@ -37,30 +37,27 @@ public class ECNRSigner * for verification or if we want to use the signer for message recovery. * @param param key parameters for signature generation. */ - public void init( - boolean forSigning, - CipherParameters param) + public void init(boolean forSigning, CipherParameters param) { this.forSigning = forSigning; - + if (forSigning) { + SecureRandom providedRandom = null; if (param instanceof ParametersWithRandom) { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.random = rParam.getRandom(); - this.key = (ECPrivateKeyParameters)rParam.getParameters(); - } - else - { - this.random = CryptoServicesRegistrar.getSecureRandom(); - this.key = (ECPrivateKeyParameters)param; + ParametersWithRandom withRandom = (ParametersWithRandom)param; + providedRandom = withRandom.getRandom(); + param = withRandom.getParameters(); } + + this.key = (ECPrivateKeyParameters)param; + this.random = CryptoServicesRegistrar.getSecureRandom(providedRandom); } else { this.key = (ECPublicKeyParameters)param; + this.random = null; } CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties("ECNR", key, forSigning)); diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/GOST3410Signer.java b/core/src/main/java/org/bouncycastle/crypto/signers/GOST3410Signer.java index 5b187ea7df..e5106c17c0 100644 --- a/core/src/main/java/org/bouncycastle/crypto/signers/GOST3410Signer.java +++ b/core/src/main/java/org/bouncycastle/crypto/signers/GOST3410Signer.java @@ -24,28 +24,25 @@ public class GOST3410Signer SecureRandom random; - public void init( - boolean forSigning, - CipherParameters param) + public void init(boolean forSigning, CipherParameters param) { if (forSigning) { + SecureRandom providedRandom = null; if (param instanceof ParametersWithRandom) { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.random = rParam.getRandom(); - this.key = (GOST3410PrivateKeyParameters)rParam.getParameters(); - } - else - { - this.random = CryptoServicesRegistrar.getSecureRandom(); - this.key = (GOST3410PrivateKeyParameters)param; + ParametersWithRandom withRandom = (ParametersWithRandom)param; + providedRandom = withRandom.getRandom(); + param = withRandom.getParameters(); } + + this.key = (GOST3410PrivateKeyParameters)param; + this.random = CryptoServicesRegistrar.getSecureRandom(providedRandom); } else { this.key = (GOST3410PublicKeyParameters)param; + this.random = null; } CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties("GOST3410", key, forSigning)); diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ISO9796d2PSSSigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/ISO9796d2PSSSigner.java index 2ee1808861..3b9cb97abe 100644 --- a/core/src/main/java/org/bouncycastle/crypto/signers/ISO9796d2PSSSigner.java +++ b/core/src/main/java/org/bouncycastle/crypto/signers/ISO9796d2PSSSigner.java @@ -125,9 +125,7 @@ public ISO9796d2PSSSigner( * @throws IllegalArgumentException if wrong parameter type or a fixed * salt is passed in which is the wrong length. */ - public void init( - boolean forSigning, - CipherParameters param) + public void init(boolean forSigning, CipherParameters param) { RSAKeyParameters kParam; int lengthOfSalt = saltLength; @@ -137,16 +135,15 @@ public void init( ParametersWithRandom p = (ParametersWithRandom)param; kParam = (RSAKeyParameters)p.getParameters(); - if (forSigning) - { - random = p.getRandom(); - } + random = forSigning ? p.getRandom() : null; + standardSalt = null; } else if (param instanceof ParametersWithSalt) { ParametersWithSalt p = (ParametersWithSalt)param; kParam = (RSAKeyParameters)p.getParameters(); + random = null; standardSalt = p.getSalt(); lengthOfSalt = standardSalt.length; if (standardSalt.length != saltLength) @@ -157,10 +154,8 @@ else if (param instanceof ParametersWithSalt) else { kParam = (RSAKeyParameters)param; - if (forSigning) - { - random = CryptoServicesRegistrar.getSecureRandom(); - } + random = forSigning ? CryptoServicesRegistrar.getSecureRandom() : null; + standardSalt = null; } cipher.init(forSigning, kParam); diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/SM2Signer.java b/core/src/main/java/org/bouncycastle/crypto/signers/SM2Signer.java index eefddc7d79..e93a7d2acf 100644 --- a/core/src/main/java/org/bouncycastle/crypto/signers/SM2Signer.java +++ b/core/src/main/java/org/bouncycastle/crypto/signers/SM2Signer.java @@ -1,6 +1,9 @@ package org.bouncycastle.crypto.signers; import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.logging.Level; +import java.util.logging.Logger; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.CryptoException; @@ -29,6 +32,8 @@ public class SM2Signer implements Signer, ECConstants { + private static final Logger LOG = Logger.getLogger(SM2Signer.class.getName()); + private static final class State { static final int UNINITIALIZED = 0; @@ -78,9 +83,10 @@ public void init(boolean forSigning, CipherParameters param) baseParam = ((ParametersWithID)param).getParameters(); userID = ((ParametersWithID)param).getID(); + // The length in bits must be expressible in two bytes if (userID.length >= 8192) { - throw new IllegalArgumentException("SM2 user ID must be less than 2^13 bits long"); + throw new IllegalArgumentException("SM2 user ID must be less than 2^16 bits long"); } } else @@ -92,35 +98,37 @@ public void init(boolean forSigning, CipherParameters param) if (forSigning) { + SecureRandom random = null; if (baseParam instanceof ParametersWithRandom) { - ParametersWithRandom rParam = (ParametersWithRandom)baseParam; - - ecKey = (ECKeyParameters)rParam.getParameters(); - ecParams = ecKey.getParameters(); - kCalculator.init(ecParams.getN(), rParam.getRandom()); - } - else - { - ecKey = (ECKeyParameters)baseParam; - ecParams = ecKey.getParameters(); - kCalculator.init(ecParams.getN(), CryptoServicesRegistrar.getSecureRandom()); + ParametersWithRandom withRandom = (ParametersWithRandom)baseParam; + baseParam = withRandom.getParameters(); + random = withRandom.getRandom(); } - BigInteger d = ((ECPrivateKeyParameters)ecKey).getD(); - BigInteger nSub1 = ecParams.getN().subtract(BigIntegers.ONE); + ECPrivateKeyParameters ecPrivateKey = (ECPrivateKeyParameters)baseParam; + + ecKey = ecPrivateKey; + ecParams = ecPrivateKey.getParameters(); - if (d.compareTo(ONE) < 0 || d.compareTo(nSub1) >= 0) + BigInteger d = ecPrivateKey.getD(); + BigInteger n = ecParams.getN(); + + if (d.compareTo(ONE) < 0 || d.compareTo(n.subtract(ONE)) >= 0) { throw new IllegalArgumentException("SM2 private key out of range"); } + + kCalculator.init(n, CryptoServicesRegistrar.getSecureRandom(random)); pubPoint = createBasePointMultiplier().multiply(ecParams.getG(), d).normalize(); } else { - ecKey = (ECKeyParameters)baseParam; - ecParams = ecKey.getParameters(); - pubPoint = ((ECPublicKeyParameters)ecKey).getQ(); + ECPublicKeyParameters ecPublicKey = (ECPublicKeyParameters)baseParam; + + ecKey = ecPublicKey; + ecParams = ecPublicKey.getParameters(); + pubPoint = ecPublicKey.getQ(); } CryptoServicesRegistrar.checkConstraints(Utils.getDefaultProperties("ECNR", ecKey, forSigning)); @@ -156,6 +164,10 @@ public boolean verifySignature(byte[] signature) } catch (Exception e) { + if (LOG.isLoggable(Level.FINE)) + { + LOG.log(Level.FINE, "SM2 signature verification failed due to exception", e); + } } finally { @@ -244,12 +256,20 @@ private boolean verifySignature(BigInteger r, BigInteger s) // B1 if (r.compareTo(ONE) < 0 || r.compareTo(n) >= 0) { + if (LOG.isLoggable(Level.FINE)) + { + LOG.fine("SM2 signature verification failed: r out of range"); + } return false; } // B2 if (s.compareTo(ONE) < 0 || s.compareTo(n) >= 0) { + if (LOG.isLoggable(Level.FINE)) + { + LOG.fine("SM2 signature verification failed: s out of range"); + } return false; } @@ -263,6 +283,10 @@ private boolean verifySignature(BigInteger r, BigInteger s) BigInteger t = r.add(s).mod(n); if (t.equals(ZERO)) { + if (LOG.isLoggable(Level.FINE)) + { + LOG.fine("SM2 signature verification failed: t equals zero"); + } return false; } @@ -271,6 +295,10 @@ private boolean verifySignature(BigInteger r, BigInteger s) ECPoint x1y1 = ECAlgorithms.sumOfTwoMultiplies(ecParams.getG(), s, q, t).normalize(); if (x1y1.isInfinity()) { + if (LOG.isLoggable(Level.FINE)) + { + LOG.fine("SM2 signature verification failed: calculated point at infinity"); + } return false; } @@ -320,6 +348,8 @@ private byte[] getZ(byte[] userID) private void addUserID(Digest digest, byte[] userID) { int len = userID.length * 8; +// assert len >>> 16 == 0; + digest.update((byte)(len >>> 8)); digest.update((byte)len); digest.update(userID, 0, userID.length); diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/StandardDSAEncoding.java b/core/src/main/java/org/bouncycastle/crypto/signers/StandardDSAEncoding.java index c92b97696f..d6a7a56943 100644 --- a/core/src/main/java/org/bouncycastle/crypto/signers/StandardDSAEncoding.java +++ b/core/src/main/java/org/bouncycastle/crypto/signers/StandardDSAEncoding.java @@ -16,17 +16,9 @@ public class StandardDSAEncoding { public static final StandardDSAEncoding INSTANCE = new StandardDSAEncoding(); - public byte[] encode(BigInteger n, BigInteger r, BigInteger s) throws IOException - { - ASN1EncodableVector v = new ASN1EncodableVector(); - encodeValue(n, v, r); - encodeValue(n, v, s); - return new DERSequence(v).getEncoded(ASN1Encoding.DER); - } - public BigInteger[] decode(BigInteger n, byte[] encoding) throws IOException { - ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding); + ASN1Sequence seq = ASN1Sequence.getInstance(encoding); if (seq.size() == 2) { BigInteger r = decodeValue(n, seq, 0); @@ -42,6 +34,14 @@ public BigInteger[] decode(BigInteger n, byte[] encoding) throws IOException throw new IllegalArgumentException("Malformed signature"); } + public byte[] encode(BigInteger n, BigInteger r, BigInteger s) throws IOException + { + return new DERSequence( + encodeValue(n, r), + encodeValue(n, s) + ).getEncoded(ASN1Encoding.DER); + } + protected BigInteger checkValue(BigInteger n, BigInteger x) { if (x.signum() < 0 || (null != n && x.compareTo(n) >= 0)) @@ -57,8 +57,8 @@ protected BigInteger decodeValue(BigInteger n, ASN1Sequence s, int pos) return checkValue(n, ((ASN1Integer)s.getObjectAt(pos)).getValue()); } - protected void encodeValue(BigInteger n, ASN1EncodableVector v, BigInteger x) + protected ASN1Integer encodeValue(BigInteger n, BigInteger x) { - v.add(new ASN1Integer(checkValue(n, x))); + return new ASN1Integer(checkValue(n, x)); } } diff --git a/core/src/main/java/org/bouncycastle/crypto/util/DerUtil.java b/core/src/main/java/org/bouncycastle/crypto/util/DerUtil.java index 324c5ae4ed..89392a87cc 100644 --- a/core/src/main/java/org/bouncycastle/crypto/util/DerUtil.java +++ b/core/src/main/java/org/bouncycastle/crypto/util/DerUtil.java @@ -6,6 +6,7 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Exceptions; class DerUtil { @@ -27,13 +28,7 @@ static byte[] toByteArray(ASN1Primitive primitive) } catch (final IOException e) { - throw new IllegalStateException("Cannot get encoding: " + e.getMessage()) - { - public Throwable getCause() - { - return e; - } - }; + throw Exceptions.illegalStateException("Cannot get encoding: " + e.getMessage(), e); } } } diff --git a/core/src/main/java/org/bouncycastle/crypto/util/DigestFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/DigestFactory.java index 685be1b1c0..be9248055f 100644 --- a/core/src/main/java/org/bouncycastle/crypto/util/DigestFactory.java +++ b/core/src/main/java/org/bouncycastle/crypto/util/DigestFactory.java @@ -40,7 +40,7 @@ public Digest createClone(Digest original) { public Digest createClone(Digest original) { - return new MD5Digest((MD5Digest)original); + return new SHA1Digest((SHA1Digest)original); } }); cloneMap.put(createSHA224().getAlgorithmName(), new Cloner() diff --git a/core/src/main/java/org/bouncycastle/crypto/util/OpenSSHPrivateKeyUtil.java b/core/src/main/java/org/bouncycastle/crypto/util/OpenSSHPrivateKeyUtil.java index b33a1a7036..866d1b1d53 100644 --- a/core/src/main/java/org/bouncycastle/crypto/util/OpenSSHPrivateKeyUtil.java +++ b/core/src/main/java/org/bouncycastle/crypto/util/OpenSSHPrivateKeyUtil.java @@ -78,7 +78,7 @@ else if (params instanceof DSAPrivateKeyParameters) DSAParameters dsaParams = dsaPrivKey.getParameters(); ASN1EncodableVector vec = new ASN1EncodableVector(); - vec.add(new ASN1Integer(0)); + vec.add(ASN1Integer.ZERO); vec.add(new ASN1Integer(dsaParams.getP())); vec.add(new ASN1Integer(dsaParams.getQ())); vec.add(new ASN1Integer(dsaParams.getG())); diff --git a/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java index 8e94bc92c4..c2bc49fbf9 100644 --- a/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java +++ b/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java @@ -152,8 +152,16 @@ else if (algOID.equals(X9ObjectIdentifiers.id_dsa)) return new DSAPrivateKeyParameters(derX.getValue(), parameters); } + /* + * TODO id-ecDH (SECObjectIdentifiers.ecdh) and/or id-ecMQV (SECObjectIdentifiers.ecmqv) could be supported if + * we could properly restrict usage of the resulting key. + */ else if (algOID.equals(X9ObjectIdentifiers.id_ecPublicKey)) { + /* + * TODO Consistency checks in case parameters and/or public key are specified at both the + * PrivateKeyInfo and ECPrivateKey levels? + */ ECPrivateKey ecPrivateKey = ECPrivateKey.getInstance(keyInfo.parsePrivateKey()); X962Parameters parameters = X962Parameters.getInstance(algId.getParameters().toASN1Primitive()); diff --git a/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java index 0a5a1189a4..688de20138 100644 --- a/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java +++ b/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java @@ -81,6 +81,10 @@ public class PublicKeyFactory converters.put(X9ObjectIdentifiers.id_dsa, new DSAConverter()); converters.put(OIWObjectIdentifiers.dsaWithSHA1, new DSAConverter()); converters.put(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalConverter()); + /* + * TODO id-ecDH (SECObjectIdentifiers.ecdh) and/or id-ecMQV (SECObjectIdentifiers.ecmqv) could be supported if + * we could properly restrict usage of the resulting key. + */ converters.put(X9ObjectIdentifiers.id_ecPublicKey, new ECConverter()); converters.put(CryptoProObjectIdentifiers.gostR3410_2001, new GOST3410_2001Converter()); converters.put(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256, new GOST3410_2012Converter()); diff --git a/core/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java index 3ade492281..a7208d0b19 100644 --- a/core/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java +++ b/core/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java @@ -35,12 +35,17 @@ import org.bouncycastle.crypto.params.X448PublicKeyParameters; import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers; import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers; +import org.bouncycastle.pqc.crypto.lms.Composer; +import org.bouncycastle.pqc.crypto.lms.HSSPublicKeyParameters; +import org.bouncycastle.pqc.crypto.lms.LMSPublicKeyParameters; +import org.bouncycastle.util.Arrays; /** * Factory to create ASN.1 subject public key info objects from lightweight public keys. */ public class SubjectPublicKeyInfoFactory { + private static final byte tag_OctetString = (byte)0x04; private static Set cryptoProOids = new HashSet(5); static @@ -192,6 +197,20 @@ else if (publicKey instanceof Ed25519PublicKeyParameters) return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), key.getEncoded()); } + else if (publicKey instanceof HSSPublicKeyParameters) + { + HSSPublicKeyParameters params = (HSSPublicKeyParameters)publicKey; + byte[] encoding = Composer.compose().u32str(params.getL()).bytes(params.getLMSPublicKey()).build(); + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_alg_hss_lms_hashsig); + return new SubjectPublicKeyInfo(algorithmIdentifier, Arrays.concatenate(new byte[]{tag_OctetString, (byte)encoding.length}, encoding)); + } + else if (publicKey instanceof LMSPublicKeyParameters) + { + LMSPublicKeyParameters params = (LMSPublicKeyParameters)publicKey; + byte[] encoding = Composer.compose().u32str(1).bytes(params).build(); + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_alg_hss_lms_hashsig); + return new SubjectPublicKeyInfo(algorithmIdentifier, Arrays.concatenate(new byte[]{tag_OctetString, (byte)encoding.length}, encoding)); + } else { throw new IOException("key parameters not recognized"); diff --git a/core/src/main/java/org/bouncycastle/i18n/LocalizedMessage.java b/core/src/main/java/org/bouncycastle/i18n/LocalizedMessage.java index ac75c6c345..1e684cf5ff 100644 --- a/core/src/main/java/org/bouncycastle/i18n/LocalizedMessage.java +++ b/core/src/main/java/org/bouncycastle/i18n/LocalizedMessage.java @@ -204,7 +204,7 @@ protected String addExtraArgs(String msg, Locale locale) { if (extraArgs != null) { - StringBuffer sb = new StringBuffer(msg); + StringBuilder sb = new StringBuilder(msg); Object[] filteredArgs = extraArgs.getFilteredArgs(locale); for (int i = 0; i < filteredArgs.length; i++) { @@ -460,7 +460,7 @@ public void setFilter(Filter filter) public String toString() { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append("Resource: \"").append(resource); sb.append("\" Id: \"").append(id).append("\""); sb.append(" Arguments: ").append(arguments.getArguments().length).append(" normal"); diff --git a/core/src/main/java/org/bouncycastle/i18n/filter/HTMLFilter.java b/core/src/main/java/org/bouncycastle/i18n/filter/HTMLFilter.java index b9904bc708..5791223f70 100644 --- a/core/src/main/java/org/bouncycastle/i18n/filter/HTMLFilter.java +++ b/core/src/main/java/org/bouncycastle/i18n/filter/HTMLFilter.java @@ -9,7 +9,7 @@ public class HTMLFilter implements Filter public String doFilter(String input) { - StringBuffer buf = new StringBuffer(input); + StringBuilder buf = new StringBuilder(input); int i = 0; while (i < buf.length()) { diff --git a/core/src/main/java/org/bouncycastle/i18n/filter/SQLFilter.java b/core/src/main/java/org/bouncycastle/i18n/filter/SQLFilter.java index d55610b60f..b9cc0ed383 100644 --- a/core/src/main/java/org/bouncycastle/i18n/filter/SQLFilter.java +++ b/core/src/main/java/org/bouncycastle/i18n/filter/SQLFilter.java @@ -11,7 +11,7 @@ public class SQLFilter implements Filter public String doFilter(String input) { - StringBuffer buf = new StringBuffer(input); + StringBuilder buf = new StringBuilder(input); int i = 0; while (i < buf.length()) { diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/cms/CCMParameters.java b/core/src/main/java/org/bouncycastle/internal/asn1/cms/CCMParameters.java index 024b107b2d..7da93d3b2c 100644 --- a/core/src/main/java/org/bouncycastle/internal/asn1/cms/CCMParameters.java +++ b/core/src/main/java/org/bouncycastle/internal/asn1/cms/CCMParameters.java @@ -94,7 +94,7 @@ public ASN1Primitive toASN1Primitive() if (icvLen != 12) { - v.add(new ASN1Integer(icvLen)); + v.add(ASN1Integer.valueOf(icvLen)); } return new DERSequence(v); diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/cms/GCMParameters.java b/core/src/main/java/org/bouncycastle/internal/asn1/cms/GCMParameters.java index de8821162c..ed52e345a4 100644 --- a/core/src/main/java/org/bouncycastle/internal/asn1/cms/GCMParameters.java +++ b/core/src/main/java/org/bouncycastle/internal/asn1/cms/GCMParameters.java @@ -94,7 +94,7 @@ public ASN1Primitive toASN1Primitive() if (icvLen != 12) { - v.add(new ASN1Integer(icvLen)); + v.add(ASN1Integer.valueOf(icvLen)); } return new DERSequence(v); diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/iana/IANAObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/iana/IANAObjectIdentifiers.java index 97a97d0680..f51756d654 100644 --- a/core/src/main/java/org/bouncycastle/internal/asn1/iana/IANAObjectIdentifiers.java +++ b/core/src/main/java/org/bouncycastle/internal/asn1/iana/IANAObjectIdentifiers.java @@ -10,51 +10,101 @@ public interface IANAObjectIdentifiers { /** { iso(1) identifier-organization(3) dod(6) internet(1) } == IETF defined things */ - static final ASN1ObjectIdentifier internet = new ASN1ObjectIdentifier("1.3.6.1"); + ASN1ObjectIdentifier internet = new ASN1ObjectIdentifier("1.3.6.1"); /** 1.3.6.1.1: Internet directory: X.500 */ - static final ASN1ObjectIdentifier directory = internet.branch("1"); + ASN1ObjectIdentifier directory = internet.branch("1"); /** 1.3.6.1.2: Internet management */ - static final ASN1ObjectIdentifier mgmt = internet.branch("2"); + ASN1ObjectIdentifier mgmt = internet.branch("2"); /** 1.3.6.1.3: */ - static final ASN1ObjectIdentifier experimental = internet.branch("3"); + ASN1ObjectIdentifier experimental = internet.branch("3"); /** 1.3.6.1.4: */ - static final ASN1ObjectIdentifier _private = internet.branch("4"); + ASN1ObjectIdentifier _private = internet.branch("4"); /** 1.3.6.1.5: Security services */ - static final ASN1ObjectIdentifier security = internet.branch("5"); + ASN1ObjectIdentifier security = internet.branch("5"); /** 1.3.6.1.6: SNMPv2 -- never really used */ - static final ASN1ObjectIdentifier SNMPv2 = internet.branch("6"); + ASN1ObjectIdentifier SNMPv2 = internet.branch("6"); /** 1.3.6.1.7: mail -- never really used */ - static final ASN1ObjectIdentifier mail = internet.branch("7"); + ASN1ObjectIdentifier mail = internet.branch("7"); - // id-SHA1 OBJECT IDENTIFIER ::= + // id-SHA1 OBJECT IDENTIFIER ::= // {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)} // /** IANA security mechanisms; 1.3.6.1.5.5 */ - static final ASN1ObjectIdentifier security_mechanisms = security.branch("5"); + ASN1ObjectIdentifier security_mechanisms = security.branch("5"); /** IANA security nametypes; 1.3.6.1.5.6 */ - static final ASN1ObjectIdentifier security_nametypes = security.branch("6"); + ASN1ObjectIdentifier security_nametypes = security.branch("6"); - /** PKIX base OID: 1.3.6.1.5.6.6 */ - static final ASN1ObjectIdentifier pkix = security_mechanisms.branch("6"); + /** PKIX base OID: 1.3.6.1.5.5.7 */ + ASN1ObjectIdentifier pkix = security_mechanisms.branch("7"); /** IPSEC base OID: 1.3.6.1.5.5.8 */ - static final ASN1ObjectIdentifier ipsec = security_mechanisms.branch("8"); + ASN1ObjectIdentifier ipsec = security_mechanisms.branch("8"); /** IPSEC ISAKMP-Oakley OID: 1.3.6.1.5.5.8.1 */ - static final ASN1ObjectIdentifier isakmpOakley = ipsec.branch("1"); + ASN1ObjectIdentifier isakmpOakley = ipsec.branch("1"); /** IPSEC ISAKMP-Oakley hmacMD5 OID: 1.3.6.1.5.5.8.1.1 */ - static final ASN1ObjectIdentifier hmacMD5 = isakmpOakley.branch("1"); + ASN1ObjectIdentifier hmacMD5 = isakmpOakley.branch("1"); /** IPSEC ISAKMP-Oakley hmacSHA1 OID: 1.3.6.1.5.5.8.1.2 */ - static final ASN1ObjectIdentifier hmacSHA1 = isakmpOakley.branch("2"); - + ASN1ObjectIdentifier hmacSHA1 = isakmpOakley.branch("2"); + /** IPSEC ISAKMP-Oakley hmacTIGER OID: 1.3.6.1.5.5.8.1.3 */ - static final ASN1ObjectIdentifier hmacTIGER = isakmpOakley.branch("3"); - + ASN1ObjectIdentifier hmacTIGER = isakmpOakley.branch("3"); + /** IPSEC ISAKMP-Oakley hmacRIPEMD160 OID: 1.3.6.1.5.5.8.1.4 */ - static final ASN1ObjectIdentifier hmacRIPEMD160 = isakmpOakley.branch("4"); + ASN1ObjectIdentifier hmacRIPEMD160 = isakmpOakley.branch("4"); + + /** 1.3.6.1.5.5.7.6 */ + ASN1ObjectIdentifier id_alg = internet.branch("5.5.7.6"); + + ASN1ObjectIdentifier id_RSASSA_PSS_SHAKE128 = id_alg.branch("30"); + + ASN1ObjectIdentifier id_RSASSA_PSS_SHAKE256 = id_alg.branch("31"); + + ASN1ObjectIdentifier id_ecdsa_with_shake128 = id_alg.branch("32"); + + ASN1ObjectIdentifier id_ecdsa_with_shake256 = id_alg.branch("33"); + + ASN1ObjectIdentifier id_alg_unsigned = id_alg.branch("36"); + + /** 1.3.6.1.5.5.7.6.37 id-MLDSA44-RSA2048-PSS-SHA256 */ + ASN1ObjectIdentifier id_MLDSA44_RSA2048_PSS_SHA256 = id_alg.branch("37"); + /** 1.3.6.1.5.5.7.6.38 id-MLDSA44-RSA2048-PKCS15-SHA256 */ + ASN1ObjectIdentifier id_MLDSA44_RSA2048_PKCS15_SHA256 = id_alg.branch("38"); + /** 1.3.6.1.5.5.7.6.39 id-MLDSA44-Ed25519-SHA512 */ + ASN1ObjectIdentifier id_MLDSA44_Ed25519_SHA512 = id_alg.branch("39"); + /** 1.3.6.1.5.5.7.6.40 id-MLDSA44-ECDSA-P256-SHA256 */ + ASN1ObjectIdentifier id_MLDSA44_ECDSA_P256_SHA256 = id_alg.branch("40"); + /** 1.3.6.1.5.5.7.6.41 id-MLDSA65-RSA3072-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA3072_PSS_SHA512 = id_alg.branch("41"); + /** 1.3.6.1.5.5.7.6.42 id-MLDSA65-RSA3072-PKCS15-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA3072_PKCS15_SHA512 = id_alg.branch("42"); + /** 1.3.6.1.5.5.7.6.43 id-MLDSA65-RSA4096-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA4096_PSS_SHA512 = id_alg.branch("43"); + /** 1.3.6.1.5.5.7.6.44 id-MLDSA65-RSA4096-PKCS15-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA4096_PKCS15_SHA512 = id_alg.branch("44"); + /** 1.3.6.1.5.5.7.6.45 id-MLDSA65-ECDSA-P256-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_ECDSA_P256_SHA512 = id_alg.branch("45"); + /** 1.3.6.1.5.5.7.6.46 id-MLDSA65-ECDSA-P384-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_ECDSA_P384_SHA512 = id_alg.branch("46"); + /** 1.3.6.1.5.5.7.6.47 id-MLDSA65-ECDSA-brainpoolP256r1-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_ECDSA_brainpoolP256r1_SHA512 = id_alg.branch("47"); + /** 1.3.6.1.5.5.7.6.48 id-MLDSA65-Ed25519-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_Ed25519_SHA512 = id_alg.branch("48"); + /** 1.3.6.1.5.5.7.6.49 id-MLDSA87-ECDSA-P384-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_ECDSA_P384_SHA512 = id_alg.branch("49"); + /** 1.3.6.1.5.5.7.6.50 id-MLDSA87-ECDSA-brainpoolP384r1-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_ECDSA_brainpoolP384r1_SHA512 = id_alg.branch("50"); + /** 1.3.6.1.5.5.7.6.51 id-MLDSA87-Ed448-SHAKE256 */ + ASN1ObjectIdentifier id_MLDSA87_Ed448_SHAKE256 = id_alg.branch("51"); + /** 1.3.6.1.5.5.7.6.52 id-MLDSA87-RSA3072-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_RSA3072_PSS_SHA512 = id_alg.branch("52"); + /** 1.3.6.1.5.5.7.6.53 id-MLDSA87-RSA4096-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_RSA4096_PSS_SHA512 = id_alg.branch("53"); + /** 1.3.6.1.5.5.7.6.54 id-MLDSA87-ECDSA-P521-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_ECDSA_P521_SHA512 = id_alg.branch("54"); } diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/kisa/KISAObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/kisa/KISAObjectIdentifiers.java index 89ac25559c..978d19b04f 100644 --- a/core/src/main/java/org/bouncycastle/internal/asn1/kisa/KISAObjectIdentifiers.java +++ b/core/src/main/java/org/bouncycastle/internal/asn1/kisa/KISAObjectIdentifiers.java @@ -14,18 +14,23 @@ */ public interface KISAObjectIdentifiers { - /** RFC 4010, 4269: id-seedCBC; OID 1.2.410.200004.1.4 */ + /** + * RFC 4010, 4269: id-seedCBC; OID 1.2.410.200004.1.4 + */ static final ASN1ObjectIdentifier id_seedCBC = new ASN1ObjectIdentifier("1.2.410.200004.1.4"); - /** RFC 4269: id-seedMAC; OID 1.2.410.200004.1.7 */ + /** + * RFC 4269: id-seedMAC; OID 1.2.410.200004.1.7 + */ static final ASN1ObjectIdentifier id_seedMAC = new ASN1ObjectIdentifier("1.2.410.200004.1.7"); - /** RFC 4269: pbeWithSHA1AndSEED-CBC; OID 1.2.410.200004.1.15 */ + /** + * RFC 4269: pbeWithSHA1AndSEED-CBC; OID 1.2.410.200004.1.15 + */ static final ASN1ObjectIdentifier pbeWithSHA1AndSEED_CBC = new ASN1ObjectIdentifier("1.2.410.200004.1.15"); - /** RFC 4010: id-npki-app-cmsSeed-wrap; OID 1.2.410.200004.7.1.1.1 */ + /** + * RFC 4010: id-npki-app-cmsSeed-wrap; OID 1.2.410.200004.7.1.1.1 + */ static final ASN1ObjectIdentifier id_npki_app_cmsSeed_wrap = new ASN1ObjectIdentifier("1.2.410.200004.7.1.1.1"); - - /** RFC 4010: SeedEncryptionAlgorithmInCMS; OID 1.2.840.113549.1.9.16.0.24 */ - static final ASN1ObjectIdentifier id_mod_cms_seed = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.0.24"); } diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/misc/CAST5CBCParameters.java b/core/src/main/java/org/bouncycastle/internal/asn1/misc/CAST5CBCParameters.java index 6f89a98b39..ecee140bf8 100644 --- a/core/src/main/java/org/bouncycastle/internal/asn1/misc/CAST5CBCParameters.java +++ b/core/src/main/java/org/bouncycastle/internal/asn1/misc/CAST5CBCParameters.java @@ -35,7 +35,7 @@ public CAST5CBCParameters( int keyLength) { this.iv = new DEROctetString(Arrays.clone(iv)); - this.keyLength = new ASN1Integer(keyLength); + this.keyLength = ASN1Integer.valueOf(keyLength); } private CAST5CBCParameters( diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/misc/MiscObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/misc/MiscObjectIdentifiers.java index f96201e8d4..b6d7cb5193 100644 --- a/core/src/main/java/org/bouncycastle/internal/asn1/misc/MiscObjectIdentifiers.java +++ b/core/src/main/java/org/bouncycastle/internal/asn1/misc/MiscObjectIdentifiers.java @@ -169,17 +169,12 @@ public interface MiscObjectIdentifiers // Composite signature related OIDs. Based https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html // The current OIDs are EXPERIMENTAL and are going to change. ASN1ObjectIdentifier id_composite_signatures = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1"); - ASN1ObjectIdentifier id_MLDSA44_RSA2048_PSS_SHA256 = id_composite_signatures.branch("21"); - ASN1ObjectIdentifier id_MLDSA44_RSA2048_PKCS15_SHA256 = id_composite_signatures.branch("22"); - ASN1ObjectIdentifier id_MLDSA44_Ed25519_SHA512 = id_composite_signatures.branch("23"); - ASN1ObjectIdentifier id_MLDSA44_ECDSA_P256_SHA256 = id_composite_signatures.branch("24"); ASN1ObjectIdentifier id_MLDSA65_RSA3072_PSS_SHA256 = id_composite_signatures.branch("26"); ASN1ObjectIdentifier id_MLDSA65_RSA3072_PKCS15_SHA256 = id_composite_signatures.branch("27"); ASN1ObjectIdentifier id_MLDSA65_RSA4096_PSS_SHA384 = id_composite_signatures.branch("34"); ASN1ObjectIdentifier id_MLDSA65_RSA4096_PKCS15_SHA384 = id_composite_signatures.branch("35"); ASN1ObjectIdentifier id_MLDSA65_ECDSA_P384_SHA384 = id_composite_signatures.branch("28"); ASN1ObjectIdentifier id_MLDSA65_ECDSA_brainpoolP256r1_SHA256 = id_composite_signatures.branch("29"); - ASN1ObjectIdentifier id_MLDSA65_Ed25519_SHA512 = id_composite_signatures.branch("30"); ASN1ObjectIdentifier id_MLDSA87_ECDSA_P384_SHA384 = id_composite_signatures.branch("31"); ASN1ObjectIdentifier id_MLDSA87_ECDSA_brainpoolP384r1_SHA384 = id_composite_signatures.branch("32"); ASN1ObjectIdentifier id_MLDSA87_Ed448_SHA512 = id_composite_signatures.branch("33"); @@ -198,5 +193,44 @@ public interface MiscObjectIdentifiers ASN1ObjectIdentifier id_HashMLDSA87_ECDSA_P384_SHA512 = id_composite_signatures.branch("51"); ASN1ObjectIdentifier id_HashMLDSA87_ECDSA_brainpoolP384r1_SHA512 = id_composite_signatures.branch("52"); ASN1ObjectIdentifier id_HashMLDSA87_Ed448_SHA512 = id_composite_signatures.branch("53"); + + ASN1ObjectIdentifier id_MLDSA_COMPSIG = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1"); + /** 2.16.840.1.114027.80.9.1.0 id-MLDSA44-RSA2048-PSS-SHA256 */ + ASN1ObjectIdentifier id_MLDSA44_RSA2048_PSS_SHA256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.0"); + /** 2.16.840.1.114027.80.9.1.1 id-MLDSA44-RSA2048-PKCS15-SHA256 */ + ASN1ObjectIdentifier id_MLDSA44_RSA2048_PKCS15_SHA256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.1"); + /** 2.16.840.1.114027.80.9.1.2 id-MLDSA44-Ed25519-SHA512 */ + ASN1ObjectIdentifier id_MLDSA44_Ed25519_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.2"); + /** 2.16.840.1.114027.80.9.1.3 id-MLDSA44-ECDSA-P256-SHA256 */ + ASN1ObjectIdentifier id_MLDSA44_ECDSA_P256_SHA256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.3"); + /** 2.16.840.1.114027.80.9.1.4 id-MLDSA65-RSA3072-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA3072_PSS_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.4"); + /** 2.16.840.1.114027.80.9.1.5 id-MLDSA65-RSA3072-PKCS15-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA3072_PKCS15_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.5"); + /** 2.16.840.1.114027.80.9.1.6 id-MLDSA65-RSA4096-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA4096_PSS_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.6"); + /** 2.16.840.1.114027.80.9.1.7 id-MLDSA65-RSA4096-PKCS15-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA4096_PKCS15_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.7"); + /** 2.16.840.1.114027.80.9.1.8 id-MLDSA65-ECDSA-P256-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_ECDSA_P256_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.8"); + /** 2.16.840.1.114027.80.9.1.9 id-MLDSA65-ECDSA-P384-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_ECDSA_P384_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.9"); + /** 2.16.840.1.114027.80.9.1.10 id-MLDSA65-ECDSA-brainpoolP256r1-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_ECDSA_brainpoolP256r1_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.10"); + /** 2.16.840.1.114027.80.9.1.11 id-MLDSA65-Ed25519-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_Ed25519_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.11"); + /** 2.16.840.1.114027.80.9.1.12 id-MLDSA87-ECDSA-P384-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_ECDSA_P384_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.12"); + /** 2.16.840.1.114027.80.9.1.13 id-MLDSA87-ECDSA-brainpoolP384r1-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_ECDSA_brainpoolP384r1_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.13"); + /** 2.16.840.1.114027.80.9.1.14 id-MLDSA87-Ed448-SHAKE256 */ + ASN1ObjectIdentifier id_MLDSA87_Ed448_SHAKE256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.14"); + /** 2.16.840.1.114027.80.9.1.15 id-MLDSA87-RSA3072-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_RSA3072_PSS_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.15"); + /** 2.16.840.1.114027.80.9.1.16 id-MLDSA87-RSA4096-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_RSA4096_PSS_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.16"); + /** 2.16.840.1.114027.80.9.1.17 id-MLDSA87-ECDSA-P521-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_ECDSA_P521_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.17"); + // COMPOSITE SIGNATURES END } diff --git a/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java b/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java index 4bef7efac6..8f944b5d6e 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java +++ b/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java @@ -596,9 +596,14 @@ protected AbstractFp(BigInteger q) super(FiniteFields.getPrimeField(q)); } + public BigInteger getQ() + { + return getField().getCharacteristic(); + } + public boolean isValidFieldElement(BigInteger x) { - return x != null && x.signum() >= 0 && x.compareTo(this.getField().getCharacteristic()) < 0; + return x != null && x.signum() >= 0 && x.compareTo(getQ()) < 0; } public ECFieldElement randomFieldElement(SecureRandom r) @@ -607,7 +612,7 @@ public ECFieldElement randomFieldElement(SecureRandom r) * NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we * use the product of two independent elements to mitigate side-channels. */ - BigInteger p = getField().getCharacteristic(); + BigInteger p = getQ(); ECFieldElement fe1 = fromBigInteger(implRandomFieldElement(r, p)); ECFieldElement fe2 = fromBigInteger(implRandomFieldElement(r, p)); return fe1.multiply(fe2); @@ -619,7 +624,7 @@ public ECFieldElement randomFieldElementMult(SecureRandom r) * NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we * use the product of two independent elements to mitigate side-channels. */ - BigInteger p = getField().getCharacteristic(); + BigInteger p = getQ(); ECFieldElement fe1 = fromBigInteger(implRandomFieldElementMult(r, p)); ECFieldElement fe2 = fromBigInteger(implRandomFieldElementMult(r, p)); return fe1.multiply(fe2); @@ -686,6 +691,8 @@ public static class Fp extends AbstractFp /** * @deprecated use constructor taking order/cofactor */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public Fp(BigInteger q, BigInteger a, BigInteger b) { this(q, a, b, null, null); @@ -702,12 +709,11 @@ public Fp(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger if (isInternal) { - this.q = q; knownQs.add(q); } else if (knownQs.contains(q) || validatedQs.contains(q)) { - this.q = q; + // No need to validate } else { @@ -727,10 +733,9 @@ else if (knownQs.contains(q) || validatedQs.contains(q)) } validatedQs.add(q); - - this.q = q; } + this.q = q; this.r = ECFieldElement.Fp.calculateResidue(q); this.infinity = new ECPoint.Fp(this, null, null); @@ -1150,6 +1155,8 @@ public static class F2m extends AbstractF2m * F2m. * @deprecated use constructor taking order/cofactor */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public F2m( int m, int k, @@ -1208,6 +1215,8 @@ public F2m( * F2m. * @deprecated use constructor taking order/cofactor */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public F2m( int m, int k1, diff --git a/core/src/main/java/org/bouncycastle/math/ec/ECPoint.java b/core/src/main/java/org/bouncycastle/math/ec/ECPoint.java index 44349f5a4e..24ca684cf1 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/ECPoint.java +++ b/core/src/main/java/org/bouncycastle/math/ec/ECPoint.java @@ -460,7 +460,7 @@ public String toString() return "INF"; } - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append('('); sb.append(getRawXCoord()); sb.append(','); diff --git a/core/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java b/core/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java index 229fae47f3..75c91505ca 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java +++ b/core/src/main/java/org/bouncycastle/math/ec/SimpleBigDecimal.java @@ -216,7 +216,7 @@ public String toString() } String rightOfPoint = new String(fractCharArr); - StringBuffer sb = new StringBuffer(leftOfPoint); + StringBuilder sb = new StringBuilder(leftOfPoint); sb.append("."); sb.append(rightOfPoint); diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecT571K1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecT571K1Point.java index cc45c3c012..ce0e6aa753 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecT571K1Point.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecT571K1Point.java @@ -7,6 +7,7 @@ import org.bouncycastle.math.ec.ECPoint.AbstractF2m; import org.bouncycastle.math.raw.Nat576; +@SuppressWarnings("AssignmentExpression") public class SecT571K1Point extends AbstractF2m { SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) @@ -58,7 +59,7 @@ protected boolean getCompressionYTilde() // Y is actually Lambda (X + Y/X) here return Y.testBitZero() != X.testBitZero(); } - + public ECPoint add(ECPoint b) { if (this.isInfinity()) diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecT571R1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecT571R1Point.java index 7a446c4be3..51e81aad01 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecT571R1Point.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecT571R1Point.java @@ -8,6 +8,7 @@ import org.bouncycastle.math.raw.Nat; import org.bouncycastle.math.raw.Nat576; +@SuppressWarnings("AssignmentExpression") public class SecT571R1Point extends AbstractF2m { SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc7748/X25519.java b/core/src/main/java/org/bouncycastle/math/ec/rfc7748/X25519.java index 02fdefed0f..3a752d3324 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/rfc7748/X25519.java +++ b/core/src/main/java/org/bouncycastle/math/ec/rfc7748/X25519.java @@ -30,6 +30,18 @@ public static boolean calculateAgreement(byte[] k, int kOff, byte[] u, int uOff, return !Arrays.areAllZeroes(r, rOff, POINT_SIZE); } + public static void clampPrivateKey(byte[] k) + { + if (k.length != SCALAR_SIZE) + { + throw new IllegalArgumentException("k"); + } + + k[0] &= 0xF8; + k[SCALAR_SIZE - 1] &= 0x7F; + k[SCALAR_SIZE - 1] |= 0x40; + } + private static int decode32(byte[] bs, int off) { int n = bs[off] & 0xFF; @@ -60,9 +72,7 @@ public static void generatePrivateKey(SecureRandom random, byte[] k) random.nextBytes(k); - k[0] &= 0xF8; - k[SCALAR_SIZE - 1] &= 0x7F; - k[SCALAR_SIZE - 1] |= 0x40; + clampPrivateKey(k); } public static void generatePublicKey(byte[] k, int kOff, byte[] r, int rOff) diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc7748/X448.java b/core/src/main/java/org/bouncycastle/math/ec/rfc7748/X448.java index 3954ba110c..ecfbc8c4f1 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/rfc7748/X448.java +++ b/core/src/main/java/org/bouncycastle/math/ec/rfc7748/X448.java @@ -31,6 +31,17 @@ public static boolean calculateAgreement(byte[] k, int kOff, byte[] u, int uOff, return !Arrays.areAllZeroes(r, rOff, POINT_SIZE); } + public static void clampPrivateKey(byte[] k) + { + if (k.length != SCALAR_SIZE) + { + throw new IllegalArgumentException("k"); + } + + k[0] &= 0xFC; + k[SCALAR_SIZE - 1] |= 0x80; + } + private static int decode32(byte[] bs, int off) { int n = bs[ off] & 0xFF; @@ -60,8 +71,7 @@ public static void generatePrivateKey(SecureRandom random, byte[] k) random.nextBytes(k); - k[0] &= 0xFC; - k[SCALAR_SIZE - 1] |= 0x80; + clampPrivateKey(k); } public static void generatePublicKey(byte[] k, int kOff, byte[] r, int rOff) diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed25519.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed25519.java index 7aedfb90ef..ff08b79b45 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed25519.java +++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed25519.java @@ -8,6 +8,7 @@ import org.bouncycastle.math.ec.rfc7748.X25519Field; import org.bouncycastle.math.raw.Interleave; import org.bouncycastle.math.raw.Nat256; +import org.bouncycastle.util.Integers; /** * A low-level implementation of the Ed25519, Ed25519ctx, and Ed25519ph instantiations of the Edwards-Curve @@ -231,11 +232,11 @@ private static boolean checkPointFullVar(byte[] p) int y0 = Codec.decode32(p, 0); // Reject 0 and 1 - if (t0 == 0 && (y0 + Integer.MIN_VALUE) <= (1 + Integer.MIN_VALUE)) + if (t0 == 0 && Integers.compareUnsigned(y0, 1) <= 0) return false; // Reject P - 1 and non-canonical encodings (i.e. >= P) - if (t1 == 0 && (y0 + Integer.MIN_VALUE) >= (P[0] - 1 + Integer.MIN_VALUE)) + if (t1 == 0 && Integers.compareUnsigned(y0, P[0] - 1) >= 0) return false; t2 |= y0 ^ ORDER8_y1[0]; diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed448.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed448.java index 2d2053e649..68990aa200 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed448.java +++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed448.java @@ -7,6 +7,7 @@ import org.bouncycastle.math.ec.rfc7748.X448; import org.bouncycastle.math.ec.rfc7748.X448Field; import org.bouncycastle.math.raw.Nat; +import org.bouncycastle.util.Integers; /** * A low-level implementation of the Ed448 and Ed448ph instantiations of the Edwards-Curve Digital Signature @@ -191,7 +192,7 @@ private static boolean checkPointFullVar(byte[] p) int yi = Codec.decode32(p, i * 4); // Reject non-canonical encodings (i.e. >= P) - if (t1 == 0 && (yi + Integer.MIN_VALUE) > (P[i] + Integer.MIN_VALUE)) + if (t1 == 0 && Integers.compareUnsigned(yi, P[i]) > 0) return false; t0 |= yi; @@ -201,11 +202,11 @@ private static boolean checkPointFullVar(byte[] p) int y0 = Codec.decode32(p, 0); // Reject 0 and 1 - if (t0 == 0 && (y0 + Integer.MIN_VALUE) <= (1 + Integer.MIN_VALUE)) + if (t0 == 0 && Integers.compareUnsigned(y0, 1) <= 0) return false; // Reject P - 1 and non-canonical encodings (i.e. >= P) - if (t1 == 0 && (y0 + Integer.MIN_VALUE) >= (P[0] - 1 + Integer.MIN_VALUE)) + if (t1 == 0 && Integers.compareUnsigned(y0, P[0] - 1) >= 0) return false; return true; diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java index 175513fba4..478f61b509 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java +++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java @@ -339,7 +339,7 @@ static boolean reduceBasisVar(int[] k, int[] z0, int[] z1) ScalarUtil.subShifted_UV(3, s, u0, u1, v0, v1); } - if (ScalarUtil.lessThan(last, Nu, Nv)) + if (ScalarUtil.lessThanUnsigned(last, Nu, Nv)) { int[] t0 = u0; u0 = v0; v0 = t0; int[] t1 = u1; u1 = v1; v1 = t1; diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java index f6ba495f97..c2cf19137f 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java +++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java @@ -604,7 +604,7 @@ static boolean reduceBasisVar(int[] k, int[] z0, int[] z1) ScalarUtil.subShifted_UV(7, s, u0, u1, v0, v1); } - if (ScalarUtil.lessThan(last, Nu, Nv)) + if (ScalarUtil.lessThanUnsigned(last, Nu, Nv)) { int[] t0 = u0; u0 = v0; v0 = t0; int[] t1 = u1; u1 = v1; v1 = t1; diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java index 483bf477d9..6630260329 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java +++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java @@ -179,7 +179,7 @@ static int getBitLengthPositive(int last, int[] x) return i * 32 + 32 - Integers.numberOfLeadingZeros(x[i]); } - static boolean lessThan(int last, int[] x, int[] y) + static boolean lessThanUnsigned(int last, int[] x, int[] y) { int i = last; do diff --git a/core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java b/core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java index f77a1a37b1..4b27fc8018 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java +++ b/core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java @@ -201,7 +201,7 @@ private static void printGLVTypeBParameters(X9ECParameters x9, BigInteger lambda private static void printProperty(String name, Object value) { - StringBuffer sb = new StringBuffer(" "); + StringBuilder sb = new StringBuilder(" "); sb.append(name); while (sb.length() < 20) { diff --git a/core/src/main/java/org/bouncycastle/math/raw/Nat.java b/core/src/main/java/org/bouncycastle/math/raw/Nat.java index 3d98cb4ec6..c38c51fa08 100644 --- a/core/src/main/java/org/bouncycastle/math/raw/Nat.java +++ b/core/src/main/java/org/bouncycastle/math/raw/Nat.java @@ -272,8 +272,8 @@ public static int compare(int len, int[] x, int[] y) { for (int i = len - 1; i >= 0; --i) { - int x_i = x[i] ^ Integer.MIN_VALUE; - int y_i = y[i] ^ Integer.MIN_VALUE; + int x_i = x[i] + Integer.MIN_VALUE; + int y_i = y[i] + Integer.MIN_VALUE; if (x_i < y_i) return -1; if (x_i > y_i) @@ -286,8 +286,8 @@ public static int compare(int len, int[] x, int xOff, int[] y, int yOff) { for (int i = len - 1; i >= 0; --i) { - int x_i = x[xOff + i] ^ Integer.MIN_VALUE; - int y_i = y[yOff + i] ^ Integer.MIN_VALUE; + int x_i = x[xOff + i] + Integer.MIN_VALUE; + int y_i = y[yOff + i] + Integer.MIN_VALUE; if (x_i < y_i) return -1; if (x_i > y_i) @@ -596,8 +596,8 @@ public static boolean gte(int len, int[] x, int[] y) { for (int i = len - 1; i >= 0; --i) { - int x_i = x[i] ^ Integer.MIN_VALUE; - int y_i = y[i] ^ Integer.MIN_VALUE; + int x_i = x[i] + Integer.MIN_VALUE; + int y_i = y[i] + Integer.MIN_VALUE; if (x_i < y_i) return false; if (x_i > y_i) @@ -610,8 +610,8 @@ public static boolean gte(int len, int[] x, int xOff, int[] y, int yOff) { for (int i = len - 1; i >= 0; --i) { - int x_i = x[xOff + i] ^ Integer.MIN_VALUE; - int y_i = y[yOff + i] ^ Integer.MIN_VALUE; + int x_i = x[xOff + i] + Integer.MIN_VALUE; + int y_i = y[yOff + i] + Integer.MIN_VALUE; if (x_i < y_i) return false; if (x_i > y_i) diff --git a/core/src/main/java/org/bouncycastle/math/raw/Nat128.java b/core/src/main/java/org/bouncycastle/math/raw/Nat128.java index 0ea22eb8e0..3979a1ca99 100644 --- a/core/src/main/java/org/bouncycastle/math/raw/Nat128.java +++ b/core/src/main/java/org/bouncycastle/math/raw/Nat128.java @@ -243,8 +243,8 @@ public static boolean gte(int[] x, int[] y) { for (int i = 3; i >= 0; --i) { - int x_i = x[i] ^ Integer.MIN_VALUE; - int y_i = y[i] ^ Integer.MIN_VALUE; + int x_i = x[i] + Integer.MIN_VALUE; + int y_i = y[i] + Integer.MIN_VALUE; if (x_i < y_i) return false; if (x_i > y_i) @@ -257,8 +257,8 @@ public static boolean gte(int[] x, int xOff, int[] y, int yOff) { for (int i = 3; i >= 0; --i) { - int x_i = x[xOff + i] ^ Integer.MIN_VALUE; - int y_i = y[yOff + i] ^ Integer.MIN_VALUE; + int x_i = x[xOff + i] + Integer.MIN_VALUE; + int y_i = y[yOff + i] + Integer.MIN_VALUE; if (x_i < y_i) return false; if (x_i > y_i) diff --git a/core/src/main/java/org/bouncycastle/math/raw/Nat160.java b/core/src/main/java/org/bouncycastle/math/raw/Nat160.java index b35c521556..3416fd8e08 100644 --- a/core/src/main/java/org/bouncycastle/math/raw/Nat160.java +++ b/core/src/main/java/org/bouncycastle/math/raw/Nat160.java @@ -209,8 +209,8 @@ public static boolean gte(int[] x, int[] y) { for (int i = 4; i >= 0; --i) { - int x_i = x[i] ^ Integer.MIN_VALUE; - int y_i = y[i] ^ Integer.MIN_VALUE; + int x_i = x[i] + Integer.MIN_VALUE; + int y_i = y[i] + Integer.MIN_VALUE; if (x_i < y_i) return false; if (x_i > y_i) @@ -223,8 +223,8 @@ public static boolean gte(int[] x, int xOff, int[] y, int yOff) { for (int i = 4; i >= 0; --i) { - int x_i = x[xOff + i] ^ Integer.MIN_VALUE; - int y_i = y[yOff + i] ^ Integer.MIN_VALUE; + int x_i = x[xOff + i] + Integer.MIN_VALUE; + int y_i = y[yOff + i] + Integer.MIN_VALUE; if (x_i < y_i) return false; if (x_i > y_i) diff --git a/core/src/main/java/org/bouncycastle/math/raw/Nat192.java b/core/src/main/java/org/bouncycastle/math/raw/Nat192.java index 9a84e6a32e..88b8f7815a 100644 --- a/core/src/main/java/org/bouncycastle/math/raw/Nat192.java +++ b/core/src/main/java/org/bouncycastle/math/raw/Nat192.java @@ -281,8 +281,8 @@ public static boolean gte(int[] x, int[] y) { for (int i = 5; i >= 0; --i) { - int x_i = x[i] ^ Integer.MIN_VALUE; - int y_i = y[i] ^ Integer.MIN_VALUE; + int x_i = x[i] + Integer.MIN_VALUE; + int y_i = y[i] + Integer.MIN_VALUE; if (x_i < y_i) return false; if (x_i > y_i) @@ -295,8 +295,8 @@ public static boolean gte(int[] x, int xOff, int[] y, int yOff) { for (int i = 5; i >= 0; --i) { - int x_i = x[xOff + i] ^ Integer.MIN_VALUE; - int y_i = y[yOff + i] ^ Integer.MIN_VALUE; + int x_i = x[xOff + i] + Integer.MIN_VALUE; + int y_i = y[yOff + i] + Integer.MIN_VALUE; if (x_i < y_i) return false; if (x_i > y_i) diff --git a/core/src/main/java/org/bouncycastle/math/raw/Nat224.java b/core/src/main/java/org/bouncycastle/math/raw/Nat224.java index 3610442165..e3a95430c7 100644 --- a/core/src/main/java/org/bouncycastle/math/raw/Nat224.java +++ b/core/src/main/java/org/bouncycastle/math/raw/Nat224.java @@ -326,8 +326,8 @@ public static boolean gte(int[] x, int[] y) { for (int i = 6; i >= 0; --i) { - int x_i = x[i] ^ Integer.MIN_VALUE; - int y_i = y[i] ^ Integer.MIN_VALUE; + int x_i = x[i] + Integer.MIN_VALUE; + int y_i = y[i] + Integer.MIN_VALUE; if (x_i < y_i) return false; if (x_i > y_i) @@ -340,8 +340,8 @@ public static boolean gte(int[] x, int xOff, int[] y, int yOff) { for (int i = 6; i >= 0; --i) { - int x_i = x[xOff + i] ^ Integer.MIN_VALUE; - int y_i = y[yOff + i] ^ Integer.MIN_VALUE; + int x_i = x[xOff + i] + Integer.MIN_VALUE; + int y_i = y[yOff + i] + Integer.MIN_VALUE; if (x_i < y_i) return false; if (x_i > y_i) diff --git a/core/src/main/java/org/bouncycastle/math/raw/Nat256.java b/core/src/main/java/org/bouncycastle/math/raw/Nat256.java index ed46d05c6d..708b0cf828 100644 --- a/core/src/main/java/org/bouncycastle/math/raw/Nat256.java +++ b/core/src/main/java/org/bouncycastle/math/raw/Nat256.java @@ -409,8 +409,8 @@ public static boolean gte(int[] x, int[] y) { for (int i = 7; i >= 0; --i) { - int x_i = x[i] ^ Integer.MIN_VALUE; - int y_i = y[i] ^ Integer.MIN_VALUE; + int x_i = x[i] + Integer.MIN_VALUE; + int y_i = y[i] + Integer.MIN_VALUE; if (x_i < y_i) return false; if (x_i > y_i) @@ -423,8 +423,8 @@ public static boolean gte(int[] x, int xOff, int[] y, int yOff) { for (int i = 7; i >= 0; --i) { - int x_i = x[xOff + i] ^ Integer.MIN_VALUE; - int y_i = y[yOff + i] ^ Integer.MIN_VALUE; + int x_i = x[xOff + i] + Integer.MIN_VALUE; + int y_i = y[yOff + i] + Integer.MIN_VALUE; if (x_i < y_i) return false; if (x_i > y_i) diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/CMCEPrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/CMCEPrivateKey.java index 4da48dcb90..258e390179 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/CMCEPrivateKey.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/CMCEPrivateKey.java @@ -120,7 +120,7 @@ public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new ASN1Integer(version)); + v.add(ASN1Integer.valueOf(version)); v.add(new DEROctetString(delta)); v.add(new DEROctetString(C)); v.add(new DEROctetString(g)); diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/CMCEPublicKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/CMCEPublicKey.java index e09a5d17da..1600da6e34 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/CMCEPublicKey.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/CMCEPublicKey.java @@ -34,6 +34,7 @@ public CMCEPublicKey(byte[] t) /** * @deprecated use getInstance() */ + @Deprecated public CMCEPublicKey(ASN1Sequence seq) { T = Arrays.clone(ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets()); diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/FalconPrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/FalconPrivateKey.java index 380f547b87..a7feb04a35 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/FalconPrivateKey.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/FalconPrivateKey.java @@ -96,7 +96,7 @@ public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new ASN1Integer(version)); + v.add(ASN1Integer.valueOf(version)); v.add(new DEROctetString(f)); v.add(new DEROctetString(g)); v.add(new DEROctetString(F)); diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/FalconPublicKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/FalconPublicKey.java index d5dc89dccb..3447bd2c23 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/FalconPublicKey.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/FalconPublicKey.java @@ -1,7 +1,13 @@ package org.bouncycastle.pqc.asn1; -import org.bouncycastle.asn1.*; +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.util.Arrays; /** @@ -32,6 +38,7 @@ public byte[] getH() /** * @deprecated use getInstance() */ + @Deprecated public FalconPublicKey(ASN1Sequence seq) { h = Arrays.clone(ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets()); diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/GMSSPrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/GMSSPrivateKey.java deleted file mode 100644 index 71a23c8a71..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/GMSSPrivateKey.java +++ /dev/null @@ -1,1318 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import java.util.Vector; - -import org.bouncycastle.asn1.ASN1Encodable; -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.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.pqc.legacy.crypto.gmss.GMSSLeaf; -import org.bouncycastle.pqc.legacy.crypto.gmss.GMSSParameters; -import org.bouncycastle.pqc.legacy.crypto.gmss.GMSSRootCalc; -import org.bouncycastle.pqc.legacy.crypto.gmss.GMSSRootSig; -import org.bouncycastle.pqc.legacy.crypto.gmss.Treehash; - -public class GMSSPrivateKey - extends ASN1Object -{ - public static GMSSPrivateKey getInstance(Object o) - { - if (o instanceof GMSSPrivateKey) - { - return (GMSSPrivateKey)o; - } - else if (o != null) - { - return new GMSSPrivateKey(ASN1Sequence.getInstance(o)); - } - - return null; - } - - private ASN1Primitive primitive; - - private GMSSPrivateKey(ASN1Sequence mtsPrivateKey) - { - // --- Decode . - ASN1Sequence indexPart = (ASN1Sequence)mtsPrivateKey.getObjectAt(0); - int[] index = new int[indexPart.size()]; - for (int i = 0; i < indexPart.size(); i++) - { - index[i] = checkBigIntegerInIntRange(indexPart.getObjectAt(i)); - } - - // --- Decode . - ASN1Sequence curSeedsPart = (ASN1Sequence)mtsPrivateKey.getObjectAt(1); - byte[][] curSeeds = new byte[curSeedsPart.size()][]; - for (int i = 0; i < curSeeds.length; i++) - { - curSeeds[i] = ((DEROctetString)curSeedsPart.getObjectAt(i)).getOctets(); - } - - // --- Decode . - ASN1Sequence nextNextSeedsPart = (ASN1Sequence)mtsPrivateKey.getObjectAt(2); - byte[][] nextNextSeeds = new byte[nextNextSeedsPart.size()][]; - for (int i = 0; i < nextNextSeeds.length; i++) - { - nextNextSeeds[i] = ((DEROctetString)nextNextSeedsPart.getObjectAt(i)).getOctets(); - } - - // --- Decode . - ASN1Sequence curAuthPart0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(3); - ASN1Sequence curAuthPart1; - - byte[][][] curAuth = new byte[curAuthPart0.size()][][]; - for (int i = 0; i < curAuth.length; i++) - { - curAuthPart1 = (ASN1Sequence)curAuthPart0.getObjectAt(i); - curAuth[i] = new byte[curAuthPart1.size()][]; - for (int j = 0; j < curAuth[i].length; j++) - { - curAuth[i][j] = ((DEROctetString)curAuthPart1.getObjectAt(j)).getOctets(); - } - } - - // --- Decode . - ASN1Sequence nextAuthPart0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(4); - ASN1Sequence nextAuthPart1; - - byte[][][] nextAuth = new byte[nextAuthPart0.size()][][]; - for (int i = 0; i < nextAuth.length; i++) - { - nextAuthPart1 = (ASN1Sequence)nextAuthPart0.getObjectAt(i); - nextAuth[i] = new byte[nextAuthPart1.size()][]; - for (int j = 0; j < nextAuth[i].length; j++) - { - nextAuth[i][j] = ((DEROctetString)nextAuthPart1.getObjectAt(j)).getOctets(); - } - } - - // --- Decode . - ASN1Sequence seqOfcurTreehash0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(5); - ASN1Sequence seqOfcurTreehash1; - ASN1Sequence seqOfcurTreehashStat; - ASN1Sequence seqOfcurTreehashBytes; - ASN1Sequence seqOfcurTreehashInts; - ASN1Sequence seqOfcurTreehashString; - - Treehash[][] curTreehash = new Treehash[seqOfcurTreehash0.size()][]; - /* - for (int i = 0; i < curTreehash.length; i++) - { - seqOfcurTreehash1 = (ASN1Sequence)seqOfcurTreehash0.getObjectAt(i); - curTreehash[i] = new Treehash[seqOfcurTreehash1.size()]; - for (int j = 0; j < curTreehash[i].length; j++) - { - seqOfcurTreehashStat = (ASN1Sequence)seqOfcurTreehash1.getObjectAt(j); - seqOfcurTreehashString = (ASN1Sequence)seqOfcurTreehashStat - .getObjectAt(0); - seqOfcurTreehashBytes = (ASN1Sequence)seqOfcurTreehashStat - .getObjectAt(1); - seqOfcurTreehashInts = (ASN1Sequence)seqOfcurTreehashStat - .getObjectAt(2); - - String[] name = new String[2]; - name[0] = ((DERIA5String)seqOfcurTreehashString.getObjectAt(0)).getString(); - name[1] = ((DERIA5String)seqOfcurTreehashString.getObjectAt(1)).getString(); - - int tailLength = checkBigIntegerInIntRange(seqOfcurTreehashInts.getObjectAt(1)); - byte[][] statByte = new byte[3 + tailLength][]; - statByte[0] = ((DEROctetString)seqOfcurTreehashBytes.getObjectAt(0)).getOctets(); - - if (statByte[0].length == 0) - { // if null was encoded - statByte[0] = null; - } - - statByte[1] = ((DEROctetString)seqOfcurTreehashBytes.getObjectAt(1)).getOctets(); - statByte[2] = ((DEROctetString)seqOfcurTreehashBytes.getObjectAt(2)).getOctets(); - for (int k = 0; k < tailLength; k++) - { - statByte[3 + k] = ((DEROctetString)seqOfcurTreehashBytes - .getObjectAt(3 + k)).getOctets(); - } - int[] statInt = new int[6 + tailLength]; - statInt[0] = checkBigIntegerInIntRange(seqOfcurTreehashInts.getObjectAt(0)); - statInt[1] = tailLength; - statInt[2] = checkBigIntegerInIntRange(seqOfcurTreehashInts.getObjectAt(2)); - statInt[3] = checkBigIntegerInIntRange(seqOfcurTreehashInts.getObjectAt(3)); - statInt[4] = checkBigIntegerInIntRange(seqOfcurTreehashInts.getObjectAt(4)); - statInt[5] = checkBigIntegerInIntRange(seqOfcurTreehashInts.getObjectAt(5)); - for (int k = 0; k < tailLength; k++) - { - statInt[6 + k] = checkBigIntegerInIntRange(seqOfcurTreehashInts.getObjectAt(6 + k)); - } - - // TODO: Check if we can do better than throwing away name[1] !!! - curTreehash[i][j] = new Treehash(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt); - } - } - - - // --- Decode . - ASN1Sequence seqOfNextTreehash0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(6); - ASN1Sequence seqOfNextTreehash1; - ASN1Sequence seqOfNextTreehashStat; - ASN1Sequence seqOfNextTreehashBytes; - ASN1Sequence seqOfNextTreehashInts; - ASN1Sequence seqOfNextTreehashString; - - Treehash[][] nextTreehash = new Treehash[seqOfNextTreehash0.size()][]; - - for (int i = 0; i < nextTreehash.length; i++) - { - seqOfNextTreehash1 = (ASN1Sequence)seqOfNextTreehash0.getObjectAt(i); - nextTreehash[i] = new Treehash[seqOfNextTreehash1.size()]; - for (int j = 0; j < nextTreehash[i].length; j++) - { - seqOfNextTreehashStat = (ASN1Sequence)seqOfNextTreehash1 - .getObjectAt(j); - seqOfNextTreehashString = (ASN1Sequence)seqOfNextTreehashStat - .getObjectAt(0); - seqOfNextTreehashBytes = (ASN1Sequence)seqOfNextTreehashStat - .getObjectAt(1); - seqOfNextTreehashInts = (ASN1Sequence)seqOfNextTreehashStat - .getObjectAt(2); - - String[] name = new String[2]; - name[0] = ((DERIA5String)seqOfNextTreehashString.getObjectAt(0)) - .getString(); - name[1] = ((DERIA5String)seqOfNextTreehashString.getObjectAt(1)) - .getString(); - - int tailLength = checkBigIntegerInIntRange(seqOfNextTreehashInts.getObjectAt(1)); - - byte[][] statByte = new byte[3 + tailLength][]; - statByte[0] = ((DEROctetString)seqOfNextTreehashBytes.getObjectAt(0)).getOctets(); - if (statByte[0].length == 0) - { // if null was encoded - statByte[0] = null; - } - - statByte[1] = ((DEROctetString)seqOfNextTreehashBytes.getObjectAt(1)).getOctets(); - statByte[2] = ((DEROctetString)seqOfNextTreehashBytes.getObjectAt(2)).getOctets(); - for (int k = 0; k < tailLength; k++) - { - statByte[3 + k] = ((DEROctetString)seqOfNextTreehashBytes - .getObjectAt(3 + k)).getOctets(); - } - int[] statInt = new int[6 + tailLength]; - statInt[0] = checkBigIntegerInIntRange(seqOfNextTreehashInts.getObjectAt(0)); - - statInt[1] = tailLength; - statInt[2] = checkBigIntegerInIntRange(seqOfNextTreehashInts.getObjectAt(2)); - - statInt[3] = checkBigIntegerInIntRange(seqOfNextTreehashInts.getObjectAt(3)); - - statInt[4] = checkBigIntegerInIntRange(seqOfNextTreehashInts.getObjectAt(4)); - - statInt[5] = checkBigIntegerInIntRange(seqOfNextTreehashInts.getObjectAt(5)); - - for (int k = 0; k < tailLength; k++) - { - statInt[6 + k] = checkBigIntegerInIntRange(seqOfNextTreehashInts.getObjectAt(6 + k)); - - } - nextTreehash[i][j] = new Treehash(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt); - } - } - - - // --- Decode . - ASN1Sequence keepPart0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(7); - ASN1Sequence keepPart1; - - byte[][][] keep = new byte[keepPart0.size()][][]; - for (int i = 0; i < keep.length; i++) - { - keepPart1 = (ASN1Sequence)keepPart0.getObjectAt(i); - keep[i] = new byte[keepPart1.size()][]; - for (int j = 0; j < keep[i].length; j++) - { - keep[i][j] = ((DEROctetString)keepPart1.getObjectAt(j)).getOctets(); - } - } - - // --- Decode . - ASN1Sequence curStackPart0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(8); - ASN1Sequence curStackPart1; - - Vector[] curStack = new Vector[curStackPart0.size()]; - for (int i = 0; i < curStack.length; i++) - { - curStackPart1 = (ASN1Sequence)curStackPart0.getObjectAt(i); - curStack[i] = new Vector(); - for (int j = 0; j < curStackPart1.size(); j++) - { - curStack[i].addElement(((DEROctetString)curStackPart1.getObjectAt(j)).getOctets()); - } - } - - // --- Decode . - ASN1Sequence nextStackPart0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(9); - ASN1Sequence nextStackPart1; - - Vector[] nextStack = new Vector[nextStackPart0.size()]; - for (int i = 0; i < nextStack.length; i++) - { - nextStackPart1 = (ASN1Sequence)nextStackPart0.getObjectAt(i); - nextStack[i] = new Vector(); - for (int j = 0; j < nextStackPart1.size(); j++) - { - nextStack[i].addElement(((DEROctetString)nextStackPart1 - .getObjectAt(j)).getOctets()); - } - } - - // --- Decode . - ASN1Sequence curRetainPart0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(10); - ASN1Sequence curRetainPart1; - ASN1Sequence curRetainPart2; - - Vector[][] curRetain = new Vector[curRetainPart0.size()][]; - for (int i = 0; i < curRetain.length; i++) - { - curRetainPart1 = (ASN1Sequence)curRetainPart0.getObjectAt(i); - curRetain[i] = new Vector[curRetainPart1.size()]; - for (int j = 0; j < curRetain[i].length; j++) - { - curRetainPart2 = (ASN1Sequence)curRetainPart1.getObjectAt(j); - curRetain[i][j] = new Vector(); - for (int k = 0; k < curRetainPart2.size(); k++) - { - curRetain[i][j] - .addElement(((DEROctetString)curRetainPart2 - .getObjectAt(k)).getOctets()); - } - } - } - - // --- Decode . - ASN1Sequence nextRetainPart0 = (ASN1Sequence)mtsPrivateKey.getObjectAt(11); - ASN1Sequence nextRetainPart1; - ASN1Sequence nextRetainPart2; - - Vector[][] nextRetain = new Vector[nextRetainPart0.size()][]; - for (int i = 0; i < nextRetain.length; i++) - { - nextRetainPart1 = (ASN1Sequence)nextRetainPart0.getObjectAt(i); - nextRetain[i] = new Vector[nextRetainPart1.size()]; - for (int j = 0; j < nextRetain[i].length; j++) - { - nextRetainPart2 = (ASN1Sequence)nextRetainPart1.getObjectAt(j); - nextRetain[i][j] = new Vector(); - for (int k = 0; k < nextRetainPart2.size(); k++) - { - nextRetain[i][j] - .addElement(((DEROctetString)nextRetainPart2 - .getObjectAt(k)).getOctets()); - } - } - } - - // --- Decode . - ASN1Sequence seqOfLeafs = (ASN1Sequence)mtsPrivateKey.getObjectAt(12); - ASN1Sequence seqOfLeafStat; - ASN1Sequence seqOfLeafBytes; - ASN1Sequence seqOfLeafInts; - ASN1Sequence seqOfLeafString; - - GMSSLeaf[] nextNextLeaf = new GMSSLeaf[seqOfLeafs.size()]; - - for (int i = 0; i < nextNextLeaf.length; i++) - { - seqOfLeafStat = (ASN1Sequence)seqOfLeafs.getObjectAt(i); - // nextNextAuth[i]= new byte[nextNextAuthPart1.size()][]; - seqOfLeafString = (ASN1Sequence)seqOfLeafStat.getObjectAt(0); - seqOfLeafBytes = (ASN1Sequence)seqOfLeafStat.getObjectAt(1); - seqOfLeafInts = (ASN1Sequence)seqOfLeafStat.getObjectAt(2); - - String[] name = new String[2]; - name[0] = ((DERIA5String)seqOfLeafString.getObjectAt(0)).getString(); - name[1] = ((DERIA5String)seqOfLeafString.getObjectAt(1)).getString(); - byte[][] statByte = new byte[4][]; - statByte[0] = ((DEROctetString)seqOfLeafBytes.getObjectAt(0)) - .getOctets(); - statByte[1] = ((DEROctetString)seqOfLeafBytes.getObjectAt(1)) - .getOctets(); - statByte[2] = ((DEROctetString)seqOfLeafBytes.getObjectAt(2)) - .getOctets(); - statByte[3] = ((DEROctetString)seqOfLeafBytes.getObjectAt(3)) - .getOctets(); - int[] statInt = new int[4]; - statInt[0] = checkBigIntegerInIntRange(seqOfLeafInts.getObjectAt(0)); - statInt[1] = checkBigIntegerInIntRange(seqOfLeafInts.getObjectAt(1)); - statInt[2] = checkBigIntegerInIntRange(seqOfLeafInts.getObjectAt(2)); - statInt[3] = checkBigIntegerInIntRange(seqOfLeafInts.getObjectAt(3)); - nextNextLeaf[i] = new GMSSLeaf(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt); - } - - // --- Decode . - ASN1Sequence seqOfUpperLeafs = (ASN1Sequence)mtsPrivateKey.getObjectAt(13); - ASN1Sequence seqOfUpperLeafStat; - ASN1Sequence seqOfUpperLeafBytes; - ASN1Sequence seqOfUpperLeafInts; - ASN1Sequence seqOfUpperLeafString; - - GMSSLeaf[] upperLeaf = new GMSSLeaf[seqOfUpperLeafs.size()]; - - for (int i = 0; i < upperLeaf.length; i++) - { - seqOfUpperLeafStat = (ASN1Sequence)seqOfUpperLeafs.getObjectAt(i); - seqOfUpperLeafString = (ASN1Sequence)seqOfUpperLeafStat.getObjectAt(0); - seqOfUpperLeafBytes = (ASN1Sequence)seqOfUpperLeafStat.getObjectAt(1); - seqOfUpperLeafInts = (ASN1Sequence)seqOfUpperLeafStat.getObjectAt(2); - - String[] name = new String[2]; - name[0] = ((DERIA5String)seqOfUpperLeafString.getObjectAt(0)).getString(); - name[1] = ((DERIA5String)seqOfUpperLeafString.getObjectAt(1)).getString(); - byte[][] statByte = new byte[4][]; - statByte[0] = ((DEROctetString)seqOfUpperLeafBytes.getObjectAt(0)) - .getOctets(); - statByte[1] = ((DEROctetString)seqOfUpperLeafBytes.getObjectAt(1)) - .getOctets(); - statByte[2] = ((DEROctetString)seqOfUpperLeafBytes.getObjectAt(2)) - .getOctets(); - statByte[3] = ((DEROctetString)seqOfUpperLeafBytes.getObjectAt(3)) - .getOctets(); - int[] statInt = new int[4]; - statInt[0] = checkBigIntegerInIntRange(seqOfUpperLeafInts.getObjectAt(0)); - statInt[1] = checkBigIntegerInIntRange(seqOfUpperLeafInts.getObjectAt(1)); - statInt[2] = checkBigIntegerInIntRange(seqOfUpperLeafInts.getObjectAt(2)); - statInt[3] = checkBigIntegerInIntRange(seqOfUpperLeafInts.getObjectAt(3)); - upperLeaf[i] = new GMSSLeaf(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt); - } - - // --- Decode . - ASN1Sequence seqOfUpperTHLeafs = (ASN1Sequence)mtsPrivateKey.getObjectAt(14); - ASN1Sequence seqOfUpperTHLeafStat; - ASN1Sequence seqOfUpperTHLeafBytes; - ASN1Sequence seqOfUpperTHLeafInts; - ASN1Sequence seqOfUpperTHLeafString; - - GMSSLeaf[] upperTHLeaf = new GMSSLeaf[seqOfUpperTHLeafs.size()]; - - for (int i = 0; i < upperTHLeaf.length; i++) - { - seqOfUpperTHLeafStat = (ASN1Sequence)seqOfUpperTHLeafs.getObjectAt(i); - seqOfUpperTHLeafString = (ASN1Sequence)seqOfUpperTHLeafStat.getObjectAt(0); - seqOfUpperTHLeafBytes = (ASN1Sequence)seqOfUpperTHLeafStat.getObjectAt(1); - seqOfUpperTHLeafInts = (ASN1Sequence)seqOfUpperTHLeafStat.getObjectAt(2); - - String[] name = new String[2]; - name[0] = ((DERIA5String)seqOfUpperTHLeafString.getObjectAt(0)) - .getString(); - name[1] = ((DERIA5String)seqOfUpperTHLeafString.getObjectAt(1)) - .getString(); - byte[][] statByte = new byte[4][]; - statByte[0] = ((DEROctetString)seqOfUpperTHLeafBytes.getObjectAt(0)) - .getOctets(); - statByte[1] = ((DEROctetString)seqOfUpperTHLeafBytes.getObjectAt(1)) - .getOctets(); - statByte[2] = ((DEROctetString)seqOfUpperTHLeafBytes.getObjectAt(2)) - .getOctets(); - statByte[3] = ((DEROctetString)seqOfUpperTHLeafBytes.getObjectAt(3)) - .getOctets(); - int[] statInt = new int[4]; - statInt[0] = checkBigIntegerInIntRange(seqOfUpperTHLeafInts.getObjectAt(0)); - statInt[1] = checkBigIntegerInIntRange(seqOfUpperTHLeafInts.getObjectAt(1)); - statInt[2] = checkBigIntegerInIntRange(seqOfUpperTHLeafInts.getObjectAt(2)); - statInt[3] = checkBigIntegerInIntRange(seqOfUpperTHLeafInts.getObjectAt(3)); - upperTHLeaf[i] = new GMSSLeaf(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt); - } - - // --- Decode . - ASN1Sequence minTreehashPart = (ASN1Sequence)mtsPrivateKey.getObjectAt(15); - int[] minTreehash = new int[minTreehashPart.size()]; - for (int i = 0; i < minTreehashPart.size(); i++) - { - minTreehash[i] = checkBigIntegerInIntRange(minTreehashPart.getObjectAt(i)); - } - - // --- Decode . - ASN1Sequence seqOfnextRoots = (ASN1Sequence)mtsPrivateKey.getObjectAt(16); - byte[][] nextRoot = new byte[seqOfnextRoots.size()][]; - for (int i = 0; i < nextRoot.length; i++) - { - nextRoot[i] = ((DEROctetString)seqOfnextRoots.getObjectAt(i)) - .getOctets(); - } - - // --- Decode . - ASN1Sequence seqOfnextNextRoot = (ASN1Sequence)mtsPrivateKey.getObjectAt(17); - ASN1Sequence seqOfnextNextRootStat; - ASN1Sequence seqOfnextNextRootBytes; - ASN1Sequence seqOfnextNextRootInts; - ASN1Sequence seqOfnextNextRootString; - ASN1Sequence seqOfnextNextRootTreeH; - ASN1Sequence seqOfnextNextRootRetain; - - GMSSRootCalc[] nextNextRoot = new GMSSRootCalc[seqOfnextNextRoot.size()]; - - for (int i = 0; i < nextNextRoot.length; i++) - { - seqOfnextNextRootStat = (ASN1Sequence)seqOfnextNextRoot.getObjectAt(i); - seqOfnextNextRootString = (ASN1Sequence)seqOfnextNextRootStat - .getObjectAt(0); - seqOfnextNextRootBytes = (ASN1Sequence)seqOfnextNextRootStat - .getObjectAt(1); - seqOfnextNextRootInts = (ASN1Sequence)seqOfnextNextRootStat.getObjectAt(2); - seqOfnextNextRootTreeH = (ASN1Sequence)seqOfnextNextRootStat - .getObjectAt(3); - seqOfnextNextRootRetain = (ASN1Sequence)seqOfnextNextRootStat - .getObjectAt(4); - - // decode treehash of nextNextRoot - // --------------------------------- - ASN1Sequence seqOfnextNextRootTreeHStat; - ASN1Sequence seqOfnextNextRootTreeHBytes; - ASN1Sequence seqOfnextNextRootTreeHInts; - ASN1Sequence seqOfnextNextRootTreeHString; - - Treehash[] nnRTreehash = new Treehash[seqOfnextNextRootTreeH.size()]; - - for (int k = 0; k < nnRTreehash.length; k++) - { - seqOfnextNextRootTreeHStat = (ASN1Sequence)seqOfnextNextRootTreeH - .getObjectAt(k); - seqOfnextNextRootTreeHString = (ASN1Sequence)seqOfnextNextRootTreeHStat - .getObjectAt(0); - seqOfnextNextRootTreeHBytes = (ASN1Sequence)seqOfnextNextRootTreeHStat - .getObjectAt(1); - seqOfnextNextRootTreeHInts = (ASN1Sequence)seqOfnextNextRootTreeHStat - .getObjectAt(2); - - String[] name = new String[2]; - name[0] = ((DERIA5String)seqOfnextNextRootTreeHString.getObjectAt(0)) - .getString(); - name[1] = ((DERIA5String)seqOfnextNextRootTreeHString.getObjectAt(1)) - .getString(); - - int tailLength = checkBigIntegerInIntRange(seqOfnextNextRootTreeHInts.getObjectAt(1)); - - byte[][] statByte = new byte[3 + tailLength][]; - statByte[0] = ((DEROctetString)seqOfnextNextRootTreeHBytes - .getObjectAt(0)).getOctets(); - if (statByte[0].length == 0) - { // if null was encoded - statByte[0] = null; - } - - statByte[1] = ((DEROctetString)seqOfnextNextRootTreeHBytes - .getObjectAt(1)).getOctets(); - statByte[2] = ((DEROctetString)seqOfnextNextRootTreeHBytes - .getObjectAt(2)).getOctets(); - for (int j = 0; j < tailLength; j++) - { - statByte[3 + j] = ((DEROctetString)seqOfnextNextRootTreeHBytes - .getObjectAt(3 + j)).getOctets(); - } - int[] statInt = new int[6 + tailLength]; - statInt[0] = checkBigIntegerInIntRange(seqOfnextNextRootTreeHInts.getObjectAt(0)); - - statInt[1] = tailLength; - statInt[2] = checkBigIntegerInIntRange(seqOfnextNextRootTreeHInts.getObjectAt(2)); - - statInt[3] = checkBigIntegerInIntRange(seqOfnextNextRootTreeHInts.getObjectAt(3)); - - statInt[4] = checkBigIntegerInIntRange(seqOfnextNextRootTreeHInts.getObjectAt(4)); - - statInt[5] = checkBigIntegerInIntRange(seqOfnextNextRootTreeHInts.getObjectAt(5)); - - for (int j = 0; j < tailLength; j++) - { - statInt[6 + j] = checkBigIntegerInIntRange(seqOfnextNextRootTreeHInts - .getObjectAt(6 + j)); - } - nnRTreehash[k] = new Treehash(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt); - } - // --------------------------------- - - // decode retain of nextNextRoot - // --------------------------------- - // ASN1Sequence seqOfnextNextRootRetainPart0 = - // (ASN1Sequence)seqOfnextNextRootRetain.get(0); - ASN1Sequence seqOfnextNextRootRetainPart1; - - Vector[] nnRRetain = new Vector[seqOfnextNextRootRetain.size()]; - for (int j = 0; j < nnRRetain.length; j++) - { - seqOfnextNextRootRetainPart1 = (ASN1Sequence)seqOfnextNextRootRetain - .getObjectAt(j); - nnRRetain[j] = new Vector(); - for (int k = 0; k < seqOfnextNextRootRetainPart1.size(); k++) - { - nnRRetain[j] - .addElement(((DEROctetString)seqOfnextNextRootRetainPart1 - .getObjectAt(k)).getOctets()); - } - } - // --------------------------------- - - String[] name = new String[2]; - name[0] = ((DERIA5String)seqOfnextNextRootString.getObjectAt(0)) - .getString(); - name[1] = ((DERIA5String)seqOfnextNextRootString.getObjectAt(1)) - .getString(); - - int heightOfTree = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(0)); - int tailLength = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(7)); - byte[][] statByte = new byte[1 + heightOfTree + tailLength][]; - statByte[0] = ((DEROctetString)seqOfnextNextRootBytes.getObjectAt(0)) - .getOctets(); - for (int j = 0; j < heightOfTree; j++) - { - statByte[1 + j] = ((DEROctetString)seqOfnextNextRootBytes - .getObjectAt(1 + j)).getOctets(); - } - for (int j = 0; j < tailLength; j++) - { - statByte[1 + heightOfTree + j] = ((DEROctetString)seqOfnextNextRootBytes - .getObjectAt(1 + heightOfTree + j)).getOctets(); - } - int[] statInt = new int[8 + heightOfTree + tailLength]; - statInt[0] = heightOfTree; - statInt[1] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(1)); - statInt[2] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(2)); - statInt[3] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(3)); - statInt[4] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(4)); - statInt[5] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(5)); - statInt[6] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(6)); - statInt[7] = tailLength; - for (int j = 0; j < heightOfTree; j++) - { - statInt[8 + j] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(8 + j)); - } - for (int j = 0; j < tailLength; j++) - { - statInt[8 + heightOfTree + j] = checkBigIntegerInIntRange(seqOfnextNextRootInts.getObjectAt(8 - + heightOfTree + j)); - } - nextNextRoot[i] = new GMSSRootCalc(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt, - nnRTreehash, nnRRetain); - } - - // --- Decode . - ASN1Sequence seqOfcurRootSig = (ASN1Sequence)mtsPrivateKey.getObjectAt(18); - byte[][] curRootSig = new byte[seqOfcurRootSig.size()][]; - for (int i = 0; i < curRootSig.length; i++) - { - curRootSig[i] = ((DEROctetString)seqOfcurRootSig.getObjectAt(i)) - .getOctets(); - } - - // --- Decode . - ASN1Sequence seqOfnextRootSigs = (ASN1Sequence)mtsPrivateKey.getObjectAt(19); - ASN1Sequence seqOfnRSStats; - ASN1Sequence seqOfnRSStrings; - ASN1Sequence seqOfnRSInts; - ASN1Sequence seqOfnRSBytes; - - GMSSRootSig[] nextRootSig = new GMSSRootSig[seqOfnextRootSigs.size()]; - - for (int i = 0; i < nextRootSig.length; i++) - { - seqOfnRSStats = (ASN1Sequence)seqOfnextRootSigs.getObjectAt(i); - // nextNextAuth[i]= new byte[nextNextAuthPart1.size()][]; - seqOfnRSStrings = (ASN1Sequence)seqOfnRSStats.getObjectAt(0); - seqOfnRSBytes = (ASN1Sequence)seqOfnRSStats.getObjectAt(1); - seqOfnRSInts = (ASN1Sequence)seqOfnRSStats.getObjectAt(2); - - String[] name = new String[2]; - name[0] = ((DERIA5String)seqOfnRSStrings.getObjectAt(0)).getString(); - name[1] = ((DERIA5String)seqOfnRSStrings.getObjectAt(1)).getString(); - byte[][] statByte = new byte[5][]; - statByte[0] = ((DEROctetString)seqOfnRSBytes.getObjectAt(0)) - .getOctets(); - statByte[1] = ((DEROctetString)seqOfnRSBytes.getObjectAt(1)) - .getOctets(); - statByte[2] = ((DEROctetString)seqOfnRSBytes.getObjectAt(2)) - .getOctets(); - statByte[3] = ((DEROctetString)seqOfnRSBytes.getObjectAt(3)) - .getOctets(); - statByte[4] = ((DEROctetString)seqOfnRSBytes.getObjectAt(4)) - .getOctets(); - int[] statInt = new int[9]; - statInt[0] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(0)); - statInt[1] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(1)); - statInt[2] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(2)); - statInt[3] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(3)); - statInt[4] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(4)); - statInt[5] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(5)); - statInt[6] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(6)); - statInt[7] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(7)); - statInt[8] = checkBigIntegerInIntRange(seqOfnRSInts.getObjectAt(8)); - nextRootSig[i] = new GMSSRootSig(DigestFactory.getDigest(name[0]).getClass(), statByte, statInt); - } - - // --- Decode . - - // TODO: Really check, why there are multiple algorithms, we only - // use the first one!!! - ASN1Sequence namePart = (ASN1Sequence)mtsPrivateKey.getObjectAt(20); - String[] name = new String[namePart.size()]; - for (int i = 0; i < name.length; i++) - { - name[i] = ((DERIA5String)namePart.getObjectAt(i)).getString(); - } - */ - } - - public GMSSPrivateKey(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, AlgorithmIdentifier digestAlg) - { - AlgorithmIdentifier[] names = new AlgorithmIdentifier[] { digestAlg }; - this.primitive = encode(index, currentSeed, nextNextSeed, currentAuthPath, nextAuthPath, keep, currentTreehash, nextTreehash, currentStack, nextStack, currentRetain, nextRetain, nextNextLeaf, upperLeaf, upperTreehashLeaf, minTreehash, nextRoot, nextNextRoot, currentRootSig, nextRootSig, gmssParameterset, names); - } - - - // TODO: change method signature to something more integrated into BouncyCastle - - /** - * @param index tree indices - * @param currentSeeds seed for the generation of private OTS keys for the - * current subtrees (TREE) - * @param nextNextSeeds seed for the generation of private OTS keys for the - * subtrees after next (TREE++) - * @param currentAuthPaths array of current authentication paths (AUTHPATH) - * @param nextAuthPaths 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 - * @param algorithms An array of algorithm identifiers, containing the hash function details - */ - private ASN1Primitive encode(int[] index, byte[][] currentSeeds, - byte[][] nextNextSeeds, byte[][][] currentAuthPaths, - byte[][][] nextAuthPaths, byte[][][] keep, - Treehash[][] currentTreehash, Treehash[][] nextTreehash, - Vector[] currentStack, Vector[] nextStack, - Vector[][] currentRetain, Vector[][] nextRetain, - GMSSLeaf[] nextNextLeaf, GMSSLeaf[] upperLeaf, - GMSSLeaf[] upperTreehashLeaf, int[] minTreehash, byte[][] nextRoot, - GMSSRootCalc[] nextNextRoot, byte[][] currentRootSig, - GMSSRootSig[] nextRootSig, GMSSParameters gmssParameterset, - AlgorithmIdentifier[] algorithms) - { - - ASN1EncodableVector result = new ASN1EncodableVector(); - - // --- Encode . - ASN1EncodableVector indexPart = new ASN1EncodableVector(); - for (int i = 0; i < index.length; i++) - { - indexPart.add(new ASN1Integer(index[i])); - } - result.add(new DERSequence(indexPart)); - - // --- Encode . - ASN1EncodableVector curSeedsPart = new ASN1EncodableVector(); - for (int i = 0; i < currentSeeds.length; i++) - { - curSeedsPart.add(new DEROctetString(currentSeeds[i])); - } - result.add(new DERSequence(curSeedsPart)); - - // --- Encode . - ASN1EncodableVector nextNextSeedsPart = new ASN1EncodableVector(); - for (int i = 0; i < nextNextSeeds.length; i++) - { - nextNextSeedsPart.add(new DEROctetString(nextNextSeeds[i])); - } - result.add(new DERSequence(nextNextSeedsPart)); - - // --- Encode . - ASN1EncodableVector curAuthPart0 = new ASN1EncodableVector(); - ASN1EncodableVector curAuthPart1 = new ASN1EncodableVector(); - for (int i = 0; i < currentAuthPaths.length; i++) - { - for (int j = 0; j < currentAuthPaths[i].length; j++) - { - curAuthPart0.add(new DEROctetString(currentAuthPaths[i][j])); - } - curAuthPart1.add(new DERSequence(curAuthPart0)); - curAuthPart0 = new ASN1EncodableVector(); - } - result.add(new DERSequence(curAuthPart1)); - - // --- Encode . - ASN1EncodableVector nextAuthPart0 = new ASN1EncodableVector(); - ASN1EncodableVector nextAuthPart1 = new ASN1EncodableVector(); - for (int i = 0; i < nextAuthPaths.length; i++) - { - for (int j = 0; j < nextAuthPaths[i].length; j++) - { - nextAuthPart0.add(new DEROctetString(nextAuthPaths[i][j])); - } - nextAuthPart1.add(new DERSequence(nextAuthPart0)); - nextAuthPart0 = new ASN1EncodableVector(); - } - result.add(new DERSequence(nextAuthPart1)); - - // --- Encode . - ASN1EncodableVector seqOfTreehash0 = new ASN1EncodableVector(); - ASN1EncodableVector seqOfTreehash1 = new ASN1EncodableVector(); - ASN1EncodableVector seqOfStat = new ASN1EncodableVector(); - ASN1EncodableVector seqOfByte = new ASN1EncodableVector(); - ASN1EncodableVector seqOfInt = new ASN1EncodableVector(); - - for (int i = 0; i < currentTreehash.length; i++) - { - for (int j = 0; j < currentTreehash[i].length; j++) - { - seqOfStat.add(new DERSequence(algorithms[0])); - - int tailLength = currentTreehash[i][j].getStatInt()[1]; - - seqOfByte.add(new DEROctetString(currentTreehash[i][j] - .getStatByte()[0])); - seqOfByte.add(new DEROctetString(currentTreehash[i][j] - .getStatByte()[1])); - seqOfByte.add(new DEROctetString(currentTreehash[i][j] - .getStatByte()[2])); - for (int k = 0; k < tailLength; k++) - { - seqOfByte.add(new DEROctetString(currentTreehash[i][j] - .getStatByte()[3 + k])); - } - seqOfStat.add(new DERSequence(seqOfByte)); - seqOfByte = new ASN1EncodableVector(); - - seqOfInt.add(new ASN1Integer( - currentTreehash[i][j].getStatInt()[0])); - seqOfInt.add(new ASN1Integer(tailLength)); - seqOfInt.add(new ASN1Integer( - currentTreehash[i][j].getStatInt()[2])); - seqOfInt.add(new ASN1Integer( - currentTreehash[i][j].getStatInt()[3])); - seqOfInt.add(new ASN1Integer( - currentTreehash[i][j].getStatInt()[4])); - seqOfInt.add(new ASN1Integer( - currentTreehash[i][j].getStatInt()[5])); - for (int k = 0; k < tailLength; k++) - { - seqOfInt.add(new ASN1Integer(currentTreehash[i][j] - .getStatInt()[6 + k])); - } - seqOfStat.add(new DERSequence(seqOfInt)); - seqOfInt = new ASN1EncodableVector(); - - seqOfTreehash1.add(new DERSequence(seqOfStat)); - seqOfStat = new ASN1EncodableVector(); - } - seqOfTreehash0.add(new DERSequence(seqOfTreehash1)); - seqOfTreehash1 = new ASN1EncodableVector(); - } - result.add(new DERSequence(seqOfTreehash0)); - - // --- Encode . - seqOfTreehash0 = new ASN1EncodableVector(); - seqOfTreehash1 = new ASN1EncodableVector(); - seqOfStat = new ASN1EncodableVector(); - seqOfByte = new ASN1EncodableVector(); - seqOfInt = new ASN1EncodableVector(); - - for (int i = 0; i < nextTreehash.length; i++) - { - for (int j = 0; j < nextTreehash[i].length; j++) - { - seqOfStat.add(new DERSequence(algorithms[0])); - - int tailLength = nextTreehash[i][j].getStatInt()[1]; - - seqOfByte.add(new DEROctetString(nextTreehash[i][j] - .getStatByte()[0])); - seqOfByte.add(new DEROctetString(nextTreehash[i][j] - .getStatByte()[1])); - seqOfByte.add(new DEROctetString(nextTreehash[i][j] - .getStatByte()[2])); - for (int k = 0; k < tailLength; k++) - { - seqOfByte.add(new DEROctetString(nextTreehash[i][j] - .getStatByte()[3 + k])); - } - seqOfStat.add(new DERSequence(seqOfByte)); - seqOfByte = new ASN1EncodableVector(); - - seqOfInt - .add(new ASN1Integer(nextTreehash[i][j].getStatInt()[0])); - seqOfInt.add(new ASN1Integer(tailLength)); - seqOfInt - .add(new ASN1Integer(nextTreehash[i][j].getStatInt()[2])); - seqOfInt - .add(new ASN1Integer(nextTreehash[i][j].getStatInt()[3])); - seqOfInt - .add(new ASN1Integer(nextTreehash[i][j].getStatInt()[4])); - seqOfInt - .add(new ASN1Integer(nextTreehash[i][j].getStatInt()[5])); - for (int k = 0; k < tailLength; k++) - { - seqOfInt.add(new ASN1Integer(nextTreehash[i][j] - .getStatInt()[6 + k])); - } - seqOfStat.add(new DERSequence(seqOfInt)); - seqOfInt = new ASN1EncodableVector(); - - seqOfTreehash1.add(new DERSequence(seqOfStat)); - seqOfStat = new ASN1EncodableVector(); - } - seqOfTreehash0.add(new DERSequence(new DERSequence(seqOfTreehash1))); - seqOfTreehash1 = new ASN1EncodableVector(); - } - result.add(new DERSequence(seqOfTreehash0)); - - // --- Encode . - ASN1EncodableVector keepPart0 = new ASN1EncodableVector(); - ASN1EncodableVector keepPart1 = new ASN1EncodableVector(); - for (int i = 0; i < keep.length; i++) - { - for (int j = 0; j < keep[i].length; j++) - { - keepPart0.add(new DEROctetString(keep[i][j])); - } - keepPart1.add(new DERSequence(keepPart0)); - keepPart0 = new ASN1EncodableVector(); - } - result.add(new DERSequence(keepPart1)); - - // --- Encode . - ASN1EncodableVector curStackPart0 = new ASN1EncodableVector(); - ASN1EncodableVector curStackPart1 = new ASN1EncodableVector(); - for (int i = 0; i < currentStack.length; i++) - { - for (int j = 0; j < currentStack[i].size(); j++) - { - curStackPart0.add(new DEROctetString((byte[])currentStack[i] - .elementAt(j))); - } - curStackPart1.add(new DERSequence(curStackPart0)); - curStackPart0 = new ASN1EncodableVector(); - } - result.add(new DERSequence(curStackPart1)); - - // --- Encode . - ASN1EncodableVector nextStackPart0 = new ASN1EncodableVector(); - ASN1EncodableVector nextStackPart1 = new ASN1EncodableVector(); - for (int i = 0; i < nextStack.length; i++) - { - for (int j = 0; j < nextStack[i].size(); j++) - { - nextStackPart0.add(new DEROctetString((byte[])nextStack[i] - .elementAt(j))); - } - nextStackPart1.add(new DERSequence(nextStackPart0)); - nextStackPart0 = new ASN1EncodableVector(); - } - result.add(new DERSequence(nextStackPart1)); - - // --- Encode . - ASN1EncodableVector currentRetainPart0 = new ASN1EncodableVector(); - ASN1EncodableVector currentRetainPart1 = new ASN1EncodableVector(); - ASN1EncodableVector currentRetainPart2 = new ASN1EncodableVector(); - for (int i = 0; i < currentRetain.length; i++) - { - for (int j = 0; j < currentRetain[i].length; j++) - { - for (int k = 0; k < currentRetain[i][j].size(); k++) - { - currentRetainPart0.add(new DEROctetString( - (byte[])currentRetain[i][j].elementAt(k))); - } - currentRetainPart1.add(new DERSequence(currentRetainPart0)); - currentRetainPart0 = new ASN1EncodableVector(); - } - currentRetainPart2.add(new DERSequence(currentRetainPart1)); - currentRetainPart1 = new ASN1EncodableVector(); - } - result.add(new DERSequence(currentRetainPart2)); - - // --- Encode . - ASN1EncodableVector nextRetainPart0 = new ASN1EncodableVector(); - ASN1EncodableVector nextRetainPart1 = new ASN1EncodableVector(); - ASN1EncodableVector nextRetainPart2 = new ASN1EncodableVector(); - for (int i = 0; i < nextRetain.length; i++) - { - for (int j = 0; j < nextRetain[i].length; j++) - { - for (int k = 0; k < nextRetain[i][j].size(); k++) - { - nextRetainPart0.add(new DEROctetString( - (byte[])nextRetain[i][j].elementAt(k))); - } - nextRetainPart1.add(new DERSequence(nextRetainPart0)); - nextRetainPart0 = new ASN1EncodableVector(); - } - nextRetainPart2.add(new DERSequence(nextRetainPart1)); - nextRetainPart1 = new ASN1EncodableVector(); - } - result.add(new DERSequence(nextRetainPart2)); - - // --- Encode . - ASN1EncodableVector seqOfLeaf = new ASN1EncodableVector(); - seqOfStat = new ASN1EncodableVector(); - seqOfByte = new ASN1EncodableVector(); - seqOfInt = new ASN1EncodableVector(); - - for (int i = 0; i < nextNextLeaf.length; i++) - { - seqOfStat.add(new DERSequence(algorithms[0])); - - byte[][] tempByte = nextNextLeaf[i].getStatByte(); - seqOfByte.add(new DEROctetString(tempByte[0])); - seqOfByte.add(new DEROctetString(tempByte[1])); - seqOfByte.add(new DEROctetString(tempByte[2])); - seqOfByte.add(new DEROctetString(tempByte[3])); - seqOfStat.add(new DERSequence(seqOfByte)); - seqOfByte = new ASN1EncodableVector(); - - int[] tempInt = nextNextLeaf[i].getStatInt(); - seqOfInt.add(new ASN1Integer(tempInt[0])); - seqOfInt.add(new ASN1Integer(tempInt[1])); - seqOfInt.add(new ASN1Integer(tempInt[2])); - seqOfInt.add(new ASN1Integer(tempInt[3])); - seqOfStat.add(new DERSequence(seqOfInt)); - seqOfInt = new ASN1EncodableVector(); - - seqOfLeaf.add(new DERSequence(seqOfStat)); - seqOfStat = new ASN1EncodableVector(); - } - result.add(new DERSequence(seqOfLeaf)); - - // --- Encode . - ASN1EncodableVector seqOfUpperLeaf = new ASN1EncodableVector(); - seqOfStat = new ASN1EncodableVector(); - seqOfByte = new ASN1EncodableVector(); - seqOfInt = new ASN1EncodableVector(); - - for (int i = 0; i < upperLeaf.length; i++) - { - seqOfStat.add(new DERSequence(algorithms[0])); - - byte[][] tempByte = upperLeaf[i].getStatByte(); - seqOfByte.add(new DEROctetString(tempByte[0])); - seqOfByte.add(new DEROctetString(tempByte[1])); - seqOfByte.add(new DEROctetString(tempByte[2])); - seqOfByte.add(new DEROctetString(tempByte[3])); - seqOfStat.add(new DERSequence(seqOfByte)); - seqOfByte = new ASN1EncodableVector(); - - int[] tempInt = upperLeaf[i].getStatInt(); - seqOfInt.add(new ASN1Integer(tempInt[0])); - seqOfInt.add(new ASN1Integer(tempInt[1])); - seqOfInt.add(new ASN1Integer(tempInt[2])); - seqOfInt.add(new ASN1Integer(tempInt[3])); - seqOfStat.add(new DERSequence(seqOfInt)); - seqOfInt = new ASN1EncodableVector(); - - seqOfUpperLeaf.add(new DERSequence(seqOfStat)); - seqOfStat = new ASN1EncodableVector(); - } - result.add(new DERSequence(seqOfUpperLeaf)); - - // encode - ASN1EncodableVector seqOfUpperTreehashLeaf = new ASN1EncodableVector(); - seqOfStat = new ASN1EncodableVector(); - seqOfByte = new ASN1EncodableVector(); - seqOfInt = new ASN1EncodableVector(); - - for (int i = 0; i < upperTreehashLeaf.length; i++) - { - seqOfStat.add(new DERSequence(algorithms[0])); - - byte[][] tempByte = upperTreehashLeaf[i].getStatByte(); - seqOfByte.add(new DEROctetString(tempByte[0])); - seqOfByte.add(new DEROctetString(tempByte[1])); - seqOfByte.add(new DEROctetString(tempByte[2])); - seqOfByte.add(new DEROctetString(tempByte[3])); - seqOfStat.add(new DERSequence(seqOfByte)); - seqOfByte = new ASN1EncodableVector(); - - int[] tempInt = upperTreehashLeaf[i].getStatInt(); - seqOfInt.add(new ASN1Integer(tempInt[0])); - seqOfInt.add(new ASN1Integer(tempInt[1])); - seqOfInt.add(new ASN1Integer(tempInt[2])); - seqOfInt.add(new ASN1Integer(tempInt[3])); - seqOfStat.add(new DERSequence(seqOfInt)); - seqOfInt = new ASN1EncodableVector(); - - seqOfUpperTreehashLeaf.add(new DERSequence(seqOfStat)); - seqOfStat = new ASN1EncodableVector(); - } - result.add(new DERSequence(seqOfUpperTreehashLeaf)); - - // --- Encode . - ASN1EncodableVector minTreehashPart = new ASN1EncodableVector(); - for (int i = 0; i < minTreehash.length; i++) - { - minTreehashPart.add(new ASN1Integer(minTreehash[i])); - } - result.add(new DERSequence(minTreehashPart)); - - // --- Encode . - ASN1EncodableVector nextRootPart = new ASN1EncodableVector(); - for (int i = 0; i < nextRoot.length; i++) - { - nextRootPart.add(new DEROctetString(nextRoot[i])); - } - result.add(new DERSequence(nextRootPart)); - - // --- Encode . - ASN1EncodableVector seqOfnextNextRoot = new ASN1EncodableVector(); - ASN1EncodableVector seqOfnnRStats = new ASN1EncodableVector(); - ASN1EncodableVector seqOfnnRStrings = new ASN1EncodableVector(); - ASN1EncodableVector seqOfnnRBytes = new ASN1EncodableVector(); - ASN1EncodableVector seqOfnnRInts = new ASN1EncodableVector(); - ASN1EncodableVector seqOfnnRTreehash = new ASN1EncodableVector(); - ASN1EncodableVector seqOfnnRRetain = new ASN1EncodableVector(); - - for (int i = 0; i < nextNextRoot.length; i++) - { - seqOfnnRStats.add(new DERSequence(algorithms[0])); - seqOfnnRStrings = new ASN1EncodableVector(); - - int heightOfTree = nextNextRoot[i].getStatInt()[0]; - int tailLength = nextNextRoot[i].getStatInt()[7]; - - seqOfnnRBytes.add(new DEROctetString( - nextNextRoot[i].getStatByte()[0])); - for (int j = 0; j < heightOfTree; j++) - { - seqOfnnRBytes.add(new DEROctetString(nextNextRoot[i] - .getStatByte()[1 + j])); - } - for (int j = 0; j < tailLength; j++) - { - seqOfnnRBytes.add(new DEROctetString(nextNextRoot[i] - .getStatByte()[1 + heightOfTree + j])); - } - - seqOfnnRStats.add(new DERSequence(seqOfnnRBytes)); - seqOfnnRBytes = new ASN1EncodableVector(); - - seqOfnnRInts.add(new ASN1Integer(heightOfTree)); - seqOfnnRInts.add(new ASN1Integer(nextNextRoot[i].getStatInt()[1])); - seqOfnnRInts.add(new ASN1Integer(nextNextRoot[i].getStatInt()[2])); - seqOfnnRInts.add(new ASN1Integer(nextNextRoot[i].getStatInt()[3])); - seqOfnnRInts.add(new ASN1Integer(nextNextRoot[i].getStatInt()[4])); - seqOfnnRInts.add(new ASN1Integer(nextNextRoot[i].getStatInt()[5])); - seqOfnnRInts.add(new ASN1Integer(nextNextRoot[i].getStatInt()[6])); - seqOfnnRInts.add(new ASN1Integer(tailLength)); - for (int j = 0; j < heightOfTree; j++) - { - seqOfnnRInts.add(new ASN1Integer( - nextNextRoot[i].getStatInt()[8 + j])); - } - for (int j = 0; j < tailLength; j++) - { - seqOfnnRInts.add(new ASN1Integer(nextNextRoot[i].getStatInt()[8 - + heightOfTree + j])); - } - - seqOfnnRStats.add(new DERSequence(seqOfnnRInts)); - seqOfnnRInts = new ASN1EncodableVector(); - - // add treehash of nextNextRoot object - // ---------------------------- - seqOfStat = new ASN1EncodableVector(); - seqOfByte = new ASN1EncodableVector(); - seqOfInt = new ASN1EncodableVector(); - - if (nextNextRoot[i].getTreehash() != null) - { - for (int j = 0; j < nextNextRoot[i].getTreehash().length; j++) - { - seqOfStat.add(new DERSequence(algorithms[0])); - - tailLength = nextNextRoot[i].getTreehash()[j].getStatInt()[1]; - - seqOfByte.add(new DEROctetString(nextNextRoot[i] - .getTreehash()[j].getStatByte()[0])); - seqOfByte.add(new DEROctetString(nextNextRoot[i] - .getTreehash()[j].getStatByte()[1])); - seqOfByte.add(new DEROctetString(nextNextRoot[i] - .getTreehash()[j].getStatByte()[2])); - for (int k = 0; k < tailLength; k++) - { - seqOfByte.add(new DEROctetString(nextNextRoot[i] - .getTreehash()[j].getStatByte()[3 + k])); - } - seqOfStat.add(new DERSequence(seqOfByte)); - seqOfByte = new ASN1EncodableVector(); - - seqOfInt.add(new ASN1Integer( - nextNextRoot[i].getTreehash()[j].getStatInt()[0])); - seqOfInt.add(new ASN1Integer(tailLength)); - seqOfInt.add(new ASN1Integer( - nextNextRoot[i].getTreehash()[j].getStatInt()[2])); - seqOfInt.add(new ASN1Integer( - nextNextRoot[i].getTreehash()[j].getStatInt()[3])); - seqOfInt.add(new ASN1Integer( - nextNextRoot[i].getTreehash()[j].getStatInt()[4])); - seqOfInt.add(new ASN1Integer( - nextNextRoot[i].getTreehash()[j].getStatInt()[5])); - for (int k = 0; k < tailLength; k++) - { - seqOfInt.add(new ASN1Integer(nextNextRoot[i] - .getTreehash()[j].getStatInt()[6 + k])); - } - seqOfStat.add(new DERSequence(seqOfInt)); - seqOfInt = new ASN1EncodableVector(); - - seqOfnnRTreehash.add(new DERSequence(seqOfStat)); - seqOfStat = new ASN1EncodableVector(); - } - } - // ---------------------------- - seqOfnnRStats.add(new DERSequence(seqOfnnRTreehash)); - seqOfnnRTreehash = new ASN1EncodableVector(); - - // encode retain of nextNextRoot - // ---------------------------- - // --- Encode . - currentRetainPart0 = new ASN1EncodableVector(); - if (nextNextRoot[i].getRetain() != null) - { - for (int j = 0; j < nextNextRoot[i].getRetain().length; j++) - { - for (int k = 0; k < nextNextRoot[i].getRetain()[j].size(); k++) - { - currentRetainPart0.add(new DEROctetString( - (byte[])nextNextRoot[i].getRetain()[j] - .elementAt(k))); - } - seqOfnnRRetain.add(new DERSequence(currentRetainPart0)); - currentRetainPart0 = new ASN1EncodableVector(); - } - } - // ---------------------------- - seqOfnnRStats.add(new DERSequence(seqOfnnRRetain)); - seqOfnnRRetain = new ASN1EncodableVector(); - - seqOfnextNextRoot.add(new DERSequence(seqOfnnRStats)); - seqOfnnRStats = new ASN1EncodableVector(); - } - result.add(new DERSequence(seqOfnextNextRoot)); - - // --- Encode . - ASN1EncodableVector curRootSigPart = new ASN1EncodableVector(); - for (int i = 0; i < currentRootSig.length; i++) - { - curRootSigPart.add(new DEROctetString(currentRootSig[i])); - } - result.add(new DERSequence(curRootSigPart)); - - // --- Encode . - ASN1EncodableVector seqOfnextRootSigs = new ASN1EncodableVector(); - ASN1EncodableVector seqOfnRSStats = new ASN1EncodableVector(); - ASN1EncodableVector seqOfnRSStrings = new ASN1EncodableVector(); - ASN1EncodableVector seqOfnRSBytes = new ASN1EncodableVector(); - ASN1EncodableVector seqOfnRSInts = new ASN1EncodableVector(); - - for (int i = 0; i < nextRootSig.length; i++) - { - seqOfnRSStats.add(new DERSequence(algorithms[0])); - seqOfnRSStrings = new ASN1EncodableVector(); - - seqOfnRSBytes.add(new DEROctetString( - nextRootSig[i].getStatByte()[0])); - seqOfnRSBytes.add(new DEROctetString( - nextRootSig[i].getStatByte()[1])); - seqOfnRSBytes.add(new DEROctetString( - nextRootSig[i].getStatByte()[2])); - seqOfnRSBytes.add(new DEROctetString( - nextRootSig[i].getStatByte()[3])); - seqOfnRSBytes.add(new DEROctetString( - nextRootSig[i].getStatByte()[4])); - - seqOfnRSStats.add(new DERSequence(seqOfnRSBytes)); - seqOfnRSBytes = new ASN1EncodableVector(); - - seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[0])); - seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[1])); - seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[2])); - seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[3])); - seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[4])); - seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[5])); - seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[6])); - seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[7])); - seqOfnRSInts.add(new ASN1Integer(nextRootSig[i].getStatInt()[8])); - - seqOfnRSStats.add(new DERSequence(seqOfnRSInts)); - seqOfnRSInts = new ASN1EncodableVector(); - - seqOfnextRootSigs.add(new DERSequence(seqOfnRSStats)); - seqOfnRSStats = new ASN1EncodableVector(); - } - result.add(new DERSequence(seqOfnextRootSigs)); - - // --- Encode . - ASN1EncodableVector parSetPart0 = new ASN1EncodableVector(); - ASN1EncodableVector parSetPart1 = new ASN1EncodableVector(); - ASN1EncodableVector parSetPart2 = new ASN1EncodableVector(); - ASN1EncodableVector parSetPart3 = new ASN1EncodableVector(); - - for (int i = 0; i < gmssParameterset.getHeightOfTrees().length; i++) - { - parSetPart1.add(new ASN1Integer( - gmssParameterset.getHeightOfTrees()[i])); - parSetPart2.add(new ASN1Integer(gmssParameterset - .getWinternitzParameter()[i])); - parSetPart3.add(new ASN1Integer(gmssParameterset.getK()[i])); - } - parSetPart0.add(new ASN1Integer(gmssParameterset.getNumOfLayers())); - parSetPart0.add(new DERSequence(parSetPart1)); - parSetPart0.add(new DERSequence(parSetPart2)); - parSetPart0.add(new DERSequence(parSetPart3)); - result.add(new DERSequence(parSetPart0)); - - // --- Encode . - ASN1EncodableVector namesPart = new ASN1EncodableVector(); - - for (int i = 0; i < algorithms.length; i++) - { - namesPart.add(algorithms[i]); - } - - result.add(new DERSequence(namesPart)); - return new DERSequence(result); - - } - - private static int checkBigIntegerInIntRange(ASN1Encodable a) - { - return ((ASN1Integer)a).intValueExact(); - } - - public ASN1Primitive toASN1Primitive() - { - return this.primitive; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/GMSSPublicKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/GMSSPublicKey.java deleted file mode 100644 index fc5c4f2bce..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/GMSSPublicKey.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import org.bouncycastle.asn1.ASN1EncodableVector; -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.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.util.Arrays; - -/** - * This class implements an ASN.1 encoded GMSS public key. The ASN.1 definition - * of this structure is: - *
    - *  GMSSPublicKey        ::= SEQUENCE{
    - *      version         INTEGER
    - *      publicKey       OCTET STRING
    - *  }
    - * 
    - */ -public class GMSSPublicKey - extends ASN1Object -{ - private ASN1Integer version; - private byte[] publicKey; - - private GMSSPublicKey(ASN1Sequence seq) - { - if (seq.size() != 2) - { - throw new IllegalArgumentException("size of seq = " + seq.size()); - } - - this.version = ASN1Integer.getInstance(seq.getObjectAt(0)); - this.publicKey = ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets(); - } - - public GMSSPublicKey(byte[] publicKeyBytes) - { - this.version = new ASN1Integer(0); - this.publicKey = publicKeyBytes; - } - - public static GMSSPublicKey getInstance(Object o) - { - if (o instanceof GMSSPublicKey) - { - return (GMSSPublicKey)o; - } - else if (o != null) - { - return new GMSSPublicKey(ASN1Sequence.getInstance(o)); - } - - return null; - } - - public byte[] getPublicKey() - { - return Arrays.clone(publicKey); - } - - public ASN1Primitive toASN1Primitive() - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(version); - v.add(new DEROctetString(publicKey)); - - return new DERSequence(v); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/KyberPrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/KyberPrivateKey.java deleted file mode 100644 index cbdf006753..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/KyberPrivateKey.java +++ /dev/null @@ -1,129 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import org.bouncycastle.asn1.ASN1EncodableVector; -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.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.util.Arrays; - -/** - * - * Crystal Kyber Private Key Format. - * See https://www.ietf.org/archive/id/draft-uni-qsckeys-kyber-01.html for details. - *
    - *        KyberPrivateKey ::= SEQUENCE {
    - *            version     INTEGER {v0(0)}   -- version (round 3)
    - *            s           OCTET STRING,     -- sample s
    - *            publicKey   [0] IMPLICIT KyberPublicKey OPTIONAL,
    - *                                          -- see next section
    - *            hpk         OCTET STRING      -- H(pk)
    - *            nonce       OCTET STRING,     -- z
    - *        }
    - *    
    - */ -public class KyberPrivateKey - extends ASN1Object -{ - private int version; - private byte[] s; - private KyberPublicKey publicKey; - private byte[] hpk; - private byte[] nonce; - - public KyberPrivateKey(int version, byte[] s, byte[] hpk, byte[] nonce, KyberPublicKey publicKey) - { - this.version = version; - this.s = s; - this.publicKey = publicKey; - this.hpk = hpk; - this.nonce = nonce; - } - - public KyberPrivateKey(int version, byte[] s, byte[] hpk, byte[] nonce) - { - this(version, s, hpk, nonce, null); - } - - public int getVersion() - { - return version; - } - - public byte[] getS() - { - return Arrays.clone(s); - } - - public KyberPublicKey getPublicKey() - { - return publicKey; - } - - public byte[] getHpk() - { - return Arrays.clone(hpk); - } - - public byte[] getNonce() - { - return Arrays.clone(nonce); - } - - private KyberPrivateKey(ASN1Sequence seq) - { - version = ASN1Integer.getInstance(seq.getObjectAt(0)).intValueExact(); - if (version != 0) - { - throw new IllegalArgumentException("unrecognized version"); - } - - s = Arrays.clone(ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets()); - - int skipPubKey = 1; - if (seq.size() == 5) - { - skipPubKey = 0; - publicKey = KyberPublicKey.getInstance(seq.getObjectAt(2)); - } - - hpk = Arrays.clone(ASN1OctetString.getInstance(seq.getObjectAt(3 - skipPubKey)).getOctets()); - - nonce = Arrays.clone(ASN1OctetString.getInstance(seq.getObjectAt(4 - skipPubKey)).getOctets()); - } - - public ASN1Primitive toASN1Primitive() - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(new ASN1Integer(version)); - v.add(new DEROctetString(s)); - // todo optional publickey - if(publicKey != null) - { - v.add(new KyberPublicKey(publicKey.getT(), publicKey.getRho())); - } - v.add(new DEROctetString(hpk)); - v.add(new DEROctetString(nonce)); - - return new DERSequence(v); - } - - public static KyberPrivateKey getInstance(Object o) - { - if (o instanceof KyberPrivateKey) - { - return (KyberPrivateKey)o; - } - else if (o != null) - { - return new KyberPrivateKey(ASN1Sequence.getInstance(o)); - } - - return null; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/KyberPublicKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/KyberPublicKey.java deleted file mode 100644 index a498e7857b..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/KyberPublicKey.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -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.util.Arrays; - -/** - * - * Crystal Kyber Public Key Format. - * See https://www.ietf.org/archive/id/draft-uni-qsckeys-kyber-01.html for details. - *
    - *        KyberPublicKey ::= SEQUENCE {
    - *         t           OCTET STRING,
    - *         rho         OCTET STRING
    -*     }
    - *    
    - */ -public class KyberPublicKey - extends ASN1Object - -{ - private byte[] t; - private byte[] rho; - - public KyberPublicKey(byte[] t, byte[] rho) - { - this.t = t; - this.rho = rho; - } - - /** - * @deprecated use getInstance() - */ - public KyberPublicKey(ASN1Sequence seq) - { - t = Arrays.clone(ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets()); - rho = Arrays.clone(ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets()); - } - - public byte[] getT() - { - return Arrays.clone(t); - } - - public byte[] getRho() - { - return Arrays.clone(rho); - } - - - - public ASN1Primitive toASN1Primitive() - { - ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new DEROctetString(t)); - v.add(new DEROctetString(rho)); - return new DERSequence(v); - } - public static KyberPublicKey getInstance(Object o) - { - if (o instanceof KyberPublicKey) - { - return (KyberPublicKey) o; - } - else if (o != null) - { - return new KyberPublicKey(ASN1Sequence.getInstance(o)); - } - - return null; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java deleted file mode 100644 index 97774f40f5..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java +++ /dev/null @@ -1,136 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import org.bouncycastle.asn1.ASN1EncodableVector; -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.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.legacy.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialGF2mSmallM; - -/** - * Return the keyData to encode in the PrivateKeyInfo structure. - *

    - * The ASN.1 definition of the key structure is - *

    - *
    - *   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
    - *   }
    - * 
    - */ -public class McElieceCCA2PrivateKey - extends ASN1Object -{ - private int n; - private int k; - private byte[] encField; - private byte[] encGp; - private byte[] encP; - private AlgorithmIdentifier digest; - - - public McElieceCCA2PrivateKey(int n, int k, GF2mField field, PolynomialGF2mSmallM goppaPoly, Permutation p, AlgorithmIdentifier digest) - { - this.n = n; - this.k = k; - this.encField = field.getEncoded(); - this.encGp = goppaPoly.getEncoded(); - this.encP = p.getEncoded(); - this.digest = digest; - } - - private McElieceCCA2PrivateKey(ASN1Sequence seq) - { - n = ((ASN1Integer)seq.getObjectAt(0)).intValueExact(); - - k = ((ASN1Integer)seq.getObjectAt(1)).intValueExact(); - - encField = ((ASN1OctetString)seq.getObjectAt(2)).getOctets(); - - encGp = ((ASN1OctetString)seq.getObjectAt(3)).getOctets(); - - encP = ((ASN1OctetString)seq.getObjectAt(4)).getOctets(); - - digest = AlgorithmIdentifier.getInstance(seq.getObjectAt(5)); - } - - public int getN() - { - return n; - } - - public int getK() - { - return k; - } - - public GF2mField getField() - { - return new GF2mField(encField); - } - - public PolynomialGF2mSmallM getGoppaPoly() - { - return new PolynomialGF2mSmallM(this.getField(), encGp); - } - - public Permutation getP() - { - return new Permutation(encP); - } - - public AlgorithmIdentifier getDigest() - { - return digest; - } - - public ASN1Primitive toASN1Primitive() - { - - ASN1EncodableVector v = new ASN1EncodableVector(); - - // encode - v.add(new ASN1Integer(n)); - - // encode - v.add(new ASN1Integer(k)); - - // encode - v.add(new DEROctetString(encField)); - - // encode - v.add(new DEROctetString(encGp)); - - // encode

    - v.add(new DEROctetString(encP)); - - v.add(digest); - - return new DERSequence(v); - } - - public static McElieceCCA2PrivateKey getInstance(Object o) - { - if (o instanceof McElieceCCA2PrivateKey) - { - return (McElieceCCA2PrivateKey)o; - } - else if (o != null) - { - return new McElieceCCA2PrivateKey(ASN1Sequence.getInstance(o)); - } - - return null; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java deleted file mode 100644 index 512010e74a..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import org.bouncycastle.asn1.ASN1EncodableVector; -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.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; - -public class McElieceCCA2PublicKey - extends ASN1Object -{ - private final int n; - private final int t; - private final GF2Matrix g; - private final AlgorithmIdentifier digest; - - public McElieceCCA2PublicKey(int n, int t, GF2Matrix g, AlgorithmIdentifier digest) - { - this.n = n; - this.t = t; - this.g = new GF2Matrix(g.getEncoded()); - this.digest = digest; - } - - private McElieceCCA2PublicKey(ASN1Sequence seq) - { - n = ((ASN1Integer)seq.getObjectAt(0)).intValueExact(); - - t = ((ASN1Integer)seq.getObjectAt(1)).intValueExact(); - - g = new GF2Matrix(((ASN1OctetString)seq.getObjectAt(2)).getOctets()); - - digest = AlgorithmIdentifier.getInstance(seq.getObjectAt(3)); - } - - public int getN() - { - return n; - } - - public int getT() - { - return t; - } - - public GF2Matrix getG() - { - return g; - } - - public AlgorithmIdentifier getDigest() - { - return digest; - } - - public ASN1Primitive toASN1Primitive() - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - // encode - v.add(new ASN1Integer(n)); - - // encode - v.add(new ASN1Integer(t)); - - // encode - v.add(new DEROctetString(g.getEncoded())); - - v.add(digest); - - return new DERSequence(v); - } - - public static McElieceCCA2PublicKey getInstance(Object o) - { - if (o instanceof McElieceCCA2PublicKey) - { - return (McElieceCCA2PublicKey)o; - } - else if (o != null) - { - return new McElieceCCA2PublicKey(ASN1Sequence.getInstance(o)); - } - - return null; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/McEliecePrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/McEliecePrivateKey.java deleted file mode 100644 index f7fd6a3ab5..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/McEliecePrivateKey.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import org.bouncycastle.asn1.ASN1EncodableVector; -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.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.legacy.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialGF2mSmallM; - -public class McEliecePrivateKey - extends ASN1Object -{ - private int n; - private int k; - private byte[] encField; - private byte[] encGp; - private byte[] encSInv; - private byte[] encP1; - private byte[] encP2; - - public McEliecePrivateKey(int n, int k, GF2mField field, PolynomialGF2mSmallM goppaPoly, Permutation p1, Permutation p2, GF2Matrix sInv) - { - this.n = n; - this.k = k; - this.encField = field.getEncoded(); - this.encGp = goppaPoly.getEncoded(); - this.encSInv = sInv.getEncoded(); - this.encP1 = p1.getEncoded(); - this.encP2 = p2.getEncoded(); - } - - public static McEliecePrivateKey getInstance(Object o) - { - if (o instanceof McEliecePrivateKey) - { - return (McEliecePrivateKey)o; - } - else if (o != null) - { - return new McEliecePrivateKey(ASN1Sequence.getInstance(o)); - } - - return null; - } - - private McEliecePrivateKey(ASN1Sequence seq) - { - n = ((ASN1Integer)seq.getObjectAt(0)).intValueExact(); - - k = ((ASN1Integer)seq.getObjectAt(1)).intValueExact(); - - encField = ((ASN1OctetString)seq.getObjectAt(2)).getOctets(); - - encGp = ((ASN1OctetString)seq.getObjectAt(3)).getOctets(); - - encP1 = ((ASN1OctetString)seq.getObjectAt(4)).getOctets(); - - encP2 = ((ASN1OctetString)seq.getObjectAt(5)).getOctets(); - - encSInv = ((ASN1OctetString)seq.getObjectAt(6)).getOctets(); - } - - public int getN() - { - return n; - } - - public int getK() - { - return k; - } - - public GF2mField getField() - { - return new GF2mField(encField); - } - - public PolynomialGF2mSmallM getGoppaPoly() - { - return new PolynomialGF2mSmallM(this.getField(), encGp); - } - - public GF2Matrix getSInv() - { - return new GF2Matrix(encSInv); - } - - public Permutation getP1() - { - return new Permutation(encP1); - } - - public Permutation getP2() - { - return new Permutation(encP2); - } - - - public ASN1Primitive toASN1Primitive() - { - - ASN1EncodableVector v = new ASN1EncodableVector(); - - // encode - v.add(new ASN1Integer(n)); - - // encode - v.add(new ASN1Integer(k)); - - // encode - v.add(new DEROctetString(encField)); - - // encode - v.add(new DEROctetString(encGp)); - - // encode - v.add(new DEROctetString(encP1)); - - // encode - v.add(new DEROctetString(encP2)); - - // encode - v.add(new DEROctetString(encSInv)); - - return new DERSequence(v); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/McEliecePublicKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/McEliecePublicKey.java deleted file mode 100644 index ffae518861..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/McEliecePublicKey.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -import org.bouncycastle.asn1.ASN1EncodableVector; -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.DEROctetString; -import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; - -public class McEliecePublicKey - extends ASN1Object -{ - private final int n; - private final int t; - private final GF2Matrix g; - - public McEliecePublicKey(int n, int t, GF2Matrix g) - { - this.n = n; - this.t = t; - this.g = new GF2Matrix(g); - } - - private McEliecePublicKey(ASN1Sequence seq) - { - n = ((ASN1Integer)seq.getObjectAt(0)).intValueExact(); - - t = ((ASN1Integer)seq.getObjectAt(1)).intValueExact(); - - g = new GF2Matrix(((ASN1OctetString)seq.getObjectAt(2)).getOctets()); - } - - public int getN() - { - return n; - } - - public int getT() - { - return t; - } - - public GF2Matrix getG() - { - return new GF2Matrix(g); - } - - public ASN1Primitive toASN1Primitive() - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - // encode - v.add(new ASN1Integer(n)); - - // encode - v.add(new ASN1Integer(t)); - - // encode - v.add(new DEROctetString(g.getEncoded())); - - return new DERSequence(v); - } - - public static McEliecePublicKey getInstance(Object o) - { - if (o instanceof McEliecePublicKey) - { - return (McEliecePublicKey)o; - } - else if (o != null) - { - return new McEliecePublicKey(ASN1Sequence.getInstance(o)); - } - - return null; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java index e88bb0898d..cb05d3b804 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java @@ -86,35 +86,43 @@ public interface PQCObjectIdentifiers /** * @deprecated use xmss_SHA256ph */ + @Deprecated final ASN1ObjectIdentifier xmss_with_SHA256 = xmss_SHA256ph; /** * @deprecated use xmss_SHA512ph */ + @Deprecated final ASN1ObjectIdentifier xmss_with_SHA512 = xmss_SHA512ph; /** * @deprecated use xmss_SHAKE128ph */ + @Deprecated final ASN1ObjectIdentifier xmss_with_SHAKE128 = xmss_SHAKE128ph; /** * @deprecated use xmss_SHAKE256ph */ + @Deprecated final ASN1ObjectIdentifier xmss_with_SHAKE256 = xmss_SHAKE256ph; /** * @deprecated use xmss_mt_SHA256ph */ + @Deprecated final ASN1ObjectIdentifier xmss_mt_with_SHA256 = xmss_mt_SHA256ph; /** * @deprecated use xmss_mt_SHA512ph */ + @Deprecated final ASN1ObjectIdentifier xmss_mt_with_SHA512 = xmss_mt_SHA512ph; /** * @deprecated use xmss_mt_SHAKE128ph */ + @Deprecated final ASN1ObjectIdentifier xmss_mt_with_SHAKE128 = xmss_mt_SHAKE128ph; /** * @deprecated use xmss_mt_SHAKE256ph */ + @Deprecated final ASN1ObjectIdentifier xmss_mt_with_SHAKE256 = xmss_mt_SHAKE256ph; /** diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/ParSet.java b/core/src/main/java/org/bouncycastle/pqc/asn1/ParSet.java index 77b87200aa..fc95558fde 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/ParSet.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/ParSet.java @@ -120,14 +120,14 @@ public ASN1Primitive toASN1Primitive() for (int i = 0; i < h.length; i++) { - seqOfPSh.add(new ASN1Integer(h[i])); - seqOfPSw.add(new ASN1Integer(w[i])); - seqOfPSK.add(new ASN1Integer(k[i])); + seqOfPSh.add(ASN1Integer.valueOf(h[i])); + seqOfPSw.add(ASN1Integer.valueOf(w[i])); + seqOfPSK.add(ASN1Integer.valueOf(k[i])); } ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new ASN1Integer(t)); + v.add(ASN1Integer.valueOf(t)); v.add(new DERSequence(seqOfPSh)); v.add(new DERSequence(seqOfPSw)); v.add(new DERSequence(seqOfPSK)); diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/RainbowPrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/RainbowPrivateKey.java deleted file mode 100644 index e194699be1..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/RainbowPrivateKey.java +++ /dev/null @@ -1,349 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -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.legacy.crypto.rainbow.Layer; -import org.bouncycastle.pqc.legacy.crypto.rainbow.util.RainbowUtil; - -/** - * Return the key data to encode in the PrivateKeyInfo structure. - *

    - * The ASN.1 definition of the key structure is - *

    - *   RainbowPrivateKey ::= SEQUENCE {
    - *         CHOICE
    - *         {
    - *         oid        OBJECT IDENTIFIER         -- OID identifying the algorithm
    - *         version    INTEGER                    -- 0
    - *         }
    - *     A1inv      SEQUENCE OF OCTET STRING  -- inversed matrix of L1
    - *     b1         OCTET STRING              -- translation vector of L1
    - *     A2inv      SEQUENCE OF OCTET STRING  -- inversed matrix of L2
    - *     b2         OCTET STRING              -- translation vector of L2
    - *     vi         OCTET STRING              -- num of elmts in each Set S
    - *     layers     SEQUENCE OF Layer         -- layers of F
    - *   }
    - *
    - *   Layer             ::= SEQUENCE OF Poly
    - *
    - *   Poly              ::= SEQUENCE {
    - *     alpha      SEQUENCE OF OCTET STRING
    - *     beta       SEQUENCE OF OCTET STRING
    - *     gamma      OCTET STRING
    - *     eta        INTEGER
    - *   }
    - * 
    - */ -public class RainbowPrivateKey - extends ASN1Object -{ - private ASN1Integer version; - private ASN1ObjectIdentifier oid; - - private byte[][] invA1; - private byte[] b1; - private byte[][] invA2; - private byte[] b2; - private byte[] vi; - private Layer[] layers; - - private RainbowPrivateKey(ASN1Sequence seq) - { - // or version - if (seq.getObjectAt(0) instanceof ASN1Integer) - { - version = ASN1Integer.getInstance(seq.getObjectAt(0)); - } - else - { - oid = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); - } - - // - ASN1Sequence asnA1 = (ASN1Sequence)seq.getObjectAt(1); - invA1 = new byte[asnA1.size()][]; - for (int i = 0; i < asnA1.size(); i++) - { - invA1[i] = ((ASN1OctetString)asnA1.getObjectAt(i)).getOctets(); - } - - // - ASN1Sequence asnb1 = (ASN1Sequence)seq.getObjectAt(2); - b1 = ((ASN1OctetString)asnb1.getObjectAt(0)).getOctets(); - - // - ASN1Sequence asnA2 = (ASN1Sequence)seq.getObjectAt(3); - invA2 = new byte[asnA2.size()][]; - for (int j = 0; j < asnA2.size(); j++) - { - invA2[j] = ((ASN1OctetString)asnA2.getObjectAt(j)).getOctets(); - } - - // - ASN1Sequence asnb2 = (ASN1Sequence)seq.getObjectAt(4); - b2 = ((ASN1OctetString)asnb2.getObjectAt(0)).getOctets(); - - // - ASN1Sequence asnvi = (ASN1Sequence)seq.getObjectAt(5); - vi = ((ASN1OctetString)asnvi.getObjectAt(0)).getOctets(); - - // - ASN1Sequence asnLayers = (ASN1Sequence)seq.getObjectAt(6); - - byte[][][][] alphas = new byte[asnLayers.size()][][][]; - byte[][][][] betas = new byte[asnLayers.size()][][][]; - byte[][][] gammas = new byte[asnLayers.size()][][]; - byte[][] etas = new byte[asnLayers.size()][]; - // a layer: - for (int l = 0; l < asnLayers.size(); l++) - { - ASN1Sequence asnLayer = (ASN1Sequence)asnLayers.getObjectAt(l); - - // alphas (num of alpha-2d-array = oi) - ASN1Sequence alphas3d = (ASN1Sequence)asnLayer.getObjectAt(0); - alphas[l] = new byte[alphas3d.size()][][]; - for (int m = 0; m < alphas3d.size(); m++) - { - ASN1Sequence alphas2d = (ASN1Sequence)alphas3d.getObjectAt(m); - alphas[l][m] = new byte[alphas2d.size()][]; - for (int n = 0; n < alphas2d.size(); n++) - { - alphas[l][m][n] = ((ASN1OctetString)alphas2d.getObjectAt(n)).getOctets(); - } - } - - // betas .... - ASN1Sequence betas3d = (ASN1Sequence)asnLayer.getObjectAt(1); - betas[l] = new byte[betas3d.size()][][]; - for (int mb = 0; mb < betas3d.size(); mb++) - { - ASN1Sequence betas2d = (ASN1Sequence)betas3d.getObjectAt(mb); - betas[l][mb] = new byte[betas2d.size()][]; - for (int nb = 0; nb < betas2d.size(); nb++) - { - betas[l][mb][nb] = ((ASN1OctetString)betas2d.getObjectAt(nb)).getOctets(); - } - } - - // gammas ... - ASN1Sequence gammas2d = (ASN1Sequence)asnLayer.getObjectAt(2); - gammas[l] = new byte[gammas2d.size()][]; - for (int mg = 0; mg < gammas2d.size(); mg++) - { - gammas[l][mg] = ((ASN1OctetString)gammas2d.getObjectAt(mg)).getOctets(); - } - - // eta ... - etas[l] = ((ASN1OctetString)asnLayer.getObjectAt(3)).getOctets(); - } - - int numOfLayers = vi.length - 1; - this.layers = new Layer[numOfLayers]; - for (int i = 0; i < numOfLayers; i++) - { - Layer l = new Layer(vi[i], vi[i + 1], RainbowUtil.convertArray(alphas[i]), - RainbowUtil.convertArray(betas[i]), RainbowUtil.convertArray(gammas[i]), RainbowUtil.convertArray(etas[i])); - this.layers[i] = l; - - } - } - - public RainbowPrivateKey(short[][] invA1, short[] b1, short[][] invA2, - short[] b2, int[] vi, Layer[] layers) - { - this.version = new ASN1Integer(1); - this.invA1 = RainbowUtil.convertArray(invA1); - this.b1 = RainbowUtil.convertArray(b1); - this.invA2 = RainbowUtil.convertArray(invA2); - this.b2 = RainbowUtil.convertArray(b2); - this.vi = RainbowUtil.convertIntArray(vi); - this.layers = layers; - } - - public static RainbowPrivateKey getInstance(Object o) - { - if (o instanceof RainbowPrivateKey) - { - return (RainbowPrivateKey)o; - } - else if (o != null) - { - return new RainbowPrivateKey(ASN1Sequence.getInstance(o)); - } - - return null; - } - - public ASN1Integer getVersion() - { - return version; - } - - /** - * Getter for the inverse matrix of A1. - * - * @return the A1inv inverse - */ - public short[][] getInvA1() - { - return RainbowUtil.convertArray(invA1); - } - - /** - * Getter for the translation part of the private quadratic map L1. - * - * @return b1 the translation part of L1 - */ - public short[] getB1() - { - return RainbowUtil.convertArray(b1); - } - - /** - * Getter for the translation part of the private quadratic map L2. - * - * @return b2 the translation part of L2 - */ - public short[] getB2() - { - return RainbowUtil.convertArray(b2); - } - - /** - * Getter for the inverse matrix of A2 - * - * @return the A2inv - */ - public short[][] getInvA2() - { - return RainbowUtil.convertArray(invA2); - } - - /** - * Returns the layers contained in the private key - * - * @return layers - */ - public Layer[] getLayers() - { - return this.layers; - } - - /** - * Returns the array of vi-s - * - * @return the vi - */ - public int[] getVi() - { - return RainbowUtil.convertArraytoInt(vi); - } - - public ASN1Primitive toASN1Primitive() - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - // encode or version - if (version != null) - { - v.add(version); - } - else - { - v.add(oid); - } - - // encode - ASN1EncodableVector asnA1 = new ASN1EncodableVector(); - for (int i = 0; i < invA1.length; i++) - { - asnA1.add(new DEROctetString(invA1[i])); - } - v.add(new DERSequence(asnA1)); - - // encode - ASN1EncodableVector asnb1 = new ASN1EncodableVector(); - asnb1.add(new DEROctetString(b1)); - v.add(new DERSequence(asnb1)); - - // encode - ASN1EncodableVector asnA2 = new ASN1EncodableVector(); - for (int i = 0; i < invA2.length; i++) - { - asnA2.add(new DEROctetString(invA2[i])); - } - v.add(new DERSequence(asnA2)); - - // encode - ASN1EncodableVector asnb2 = new ASN1EncodableVector(); - asnb2.add(new DEROctetString(b2)); - v.add(new DERSequence(asnb2)); - - // encode - ASN1EncodableVector asnvi = new ASN1EncodableVector(); - asnvi.add(new DEROctetString(vi)); - v.add(new DERSequence(asnvi)); - - // encode - ASN1EncodableVector asnLayers = new ASN1EncodableVector(); - // a layer: - for (int l = 0; l < layers.length; l++) - { - ASN1EncodableVector aLayer = new ASN1EncodableVector(); - - // alphas (num of alpha-2d-array = oi) - byte[][][] alphas = RainbowUtil.convertArray(layers[l].getCoeffAlpha()); - ASN1EncodableVector alphas3d = new ASN1EncodableVector(); - for (int i = 0; i < alphas.length; i++) - { - ASN1EncodableVector alphas2d = new ASN1EncodableVector(); - for (int j = 0; j < alphas[i].length; j++) - { - alphas2d.add(new DEROctetString(alphas[i][j])); - } - alphas3d.add(new DERSequence(alphas2d)); - } - aLayer.add(new DERSequence(alphas3d)); - - // betas .... - byte[][][] betas = RainbowUtil.convertArray(layers[l].getCoeffBeta()); - ASN1EncodableVector betas3d = new ASN1EncodableVector(); - for (int i = 0; i < betas.length; i++) - { - ASN1EncodableVector betas2d = new ASN1EncodableVector(); - for (int j = 0; j < betas[i].length; j++) - { - betas2d.add(new DEROctetString(betas[i][j])); - } - betas3d.add(new DERSequence(betas2d)); - } - aLayer.add(new DERSequence(betas3d)); - - // gammas ... - byte[][] gammas = RainbowUtil.convertArray(layers[l].getCoeffGamma()); - ASN1EncodableVector asnG = new ASN1EncodableVector(); - for (int i = 0; i < gammas.length; i++) - { - asnG.add(new DEROctetString(gammas[i])); - } - aLayer.add(new DERSequence(asnG)); - - // eta - aLayer.add(new DEROctetString(RainbowUtil.convertArray(layers[l].getCoeffEta()))); - - // now, layer built up. add it! - asnLayers.add(new DERSequence(aLayer)); - } - - v.add(new DERSequence(asnLayers)); - - return new DERSequence(v); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/RainbowPublicKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/RainbowPublicKey.java deleted file mode 100644 index 0e36f91f23..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/RainbowPublicKey.java +++ /dev/null @@ -1,174 +0,0 @@ -package org.bouncycastle.pqc.asn1; - -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.legacy.crypto.rainbow.util.RainbowUtil; - -/** - * This class implements an ASN.1 encoded Rainbow public key. The ASN.1 definition - * of this structure is: - *
    - *       RainbowPublicKey ::= SEQUENCE {
    - *         CHOICE
    - *         {
    - *         oid        OBJECT IDENTIFIER         -- OID identifying the algorithm
    - *         version    INTEGER                    -- 0
    - *         }
    - *         docLength        Integer               -- length of the code
    - *         coeffquadratic   SEQUENCE OF OCTET STRING -- quadratic (mixed) coefficients
    - *         coeffsingular    SEQUENCE OF OCTET STRING -- singular coefficients
    - *         coeffscalar    SEQUENCE OF OCTET STRING -- scalar coefficients
    - *       }
    - * 
    - */ -public class RainbowPublicKey - extends ASN1Object -{ - private ASN1Integer version; - private ASN1ObjectIdentifier oid; - private ASN1Integer docLength; - private byte[][] coeffQuadratic; - private byte[][] coeffSingular; - private byte[] coeffScalar; - - private RainbowPublicKey(ASN1Sequence seq) - { - // or version - if (seq.getObjectAt(0) instanceof ASN1Integer) - { - version = ASN1Integer.getInstance(seq.getObjectAt(0)); - } - else - { - oid = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); - } - - docLength = ASN1Integer.getInstance(seq.getObjectAt(1)); - - ASN1Sequence asnCoeffQuad = ASN1Sequence.getInstance(seq.getObjectAt(2)); - coeffQuadratic = new byte[asnCoeffQuad.size()][]; - for (int quadSize = 0; quadSize < asnCoeffQuad.size(); quadSize++) - { - coeffQuadratic[quadSize] = ASN1OctetString.getInstance(asnCoeffQuad.getObjectAt(quadSize)).getOctets(); - } - - ASN1Sequence asnCoeffSing = (ASN1Sequence)seq.getObjectAt(3); - coeffSingular = new byte[asnCoeffSing.size()][]; - for (int singSize = 0; singSize < asnCoeffSing.size(); singSize++) - { - coeffSingular[singSize] = ASN1OctetString.getInstance(asnCoeffSing.getObjectAt(singSize)).getOctets(); - } - - ASN1Sequence asnCoeffScalar = (ASN1Sequence)seq.getObjectAt(4); - coeffScalar = ASN1OctetString.getInstance(asnCoeffScalar.getObjectAt(0)).getOctets(); - } - - public RainbowPublicKey(int docLength, short[][] coeffQuadratic, short[][] coeffSingular, short[] coeffScalar) - { - this.version = new ASN1Integer(0); - this.docLength = new ASN1Integer(docLength); - this.coeffQuadratic = RainbowUtil.convertArray(coeffQuadratic); - this.coeffSingular = RainbowUtil.convertArray(coeffSingular); - this.coeffScalar = RainbowUtil.convertArray(coeffScalar); - } - - public static RainbowPublicKey getInstance(Object o) - { - if (o instanceof RainbowPublicKey) - { - return (RainbowPublicKey)o; - } - else if (o != null) - { - return new RainbowPublicKey(ASN1Sequence.getInstance(o)); - } - - return null; - } - - public ASN1Integer getVersion() - { - return version; - } - - /** - * @return the docLength - */ - public int getDocLength() - { - return this.docLength.intValueExact(); - } - - /** - * @return the coeffquadratic - */ - public short[][] getCoeffQuadratic() - { - return RainbowUtil.convertArray(coeffQuadratic); - } - - /** - * @return the coeffsingular - */ - public short[][] getCoeffSingular() - { - return RainbowUtil.convertArray(coeffSingular); - } - - /** - * @return the coeffscalar - */ - public short[] getCoeffScalar() - { - return RainbowUtil.convertArray(coeffScalar); - } - - public ASN1Primitive toASN1Primitive() - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - // encode or version - if (version != null) - { - v.add(version); - } - else - { - v.add(oid); - } - - // encode - v.add(docLength); - - // encode - ASN1EncodableVector asnCoeffQuad = new ASN1EncodableVector(); - for (int i = 0; i < coeffQuadratic.length; i++) - { - asnCoeffQuad.add(new DEROctetString(coeffQuadratic[i])); - } - v.add(new DERSequence(asnCoeffQuad)); - - // encode - ASN1EncodableVector asnCoeffSing = new ASN1EncodableVector(); - for (int i = 0; i < coeffSingular.length; i++) - { - asnCoeffSing.add(new DEROctetString(coeffSingular[i])); - } - v.add(new DERSequence(asnCoeffSing)); - - // encode - ASN1EncodableVector asnCoeffScalar = new ASN1EncodableVector(); - asnCoeffScalar.add(new DEROctetString(coeffScalar)); - v.add(new DERSequence(asnCoeffScalar)); - - - return new DERSequence(v); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/SABERPrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/SABERPrivateKey.java index d964d2eb49..62bfd4d79f 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/SABERPrivateKey.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/SABERPrivateKey.java @@ -104,7 +104,7 @@ public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new ASN1Integer(version)); + v.add(ASN1Integer.valueOf(version)); v.add(new DEROctetString(z)); v.add(new DEROctetString(s)); //todo optinal pubkey diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/SPHINCS256KeyParams.java b/core/src/main/java/org/bouncycastle/pqc/asn1/SPHINCS256KeyParams.java index 77f32a3c03..e446406458 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/SPHINCS256KeyParams.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/SPHINCS256KeyParams.java @@ -16,7 +16,7 @@ public class SPHINCS256KeyParams public SPHINCS256KeyParams(AlgorithmIdentifier treeDigest) { - this.version = new ASN1Integer(0); + this.version = ASN1Integer.ZERO; this.treeDigest = treeDigest; } diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/SPHINCSPLUSPrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/SPHINCSPLUSPrivateKey.java index 3f86bbe1c3..50505aa7e0 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/SPHINCSPLUSPrivateKey.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/SPHINCSPLUSPrivateKey.java @@ -68,6 +68,7 @@ public SPHINCSPLUSPrivateKey(int version, byte[] skseed, byte[] skprf, SPHINCSPL /** * @deprecated use getInstance() */ + @Deprecated public SPHINCSPLUSPrivateKey(ASN1Sequence seq) { version = ASN1Integer.getInstance(seq.getObjectAt(0)).intValueExact(); @@ -90,7 +91,7 @@ public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new ASN1Integer(version)); + v.add(ASN1Integer.valueOf(version)); v.add(new DEROctetString(skseed)); v.add(new DEROctetString(skprf)); diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/SPHINCSPLUSPublicKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/SPHINCSPLUSPublicKey.java index d0514d6ffc..ac4cfb98a8 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/SPHINCSPLUSPublicKey.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/SPHINCSPLUSPublicKey.java @@ -1,6 +1,12 @@ package org.bouncycastle.pqc.asn1; -import org.bouncycastle.asn1.*; +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.util.Arrays; /** @@ -29,6 +35,7 @@ public SPHINCSPLUSPublicKey(byte[] pkseed, byte[] pkroot) /** * @deprecated use getInstance() */ + @Deprecated public SPHINCSPLUSPublicKey(ASN1Sequence seq) { pkseed = Arrays.clone(ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets()); diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSKeyParams.java b/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSKeyParams.java index d4a4f669da..b1e34dfac1 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSKeyParams.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSKeyParams.java @@ -27,7 +27,7 @@ public class XMSSKeyParams public XMSSKeyParams(int height, AlgorithmIdentifier treeDigest) { - this.version = new ASN1Integer(0); + this.version = ASN1Integer.ZERO; this.height = height; this.treeDigest = treeDigest; } @@ -68,7 +68,7 @@ public ASN1Primitive toASN1Primitive() ASN1EncodableVector v = new ASN1EncodableVector(); v.add(version); - v.add(new ASN1Integer(height)); + v.add(ASN1Integer.valueOf(height)); v.add(treeDigest); return new DERSequence(v); diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSMTKeyParams.java b/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSMTKeyParams.java index 02579a94b8..45a237564c 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSMTKeyParams.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSMTKeyParams.java @@ -29,7 +29,7 @@ public class XMSSMTKeyParams public XMSSMTKeyParams(int height, int layers, AlgorithmIdentifier treeDigest) { - this.version = new ASN1Integer(0); + this.version = ASN1Integer.ZERO; this.height = height; this.layers = layers; this.treeDigest = treeDigest; @@ -74,11 +74,11 @@ public AlgorithmIdentifier getTreeDigest() public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(version); - v.add(new ASN1Integer(height)); - v.add(new ASN1Integer(layers)); + v.add(ASN1Integer.valueOf(height)); + v.add(ASN1Integer.valueOf(layers)); v.add(treeDigest); return new DERSequence(v); diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSMTPrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSMTPrivateKey.java index a9f1ecbafe..72ffb892b3 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSMTPrivateKey.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSMTPrivateKey.java @@ -176,23 +176,23 @@ public ASN1Primitive toASN1Primitive() if (maxIndex >= 0) { - v.add(new ASN1Integer(1)); // version 1 + v.add(ASN1Integer.ONE); // version 1 } else { - v.add(new ASN1Integer(0)); // version 0 + v.add(ASN1Integer.ZERO); // version 0 } ASN1EncodableVector vK = new ASN1EncodableVector(); - vK.add(new ASN1Integer(index)); + vK.add(ASN1Integer.valueOf(index)); vK.add(new DEROctetString(secretKeySeed)); vK.add(new DEROctetString(secretKeyPRF)); vK.add(new DEROctetString(publicSeed)); vK.add(new DEROctetString(root)); if (maxIndex >= 0) { - vK.add(new DERTaggedObject(false, 0, new ASN1Integer(maxIndex))); + vK.add(new DERTaggedObject(false, 0, ASN1Integer.valueOf(maxIndex))); } v.add(new DERSequence(vK)); diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSMTPublicKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSMTPublicKey.java index 11ff2ec39a..5c6ab202f6 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSMTPublicKey.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSMTPublicKey.java @@ -68,9 +68,9 @@ public byte[] getRoot() public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); - v.add(new ASN1Integer(0)); // version + v.add(ASN1Integer.ZERO); // version v.add(new DEROctetString(publicSeed)); v.add(new DEROctetString(root)); diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSPrivateKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSPrivateKey.java index 94d2a6efa7..9107049ba7 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSPrivateKey.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSPrivateKey.java @@ -172,27 +172,27 @@ public byte[] getBdsState() public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); if (maxIndex >= 0) { - v.add(new ASN1Integer(1)); // version 1 + v.add(ASN1Integer.ONE); // version 1 } else { - v.add(new ASN1Integer(0)); // version 0 + v.add(ASN1Integer.ZERO); // version 0 } ASN1EncodableVector vK = new ASN1EncodableVector(); - vK.add(new ASN1Integer(index)); + vK.add(ASN1Integer.valueOf(index)); vK.add(new DEROctetString(secretKeySeed)); vK.add(new DEROctetString(secretKeyPRF)); vK.add(new DEROctetString(publicSeed)); vK.add(new DEROctetString(root)); if (maxIndex >= 0) { - vK.add(new DERTaggedObject(false, 0, new ASN1Integer(maxIndex))); + vK.add(new DERTaggedObject(false, 0, ASN1Integer.valueOf(maxIndex))); } v.add(new DERSequence(vK)); diff --git a/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSPublicKey.java b/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSPublicKey.java index ace4df9b0e..8885024240 100644 --- a/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSPublicKey.java +++ b/core/src/main/java/org/bouncycastle/pqc/asn1/XMSSPublicKey.java @@ -68,9 +68,9 @@ public byte[] getRoot() public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); - v.add(new ASN1Integer(0)); // version + v.add(ASN1Integer.ZERO); // version v.add(new DEROctetString(publicSeed)); v.add(new DEROctetString(root)); diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/MessageSignerAdapter.java b/core/src/main/java/org/bouncycastle/pqc/crypto/MessageSignerAdapter.java new file mode 100644 index 0000000000..539b79707e --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/MessageSignerAdapter.java @@ -0,0 +1,76 @@ +package org.bouncycastle.pqc.crypto; + +import java.io.ByteArrayOutputStream; + +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.Signer; +import org.bouncycastle.util.Arrays; + +public final class MessageSignerAdapter + implements Signer +{ + private final Buffer buffer = new Buffer(); + + private final MessageSigner messageSigner; + + public MessageSignerAdapter(MessageSigner messageSigner) + { + if (messageSigner == null) + { + throw new NullPointerException("'messageSigner' cannot be null"); + } + + this.messageSigner = messageSigner; + } + + public void init(boolean forSigning, CipherParameters param) + { + messageSigner.init(forSigning, param); + } + + public void update(byte b) + { + buffer.write(b); + } + + public void update(byte[] in, int off, int len) + { + buffer.write(in, off, len); + } + + public byte[] generateSignature() + { + return messageSigner.generateSignature(getMessage()); + } + + public boolean verifySignature(byte[] signature) + { + return messageSigner.verifySignature(getMessage(), signature); + } + + public void reset() + { + buffer.reset(); + } + + private byte[] getMessage() + { + try + { + return buffer.toByteArray(); + } + finally + { + reset(); + } + } + + private static final class Buffer extends ByteArrayOutputStream + { + public synchronized void reset() + { + Arrays.fill(buf, 0, count, (byte)0); + this.count = 0; + } + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/cmce/CMCEEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/cmce/CMCEEngine.java index 9940495dfc..57542358d5 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/cmce/CMCEEngine.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/cmce/CMCEEngine.java @@ -1049,7 +1049,7 @@ private static int ctz(long in) } /* Used in mov columns*/ - static private long same_mask64(short x, short y) + private static long same_mask64(short x, short y) { long mask; diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/cmce/CMCEPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/cmce/CMCEPrivateKeyParameters.java index 3d58131d00..7106d619df 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/cmce/CMCEPrivateKeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/cmce/CMCEPrivateKeyParameters.java @@ -39,9 +39,7 @@ public CMCEPrivateKeyParameters(CMCEParameters params, byte[] delta, byte[] C, b public byte[] reconstructPublicKey() { CMCEEngine engine = getParameters().getEngine(); - byte[] pk = new byte[engine.getPublicKeySize()]; - engine.generate_public_key_from_private_key(privateKey); - return pk; + return engine.generate_public_key_from_private_key(privateKey); } public byte[] getEncoded() diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/dilithium/DilithiumParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/dilithium/DilithiumParameters.java index b64cc82ab5..97843ecac0 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/dilithium/DilithiumParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/dilithium/DilithiumParameters.java @@ -15,6 +15,7 @@ public class DilithiumParameters * @deprecated * obsolete to be removed */ + @Deprecated private final boolean usingAES;// or shake private DilithiumParameters(String name, int k, boolean usingAES) diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/dilithium/DilithiumPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/dilithium/DilithiumPrivateKeyParameters.java index 4193d654b8..66a4a3af98 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/dilithium/DilithiumPrivateKeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/dilithium/DilithiumPrivateKeyParameters.java @@ -63,6 +63,8 @@ public byte[] getK() } /** @deprecated Use {@link #getEncoded()} instead. */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public byte[] getPrivateKey() { return getEncoded(); diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/dilithium/Poly.java b/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/dilithium/Poly.java index 62d6a753ce..e4d0321d1e 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/dilithium/Poly.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/dilithium/Poly.java @@ -786,7 +786,7 @@ public void shiftLeft() public String toString() { - StringBuffer out = new StringBuffer(); + StringBuilder out = new StringBuilder(); out.append("["); for (int i = 0; i < coeffs.length; i++) { diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/ComplexNumberWrapper.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/ComplexNumberWrapper.java deleted file mode 100644 index f3a9345381..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/ComplexNumberWrapper.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.bouncycastle.pqc.crypto.falcon; - -class ComplexNumberWrapper -{ - FalconFPR re; - FalconFPR im; - - ComplexNumberWrapper(FalconFPR re, FalconFPR im) - { - this.re = re; - this.im = im; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FPREngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FPREngine.java index f90b25f456..37906426d1 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FPREngine.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FPREngine.java @@ -2,1144 +2,1136 @@ class FPREngine { - private static final FalconFPR[] inv_sigma; - private static final FalconFPR[] sigma_min; - private static final FalconFPR[] gm_tab; - private static final FalconFPR[] p2_tab; +// static final double[] inv_sigma; +// static final double[] sigma_min; +// static final double[] gm_tab; +// static final double[] p2_tab; static { - inv_sigma = new FalconFPR[]{ - new FalconFPR(0.0), /* unused */ - new FalconFPR(0.0069054793295940891952143765991630516), - new FalconFPR(0.0068102267767177975961393730687908629), - new FalconFPR(0.0067188101910722710707826117910434131), - new FalconFPR(0.0065883354370073665545865037227681924), - new FalconFPR(0.0064651781207602900738053897763485516), - new FalconFPR(0.0063486788828078995327741182928037856), - new FalconFPR(0.0062382586529084374473367528433697537), - new FalconFPR(0.0061334065020930261548984001431770281), - new FalconFPR(0.0060336696681577241031668062510953022), - new FalconFPR(0.0059386453095331159950250124336477482) + fpr_inv_sigma = new double[]{ + 0.0, /* unused */ + 0.0069054793295940891952143765991630516, + 0.0068102267767177975961393730687908629, + 0.0067188101910722710707826117910434131, + 0.0065883354370073665545865037227681924, + 0.0064651781207602900738053897763485516, + 0.0063486788828078995327741182928037856, + 0.0062382586529084374473367528433697537, + 0.0061334065020930261548984001431770281, + 0.0060336696681577241031668062510953022, + 0.0059386453095331159950250124336477482 }; - sigma_min = new FalconFPR[]{ - new FalconFPR(0.0), /* unused */ - new FalconFPR(1.1165085072329102588881898380334015), - new FalconFPR(1.1321247692325272405718031785357108), - new FalconFPR(1.1475285353733668684571123112513188), - new FalconFPR(1.1702540788534828939713084716509250), - new FalconFPR(1.1925466358390344011122170489094133), - new FalconFPR(1.2144300507766139921088487776957699), - new FalconFPR(1.2359260567719808790104525941706723), - new FalconFPR(1.2570545284063214162779743112075080), - new FalconFPR(1.2778336969128335860256340575729042), - new FalconFPR(1.2982803343442918539708792538826807) + fpr_sigma_min = new double[]{ + 0.0, /* unused */ + 1.1165085072329102588881898380334015, + 1.1321247692325272405718031785357108, + 1.1475285353733668684571123112513188, + 1.1702540788534828939713084716509250, + 1.1925466358390344011122170489094133, + 1.2144300507766139921088487776957699, + 1.2359260567719808790104525941706723, + 1.2570545284063214162779743112075080, + 1.2778336969128335860256340575729042, + 1.2982803343442918539708792538826807 }; - gm_tab = new FalconFPR[]{ - new FalconFPR(0), new FalconFPR(0), /* unused */ - new FalconFPR(-0.000000000000000000000000000), new FalconFPR(1.000000000000000000000000000), - new FalconFPR(0.707106781186547524400844362), new FalconFPR(0.707106781186547524400844362), - new FalconFPR(-0.707106781186547524400844362), new FalconFPR(0.707106781186547524400844362), - new FalconFPR(0.923879532511286756128183189), new FalconFPR(0.382683432365089771728459984), - new FalconFPR(-0.382683432365089771728459984), new FalconFPR(0.923879532511286756128183189), - new FalconFPR(0.382683432365089771728459984), new FalconFPR(0.923879532511286756128183189), - new FalconFPR(-0.923879532511286756128183189), new FalconFPR(0.382683432365089771728459984), - new FalconFPR(0.980785280403230449126182236), new FalconFPR(0.195090322016128267848284868), - new FalconFPR(-0.195090322016128267848284868), new FalconFPR(0.980785280403230449126182236), - new FalconFPR(0.555570233019602224742830814), new FalconFPR(0.831469612302545237078788378), - new FalconFPR(-0.831469612302545237078788378), new FalconFPR(0.555570233019602224742830814), - new FalconFPR(0.831469612302545237078788378), new FalconFPR(0.555570233019602224742830814), - new FalconFPR(-0.555570233019602224742830814), new FalconFPR(0.831469612302545237078788378), - new FalconFPR(0.195090322016128267848284868), new FalconFPR(0.980785280403230449126182236), - new FalconFPR(-0.980785280403230449126182236), new FalconFPR(0.195090322016128267848284868), - new FalconFPR(0.995184726672196886244836953), new FalconFPR(0.098017140329560601994195564), - new FalconFPR(-0.098017140329560601994195564), new FalconFPR(0.995184726672196886244836953), - new FalconFPR(0.634393284163645498215171613), new FalconFPR(0.773010453362736960810906610), - new FalconFPR(-0.773010453362736960810906610), new FalconFPR(0.634393284163645498215171613), - new FalconFPR(0.881921264348355029712756864), new FalconFPR(0.471396736825997648556387626), - new FalconFPR(-0.471396736825997648556387626), new FalconFPR(0.881921264348355029712756864), - new FalconFPR(0.290284677254462367636192376), new FalconFPR(0.956940335732208864935797887), - new FalconFPR(-0.956940335732208864935797887), new FalconFPR(0.290284677254462367636192376), - new FalconFPR(0.956940335732208864935797887), new FalconFPR(0.290284677254462367636192376), - new FalconFPR(-0.290284677254462367636192376), new FalconFPR(0.956940335732208864935797887), - new FalconFPR(0.471396736825997648556387626), new FalconFPR(0.881921264348355029712756864), - new FalconFPR(-0.881921264348355029712756864), new FalconFPR(0.471396736825997648556387626), - new FalconFPR(0.773010453362736960810906610), new FalconFPR(0.634393284163645498215171613), - new FalconFPR(-0.634393284163645498215171613), new FalconFPR(0.773010453362736960810906610), - new FalconFPR(0.098017140329560601994195564), new FalconFPR(0.995184726672196886244836953), - new FalconFPR(-0.995184726672196886244836953), new FalconFPR(0.098017140329560601994195564), - new FalconFPR(0.998795456205172392714771605), new FalconFPR(0.049067674327418014254954977), - new FalconFPR(-0.049067674327418014254954977), new FalconFPR(0.998795456205172392714771605), - new FalconFPR(0.671558954847018400625376850), new FalconFPR(0.740951125354959091175616897), - new FalconFPR(-0.740951125354959091175616897), new FalconFPR(0.671558954847018400625376850), - new FalconFPR(0.903989293123443331586200297), new FalconFPR(0.427555093430282094320966857), - new FalconFPR(-0.427555093430282094320966857), new FalconFPR(0.903989293123443331586200297), - new FalconFPR(0.336889853392220050689253213), new FalconFPR(0.941544065183020778412509403), - new FalconFPR(-0.941544065183020778412509403), new FalconFPR(0.336889853392220050689253213), - new FalconFPR(0.970031253194543992603984207), new FalconFPR(0.242980179903263889948274162), - new FalconFPR(-0.242980179903263889948274162), new FalconFPR(0.970031253194543992603984207), - new FalconFPR(0.514102744193221726593693839), new FalconFPR(0.857728610000272069902269984), - new FalconFPR(-0.857728610000272069902269984), new FalconFPR(0.514102744193221726593693839), - new FalconFPR(0.803207531480644909806676513), new FalconFPR(0.595699304492433343467036529), - new FalconFPR(-0.595699304492433343467036529), new FalconFPR(0.803207531480644909806676513), - new FalconFPR(0.146730474455361751658850130), new FalconFPR(0.989176509964780973451673738), - new FalconFPR(-0.989176509964780973451673738), new FalconFPR(0.146730474455361751658850130), - new FalconFPR(0.989176509964780973451673738), new FalconFPR(0.146730474455361751658850130), - new FalconFPR(-0.146730474455361751658850130), new FalconFPR(0.989176509964780973451673738), - new FalconFPR(0.595699304492433343467036529), new FalconFPR(0.803207531480644909806676513), - new FalconFPR(-0.803207531480644909806676513), new FalconFPR(0.595699304492433343467036529), - new FalconFPR(0.857728610000272069902269984), new FalconFPR(0.514102744193221726593693839), - new FalconFPR(-0.514102744193221726593693839), new FalconFPR(0.857728610000272069902269984), - new FalconFPR(0.242980179903263889948274162), new FalconFPR(0.970031253194543992603984207), - new FalconFPR(-0.970031253194543992603984207), new FalconFPR(0.242980179903263889948274162), - new FalconFPR(0.941544065183020778412509403), new FalconFPR(0.336889853392220050689253213), - new FalconFPR(-0.336889853392220050689253213), new FalconFPR(0.941544065183020778412509403), - new FalconFPR(0.427555093430282094320966857), new FalconFPR(0.903989293123443331586200297), - new FalconFPR(-0.903989293123443331586200297), new FalconFPR(0.427555093430282094320966857), - new FalconFPR(0.740951125354959091175616897), new FalconFPR(0.671558954847018400625376850), - new FalconFPR(-0.671558954847018400625376850), new FalconFPR(0.740951125354959091175616897), - new FalconFPR(0.049067674327418014254954977), new FalconFPR(0.998795456205172392714771605), - new FalconFPR(-0.998795456205172392714771605), new FalconFPR(0.049067674327418014254954977), - new FalconFPR(0.999698818696204220115765650), new FalconFPR(0.024541228522912288031734529), - new FalconFPR(-0.024541228522912288031734529), new FalconFPR(0.999698818696204220115765650), - new FalconFPR(0.689540544737066924616730630), new FalconFPR(0.724247082951466920941069243), - new FalconFPR(-0.724247082951466920941069243), new FalconFPR(0.689540544737066924616730630), - new FalconFPR(0.914209755703530654635014829), new FalconFPR(0.405241314004989870908481306), - new FalconFPR(-0.405241314004989870908481306), new FalconFPR(0.914209755703530654635014829), - new FalconFPR(0.359895036534988148775104572), new FalconFPR(0.932992798834738887711660256), - new FalconFPR(-0.932992798834738887711660256), new FalconFPR(0.359895036534988148775104572), - new FalconFPR(0.975702130038528544460395766), new FalconFPR(0.219101240156869797227737547), - new FalconFPR(-0.219101240156869797227737547), new FalconFPR(0.975702130038528544460395766), - new FalconFPR(0.534997619887097210663076905), new FalconFPR(0.844853565249707073259571205), - new FalconFPR(-0.844853565249707073259571205), new FalconFPR(0.534997619887097210663076905), - new FalconFPR(0.817584813151583696504920884), new FalconFPR(0.575808191417845300745972454), - new FalconFPR(-0.575808191417845300745972454), new FalconFPR(0.817584813151583696504920884), - new FalconFPR(0.170961888760301226363642357), new FalconFPR(0.985277642388941244774018433), - new FalconFPR(-0.985277642388941244774018433), new FalconFPR(0.170961888760301226363642357), - new FalconFPR(0.992479534598709998156767252), new FalconFPR(0.122410675199216198498704474), - new FalconFPR(-0.122410675199216198498704474), new FalconFPR(0.992479534598709998156767252), - new FalconFPR(0.615231590580626845484913563), new FalconFPR(0.788346427626606262009164705), - new FalconFPR(-0.788346427626606262009164705), new FalconFPR(0.615231590580626845484913563), - new FalconFPR(0.870086991108711418652292404), new FalconFPR(0.492898192229784036873026689), - new FalconFPR(-0.492898192229784036873026689), new FalconFPR(0.870086991108711418652292404), - new FalconFPR(0.266712757474898386325286515), new FalconFPR(0.963776065795439866686464356), - new FalconFPR(-0.963776065795439866686464356), new FalconFPR(0.266712757474898386325286515), - new FalconFPR(0.949528180593036667195936074), new FalconFPR(0.313681740398891476656478846), - new FalconFPR(-0.313681740398891476656478846), new FalconFPR(0.949528180593036667195936074), - new FalconFPR(0.449611329654606600046294579), new FalconFPR(0.893224301195515320342416447), - new FalconFPR(-0.893224301195515320342416447), new FalconFPR(0.449611329654606600046294579), - new FalconFPR(0.757208846506484547575464054), new FalconFPR(0.653172842953776764084203014), - new FalconFPR(-0.653172842953776764084203014), new FalconFPR(0.757208846506484547575464054), - new FalconFPR(0.073564563599667423529465622), new FalconFPR(0.997290456678690216135597140), - new FalconFPR(-0.997290456678690216135597140), new FalconFPR(0.073564563599667423529465622), - new FalconFPR(0.997290456678690216135597140), new FalconFPR(0.073564563599667423529465622), - new FalconFPR(-0.073564563599667423529465622), new FalconFPR(0.997290456678690216135597140), - new FalconFPR(0.653172842953776764084203014), new FalconFPR(0.757208846506484547575464054), - new FalconFPR(-0.757208846506484547575464054), new FalconFPR(0.653172842953776764084203014), - new FalconFPR(0.893224301195515320342416447), new FalconFPR(0.449611329654606600046294579), - new FalconFPR(-0.449611329654606600046294579), new FalconFPR(0.893224301195515320342416447), - new FalconFPR(0.313681740398891476656478846), new FalconFPR(0.949528180593036667195936074), - new FalconFPR(-0.949528180593036667195936074), new FalconFPR(0.313681740398891476656478846), - new FalconFPR(0.963776065795439866686464356), new FalconFPR(0.266712757474898386325286515), - new FalconFPR(-0.266712757474898386325286515), new FalconFPR(0.963776065795439866686464356), - new FalconFPR(0.492898192229784036873026689), new FalconFPR(0.870086991108711418652292404), - new FalconFPR(-0.870086991108711418652292404), new FalconFPR(0.492898192229784036873026689), - new FalconFPR(0.788346427626606262009164705), new FalconFPR(0.615231590580626845484913563), - new FalconFPR(-0.615231590580626845484913563), new FalconFPR(0.788346427626606262009164705), - new FalconFPR(0.122410675199216198498704474), new FalconFPR(0.992479534598709998156767252), - new FalconFPR(-0.992479534598709998156767252), new FalconFPR(0.122410675199216198498704474), - new FalconFPR(0.985277642388941244774018433), new FalconFPR(0.170961888760301226363642357), - new FalconFPR(-0.170961888760301226363642357), new FalconFPR(0.985277642388941244774018433), - new FalconFPR(0.575808191417845300745972454), new FalconFPR(0.817584813151583696504920884), - new FalconFPR(-0.817584813151583696504920884), new FalconFPR(0.575808191417845300745972454), - new FalconFPR(0.844853565249707073259571205), new FalconFPR(0.534997619887097210663076905), - new FalconFPR(-0.534997619887097210663076905), new FalconFPR(0.844853565249707073259571205), - new FalconFPR(0.219101240156869797227737547), new FalconFPR(0.975702130038528544460395766), - new FalconFPR(-0.975702130038528544460395766), new FalconFPR(0.219101240156869797227737547), - new FalconFPR(0.932992798834738887711660256), new FalconFPR(0.359895036534988148775104572), - new FalconFPR(-0.359895036534988148775104572), new FalconFPR(0.932992798834738887711660256), - new FalconFPR(0.405241314004989870908481306), new FalconFPR(0.914209755703530654635014829), - new FalconFPR(-0.914209755703530654635014829), new FalconFPR(0.405241314004989870908481306), - new FalconFPR(0.724247082951466920941069243), new FalconFPR(0.689540544737066924616730630), - new FalconFPR(-0.689540544737066924616730630), new FalconFPR(0.724247082951466920941069243), - new FalconFPR(0.024541228522912288031734529), new FalconFPR(0.999698818696204220115765650), - new FalconFPR(-0.999698818696204220115765650), new FalconFPR(0.024541228522912288031734529), - new FalconFPR(0.999924701839144540921646491), new FalconFPR(0.012271538285719926079408262), - new FalconFPR(-0.012271538285719926079408262), new FalconFPR(0.999924701839144540921646491), - new FalconFPR(0.698376249408972853554813503), new FalconFPR(0.715730825283818654125532623), - new FalconFPR(-0.715730825283818654125532623), new FalconFPR(0.698376249408972853554813503), - new FalconFPR(0.919113851690057743908477789), new FalconFPR(0.393992040061048108596188661), - new FalconFPR(-0.393992040061048108596188661), new FalconFPR(0.919113851690057743908477789), - new FalconFPR(0.371317193951837543411934967), new FalconFPR(0.928506080473215565937167396), - new FalconFPR(-0.928506080473215565937167396), new FalconFPR(0.371317193951837543411934967), - new FalconFPR(0.978317370719627633106240097), new FalconFPR(0.207111376192218549708116020), - new FalconFPR(-0.207111376192218549708116020), new FalconFPR(0.978317370719627633106240097), - new FalconFPR(0.545324988422046422313987347), new FalconFPR(0.838224705554838043186996856), - new FalconFPR(-0.838224705554838043186996856), new FalconFPR(0.545324988422046422313987347), - new FalconFPR(0.824589302785025264474803737), new FalconFPR(0.565731810783613197389765011), - new FalconFPR(-0.565731810783613197389765011), new FalconFPR(0.824589302785025264474803737), - new FalconFPR(0.183039887955140958516532578), new FalconFPR(0.983105487431216327180301155), - new FalconFPR(-0.983105487431216327180301155), new FalconFPR(0.183039887955140958516532578), - new FalconFPR(0.993906970002356041546922813), new FalconFPR(0.110222207293883058807899140), - new FalconFPR(-0.110222207293883058807899140), new FalconFPR(0.993906970002356041546922813), - new FalconFPR(0.624859488142386377084072816), new FalconFPR(0.780737228572094478301588484), - new FalconFPR(-0.780737228572094478301588484), new FalconFPR(0.624859488142386377084072816), - new FalconFPR(0.876070094195406607095844268), new FalconFPR(0.482183772079122748517344481), - new FalconFPR(-0.482183772079122748517344481), new FalconFPR(0.876070094195406607095844268), - new FalconFPR(0.278519689385053105207848526), new FalconFPR(0.960430519415565811199035138), - new FalconFPR(-0.960430519415565811199035138), new FalconFPR(0.278519689385053105207848526), - new FalconFPR(0.953306040354193836916740383), new FalconFPR(0.302005949319228067003463232), - new FalconFPR(-0.302005949319228067003463232), new FalconFPR(0.953306040354193836916740383), - new FalconFPR(0.460538710958240023633181487), new FalconFPR(0.887639620402853947760181617), - new FalconFPR(-0.887639620402853947760181617), new FalconFPR(0.460538710958240023633181487), - new FalconFPR(0.765167265622458925888815999), new FalconFPR(0.643831542889791465068086063), - new FalconFPR(-0.643831542889791465068086063), new FalconFPR(0.765167265622458925888815999), - new FalconFPR(0.085797312344439890461556332), new FalconFPR(0.996312612182778012627226190), - new FalconFPR(-0.996312612182778012627226190), new FalconFPR(0.085797312344439890461556332), - new FalconFPR(0.998118112900149207125155861), new FalconFPR(0.061320736302208577782614593), - new FalconFPR(-0.061320736302208577782614593), new FalconFPR(0.998118112900149207125155861), - new FalconFPR(0.662415777590171761113069817), new FalconFPR(0.749136394523459325469203257), - new FalconFPR(-0.749136394523459325469203257), new FalconFPR(0.662415777590171761113069817), - new FalconFPR(0.898674465693953843041976744), new FalconFPR(0.438616238538527637647025738), - new FalconFPR(-0.438616238538527637647025738), new FalconFPR(0.898674465693953843041976744), - new FalconFPR(0.325310292162262934135954708), new FalconFPR(0.945607325380521325730945387), - new FalconFPR(-0.945607325380521325730945387), new FalconFPR(0.325310292162262934135954708), - new FalconFPR(0.966976471044852109087220226), new FalconFPR(0.254865659604514571553980779), - new FalconFPR(-0.254865659604514571553980779), new FalconFPR(0.966976471044852109087220226), - new FalconFPR(0.503538383725717558691867071), new FalconFPR(0.863972856121586737918147054), - new FalconFPR(-0.863972856121586737918147054), new FalconFPR(0.503538383725717558691867071), - new FalconFPR(0.795836904608883536262791915), new FalconFPR(0.605511041404325513920626941), - new FalconFPR(-0.605511041404325513920626941), new FalconFPR(0.795836904608883536262791915), - new FalconFPR(0.134580708507126186316358409), new FalconFPR(0.990902635427780025108237011), - new FalconFPR(-0.990902635427780025108237011), new FalconFPR(0.134580708507126186316358409), - new FalconFPR(0.987301418157858382399815802), new FalconFPR(0.158858143333861441684385360), - new FalconFPR(-0.158858143333861441684385360), new FalconFPR(0.987301418157858382399815802), - new FalconFPR(0.585797857456438860328080838), new FalconFPR(0.810457198252594791726703434), - new FalconFPR(-0.810457198252594791726703434), new FalconFPR(0.585797857456438860328080838), - new FalconFPR(0.851355193105265142261290312), new FalconFPR(0.524589682678468906215098464), - new FalconFPR(-0.524589682678468906215098464), new FalconFPR(0.851355193105265142261290312), - new FalconFPR(0.231058108280671119643236018), new FalconFPR(0.972939952205560145467720114), - new FalconFPR(-0.972939952205560145467720114), new FalconFPR(0.231058108280671119643236018), - new FalconFPR(0.937339011912574923201899593), new FalconFPR(0.348418680249434568419308588), - new FalconFPR(-0.348418680249434568419308588), new FalconFPR(0.937339011912574923201899593), - new FalconFPR(0.416429560097637182562598911), new FalconFPR(0.909167983090522376563884788), - new FalconFPR(-0.909167983090522376563884788), new FalconFPR(0.416429560097637182562598911), - new FalconFPR(0.732654271672412834615546649), new FalconFPR(0.680600997795453050594430464), - new FalconFPR(-0.680600997795453050594430464), new FalconFPR(0.732654271672412834615546649), - new FalconFPR(0.036807222941358832324332691), new FalconFPR(0.999322384588349500896221011), - new FalconFPR(-0.999322384588349500896221011), new FalconFPR(0.036807222941358832324332691), - new FalconFPR(0.999322384588349500896221011), new FalconFPR(0.036807222941358832324332691), - new FalconFPR(-0.036807222941358832324332691), new FalconFPR(0.999322384588349500896221011), - new FalconFPR(0.680600997795453050594430464), new FalconFPR(0.732654271672412834615546649), - new FalconFPR(-0.732654271672412834615546649), new FalconFPR(0.680600997795453050594430464), - new FalconFPR(0.909167983090522376563884788), new FalconFPR(0.416429560097637182562598911), - new FalconFPR(-0.416429560097637182562598911), new FalconFPR(0.909167983090522376563884788), - new FalconFPR(0.348418680249434568419308588), new FalconFPR(0.937339011912574923201899593), - new FalconFPR(-0.937339011912574923201899593), new FalconFPR(0.348418680249434568419308588), - new FalconFPR(0.972939952205560145467720114), new FalconFPR(0.231058108280671119643236018), - new FalconFPR(-0.231058108280671119643236018), new FalconFPR(0.972939952205560145467720114), - new FalconFPR(0.524589682678468906215098464), new FalconFPR(0.851355193105265142261290312), - new FalconFPR(-0.851355193105265142261290312), new FalconFPR(0.524589682678468906215098464), - new FalconFPR(0.810457198252594791726703434), new FalconFPR(0.585797857456438860328080838), - new FalconFPR(-0.585797857456438860328080838), new FalconFPR(0.810457198252594791726703434), - new FalconFPR(0.158858143333861441684385360), new FalconFPR(0.987301418157858382399815802), - new FalconFPR(-0.987301418157858382399815802), new FalconFPR(0.158858143333861441684385360), - new FalconFPR(0.990902635427780025108237011), new FalconFPR(0.134580708507126186316358409), - new FalconFPR(-0.134580708507126186316358409), new FalconFPR(0.990902635427780025108237011), - new FalconFPR(0.605511041404325513920626941), new FalconFPR(0.795836904608883536262791915), - new FalconFPR(-0.795836904608883536262791915), new FalconFPR(0.605511041404325513920626941), - new FalconFPR(0.863972856121586737918147054), new FalconFPR(0.503538383725717558691867071), - new FalconFPR(-0.503538383725717558691867071), new FalconFPR(0.863972856121586737918147054), - new FalconFPR(0.254865659604514571553980779), new FalconFPR(0.966976471044852109087220226), - new FalconFPR(-0.966976471044852109087220226), new FalconFPR(0.254865659604514571553980779), - new FalconFPR(0.945607325380521325730945387), new FalconFPR(0.325310292162262934135954708), - new FalconFPR(-0.325310292162262934135954708), new FalconFPR(0.945607325380521325730945387), - new FalconFPR(0.438616238538527637647025738), new FalconFPR(0.898674465693953843041976744), - new FalconFPR(-0.898674465693953843041976744), new FalconFPR(0.438616238538527637647025738), - new FalconFPR(0.749136394523459325469203257), new FalconFPR(0.662415777590171761113069817), - new FalconFPR(-0.662415777590171761113069817), new FalconFPR(0.749136394523459325469203257), - new FalconFPR(0.061320736302208577782614593), new FalconFPR(0.998118112900149207125155861), - new FalconFPR(-0.998118112900149207125155861), new FalconFPR(0.061320736302208577782614593), - new FalconFPR(0.996312612182778012627226190), new FalconFPR(0.085797312344439890461556332), - new FalconFPR(-0.085797312344439890461556332), new FalconFPR(0.996312612182778012627226190), - new FalconFPR(0.643831542889791465068086063), new FalconFPR(0.765167265622458925888815999), - new FalconFPR(-0.765167265622458925888815999), new FalconFPR(0.643831542889791465068086063), - new FalconFPR(0.887639620402853947760181617), new FalconFPR(0.460538710958240023633181487), - new FalconFPR(-0.460538710958240023633181487), new FalconFPR(0.887639620402853947760181617), - new FalconFPR(0.302005949319228067003463232), new FalconFPR(0.953306040354193836916740383), - new FalconFPR(-0.953306040354193836916740383), new FalconFPR(0.302005949319228067003463232), - new FalconFPR(0.960430519415565811199035138), new FalconFPR(0.278519689385053105207848526), - new FalconFPR(-0.278519689385053105207848526), new FalconFPR(0.960430519415565811199035138), - new FalconFPR(0.482183772079122748517344481), new FalconFPR(0.876070094195406607095844268), - new FalconFPR(-0.876070094195406607095844268), new FalconFPR(0.482183772079122748517344481), - new FalconFPR(0.780737228572094478301588484), new FalconFPR(0.624859488142386377084072816), - new FalconFPR(-0.624859488142386377084072816), new FalconFPR(0.780737228572094478301588484), - new FalconFPR(0.110222207293883058807899140), new FalconFPR(0.993906970002356041546922813), - new FalconFPR(-0.993906970002356041546922813), new FalconFPR(0.110222207293883058807899140), - new FalconFPR(0.983105487431216327180301155), new FalconFPR(0.183039887955140958516532578), - new FalconFPR(-0.183039887955140958516532578), new FalconFPR(0.983105487431216327180301155), - new FalconFPR(0.565731810783613197389765011), new FalconFPR(0.824589302785025264474803737), - new FalconFPR(-0.824589302785025264474803737), new FalconFPR(0.565731810783613197389765011), - new FalconFPR(0.838224705554838043186996856), new FalconFPR(0.545324988422046422313987347), - new FalconFPR(-0.545324988422046422313987347), new FalconFPR(0.838224705554838043186996856), - new FalconFPR(0.207111376192218549708116020), new FalconFPR(0.978317370719627633106240097), - new FalconFPR(-0.978317370719627633106240097), new FalconFPR(0.207111376192218549708116020), - new FalconFPR(0.928506080473215565937167396), new FalconFPR(0.371317193951837543411934967), - new FalconFPR(-0.371317193951837543411934967), new FalconFPR(0.928506080473215565937167396), - new FalconFPR(0.393992040061048108596188661), new FalconFPR(0.919113851690057743908477789), - new FalconFPR(-0.919113851690057743908477789), new FalconFPR(0.393992040061048108596188661), - new FalconFPR(0.715730825283818654125532623), new FalconFPR(0.698376249408972853554813503), - new FalconFPR(-0.698376249408972853554813503), new FalconFPR(0.715730825283818654125532623), - new FalconFPR(0.012271538285719926079408262), new FalconFPR(0.999924701839144540921646491), - new FalconFPR(-0.999924701839144540921646491), new FalconFPR(0.012271538285719926079408262), - new FalconFPR(0.999981175282601142656990438), new FalconFPR(0.006135884649154475359640235), - new FalconFPR(-0.006135884649154475359640235), new FalconFPR(0.999981175282601142656990438), - new FalconFPR(0.702754744457225302452914421), new FalconFPR(0.711432195745216441522130290), - new FalconFPR(-0.711432195745216441522130290), new FalconFPR(0.702754744457225302452914421), - new FalconFPR(0.921514039342041943465396332), new FalconFPR(0.388345046698826291624993541), - new FalconFPR(-0.388345046698826291624993541), new FalconFPR(0.921514039342041943465396332), - new FalconFPR(0.377007410216418256726567823), new FalconFPR(0.926210242138311341974793388), - new FalconFPR(-0.926210242138311341974793388), new FalconFPR(0.377007410216418256726567823), - new FalconFPR(0.979569765685440534439326110), new FalconFPR(0.201104634842091911558443546), - new FalconFPR(-0.201104634842091911558443546), new FalconFPR(0.979569765685440534439326110), - new FalconFPR(0.550457972936604802977289893), new FalconFPR(0.834862874986380056304401383), - new FalconFPR(-0.834862874986380056304401383), new FalconFPR(0.550457972936604802977289893), - new FalconFPR(0.828045045257755752067527592), new FalconFPR(0.560661576197336023839710223), - new FalconFPR(-0.560661576197336023839710223), new FalconFPR(0.828045045257755752067527592), - new FalconFPR(0.189068664149806212754997837), new FalconFPR(0.981963869109555264072848154), - new FalconFPR(-0.981963869109555264072848154), new FalconFPR(0.189068664149806212754997837), - new FalconFPR(0.994564570734255452119106243), new FalconFPR(0.104121633872054579120943880), - new FalconFPR(-0.104121633872054579120943880), new FalconFPR(0.994564570734255452119106243), - new FalconFPR(0.629638238914927025372981341), new FalconFPR(0.776888465673232450040827983), - new FalconFPR(-0.776888465673232450040827983), new FalconFPR(0.629638238914927025372981341), - new FalconFPR(0.879012226428633477831323711), new FalconFPR(0.476799230063322133342158117), - new FalconFPR(-0.476799230063322133342158117), new FalconFPR(0.879012226428633477831323711), - new FalconFPR(0.284407537211271843618310615), new FalconFPR(0.958703474895871555374645792), - new FalconFPR(-0.958703474895871555374645792), new FalconFPR(0.284407537211271843618310615), - new FalconFPR(0.955141168305770721498157712), new FalconFPR(0.296150888243623824121786128), - new FalconFPR(-0.296150888243623824121786128), new FalconFPR(0.955141168305770721498157712), - new FalconFPR(0.465976495767966177902756065), new FalconFPR(0.884797098430937780104007041), - new FalconFPR(-0.884797098430937780104007041), new FalconFPR(0.465976495767966177902756065), - new FalconFPR(0.769103337645579639346626069), new FalconFPR(0.639124444863775743801488193), - new FalconFPR(-0.639124444863775743801488193), new FalconFPR(0.769103337645579639346626069), - new FalconFPR(0.091908956497132728624990979), new FalconFPR(0.995767414467659793982495643), - new FalconFPR(-0.995767414467659793982495643), new FalconFPR(0.091908956497132728624990979), - new FalconFPR(0.998475580573294752208559038), new FalconFPR(0.055195244349689939809447526), - new FalconFPR(-0.055195244349689939809447526), new FalconFPR(0.998475580573294752208559038), - new FalconFPR(0.666999922303637506650154222), new FalconFPR(0.745057785441465962407907310), - new FalconFPR(-0.745057785441465962407907310), new FalconFPR(0.666999922303637506650154222), - new FalconFPR(0.901348847046022014570746093), new FalconFPR(0.433093818853151968484222638), - new FalconFPR(-0.433093818853151968484222638), new FalconFPR(0.901348847046022014570746093), - new FalconFPR(0.331106305759876401737190737), new FalconFPR(0.943593458161960361495301445), - new FalconFPR(-0.943593458161960361495301445), new FalconFPR(0.331106305759876401737190737), - new FalconFPR(0.968522094274417316221088329), new FalconFPR(0.248927605745720168110682816), - new FalconFPR(-0.248927605745720168110682816), new FalconFPR(0.968522094274417316221088329), - new FalconFPR(0.508830142543107036931749324), new FalconFPR(0.860866938637767279344583877), - new FalconFPR(-0.860866938637767279344583877), new FalconFPR(0.508830142543107036931749324), - new FalconFPR(0.799537269107905033500246232), new FalconFPR(0.600616479383868926653875896), - new FalconFPR(-0.600616479383868926653875896), new FalconFPR(0.799537269107905033500246232), - new FalconFPR(0.140658239332849230714788846), new FalconFPR(0.990058210262297105505906464), - new FalconFPR(-0.990058210262297105505906464), new FalconFPR(0.140658239332849230714788846), - new FalconFPR(0.988257567730749491404792538), new FalconFPR(0.152797185258443427720336613), - new FalconFPR(-0.152797185258443427720336613), new FalconFPR(0.988257567730749491404792538), - new FalconFPR(0.590759701858874228423887908), new FalconFPR(0.806847553543799272206514313), - new FalconFPR(-0.806847553543799272206514313), new FalconFPR(0.590759701858874228423887908), - new FalconFPR(0.854557988365400520767862276), new FalconFPR(0.519355990165589587361829932), - new FalconFPR(-0.519355990165589587361829932), new FalconFPR(0.854557988365400520767862276), - new FalconFPR(0.237023605994367206867735915), new FalconFPR(0.971503890986251775537099622), - new FalconFPR(-0.971503890986251775537099622), new FalconFPR(0.237023605994367206867735915), - new FalconFPR(0.939459223602189911962669246), new FalconFPR(0.342660717311994397592781983), - new FalconFPR(-0.342660717311994397592781983), new FalconFPR(0.939459223602189911962669246), - new FalconFPR(0.422000270799799685941287941), new FalconFPR(0.906595704514915365332960588), - new FalconFPR(-0.906595704514915365332960588), new FalconFPR(0.422000270799799685941287941), - new FalconFPR(0.736816568877369875090132520), new FalconFPR(0.676092703575315960360419228), - new FalconFPR(-0.676092703575315960360419228), new FalconFPR(0.736816568877369875090132520), - new FalconFPR(0.042938256934940823077124540), new FalconFPR(0.999077727752645382888781997), - new FalconFPR(-0.999077727752645382888781997), new FalconFPR(0.042938256934940823077124540), - new FalconFPR(0.999529417501093163079703322), new FalconFPR(0.030674803176636625934021028), - new FalconFPR(-0.030674803176636625934021028), new FalconFPR(0.999529417501093163079703322), - new FalconFPR(0.685083667772700381362052545), new FalconFPR(0.728464390448225196492035438), - new FalconFPR(-0.728464390448225196492035438), new FalconFPR(0.685083667772700381362052545), - new FalconFPR(0.911706032005429851404397325), new FalconFPR(0.410843171057903942183466675), - new FalconFPR(-0.410843171057903942183466675), new FalconFPR(0.911706032005429851404397325), - new FalconFPR(0.354163525420490382357395796), new FalconFPR(0.935183509938947577642207480), - new FalconFPR(-0.935183509938947577642207480), new FalconFPR(0.354163525420490382357395796), - new FalconFPR(0.974339382785575860518721668), new FalconFPR(0.225083911359792835991642120), - new FalconFPR(-0.225083911359792835991642120), new FalconFPR(0.974339382785575860518721668), - new FalconFPR(0.529803624686294668216054671), new FalconFPR(0.848120344803297251279133563), - new FalconFPR(-0.848120344803297251279133563), new FalconFPR(0.529803624686294668216054671), - new FalconFPR(0.814036329705948361654516690), new FalconFPR(0.580813958095764545075595272), - new FalconFPR(-0.580813958095764545075595272), new FalconFPR(0.814036329705948361654516690), - new FalconFPR(0.164913120489969921418189113), new FalconFPR(0.986308097244598647863297524), - new FalconFPR(-0.986308097244598647863297524), new FalconFPR(0.164913120489969921418189113), - new FalconFPR(0.991709753669099522860049931), new FalconFPR(0.128498110793793172624415589), - new FalconFPR(-0.128498110793793172624415589), new FalconFPR(0.991709753669099522860049931), - new FalconFPR(0.610382806276309452716352152), new FalconFPR(0.792106577300212351782342879), - new FalconFPR(-0.792106577300212351782342879), new FalconFPR(0.610382806276309452716352152), - new FalconFPR(0.867046245515692651480195629), new FalconFPR(0.498227666972781852410983869), - new FalconFPR(-0.498227666972781852410983869), new FalconFPR(0.867046245515692651480195629), - new FalconFPR(0.260794117915275518280186509), new FalconFPR(0.965394441697689374550843858), - new FalconFPR(-0.965394441697689374550843858), new FalconFPR(0.260794117915275518280186509), - new FalconFPR(0.947585591017741134653387321), new FalconFPR(0.319502030816015677901518272), - new FalconFPR(-0.319502030816015677901518272), new FalconFPR(0.947585591017741134653387321), - new FalconFPR(0.444122144570429231642069418), new FalconFPR(0.895966249756185155914560282), - new FalconFPR(-0.895966249756185155914560282), new FalconFPR(0.444122144570429231642069418), - new FalconFPR(0.753186799043612482483430486), new FalconFPR(0.657806693297078656931182264), - new FalconFPR(-0.657806693297078656931182264), new FalconFPR(0.753186799043612482483430486), - new FalconFPR(0.067443919563664057897972422), new FalconFPR(0.997723066644191609848546728), - new FalconFPR(-0.997723066644191609848546728), new FalconFPR(0.067443919563664057897972422), - new FalconFPR(0.996820299291165714972629398), new FalconFPR(0.079682437971430121147120656), - new FalconFPR(-0.079682437971430121147120656), new FalconFPR(0.996820299291165714972629398), - new FalconFPR(0.648514401022112445084560551), new FalconFPR(0.761202385484261814029709836), - new FalconFPR(-0.761202385484261814029709836), new FalconFPR(0.648514401022112445084560551), - new FalconFPR(0.890448723244757889952150560), new FalconFPR(0.455083587126343823535869268), - new FalconFPR(-0.455083587126343823535869268), new FalconFPR(0.890448723244757889952150560), - new FalconFPR(0.307849640041534893682063646), new FalconFPR(0.951435020969008369549175569), - new FalconFPR(-0.951435020969008369549175569), new FalconFPR(0.307849640041534893682063646), - new FalconFPR(0.962121404269041595429604316), new FalconFPR(0.272621355449948984493347477), - new FalconFPR(-0.272621355449948984493347477), new FalconFPR(0.962121404269041595429604316), - new FalconFPR(0.487550160148435954641485027), new FalconFPR(0.873094978418290098636085973), - new FalconFPR(-0.873094978418290098636085973), new FalconFPR(0.487550160148435954641485027), - new FalconFPR(0.784556597155575233023892575), new FalconFPR(0.620057211763289178646268191), - new FalconFPR(-0.620057211763289178646268191), new FalconFPR(0.784556597155575233023892575), - new FalconFPR(0.116318630911904767252544319), new FalconFPR(0.993211949234794533104601012), - new FalconFPR(-0.993211949234794533104601012), new FalconFPR(0.116318630911904767252544319), - new FalconFPR(0.984210092386929073193874387), new FalconFPR(0.177004220412148756196839844), - new FalconFPR(-0.177004220412148756196839844), new FalconFPR(0.984210092386929073193874387), - new FalconFPR(0.570780745886967280232652864), new FalconFPR(0.821102514991104679060430820), - new FalconFPR(-0.821102514991104679060430820), new FalconFPR(0.570780745886967280232652864), - new FalconFPR(0.841554977436898409603499520), new FalconFPR(0.540171472729892881297845480), - new FalconFPR(-0.540171472729892881297845480), new FalconFPR(0.841554977436898409603499520), - new FalconFPR(0.213110319916091373967757518), new FalconFPR(0.977028142657754351485866211), - new FalconFPR(-0.977028142657754351485866211), new FalconFPR(0.213110319916091373967757518), - new FalconFPR(0.930766961078983731944872340), new FalconFPR(0.365612997804773870011745909), - new FalconFPR(-0.365612997804773870011745909), new FalconFPR(0.930766961078983731944872340), - new FalconFPR(0.399624199845646828544117031), new FalconFPR(0.916679059921042663116457013), - new FalconFPR(-0.916679059921042663116457013), new FalconFPR(0.399624199845646828544117031), - new FalconFPR(0.720002507961381629076682999), new FalconFPR(0.693971460889654009003734389), - new FalconFPR(-0.693971460889654009003734389), new FalconFPR(0.720002507961381629076682999), - new FalconFPR(0.018406729905804820927366313), new FalconFPR(0.999830581795823422015722275), - new FalconFPR(-0.999830581795823422015722275), new FalconFPR(0.018406729905804820927366313), - new FalconFPR(0.999830581795823422015722275), new FalconFPR(0.018406729905804820927366313), - new FalconFPR(-0.018406729905804820927366313), new FalconFPR(0.999830581795823422015722275), - new FalconFPR(0.693971460889654009003734389), new FalconFPR(0.720002507961381629076682999), - new FalconFPR(-0.720002507961381629076682999), new FalconFPR(0.693971460889654009003734389), - new FalconFPR(0.916679059921042663116457013), new FalconFPR(0.399624199845646828544117031), - new FalconFPR(-0.399624199845646828544117031), new FalconFPR(0.916679059921042663116457013), - new FalconFPR(0.365612997804773870011745909), new FalconFPR(0.930766961078983731944872340), - new FalconFPR(-0.930766961078983731944872340), new FalconFPR(0.365612997804773870011745909), - new FalconFPR(0.977028142657754351485866211), new FalconFPR(0.213110319916091373967757518), - new FalconFPR(-0.213110319916091373967757518), new FalconFPR(0.977028142657754351485866211), - new FalconFPR(0.540171472729892881297845480), new FalconFPR(0.841554977436898409603499520), - new FalconFPR(-0.841554977436898409603499520), new FalconFPR(0.540171472729892881297845480), - new FalconFPR(0.821102514991104679060430820), new FalconFPR(0.570780745886967280232652864), - new FalconFPR(-0.570780745886967280232652864), new FalconFPR(0.821102514991104679060430820), - new FalconFPR(0.177004220412148756196839844), new FalconFPR(0.984210092386929073193874387), - new FalconFPR(-0.984210092386929073193874387), new FalconFPR(0.177004220412148756196839844), - new FalconFPR(0.993211949234794533104601012), new FalconFPR(0.116318630911904767252544319), - new FalconFPR(-0.116318630911904767252544319), new FalconFPR(0.993211949234794533104601012), - new FalconFPR(0.620057211763289178646268191), new FalconFPR(0.784556597155575233023892575), - new FalconFPR(-0.784556597155575233023892575), new FalconFPR(0.620057211763289178646268191), - new FalconFPR(0.873094978418290098636085973), new FalconFPR(0.487550160148435954641485027), - new FalconFPR(-0.487550160148435954641485027), new FalconFPR(0.873094978418290098636085973), - new FalconFPR(0.272621355449948984493347477), new FalconFPR(0.962121404269041595429604316), - new FalconFPR(-0.962121404269041595429604316), new FalconFPR(0.272621355449948984493347477), - new FalconFPR(0.951435020969008369549175569), new FalconFPR(0.307849640041534893682063646), - new FalconFPR(-0.307849640041534893682063646), new FalconFPR(0.951435020969008369549175569), - new FalconFPR(0.455083587126343823535869268), new FalconFPR(0.890448723244757889952150560), - new FalconFPR(-0.890448723244757889952150560), new FalconFPR(0.455083587126343823535869268), - new FalconFPR(0.761202385484261814029709836), new FalconFPR(0.648514401022112445084560551), - new FalconFPR(-0.648514401022112445084560551), new FalconFPR(0.761202385484261814029709836), - new FalconFPR(0.079682437971430121147120656), new FalconFPR(0.996820299291165714972629398), - new FalconFPR(-0.996820299291165714972629398), new FalconFPR(0.079682437971430121147120656), - new FalconFPR(0.997723066644191609848546728), new FalconFPR(0.067443919563664057897972422), - new FalconFPR(-0.067443919563664057897972422), new FalconFPR(0.997723066644191609848546728), - new FalconFPR(0.657806693297078656931182264), new FalconFPR(0.753186799043612482483430486), - new FalconFPR(-0.753186799043612482483430486), new FalconFPR(0.657806693297078656931182264), - new FalconFPR(0.895966249756185155914560282), new FalconFPR(0.444122144570429231642069418), - new FalconFPR(-0.444122144570429231642069418), new FalconFPR(0.895966249756185155914560282), - new FalconFPR(0.319502030816015677901518272), new FalconFPR(0.947585591017741134653387321), - new FalconFPR(-0.947585591017741134653387321), new FalconFPR(0.319502030816015677901518272), - new FalconFPR(0.965394441697689374550843858), new FalconFPR(0.260794117915275518280186509), - new FalconFPR(-0.260794117915275518280186509), new FalconFPR(0.965394441697689374550843858), - new FalconFPR(0.498227666972781852410983869), new FalconFPR(0.867046245515692651480195629), - new FalconFPR(-0.867046245515692651480195629), new FalconFPR(0.498227666972781852410983869), - new FalconFPR(0.792106577300212351782342879), new FalconFPR(0.610382806276309452716352152), - new FalconFPR(-0.610382806276309452716352152), new FalconFPR(0.792106577300212351782342879), - new FalconFPR(0.128498110793793172624415589), new FalconFPR(0.991709753669099522860049931), - new FalconFPR(-0.991709753669099522860049931), new FalconFPR(0.128498110793793172624415589), - new FalconFPR(0.986308097244598647863297524), new FalconFPR(0.164913120489969921418189113), - new FalconFPR(-0.164913120489969921418189113), new FalconFPR(0.986308097244598647863297524), - new FalconFPR(0.580813958095764545075595272), new FalconFPR(0.814036329705948361654516690), - new FalconFPR(-0.814036329705948361654516690), new FalconFPR(0.580813958095764545075595272), - new FalconFPR(0.848120344803297251279133563), new FalconFPR(0.529803624686294668216054671), - new FalconFPR(-0.529803624686294668216054671), new FalconFPR(0.848120344803297251279133563), - new FalconFPR(0.225083911359792835991642120), new FalconFPR(0.974339382785575860518721668), - new FalconFPR(-0.974339382785575860518721668), new FalconFPR(0.225083911359792835991642120), - new FalconFPR(0.935183509938947577642207480), new FalconFPR(0.354163525420490382357395796), - new FalconFPR(-0.354163525420490382357395796), new FalconFPR(0.935183509938947577642207480), - new FalconFPR(0.410843171057903942183466675), new FalconFPR(0.911706032005429851404397325), - new FalconFPR(-0.911706032005429851404397325), new FalconFPR(0.410843171057903942183466675), - new FalconFPR(0.728464390448225196492035438), new FalconFPR(0.685083667772700381362052545), - new FalconFPR(-0.685083667772700381362052545), new FalconFPR(0.728464390448225196492035438), - new FalconFPR(0.030674803176636625934021028), new FalconFPR(0.999529417501093163079703322), - new FalconFPR(-0.999529417501093163079703322), new FalconFPR(0.030674803176636625934021028), - new FalconFPR(0.999077727752645382888781997), new FalconFPR(0.042938256934940823077124540), - new FalconFPR(-0.042938256934940823077124540), new FalconFPR(0.999077727752645382888781997), - new FalconFPR(0.676092703575315960360419228), new FalconFPR(0.736816568877369875090132520), - new FalconFPR(-0.736816568877369875090132520), new FalconFPR(0.676092703575315960360419228), - new FalconFPR(0.906595704514915365332960588), new FalconFPR(0.422000270799799685941287941), - new FalconFPR(-0.422000270799799685941287941), new FalconFPR(0.906595704514915365332960588), - new FalconFPR(0.342660717311994397592781983), new FalconFPR(0.939459223602189911962669246), - new FalconFPR(-0.939459223602189911962669246), new FalconFPR(0.342660717311994397592781983), - new FalconFPR(0.971503890986251775537099622), new FalconFPR(0.237023605994367206867735915), - new FalconFPR(-0.237023605994367206867735915), new FalconFPR(0.971503890986251775537099622), - new FalconFPR(0.519355990165589587361829932), new FalconFPR(0.854557988365400520767862276), - new FalconFPR(-0.854557988365400520767862276), new FalconFPR(0.519355990165589587361829932), - new FalconFPR(0.806847553543799272206514313), new FalconFPR(0.590759701858874228423887908), - new FalconFPR(-0.590759701858874228423887908), new FalconFPR(0.806847553543799272206514313), - new FalconFPR(0.152797185258443427720336613), new FalconFPR(0.988257567730749491404792538), - new FalconFPR(-0.988257567730749491404792538), new FalconFPR(0.152797185258443427720336613), - new FalconFPR(0.990058210262297105505906464), new FalconFPR(0.140658239332849230714788846), - new FalconFPR(-0.140658239332849230714788846), new FalconFPR(0.990058210262297105505906464), - new FalconFPR(0.600616479383868926653875896), new FalconFPR(0.799537269107905033500246232), - new FalconFPR(-0.799537269107905033500246232), new FalconFPR(0.600616479383868926653875896), - new FalconFPR(0.860866938637767279344583877), new FalconFPR(0.508830142543107036931749324), - new FalconFPR(-0.508830142543107036931749324), new FalconFPR(0.860866938637767279344583877), - new FalconFPR(0.248927605745720168110682816), new FalconFPR(0.968522094274417316221088329), - new FalconFPR(-0.968522094274417316221088329), new FalconFPR(0.248927605745720168110682816), - new FalconFPR(0.943593458161960361495301445), new FalconFPR(0.331106305759876401737190737), - new FalconFPR(-0.331106305759876401737190737), new FalconFPR(0.943593458161960361495301445), - new FalconFPR(0.433093818853151968484222638), new FalconFPR(0.901348847046022014570746093), - new FalconFPR(-0.901348847046022014570746093), new FalconFPR(0.433093818853151968484222638), - new FalconFPR(0.745057785441465962407907310), new FalconFPR(0.666999922303637506650154222), - new FalconFPR(-0.666999922303637506650154222), new FalconFPR(0.745057785441465962407907310), - new FalconFPR(0.055195244349689939809447526), new FalconFPR(0.998475580573294752208559038), - new FalconFPR(-0.998475580573294752208559038), new FalconFPR(0.055195244349689939809447526), - new FalconFPR(0.995767414467659793982495643), new FalconFPR(0.091908956497132728624990979), - new FalconFPR(-0.091908956497132728624990979), new FalconFPR(0.995767414467659793982495643), - new FalconFPR(0.639124444863775743801488193), new FalconFPR(0.769103337645579639346626069), - new FalconFPR(-0.769103337645579639346626069), new FalconFPR(0.639124444863775743801488193), - new FalconFPR(0.884797098430937780104007041), new FalconFPR(0.465976495767966177902756065), - new FalconFPR(-0.465976495767966177902756065), new FalconFPR(0.884797098430937780104007041), - new FalconFPR(0.296150888243623824121786128), new FalconFPR(0.955141168305770721498157712), - new FalconFPR(-0.955141168305770721498157712), new FalconFPR(0.296150888243623824121786128), - new FalconFPR(0.958703474895871555374645792), new FalconFPR(0.284407537211271843618310615), - new FalconFPR(-0.284407537211271843618310615), new FalconFPR(0.958703474895871555374645792), - new FalconFPR(0.476799230063322133342158117), new FalconFPR(0.879012226428633477831323711), - new FalconFPR(-0.879012226428633477831323711), new FalconFPR(0.476799230063322133342158117), - new FalconFPR(0.776888465673232450040827983), new FalconFPR(0.629638238914927025372981341), - new FalconFPR(-0.629638238914927025372981341), new FalconFPR(0.776888465673232450040827983), - new FalconFPR(0.104121633872054579120943880), new FalconFPR(0.994564570734255452119106243), - new FalconFPR(-0.994564570734255452119106243), new FalconFPR(0.104121633872054579120943880), - new FalconFPR(0.981963869109555264072848154), new FalconFPR(0.189068664149806212754997837), - new FalconFPR(-0.189068664149806212754997837), new FalconFPR(0.981963869109555264072848154), - new FalconFPR(0.560661576197336023839710223), new FalconFPR(0.828045045257755752067527592), - new FalconFPR(-0.828045045257755752067527592), new FalconFPR(0.560661576197336023839710223), - new FalconFPR(0.834862874986380056304401383), new FalconFPR(0.550457972936604802977289893), - new FalconFPR(-0.550457972936604802977289893), new FalconFPR(0.834862874986380056304401383), - new FalconFPR(0.201104634842091911558443546), new FalconFPR(0.979569765685440534439326110), - new FalconFPR(-0.979569765685440534439326110), new FalconFPR(0.201104634842091911558443546), - new FalconFPR(0.926210242138311341974793388), new FalconFPR(0.377007410216418256726567823), - new FalconFPR(-0.377007410216418256726567823), new FalconFPR(0.926210242138311341974793388), - new FalconFPR(0.388345046698826291624993541), new FalconFPR(0.921514039342041943465396332), - new FalconFPR(-0.921514039342041943465396332), new FalconFPR(0.388345046698826291624993541), - new FalconFPR(0.711432195745216441522130290), new FalconFPR(0.702754744457225302452914421), - new FalconFPR(-0.702754744457225302452914421), new FalconFPR(0.711432195745216441522130290), - new FalconFPR(0.006135884649154475359640235), new FalconFPR(0.999981175282601142656990438), - new FalconFPR(-0.999981175282601142656990438), new FalconFPR(0.006135884649154475359640235), - new FalconFPR(0.999995293809576171511580126), new FalconFPR(0.003067956762965976270145365), - new FalconFPR(-0.003067956762965976270145365), new FalconFPR(0.999995293809576171511580126), - new FalconFPR(0.704934080375904908852523758), new FalconFPR(0.709272826438865651316533772), - new FalconFPR(-0.709272826438865651316533772), new FalconFPR(0.704934080375904908852523758), - new FalconFPR(0.922701128333878570437264227), new FalconFPR(0.385516053843918864075607949), - new FalconFPR(-0.385516053843918864075607949), new FalconFPR(0.922701128333878570437264227), - new FalconFPR(0.379847208924051170576281147), new FalconFPR(0.925049240782677590302371869), - new FalconFPR(-0.925049240782677590302371869), new FalconFPR(0.379847208924051170576281147), - new FalconFPR(0.980182135968117392690210009), new FalconFPR(0.198098410717953586179324918), - new FalconFPR(-0.198098410717953586179324918), new FalconFPR(0.980182135968117392690210009), - new FalconFPR(0.553016705580027531764226988), new FalconFPR(0.833170164701913186439915922), - new FalconFPR(-0.833170164701913186439915922), new FalconFPR(0.553016705580027531764226988), - new FalconFPR(0.829761233794523042469023765), new FalconFPR(0.558118531220556115693702964), - new FalconFPR(-0.558118531220556115693702964), new FalconFPR(0.829761233794523042469023765), - new FalconFPR(0.192080397049892441679288205), new FalconFPR(0.981379193313754574318224190), - new FalconFPR(-0.981379193313754574318224190), new FalconFPR(0.192080397049892441679288205), - new FalconFPR(0.994879330794805620591166107), new FalconFPR(0.101069862754827824987887585), - new FalconFPR(-0.101069862754827824987887585), new FalconFPR(0.994879330794805620591166107), - new FalconFPR(0.632018735939809021909403706), new FalconFPR(0.774953106594873878359129282), - new FalconFPR(-0.774953106594873878359129282), new FalconFPR(0.632018735939809021909403706), - new FalconFPR(0.880470889052160770806542929), new FalconFPR(0.474100214650550014398580015), - new FalconFPR(-0.474100214650550014398580015), new FalconFPR(0.880470889052160770806542929), - new FalconFPR(0.287347459544729526477331841), new FalconFPR(0.957826413027532890321037029), - new FalconFPR(-0.957826413027532890321037029), new FalconFPR(0.287347459544729526477331841), - new FalconFPR(0.956045251349996443270479823), new FalconFPR(0.293219162694258650606608599), - new FalconFPR(-0.293219162694258650606608599), new FalconFPR(0.956045251349996443270479823), - new FalconFPR(0.468688822035827933697617870), new FalconFPR(0.883363338665731594736308015), - new FalconFPR(-0.883363338665731594736308015), new FalconFPR(0.468688822035827933697617870), - new FalconFPR(0.771060524261813773200605759), new FalconFPR(0.636761861236284230413943435), - new FalconFPR(-0.636761861236284230413943435), new FalconFPR(0.771060524261813773200605759), - new FalconFPR(0.094963495329638998938034312), new FalconFPR(0.995480755491926941769171600), - new FalconFPR(-0.995480755491926941769171600), new FalconFPR(0.094963495329638998938034312), - new FalconFPR(0.998640218180265222418199049), new FalconFPR(0.052131704680283321236358216), - new FalconFPR(-0.052131704680283321236358216), new FalconFPR(0.998640218180265222418199049), - new FalconFPR(0.669282588346636065720696366), new FalconFPR(0.743007952135121693517362293), - new FalconFPR(-0.743007952135121693517362293), new FalconFPR(0.669282588346636065720696366), - new FalconFPR(0.902673318237258806751502391), new FalconFPR(0.430326481340082633908199031), - new FalconFPR(-0.430326481340082633908199031), new FalconFPR(0.902673318237258806751502391), - new FalconFPR(0.333999651442009404650865481), new FalconFPR(0.942573197601446879280758735), - new FalconFPR(-0.942573197601446879280758735), new FalconFPR(0.333999651442009404650865481), - new FalconFPR(0.969281235356548486048290738), new FalconFPR(0.245955050335794611599924709), - new FalconFPR(-0.245955050335794611599924709), new FalconFPR(0.969281235356548486048290738), - new FalconFPR(0.511468850437970399504391001), new FalconFPR(0.859301818357008404783582139), - new FalconFPR(-0.859301818357008404783582139), new FalconFPR(0.511468850437970399504391001), - new FalconFPR(0.801376171723140219430247777), new FalconFPR(0.598160706996342311724958652), - new FalconFPR(-0.598160706996342311724958652), new FalconFPR(0.801376171723140219430247777), - new FalconFPR(0.143695033150294454819773349), new FalconFPR(0.989622017463200834623694454), - new FalconFPR(-0.989622017463200834623694454), new FalconFPR(0.143695033150294454819773349), - new FalconFPR(0.988721691960323767604516485), new FalconFPR(0.149764534677321517229695737), - new FalconFPR(-0.149764534677321517229695737), new FalconFPR(0.988721691960323767604516485), - new FalconFPR(0.593232295039799808047809426), new FalconFPR(0.805031331142963597922659282), - new FalconFPR(-0.805031331142963597922659282), new FalconFPR(0.593232295039799808047809426), - new FalconFPR(0.856147328375194481019630732), new FalconFPR(0.516731799017649881508753876), - new FalconFPR(-0.516731799017649881508753876), new FalconFPR(0.856147328375194481019630732), - new FalconFPR(0.240003022448741486568922365), new FalconFPR(0.970772140728950302138169611), - new FalconFPR(-0.970772140728950302138169611), new FalconFPR(0.240003022448741486568922365), - new FalconFPR(0.940506070593268323787291309), new FalconFPR(0.339776884406826857828825803), - new FalconFPR(-0.339776884406826857828825803), new FalconFPR(0.940506070593268323787291309), - new FalconFPR(0.424779681209108833357226189), new FalconFPR(0.905296759318118774354048329), - new FalconFPR(-0.905296759318118774354048329), new FalconFPR(0.424779681209108833357226189), - new FalconFPR(0.738887324460615147933116508), new FalconFPR(0.673829000378756060917568372), - new FalconFPR(-0.673829000378756060917568372), new FalconFPR(0.738887324460615147933116508), - new FalconFPR(0.046003182130914628814301788), new FalconFPR(0.998941293186856850633930266), - new FalconFPR(-0.998941293186856850633930266), new FalconFPR(0.046003182130914628814301788), - new FalconFPR(0.999618822495178597116830637), new FalconFPR(0.027608145778965741612354872), - new FalconFPR(-0.027608145778965741612354872), new FalconFPR(0.999618822495178597116830637), - new FalconFPR(0.687315340891759108199186948), new FalconFPR(0.726359155084345976817494315), - new FalconFPR(-0.726359155084345976817494315), new FalconFPR(0.687315340891759108199186948), - new FalconFPR(0.912962190428398164628018233), new FalconFPR(0.408044162864978680820747499), - new FalconFPR(-0.408044162864978680820747499), new FalconFPR(0.912962190428398164628018233), - new FalconFPR(0.357030961233430032614954036), new FalconFPR(0.934092550404258914729877883), - new FalconFPR(-0.934092550404258914729877883), new FalconFPR(0.357030961233430032614954036), - new FalconFPR(0.975025345066994146844913468), new FalconFPR(0.222093620973203534094094721), - new FalconFPR(-0.222093620973203534094094721), new FalconFPR(0.975025345066994146844913468), - new FalconFPR(0.532403127877197971442805218), new FalconFPR(0.846490938774052078300544488), - new FalconFPR(-0.846490938774052078300544488), new FalconFPR(0.532403127877197971442805218), - new FalconFPR(0.815814410806733789010772660), new FalconFPR(0.578313796411655563342245019), - new FalconFPR(-0.578313796411655563342245019), new FalconFPR(0.815814410806733789010772660), - new FalconFPR(0.167938294974731178054745536), new FalconFPR(0.985797509167567424700995000), - new FalconFPR(-0.985797509167567424700995000), new FalconFPR(0.167938294974731178054745536), - new FalconFPR(0.992099313142191757112085445), new FalconFPR(0.125454983411546238542336453), - new FalconFPR(-0.125454983411546238542336453), new FalconFPR(0.992099313142191757112085445), - new FalconFPR(0.612810082429409703935211936), new FalconFPR(0.790230221437310055030217152), - new FalconFPR(-0.790230221437310055030217152), new FalconFPR(0.612810082429409703935211936), - new FalconFPR(0.868570705971340895340449876), new FalconFPR(0.495565261825772531150266670), - new FalconFPR(-0.495565261825772531150266670), new FalconFPR(0.868570705971340895340449876), - new FalconFPR(0.263754678974831383611349322), new FalconFPR(0.964589793289812723836432159), - new FalconFPR(-0.964589793289812723836432159), new FalconFPR(0.263754678974831383611349322), - new FalconFPR(0.948561349915730288158494826), new FalconFPR(0.316593375556165867243047035), - new FalconFPR(-0.316593375556165867243047035), new FalconFPR(0.948561349915730288158494826), - new FalconFPR(0.446868840162374195353044389), new FalconFPR(0.894599485631382678433072126), - new FalconFPR(-0.894599485631382678433072126), new FalconFPR(0.446868840162374195353044389), - new FalconFPR(0.755201376896536527598710756), new FalconFPR(0.655492852999615385312679701), - new FalconFPR(-0.655492852999615385312679701), new FalconFPR(0.755201376896536527598710756), - new FalconFPR(0.070504573389613863027351471), new FalconFPR(0.997511456140303459699448390), - new FalconFPR(-0.997511456140303459699448390), new FalconFPR(0.070504573389613863027351471), - new FalconFPR(0.997060070339482978987989949), new FalconFPR(0.076623861392031492278332463), - new FalconFPR(-0.076623861392031492278332463), new FalconFPR(0.997060070339482978987989949), - new FalconFPR(0.650846684996380915068975573), new FalconFPR(0.759209188978388033485525443), - new FalconFPR(-0.759209188978388033485525443), new FalconFPR(0.650846684996380915068975573), - new FalconFPR(0.891840709392342727796478697), new FalconFPR(0.452349587233770874133026703), - new FalconFPR(-0.452349587233770874133026703), new FalconFPR(0.891840709392342727796478697), - new FalconFPR(0.310767152749611495835997250), new FalconFPR(0.950486073949481721759926101), - new FalconFPR(-0.950486073949481721759926101), new FalconFPR(0.310767152749611495835997250), - new FalconFPR(0.962953266873683886347921481), new FalconFPR(0.269668325572915106525464462), - new FalconFPR(-0.269668325572915106525464462), new FalconFPR(0.962953266873683886347921481), - new FalconFPR(0.490226483288291154229598449), new FalconFPR(0.871595086655951034842481435), - new FalconFPR(-0.871595086655951034842481435), new FalconFPR(0.490226483288291154229598449), - new FalconFPR(0.786455213599085757522319464), new FalconFPR(0.617647307937803932403979402), - new FalconFPR(-0.617647307937803932403979402), new FalconFPR(0.786455213599085757522319464), - new FalconFPR(0.119365214810991364593637790), new FalconFPR(0.992850414459865090793563344), - new FalconFPR(-0.992850414459865090793563344), new FalconFPR(0.119365214810991364593637790), - new FalconFPR(0.984748501801904218556553176), new FalconFPR(0.173983873387463827950700807), - new FalconFPR(-0.173983873387463827950700807), new FalconFPR(0.984748501801904218556553176), - new FalconFPR(0.573297166698042212820171239), new FalconFPR(0.819347520076796960824689637), - new FalconFPR(-0.819347520076796960824689637), new FalconFPR(0.573297166698042212820171239), - new FalconFPR(0.843208239641845437161743865), new FalconFPR(0.537587076295645482502214932), - new FalconFPR(-0.537587076295645482502214932), new FalconFPR(0.843208239641845437161743865), - new FalconFPR(0.216106797076219509948385131), new FalconFPR(0.976369731330021149312732194), - new FalconFPR(-0.976369731330021149312732194), new FalconFPR(0.216106797076219509948385131), - new FalconFPR(0.931884265581668106718557199), new FalconFPR(0.362755724367397216204854462), - new FalconFPR(-0.362755724367397216204854462), new FalconFPR(0.931884265581668106718557199), - new FalconFPR(0.402434650859418441082533934), new FalconFPR(0.915448716088267819566431292), - new FalconFPR(-0.915448716088267819566431292), new FalconFPR(0.402434650859418441082533934), - new FalconFPR(0.722128193929215321243607198), new FalconFPR(0.691759258364157774906734132), - new FalconFPR(-0.691759258364157774906734132), new FalconFPR(0.722128193929215321243607198), - new FalconFPR(0.021474080275469507418374898), new FalconFPR(0.999769405351215321657617036), - new FalconFPR(-0.999769405351215321657617036), new FalconFPR(0.021474080275469507418374898), - new FalconFPR(0.999882347454212525633049627), new FalconFPR(0.015339206284988101044151868), - new FalconFPR(-0.015339206284988101044151868), new FalconFPR(0.999882347454212525633049627), - new FalconFPR(0.696177131491462944788582591), new FalconFPR(0.717870045055731736211325329), - new FalconFPR(-0.717870045055731736211325329), new FalconFPR(0.696177131491462944788582591), - new FalconFPR(0.917900775621390457642276297), new FalconFPR(0.396809987416710328595290911), - new FalconFPR(-0.396809987416710328595290911), new FalconFPR(0.917900775621390457642276297), - new FalconFPR(0.368466829953372331712746222), new FalconFPR(0.929640895843181265457918066), - new FalconFPR(-0.929640895843181265457918066), new FalconFPR(0.368466829953372331712746222), - new FalconFPR(0.977677357824509979943404762), new FalconFPR(0.210111836880469621717489972), - new FalconFPR(-0.210111836880469621717489972), new FalconFPR(0.977677357824509979943404762), - new FalconFPR(0.542750784864515906586768661), new FalconFPR(0.839893794195999504583383987), - new FalconFPR(-0.839893794195999504583383987), new FalconFPR(0.542750784864515906586768661), - new FalconFPR(0.822849781375826332046780034), new FalconFPR(0.568258952670131549790548489), - new FalconFPR(-0.568258952670131549790548489), new FalconFPR(0.822849781375826332046780034), - new FalconFPR(0.180022901405699522679906590), new FalconFPR(0.983662419211730274396237776), - new FalconFPR(-0.983662419211730274396237776), new FalconFPR(0.180022901405699522679906590), - new FalconFPR(0.993564135520595333782021697), new FalconFPR(0.113270952177564349018228733), - new FalconFPR(-0.113270952177564349018228733), new FalconFPR(0.993564135520595333782021697), - new FalconFPR(0.622461279374149972519166721), new FalconFPR(0.782650596166575738458949301), - new FalconFPR(-0.782650596166575738458949301), new FalconFPR(0.622461279374149972519166721), - new FalconFPR(0.874586652278176112634431897), new FalconFPR(0.484869248000791101822951699), - new FalconFPR(-0.484869248000791101822951699), new FalconFPR(0.874586652278176112634431897), - new FalconFPR(0.275571819310958163076425168), new FalconFPR(0.961280485811320641748659653), - new FalconFPR(-0.961280485811320641748659653), new FalconFPR(0.275571819310958163076425168), - new FalconFPR(0.952375012719765858529893608), new FalconFPR(0.304929229735402406490728633), - new FalconFPR(-0.304929229735402406490728633), new FalconFPR(0.952375012719765858529893608), - new FalconFPR(0.457813303598877221904961155), new FalconFPR(0.889048355854664562540777729), - new FalconFPR(-0.889048355854664562540777729), new FalconFPR(0.457813303598877221904961155), - new FalconFPR(0.763188417263381271704838297), new FalconFPR(0.646176012983316364832802220), - new FalconFPR(-0.646176012983316364832802220), new FalconFPR(0.763188417263381271704838297), - new FalconFPR(0.082740264549375693111987083), new FalconFPR(0.996571145790554847093566910), - new FalconFPR(-0.996571145790554847093566910), new FalconFPR(0.082740264549375693111987083), - new FalconFPR(0.997925286198596012623025462), new FalconFPR(0.064382630929857460819324537), - new FalconFPR(-0.064382630929857460819324537), new FalconFPR(0.997925286198596012623025462), - new FalconFPR(0.660114342067420478559490747), new FalconFPR(0.751165131909686411205819422), - new FalconFPR(-0.751165131909686411205819422), new FalconFPR(0.660114342067420478559490747), - new FalconFPR(0.897324580705418281231391836), new FalconFPR(0.441371268731716692879988968), - new FalconFPR(-0.441371268731716692879988968), new FalconFPR(0.897324580705418281231391836), - new FalconFPR(0.322407678801069848384807478), new FalconFPR(0.946600913083283570044599823), - new FalconFPR(-0.946600913083283570044599823), new FalconFPR(0.322407678801069848384807478), - new FalconFPR(0.966190003445412555433832961), new FalconFPR(0.257831102162159005614471295), - new FalconFPR(-0.257831102162159005614471295), new FalconFPR(0.966190003445412555433832961), - new FalconFPR(0.500885382611240786241285004), new FalconFPR(0.865513624090569082825488358), - new FalconFPR(-0.865513624090569082825488358), new FalconFPR(0.500885382611240786241285004), - new FalconFPR(0.793975477554337164895083757), new FalconFPR(0.607949784967773667243642671), - new FalconFPR(-0.607949784967773667243642671), new FalconFPR(0.793975477554337164895083757), - new FalconFPR(0.131540028702883111103387493), new FalconFPR(0.991310859846115418957349799), - new FalconFPR(-0.991310859846115418957349799), new FalconFPR(0.131540028702883111103387493), - new FalconFPR(0.986809401814185476970235952), new FalconFPR(0.161886393780111837641387995), - new FalconFPR(-0.161886393780111837641387995), new FalconFPR(0.986809401814185476970235952), - new FalconFPR(0.583308652937698294392830961), new FalconFPR(0.812250586585203913049744181), - new FalconFPR(-0.812250586585203913049744181), new FalconFPR(0.583308652937698294392830961), - new FalconFPR(0.849741768000852489471268395), new FalconFPR(0.527199134781901348464274575), - new FalconFPR(-0.527199134781901348464274575), new FalconFPR(0.849741768000852489471268395), - new FalconFPR(0.228072083170885739254457379), new FalconFPR(0.973644249650811925318383912), - new FalconFPR(-0.973644249650811925318383912), new FalconFPR(0.228072083170885739254457379), - new FalconFPR(0.936265667170278246576310996), new FalconFPR(0.351292756085567125601307623), - new FalconFPR(-0.351292756085567125601307623), new FalconFPR(0.936265667170278246576310996), - new FalconFPR(0.413638312238434547471944324), new FalconFPR(0.910441292258067196934095369), - new FalconFPR(-0.910441292258067196934095369), new FalconFPR(0.413638312238434547471944324), - new FalconFPR(0.730562769227827561177758850), new FalconFPR(0.682845546385248068164596123), - new FalconFPR(-0.682845546385248068164596123), new FalconFPR(0.730562769227827561177758850), - new FalconFPR(0.033741171851377584833716112), new FalconFPR(0.999430604555461772019008327), - new FalconFPR(-0.999430604555461772019008327), new FalconFPR(0.033741171851377584833716112), - new FalconFPR(0.999204758618363895492950001), new FalconFPR(0.039872927587739811128578738), - new FalconFPR(-0.039872927587739811128578738), new FalconFPR(0.999204758618363895492950001), - new FalconFPR(0.678350043129861486873655042), new FalconFPR(0.734738878095963464563223604), - new FalconFPR(-0.734738878095963464563223604), new FalconFPR(0.678350043129861486873655042), - new FalconFPR(0.907886116487666212038681480), new FalconFPR(0.419216888363223956433010020), - new FalconFPR(-0.419216888363223956433010020), new FalconFPR(0.907886116487666212038681480), - new FalconFPR(0.345541324963989065539191723), new FalconFPR(0.938403534063108112192420774), - new FalconFPR(-0.938403534063108112192420774), new FalconFPR(0.345541324963989065539191723), - new FalconFPR(0.972226497078936305708321144), new FalconFPR(0.234041958583543423191242045), - new FalconFPR(-0.234041958583543423191242045), new FalconFPR(0.972226497078936305708321144), - new FalconFPR(0.521975292937154342694258318), new FalconFPR(0.852960604930363657746588082), - new FalconFPR(-0.852960604930363657746588082), new FalconFPR(0.521975292937154342694258318), - new FalconFPR(0.808656181588174991946968128), new FalconFPR(0.588281548222645304786439813), - new FalconFPR(-0.588281548222645304786439813), new FalconFPR(0.808656181588174991946968128), - new FalconFPR(0.155828397654265235743101486), new FalconFPR(0.987784141644572154230969032), - new FalconFPR(-0.987784141644572154230969032), new FalconFPR(0.155828397654265235743101486), - new FalconFPR(0.990485084256457037998682243), new FalconFPR(0.137620121586486044948441663), - new FalconFPR(-0.137620121586486044948441663), new FalconFPR(0.990485084256457037998682243), - new FalconFPR(0.603066598540348201693430617), new FalconFPR(0.797690840943391108362662755), - new FalconFPR(-0.797690840943391108362662755), new FalconFPR(0.603066598540348201693430617), - new FalconFPR(0.862423956111040538690933878), new FalconFPR(0.506186645345155291048942344), - new FalconFPR(-0.506186645345155291048942344), new FalconFPR(0.862423956111040538690933878), - new FalconFPR(0.251897818154216950498106628), new FalconFPR(0.967753837093475465243391912), - new FalconFPR(-0.967753837093475465243391912), new FalconFPR(0.251897818154216950498106628), - new FalconFPR(0.944604837261480265659265493), new FalconFPR(0.328209843579092526107916817), - new FalconFPR(-0.328209843579092526107916817), new FalconFPR(0.944604837261480265659265493), - new FalconFPR(0.435857079922255491032544080), new FalconFPR(0.900015892016160228714535267), - new FalconFPR(-0.900015892016160228714535267), new FalconFPR(0.435857079922255491032544080), - new FalconFPR(0.747100605980180144323078847), new FalconFPR(0.664710978203344868130324985), - new FalconFPR(-0.664710978203344868130324985), new FalconFPR(0.747100605980180144323078847), - new FalconFPR(0.058258264500435759613979782), new FalconFPR(0.998301544933892840738782163), - new FalconFPR(-0.998301544933892840738782163), new FalconFPR(0.058258264500435759613979782), - new FalconFPR(0.996044700901251989887944810), new FalconFPR(0.088853552582524596561586535), - new FalconFPR(-0.088853552582524596561586535), new FalconFPR(0.996044700901251989887944810), - new FalconFPR(0.641481012808583151988739898), new FalconFPR(0.767138911935820381181694573), - new FalconFPR(-0.767138911935820381181694573), new FalconFPR(0.641481012808583151988739898), - new FalconFPR(0.886222530148880631647990821), new FalconFPR(0.463259783551860197390719637), - new FalconFPR(-0.463259783551860197390719637), new FalconFPR(0.886222530148880631647990821), - new FalconFPR(0.299079826308040476750336973), new FalconFPR(0.954228095109105629780430732), - new FalconFPR(-0.954228095109105629780430732), new FalconFPR(0.299079826308040476750336973), - new FalconFPR(0.959571513081984528335528181), new FalconFPR(0.281464937925757984095231007), - new FalconFPR(-0.281464937925757984095231007), new FalconFPR(0.959571513081984528335528181), - new FalconFPR(0.479493757660153026679839798), new FalconFPR(0.877545290207261291668470750), - new FalconFPR(-0.877545290207261291668470750), new FalconFPR(0.479493757660153026679839798), - new FalconFPR(0.778816512381475953374724325), new FalconFPR(0.627251815495144113509622565), - new FalconFPR(-0.627251815495144113509622565), new FalconFPR(0.778816512381475953374724325), - new FalconFPR(0.107172424956808849175529148), new FalconFPR(0.994240449453187946358413442), - new FalconFPR(-0.994240449453187946358413442), new FalconFPR(0.107172424956808849175529148), - new FalconFPR(0.982539302287441255907040396), new FalconFPR(0.186055151663446648105438304), - new FalconFPR(-0.186055151663446648105438304), new FalconFPR(0.982539302287441255907040396), - new FalconFPR(0.563199344013834115007363772), new FalconFPR(0.826321062845663480311195452), - new FalconFPR(-0.826321062845663480311195452), new FalconFPR(0.563199344013834115007363772), - new FalconFPR(0.836547727223511984524285790), new FalconFPR(0.547894059173100165608820571), - new FalconFPR(-0.547894059173100165608820571), new FalconFPR(0.836547727223511984524285790), - new FalconFPR(0.204108966092816874181696950), new FalconFPR(0.978948175319062194715480124), - new FalconFPR(-0.978948175319062194715480124), new FalconFPR(0.204108966092816874181696950), - new FalconFPR(0.927362525650401087274536959), new FalconFPR(0.374164062971457997104393020), - new FalconFPR(-0.374164062971457997104393020), new FalconFPR(0.927362525650401087274536959), - new FalconFPR(0.391170384302253888687512949), new FalconFPR(0.920318276709110566440076541), - new FalconFPR(-0.920318276709110566440076541), new FalconFPR(0.391170384302253888687512949), - new FalconFPR(0.713584868780793592903125099), new FalconFPR(0.700568793943248366792866380), - new FalconFPR(-0.700568793943248366792866380), new FalconFPR(0.713584868780793592903125099), - new FalconFPR(0.009203754782059819315102378), new FalconFPR(0.999957644551963866333120920), - new FalconFPR(-0.999957644551963866333120920), new FalconFPR(0.009203754782059819315102378), - new FalconFPR(0.999957644551963866333120920), new FalconFPR(0.009203754782059819315102378), - new FalconFPR(-0.009203754782059819315102378), new FalconFPR(0.999957644551963866333120920), - new FalconFPR(0.700568793943248366792866380), new FalconFPR(0.713584868780793592903125099), - new FalconFPR(-0.713584868780793592903125099), new FalconFPR(0.700568793943248366792866380), - new FalconFPR(0.920318276709110566440076541), new FalconFPR(0.391170384302253888687512949), - new FalconFPR(-0.391170384302253888687512949), new FalconFPR(0.920318276709110566440076541), - new FalconFPR(0.374164062971457997104393020), new FalconFPR(0.927362525650401087274536959), - new FalconFPR(-0.927362525650401087274536959), new FalconFPR(0.374164062971457997104393020), - new FalconFPR(0.978948175319062194715480124), new FalconFPR(0.204108966092816874181696950), - new FalconFPR(-0.204108966092816874181696950), new FalconFPR(0.978948175319062194715480124), - new FalconFPR(0.547894059173100165608820571), new FalconFPR(0.836547727223511984524285790), - new FalconFPR(-0.836547727223511984524285790), new FalconFPR(0.547894059173100165608820571), - new FalconFPR(0.826321062845663480311195452), new FalconFPR(0.563199344013834115007363772), - new FalconFPR(-0.563199344013834115007363772), new FalconFPR(0.826321062845663480311195452), - new FalconFPR(0.186055151663446648105438304), new FalconFPR(0.982539302287441255907040396), - new FalconFPR(-0.982539302287441255907040396), new FalconFPR(0.186055151663446648105438304), - new FalconFPR(0.994240449453187946358413442), new FalconFPR(0.107172424956808849175529148), - new FalconFPR(-0.107172424956808849175529148), new FalconFPR(0.994240449453187946358413442), - new FalconFPR(0.627251815495144113509622565), new FalconFPR(0.778816512381475953374724325), - new FalconFPR(-0.778816512381475953374724325), new FalconFPR(0.627251815495144113509622565), - new FalconFPR(0.877545290207261291668470750), new FalconFPR(0.479493757660153026679839798), - new FalconFPR(-0.479493757660153026679839798), new FalconFPR(0.877545290207261291668470750), - new FalconFPR(0.281464937925757984095231007), new FalconFPR(0.959571513081984528335528181), - new FalconFPR(-0.959571513081984528335528181), new FalconFPR(0.281464937925757984095231007), - new FalconFPR(0.954228095109105629780430732), new FalconFPR(0.299079826308040476750336973), - new FalconFPR(-0.299079826308040476750336973), new FalconFPR(0.954228095109105629780430732), - new FalconFPR(0.463259783551860197390719637), new FalconFPR(0.886222530148880631647990821), - new FalconFPR(-0.886222530148880631647990821), new FalconFPR(0.463259783551860197390719637), - new FalconFPR(0.767138911935820381181694573), new FalconFPR(0.641481012808583151988739898), - new FalconFPR(-0.641481012808583151988739898), new FalconFPR(0.767138911935820381181694573), - new FalconFPR(0.088853552582524596561586535), new FalconFPR(0.996044700901251989887944810), - new FalconFPR(-0.996044700901251989887944810), new FalconFPR(0.088853552582524596561586535), - new FalconFPR(0.998301544933892840738782163), new FalconFPR(0.058258264500435759613979782), - new FalconFPR(-0.058258264500435759613979782), new FalconFPR(0.998301544933892840738782163), - new FalconFPR(0.664710978203344868130324985), new FalconFPR(0.747100605980180144323078847), - new FalconFPR(-0.747100605980180144323078847), new FalconFPR(0.664710978203344868130324985), - new FalconFPR(0.900015892016160228714535267), new FalconFPR(0.435857079922255491032544080), - new FalconFPR(-0.435857079922255491032544080), new FalconFPR(0.900015892016160228714535267), - new FalconFPR(0.328209843579092526107916817), new FalconFPR(0.944604837261480265659265493), - new FalconFPR(-0.944604837261480265659265493), new FalconFPR(0.328209843579092526107916817), - new FalconFPR(0.967753837093475465243391912), new FalconFPR(0.251897818154216950498106628), - new FalconFPR(-0.251897818154216950498106628), new FalconFPR(0.967753837093475465243391912), - new FalconFPR(0.506186645345155291048942344), new FalconFPR(0.862423956111040538690933878), - new FalconFPR(-0.862423956111040538690933878), new FalconFPR(0.506186645345155291048942344), - new FalconFPR(0.797690840943391108362662755), new FalconFPR(0.603066598540348201693430617), - new FalconFPR(-0.603066598540348201693430617), new FalconFPR(0.797690840943391108362662755), - new FalconFPR(0.137620121586486044948441663), new FalconFPR(0.990485084256457037998682243), - new FalconFPR(-0.990485084256457037998682243), new FalconFPR(0.137620121586486044948441663), - new FalconFPR(0.987784141644572154230969032), new FalconFPR(0.155828397654265235743101486), - new FalconFPR(-0.155828397654265235743101486), new FalconFPR(0.987784141644572154230969032), - new FalconFPR(0.588281548222645304786439813), new FalconFPR(0.808656181588174991946968128), - new FalconFPR(-0.808656181588174991946968128), new FalconFPR(0.588281548222645304786439813), - new FalconFPR(0.852960604930363657746588082), new FalconFPR(0.521975292937154342694258318), - new FalconFPR(-0.521975292937154342694258318), new FalconFPR(0.852960604930363657746588082), - new FalconFPR(0.234041958583543423191242045), new FalconFPR(0.972226497078936305708321144), - new FalconFPR(-0.972226497078936305708321144), new FalconFPR(0.234041958583543423191242045), - new FalconFPR(0.938403534063108112192420774), new FalconFPR(0.345541324963989065539191723), - new FalconFPR(-0.345541324963989065539191723), new FalconFPR(0.938403534063108112192420774), - new FalconFPR(0.419216888363223956433010020), new FalconFPR(0.907886116487666212038681480), - new FalconFPR(-0.907886116487666212038681480), new FalconFPR(0.419216888363223956433010020), - new FalconFPR(0.734738878095963464563223604), new FalconFPR(0.678350043129861486873655042), - new FalconFPR(-0.678350043129861486873655042), new FalconFPR(0.734738878095963464563223604), - new FalconFPR(0.039872927587739811128578738), new FalconFPR(0.999204758618363895492950001), - new FalconFPR(-0.999204758618363895492950001), new FalconFPR(0.039872927587739811128578738), - new FalconFPR(0.999430604555461772019008327), new FalconFPR(0.033741171851377584833716112), - new FalconFPR(-0.033741171851377584833716112), new FalconFPR(0.999430604555461772019008327), - new FalconFPR(0.682845546385248068164596123), new FalconFPR(0.730562769227827561177758850), - new FalconFPR(-0.730562769227827561177758850), new FalconFPR(0.682845546385248068164596123), - new FalconFPR(0.910441292258067196934095369), new FalconFPR(0.413638312238434547471944324), - new FalconFPR(-0.413638312238434547471944324), new FalconFPR(0.910441292258067196934095369), - new FalconFPR(0.351292756085567125601307623), new FalconFPR(0.936265667170278246576310996), - new FalconFPR(-0.936265667170278246576310996), new FalconFPR(0.351292756085567125601307623), - new FalconFPR(0.973644249650811925318383912), new FalconFPR(0.228072083170885739254457379), - new FalconFPR(-0.228072083170885739254457379), new FalconFPR(0.973644249650811925318383912), - new FalconFPR(0.527199134781901348464274575), new FalconFPR(0.849741768000852489471268395), - new FalconFPR(-0.849741768000852489471268395), new FalconFPR(0.527199134781901348464274575), - new FalconFPR(0.812250586585203913049744181), new FalconFPR(0.583308652937698294392830961), - new FalconFPR(-0.583308652937698294392830961), new FalconFPR(0.812250586585203913049744181), - new FalconFPR(0.161886393780111837641387995), new FalconFPR(0.986809401814185476970235952), - new FalconFPR(-0.986809401814185476970235952), new FalconFPR(0.161886393780111837641387995), - new FalconFPR(0.991310859846115418957349799), new FalconFPR(0.131540028702883111103387493), - new FalconFPR(-0.131540028702883111103387493), new FalconFPR(0.991310859846115418957349799), - new FalconFPR(0.607949784967773667243642671), new FalconFPR(0.793975477554337164895083757), - new FalconFPR(-0.793975477554337164895083757), new FalconFPR(0.607949784967773667243642671), - new FalconFPR(0.865513624090569082825488358), new FalconFPR(0.500885382611240786241285004), - new FalconFPR(-0.500885382611240786241285004), new FalconFPR(0.865513624090569082825488358), - new FalconFPR(0.257831102162159005614471295), new FalconFPR(0.966190003445412555433832961), - new FalconFPR(-0.966190003445412555433832961), new FalconFPR(0.257831102162159005614471295), - new FalconFPR(0.946600913083283570044599823), new FalconFPR(0.322407678801069848384807478), - new FalconFPR(-0.322407678801069848384807478), new FalconFPR(0.946600913083283570044599823), - new FalconFPR(0.441371268731716692879988968), new FalconFPR(0.897324580705418281231391836), - new FalconFPR(-0.897324580705418281231391836), new FalconFPR(0.441371268731716692879988968), - new FalconFPR(0.751165131909686411205819422), new FalconFPR(0.660114342067420478559490747), - new FalconFPR(-0.660114342067420478559490747), new FalconFPR(0.751165131909686411205819422), - new FalconFPR(0.064382630929857460819324537), new FalconFPR(0.997925286198596012623025462), - new FalconFPR(-0.997925286198596012623025462), new FalconFPR(0.064382630929857460819324537), - new FalconFPR(0.996571145790554847093566910), new FalconFPR(0.082740264549375693111987083), - new FalconFPR(-0.082740264549375693111987083), new FalconFPR(0.996571145790554847093566910), - new FalconFPR(0.646176012983316364832802220), new FalconFPR(0.763188417263381271704838297), - new FalconFPR(-0.763188417263381271704838297), new FalconFPR(0.646176012983316364832802220), - new FalconFPR(0.889048355854664562540777729), new FalconFPR(0.457813303598877221904961155), - new FalconFPR(-0.457813303598877221904961155), new FalconFPR(0.889048355854664562540777729), - new FalconFPR(0.304929229735402406490728633), new FalconFPR(0.952375012719765858529893608), - new FalconFPR(-0.952375012719765858529893608), new FalconFPR(0.304929229735402406490728633), - new FalconFPR(0.961280485811320641748659653), new FalconFPR(0.275571819310958163076425168), - new FalconFPR(-0.275571819310958163076425168), new FalconFPR(0.961280485811320641748659653), - new FalconFPR(0.484869248000791101822951699), new FalconFPR(0.874586652278176112634431897), - new FalconFPR(-0.874586652278176112634431897), new FalconFPR(0.484869248000791101822951699), - new FalconFPR(0.782650596166575738458949301), new FalconFPR(0.622461279374149972519166721), - new FalconFPR(-0.622461279374149972519166721), new FalconFPR(0.782650596166575738458949301), - new FalconFPR(0.113270952177564349018228733), new FalconFPR(0.993564135520595333782021697), - new FalconFPR(-0.993564135520595333782021697), new FalconFPR(0.113270952177564349018228733), - new FalconFPR(0.983662419211730274396237776), new FalconFPR(0.180022901405699522679906590), - new FalconFPR(-0.180022901405699522679906590), new FalconFPR(0.983662419211730274396237776), - new FalconFPR(0.568258952670131549790548489), new FalconFPR(0.822849781375826332046780034), - new FalconFPR(-0.822849781375826332046780034), new FalconFPR(0.568258952670131549790548489), - new FalconFPR(0.839893794195999504583383987), new FalconFPR(0.542750784864515906586768661), - new FalconFPR(-0.542750784864515906586768661), new FalconFPR(0.839893794195999504583383987), - new FalconFPR(0.210111836880469621717489972), new FalconFPR(0.977677357824509979943404762), - new FalconFPR(-0.977677357824509979943404762), new FalconFPR(0.210111836880469621717489972), - new FalconFPR(0.929640895843181265457918066), new FalconFPR(0.368466829953372331712746222), - new FalconFPR(-0.368466829953372331712746222), new FalconFPR(0.929640895843181265457918066), - new FalconFPR(0.396809987416710328595290911), new FalconFPR(0.917900775621390457642276297), - new FalconFPR(-0.917900775621390457642276297), new FalconFPR(0.396809987416710328595290911), - new FalconFPR(0.717870045055731736211325329), new FalconFPR(0.696177131491462944788582591), - new FalconFPR(-0.696177131491462944788582591), new FalconFPR(0.717870045055731736211325329), - new FalconFPR(0.015339206284988101044151868), new FalconFPR(0.999882347454212525633049627), - new FalconFPR(-0.999882347454212525633049627), new FalconFPR(0.015339206284988101044151868), - new FalconFPR(0.999769405351215321657617036), new FalconFPR(0.021474080275469507418374898), - new FalconFPR(-0.021474080275469507418374898), new FalconFPR(0.999769405351215321657617036), - new FalconFPR(0.691759258364157774906734132), new FalconFPR(0.722128193929215321243607198), - new FalconFPR(-0.722128193929215321243607198), new FalconFPR(0.691759258364157774906734132), - new FalconFPR(0.915448716088267819566431292), new FalconFPR(0.402434650859418441082533934), - new FalconFPR(-0.402434650859418441082533934), new FalconFPR(0.915448716088267819566431292), - new FalconFPR(0.362755724367397216204854462), new FalconFPR(0.931884265581668106718557199), - new FalconFPR(-0.931884265581668106718557199), new FalconFPR(0.362755724367397216204854462), - new FalconFPR(0.976369731330021149312732194), new FalconFPR(0.216106797076219509948385131), - new FalconFPR(-0.216106797076219509948385131), new FalconFPR(0.976369731330021149312732194), - new FalconFPR(0.537587076295645482502214932), new FalconFPR(0.843208239641845437161743865), - new FalconFPR(-0.843208239641845437161743865), new FalconFPR(0.537587076295645482502214932), - new FalconFPR(0.819347520076796960824689637), new FalconFPR(0.573297166698042212820171239), - new FalconFPR(-0.573297166698042212820171239), new FalconFPR(0.819347520076796960824689637), - new FalconFPR(0.173983873387463827950700807), new FalconFPR(0.984748501801904218556553176), - new FalconFPR(-0.984748501801904218556553176), new FalconFPR(0.173983873387463827950700807), - new FalconFPR(0.992850414459865090793563344), new FalconFPR(0.119365214810991364593637790), - new FalconFPR(-0.119365214810991364593637790), new FalconFPR(0.992850414459865090793563344), - new FalconFPR(0.617647307937803932403979402), new FalconFPR(0.786455213599085757522319464), - new FalconFPR(-0.786455213599085757522319464), new FalconFPR(0.617647307937803932403979402), - new FalconFPR(0.871595086655951034842481435), new FalconFPR(0.490226483288291154229598449), - new FalconFPR(-0.490226483288291154229598449), new FalconFPR(0.871595086655951034842481435), - new FalconFPR(0.269668325572915106525464462), new FalconFPR(0.962953266873683886347921481), - new FalconFPR(-0.962953266873683886347921481), new FalconFPR(0.269668325572915106525464462), - new FalconFPR(0.950486073949481721759926101), new FalconFPR(0.310767152749611495835997250), - new FalconFPR(-0.310767152749611495835997250), new FalconFPR(0.950486073949481721759926101), - new FalconFPR(0.452349587233770874133026703), new FalconFPR(0.891840709392342727796478697), - new FalconFPR(-0.891840709392342727796478697), new FalconFPR(0.452349587233770874133026703), - new FalconFPR(0.759209188978388033485525443), new FalconFPR(0.650846684996380915068975573), - new FalconFPR(-0.650846684996380915068975573), new FalconFPR(0.759209188978388033485525443), - new FalconFPR(0.076623861392031492278332463), new FalconFPR(0.997060070339482978987989949), - new FalconFPR(-0.997060070339482978987989949), new FalconFPR(0.076623861392031492278332463), - new FalconFPR(0.997511456140303459699448390), new FalconFPR(0.070504573389613863027351471), - new FalconFPR(-0.070504573389613863027351471), new FalconFPR(0.997511456140303459699448390), - new FalconFPR(0.655492852999615385312679701), new FalconFPR(0.755201376896536527598710756), - new FalconFPR(-0.755201376896536527598710756), new FalconFPR(0.655492852999615385312679701), - new FalconFPR(0.894599485631382678433072126), new FalconFPR(0.446868840162374195353044389), - new FalconFPR(-0.446868840162374195353044389), new FalconFPR(0.894599485631382678433072126), - new FalconFPR(0.316593375556165867243047035), new FalconFPR(0.948561349915730288158494826), - new FalconFPR(-0.948561349915730288158494826), new FalconFPR(0.316593375556165867243047035), - new FalconFPR(0.964589793289812723836432159), new FalconFPR(0.263754678974831383611349322), - new FalconFPR(-0.263754678974831383611349322), new FalconFPR(0.964589793289812723836432159), - new FalconFPR(0.495565261825772531150266670), new FalconFPR(0.868570705971340895340449876), - new FalconFPR(-0.868570705971340895340449876), new FalconFPR(0.495565261825772531150266670), - new FalconFPR(0.790230221437310055030217152), new FalconFPR(0.612810082429409703935211936), - new FalconFPR(-0.612810082429409703935211936), new FalconFPR(0.790230221437310055030217152), - new FalconFPR(0.125454983411546238542336453), new FalconFPR(0.992099313142191757112085445), - new FalconFPR(-0.992099313142191757112085445), new FalconFPR(0.125454983411546238542336453), - new FalconFPR(0.985797509167567424700995000), new FalconFPR(0.167938294974731178054745536), - new FalconFPR(-0.167938294974731178054745536), new FalconFPR(0.985797509167567424700995000), - new FalconFPR(0.578313796411655563342245019), new FalconFPR(0.815814410806733789010772660), - new FalconFPR(-0.815814410806733789010772660), new FalconFPR(0.578313796411655563342245019), - new FalconFPR(0.846490938774052078300544488), new FalconFPR(0.532403127877197971442805218), - new FalconFPR(-0.532403127877197971442805218), new FalconFPR(0.846490938774052078300544488), - new FalconFPR(0.222093620973203534094094721), new FalconFPR(0.975025345066994146844913468), - new FalconFPR(-0.975025345066994146844913468), new FalconFPR(0.222093620973203534094094721), - new FalconFPR(0.934092550404258914729877883), new FalconFPR(0.357030961233430032614954036), - new FalconFPR(-0.357030961233430032614954036), new FalconFPR(0.934092550404258914729877883), - new FalconFPR(0.408044162864978680820747499), new FalconFPR(0.912962190428398164628018233), - new FalconFPR(-0.912962190428398164628018233), new FalconFPR(0.408044162864978680820747499), - new FalconFPR(0.726359155084345976817494315), new FalconFPR(0.687315340891759108199186948), - new FalconFPR(-0.687315340891759108199186948), new FalconFPR(0.726359155084345976817494315), - new FalconFPR(0.027608145778965741612354872), new FalconFPR(0.999618822495178597116830637), - new FalconFPR(-0.999618822495178597116830637), new FalconFPR(0.027608145778965741612354872), - new FalconFPR(0.998941293186856850633930266), new FalconFPR(0.046003182130914628814301788), - new FalconFPR(-0.046003182130914628814301788), new FalconFPR(0.998941293186856850633930266), - new FalconFPR(0.673829000378756060917568372), new FalconFPR(0.738887324460615147933116508), - new FalconFPR(-0.738887324460615147933116508), new FalconFPR(0.673829000378756060917568372), - new FalconFPR(0.905296759318118774354048329), new FalconFPR(0.424779681209108833357226189), - new FalconFPR(-0.424779681209108833357226189), new FalconFPR(0.905296759318118774354048329), - new FalconFPR(0.339776884406826857828825803), new FalconFPR(0.940506070593268323787291309), - new FalconFPR(-0.940506070593268323787291309), new FalconFPR(0.339776884406826857828825803), - new FalconFPR(0.970772140728950302138169611), new FalconFPR(0.240003022448741486568922365), - new FalconFPR(-0.240003022448741486568922365), new FalconFPR(0.970772140728950302138169611), - new FalconFPR(0.516731799017649881508753876), new FalconFPR(0.856147328375194481019630732), - new FalconFPR(-0.856147328375194481019630732), new FalconFPR(0.516731799017649881508753876), - new FalconFPR(0.805031331142963597922659282), new FalconFPR(0.593232295039799808047809426), - new FalconFPR(-0.593232295039799808047809426), new FalconFPR(0.805031331142963597922659282), - new FalconFPR(0.149764534677321517229695737), new FalconFPR(0.988721691960323767604516485), - new FalconFPR(-0.988721691960323767604516485), new FalconFPR(0.149764534677321517229695737), - new FalconFPR(0.989622017463200834623694454), new FalconFPR(0.143695033150294454819773349), - new FalconFPR(-0.143695033150294454819773349), new FalconFPR(0.989622017463200834623694454), - new FalconFPR(0.598160706996342311724958652), new FalconFPR(0.801376171723140219430247777), - new FalconFPR(-0.801376171723140219430247777), new FalconFPR(0.598160706996342311724958652), - new FalconFPR(0.859301818357008404783582139), new FalconFPR(0.511468850437970399504391001), - new FalconFPR(-0.511468850437970399504391001), new FalconFPR(0.859301818357008404783582139), - new FalconFPR(0.245955050335794611599924709), new FalconFPR(0.969281235356548486048290738), - new FalconFPR(-0.969281235356548486048290738), new FalconFPR(0.245955050335794611599924709), - new FalconFPR(0.942573197601446879280758735), new FalconFPR(0.333999651442009404650865481), - new FalconFPR(-0.333999651442009404650865481), new FalconFPR(0.942573197601446879280758735), - new FalconFPR(0.430326481340082633908199031), new FalconFPR(0.902673318237258806751502391), - new FalconFPR(-0.902673318237258806751502391), new FalconFPR(0.430326481340082633908199031), - new FalconFPR(0.743007952135121693517362293), new FalconFPR(0.669282588346636065720696366), - new FalconFPR(-0.669282588346636065720696366), new FalconFPR(0.743007952135121693517362293), - new FalconFPR(0.052131704680283321236358216), new FalconFPR(0.998640218180265222418199049), - new FalconFPR(-0.998640218180265222418199049), new FalconFPR(0.052131704680283321236358216), - new FalconFPR(0.995480755491926941769171600), new FalconFPR(0.094963495329638998938034312), - new FalconFPR(-0.094963495329638998938034312), new FalconFPR(0.995480755491926941769171600), - new FalconFPR(0.636761861236284230413943435), new FalconFPR(0.771060524261813773200605759), - new FalconFPR(-0.771060524261813773200605759), new FalconFPR(0.636761861236284230413943435), - new FalconFPR(0.883363338665731594736308015), new FalconFPR(0.468688822035827933697617870), - new FalconFPR(-0.468688822035827933697617870), new FalconFPR(0.883363338665731594736308015), - new FalconFPR(0.293219162694258650606608599), new FalconFPR(0.956045251349996443270479823), - new FalconFPR(-0.956045251349996443270479823), new FalconFPR(0.293219162694258650606608599), - new FalconFPR(0.957826413027532890321037029), new FalconFPR(0.287347459544729526477331841), - new FalconFPR(-0.287347459544729526477331841), new FalconFPR(0.957826413027532890321037029), - new FalconFPR(0.474100214650550014398580015), new FalconFPR(0.880470889052160770806542929), - new FalconFPR(-0.880470889052160770806542929), new FalconFPR(0.474100214650550014398580015), - new FalconFPR(0.774953106594873878359129282), new FalconFPR(0.632018735939809021909403706), - new FalconFPR(-0.632018735939809021909403706), new FalconFPR(0.774953106594873878359129282), - new FalconFPR(0.101069862754827824987887585), new FalconFPR(0.994879330794805620591166107), - new FalconFPR(-0.994879330794805620591166107), new FalconFPR(0.101069862754827824987887585), - new FalconFPR(0.981379193313754574318224190), new FalconFPR(0.192080397049892441679288205), - new FalconFPR(-0.192080397049892441679288205), new FalconFPR(0.981379193313754574318224190), - new FalconFPR(0.558118531220556115693702964), new FalconFPR(0.829761233794523042469023765), - new FalconFPR(-0.829761233794523042469023765), new FalconFPR(0.558118531220556115693702964), - new FalconFPR(0.833170164701913186439915922), new FalconFPR(0.553016705580027531764226988), - new FalconFPR(-0.553016705580027531764226988), new FalconFPR(0.833170164701913186439915922), - new FalconFPR(0.198098410717953586179324918), new FalconFPR(0.980182135968117392690210009), - new FalconFPR(-0.980182135968117392690210009), new FalconFPR(0.198098410717953586179324918), - new FalconFPR(0.925049240782677590302371869), new FalconFPR(0.379847208924051170576281147), - new FalconFPR(-0.379847208924051170576281147), new FalconFPR(0.925049240782677590302371869), - new FalconFPR(0.385516053843918864075607949), new FalconFPR(0.922701128333878570437264227), - new FalconFPR(-0.922701128333878570437264227), new FalconFPR(0.385516053843918864075607949), - new FalconFPR(0.709272826438865651316533772), new FalconFPR(0.704934080375904908852523758), - new FalconFPR(-0.704934080375904908852523758), new FalconFPR(0.709272826438865651316533772), - new FalconFPR(0.003067956762965976270145365), new FalconFPR(0.999995293809576171511580126), - new FalconFPR(-0.999995293809576171511580126), new FalconFPR(0.003067956762965976270145365) + fpr_gm_tab = new double[]{ + 0, 0, /* unused */ + -0.000000000000000000000000000, 1.000000000000000000000000000, + 0.707106781186547524400844362, 0.707106781186547524400844362, + -0.707106781186547524400844362, 0.707106781186547524400844362, + 0.923879532511286756128183189, 0.382683432365089771728459984, + -0.382683432365089771728459984, 0.923879532511286756128183189, + 0.382683432365089771728459984, 0.923879532511286756128183189, + -0.923879532511286756128183189, 0.382683432365089771728459984, + 0.980785280403230449126182236, 0.195090322016128267848284868, + -0.195090322016128267848284868, 0.980785280403230449126182236, + 0.555570233019602224742830814, 0.831469612302545237078788378, + -0.831469612302545237078788378, 0.555570233019602224742830814, + 0.831469612302545237078788378, 0.555570233019602224742830814, + -0.555570233019602224742830814, 0.831469612302545237078788378, + 0.195090322016128267848284868, 0.980785280403230449126182236, + -0.980785280403230449126182236, 0.195090322016128267848284868, + 0.995184726672196886244836953, 0.098017140329560601994195564, + -0.098017140329560601994195564, 0.995184726672196886244836953, + 0.634393284163645498215171613, 0.773010453362736960810906610, + -0.773010453362736960810906610, 0.634393284163645498215171613, + 0.881921264348355029712756864, 0.471396736825997648556387626, + -0.471396736825997648556387626, 0.881921264348355029712756864, + 0.290284677254462367636192376, 0.956940335732208864935797887, + -0.956940335732208864935797887, 0.290284677254462367636192376, + 0.956940335732208864935797887, 0.290284677254462367636192376, + -0.290284677254462367636192376, 0.956940335732208864935797887, + 0.471396736825997648556387626, 0.881921264348355029712756864, + -0.881921264348355029712756864, 0.471396736825997648556387626, + 0.773010453362736960810906610, 0.634393284163645498215171613, + -0.634393284163645498215171613, 0.773010453362736960810906610, + 0.098017140329560601994195564, 0.995184726672196886244836953, + -0.995184726672196886244836953, 0.098017140329560601994195564, + 0.998795456205172392714771605, 0.049067674327418014254954977, + -0.049067674327418014254954977, 0.998795456205172392714771605, + 0.671558954847018400625376850, 0.740951125354959091175616897, + -0.740951125354959091175616897, 0.671558954847018400625376850, + 0.903989293123443331586200297, 0.427555093430282094320966857, + -0.427555093430282094320966857, 0.903989293123443331586200297, + 0.336889853392220050689253213, 0.941544065183020778412509403, + -0.941544065183020778412509403, 0.336889853392220050689253213, + 0.970031253194543992603984207, 0.242980179903263889948274162, + -0.242980179903263889948274162, 0.970031253194543992603984207, + 0.514102744193221726593693839, 0.857728610000272069902269984, + -0.857728610000272069902269984, 0.514102744193221726593693839, + 0.803207531480644909806676513, 0.595699304492433343467036529, + -0.595699304492433343467036529, 0.803207531480644909806676513, + 0.146730474455361751658850130, 0.989176509964780973451673738, + -0.989176509964780973451673738, 0.146730474455361751658850130, + 0.989176509964780973451673738, 0.146730474455361751658850130, + -0.146730474455361751658850130, 0.989176509964780973451673738, + 0.595699304492433343467036529, 0.803207531480644909806676513, + -0.803207531480644909806676513, 0.595699304492433343467036529, + 0.857728610000272069902269984, 0.514102744193221726593693839, + -0.514102744193221726593693839, 0.857728610000272069902269984, + 0.242980179903263889948274162, 0.970031253194543992603984207, + -0.970031253194543992603984207, 0.242980179903263889948274162, + 0.941544065183020778412509403, 0.336889853392220050689253213, + -0.336889853392220050689253213, 0.941544065183020778412509403, + 0.427555093430282094320966857, 0.903989293123443331586200297, + -0.903989293123443331586200297, 0.427555093430282094320966857, + 0.740951125354959091175616897, 0.671558954847018400625376850, + -0.671558954847018400625376850, 0.740951125354959091175616897, + 0.049067674327418014254954977, 0.998795456205172392714771605, + -0.998795456205172392714771605, 0.049067674327418014254954977, + 0.999698818696204220115765650, 0.024541228522912288031734529, + -0.024541228522912288031734529, 0.999698818696204220115765650, + 0.689540544737066924616730630, 0.724247082951466920941069243, + -0.724247082951466920941069243, 0.689540544737066924616730630, + 0.914209755703530654635014829, 0.405241314004989870908481306, + -0.405241314004989870908481306, 0.914209755703530654635014829, + 0.359895036534988148775104572, 0.932992798834738887711660256, + -0.932992798834738887711660256, 0.359895036534988148775104572, + 0.975702130038528544460395766, 0.219101240156869797227737547, + -0.219101240156869797227737547, 0.975702130038528544460395766, + 0.534997619887097210663076905, 0.844853565249707073259571205, + -0.844853565249707073259571205, 0.534997619887097210663076905, + 0.817584813151583696504920884, 0.575808191417845300745972454, + -0.575808191417845300745972454, 0.817584813151583696504920884, + 0.170961888760301226363642357, 0.985277642388941244774018433, + -0.985277642388941244774018433, 0.170961888760301226363642357, + 0.992479534598709998156767252, 0.122410675199216198498704474, + -0.122410675199216198498704474, 0.992479534598709998156767252, + 0.615231590580626845484913563, 0.788346427626606262009164705, + -0.788346427626606262009164705, 0.615231590580626845484913563, + 0.870086991108711418652292404, 0.492898192229784036873026689, + -0.492898192229784036873026689, 0.870086991108711418652292404, + 0.266712757474898386325286515, 0.963776065795439866686464356, + -0.963776065795439866686464356, 0.266712757474898386325286515, + 0.949528180593036667195936074, 0.313681740398891476656478846, + -0.313681740398891476656478846, 0.949528180593036667195936074, + 0.449611329654606600046294579, 0.893224301195515320342416447, + -0.893224301195515320342416447, 0.449611329654606600046294579, + 0.757208846506484547575464054, 0.653172842953776764084203014, + -0.653172842953776764084203014, 0.757208846506484547575464054, + 0.073564563599667423529465622, 0.997290456678690216135597140, + -0.997290456678690216135597140, 0.073564563599667423529465622, + 0.997290456678690216135597140, 0.073564563599667423529465622, + -0.073564563599667423529465622, 0.997290456678690216135597140, + 0.653172842953776764084203014, 0.757208846506484547575464054, + -0.757208846506484547575464054, 0.653172842953776764084203014, + 0.893224301195515320342416447, 0.449611329654606600046294579, + -0.449611329654606600046294579, 0.893224301195515320342416447, + 0.313681740398891476656478846, 0.949528180593036667195936074, + -0.949528180593036667195936074, 0.313681740398891476656478846, + 0.963776065795439866686464356, 0.266712757474898386325286515, + -0.266712757474898386325286515, 0.963776065795439866686464356, + 0.492898192229784036873026689, 0.870086991108711418652292404, + -0.870086991108711418652292404, 0.492898192229784036873026689, + 0.788346427626606262009164705, 0.615231590580626845484913563, + -0.615231590580626845484913563, 0.788346427626606262009164705, + 0.122410675199216198498704474, 0.992479534598709998156767252, + -0.992479534598709998156767252, 0.122410675199216198498704474, + 0.985277642388941244774018433, 0.170961888760301226363642357, + -0.170961888760301226363642357, 0.985277642388941244774018433, + 0.575808191417845300745972454, 0.817584813151583696504920884, + -0.817584813151583696504920884, 0.575808191417845300745972454, + 0.844853565249707073259571205, 0.534997619887097210663076905, + -0.534997619887097210663076905, 0.844853565249707073259571205, + 0.219101240156869797227737547, 0.975702130038528544460395766, + -0.975702130038528544460395766, 0.219101240156869797227737547, + 0.932992798834738887711660256, 0.359895036534988148775104572, + -0.359895036534988148775104572, 0.932992798834738887711660256, + 0.405241314004989870908481306, 0.914209755703530654635014829, + -0.914209755703530654635014829, 0.405241314004989870908481306, + 0.724247082951466920941069243, 0.689540544737066924616730630, + -0.689540544737066924616730630, 0.724247082951466920941069243, + 0.024541228522912288031734529, 0.999698818696204220115765650, + -0.999698818696204220115765650, 0.024541228522912288031734529, + 0.999924701839144540921646491, 0.012271538285719926079408262, + -0.012271538285719926079408262, 0.999924701839144540921646491, + 0.698376249408972853554813503, 0.715730825283818654125532623, + -0.715730825283818654125532623, 0.698376249408972853554813503, + 0.919113851690057743908477789, 0.393992040061048108596188661, + -0.393992040061048108596188661, 0.919113851690057743908477789, + 0.371317193951837543411934967, 0.928506080473215565937167396, + -0.928506080473215565937167396, 0.371317193951837543411934967, + 0.978317370719627633106240097, 0.207111376192218549708116020, + -0.207111376192218549708116020, 0.978317370719627633106240097, + 0.545324988422046422313987347, 0.838224705554838043186996856, + -0.838224705554838043186996856, 0.545324988422046422313987347, + 0.824589302785025264474803737, 0.565731810783613197389765011, + -0.565731810783613197389765011, 0.824589302785025264474803737, + 0.183039887955140958516532578, 0.983105487431216327180301155, + -0.983105487431216327180301155, 0.183039887955140958516532578, + 0.993906970002356041546922813, 0.110222207293883058807899140, + -0.110222207293883058807899140, 0.993906970002356041546922813, + 0.624859488142386377084072816, 0.780737228572094478301588484, + -0.780737228572094478301588484, 0.624859488142386377084072816, + 0.876070094195406607095844268, 0.482183772079122748517344481, + -0.482183772079122748517344481, 0.876070094195406607095844268, + 0.278519689385053105207848526, 0.960430519415565811199035138, + -0.960430519415565811199035138, 0.278519689385053105207848526, + 0.953306040354193836916740383, 0.302005949319228067003463232, + -0.302005949319228067003463232, 0.953306040354193836916740383, + 0.460538710958240023633181487, 0.887639620402853947760181617, + -0.887639620402853947760181617, 0.460538710958240023633181487, + 0.765167265622458925888815999, 0.643831542889791465068086063, + -0.643831542889791465068086063, 0.765167265622458925888815999, + 0.085797312344439890461556332, 0.996312612182778012627226190, + -0.996312612182778012627226190, 0.085797312344439890461556332, + 0.998118112900149207125155861, 0.061320736302208577782614593, + -0.061320736302208577782614593, 0.998118112900149207125155861, + 0.662415777590171761113069817, 0.749136394523459325469203257, + -0.749136394523459325469203257, 0.662415777590171761113069817, + 0.898674465693953843041976744, 0.438616238538527637647025738, + -0.438616238538527637647025738, 0.898674465693953843041976744, + 0.325310292162262934135954708, 0.945607325380521325730945387, + -0.945607325380521325730945387, 0.325310292162262934135954708, + 0.966976471044852109087220226, 0.254865659604514571553980779, + -0.254865659604514571553980779, 0.966976471044852109087220226, + 0.503538383725717558691867071, 0.863972856121586737918147054, + -0.863972856121586737918147054, 0.503538383725717558691867071, + 0.795836904608883536262791915, 0.605511041404325513920626941, + -0.605511041404325513920626941, 0.795836904608883536262791915, + 0.134580708507126186316358409, 0.990902635427780025108237011, + -0.990902635427780025108237011, 0.134580708507126186316358409, + 0.987301418157858382399815802, 0.158858143333861441684385360, + -0.158858143333861441684385360, 0.987301418157858382399815802, + 0.585797857456438860328080838, 0.810457198252594791726703434, + -0.810457198252594791726703434, 0.585797857456438860328080838, + 0.851355193105265142261290312, 0.524589682678468906215098464, + -0.524589682678468906215098464, 0.851355193105265142261290312, + 0.231058108280671119643236018, 0.972939952205560145467720114, + -0.972939952205560145467720114, 0.231058108280671119643236018, + 0.937339011912574923201899593, 0.348418680249434568419308588, + -0.348418680249434568419308588, 0.937339011912574923201899593, + 0.416429560097637182562598911, 0.909167983090522376563884788, + -0.909167983090522376563884788, 0.416429560097637182562598911, + 0.732654271672412834615546649, 0.680600997795453050594430464, + -0.680600997795453050594430464, 0.732654271672412834615546649, + 0.036807222941358832324332691, 0.999322384588349500896221011, + -0.999322384588349500896221011, 0.036807222941358832324332691, + 0.999322384588349500896221011, 0.036807222941358832324332691, + -0.036807222941358832324332691, 0.999322384588349500896221011, + 0.680600997795453050594430464, 0.732654271672412834615546649, + -0.732654271672412834615546649, 0.680600997795453050594430464, + 0.909167983090522376563884788, 0.416429560097637182562598911, + -0.416429560097637182562598911, 0.909167983090522376563884788, + 0.348418680249434568419308588, 0.937339011912574923201899593, + -0.937339011912574923201899593, 0.348418680249434568419308588, + 0.972939952205560145467720114, 0.231058108280671119643236018, + -0.231058108280671119643236018, 0.972939952205560145467720114, + 0.524589682678468906215098464, 0.851355193105265142261290312, + -0.851355193105265142261290312, 0.524589682678468906215098464, + 0.810457198252594791726703434, 0.585797857456438860328080838, + -0.585797857456438860328080838, 0.810457198252594791726703434, + 0.158858143333861441684385360, 0.987301418157858382399815802, + -0.987301418157858382399815802, 0.158858143333861441684385360, + 0.990902635427780025108237011, 0.134580708507126186316358409, + -0.134580708507126186316358409, 0.990902635427780025108237011, + 0.605511041404325513920626941, 0.795836904608883536262791915, + -0.795836904608883536262791915, 0.605511041404325513920626941, + 0.863972856121586737918147054, 0.503538383725717558691867071, + -0.503538383725717558691867071, 0.863972856121586737918147054, + 0.254865659604514571553980779, 0.966976471044852109087220226, + -0.966976471044852109087220226, 0.254865659604514571553980779, + 0.945607325380521325730945387, 0.325310292162262934135954708, + -0.325310292162262934135954708, 0.945607325380521325730945387, + 0.438616238538527637647025738, 0.898674465693953843041976744, + -0.898674465693953843041976744, 0.438616238538527637647025738, + 0.749136394523459325469203257, 0.662415777590171761113069817, + -0.662415777590171761113069817, 0.749136394523459325469203257, + 0.061320736302208577782614593, 0.998118112900149207125155861, + -0.998118112900149207125155861, 0.061320736302208577782614593, + 0.996312612182778012627226190, 0.085797312344439890461556332, + -0.085797312344439890461556332, 0.996312612182778012627226190, + 0.643831542889791465068086063, 0.765167265622458925888815999, + -0.765167265622458925888815999, 0.643831542889791465068086063, + 0.887639620402853947760181617, 0.460538710958240023633181487, + -0.460538710958240023633181487, 0.887639620402853947760181617, + 0.302005949319228067003463232, 0.953306040354193836916740383, + -0.953306040354193836916740383, 0.302005949319228067003463232, + 0.960430519415565811199035138, 0.278519689385053105207848526, + -0.278519689385053105207848526, 0.960430519415565811199035138, + 0.482183772079122748517344481, 0.876070094195406607095844268, + -0.876070094195406607095844268, 0.482183772079122748517344481, + 0.780737228572094478301588484, 0.624859488142386377084072816, + -0.624859488142386377084072816, 0.780737228572094478301588484, + 0.110222207293883058807899140, 0.993906970002356041546922813, + -0.993906970002356041546922813, 0.110222207293883058807899140, + 0.983105487431216327180301155, 0.183039887955140958516532578, + -0.183039887955140958516532578, 0.983105487431216327180301155, + 0.565731810783613197389765011, 0.824589302785025264474803737, + -0.824589302785025264474803737, 0.565731810783613197389765011, + 0.838224705554838043186996856, 0.545324988422046422313987347, + -0.545324988422046422313987347, 0.838224705554838043186996856, + 0.207111376192218549708116020, 0.978317370719627633106240097, + -0.978317370719627633106240097, 0.207111376192218549708116020, + 0.928506080473215565937167396, 0.371317193951837543411934967, + -0.371317193951837543411934967, 0.928506080473215565937167396, + 0.393992040061048108596188661, 0.919113851690057743908477789, + -0.919113851690057743908477789, 0.393992040061048108596188661, + 0.715730825283818654125532623, 0.698376249408972853554813503, + -0.698376249408972853554813503, 0.715730825283818654125532623, + 0.012271538285719926079408262, 0.999924701839144540921646491, + -0.999924701839144540921646491, 0.012271538285719926079408262, + 0.999981175282601142656990438, 0.006135884649154475359640235, + -0.006135884649154475359640235, 0.999981175282601142656990438, + 0.702754744457225302452914421, 0.711432195745216441522130290, + -0.711432195745216441522130290, 0.702754744457225302452914421, + 0.921514039342041943465396332, 0.388345046698826291624993541, + -0.388345046698826291624993541, 0.921514039342041943465396332, + 0.377007410216418256726567823, 0.926210242138311341974793388, + -0.926210242138311341974793388, 0.377007410216418256726567823, + 0.979569765685440534439326110, 0.201104634842091911558443546, + -0.201104634842091911558443546, 0.979569765685440534439326110, + 0.550457972936604802977289893, 0.834862874986380056304401383, + -0.834862874986380056304401383, 0.550457972936604802977289893, + 0.828045045257755752067527592, 0.560661576197336023839710223, + -0.560661576197336023839710223, 0.828045045257755752067527592, + 0.189068664149806212754997837, 0.981963869109555264072848154, + -0.981963869109555264072848154, 0.189068664149806212754997837, + 0.994564570734255452119106243, 0.104121633872054579120943880, + -0.104121633872054579120943880, 0.994564570734255452119106243, + 0.629638238914927025372981341, 0.776888465673232450040827983, + -0.776888465673232450040827983, 0.629638238914927025372981341, + 0.879012226428633477831323711, 0.476799230063322133342158117, + -0.476799230063322133342158117, 0.879012226428633477831323711, + 0.284407537211271843618310615, 0.958703474895871555374645792, + -0.958703474895871555374645792, 0.284407537211271843618310615, + 0.955141168305770721498157712, 0.296150888243623824121786128, + -0.296150888243623824121786128, 0.955141168305770721498157712, + 0.465976495767966177902756065, 0.884797098430937780104007041, + -0.884797098430937780104007041, 0.465976495767966177902756065, + 0.769103337645579639346626069, 0.639124444863775743801488193, + -0.639124444863775743801488193, 0.769103337645579639346626069, + 0.091908956497132728624990979, 0.995767414467659793982495643, + -0.995767414467659793982495643, 0.091908956497132728624990979, + 0.998475580573294752208559038, 0.055195244349689939809447526, + -0.055195244349689939809447526, 0.998475580573294752208559038, + 0.666999922303637506650154222, 0.745057785441465962407907310, + -0.745057785441465962407907310, 0.666999922303637506650154222, + 0.901348847046022014570746093, 0.433093818853151968484222638, + -0.433093818853151968484222638, 0.901348847046022014570746093, + 0.331106305759876401737190737, 0.943593458161960361495301445, + -0.943593458161960361495301445, 0.331106305759876401737190737, + 0.968522094274417316221088329, 0.248927605745720168110682816, + -0.248927605745720168110682816, 0.968522094274417316221088329, + 0.508830142543107036931749324, 0.860866938637767279344583877, + -0.860866938637767279344583877, 0.508830142543107036931749324, + 0.799537269107905033500246232, 0.600616479383868926653875896, + -0.600616479383868926653875896, 0.799537269107905033500246232, + 0.140658239332849230714788846, 0.990058210262297105505906464, + -0.990058210262297105505906464, 0.140658239332849230714788846, + 0.988257567730749491404792538, 0.152797185258443427720336613, + -0.152797185258443427720336613, 0.988257567730749491404792538, + 0.590759701858874228423887908, 0.806847553543799272206514313, + -0.806847553543799272206514313, 0.590759701858874228423887908, + 0.854557988365400520767862276, 0.519355990165589587361829932, + -0.519355990165589587361829932, 0.854557988365400520767862276, + 0.237023605994367206867735915, 0.971503890986251775537099622, + -0.971503890986251775537099622, 0.237023605994367206867735915, + 0.939459223602189911962669246, 0.342660717311994397592781983, + -0.342660717311994397592781983, 0.939459223602189911962669246, + 0.422000270799799685941287941, 0.906595704514915365332960588, + -0.906595704514915365332960588, 0.422000270799799685941287941, + 0.736816568877369875090132520, 0.676092703575315960360419228, + -0.676092703575315960360419228, 0.736816568877369875090132520, + 0.042938256934940823077124540, 0.999077727752645382888781997, + -0.999077727752645382888781997, 0.042938256934940823077124540, + 0.999529417501093163079703322, 0.030674803176636625934021028, + -0.030674803176636625934021028, 0.999529417501093163079703322, + 0.685083667772700381362052545, 0.728464390448225196492035438, + -0.728464390448225196492035438, 0.685083667772700381362052545, + 0.911706032005429851404397325, 0.410843171057903942183466675, + -0.410843171057903942183466675, 0.911706032005429851404397325, + 0.354163525420490382357395796, 0.935183509938947577642207480, + -0.935183509938947577642207480, 0.354163525420490382357395796, + 0.974339382785575860518721668, 0.225083911359792835991642120, + -0.225083911359792835991642120, 0.974339382785575860518721668, + 0.529803624686294668216054671, 0.848120344803297251279133563, + -0.848120344803297251279133563, 0.529803624686294668216054671, + 0.814036329705948361654516690, 0.580813958095764545075595272, + -0.580813958095764545075595272, 0.814036329705948361654516690, + 0.164913120489969921418189113, 0.986308097244598647863297524, + -0.986308097244598647863297524, 0.164913120489969921418189113, + 0.991709753669099522860049931, 0.128498110793793172624415589, + -0.128498110793793172624415589, 0.991709753669099522860049931, + 0.610382806276309452716352152, 0.792106577300212351782342879, + -0.792106577300212351782342879, 0.610382806276309452716352152, + 0.867046245515692651480195629, 0.498227666972781852410983869, + -0.498227666972781852410983869, 0.867046245515692651480195629, + 0.260794117915275518280186509, 0.965394441697689374550843858, + -0.965394441697689374550843858, 0.260794117915275518280186509, + 0.947585591017741134653387321, 0.319502030816015677901518272, + -0.319502030816015677901518272, 0.947585591017741134653387321, + 0.444122144570429231642069418, 0.895966249756185155914560282, + -0.895966249756185155914560282, 0.444122144570429231642069418, + 0.753186799043612482483430486, 0.657806693297078656931182264, + -0.657806693297078656931182264, 0.753186799043612482483430486, + 0.067443919563664057897972422, 0.997723066644191609848546728, + -0.997723066644191609848546728, 0.067443919563664057897972422, + 0.996820299291165714972629398, 0.079682437971430121147120656, + -0.079682437971430121147120656, 0.996820299291165714972629398, + 0.648514401022112445084560551, 0.761202385484261814029709836, + -0.761202385484261814029709836, 0.648514401022112445084560551, + 0.890448723244757889952150560, 0.455083587126343823535869268, + -0.455083587126343823535869268, 0.890448723244757889952150560, + 0.307849640041534893682063646, 0.951435020969008369549175569, + -0.951435020969008369549175569, 0.307849640041534893682063646, + 0.962121404269041595429604316, 0.272621355449948984493347477, + -0.272621355449948984493347477, 0.962121404269041595429604316, + 0.487550160148435954641485027, 0.873094978418290098636085973, + -0.873094978418290098636085973, 0.487550160148435954641485027, + 0.784556597155575233023892575, 0.620057211763289178646268191, + -0.620057211763289178646268191, 0.784556597155575233023892575, + 0.116318630911904767252544319, 0.993211949234794533104601012, + -0.993211949234794533104601012, 0.116318630911904767252544319, + 0.984210092386929073193874387, 0.177004220412148756196839844, + -0.177004220412148756196839844, 0.984210092386929073193874387, + 0.570780745886967280232652864, 0.821102514991104679060430820, + -0.821102514991104679060430820, 0.570780745886967280232652864, + 0.841554977436898409603499520, 0.540171472729892881297845480, + -0.540171472729892881297845480, 0.841554977436898409603499520, + 0.213110319916091373967757518, 0.977028142657754351485866211, + -0.977028142657754351485866211, 0.213110319916091373967757518, + 0.930766961078983731944872340, 0.365612997804773870011745909, + -0.365612997804773870011745909, 0.930766961078983731944872340, + 0.399624199845646828544117031, 0.916679059921042663116457013, + -0.916679059921042663116457013, 0.399624199845646828544117031, + 0.720002507961381629076682999, 0.693971460889654009003734389, + -0.693971460889654009003734389, 0.720002507961381629076682999, + 0.018406729905804820927366313, 0.999830581795823422015722275, + -0.999830581795823422015722275, 0.018406729905804820927366313, + 0.999830581795823422015722275, 0.018406729905804820927366313, + -0.018406729905804820927366313, 0.999830581795823422015722275, + 0.693971460889654009003734389, 0.720002507961381629076682999, + -0.720002507961381629076682999, 0.693971460889654009003734389, + 0.916679059921042663116457013, 0.399624199845646828544117031, + -0.399624199845646828544117031, 0.916679059921042663116457013, + 0.365612997804773870011745909, 0.930766961078983731944872340, + -0.930766961078983731944872340, 0.365612997804773870011745909, + 0.977028142657754351485866211, 0.213110319916091373967757518, + -0.213110319916091373967757518, 0.977028142657754351485866211, + 0.540171472729892881297845480, 0.841554977436898409603499520, + -0.841554977436898409603499520, 0.540171472729892881297845480, + 0.821102514991104679060430820, 0.570780745886967280232652864, + -0.570780745886967280232652864, 0.821102514991104679060430820, + 0.177004220412148756196839844, 0.984210092386929073193874387, + -0.984210092386929073193874387, 0.177004220412148756196839844, + 0.993211949234794533104601012, 0.116318630911904767252544319, + -0.116318630911904767252544319, 0.993211949234794533104601012, + 0.620057211763289178646268191, 0.784556597155575233023892575, + -0.784556597155575233023892575, 0.620057211763289178646268191, + 0.873094978418290098636085973, 0.487550160148435954641485027, + -0.487550160148435954641485027, 0.873094978418290098636085973, + 0.272621355449948984493347477, 0.962121404269041595429604316, + -0.962121404269041595429604316, 0.272621355449948984493347477, + 0.951435020969008369549175569, 0.307849640041534893682063646, + -0.307849640041534893682063646, 0.951435020969008369549175569, + 0.455083587126343823535869268, 0.890448723244757889952150560, + -0.890448723244757889952150560, 0.455083587126343823535869268, + 0.761202385484261814029709836, 0.648514401022112445084560551, + -0.648514401022112445084560551, 0.761202385484261814029709836, + 0.079682437971430121147120656, 0.996820299291165714972629398, + -0.996820299291165714972629398, 0.079682437971430121147120656, + 0.997723066644191609848546728, 0.067443919563664057897972422, + -0.067443919563664057897972422, 0.997723066644191609848546728, + 0.657806693297078656931182264, 0.753186799043612482483430486, + -0.753186799043612482483430486, 0.657806693297078656931182264, + 0.895966249756185155914560282, 0.444122144570429231642069418, + -0.444122144570429231642069418, 0.895966249756185155914560282, + 0.319502030816015677901518272, 0.947585591017741134653387321, + -0.947585591017741134653387321, 0.319502030816015677901518272, + 0.965394441697689374550843858, 0.260794117915275518280186509, + -0.260794117915275518280186509, 0.965394441697689374550843858, + 0.498227666972781852410983869, 0.867046245515692651480195629, + -0.867046245515692651480195629, 0.498227666972781852410983869, + 0.792106577300212351782342879, 0.610382806276309452716352152, + -0.610382806276309452716352152, 0.792106577300212351782342879, + 0.128498110793793172624415589, 0.991709753669099522860049931, + -0.991709753669099522860049931, 0.128498110793793172624415589, + 0.986308097244598647863297524, 0.164913120489969921418189113, + -0.164913120489969921418189113, 0.986308097244598647863297524, + 0.580813958095764545075595272, 0.814036329705948361654516690, + -0.814036329705948361654516690, 0.580813958095764545075595272, + 0.848120344803297251279133563, 0.529803624686294668216054671, + -0.529803624686294668216054671, 0.848120344803297251279133563, + 0.225083911359792835991642120, 0.974339382785575860518721668, + -0.974339382785575860518721668, 0.225083911359792835991642120, + 0.935183509938947577642207480, 0.354163525420490382357395796, + -0.354163525420490382357395796, 0.935183509938947577642207480, + 0.410843171057903942183466675, 0.911706032005429851404397325, + -0.911706032005429851404397325, 0.410843171057903942183466675, + 0.728464390448225196492035438, 0.685083667772700381362052545, + -0.685083667772700381362052545, 0.728464390448225196492035438, + 0.030674803176636625934021028, 0.999529417501093163079703322, + -0.999529417501093163079703322, 0.030674803176636625934021028, + 0.999077727752645382888781997, 0.042938256934940823077124540, + -0.042938256934940823077124540, 0.999077727752645382888781997, + 0.676092703575315960360419228, 0.736816568877369875090132520, + -0.736816568877369875090132520, 0.676092703575315960360419228, + 0.906595704514915365332960588, 0.422000270799799685941287941, + -0.422000270799799685941287941, 0.906595704514915365332960588, + 0.342660717311994397592781983, 0.939459223602189911962669246, + -0.939459223602189911962669246, 0.342660717311994397592781983, + 0.971503890986251775537099622, 0.237023605994367206867735915, + -0.237023605994367206867735915, 0.971503890986251775537099622, + 0.519355990165589587361829932, 0.854557988365400520767862276, + -0.854557988365400520767862276, 0.519355990165589587361829932, + 0.806847553543799272206514313, 0.590759701858874228423887908, + -0.590759701858874228423887908, 0.806847553543799272206514313, + 0.152797185258443427720336613, 0.988257567730749491404792538, + -0.988257567730749491404792538, 0.152797185258443427720336613, + 0.990058210262297105505906464, 0.140658239332849230714788846, + -0.140658239332849230714788846, 0.990058210262297105505906464, + 0.600616479383868926653875896, 0.799537269107905033500246232, + -0.799537269107905033500246232, 0.600616479383868926653875896, + 0.860866938637767279344583877, 0.508830142543107036931749324, + -0.508830142543107036931749324, 0.860866938637767279344583877, + 0.248927605745720168110682816, 0.968522094274417316221088329, + -0.968522094274417316221088329, 0.248927605745720168110682816, + 0.943593458161960361495301445, 0.331106305759876401737190737, + -0.331106305759876401737190737, 0.943593458161960361495301445, + 0.433093818853151968484222638, 0.901348847046022014570746093, + -0.901348847046022014570746093, 0.433093818853151968484222638, + 0.745057785441465962407907310, 0.666999922303637506650154222, + -0.666999922303637506650154222, 0.745057785441465962407907310, + 0.055195244349689939809447526, 0.998475580573294752208559038, + -0.998475580573294752208559038, 0.055195244349689939809447526, + 0.995767414467659793982495643, 0.091908956497132728624990979, + -0.091908956497132728624990979, 0.995767414467659793982495643, + 0.639124444863775743801488193, 0.769103337645579639346626069, + -0.769103337645579639346626069, 0.639124444863775743801488193, + 0.884797098430937780104007041, 0.465976495767966177902756065, + -0.465976495767966177902756065, 0.884797098430937780104007041, + 0.296150888243623824121786128, 0.955141168305770721498157712, + -0.955141168305770721498157712, 0.296150888243623824121786128, + 0.958703474895871555374645792, 0.284407537211271843618310615, + -0.284407537211271843618310615, 0.958703474895871555374645792, + 0.476799230063322133342158117, 0.879012226428633477831323711, + -0.879012226428633477831323711, 0.476799230063322133342158117, + 0.776888465673232450040827983, 0.629638238914927025372981341, + -0.629638238914927025372981341, 0.776888465673232450040827983, + 0.104121633872054579120943880, 0.994564570734255452119106243, + -0.994564570734255452119106243, 0.104121633872054579120943880, + 0.981963869109555264072848154, 0.189068664149806212754997837, + -0.189068664149806212754997837, 0.981963869109555264072848154, + 0.560661576197336023839710223, 0.828045045257755752067527592, + -0.828045045257755752067527592, 0.560661576197336023839710223, + 0.834862874986380056304401383, 0.550457972936604802977289893, + -0.550457972936604802977289893, 0.834862874986380056304401383, + 0.201104634842091911558443546, 0.979569765685440534439326110, + -0.979569765685440534439326110, 0.201104634842091911558443546, + 0.926210242138311341974793388, 0.377007410216418256726567823, + -0.377007410216418256726567823, 0.926210242138311341974793388, + 0.388345046698826291624993541, 0.921514039342041943465396332, + -0.921514039342041943465396332, 0.388345046698826291624993541, + 0.711432195745216441522130290, 0.702754744457225302452914421, + -0.702754744457225302452914421, 0.711432195745216441522130290, + 0.006135884649154475359640235, 0.999981175282601142656990438, + -0.999981175282601142656990438, 0.006135884649154475359640235, + 0.999995293809576171511580126, 0.003067956762965976270145365, + -0.003067956762965976270145365, 0.999995293809576171511580126, + 0.704934080375904908852523758, 0.709272826438865651316533772, + -0.709272826438865651316533772, 0.704934080375904908852523758, + 0.922701128333878570437264227, 0.385516053843918864075607949, + -0.385516053843918864075607949, 0.922701128333878570437264227, + 0.379847208924051170576281147, 0.925049240782677590302371869, + -0.925049240782677590302371869, 0.379847208924051170576281147, + 0.980182135968117392690210009, 0.198098410717953586179324918, + -0.198098410717953586179324918, 0.980182135968117392690210009, + 0.553016705580027531764226988, 0.833170164701913186439915922, + -0.833170164701913186439915922, 0.553016705580027531764226988, + 0.829761233794523042469023765, 0.558118531220556115693702964, + -0.558118531220556115693702964, 0.829761233794523042469023765, + 0.192080397049892441679288205, 0.981379193313754574318224190, + -0.981379193313754574318224190, 0.192080397049892441679288205, + 0.994879330794805620591166107, 0.101069862754827824987887585, + -0.101069862754827824987887585, 0.994879330794805620591166107, + 0.632018735939809021909403706, 0.774953106594873878359129282, + -0.774953106594873878359129282, 0.632018735939809021909403706, + 0.880470889052160770806542929, 0.474100214650550014398580015, + -0.474100214650550014398580015, 0.880470889052160770806542929, + 0.287347459544729526477331841, 0.957826413027532890321037029, + -0.957826413027532890321037029, 0.287347459544729526477331841, + 0.956045251349996443270479823, 0.293219162694258650606608599, + -0.293219162694258650606608599, 0.956045251349996443270479823, + 0.468688822035827933697617870, 0.883363338665731594736308015, + -0.883363338665731594736308015, 0.468688822035827933697617870, + 0.771060524261813773200605759, 0.636761861236284230413943435, + -0.636761861236284230413943435, 0.771060524261813773200605759, + 0.094963495329638998938034312, 0.995480755491926941769171600, + -0.995480755491926941769171600, 0.094963495329638998938034312, + 0.998640218180265222418199049, 0.052131704680283321236358216, + -0.052131704680283321236358216, 0.998640218180265222418199049, + 0.669282588346636065720696366, 0.743007952135121693517362293, + -0.743007952135121693517362293, 0.669282588346636065720696366, + 0.902673318237258806751502391, 0.430326481340082633908199031, + -0.430326481340082633908199031, 0.902673318237258806751502391, + 0.333999651442009404650865481, 0.942573197601446879280758735, + -0.942573197601446879280758735, 0.333999651442009404650865481, + 0.969281235356548486048290738, 0.245955050335794611599924709, + -0.245955050335794611599924709, 0.969281235356548486048290738, + 0.511468850437970399504391001, 0.859301818357008404783582139, + -0.859301818357008404783582139, 0.511468850437970399504391001, + 0.801376171723140219430247777, 0.598160706996342311724958652, + -0.598160706996342311724958652, 0.801376171723140219430247777, + 0.143695033150294454819773349, 0.989622017463200834623694454, + -0.989622017463200834623694454, 0.143695033150294454819773349, + 0.988721691960323767604516485, 0.149764534677321517229695737, + -0.149764534677321517229695737, 0.988721691960323767604516485, + 0.593232295039799808047809426, 0.805031331142963597922659282, + -0.805031331142963597922659282, 0.593232295039799808047809426, + 0.856147328375194481019630732, 0.516731799017649881508753876, + -0.516731799017649881508753876, 0.856147328375194481019630732, + 0.240003022448741486568922365, 0.970772140728950302138169611, + -0.970772140728950302138169611, 0.240003022448741486568922365, + 0.940506070593268323787291309, 0.339776884406826857828825803, + -0.339776884406826857828825803, 0.940506070593268323787291309, + 0.424779681209108833357226189, 0.905296759318118774354048329, + -0.905296759318118774354048329, 0.424779681209108833357226189, + 0.738887324460615147933116508, 0.673829000378756060917568372, + -0.673829000378756060917568372, 0.738887324460615147933116508, + 0.046003182130914628814301788, 0.998941293186856850633930266, + -0.998941293186856850633930266, 0.046003182130914628814301788, + 0.999618822495178597116830637, 0.027608145778965741612354872, + -0.027608145778965741612354872, 0.999618822495178597116830637, + 0.687315340891759108199186948, 0.726359155084345976817494315, + -0.726359155084345976817494315, 0.687315340891759108199186948, + 0.912962190428398164628018233, 0.408044162864978680820747499, + -0.408044162864978680820747499, 0.912962190428398164628018233, + 0.357030961233430032614954036, 0.934092550404258914729877883, + -0.934092550404258914729877883, 0.357030961233430032614954036, + 0.975025345066994146844913468, 0.222093620973203534094094721, + -0.222093620973203534094094721, 0.975025345066994146844913468, + 0.532403127877197971442805218, 0.846490938774052078300544488, + -0.846490938774052078300544488, 0.532403127877197971442805218, + 0.815814410806733789010772660, 0.578313796411655563342245019, + -0.578313796411655563342245019, 0.815814410806733789010772660, + 0.167938294974731178054745536, 0.985797509167567424700995000, + -0.985797509167567424700995000, 0.167938294974731178054745536, + 0.992099313142191757112085445, 0.125454983411546238542336453, + -0.125454983411546238542336453, 0.992099313142191757112085445, + 0.612810082429409703935211936, 0.790230221437310055030217152, + -0.790230221437310055030217152, 0.612810082429409703935211936, + 0.868570705971340895340449876, 0.495565261825772531150266670, + -0.495565261825772531150266670, 0.868570705971340895340449876, + 0.263754678974831383611349322, 0.964589793289812723836432159, + -0.964589793289812723836432159, 0.263754678974831383611349322, + 0.948561349915730288158494826, 0.316593375556165867243047035, + -0.316593375556165867243047035, 0.948561349915730288158494826, + 0.446868840162374195353044389, 0.894599485631382678433072126, + -0.894599485631382678433072126, 0.446868840162374195353044389, + 0.755201376896536527598710756, 0.655492852999615385312679701, + -0.655492852999615385312679701, 0.755201376896536527598710756, + 0.070504573389613863027351471, 0.997511456140303459699448390, + -0.997511456140303459699448390, 0.070504573389613863027351471, + 0.997060070339482978987989949, 0.076623861392031492278332463, + -0.076623861392031492278332463, 0.997060070339482978987989949, + 0.650846684996380915068975573, 0.759209188978388033485525443, + -0.759209188978388033485525443, 0.650846684996380915068975573, + 0.891840709392342727796478697, 0.452349587233770874133026703, + -0.452349587233770874133026703, 0.891840709392342727796478697, + 0.310767152749611495835997250, 0.950486073949481721759926101, + -0.950486073949481721759926101, 0.310767152749611495835997250, + 0.962953266873683886347921481, 0.269668325572915106525464462, + -0.269668325572915106525464462, 0.962953266873683886347921481, + 0.490226483288291154229598449, 0.871595086655951034842481435, + -0.871595086655951034842481435, 0.490226483288291154229598449, + 0.786455213599085757522319464, 0.617647307937803932403979402, + -0.617647307937803932403979402, 0.786455213599085757522319464, + 0.119365214810991364593637790, 0.992850414459865090793563344, + -0.992850414459865090793563344, 0.119365214810991364593637790, + 0.984748501801904218556553176, 0.173983873387463827950700807, + -0.173983873387463827950700807, 0.984748501801904218556553176, + 0.573297166698042212820171239, 0.819347520076796960824689637, + -0.819347520076796960824689637, 0.573297166698042212820171239, + 0.843208239641845437161743865, 0.537587076295645482502214932, + -0.537587076295645482502214932, 0.843208239641845437161743865, + 0.216106797076219509948385131, 0.976369731330021149312732194, + -0.976369731330021149312732194, 0.216106797076219509948385131, + 0.931884265581668106718557199, 0.362755724367397216204854462, + -0.362755724367397216204854462, 0.931884265581668106718557199, + 0.402434650859418441082533934, 0.915448716088267819566431292, + -0.915448716088267819566431292, 0.402434650859418441082533934, + 0.722128193929215321243607198, 0.691759258364157774906734132, + -0.691759258364157774906734132, 0.722128193929215321243607198, + 0.021474080275469507418374898, 0.999769405351215321657617036, + -0.999769405351215321657617036, 0.021474080275469507418374898, + 0.999882347454212525633049627, 0.015339206284988101044151868, + -0.015339206284988101044151868, 0.999882347454212525633049627, + 0.696177131491462944788582591, 0.717870045055731736211325329, + -0.717870045055731736211325329, 0.696177131491462944788582591, + 0.917900775621390457642276297, 0.396809987416710328595290911, + -0.396809987416710328595290911, 0.917900775621390457642276297, + 0.368466829953372331712746222, 0.929640895843181265457918066, + -0.929640895843181265457918066, 0.368466829953372331712746222, + 0.977677357824509979943404762, 0.210111836880469621717489972, + -0.210111836880469621717489972, 0.977677357824509979943404762, + 0.542750784864515906586768661, 0.839893794195999504583383987, + -0.839893794195999504583383987, 0.542750784864515906586768661, + 0.822849781375826332046780034, 0.568258952670131549790548489, + -0.568258952670131549790548489, 0.822849781375826332046780034, + 0.180022901405699522679906590, 0.983662419211730274396237776, + -0.983662419211730274396237776, 0.180022901405699522679906590, + 0.993564135520595333782021697, 0.113270952177564349018228733, + -0.113270952177564349018228733, 0.993564135520595333782021697, + 0.622461279374149972519166721, 0.782650596166575738458949301, + -0.782650596166575738458949301, 0.622461279374149972519166721, + 0.874586652278176112634431897, 0.484869248000791101822951699, + -0.484869248000791101822951699, 0.874586652278176112634431897, + 0.275571819310958163076425168, 0.961280485811320641748659653, + -0.961280485811320641748659653, 0.275571819310958163076425168, + 0.952375012719765858529893608, 0.304929229735402406490728633, + -0.304929229735402406490728633, 0.952375012719765858529893608, + 0.457813303598877221904961155, 0.889048355854664562540777729, + -0.889048355854664562540777729, 0.457813303598877221904961155, + 0.763188417263381271704838297, 0.646176012983316364832802220, + -0.646176012983316364832802220, 0.763188417263381271704838297, + 0.082740264549375693111987083, 0.996571145790554847093566910, + -0.996571145790554847093566910, 0.082740264549375693111987083, + 0.997925286198596012623025462, 0.064382630929857460819324537, + -0.064382630929857460819324537, 0.997925286198596012623025462, + 0.660114342067420478559490747, 0.751165131909686411205819422, + -0.751165131909686411205819422, 0.660114342067420478559490747, + 0.897324580705418281231391836, 0.441371268731716692879988968, + -0.441371268731716692879988968, 0.897324580705418281231391836, + 0.322407678801069848384807478, 0.946600913083283570044599823, + -0.946600913083283570044599823, 0.322407678801069848384807478, + 0.966190003445412555433832961, 0.257831102162159005614471295, + -0.257831102162159005614471295, 0.966190003445412555433832961, + 0.500885382611240786241285004, 0.865513624090569082825488358, + -0.865513624090569082825488358, 0.500885382611240786241285004, + 0.793975477554337164895083757, 0.607949784967773667243642671, + -0.607949784967773667243642671, 0.793975477554337164895083757, + 0.131540028702883111103387493, 0.991310859846115418957349799, + -0.991310859846115418957349799, 0.131540028702883111103387493, + 0.986809401814185476970235952, 0.161886393780111837641387995, + -0.161886393780111837641387995, 0.986809401814185476970235952, + 0.583308652937698294392830961, 0.812250586585203913049744181, + -0.812250586585203913049744181, 0.583308652937698294392830961, + 0.849741768000852489471268395, 0.527199134781901348464274575, + -0.527199134781901348464274575, 0.849741768000852489471268395, + 0.228072083170885739254457379, 0.973644249650811925318383912, + -0.973644249650811925318383912, 0.228072083170885739254457379, + 0.936265667170278246576310996, 0.351292756085567125601307623, + -0.351292756085567125601307623, 0.936265667170278246576310996, + 0.413638312238434547471944324, 0.910441292258067196934095369, + -0.910441292258067196934095369, 0.413638312238434547471944324, + 0.730562769227827561177758850, 0.682845546385248068164596123, + -0.682845546385248068164596123, 0.730562769227827561177758850, + 0.033741171851377584833716112, 0.999430604555461772019008327, + -0.999430604555461772019008327, 0.033741171851377584833716112, + 0.999204758618363895492950001, 0.039872927587739811128578738, + -0.039872927587739811128578738, 0.999204758618363895492950001, + 0.678350043129861486873655042, 0.734738878095963464563223604, + -0.734738878095963464563223604, 0.678350043129861486873655042, + 0.907886116487666212038681480, 0.419216888363223956433010020, + -0.419216888363223956433010020, 0.907886116487666212038681480, + 0.345541324963989065539191723, 0.938403534063108112192420774, + -0.938403534063108112192420774, 0.345541324963989065539191723, + 0.972226497078936305708321144, 0.234041958583543423191242045, + -0.234041958583543423191242045, 0.972226497078936305708321144, + 0.521975292937154342694258318, 0.852960604930363657746588082, + -0.852960604930363657746588082, 0.521975292937154342694258318, + 0.808656181588174991946968128, 0.588281548222645304786439813, + -0.588281548222645304786439813, 0.808656181588174991946968128, + 0.155828397654265235743101486, 0.987784141644572154230969032, + -0.987784141644572154230969032, 0.155828397654265235743101486, + 0.990485084256457037998682243, 0.137620121586486044948441663, + -0.137620121586486044948441663, 0.990485084256457037998682243, + 0.603066598540348201693430617, 0.797690840943391108362662755, + -0.797690840943391108362662755, 0.603066598540348201693430617, + 0.862423956111040538690933878, 0.506186645345155291048942344, + -0.506186645345155291048942344, 0.862423956111040538690933878, + 0.251897818154216950498106628, 0.967753837093475465243391912, + -0.967753837093475465243391912, 0.251897818154216950498106628, + 0.944604837261480265659265493, 0.328209843579092526107916817, + -0.328209843579092526107916817, 0.944604837261480265659265493, + 0.435857079922255491032544080, 0.900015892016160228714535267, + -0.900015892016160228714535267, 0.435857079922255491032544080, + 0.747100605980180144323078847, 0.664710978203344868130324985, + -0.664710978203344868130324985, 0.747100605980180144323078847, + 0.058258264500435759613979782, 0.998301544933892840738782163, + -0.998301544933892840738782163, 0.058258264500435759613979782, + 0.996044700901251989887944810, 0.088853552582524596561586535, + -0.088853552582524596561586535, 0.996044700901251989887944810, + 0.641481012808583151988739898, 0.767138911935820381181694573, + -0.767138911935820381181694573, 0.641481012808583151988739898, + 0.886222530148880631647990821, 0.463259783551860197390719637, + -0.463259783551860197390719637, 0.886222530148880631647990821, + 0.299079826308040476750336973, 0.954228095109105629780430732, + -0.954228095109105629780430732, 0.299079826308040476750336973, + 0.959571513081984528335528181, 0.281464937925757984095231007, + -0.281464937925757984095231007, 0.959571513081984528335528181, + 0.479493757660153026679839798, 0.877545290207261291668470750, + -0.877545290207261291668470750, 0.479493757660153026679839798, + 0.778816512381475953374724325, 0.627251815495144113509622565, + -0.627251815495144113509622565, 0.778816512381475953374724325, + 0.107172424956808849175529148, 0.994240449453187946358413442, + -0.994240449453187946358413442, 0.107172424956808849175529148, + 0.982539302287441255907040396, 0.186055151663446648105438304, + -0.186055151663446648105438304, 0.982539302287441255907040396, + 0.563199344013834115007363772, 0.826321062845663480311195452, + -0.826321062845663480311195452, 0.563199344013834115007363772, + 0.836547727223511984524285790, 0.547894059173100165608820571, + -0.547894059173100165608820571, 0.836547727223511984524285790, + 0.204108966092816874181696950, 0.978948175319062194715480124, + -0.978948175319062194715480124, 0.204108966092816874181696950, + 0.927362525650401087274536959, 0.374164062971457997104393020, + -0.374164062971457997104393020, 0.927362525650401087274536959, + 0.391170384302253888687512949, 0.920318276709110566440076541, + -0.920318276709110566440076541, 0.391170384302253888687512949, + 0.713584868780793592903125099, 0.700568793943248366792866380, + -0.700568793943248366792866380, 0.713584868780793592903125099, + 0.009203754782059819315102378, 0.999957644551963866333120920, + -0.999957644551963866333120920, 0.009203754782059819315102378, + 0.999957644551963866333120920, 0.009203754782059819315102378, + -0.009203754782059819315102378, 0.999957644551963866333120920, + 0.700568793943248366792866380, 0.713584868780793592903125099, + -0.713584868780793592903125099, 0.700568793943248366792866380, + 0.920318276709110566440076541, 0.391170384302253888687512949, + -0.391170384302253888687512949, 0.920318276709110566440076541, + 0.374164062971457997104393020, 0.927362525650401087274536959, + -0.927362525650401087274536959, 0.374164062971457997104393020, + 0.978948175319062194715480124, 0.204108966092816874181696950, + -0.204108966092816874181696950, 0.978948175319062194715480124, + 0.547894059173100165608820571, 0.836547727223511984524285790, + -0.836547727223511984524285790, 0.547894059173100165608820571, + 0.826321062845663480311195452, 0.563199344013834115007363772, + -0.563199344013834115007363772, 0.826321062845663480311195452, + 0.186055151663446648105438304, 0.982539302287441255907040396, + -0.982539302287441255907040396, 0.186055151663446648105438304, + 0.994240449453187946358413442, 0.107172424956808849175529148, + -0.107172424956808849175529148, 0.994240449453187946358413442, + 0.627251815495144113509622565, 0.778816512381475953374724325, + -0.778816512381475953374724325, 0.627251815495144113509622565, + 0.877545290207261291668470750, 0.479493757660153026679839798, + -0.479493757660153026679839798, 0.877545290207261291668470750, + 0.281464937925757984095231007, 0.959571513081984528335528181, + -0.959571513081984528335528181, 0.281464937925757984095231007, + 0.954228095109105629780430732, 0.299079826308040476750336973, + -0.299079826308040476750336973, 0.954228095109105629780430732, + 0.463259783551860197390719637, 0.886222530148880631647990821, + -0.886222530148880631647990821, 0.463259783551860197390719637, + 0.767138911935820381181694573, 0.641481012808583151988739898, + -0.641481012808583151988739898, 0.767138911935820381181694573, + 0.088853552582524596561586535, 0.996044700901251989887944810, + -0.996044700901251989887944810, 0.088853552582524596561586535, + 0.998301544933892840738782163, 0.058258264500435759613979782, + -0.058258264500435759613979782, 0.998301544933892840738782163, + 0.664710978203344868130324985, 0.747100605980180144323078847, + -0.747100605980180144323078847, 0.664710978203344868130324985, + 0.900015892016160228714535267, 0.435857079922255491032544080, + -0.435857079922255491032544080, 0.900015892016160228714535267, + 0.328209843579092526107916817, 0.944604837261480265659265493, + -0.944604837261480265659265493, 0.328209843579092526107916817, + 0.967753837093475465243391912, 0.251897818154216950498106628, + -0.251897818154216950498106628, 0.967753837093475465243391912, + 0.506186645345155291048942344, 0.862423956111040538690933878, + -0.862423956111040538690933878, 0.506186645345155291048942344, + 0.797690840943391108362662755, 0.603066598540348201693430617, + -0.603066598540348201693430617, 0.797690840943391108362662755, + 0.137620121586486044948441663, 0.990485084256457037998682243, + -0.990485084256457037998682243, 0.137620121586486044948441663, + 0.987784141644572154230969032, 0.155828397654265235743101486, + -0.155828397654265235743101486, 0.987784141644572154230969032, + 0.588281548222645304786439813, 0.808656181588174991946968128, + -0.808656181588174991946968128, 0.588281548222645304786439813, + 0.852960604930363657746588082, 0.521975292937154342694258318, + -0.521975292937154342694258318, 0.852960604930363657746588082, + 0.234041958583543423191242045, 0.972226497078936305708321144, + -0.972226497078936305708321144, 0.234041958583543423191242045, + 0.938403534063108112192420774, 0.345541324963989065539191723, + -0.345541324963989065539191723, 0.938403534063108112192420774, + 0.419216888363223956433010020, 0.907886116487666212038681480, + -0.907886116487666212038681480, 0.419216888363223956433010020, + 0.734738878095963464563223604, 0.678350043129861486873655042, + -0.678350043129861486873655042, 0.734738878095963464563223604, + 0.039872927587739811128578738, 0.999204758618363895492950001, + -0.999204758618363895492950001, 0.039872927587739811128578738, + 0.999430604555461772019008327, 0.033741171851377584833716112, + -0.033741171851377584833716112, 0.999430604555461772019008327, + 0.682845546385248068164596123, 0.730562769227827561177758850, + -0.730562769227827561177758850, 0.682845546385248068164596123, + 0.910441292258067196934095369, 0.413638312238434547471944324, + -0.413638312238434547471944324, 0.910441292258067196934095369, + 0.351292756085567125601307623, 0.936265667170278246576310996, + -0.936265667170278246576310996, 0.351292756085567125601307623, + 0.973644249650811925318383912, 0.228072083170885739254457379, + -0.228072083170885739254457379, 0.973644249650811925318383912, + 0.527199134781901348464274575, 0.849741768000852489471268395, + -0.849741768000852489471268395, 0.527199134781901348464274575, + 0.812250586585203913049744181, 0.583308652937698294392830961, + -0.583308652937698294392830961, 0.812250586585203913049744181, + 0.161886393780111837641387995, 0.986809401814185476970235952, + -0.986809401814185476970235952, 0.161886393780111837641387995, + 0.991310859846115418957349799, 0.131540028702883111103387493, + -0.131540028702883111103387493, 0.991310859846115418957349799, + 0.607949784967773667243642671, 0.793975477554337164895083757, + -0.793975477554337164895083757, 0.607949784967773667243642671, + 0.865513624090569082825488358, 0.500885382611240786241285004, + -0.500885382611240786241285004, 0.865513624090569082825488358, + 0.257831102162159005614471295, 0.966190003445412555433832961, + -0.966190003445412555433832961, 0.257831102162159005614471295, + 0.946600913083283570044599823, 0.322407678801069848384807478, + -0.322407678801069848384807478, 0.946600913083283570044599823, + 0.441371268731716692879988968, 0.897324580705418281231391836, + -0.897324580705418281231391836, 0.441371268731716692879988968, + 0.751165131909686411205819422, 0.660114342067420478559490747, + -0.660114342067420478559490747, 0.751165131909686411205819422, + 0.064382630929857460819324537, 0.997925286198596012623025462, + -0.997925286198596012623025462, 0.064382630929857460819324537, + 0.996571145790554847093566910, 0.082740264549375693111987083, + -0.082740264549375693111987083, 0.996571145790554847093566910, + 0.646176012983316364832802220, 0.763188417263381271704838297, + -0.763188417263381271704838297, 0.646176012983316364832802220, + 0.889048355854664562540777729, 0.457813303598877221904961155, + -0.457813303598877221904961155, 0.889048355854664562540777729, + 0.304929229735402406490728633, 0.952375012719765858529893608, + -0.952375012719765858529893608, 0.304929229735402406490728633, + 0.961280485811320641748659653, 0.275571819310958163076425168, + -0.275571819310958163076425168, 0.961280485811320641748659653, + 0.484869248000791101822951699, 0.874586652278176112634431897, + -0.874586652278176112634431897, 0.484869248000791101822951699, + 0.782650596166575738458949301, 0.622461279374149972519166721, + -0.622461279374149972519166721, 0.782650596166575738458949301, + 0.113270952177564349018228733, 0.993564135520595333782021697, + -0.993564135520595333782021697, 0.113270952177564349018228733, + 0.983662419211730274396237776, 0.180022901405699522679906590, + -0.180022901405699522679906590, 0.983662419211730274396237776, + 0.568258952670131549790548489, 0.822849781375826332046780034, + -0.822849781375826332046780034, 0.568258952670131549790548489, + 0.839893794195999504583383987, 0.542750784864515906586768661, + -0.542750784864515906586768661, 0.839893794195999504583383987, + 0.210111836880469621717489972, 0.977677357824509979943404762, + -0.977677357824509979943404762, 0.210111836880469621717489972, + 0.929640895843181265457918066, 0.368466829953372331712746222, + -0.368466829953372331712746222, 0.929640895843181265457918066, + 0.396809987416710328595290911, 0.917900775621390457642276297, + -0.917900775621390457642276297, 0.396809987416710328595290911, + 0.717870045055731736211325329, 0.696177131491462944788582591, + -0.696177131491462944788582591, 0.717870045055731736211325329, + 0.015339206284988101044151868, 0.999882347454212525633049627, + -0.999882347454212525633049627, 0.015339206284988101044151868, + 0.999769405351215321657617036, 0.021474080275469507418374898, + -0.021474080275469507418374898, 0.999769405351215321657617036, + 0.691759258364157774906734132, 0.722128193929215321243607198, + -0.722128193929215321243607198, 0.691759258364157774906734132, + 0.915448716088267819566431292, 0.402434650859418441082533934, + -0.402434650859418441082533934, 0.915448716088267819566431292, + 0.362755724367397216204854462, 0.931884265581668106718557199, + -0.931884265581668106718557199, 0.362755724367397216204854462, + 0.976369731330021149312732194, 0.216106797076219509948385131, + -0.216106797076219509948385131, 0.976369731330021149312732194, + 0.537587076295645482502214932, 0.843208239641845437161743865, + -0.843208239641845437161743865, 0.537587076295645482502214932, + 0.819347520076796960824689637, 0.573297166698042212820171239, + -0.573297166698042212820171239, 0.819347520076796960824689637, + 0.173983873387463827950700807, 0.984748501801904218556553176, + -0.984748501801904218556553176, 0.173983873387463827950700807, + 0.992850414459865090793563344, 0.119365214810991364593637790, + -0.119365214810991364593637790, 0.992850414459865090793563344, + 0.617647307937803932403979402, 0.786455213599085757522319464, + -0.786455213599085757522319464, 0.617647307937803932403979402, + 0.871595086655951034842481435, 0.490226483288291154229598449, + -0.490226483288291154229598449, 0.871595086655951034842481435, + 0.269668325572915106525464462, 0.962953266873683886347921481, + -0.962953266873683886347921481, 0.269668325572915106525464462, + 0.950486073949481721759926101, 0.310767152749611495835997250, + -0.310767152749611495835997250, 0.950486073949481721759926101, + 0.452349587233770874133026703, 0.891840709392342727796478697, + -0.891840709392342727796478697, 0.452349587233770874133026703, + 0.759209188978388033485525443, 0.650846684996380915068975573, + -0.650846684996380915068975573, 0.759209188978388033485525443, + 0.076623861392031492278332463, 0.997060070339482978987989949, + -0.997060070339482978987989949, 0.076623861392031492278332463, + 0.997511456140303459699448390, 0.070504573389613863027351471, + -0.070504573389613863027351471, 0.997511456140303459699448390, + 0.655492852999615385312679701, 0.755201376896536527598710756, + -0.755201376896536527598710756, 0.655492852999615385312679701, + 0.894599485631382678433072126, 0.446868840162374195353044389, + -0.446868840162374195353044389, 0.894599485631382678433072126, + 0.316593375556165867243047035, 0.948561349915730288158494826, + -0.948561349915730288158494826, 0.316593375556165867243047035, + 0.964589793289812723836432159, 0.263754678974831383611349322, + -0.263754678974831383611349322, 0.964589793289812723836432159, + 0.495565261825772531150266670, 0.868570705971340895340449876, + -0.868570705971340895340449876, 0.495565261825772531150266670, + 0.790230221437310055030217152, 0.612810082429409703935211936, + -0.612810082429409703935211936, 0.790230221437310055030217152, + 0.125454983411546238542336453, 0.992099313142191757112085445, + -0.992099313142191757112085445, 0.125454983411546238542336453, + 0.985797509167567424700995000, 0.167938294974731178054745536, + -0.167938294974731178054745536, 0.985797509167567424700995000, + 0.578313796411655563342245019, 0.815814410806733789010772660, + -0.815814410806733789010772660, 0.578313796411655563342245019, + 0.846490938774052078300544488, 0.532403127877197971442805218, + -0.532403127877197971442805218, 0.846490938774052078300544488, + 0.222093620973203534094094721, 0.975025345066994146844913468, + -0.975025345066994146844913468, 0.222093620973203534094094721, + 0.934092550404258914729877883, 0.357030961233430032614954036, + -0.357030961233430032614954036, 0.934092550404258914729877883, + 0.408044162864978680820747499, 0.912962190428398164628018233, + -0.912962190428398164628018233, 0.408044162864978680820747499, + 0.726359155084345976817494315, 0.687315340891759108199186948, + -0.687315340891759108199186948, 0.726359155084345976817494315, + 0.027608145778965741612354872, 0.999618822495178597116830637, + -0.999618822495178597116830637, 0.027608145778965741612354872, + 0.998941293186856850633930266, 0.046003182130914628814301788, + -0.046003182130914628814301788, 0.998941293186856850633930266, + 0.673829000378756060917568372, 0.738887324460615147933116508, + -0.738887324460615147933116508, 0.673829000378756060917568372, + 0.905296759318118774354048329, 0.424779681209108833357226189, + -0.424779681209108833357226189, 0.905296759318118774354048329, + 0.339776884406826857828825803, 0.940506070593268323787291309, + -0.940506070593268323787291309, 0.339776884406826857828825803, + 0.970772140728950302138169611, 0.240003022448741486568922365, + -0.240003022448741486568922365, 0.970772140728950302138169611, + 0.516731799017649881508753876, 0.856147328375194481019630732, + -0.856147328375194481019630732, 0.516731799017649881508753876, + 0.805031331142963597922659282, 0.593232295039799808047809426, + -0.593232295039799808047809426, 0.805031331142963597922659282, + 0.149764534677321517229695737, 0.988721691960323767604516485, + -0.988721691960323767604516485, 0.149764534677321517229695737, + 0.989622017463200834623694454, 0.143695033150294454819773349, + -0.143695033150294454819773349, 0.989622017463200834623694454, + 0.598160706996342311724958652, 0.801376171723140219430247777, + -0.801376171723140219430247777, 0.598160706996342311724958652, + 0.859301818357008404783582139, 0.511468850437970399504391001, + -0.511468850437970399504391001, 0.859301818357008404783582139, + 0.245955050335794611599924709, 0.969281235356548486048290738, + -0.969281235356548486048290738, 0.245955050335794611599924709, + 0.942573197601446879280758735, 0.333999651442009404650865481, + -0.333999651442009404650865481, 0.942573197601446879280758735, + 0.430326481340082633908199031, 0.902673318237258806751502391, + -0.902673318237258806751502391, 0.430326481340082633908199031, + 0.743007952135121693517362293, 0.669282588346636065720696366, + -0.669282588346636065720696366, 0.743007952135121693517362293, + 0.052131704680283321236358216, 0.998640218180265222418199049, + -0.998640218180265222418199049, 0.052131704680283321236358216, + 0.995480755491926941769171600, 0.094963495329638998938034312, + -0.094963495329638998938034312, 0.995480755491926941769171600, + 0.636761861236284230413943435, 0.771060524261813773200605759, + -0.771060524261813773200605759, 0.636761861236284230413943435, + 0.883363338665731594736308015, 0.468688822035827933697617870, + -0.468688822035827933697617870, 0.883363338665731594736308015, + 0.293219162694258650606608599, 0.956045251349996443270479823, + -0.956045251349996443270479823, 0.293219162694258650606608599, + 0.957826413027532890321037029, 0.287347459544729526477331841, + -0.287347459544729526477331841, 0.957826413027532890321037029, + 0.474100214650550014398580015, 0.880470889052160770806542929, + -0.880470889052160770806542929, 0.474100214650550014398580015, + 0.774953106594873878359129282, 0.632018735939809021909403706, + -0.632018735939809021909403706, 0.774953106594873878359129282, + 0.101069862754827824987887585, 0.994879330794805620591166107, + -0.994879330794805620591166107, 0.101069862754827824987887585, + 0.981379193313754574318224190, 0.192080397049892441679288205, + -0.192080397049892441679288205, 0.981379193313754574318224190, + 0.558118531220556115693702964, 0.829761233794523042469023765, + -0.829761233794523042469023765, 0.558118531220556115693702964, + 0.833170164701913186439915922, 0.553016705580027531764226988, + -0.553016705580027531764226988, 0.833170164701913186439915922, + 0.198098410717953586179324918, 0.980182135968117392690210009, + -0.980182135968117392690210009, 0.198098410717953586179324918, + 0.925049240782677590302371869, 0.379847208924051170576281147, + -0.379847208924051170576281147, 0.925049240782677590302371869, + 0.385516053843918864075607949, 0.922701128333878570437264227, + -0.922701128333878570437264227, 0.385516053843918864075607949, + 0.709272826438865651316533772, 0.704934080375904908852523758, + -0.704934080375904908852523758, 0.709272826438865651316533772, + 0.003067956762965976270145365, 0.999995293809576171511580126, + -0.999995293809576171511580126, 0.003067956762965976270145365 }; - p2_tab = new FalconFPR[]{ - new FalconFPR(2.00000000000), - new FalconFPR(1.00000000000), - new FalconFPR(0.50000000000), - new FalconFPR(0.25000000000), - new FalconFPR(0.12500000000), - new FalconFPR(0.06250000000), - new FalconFPR(0.03125000000), - new FalconFPR(0.01562500000), - new FalconFPR(0.00781250000), - new FalconFPR(0.00390625000), - new FalconFPR(0.00195312500) + fpr_p2_tab = new double[]{ + 2.00000000000, + 1.00000000000, + 0.50000000000, + 0.25000000000, + 0.12500000000, + 0.06250000000, + 0.03125000000, + 0.01562500000, + 0.00781250000, + 0.00390625000, + 0.00195312500 }; } FPREngine() { - this.fpr_q = new FalconFPR(12289.0); - this.fpr_inverse_of_q = new FalconFPR(1.0 / 12289.0); - this.fpr_inv_2sqrsigma0 = new FalconFPR(0.150865048875372721532312163019); - this.fpr_inv_sigma = inv_sigma; - this.fpr_sigma_min = sigma_min; - this.fpr_log2 = new FalconFPR(0.69314718055994530941723212146); - this.fpr_inv_log2 = new FalconFPR(1.4426950408889634073599246810); - this.fpr_bnorm_max = new FalconFPR(16822.4121); - this.fpr_zero = new FalconFPR(0.0); - this.fpr_one = new FalconFPR(1.0); - this.fpr_two = new FalconFPR(2.0); - this.fpr_onehalf = new FalconFPR(0.5); - this.fpr_invsqrt2 = new FalconFPR(0.707106781186547524400844362105); - this.fpr_invsqrt8 = new FalconFPR(0.353553390593273762200422181052); - this.fpr_ptwo31 = new FalconFPR(2147483648.0); - this.fpr_ptwo31m1 = new FalconFPR(2147483647.0); - this.fpr_mtwo31m1 = new FalconFPR(-2147483647.0); - this.fpr_ptwo63m1 = new FalconFPR(9223372036854775807.0); - this.fpr_mtwo63m1 = new FalconFPR(-9223372036854775807.0); - this.fpr_ptwo63 = new FalconFPR(9223372036854775808.0); - this.fpr_gm_tab = gm_tab; - this.fpr_p2_tab = p2_tab; + //this.fpr_inverse_of_q = 1.0 / 12289.0; + //this.fpr_inv_2sqrsigma0 = 0.150865048875372721532312163019; + //this.fpr_inv_sigma = inv_sigma; + //this.fpr_sigma_min = sigma_min; + //this.fpr_log2 = 0.69314718055994530941723212146; + //this.fpr_inv_log2 = 1.4426950408889634073599246810; + //this.fpr_bnorm_max = 16822.4121; +// this.fpr_zero = 0.0; +// this.fpr_one = 1.0; +// this.fpr_two = 2.0; + //this.fpr_onehalf = 0.5; +// this.fpr_invsqrt2 = 0.707106781186547524400844362105; +// this.fpr_invsqrt8 = 0.353553390593273762200422181052; +// this.fpr_ptwo31 = 2147483648.0; +// this.fpr_ptwo31m1 = 2147483647.0; +// this.fpr_mtwo31m1 = -2147483647.0; +// this.fpr_ptwo63m1 = 9223372036854775807.0; +// this.fpr_mtwo63m1 = -9223372036854775807.0; +// this.fpr_ptwo63 = 9223372036854775808.0; + //this.fpr_gm_tab = gm_tab; + //this.fpr_p2_tab = p2_tab; } - FalconFPR FPR(double v) - { - FalconFPR x = new FalconFPR(v); - return x; - } - - FalconFPR fpr_of(long i) - { - return FPR((double)i); - } +// static double fpr_of(long i) +// { +// return (double)i; +// } - final FalconFPR fpr_q; - final FalconFPR fpr_inverse_of_q; - final FalconFPR fpr_inv_2sqrsigma0; - final FalconFPR[] fpr_inv_sigma; - final FalconFPR[] fpr_sigma_min; - final FalconFPR fpr_log2; - final FalconFPR fpr_inv_log2; - final FalconFPR fpr_bnorm_max; - final FalconFPR fpr_zero; - final FalconFPR fpr_one; - final FalconFPR fpr_two; - final FalconFPR fpr_onehalf; - final FalconFPR fpr_invsqrt2; - final FalconFPR fpr_invsqrt8; - final FalconFPR fpr_ptwo31; - final FalconFPR fpr_ptwo31m1; - final FalconFPR fpr_mtwo31m1; - final FalconFPR fpr_ptwo63m1; - final FalconFPR fpr_mtwo63m1; - final FalconFPR fpr_ptwo63; - final FalconFPR[] fpr_gm_tab; - final FalconFPR[] fpr_p2_tab; + static final double fpr_q = 12289.0; + static final double fpr_inverse_of_q = 1.0 / 12289.0; + static final double fpr_inv_2sqrsigma0 = 0.150865048875372721532312163019; + static final double[] fpr_inv_sigma; + static final double[] fpr_sigma_min; + static final double fpr_log2 = 0.69314718055994530941723212146; + static final double fpr_inv_log2 = 1.4426950408889634073599246810; + static final double fpr_bnorm_max = 16822.4121; + static final double fpr_zero = 0.0; + static final double fpr_one = 1.0; + static final double fpr_two = 2.0; + static final double fpr_onehalf = 0.5; +// static final double fpr_invsqrt2 = 0.707106781186547524400844362105; +// static final double fpr_invsqrt8 = 0.353553390593273762200422181052; + static final double fpr_ptwo31 = 2147483648.0; + static final double fpr_ptwo31m1 = 2147483647.0; + static final double fpr_mtwo31m1 = -2147483647.0; + static final double fpr_ptwo63m1 = 9223372036854775807.0; + static final double fpr_mtwo63m1 = -9223372036854775807.0; + static final double fpr_ptwo63 = 9223372036854775808.0; + static final double[] fpr_gm_tab; + static final double[] fpr_p2_tab; - long - fpr_rint(FalconFPR x) + static long fpr_rint(double x) { /* * We do not want to use llrint() since it might be not @@ -1158,10 +1150,10 @@ FalconFPR fpr_of(long i) long sx, tx, rp, rn, m; int ub; - sx = (long)(x.v - 1.0); - tx = (long)x.v; - rp = (long)(x.v + 4503599627370496.0) - 4503599627370496l; - rn = (long)(x.v - 4503599627370496.0) + 4503599627370496l; + sx = (long)(x - 1.0); + tx = (long)x; + rp = (long)(x + 4503599627370496.0) - 4503599627370496L; + rn = (long)(x - 4503599627370496.0) + 4503599627370496L; /* * If tx >= 2^52 or tx < -2^52, then result is tx. @@ -1198,7 +1190,7 @@ FalconFPR fpr_of(long i) return tx | rn | rp; } - long fpr_floor(FalconFPR x) + static long fpr_floor(double x) { long r; @@ -1212,85 +1204,82 @@ long fpr_floor(FalconFPR x) * if it is false on a given arch, then chances are that the FPU * itself is not constant-time, making the point moot). */ - r = (long)x.v; - return r - (x.v < (double)r ? 1 : 0); + r = (long)x; + return r - (x < (double)r ? 1 : 0); } - long - fpr_trunc(FalconFPR x) - { - return (long)x.v; - } +// long +// fpr_trunc(double x) +// { +// return (long)x; +// } - FalconFPR - fpr_add(FalconFPR x, FalconFPR y) - { - return FPR(x.v + y.v); - } +// static double fpr_add(double x, double y) +// { +// return x + y; +// } - FalconFPR - fpr_sub(FalconFPR x, FalconFPR y) - { - return FPR(x.v - y.v); - } +// static double fpr_sub(double x, double y) +// { +// return x - y; +// } - FalconFPR - fpr_neg(FalconFPR x) - { - return FPR(-x.v); - } +// static double fpr_neg(double x) +// { +// return -x; +// } - FalconFPR - fpr_half(FalconFPR x) - { - return FPR(x.v * 0.5); - } +// static double +// fpr_half(double x) +// { +// return x * 0.5; +// } - FalconFPR - fpr_double(FalconFPR x) - { - return FPR(x.v + x.v); - } +// double +// fpr_double(double x) +// { +// return x + x; +// } - FalconFPR - fpr_mul(FalconFPR x, FalconFPR y) - { - return FPR(x.v * y.v); - } +// static double +// fpr_mul(double x, double y) +// { +// return x * y; +// } - FalconFPR - fpr_sqr(FalconFPR x) - { - return FPR(x.v * x.v); - } +// static double +// fpr_sqr(double x) +// { +// return x * x; +// } - FalconFPR - fpr_inv(FalconFPR x) - { - return FPR(1.0 / x.v); - } +// static double +// fpr_inv(double x) +// { +// return 1.0 / x; +// } - FalconFPR - fpr_div(FalconFPR x, FalconFPR y) - { - return FPR(x.v / y.v); - } +// double +// fpr_div(double x, double y) +// { +// return FPR(x / y); +// } - FalconFPR - fpr_sqrt(FalconFPR x) - { - return FPR(Math.sqrt(x.v)); - } +// static double +// fpr_sqrt(double x) +// { +// return Math.sqrt(x); +// } - boolean - fpr_lt(FalconFPR x, FalconFPR y) - { - return x.v < y.v; - } +// static boolean +// fpr_lt(double x, double y) +// { +// return x < y; +// } - long - fpr_expm_p63(FalconFPR x, FalconFPR ccs) + static long + fpr_expm_p63(double x, double ccs) { /* * Polynomial approximation of exp(-x) is taken from FACCT: @@ -1311,7 +1300,7 @@ long fpr_floor(FalconFPR x) double d, y; - d = x.v; + d = x; y = 0.000000002073772366009083061987; y = 0.000000025299506379442070029551 - y * d; y = 0.000000275607356160477811864927 - y * d; @@ -1325,7 +1314,7 @@ long fpr_floor(FalconFPR x) y = 0.500000000000019206858326015208 - y * d; y = 0.999999999999994892974086724280 - y * d; y = 1.000000000000000000000000000000 - y * d; - y *= ccs.v; - return (long)(y * fpr_ptwo63.v); + y *= ccs; + return (long)(y * fpr_ptwo63); } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconCodec.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconCodec.java index 1452ccb849..271473d744 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconCodec.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconCodec.java @@ -2,15 +2,10 @@ class FalconCodec { - - FalconCodec() - { - } - /* see inner.h */ - int modq_encode( - byte[] srcout, int out, int max_out_len, - short[] srcx, int x, int logn) + static int modq_encode( + byte[] srcout, int max_out_len, + short[] srcx, int logn) { int n, out_len, u; int buf; @@ -20,7 +15,7 @@ int modq_encode( n = 1 << logn; for (u = 0; u < n; u++) { - if ((srcx[x + u] & 0x0000ffff) >= 12289) + if ((srcx[u] & 0x0000ffff) >= 12289) { return 0; } @@ -34,12 +29,12 @@ int modq_encode( { return 0; } - buf = out; + buf = 1; acc = 0; acc_len = 0; for (u = 0; u < n; u++) { - acc = (acc << 14) | (srcx[x + u] & 0xffff); + acc = (acc << 14) | (srcx[u] & 0xffff); acc_len += 14; while (acc_len >= 8) { @@ -55,9 +50,9 @@ int modq_encode( } /* see inner.h */ - int modq_decode( - short[] srcx, int x, int logn, - byte[] srcin, int in, int max_in_len) + static int modq_decode( + short[] srcx, int logn, + byte[] srcin, int max_in_len) { int n, in_len, u; int buf; @@ -70,7 +65,7 @@ int modq_decode( { return 0; } - buf = in; + buf = 0; acc = 0; acc_len = 0; u = 0; @@ -88,7 +83,7 @@ int modq_decode( { return 0; } - srcx[x + u] = (short)w; + srcx[u] = (short)w; u++; } } @@ -100,116 +95,116 @@ int modq_decode( } /* see inner.h */ - int trim_i16_encode( - byte[] srcout, int out, int max_out_len, - short[] srcx, int x, int logn, int bits) - { - int n, u, out_len; - int minv, maxv; - int buf; - int acc, mask; - int acc_len; - - n = 1 << logn; - maxv = (1 << (bits - 1)) - 1; - minv = -maxv; - for (u = 0; u < n; u++) - { - if (srcx[x + u] < minv || srcx[x + u] > maxv) - { - return 0; - } - } - out_len = ((n * bits) + 7) >> 3; - if (srcout == null) - { - return out_len; - } - if (out_len > max_out_len) - { - return 0; - } - buf = out; - acc = 0; - acc_len = 0; - mask = (1 << bits) - 1; - for (u = 0; u < n; u++) - { - acc = (acc << bits) | ((srcx[x + u] & 0xfff) & mask); - acc_len += bits; - while (acc_len >= 8) - { - acc_len -= 8; - srcout[buf++] = (byte)(acc >> acc_len); - } - } - if (acc_len > 0) - { - srcout[buf++] = (byte)(acc << (8 - acc_len)); - } - return out_len; - } +// int trim_i16_encode( +// byte[] srcout, int out, int max_out_len, +// short[] srcx, int x, int logn, int bits) +// { +// int n, u, out_len; +// int minv, maxv; +// int buf; +// int acc, mask; +// int acc_len; +// +// n = 1 << logn; +// maxv = (1 << (bits - 1)) - 1; +// minv = -maxv; +// for (u = 0; u < n; u++) +// { +// if (srcx[x + u] < minv || srcx[x + u] > maxv) +// { +// return 0; +// } +// } +// out_len = ((n * bits) + 7) >> 3; +// if (srcout == null) +// { +// return out_len; +// } +// if (out_len > max_out_len) +// { +// return 0; +// } +// buf = out; +// acc = 0; +// acc_len = 0; +// mask = (1 << bits) - 1; +// for (u = 0; u < n; u++) +// { +// acc = (acc << bits) | ((srcx[x + u] & 0xfff) & mask); +// acc_len += bits; +// while (acc_len >= 8) +// { +// acc_len -= 8; +// srcout[buf++] = (byte)(acc >> acc_len); +// } +// } +// if (acc_len > 0) +// { +// srcout[buf++] = (byte)(acc << (8 - acc_len)); +// } +// return out_len; +// } /* see inner.h */ - int trim_i16_decode( - short[] srcx, int x, int logn, int bits, - byte[] srcin, int in, int max_in_len) - { - int n, in_len; - int buf; - int u; - int acc, mask1, mask2; - int acc_len; - - n = 1 << logn; - in_len = ((n * bits) + 7) >> 3; - if (in_len > max_in_len) - { - return 0; - } - buf = in; - u = 0; - acc = 0; - acc_len = 0; - mask1 = (1 << bits) - 1; - mask2 = 1 << (bits - 1); - while (u < n) - { - acc = (acc << 8) | (srcin[buf++] & 0xff); - acc_len += 8; - while (acc_len >= bits && u < n) - { - int w; - - acc_len -= bits; - w = (acc >>> acc_len) & mask1; - w |= -(w & mask2); - if (w == -mask2) - { - /* - * The -2^(bits-1) value is forbidden. - */ - return 0; - } - w |= -(w & mask2); - srcx[x + u] = (short)w; - u++; - } - } - if ((acc & ((1 << acc_len) - 1)) != 0) - { - /* - * Extra bits in the last byte must be zero. - */ - return 0; - } - return in_len; - } +// int trim_i16_decode( +// short[] srcx, int x, int logn, int bits, +// byte[] srcin, int in, int max_in_len) +// { +// int n, in_len; +// int buf; +// int u; +// int acc, mask1, mask2; +// int acc_len; +// +// n = 1 << logn; +// in_len = ((n * bits) + 7) >> 3; +// if (in_len > max_in_len) +// { +// return 0; +// } +// buf = in; +// u = 0; +// acc = 0; +// acc_len = 0; +// mask1 = (1 << bits) - 1; +// mask2 = 1 << (bits - 1); +// while (u < n) +// { +// acc = (acc << 8) | (srcin[buf++] & 0xff); +// acc_len += 8; +// while (acc_len >= bits && u < n) +// { +// int w; +// +// acc_len -= bits; +// w = (acc >>> acc_len) & mask1; +// w |= -(w & mask2); +// if (w == -mask2) +// { +// /* +// * The -2^(bits-1) value is forbidden. +// */ +// return 0; +// } +// w |= -(w & mask2); +// srcx[x + u] = (short)w; +// u++; +// } +// } +// if ((acc & ((1 << acc_len) - 1)) != 0) +// { +// /* +// * Extra bits in the last byte must be zero. +// */ +// return 0; +// } +// return in_len; +// } /* see inner.h */ - int trim_i8_encode( + static int trim_i8_encode( byte[] srcout, int out, int max_out_len, - byte[] srcx, int x, int logn, int bits) + byte[] srcx, int logn, int bits) { int n, u, out_len; int minv, maxv; @@ -222,7 +217,7 @@ int trim_i8_encode( minv = -maxv; for (u = 0; u < n; u++) { - if (srcx[x + u] < minv || srcx[x + u] > maxv) + if (srcx[u] < minv || srcx[u] > maxv) { return 0; } @@ -242,7 +237,7 @@ int trim_i8_encode( mask = (1 << bits) - 1; for (u = 0; u < n; u++) { - acc = (acc << bits) | ((srcx[x + u] & 0xffff) & mask); + acc = (acc << bits) | ((srcx[u] & 0xffff) & mask); acc_len += bits; while (acc_len >= 8) { @@ -252,14 +247,14 @@ int trim_i8_encode( } if (acc_len > 0) { - srcout[buf++] = (byte)(acc << (8 - acc_len)); + srcout[buf] = (byte)(acc << (8 - acc_len)); } return out_len; } /* see inner.h */ - int trim_i8_decode( - byte[] srcx, int x, int logn, int bits, + static int trim_i8_decode( + byte[] srcx, int logn, int bits, byte[] srcin, int in, int max_in_len) { int n, in_len; @@ -298,7 +293,7 @@ int trim_i8_decode( */ return 0; } - srcx[x + u] = (byte)w; + srcx[u] = (byte)w; u++; } } @@ -313,9 +308,9 @@ int trim_i8_decode( } /* see inner.h */ - int comp_encode( - byte[] srcout, int out, int max_out_len, - short[] srcx, int x, int logn) + static int comp_encode( + byte[] srcout, int max_out_len, + short[] srcx, int logn) { int buf; int n, u, v; @@ -323,14 +318,14 @@ int comp_encode( int acc_len; n = 1 << logn; - buf = out; + buf = 0; /* * Make sure that all values are within the -2047..+2047 range. */ for (u = 0; u < n; u++) { - if (srcx[x + u] < -2047 || srcx[x + u] > +2047) + if (srcx[u] < -2047 || srcx[u] > 2047) { return 0; } @@ -349,7 +344,7 @@ int comp_encode( * sign bit. */ acc <<= 1; - t = srcx[x + u]; + t = srcx[u]; if (t < 0) { t = -t; @@ -419,9 +414,9 @@ int comp_encode( } /* see inner.h */ - int comp_decode( - short[] srcx, int x, int logn, - byte[] srcin, int in, int max_in_len) + static int comp_decode( + short[] srcx, int logn, + byte[] srcin, int max_in_len) { int buf; int n, u, v; @@ -429,7 +424,7 @@ int comp_decode( int acc_len; n = 1 << logn; - buf = in; + buf = 0; acc = 0; acc_len = 0; v = 0; @@ -486,7 +481,7 @@ int comp_decode( return 0; } - srcx[x + u] = (short)(s != 0 ? -m : m); + srcx[u] = (short)(s != 0 ? -m : m); } /* @@ -532,7 +527,7 @@ int comp_decode( * of max_fg_bits[] and max_FG_bits[] shall be greater than 8. */ - final byte[] max_fg_bits = { + static final byte[] max_fg_bits = { 0, /* unused */ 8, 8, @@ -546,7 +541,7 @@ int comp_decode( 5 }; - final byte[] max_FG_bits = { + static final byte[] max_FG_bits = { 0, /* unused */ 8, 8, @@ -588,18 +583,18 @@ int comp_decode( * in -2047..2047, i.e. 12 bits. */ - final byte[] max_sig_bits = { - 0, /* unused */ - 10, - 11, - 11, - 12, - 12, - 12, - 12, - 12, - 12, - 12 - }; +// final byte[] max_sig_bits = { +// 0, /* unused */ +// 10, +// 11, +// 11, +// 12, +// 12, +// 12, +// 12, +// 12, +// 12, +// 12 +// }; } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconCommon.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconCommon.java index a4f266a8df..2a5c19ab42 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconCommon.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconCommon.java @@ -1,13 +1,12 @@ package org.bouncycastle.pqc.crypto.falcon; +import org.bouncycastle.crypto.digests.SHAKEDigest; + class FalconCommon { - FalconCommon() - { - } /* see inner.h */ - void hash_to_point_vartime(SHAKE256 sc, short[] srcx, int x, int logn) + static void hash_to_point_vartime(SHAKEDigest sc, short[] srcx, int logn) { /* * This is the straightforward per-the-spec implementation. It @@ -20,251 +19,253 @@ void hash_to_point_vartime(SHAKE256 sc, short[] srcx, int x, int logn) * plaintexts). */ int n; - + int x = 0; n = 1 << logn; + byte[] buf = new byte[2]; while (n > 0) { - byte[] buf = new byte[2]; + int w; // unsigned // inner_shake256_extract(sc, (void *)buf, sizeof buf); - sc.inner_shake256_extract(buf, 0, 2); + sc.doOutput(buf, 0, 2); w = ((buf[0] & 0xff) << 8) | (buf[1] & 0xff); if (w < 61445) { - while (w >= 12289) - { - w -= 12289; - } +// while (w >= 12289) +// { +// w -= 12289; +// } + w %= 12289; srcx[x++] = (short)w; n--; } } } - void hash_to_point_ct( - SHAKE256 sc, - short[] srcx, int x, int logn, short[] srctmp, int tmp) - { - /* - * Each 16-bit sample is a value in 0..65535. The value is - * kept if it falls in 0..61444 (because 61445 = 5*12289) - * and rejected otherwise; thus, each sample has probability - * about 0.93758 of being selected. - * - * We want to oversample enough to be sure that we will - * have enough values with probability at least 1 - 2^(-256). - * Depending on degree N, this leads to the following - * required oversampling: - * - * logn n oversampling - * 1 2 65 - * 2 4 67 - * 3 8 71 - * 4 16 77 - * 5 32 86 - * 6 64 100 - * 7 128 122 - * 8 256 154 - * 9 512 205 - * 10 1024 287 - * - * If logn >= 7, then the provided temporary buffer is large - * enough. Otherwise, we use a stack buffer of 63 entries - * (i.e. 126 bytes) for the values that do not fit in tmp[]. - */ - - short overtab[] = { - 0, /* unused */ - 65, - 67, - 71, - 77, - 86, - 100, - 122, - 154, - 205, - 287 - }; - - int n, n2, u, m, p, over; - int tt1; - short[] tt2 = new short[63]; - - /* - * We first generate m 16-bit value. Values 0..n-1 go to x[]. - * Values n..2*n-1 go to tt1[]. Values 2*n and later go to tt2[]. - * We also reduce modulo q the values; rejected values are set - * to 0xFFFF. - */ - n = 1 << logn; - n2 = n << 1; - over = overtab[logn]; - m = n + over; - tt1 = tmp; - for (u = 0; u < m; u++) - { - byte[] buf = new byte[2]; - int w, wr; - - sc.inner_shake256_extract(buf, 0, buf.length); - w = ((buf[0] & 0xff) << 8) | (buf[1] & 0xff); - wr = w - (24578 & (((w - 24578) >>> 31) - 1)); - wr = wr - (24578 & (((wr - 24578) >>> 31) - 1)); - wr = wr - (12289 & (((wr - 12289) >>> 31) - 1)); - wr |= ((w - 61445) >>> 31) - 1; - if (u < n) - { - srcx[x + u] = (short)wr; - } - else if (u < n2) - { - srctmp[tt1 + u - n] = (short)wr; - } - else - { - tt2[u - n2] = (short)wr; - } - } - - /* - * Now we must "squeeze out" the invalid values. We do this in - * a logarithmic sequence of passes; each pass computes where a - * value should go, and moves it down by 'p' slots if necessary, - * where 'p' uses an increasing powers-of-two scale. It can be - * shown that in all cases where the loop decides that a value - * has to be moved down by p slots, the destination slot is - * "free" (i.e. contains an invalid value). - */ - for (p = 1; p <= over; p <<= 1) - { - int v; - - /* - * In the loop below: - * - * - v contains the index of the final destination of - * the value; it is recomputed dynamically based on - * whether values are valid or not. - * - * - u is the index of the value we consider ("source"); - * its address is s. - * - * - The loop may swap the value with the one at index - * u-p. The address of the swap destination is d. - */ - v = 0; - for (u = 0; u < m; u++) - { - int s, d; - int sp, dp; - int j, sv, dv, mk; - - if (u < n) - { - sp = 1; - s = x + u; - sv = srcx[s]; - } - else if (u < n2) - { - sp = 2; - s = tt1 + u - n; - sv = srctmp[s]; - } - else - { - sp = 3; - s = u - n2; - sv = tt2[s]; - } - - /* - * The value in sv should ultimately go to - * address v, i.e. jump back by u-v slots. - */ - j = u - v; - - /* - * We increment v for the next iteration, but - * only if the source value is valid. The mask - * 'mk' is -1 if the value is valid, 0 otherwise, - * so we _subtract_ mk. - */ - mk = (sv >>> 15) - 1; - v -= mk; - - /* - * In this loop we consider jumps by p slots; if - * u < p then there is nothing more to do. - */ - if (u < p) - { - continue; - } - - /* - * Destination for the swap: value at address u-p. - */ - if ((u - p) < n) - { - dp = 1; - d = x + u - p; - dv = srcx[d]; - } - else if ((u - p) < n2) - { - dp = 2; - d = tt1 + (u - p) - n; - dv = srctmp[d]; - } - else - { - dp = 3; - d = (u - p) - n2; - dv = tt2[d]; - } - - /* - * The swap should be performed only if the source - * is valid AND the jump j has its 'p' bit set. - */ - mk &= -(((j & p) + 0x1FF) >> 9); - if (sp == 1) - { - srcx[s] = (short)(sv ^ (mk & (sv ^ dv))); - } - else if (sp == 2) - { - srctmp[s] = (short)(sv ^ (mk & (sv ^ dv))); - } - else - { - tt2[s] = (short)(sv ^ (mk & (sv ^ dv))); - } - if (dp == 1) - { - srcx[d] = (short)(dv ^ (mk & (sv ^ dv))); - } - else if (dp == 2) - { - srctmp[d] = (short)(dv ^ (mk & (sv ^ dv))); - } - else - { - tt2[d] = (short)(dv ^ (mk & (sv ^ dv))); - } - } - } - } +// void hash_to_point_ct( +// SHAKE256 sc, +// short[] srcx, int x, int logn, short[] srctmp, int tmp) +// { +// /* +// * Each 16-bit sample is a value in 0..65535. The value is +// * kept if it falls in 0..61444 (because 61445 = 5*12289) +// * and rejected otherwise; thus, each sample has probability +// * about 0.93758 of being selected. +// * +// * We want to oversample enough to be sure that we will +// * have enough values with probability at least 1 - 2^(-256). +// * Depending on degree N, this leads to the following +// * required oversampling: +// * +// * logn n oversampling +// * 1 2 65 +// * 2 4 67 +// * 3 8 71 +// * 4 16 77 +// * 5 32 86 +// * 6 64 100 +// * 7 128 122 +// * 8 256 154 +// * 9 512 205 +// * 10 1024 287 +// * +// * If logn >= 7, then the provided temporary buffer is large +// * enough. Otherwise, we use a stack buffer of 63 entries +// * (i.e. 126 bytes) for the values that do not fit in tmp[]. +// */ +// +// short overtab[] = { +// 0, /* unused */ +// 65, +// 67, +// 71, +// 77, +// 86, +// 100, +// 122, +// 154, +// 205, +// 287 +// }; +// +// int n, n2, u, m, p, over; +// int tt1; +// short[] tt2 = new short[63]; +// +// /* +// * We first generate m 16-bit value. Values 0..n-1 go to x[]. +// * Values n..2*n-1 go to tt1[]. Values 2*n and later go to tt2[]. +// * We also reduce modulo q the values; rejected values are set +// * to 0xFFFF. +// */ +// n = 1 << logn; +// n2 = n << 1; +// over = overtab[logn]; +// m = n + over; +// tt1 = tmp; +// for (u = 0; u < m; u++) +// { +// byte[] buf = new byte[2]; +// int w, wr; +// +// sc.inner_shake256_extract(buf, 0, buf.length); +// w = ((buf[0] & 0xff) << 8) | (buf[1] & 0xff); +// wr = w - (24578 & (((w - 24578) >>> 31) - 1)); +// wr = wr - (24578 & (((wr - 24578) >>> 31) - 1)); +// wr = wr - (12289 & (((wr - 12289) >>> 31) - 1)); +// wr |= ((w - 61445) >>> 31) - 1; +// if (u < n) +// { +// srcx[x + u] = (short)wr; +// } +// else if (u < n2) +// { +// srctmp[tt1 + u - n] = (short)wr; +// } +// else +// { +// tt2[u - n2] = (short)wr; +// } +// } +// +// /* +// * Now we must "squeeze out" the invalid values. We do this in +// * a logarithmic sequence of passes; each pass computes where a +// * value should go, and moves it down by 'p' slots if necessary, +// * where 'p' uses an increasing powers-of-two scale. It can be +// * shown that in all cases where the loop decides that a value +// * has to be moved down by p slots, the destination slot is +// * "free" (i.e. contains an invalid value). +// */ +// for (p = 1; p <= over; p <<= 1) +// { +// int v; +// +// /* +// * In the loop below: +// * +// * - v contains the index of the final destination of +// * the value; it is recomputed dynamically based on +// * whether values are valid or not. +// * +// * - u is the index of the value we consider ("source"); +// * its address is s. +// * +// * - The loop may swap the value with the one at index +// * u-p. The address of the swap destination is d. +// */ +// v = 0; +// for (u = 0; u < m; u++) +// { +// int s, d; +// int sp, dp; +// int j, sv, dv, mk; +// +// if (u < n) +// { +// sp = 1; +// s = x + u; +// sv = srcx[s]; +// } +// else if (u < n2) +// { +// sp = 2; +// s = tt1 + u - n; +// sv = srctmp[s]; +// } +// else +// { +// sp = 3; +// s = u - n2; +// sv = tt2[s]; +// } +// +// /* +// * The value in sv should ultimately go to +// * address v, i.e. jump back by u-v slots. +// */ +// j = u - v; +// +// /* +// * We increment v for the next iteration, but +// * only if the source value is valid. The mask +// * 'mk' is -1 if the value is valid, 0 otherwise, +// * so we _subtract_ mk. +// */ +// mk = (sv >>> 15) - 1; +// v -= mk; +// +// /* +// * In this loop we consider jumps by p slots; if +// * u < p then there is nothing more to do. +// */ +// if (u < p) +// { +// continue; +// } +// +// /* +// * Destination for the swap: value at address u-p. +// */ +// if ((u - p) < n) +// { +// dp = 1; +// d = x + u - p; +// dv = srcx[d]; +// } +// else if ((u - p) < n2) +// { +// dp = 2; +// d = tt1 + (u - p) - n; +// dv = srctmp[d]; +// } +// else +// { +// dp = 3; +// d = (u - p) - n2; +// dv = tt2[d]; +// } +// +// /* +// * The swap should be performed only if the source +// * is valid AND the jump j has its 'p' bit set. +// */ +// mk &= -(((j & p) + 0x1FF) >> 9); +// if (sp == 1) +// { +// srcx[s] = (short)(sv ^ (mk & (sv ^ dv))); +// } +// else if (sp == 2) +// { +// srctmp[s] = (short)(sv ^ (mk & (sv ^ dv))); +// } +// else +// { +// tt2[s] = (short)(sv ^ (mk & (sv ^ dv))); +// } +// if (dp == 1) +// { +// srcx[d] = (short)(dv ^ (mk & (sv ^ dv))); +// } +// else if (dp == 2) +// { +// srctmp[d] = (short)(dv ^ (mk & (sv ^ dv))); +// } +// else +// { +// tt2[d] = (short)(dv ^ (mk & (sv ^ dv))); +// } +// } +// } +// } /* * Acceptance bound for the (squared) l2-norm of the signature depends * on the degree. This array is indexed by logn (1 to 10). These bounds * are _inclusive_ (they are equal to floor(beta^2)). */ - static final int l2bound[] = { + static final int[] l2bound = { 0, /* unused */ 101498, 208714, @@ -279,8 +280,7 @@ else if (dp == 2) }; /* see inner.h */ - int is_short( - short[] srcs1, int s1, short[] srcs2, int s2, int logn) + static int is_short(short[] srcs1, int s1, short[] srcs2, int logn) { /* * We use the l2-norm. Code below uses only 32-bit operations to @@ -300,7 +300,7 @@ int is_short( z = srcs1[s1 + u]; s += (z * z); ng |= s; - z = srcs2[s2 + u]; + z = srcs2[u]; s += (z * z); ng |= s; } @@ -310,8 +310,7 @@ int is_short( } /* see inner.h */ - int is_short_half( - int sqn, short[] srcs2, int s2, int logn) + static int is_short_half(int sqn, short[] srcs2, int logn) { int n, u; int ng; @@ -322,7 +321,7 @@ int is_short_half( { int z; - z = srcs2[s2 + u]; + z = srcs2[u]; sqn += (z * z); ng |= sqn; } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconConversions.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconConversions.java deleted file mode 100644 index 873236ae08..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconConversions.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.bouncycastle.pqc.crypto.falcon; - -class FalconConversions -{ - - FalconConversions() - { - } - - byte[] int_to_bytes(int x) - { - byte[] res = new byte[4]; - res[0] = (byte)(x >>> 0); - res[1] = (byte)(x >>> 8); - res[2] = (byte)(x >>> 16); - res[3] = (byte)(x >>> 24); - return res; - } - - int bytes_to_int(byte[] src, int pos) - { - int acc = 0; - acc = toUnsignedInt(src[pos + 0]) << 0 | - toUnsignedInt(src[pos + 1]) << 8 | - toUnsignedInt(src[pos + 2]) << 16 | - toUnsignedInt(src[pos + 3]) << 24; - return acc; - } - - int[] bytes_to_int_array(byte[] src, int pos, int num) - { - int[] res = new int[num]; - for (int i = 0; i < num; i++) - { - res[i] = bytes_to_int(src, pos + (4 * i)); - } - return res; - } - - byte[] long_to_bytes(long x) - { - byte[] res = new byte[8]; - res[0] = (byte)(x >>> 0); - res[1] = (byte)(x >>> 8); - res[2] = (byte)(x >>> 16); - res[3] = (byte)(x >>> 24); - res[4] = (byte)(x >>> 32); - res[5] = (byte)(x >>> 40); - res[6] = (byte)(x >>> 48); - res[7] = (byte)(x >>> 56); - return res; - } - - long bytes_to_long(byte[] src, int pos) - { - long acc = 0; - acc = toUnsignedLong(src[pos + 0]) << 0 | - toUnsignedLong(src[pos + 1]) << 8 | - toUnsignedLong(src[pos + 2]) << 16 | - toUnsignedLong(src[pos + 3]) << 24 | - toUnsignedLong(src[pos + 4]) << 32 | - toUnsignedLong(src[pos + 5]) << 40 | - toUnsignedLong(src[pos + 6]) << 48 | - toUnsignedLong(src[pos + 7]) << 56; - return acc; - } - - private int toUnsignedInt(byte b) - { - return b & 0xff; - } - - private long toUnsignedLong(byte b) - { - return b & 0xffL; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconFFT.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconFFT.java index bbd72a54f0..adb338947a 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconFFT.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconFFT.java @@ -2,95 +2,58 @@ class FalconFFT { - FPREngine fpr; - - FalconFFT() - { - fpr = new FPREngine(); - } +// FalconFFT() +// { +// } // complex number functions - ComplexNumberWrapper FPC_ADD(FalconFPR a_re, FalconFPR a_im, FalconFPR b_re, FalconFPR b_im) - { - FalconFPR fpct_re, fpct_im; - fpct_re = fpr.fpr_add(a_re, b_re); - fpct_im = fpr.fpr_add(a_im, b_im); - return new ComplexNumberWrapper(fpct_re, fpct_im); - } - - ComplexNumberWrapper FPC_SUB(FalconFPR a_re, FalconFPR a_im, FalconFPR b_re, FalconFPR b_im) - { - FalconFPR fpct_re, fpct_im; - fpct_re = fpr.fpr_sub(a_re, b_re); - fpct_im = fpr.fpr_sub(a_im, b_im); - return new ComplexNumberWrapper(fpct_re, fpct_im); - } - - ComplexNumberWrapper FPC_MUL(FalconFPR a_re, FalconFPR a_im, FalconFPR b_re, FalconFPR b_im) - { - FalconFPR fpct_a_re, fpct_a_im; - FalconFPR fpct_b_re, fpct_b_im; - FalconFPR fpct_d_re, fpct_d_im; - fpct_a_re = (a_re); - fpct_a_im = (a_im); - fpct_b_re = (b_re); - fpct_b_im = (b_im); - fpct_d_re = fpr.fpr_sub( - fpr.fpr_mul(fpct_a_re, fpct_b_re), - fpr.fpr_mul(fpct_a_im, fpct_b_im)); - fpct_d_im = fpr.fpr_add( - fpr.fpr_mul(fpct_a_re, fpct_b_im), - fpr.fpr_mul(fpct_a_im, fpct_b_re)); - return new ComplexNumberWrapper(fpct_d_re, fpct_d_im); - } - - ComplexNumberWrapper FPC_SQR(FalconFPR a_re, FalconFPR a_im) - { - FalconFPR fpct_a_re, fpct_a_im; - FalconFPR fpct_d_re, fpct_d_im; - fpct_a_re = (a_re); - fpct_a_im = (a_im); - fpct_d_re = fpr.fpr_sub(fpr.fpr_sqr(fpct_a_re), fpr.fpr_sqr(fpct_a_im)); - fpct_d_im = fpr.fpr_double(fpr.fpr_mul(fpct_a_re, fpct_a_im)); - return new ComplexNumberWrapper(fpct_d_re, fpct_d_im); - } - - ComplexNumberWrapper FPC_INV(FalconFPR a_re, FalconFPR a_im) - { - FalconFPR fpct_a_re, fpct_a_im; - FalconFPR fpct_d_re, fpct_d_im; - FalconFPR fpct_m; - fpct_a_re = (a_re); - fpct_a_im = (a_im); - fpct_m = fpr.fpr_add(fpr.fpr_sqr(fpct_a_re), fpr.fpr_sqr(fpct_a_im)); - fpct_m = fpr.fpr_inv(fpct_m); - fpct_d_re = fpr.fpr_mul(fpct_a_re, fpct_m); - fpct_d_im = fpr.fpr_mul(fpr.fpr_neg(fpct_a_im), fpct_m); - return new ComplexNumberWrapper(fpct_d_re, fpct_d_im); - } - - ComplexNumberWrapper FPC_DIV(FalconFPR a_re, FalconFPR a_im, FalconFPR b_re, FalconFPR b_im) - { - FalconFPR fpct_a_re, fpct_a_im; - FalconFPR fpct_b_re, fpct_b_im; - FalconFPR fpct_d_re, fpct_d_im; - FalconFPR fpct_m; - fpct_a_re = (a_re); - fpct_a_im = (a_im); - fpct_b_re = (b_re); - fpct_b_im = (b_im); - fpct_m = fpr.fpr_add(fpr.fpr_sqr(fpct_b_re), fpr.fpr_sqr(fpct_b_im)); - fpct_m = fpr.fpr_inv(fpct_m); - fpct_b_re = fpr.fpr_mul(fpct_b_re, fpct_m); - fpct_b_im = fpr.fpr_mul(fpr.fpr_neg(fpct_b_im), fpct_m); - fpct_d_re = fpr.fpr_sub( - fpr.fpr_mul(fpct_a_re, fpct_b_re), - fpr.fpr_mul(fpct_a_im, fpct_b_im)); - fpct_d_im = fpr.fpr_add( - fpr.fpr_mul(fpct_a_re, fpct_b_im), - fpr.fpr_mul(fpct_a_im, fpct_b_re)); - return new ComplexNumberWrapper(fpct_d_re, fpct_d_im); - } +// static ComplexNumberWrapper FPC_ADD(double a_re, double a_im, double b_re, double b_im) +// { +// return new ComplexNumberWrapper(a_re + b_re, a_im + b_im); +// } +// +// static ComplexNumberWrapper FPC_SUB(double a_re, double a_im, double b_re, double b_im) +// { +// return new ComplexNumberWrapper(a_re - b_re, a_im - b_im); +// } + +// static ComplexNumberWrapper FPC_MUL(double a_re, double a_im, double b_re, double b_im) +// { +// return new ComplexNumberWrapper(a_re * b_re - a_im * b_im, a_re * b_im + a_im * b_re); +// } + +// ComplexNumberWrapper FPC_SQR(double a_re, double a_im) +// { +// double fpct_a_re, fpct_a_im; +// double fpct_d_re, fpct_d_im; +// fpct_a_re = (a_re); +// fpct_a_im = (a_im); +// fpct_d_re = FPREngine.fpr_sub(FPREngine.fpr_sqr(fpct_a_re), FPREngine.fpr_sqr(fpct_a_im)); +// fpct_d_im = FPREngine.fpr_double(FPREngine.fpr_mul(fpct_a_re, fpct_a_im)); +// return new ComplexNumberWrapper(fpct_d_re, fpct_d_im); +// } + +// ComplexNumberWrapper FPC_INV(double a_re, double a_im) +// { +// double fpct_a_re, fpct_a_im; +// double fpct_d_re, fpct_d_im; +// double fpct_m; +// fpct_a_re = (a_re); +// fpct_a_im = (a_im); +// fpct_m = FPREngine.fpr_add(FPREngine.fpr_sqr(fpct_a_re), FPREngine.fpr_sqr(fpct_a_im)); +// fpct_m = FPREngine.fpr_inv(fpct_m); +// fpct_d_re = FPREngine.fpr_mul(fpct_a_re, fpct_m); +// fpct_d_im = FPREngine.fpr_mul(FPREngine.fpr_neg(fpct_a_im), fpct_m); +// return new ComplexNumberWrapper(fpct_d_re, fpct_d_im); +// } + +// static ComplexNumberWrapper FPC_DIV(double a_re, double a_im, double b_re, double b_im) +// { +// double fpct_m = 1.0 / (b_re * b_re + b_im * b_im); +// b_re = b_re * fpct_m; +// b_im = -b_im * fpct_m; +// return new ComplexNumberWrapper(a_re * b_re - a_im * b_im, a_re * b_im + a_im * b_re); +// } /* * Let w = exp(i*pi/N); w is a primitive 2N-th root of 1. We define the @@ -117,7 +80,7 @@ ComplexNumberWrapper FPC_DIV(FalconFPR a_re, FalconFPR a_im, FalconFPR b_re, Fal */ /* see inner.h */ - void FFT(FalconFPR[] srcf, int f, int logn) + static void FFT(double[] srcf, int f, int logn) { /* * FFT algorithm in bit-reversal order uses the following @@ -165,41 +128,33 @@ void FFT(FalconFPR[] srcf, int f, int logn) n = 1 << logn; hn = n >> 1; t = hn; + int ht, hm, i1, j1; + int j2, fj, fjhn, fjht, fjhthn; + double s_re, s_im; + double x_re, x_im, y_re, y_im, a_re, a_im; for (u = 1, m = 2; u < logn; u++, m <<= 1) { - int ht, hm, i1, j1; - ht = t >> 1; hm = m >> 1; for (i1 = 0, j1 = 0; i1 < hm; i1++, j1 += t) { - int j, j2; - - j2 = j1 + ht; - FalconFPR s_re, s_im; - - s_re = fpr.fpr_gm_tab[((m + i1) << 1) + 0]; - s_im = fpr.fpr_gm_tab[((m + i1) << 1) + 1]; - for (j = j1; j < j2; j++) + j2 = j1 + ht + f; + fj = ((m + i1) << 1); + s_re = FPREngine.fpr_gm_tab[fj]; + s_im = FPREngine.fpr_gm_tab[fj + 1]; + for (fj = f + j1, fjhn = fj + hn, fjht = fj + ht, fjhthn = fjht + hn; fj < j2; + fj++, fjhn++, fjht++, fjhthn++) { - FalconFPR x_re, x_im, y_re, y_im; - ComplexNumberWrapper res; - - x_re = srcf[f + j]; - x_im = srcf[f + j + hn]; - y_re = srcf[f + j + ht]; - y_im = srcf[f + j + ht + hn]; - res = FPC_MUL(y_re, y_im, s_re, s_im); - y_re = res.re; - y_im = res.im; - - res = FPC_ADD(x_re, x_im, y_re, y_im); - srcf[f + j] = res.re; - srcf[f + j + hn] = res.im; - - res = FPC_SUB(x_re, x_im, y_re, y_im); - srcf[f + j + ht] = res.re; - srcf[f + j + ht + hn] = res.im; + x_re = srcf[fj]; + x_im = srcf[fjhn]; + a_re = srcf[fjht]; + a_im = srcf[fjhthn]; + y_re = a_re * s_re - a_im * s_im; + y_im = a_re * s_im + a_im * s_re; + srcf[fj] = x_re + y_re; + srcf[fjhn] = x_im + y_im; + srcf[fjht] = x_re - y_re; + srcf[fjhthn] = x_im - y_im; } } t = ht; @@ -207,7 +162,7 @@ void FFT(FalconFPR[] srcf, int f, int logn) } /* see inner.h */ - void iFFT(FalconFPR[] srcf, int f, int logn) + static void iFFT(double[] srcf, int f, int logn) { /* * Inverse FFT algorithm in bit-reversal order uses the following @@ -252,46 +207,37 @@ void iFFT(FalconFPR[] srcf, int f, int logn) * division into a division by N/2, not N. */ int u, n, hn, t, m; - + int dt, hm, i1, j1; + int j2, fj, fjhn, fjt, fjthn; + double s_re, s_im; + double x_re, x_im, y_re, y_im; n = 1 << logn; t = 1; m = n; hn = n >> 1; for (u = logn; u > 1; u--) { - int hm, dt, i1, j1; - hm = m >> 1; dt = t << 1; for (i1 = 0, j1 = 0; j1 < hn; i1++, j1 += dt) { - int j, j2; - - j2 = j1 + t; - FalconFPR s_re, s_im; - - s_re = fpr.fpr_gm_tab[((hm + i1) << 1) + 0]; - s_im = fpr.fpr_neg(fpr.fpr_gm_tab[((hm + i1) << 1) + 1]); - for (j = j1; j < j2; j++) + j2 = j1 + t + f; + fj = (hm + i1) << 1; + s_re = FPREngine.fpr_gm_tab[fj]; + s_im = -FPREngine.fpr_gm_tab[fj + 1]; + for (fj = f + j1, fjhn = fj + hn, fjt = fj + t, fjthn = fjt + hn; fj < j2; + fj++, fjhn++, fjt++, fjthn++) { - FalconFPR x_re, x_im, y_re, y_im; - ComplexNumberWrapper res; - - x_re = srcf[f + j]; - x_im = srcf[f + j + hn]; - y_re = srcf[f + j + t]; - y_im = srcf[f + j + t + hn]; - res = FPC_ADD(x_re, x_im, y_re, y_im); - srcf[f + j] = res.re; - srcf[f + j + hn] = res.im; - - res = FPC_SUB(x_re, x_im, y_re, y_im); - x_re = res.re; - x_im = res.im; - - res = FPC_MUL(x_re, x_im, s_re, s_im); - srcf[f + j + t] = res.re; - srcf[f + j + t + hn] = res.im; + x_re = srcf[fj]; + x_im = srcf[fjhn]; + y_re = srcf[fjt]; + y_im = srcf[fjthn]; + srcf[fj] = x_re + y_re; + srcf[fjhn] = x_im + y_im; + x_re -= y_re; + x_im -= y_im; + srcf[fjt] = x_re * s_re - x_im * s_im; + srcf[fjthn] = x_re * s_im + x_im * s_re; } } t = dt; @@ -304,114 +250,108 @@ void iFFT(FalconFPR[] srcf, int f, int logn) */ if (logn > 0) { - FalconFPR ni; + double ni; - ni = fpr.fpr_p2_tab[logn]; + ni = FPREngine.fpr_p2_tab[logn]; for (u = 0; u < n; u++) { - srcf[f + u] = fpr.fpr_mul(srcf[f + u], ni); + srcf[f + u] = srcf[f + u] * ni; } } } /* see inner.h */ - void poly_add( - FalconFPR[] srca, int a, FalconFPR[] srcb, int b, int logn) + static void poly_add( + double[] srca, int a, double[] srcb, int b, int logn) { int n, u; n = 1 << logn; for (u = 0; u < n; u++) { - srca[a + u] = fpr.fpr_add(srca[a + u], srcb[b + u]); + srca[a + u] += srcb[b + u]; } } /* see inner.h */ - void poly_sub( - FalconFPR[] srca, int a, FalconFPR[] srcb, int b, int logn) + static void poly_sub( + double[] srca, int a, double[] srcb, int b, int logn) { int n, u; n = 1 << logn; for (u = 0; u < n; u++) { - srca[a + u] = fpr.fpr_sub(srca[a + u], srcb[b + u]); + srca[a + u] -= srcb[b + u]; } } /* see inner.h */ - void poly_neg(FalconFPR[] srca, int a, int logn) + static void poly_neg(double[] srca, int a, int logn) { int n, u; n = 1 << logn; for (u = 0; u < n; u++) { - srca[a + u] = fpr.fpr_neg(srca[a + u]); + srca[a + u] = -srca[a + u]; } } /* see inner.h */ - void poly_adj_fft(FalconFPR[] srca, int a, int logn) + static void poly_adj_fft(double[] srca, int a, int logn) { int n, u; n = 1 << logn; for (u = (n >> 1); u < n; u++) { - srca[a + u] = fpr.fpr_neg(srca[a + u]); + srca[a + u] = -srca[a + u]; } } /* see inner.h */ - void poly_mul_fft( - FalconFPR[] srca, int a, FalconFPR[] srcb, int b, int logn) + static void poly_mul_fft( + double[] srca, int a, double[] srcb, int b, int logn) { int n, hn, u; n = 1 << logn; hn = n >> 1; - for (u = 0; u < hn; u++) + double a_re, a_im, b_re, b_im; + int au, auhn, bu; + for (u = 0, au = a, auhn = a + hn, bu = b; u < hn; u++, au++, bu++, auhn++) { - FalconFPR a_re, a_im, b_re, b_im; - ComplexNumberWrapper res; - - a_re = srca[a + u]; - a_im = srca[a + u + hn]; - b_re = srcb[b + u]; - b_im = srcb[b + u + hn]; - res = FPC_MUL(a_re, a_im, b_re, b_im); - srca[a + u] = res.re; - srca[a + u + hn] = res.im; + a_re = srca[au]; + a_im = srca[auhn]; + b_re = srcb[bu]; + b_im = srcb[bu + hn]; + srca[au] = a_re * b_re - a_im * b_im; + srca[auhn] = a_re * b_im + a_im * b_re; } } /* see inner.h */ - void poly_muladj_fft( - FalconFPR[] srca, int a, FalconFPR[] srcb, int b, int logn) + static void poly_muladj_fft( + double[] srca, int a, double[] srcb, int b, int logn) { - int n, hn, u; - + int n, hn, u, au; + double a_re, a_im, b_re, b_im; n = 1 << logn; hn = n >> 1; - for (u = 0; u < hn; u++) + for (u = 0, au = a; u < hn; u++, au++) { - FalconFPR a_re, a_im, b_re, b_im; - ComplexNumberWrapper res; - - a_re = srca[a + u]; - a_im = srca[a + u + hn]; + a_re = srca[au]; + a_im = srca[au + hn]; b_re = srcb[b + u]; - b_im = fpr.fpr_neg(srcb[b + u + hn]); - res = FPC_MUL(a_re, a_im, b_re, b_im); - srca[a + u] = res.re; - srca[a + u + hn] = res.im; + b_im = srcb[b + u + hn]; + srca[au] = a_re * b_re + a_im * b_im; + srca[au + hn] = a_im * b_re - a_re * b_im; } } /* see inner.h */ - void poly_mulselfadj_fft(FalconFPR[] srca, int a, int logn) + static void poly_mulselfadj_fft(double[] srca, int a, int logn) { /* * Since each coefficient is multiplied with its own conjugate, @@ -423,113 +363,108 @@ void poly_mulselfadj_fft(FalconFPR[] srca, int a, int logn) hn = n >> 1; for (u = 0; u < hn; u++) { - FalconFPR a_re, a_im; - ComplexNumberWrapper res; + double a_re, a_im; + //ComplexNumberWrapper res; a_re = srca[a + u]; a_im = srca[a + u + hn]; - srca[a + u] = fpr.fpr_add(fpr.fpr_sqr(a_re), fpr.fpr_sqr(a_im)); - srca[a + u + hn] = fpr.fpr_zero; + srca[a + u] = a_re * a_re + a_im * a_im; + srca[a + u + hn] = FPREngine.fpr_zero; } } /* see inner.h */ - void poly_mulconst(FalconFPR[] srca, int a, FalconFPR x, int logn) + static void poly_mulconst(double[] srca, int a, double x, int logn) { int n, u; n = 1 << logn; for (u = 0; u < n; u++) { - srca[a + u] = fpr.fpr_mul(srca[a + u], x); + srca[a + u] = srca[a + u] * x; } } /* see inner.h */ - void poly_div_fft( - FalconFPR[] srca, int a, FalconFPR[] srcb, int b, int logn) - { - int n, hn, u; - - n = 1 << logn; - hn = n >> 1; - for (u = 0; u < hn; u++) - { - FalconFPR a_re, a_im, b_re, b_im; - ComplexNumberWrapper res; - - a_re = srca[a + u]; - a_im = srca[a + u + hn]; - b_re = srcb[b + u]; - b_im = srcb[b + u + hn]; - res = FPC_DIV(a_re, a_im, b_re, b_im); - srca[a + u] = res.re; - srca[a + u + hn] = res.im; - } - } +// void poly_div_fft( +// double[] srca, int a, double[] srcb, int b, int logn) +// { +// int n, hn, u; +// +// n = 1 << logn; +// hn = n >> 1; +// for (u = 0; u < hn; u++) +// { +// double a_re, a_im, b_re, b_im; +// ComplexNumberWrapper res; +// +// a_re = srca[a + u]; +// a_im = srca[a + u + hn]; +// b_re = srcb[b + u]; +// b_im = srcb[b + u + hn]; +// res = FPC_DIV(a_re, a_im, b_re, b_im); +// srca[a + u] = res.re; +// srca[a + u + hn] = res.im; +// } +// } /* see inner.h */ - void poly_invnorm2_fft(FalconFPR[] srcd, int d, - FalconFPR[] srca, int a, FalconFPR[] srcb, int b, int logn) + static void poly_invnorm2_fft(double[] srcd, int d, + double[] srca, int a, double[] srcb, int b, int logn) { int n, hn, u; - + double a_re, a_im; + double b_re, b_im; n = 1 << logn; hn = n >> 1; for (u = 0; u < hn; u++) { - FalconFPR a_re, a_im; - FalconFPR b_re, b_im; + a_re = srca[a + u]; a_im = srca[a + u + hn]; b_re = srcb[b + u]; b_im = srcb[b + u + hn]; - srcd[d + u] = fpr.fpr_inv(fpr.fpr_add( - fpr.fpr_add(fpr.fpr_sqr(a_re), fpr.fpr_sqr(a_im)), - fpr.fpr_add(fpr.fpr_sqr(b_re), fpr.fpr_sqr(b_im)))); + srcd[d + u] = 1.0 / (a_re * a_re + a_im * a_im + + b_re * b_re + b_im * b_im); } } /* see inner.h */ - void poly_add_muladj_fft(FalconFPR[] srcd, int d, - FalconFPR[] srcF, int F, FalconFPR[] srcG, int G, - FalconFPR[] srcf, int f, FalconFPR[] srcg, int g, int logn) + static void poly_add_muladj_fft(double[] srcd, + double[] srcF, double[] srcG, + double[] srcf, double[] srcg, int logn) { int n, hn, u; - + double F_re, F_im, G_re, G_im; + double f_re, f_im, g_re, g_im; + double a_re, a_im, b_re, b_im; n = 1 << logn; hn = n >> 1; for (u = 0; u < hn; u++) { - FalconFPR F_re, F_im, G_re, G_im; - FalconFPR f_re, f_im, g_re, g_im; - FalconFPR a_re, a_im, b_re, b_im; - ComplexNumberWrapper res; - - F_re = srcF[F + u]; - F_im = srcF[F + u + hn]; - G_re = srcG[G + u]; - G_im = srcG[G + u + hn]; - f_re = srcf[f + u]; - f_im = srcf[f + u + hn]; - g_re = srcg[g + u]; - g_im = srcg[g + u + hn]; - - res = FPC_MUL(F_re, F_im, f_re, fpr.fpr_neg(f_im)); - a_re = res.re; - a_im = res.im; - res = FPC_MUL(G_re, G_im, g_re, fpr.fpr_neg(g_im)); - b_re = res.re; - b_im = res.im; - srcd[d + u] = fpr.fpr_add(a_re, b_re); - srcd[d + u + hn] = fpr.fpr_add(a_im, b_im); + int uhn = u + hn; + F_re = srcF[u]; + F_im = srcF[uhn]; + G_re = srcG[u]; + G_im = srcG[uhn]; + f_re = srcf[u]; + f_im = srcf[uhn]; + g_re = srcg[u]; + g_im = srcg[uhn]; + + a_re = F_re * f_re + F_im * f_im; + a_im = F_im * f_re - F_re * f_im; + b_re = G_re * g_re + G_im * g_im; + b_im = G_im * g_re - G_re * g_im; + srcd[u] = a_re + b_re; + srcd[uhn] = a_im + b_im; } } /* see inner.h */ - void poly_mul_autoadj_fft( - FalconFPR[] srca, int a, FalconFPR[] srcb, int b, int logn) + static void poly_mul_autoadj_fft( + double[] srca, int a, double[] srcb, int b, int logn) { int n, hn, u; @@ -537,14 +472,14 @@ void poly_mul_autoadj_fft( hn = n >> 1; for (u = 0; u < hn; u++) { - srca[a + u] = fpr.fpr_mul(srca[a + u], srcb[b + u]); - srca[a + u + hn] = fpr.fpr_mul(srca[a + u + hn], srcb[b + u]); + srca[a + u] *= srcb[b + u]; + srca[a + u + hn] *= srcb[b + u]; } } /* see inner.h */ - void poly_div_autoadj_fft( - FalconFPR[] srca, int a, FalconFPR[] srcb, int b, int logn) + static void poly_div_autoadj_fft( + double[] srca, int a, double[] srcb, int b, int logn) { int n, hn, u; @@ -552,89 +487,85 @@ void poly_div_autoadj_fft( hn = n >> 1; for (u = 0; u < hn; u++) { - FalconFPR ib; - - ib = fpr.fpr_inv(srcb[b + u]); - srca[a + u] = fpr.fpr_mul(srca[a + u], ib); - srca[a + u + hn] = fpr.fpr_mul(srca[a + u + hn], ib); + double ib = 1.0 / srcb[b + u]; + srca[a + u] *= ib; + srca[a + u + hn] *= ib; } } /* see inner.h */ - void poly_LDL_fft( - FalconFPR[] srcg00, int g00, - FalconFPR[] srcg01, int g01, FalconFPR[] srcg11, int g11, int logn) + static void poly_LDL_fft( + double[] srcg00, int g00, + double[] srcg01, int g01, double[] srcg11, int g11, int logn) { - int n, hn, u; - + int n, hn, u, uhn, g01u, g01uhn; + double g00_re, g00_im, g01_re, g01_im, g11_re, g11_im; n = 1 << logn; hn = n >> 1; - for (u = 0; u < hn; u++) + for (u = 0, uhn = hn, g01u = g01, g01uhn = g01 + hn; + u < hn; u++, uhn++, g01u++, g01uhn++) { - FalconFPR g00_re, g00_im, g01_re, g01_im, g11_re, g11_im; - FalconFPR mu_re, mu_im; - ComplexNumberWrapper res; - g00_re = srcg00[g00 + u]; - g00_im = srcg00[g00 + u + hn]; - g01_re = srcg01[g01 + u]; - g01_im = srcg01[g01 + u + hn]; - g11_re = srcg11[g11 + u]; - g11_im = srcg11[g11 + u + hn]; - res = FPC_DIV(g01_re, g01_im, g00_re, g00_im); - mu_re = res.re; - mu_im = res.im; - res = FPC_MUL(mu_re, mu_im, g01_re, fpr.fpr_neg(g01_im)); - g01_re = res.re; - g01_im = res.im; - res = FPC_SUB(g11_re, g11_im, g01_re, g01_im); - srcg11[g11 + u] = res.re; - srcg11[g11 + u + hn] = res.im; - srcg01[g01 + u] = mu_re; - srcg01[g01 + u + hn] = fpr.fpr_neg(mu_im); + g00_im = srcg00[g00 + uhn]; + g01_re = srcg01[g01u]; + g01_im = srcg01[g01uhn]; + + g11_im = 1.0 / (g00_re * g00_re + g00_im * g00_im); + g11_re = g00_re * g11_im; + g11_im *= -g00_im; + g00_re = g01_re * g11_re - g01_im * g11_im; + g00_im = g01_re * g11_im + g01_im * g11_re; + g11_re = g01_re; + g11_im = g01_im; + g01_re = g00_re * g11_re + g00_im * g11_im; + g01_im = g00_re * -g11_im + g00_im * g11_re; + srcg11[g11 + u] -= g01_re; + srcg11[g11 + uhn] -= g01_im; + srcg01[g01u] = g00_re; + srcg01[g01uhn] = -g00_im; } } /* see inner.h */ - void poly_LDLmv_fft( - FalconFPR[] srcd11, int d11, FalconFPR[] srcl10, int l10, - FalconFPR[] srcg00, int g00, FalconFPR[] srcg01, int g01, - FalconFPR[] srcg11, int g11, int logn) - { - int n, hn, u; - - n = 1 << logn; - hn = n >> 1; - for (u = 0; u < hn; u++) - { - FalconFPR g00_re, g00_im, g01_re, g01_im, g11_re, g11_im; - FalconFPR mu_re, mu_im; - ComplexNumberWrapper res; - - g00_re = srcg00[g00 + u]; - g00_im = srcg00[g00 + u + hn]; - g01_re = srcg01[g01 + u]; - g01_im = srcg01[g01 + u + hn]; - g11_re = srcg11[g11 + u]; - g11_im = srcg11[g11 + u + hn]; - res = FPC_DIV(g01_re, g01_im, g00_re, g00_im); - mu_re = res.re; - mu_im = res.im; - res = FPC_MUL(mu_re, mu_im, g01_re, fpr.fpr_neg(g01_im)); - g01_re = res.re; - g01_im = res.im; - res = FPC_SUB(g11_re, g11_im, g01_re, g01_im); - srcd11[d11 + u] = res.re; - srcd11[d11 + u + hn] = res.im; - srcl10[l10 + u] = mu_re; - srcl10[l10 + u + hn] = fpr.fpr_neg(mu_im); - } - } +// void poly_LDLmv_fft( +// double[] srcd11, int d11, double[] srcl10, int l10, +// double[] srcg00, int g00, double[] srcg01, int g01, +// double[] srcg11, int g11, int logn) +// { +// int n, hn, u; +// +// n = 1 << logn; +// hn = n >> 1; +// for (u = 0; u < hn; u++) +// { +// double g00_re, g00_im, g01_re, g01_im, g11_re, g11_im; +// double mu_re, mu_im; +// ComplexNumberWrapper res; +// +// g00_re = srcg00[g00 + u]; +// g00_im = srcg00[g00 + u + hn]; +// g01_re = srcg01[g01 + u]; +// g01_im = srcg01[g01 + u + hn]; +// g11_re = srcg11[g11 + u]; +// g11_im = srcg11[g11 + u + hn]; +// res = FPC_DIV(g01_re, g01_im, g00_re, g00_im); +// mu_re = res.re; +// mu_im = res.im; +// res = FPC_MUL(mu_re, mu_im, g01_re, FPREngine.fpr_neg(g01_im)); +// g01_re = res.re; +// g01_im = res.im; +// res = FPC_SUB(g11_re, g11_im, g01_re, g01_im); +// srcd11[d11 + u] = res.re; +// srcd11[d11 + u + hn] = res.im; +// srcl10[l10 + u] = mu_re; +// srcl10[l10 + u + hn] = FPREngine.fpr_neg(mu_im); +// } +// } /* see inner.h */ - void poly_split_fft( - FalconFPR[] srcf0, int f0, FalconFPR[] srcf1, int f1, - FalconFPR[] srcf, int f, int logn) + static void poly_split_fft( + double[] srcf0, int f0, double[] srcf1, int f1, + double[] srcf, int f, int logn) { /* * The FFT representation we use is in bit-reversed order @@ -643,57 +574,52 @@ void poly_split_fft( * indexes with regards to the Falcon specification. */ int n, hn, qn, u; - + double a_re, a_im, b_re, b_im; + double t_re, t_im; n = 1 << logn; hn = n >> 1; qn = hn >> 1; - + int idx; /* * We process complex values by pairs. For logn = 1, there is only * one complex value (the other one is the implicit conjugate), * so we add the two lines below because the loop will be * skipped. */ - srcf0[f0 + 0] = srcf[f + 0]; - srcf1[f1 + 0] = srcf[f + hn]; + srcf0[f0] = srcf[f]; + srcf1[f1] = srcf[f + hn]; for (u = 0; u < qn; u++) { - FalconFPR a_re, a_im, b_re, b_im; - FalconFPR t_re, t_im; - ComplexNumberWrapper res; - - a_re = srcf[f + (u << 1) + 0]; - a_im = srcf[f + (u << 1) + 0 + hn]; - b_re = srcf[f + (u << 1) + 1]; - b_im = srcf[f + (u << 1) + 1 + hn]; - - res = FPC_ADD(a_re, a_im, b_re, b_im); - t_re = res.re; - t_im = res.im; - srcf0[f0 + u] = fpr.fpr_half(t_re); - srcf0[f0 + u + qn] = fpr.fpr_half(t_im); - - res = FPC_SUB(a_re, a_im, b_re, b_im); - t_re = res.re; - t_im = res.im; - res = FPC_MUL(t_re, t_im, - fpr.fpr_gm_tab[((u + hn) << 1) + 0], - fpr.fpr_neg(fpr.fpr_gm_tab[((u + hn) << 1) + 1])); - t_re = res.re; - t_im = res.im; - srcf1[f1 + u] = fpr.fpr_half(t_re); - srcf1[f1 + u + qn] = fpr.fpr_half(t_im); + idx = f + (u << 1); + a_re = srcf[idx]; + a_im = srcf[idx++ + hn]; + b_re = srcf[idx]; + b_im = srcf[idx + hn]; + + srcf0[f0 + u] = (a_re + b_re) * 0.5; + srcf0[f0 + u + qn] = (a_im + b_im) * 0.5; + + t_re = a_re - b_re; + t_im = a_im - b_im; + + idx = ((u + hn) << 1); + b_re = FPREngine.fpr_gm_tab[idx]; + b_im = -FPREngine.fpr_gm_tab[idx + 1]; + idx = f1 + u; + srcf1[idx] = (t_re * b_re - t_im * b_im) * 0.5; + srcf1[idx + qn] = (t_re * b_im + t_im * b_re) * 0.5; } } /* see inner.h */ - void poly_merge_fft( - FalconFPR[] srcf, int f, - FalconFPR[] srcf0, int f0, FalconFPR[] srcf1, int f1, int logn) + static void poly_merge_fft( + double[] srcf, int f, + double[] srcf0, int f0, double[] srcf1, int f1, int logn) { - int n, hn, qn, u; - + int n, hn, qn, u, idx; + double a_re, a_im, b_re, b_im; + double t_re, t_im; n = 1 << logn; hn = n >> 1; qn = hn >> 1; @@ -701,32 +627,30 @@ void poly_merge_fft( /* * An extra copy to handle the special case logn = 1. */ - srcf[f + 0] = srcf0[f0 + 0]; - srcf[f + hn] = srcf1[f1 + 0]; + srcf[f] = srcf0[f0]; + srcf[f + hn] = srcf1[f1]; for (u = 0; u < qn; u++) { - FalconFPR a_re, a_im, b_re, b_im; - FalconFPR t_re, t_im; - ComplexNumberWrapper res; - - a_re = srcf0[f0 + u]; - a_im = srcf0[f0 + u + qn]; - res = FPC_MUL(srcf1[f1 + u], srcf1[f1 + u + qn], - fpr.fpr_gm_tab[((u + hn) << 1) + 0], - fpr.fpr_gm_tab[((u + hn) << 1) + 1]); - b_re = res.re; - b_im = res.im; - res = FPC_ADD(a_re, a_im, b_re, b_im); - t_re = res.re; - t_im = res.im; - srcf[f + (u << 1) + 0] = t_re; - srcf[f + (u << 1) + 0 + hn] = t_im; - res = FPC_SUB(a_re, a_im, b_re, b_im); - t_re = res.re; - t_im = res.im; - srcf[f + (u << 1) + 1] = t_re; - srcf[f + (u << 1) + 1 + hn] = t_im; + idx = f1 + u; + a_re = srcf1[idx]; + a_im = srcf1[idx + qn]; + idx = ((u + hn) << 1); + t_re = FPREngine.fpr_gm_tab[idx]; + t_im = FPREngine.fpr_gm_tab[idx + 1]; + b_re = a_re * t_re - a_im * t_im; + b_im = a_re * t_im + a_im * t_re; + + idx = f0 + u; + a_re = srcf0[idx]; + a_im = srcf0[idx + qn]; + + idx = f + (u << 1); + srcf[idx] = a_re + b_re; + srcf[idx++ + hn] = a_im + b_im; + + srcf[idx] = a_re - b_re; + srcf[idx + hn] = a_im - b_im; } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconFPR.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconFPR.java deleted file mode 100644 index ec1f90343a..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconFPR.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.bouncycastle.pqc.crypto.falcon; - -class FalconFPR -{ - double v; - - FalconFPR(double v) - { - this.v = v; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconKeyGen.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconKeyGen.java index 2932bc8c27..d1b26add7b 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconKeyGen.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconKeyGen.java @@ -1,20 +1,23 @@ package org.bouncycastle.pqc.crypto.falcon; +import org.bouncycastle.crypto.digests.SHAKEDigest; +import org.bouncycastle.util.Pack; + class FalconKeyGen { - FPREngine fpr; - FalconSmallPrimeList primes; - FalconFFT fft; - FalconCodec codec; - FalconVrfy vrfy; + // FPREngine fpr; + //FalconSmallPrimeList primes; + //FalconFFT fft; +// FalconCodec codec; +// FalconVrfy vrfy; FalconKeyGen() { - this.fpr = new FPREngine(); - this.primes = new FalconSmallPrimeList(); - this.fft = new FalconFFT(); - this.codec = new FalconCodec(); - this.vrfy = new FalconVrfy(); +// this.fpr = new FPREngine(); + //this.primes = new FalconSmallPrimeList(); + //this.fft = new FalconFFT(); +// this.codec = new FalconCodec(); +// this.vrfy = new FalconVrfy(); } private static int mkn(int logn) @@ -26,11 +29,9 @@ private static int mkn(int logn) * Reduce a small signed integer modulo a small prime. The source * value x MUST be such that -p < x < p. */ - int modp_set(int x, int p) + private static int modp_set(int x, int p) { - int w; - - w = x; + int w = x; w += p & -(w >>> 31); return w; } @@ -38,7 +39,7 @@ int modp_set(int x, int p) /* * Normalize a modular integer around 0. */ - int modp_norm(int x, int p) + private static int modp_norm(int x, int p) { return (x - (p & (((x - ((p + 1) >>> 1)) >>> 31) - 1))); } @@ -47,11 +48,9 @@ int modp_norm(int x, int p) * Compute -1/p mod 2^31. This works for all odd integers p that fit * on 31 bits. */ - int modp_ninv31(int p) + private static int modp_ninv31(int p) { - int y; - - y = 2 - p; + int y = 2 - p; y *= 2 - p * y; y *= 2 - p * y; y *= 2 - p * y; @@ -62,7 +61,7 @@ int modp_ninv31(int p) /* * Compute R = 2^31 mod p. */ - int modp_R(int p) + private static int modp_R(int p) { /* * Since 2^30 < p < 2^31, we know that 2^31 mod p is simply @@ -74,11 +73,9 @@ int modp_R(int p) /* * Addition modulo p. */ - int modp_add(int a, int b, int p) + private static int modp_add(int a, int b, int p) { - int d; - - d = a + b - p; + int d = a + b - p; d += p & -(d >>> 31); return d; } @@ -86,11 +83,9 @@ int modp_add(int a, int b, int p) /* * Subtraction modulo p. */ - int modp_sub(int a, int b, int p) + private static int modp_sub(int a, int b, int p) { - int d; - - d = a - b; + int d = a - b; d += p & -(d >>> 31); return d; } @@ -99,13 +94,13 @@ int modp_sub(int a, int b, int p) * Montgomery multiplication modulo p. The 'p0i' value is -1/p mod 2^31. * It is required that p is an odd integer. */ - int modp_montymul(int a, int b, int p, int p0i) + private static int modp_montymul(int a, int b, int p, int p0i) { long z, w; int d; z = toUnsignedLong(a) * toUnsignedLong(b); - w = ((z * p0i) & toUnsignedLong(0x7FFFFFFF)) * p; + w = ((z * p0i) & 0x7FFFFFFFL) * p; d = (int)((z + w) >>> 31) - p; d += p & -(d >>> 31); return d; @@ -114,7 +109,7 @@ int modp_montymul(int a, int b, int p, int p0i) /* * Compute R2 = 2^62 mod p. */ - int modp_R2(int p, int p0i) + private static int modp_R2(int p, int p0i) { int z; @@ -147,7 +142,7 @@ int modp_R2(int p, int p0i) * p must be prime such that 2^30 < p < 2^31; p0i must be equal to * -1/p mod 2^31; R2 must be equal to 2^62 mod p. */ - int modp_Rx(int x, int p, int p0i, int R2) + private static int modp_Rx(int x, int p, int p0i, int R2) { int i; int r, z; @@ -181,7 +176,7 @@ int modp_Rx(int x, int p, int p0i, int R2) * p0i -1/p mod 2^31 * R 2^31 mod R */ - int modp_div(int a, int b, int p, int p0i, int R) + private static int modp_div(int a, int b, int p, int p0i, int R) { int z, e; int i; @@ -215,7 +210,7 @@ int modp_div(int a, int b, int p, int p0i, int R) /* * Bit-reversal index table. */ - private short REV10[] = { + private static final short[] REV10 = { 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, @@ -317,8 +312,8 @@ int modp_div(int a, int b, int p, int p0i, int R) * * p must be a prime such that p = 1 mod 2048. */ - void modp_mkgm2(int[] srcgm, int gm, int[] srcigm, int igm, int logn, - int g, int p, int p0i) + private static void modp_mkgm2(int[] srcgm, int gm, int[] srcigm, int igm, int logn, + int g, int p, int p0i) { int u, n; int k; @@ -356,8 +351,8 @@ void modp_mkgm2(int[] srcgm, int gm, int[] srcigm, int igm, int logn, * Compute the NTT over a polynomial (binary case). Polynomial elements * are a[0], a[stride], a[2 * stride]... */ - void modp_NTT2_ext(int[] srca, int a, int stride, int[] srcgm, int gm, int logn, - int p, int p0i) + private static void modp_NTT2_ext(int[] srca, int a, int stride, int[] srcgm, int gm, int logn, + int p, int p0i) { int t, m, n; @@ -398,8 +393,8 @@ void modp_NTT2_ext(int[] srca, int a, int stride, int[] srcgm, int gm, int logn, /* * Compute the inverse NTT over a polynomial (binary case). */ - void modp_iNTT2_ext(int[] srca, int a, int stride, int[] srcigm, int igm, int logn, - int p, int p0i) + private static void modp_iNTT2_ext(int[] srca, int a, int stride, int[] srcigm, int igm, int logn, + int p, int p0i) { int t, m, n, k; int ni; @@ -435,7 +430,6 @@ void modp_iNTT2_ext(int[] srca, int a, int stride, int[] srcigm, int igm, int lo srca[r1] = modp_add(x, y, p); srca[r2] = modp_montymul( modp_sub(x, y, p), s, p, p0i); - ; } } t = dt; @@ -458,13 +452,13 @@ void modp_iNTT2_ext(int[] srca, int a, int stride, int[] srcigm, int igm, int lo * are consecutive in RAM. */ // #define modp_NTT2(a, gm, logn, p, p0i) modp_NTT2_ext(a, 1, gm, logn, p, p0i) - void modp_NTT2(int[] srca, int a, int[] srcgm, int gm, int logn, int p, int p0i) + private static void modp_NTT2(int[] srca, int a, int[] srcgm, int gm, int logn, int p, int p0i) { modp_NTT2_ext(srca, a, 1, srcgm, gm, logn, p, p0i); } // #define modp_iNTT2(a, igm, logn, p, p0i) modp_iNTT2_ext(a, 1, igm, logn, p, p0i) - void modp_iNTT2(int[] srca, int a, int[] srcigm, int igm, int logn, int p, int p0i) + private static void modp_iNTT2(int[] srca, int a, int[] srcigm, int igm, int logn, int p, int p0i) { modp_iNTT2_ext(srca, a, 1, srcigm, igm, logn, p, p0i); } @@ -483,8 +477,8 @@ void modp_iNTT2(int[] srca, int a, int[] srcigm, int igm, int logn, int p, int p * This function applies only to the binary case; it is invoked from * solve_NTRU_binary_depth1(). */ - void modp_poly_rec_res(int[] srcf, int f, int logn, - int p, int p0i, int R2) + private static void modp_poly_rec_res(int[] srcf, int f, int logn, + int p, int p0i, int R2) { int hn, u; @@ -493,7 +487,7 @@ void modp_poly_rec_res(int[] srcf, int f, int logn, { int w0, w1; - w0 = srcf[f + (u << 1) + 0]; + w0 = srcf[f + (u << 1)]; w1 = srcf[f + (u << 1) + 1]; srcf[f + u] = modp_montymul(modp_montymul(w0, w1, p, p0i), R2, p, p0i); } @@ -540,32 +534,30 @@ void modp_poly_rec_res(int[] srcf, int f, int logn, * ctl = 0, the value a[] is unmodified, but all memory accesses are * still performed, and the carry is computed and returned. */ - int zint_sub(int[] srca, int a, int[] srcb, int b, int len, - int ctl) + private static void zint_sub(int[] srca, int a, int[] srcb, int b, int len, + int ctl) { int u; int cc, m; - + int aw, w, au; cc = 0; m = -ctl; for (u = 0; u < len; u++) { - int aw, w; - - aw = srca[a + u]; + au = a + u; + aw = srca[au]; w = aw - srcb[b + u] - cc; cc = w >>> 31; aw ^= ((w & 0x7FFFFFFF) ^ aw) & m; - srca[a + u] = aw; + srca[au] = aw; } - return cc; } /* * Mutiply the provided big integer m with a small value x. * This function assumes that x < 2^31. The carry word is returned. */ - int zint_mul_small(int[] srcm, int m, int mlen, int x) + private static int zint_mul_small(int[] srcm, int m, int mlen, int x) { int u; int cc; @@ -591,20 +583,17 @@ int zint_mul_small(int[] srcm, int m, int mlen, int x) * p0i = -(1/p) mod 2^31 * R2 = 2^62 mod p */ - int zint_mod_small_unsigned(int[] srcd, int d, int dlen, - int p, int p0i, int R2) + private static int zint_mod_small_unsigned(int[] srcd, int d, int dlen, + int p, int p0i, int R2) { - int x; - int u; - /* * Algorithm: we inject words one by one, starting with the high * word. Each step is: * - multiply x by 2^31 * - add new word */ - x = 0; - u = dlen; + int x = 0; + int u = dlen; while (u-- > 0) { int w; @@ -621,8 +610,8 @@ int zint_mod_small_unsigned(int[] srcd, int d, int dlen, * Similar to zint_mod_small_unsigned(), except that d may be signed. * Extra parameter is Rx = 2^(31*dlen) mod p. */ - int zint_mod_small_signed(int[] srcd, int d, int dlen, - int p, int p0i, int R2, int Rx) + private static int zint_mod_small_signed(int[] srcd, int d, int dlen, + int p, int p0i, int R2, int Rx) { int z; @@ -640,8 +629,8 @@ int zint_mod_small_signed(int[] srcd, int d, int dlen, * has length 'len+1' words. 's' must fit on 31 bits. x[] and y[] must * not overlap. */ - void zint_add_mul_small(int[] srcx, int x, - int[] srcy, int y, int len, int s) + private static void zint_add_mul_small(int[] srcx, int x, + int[] srcy, int y, int len, int s) { int u; int cc; @@ -666,7 +655,7 @@ void zint_add_mul_small(int[] srcx, int x, * with x - p (signed encoding with two's complement); otherwise, x is * untouched. The two integers x and p are encoded over the same length. */ - void zint_norm_zero(int[] srcx, int x, int[] srcp, int p, int len) + private static void zint_norm_zero(int[] srcx, int x, int[] srcp, int p, int len) { int u; int r, bb; @@ -727,14 +716,14 @@ void zint_norm_zero(int[] srcx, int x, int[] srcp, int p, int len) * normalized to the -m/2..m/2 interval (where m is the product of all * small prime moduli); two's complement is used for negative values. */ - void zint_rebuild_CRT(int[] srcxx, int xx, int xlen, int xstride, - int num, FalconSmallPrime[] primes, int normalize_signed, - int[] srctmp, int tmp) + private static void zint_rebuild_CRT(int[] srcxx, int xx, int xlen, int xstride, + int num, int normalize_signed, + int[] srctmp, int tmp) { int u; int x; - srctmp[tmp + 0] = primes[0].p; + srctmp[tmp] = FalconSmallPrimeList.PRIMES[0].p; for (u = 1; u < xlen; u++) { /* @@ -749,8 +738,8 @@ void zint_rebuild_CRT(int[] srcxx, int xx, int xlen, int xstride, int p, p0i, s, R2; int v; - p = primes[u].p; - s = primes[u].s; + p = FalconSmallPrimeList.PRIMES[u].p; + s = FalconSmallPrimeList.PRIMES[u].s; p0i = modp_ninv31(p); R2 = modp_R2(p, p0i); @@ -794,7 +783,7 @@ void zint_rebuild_CRT(int[] srcxx, int xx, int xlen, int xstride, * Negate a big integer conditionally: value a is replaced with -a if * and only if ctl = 1. Control value ctl must be 0 or 1. */ - void zint_negate(int[] srca, int a, int len, int ctl) + private static void zint_negate(int[] srca, int a, int len, int ctl) { int u; int cc, m; @@ -831,8 +820,8 @@ void zint_negate(int[] srca, int a, int len, int ctl) * * Coefficients xa, xb, ya and yb may use the full signed 32-bit range. */ - int zint_co_reduce(int[] srca, int a, int[] srcb, int b, int len, - long xa, long xb, long ya, long yb) + private static int zint_co_reduce(int[] srca, int a, int[] srcb, int b, int len, + long xa, long xb, long ya, long yb) { int u; long cca, ccb; @@ -879,7 +868,7 @@ int zint_co_reduce(int[] srca, int a, int[] srcb, int b, int len, * * Modulus m must be odd. */ - void zint_finish_mod(int[] srca, int a, int len, int[] srcm, int m, int neg) + private static void zint_finish_mod(int[] srca, int a, int len, int[] srcm, int m, int neg) { int u; int cc, xm, ym; @@ -923,8 +912,8 @@ void zint_finish_mod(int[] srca, int a, int len, int[] srcm, int m, int neg) * Replace a with (a*xa+b*xb)/(2^31) mod m, and b with * (a*ya+b*yb)/(2^31) mod m. Modulus m must be odd; m0i = -1/m[0] mod 2^31. */ - void zint_co_reduce_mod(int[] srca, int a, int[] srcb, int b, int[] srcm, int m, int len, - int m0i, long xa, long xb, long ya, long yb) + private static void zint_co_reduce_mod(int[] srca, int a, int[] srcb, int b, int[] srcm, int m, int len, + int m0i, long xa, long xb, long ya, long yb) { int u; long cca, ccb; @@ -935,8 +924,8 @@ void zint_co_reduce_mod(int[] srca, int a, int[] srcb, int b, int[] srcm, int m, */ cca = 0; ccb = 0; - fa = ((srca[a + 0] * (int)xa + srcb[b + 0] * (int)xb) * m0i) & 0x7FFFFFFF; - fb = ((srca[a + 0] * (int)ya + srcb[b + 0] * (int)yb) * m0i) & 0x7FFFFFFF; + fa = ((srca[a] * (int)xa + srcb[b] * (int)xb) * m0i) & 0x7FFFFFFF; + fb = ((srca[a] * (int)ya + srcb[b] * (int)yb) * m0i) & 0x7FFFFFFF; for (u = 0; u < len; u++) { int wa, wb; @@ -984,9 +973,9 @@ void zint_co_reduce_mod(int[] srca, int a, int[] srcb, int b, int[] srcm, int m, * extra values of that length. Arrays u, v and tmp may not overlap with * each other, or with either x or y. */ - int zint_bezout(int[] srcu, int u, int[] srcv, int v, - int[] srcx, int x, int[] srcy, int y, - int len, int[] srctmp, int tmp) + private static int zint_bezout(int[] srcu, int u, int[] srcv, int v, + int[] srcx, int x, int[] srcy, int y, + int len, int[] srctmp, int tmp) { /* * Algorithm is an extended binary GCD. We maintain 6 values @@ -1121,8 +1110,8 @@ int zint_bezout(int[] srcu, int u, int[] srcv, int v, /* * We'll need the Montgomery reduction coefficients. */ - x0i = modp_ninv31(srcx[x + 0]); - y0i = modp_ninv31(srcy[y + 0]); + x0i = modp_ninv31(srcx[x]); + y0i = modp_ninv31(srcy[y]); /* * Initialize a, b, u0, u1, v0 and v1. @@ -1135,10 +1124,10 @@ int zint_bezout(int[] srcu, int u, int[] srcv, int v, // memcpy(b, y, len * sizeof *y); System.arraycopy(srcy, y, srctmp, b, len); // u0[0] = 1; - srcu[u0 + 0] = 1; + srcu[u0] = 1; // memset(u0 + 1, 0, (len - 1) * sizeof *u0); // memset(v0, 0, len * sizeof *v0); - srcv[v0 + 0] = 0; + srcv[v0] = 0; for (int i = 1; i < len; i++) { srcu[u0 + i] = 0; @@ -1149,7 +1138,7 @@ int zint_bezout(int[] srcu, int u, int[] srcv, int v, // memcpy(v1, x, len * sizeof *v1); System.arraycopy(srcx, x, srctmp, v1, len); // v1[0] --; - srctmp[v1 + 0]--; + srctmp[v1]--; /* * Each input operand may be as large as 31*len bits, and we * reduce the total length by at least 30 bits at each iteration. @@ -1204,8 +1193,8 @@ int zint_bezout(int[] srcu, int u, int[] srcv, int v, b0 &= ~c1; a_hi = (toUnsignedLong(a0) << 31) + toUnsignedLong(a1); b_hi = (toUnsignedLong(b0) << 31) + toUnsignedLong(b1); - a_lo = srctmp[a + 0]; - b_lo = srctmp[b + 0]; + a_lo = srctmp[a]; + b_lo = srctmp[b]; /* * Compute reduction factors: @@ -1306,12 +1295,12 @@ int zint_bezout(int[] srcu, int u, int[] srcv, int v, * is indeed 1. We also check that the two operands x and y * are odd. */ - rc = srctmp[a + 0] ^ 1; + rc = srctmp[a] ^ 1; for (j = 1; j < len; j++) { rc |= srctmp[a + j]; } - return ((1 - ((rc | -rc) >>> 31)) & srcx[x + 0] & srcy[y + 0]); + return ((1 - ((rc | -rc) >>> 31)) & srcx[x] & srcy[y]); } /* @@ -1325,9 +1314,9 @@ int zint_bezout(int[] srcu, int u, int[] srcv, int v, * x[] and y[] are both signed integers, using two's complement for * negative values. */ - void zint_add_scaled_mul_small(int[] srcx, int x, int xlen, - int[] srcy, int y, int ylen, int k, - int sch, int scl) + private static void zint_add_scaled_mul_small(int[] srcx, int x, int xlen, + int[] srcy, int y, int ylen, int k, + int sch, int scl) { int u; int ysign, tw; @@ -1387,8 +1376,8 @@ void zint_add_scaled_mul_small(int[] srcx, int x, int xlen, * x[] and y[] are both signed integers, using two's complement for * negative values. */ - void zint_sub_scaled(int[] srcx, int x, int xlen, - int[] srcy, int y, int ylen, int sch, int scl) + private static void zint_sub_scaled(int[] srcx, int x, int xlen, + int[] srcy, int y, int ylen, int sch, int scl) { int u; int ysign, tw; @@ -1424,11 +1413,11 @@ void zint_sub_scaled(int[] srcx, int x, int xlen, /* * Convert a one-word signed big integer into a signed value. */ - int zint_one_to_plain(int[] srcx, int x) + private static int zint_one_to_plain(int[] srcx, int x) { int w; - w = srcx[x + 0]; + w = srcx[x]; w |= (w & 0x40000000) << 1; return w; } @@ -1446,8 +1435,8 @@ int zint_one_to_plain(int[] srcx, int x) * they should be "trimmed" by pointing not to the lowest word of each, * but upper. */ - void poly_big_to_fp(FalconFPR[] srcd, int d, int[] srcf, int f, int flen, int fstride, - int logn) + private static void poly_big_to_fp(double[] srcd, int[] srcf, int f, int flen, int fstride, + int logn) { int n, u; @@ -1456,7 +1445,7 @@ void poly_big_to_fp(FalconFPR[] srcd, int d, int[] srcf, int f, int flen, int fs { for (u = 0; u < n; u++) { - srcd[d + u] = fpr.fpr_zero; + srcd[u] = FPREngine.fpr_zero; } return; } @@ -1464,7 +1453,7 @@ void poly_big_to_fp(FalconFPR[] srcd, int d, int[] srcf, int f, int flen, int fs { int v; int neg, cc, xm; - FalconFPR x, fsc; + double x, fsc; /* * Get sign of the integer; if it is negative, then we @@ -1474,19 +1463,17 @@ void poly_big_to_fp(FalconFPR[] srcd, int d, int[] srcf, int f, int flen, int fs neg = -(srcf[f + flen - 1] >>> 30); xm = neg >>> 1; cc = neg & 1; - x = fpr.fpr_zero; - fsc = fpr.fpr_one; - for (v = 0; v < flen; v++, fsc = fpr.fpr_mul(fsc, fpr.fpr_ptwo31)) + x = FPREngine.fpr_zero; + fsc = FPREngine.fpr_one; + for (v = 0; v < flen; v++, fsc *= FPREngine.fpr_ptwo31) { - int w; - - w = (srcf[f + v] ^ xm) + cc; + int w = (srcf[f + v] ^ xm) + cc; cc = w >>> 31; w &= 0x7FFFFFFF; w -= (w << 1) & neg; - x = fpr.fpr_add(x, fpr.fpr_mul(fpr.fpr_of(w), fsc)); + x += w * fsc; } - srcd[d + u] = x; + srcd[u] = x; } } @@ -1500,7 +1487,7 @@ void poly_big_to_fp(FalconFPR[] srcd, int d, int[] srcf, int f, int flen, int fs * any failure, the NTRU-solving process will be deemed to have failed * and the (f,g) polynomials will be discarded. */ - int poly_big_to_small(byte[] srcd, int d, int[] srcs, int s, int lim, int logn) + private static int poly_big_to_small(byte[] srcd, int d, int[] srcs, int s, int lim, int logn) { int n, u; @@ -1529,9 +1516,9 @@ int poly_big_to_small(byte[] srcd, int d, int[] srcs, int s, int lim, int logn) * which is efficient in space (no extra buffer needed) but slow at * high degree. */ - void poly_sub_scaled(int[] srcF, int F, int Flen, int Fstride, - int[] srcf, int f, int flen, int fstride, - int[] srck, int k, int sch, int scl, int logn) + private static void poly_sub_scaled(int[] srcF, int F, int Flen, int Fstride, + int[] srcf, int f, int flen, int fstride, + int[] srck, int sch, int scl, int logn) { int n, u; @@ -1543,7 +1530,7 @@ void poly_sub_scaled(int[] srcF, int F, int Flen, int Fstride, int x; int y; - kf = -srck[k + u]; + kf = -srck[u]; x = F + u * Fstride; y = f; for (v = 0; v < n; v++) @@ -1570,15 +1557,15 @@ void poly_sub_scaled(int[] srcF, int F, int Flen, int Fstride, * assumes that the degree is large, and integers relatively small. * The value sc is provided as sch = sc / 31 and scl = sc % 31. */ - void poly_sub_scaled_ntt(int[] srcF, int F, int Flen, int Fstride, - int[] srcf, int f, int flen, int fstride, - int[] srck, int k, int sch, int scl, int logn, - int[] srctmp, int tmp) + private static void poly_sub_scaled_ntt(int[] srcF, int F, int Flen, int Fstride, + int[] srcf, int f, int flen, int fstride, + int[] srck, int sch, int scl, int logn, + int[] srctmp, int tmp) { int gm, igm, fk, t1, x; int y; int n, u, tlen; - FalconSmallPrime[] primes; +// FalconSmallPrime[] primes; n = mkn(logn); tlen = flen + 1; @@ -1587,7 +1574,7 @@ void poly_sub_scaled_ntt(int[] srcF, int F, int Flen, int Fstride, fk = igm + mkn(logn); t1 = fk + n * tlen; - primes = this.primes.PRIMES; +// primes = this.primes.PRIMES; /* * Compute k*f in fk[], in RNS notation. @@ -1597,15 +1584,15 @@ void poly_sub_scaled_ntt(int[] srcF, int F, int Flen, int Fstride, int p, p0i, R2, Rx; int v; - p = primes[u].p; + p = FalconSmallPrimeList.PRIMES[u].p; p0i = modp_ninv31(p); R2 = modp_R2(p, p0i); Rx = modp_Rx(flen, p, p0i, R2); - modp_mkgm2(srctmp, gm, srctmp, igm, logn, primes[u].g, p, p0i); + modp_mkgm2(srctmp, gm, srctmp, igm, logn, FalconSmallPrimeList.PRIMES[u].g, p, p0i); for (v = 0; v < n; v++) { - srctmp[t1 + v] = modp_set(srck[k + v], p); + srctmp[t1 + v] = modp_set(srck[v], p); } modp_NTT2(srctmp, t1, srctmp, gm, logn, p, p0i); for (v = 0, y = f, x = fk + u; @@ -1625,7 +1612,7 @@ void poly_sub_scaled_ntt(int[] srcF, int F, int Flen, int Fstride, /* * Rebuild k*f. */ - zint_rebuild_CRT(srctmp, fk, tlen, tlen, n, primes, 1, srctmp, t1); + zint_rebuild_CRT(srctmp, fk, tlen, tlen, n, 1, srctmp, t1); /* * Subtract k*f, scaled, from F. @@ -1644,7 +1631,7 @@ void poly_sub_scaled_ntt(int[] srcF, int F, int Flen, int Fstride, * the same values will be obtained over different platforms, in case * a known seed is used. */ - long get_rng_u64(SHAKE256 rng) + private static long get_rng_u64(SHAKEDigest rng) { /* * We enforce little-endian representation. @@ -1652,15 +1639,16 @@ long get_rng_u64(SHAKE256 rng) byte[] tmp = new byte[8]; - rng.inner_shake256_extract(tmp, 0, tmp.length); - return (tmp[0] & 0xffL) - | ((tmp[1] & 0xffL) << 8) - | ((tmp[2] & 0xffL) << 16) - | ((tmp[3] & 0xffL) << 24) - | ((tmp[4] & 0xffL) << 32) - | ((tmp[5] & 0xffL) << 40) - | ((tmp[6] & 0xffL) << 48) - | ((tmp[7] & 0xffL) << 56); + rng.doOutput(tmp, 0, tmp.length); + return Pack.littleEndianToLong(tmp, 0); +// return (tmp[0] & 0xffL) +// | ((tmp[1] & 0xffL) << 8) +// | ((tmp[2] & 0xffL) << 16) +// | ((tmp[3] & 0xffL) << 24) +// | ((tmp[4] & 0xffL) << 32) +// | ((tmp[5] & 0xffL) << 40) +// | ((tmp[6] & 0xffL) << 48) +// | ((tmp[7] & 0xffL) << 56); } @@ -1672,16 +1660,16 @@ long get_rng_u64(SHAKE256 rng) * For k > 0, element k is P(x >= k+1 | x > 0). * Probabilities are scaled up by 2^63. */ - final long[] gauss_1024_12289 = { - 1283868770400643928l, 6416574995475331444l, 4078260278032692663l, - 2353523259288686585l, 1227179971273316331l, 575931623374121527l, - 242543240509105209l, 91437049221049666l, 30799446349977173l, - 9255276791179340l, 2478152334826140l, 590642893610164l, - 125206034929641l, 23590435911403l, 3948334035941l, - 586753615614l, 77391054539l, 9056793210l, - 940121950l, 86539696l, 7062824l, - 510971l, 32764l, 1862l, - 94l, 4l, 0l + private static final long[] gauss_1024_12289 = { + 1283868770400643928L, 6416574995475331444L, 4078260278032692663L, + 2353523259288686585L, 1227179971273316331L, 575931623374121527L, + 242543240509105209L, 91437049221049666L, 30799446349977173L, + 9255276791179340L, 2478152334826140L, 590642893610164L, + 125206034929641L, 23590435911403L, 3948334035941L, + 586753615614L, 77391054539L, 9056793210L, + 940121950L, 86539696L, 7062824L, + 510971L, 32764L, 1862L, + 94L, 4L, 0L }; /* @@ -1694,7 +1682,7 @@ long get_rng_u64(SHAKE256 rng) * sigma*sqrt(2), then we can just generate more values and add them * together for lower dimensions. */ - int mkgauss(SHAKE256 rng, int logn) + private static int mkgauss(SHAKEDigest rng, int logn) { int u, g; int val; @@ -1728,7 +1716,7 @@ int mkgauss(SHAKE256 rng, int logn) */ r = get_rng_u64(rng); neg = (int)(r >>> 63); - r &= ~(1l << 63); + r &= ~(1L << 63); f = (int)((r - gauss_1024_12289[0]) >>> 63); /* @@ -1739,7 +1727,7 @@ int mkgauss(SHAKE256 rng, int logn) */ v = 0; r = get_rng_u64(rng); - r &= ~(1l << 63); + r &= ~(1L << 63); for (k = 1; k < gauss_1024_12289.length; k++) { int t; @@ -1819,11 +1807,11 @@ int mkgauss(SHAKE256 rng, int logn) * accordingly. */ - final int[] MAX_BL_SMALL = { + private static final int[] MAX_BL_SMALL = { 1, 1, 2, 2, 4, 7, 14, 27, 53, 106, 209 }; - final int[] MAX_BL_LARGE = { + private static final int[] MAX_BL_LARGE = { 2, 2, 5, 7, 12, 21, 40, 78, 157, 308 }; @@ -1832,7 +1820,7 @@ int mkgauss(SHAKE256 rng, int logn) * coefficients of (f,g), depending on depth. These values are used * to compute bounds for Babai's reduction. */ - final int[] bitlength_avg = { + private static final int[] bitlength_avg = { 4, 11, 24, @@ -1845,7 +1833,7 @@ int mkgauss(SHAKE256 rng, int logn) 3138, 6308 }; - final int[] bitlength_std = { + private static final int[] bitlength_std = { 0, 1, 1, @@ -1863,13 +1851,13 @@ int mkgauss(SHAKE256 rng, int logn) * Minimal recursion depth at which we rebuild intermediate values * when reconstructing f and g. */ - final int DEPTH_INT_FG = 4; + private static final int DEPTH_INT_FG = 4; /* * Compute squared norm of a short vector. Returned value is saturated to * 2^32-1 if it is not lower than 2^31. */ - int poly_small_sqnorm(byte[] srcf, int f, int logn) + private static int poly_small_sqnorm(byte[] srcf, int logn) { int n, u; int s, ng; @@ -1881,7 +1869,7 @@ int poly_small_sqnorm(byte[] srcf, int f, int logn) { int z; - z = srcf[f + u]; + z = srcf[u]; s += (z * z); ng |= s; } @@ -1891,14 +1879,14 @@ int poly_small_sqnorm(byte[] srcf, int f, int logn) /* * Convert a small vector to floating point. */ - void poly_small_to_fp(FalconFPR[] srcx, int x, byte[] srcf, int f, int logn) + private static void poly_small_to_fp(double[] srcx, int x, byte[] srcf, int logn) { int n, u; n = mkn(logn); for (u = 0; u < n; u++) { - srcx[x + u] = fpr.fpr_of(srcf[f + u]); + srcx[x + u] = srcf[u]; } } @@ -1910,19 +1898,19 @@ void poly_small_to_fp(FalconFPR[] srcx, int x, byte[] srcf, int f, int logn) * * Values are in RNS; input and/or output may also be in NTT. */ - void make_fg_step(int[] srcdata, int data, int logn, int depth, - int in_ntt, int out_ntt) + private static void make_fg_step(int[] srcdata, int data, int logn, int depth, + int in_ntt, int out_ntt) { int n, hn, u; int slen, tlen; int fd, gd, fs, gs, gm, igm, t1; - FalconSmallPrime[] primes; + //FalconSmallPrime[] primes; n = 1 << logn; hn = n >> 1; slen = MAX_BL_SMALL[depth]; tlen = MAX_BL_SMALL[depth + 1]; - primes = this.primes.PRIMES; + //primes = FalconSmallPrimeList.PRIMES; /* * Prepare room for the result. @@ -1947,10 +1935,10 @@ void make_fg_step(int[] srcdata, int data, int logn, int depth, int v; int x; - p = primes[u].p; + p = FalconSmallPrimeList.PRIMES[u].p; p0i = modp_ninv31(p); R2 = modp_R2(p, p0i); - modp_mkgm2(srcdata, gm, srcdata, igm, logn, primes[u].g, p, p0i); + modp_mkgm2(srcdata, gm, srcdata, igm, logn, FalconSmallPrimeList.PRIMES[u].g, p, p0i); for (v = 0, x = fs + u; v < n; v++, x += slen) { @@ -1964,7 +1952,7 @@ void make_fg_step(int[] srcdata, int data, int logn, int depth, { int w0, w1; - w0 = srcdata[t1 + (v << 1) + 0]; + w0 = srcdata[t1 + (v << 1)]; w1 = srcdata[t1 + (v << 1) + 1]; srcdata[x] = modp_montymul( modp_montymul(w0, w1, p, p0i), R2, p, p0i); @@ -1986,7 +1974,7 @@ void make_fg_step(int[] srcdata, int data, int logn, int depth, { int w0, w1; - w0 = srcdata[t1 + (v << 1) + 0]; + w0 = srcdata[t1 + (v << 1)]; w1 = srcdata[t1 + (v << 1) + 1]; srcdata[x] = modp_montymul( modp_montymul(w0, w1, p, p0i), R2, p, p0i); @@ -2007,8 +1995,8 @@ void make_fg_step(int[] srcdata, int data, int logn, int depth, * Since the fs and gs words have been de-NTTized, we can use the * CRT to rebuild the values. */ - zint_rebuild_CRT(srcdata, fs, slen, slen, n, primes, 1, srcdata, gm); - zint_rebuild_CRT(srcdata, gs, slen, slen, n, primes, 1, srcdata, gm); + zint_rebuild_CRT(srcdata, fs, slen, slen, n, 1, srcdata, gm); + zint_rebuild_CRT(srcdata, gs, slen, slen, n, 1, srcdata, gm); /* * Remaining words: use modular reductions to extract the values. @@ -2019,11 +2007,11 @@ void make_fg_step(int[] srcdata, int data, int logn, int depth, int v; int x; - p = primes[u].p; + p = FalconSmallPrimeList.PRIMES[u].p; p0i = modp_ninv31(p); R2 = modp_R2(p, p0i); Rx = modp_Rx(slen, p, p0i, R2); - modp_mkgm2(srcdata, gm, srcdata, igm, logn, primes[u].g, p, p0i); + modp_mkgm2(srcdata, gm, srcdata, igm, logn, FalconSmallPrimeList.PRIMES[u].g, p, p0i); for (v = 0, x = fs; v < n; v++, x += slen) { srcdata[t1 + v] = zint_mod_small_signed(srcdata, x, slen, p, p0i, R2, Rx); @@ -2033,7 +2021,7 @@ void make_fg_step(int[] srcdata, int data, int logn, int depth, { int w0, w1; - w0 = srcdata[t1 + (v << 1) + 0]; + w0 = srcdata[t1 + (v << 1)]; w1 = srcdata[t1 + (v << 1) + 1]; srcdata[x] = modp_montymul( modp_montymul(w0, w1, p, p0i), R2, p, p0i); @@ -2047,7 +2035,7 @@ void make_fg_step(int[] srcdata, int data, int logn, int depth, { int w0, w1; - w0 = srcdata[t1 + (v << 1) + 0]; + w0 = srcdata[t1 + (v << 1)]; w1 = srcdata[t1 + (v << 1) + 1]; srcdata[x] = modp_montymul( modp_montymul(w0, w1, p, p0i), R2, p, p0i); @@ -2069,23 +2057,23 @@ void make_fg_step(int[] srcdata, int data, int logn, int depth, * Space use in data[]: enough room for any two successive values (f', g', * f and g). */ - void make_fg(int[] srcdata, int data, byte[] srcf, int f, byte[] srcg, int g, - int logn, int depth, int out_ntt) + private static void make_fg(int[] srcdata, int data, byte[] srcf, byte[] srcg, + int logn, int depth, int out_ntt) { int n, u; int ft, gt, p0; int d; - FalconSmallPrime[] primes; + n = mkn(logn); ft = data; gt = ft + n; - primes = this.primes.PRIMES; - p0 = primes[0].p; + + p0 = FalconSmallPrimeList.PRIMES[0].p; for (u = 0; u < n; u++) { - srcdata[ft + u] = modp_set(srcf[f + u], p0); - srcdata[gt + u] = modp_set(srcg[g + u], p0); + srcdata[ft + u] = modp_set(srcf[u], p0); + srcdata[gt + u] = modp_set(srcg[u], p0); } if (depth == 0 && out_ntt != 0) @@ -2093,11 +2081,11 @@ void make_fg(int[] srcdata, int data, byte[] srcf, int f, byte[] srcg, int g, int gm, igm; int p, p0i; - p = primes[0].p; + p = FalconSmallPrimeList.PRIMES[0].p; p0i = modp_ninv31(p); gm = gt + n; igm = gm + n; - modp_mkgm2(srcdata, gm, srcdata, igm, logn, primes[0].g, p, p0i); + modp_mkgm2(srcdata, gm, srcdata, igm, logn, FalconSmallPrimeList.PRIMES[0].g, p, p0i); modp_NTT2(srcdata, ft, srcdata, gm, logn, p, p0i); modp_NTT2(srcdata, gt, srcdata, gm, logn, p, p0i); return; @@ -2117,30 +2105,30 @@ void make_fg(int[] srcdata, int data, byte[] srcf, int f, byte[] srcg, int g, * * Returned value: 1 on success, 0 on error. */ - int solve_NTRU_deepest(int logn_top, - byte[] srcf, int f, byte[] srcg, int g, int[] srctmp, int tmp) + private static int solve_NTRU_deepest(int logn_top, + byte[] srcf, byte[] srcg, int[] srctmp) { int len; int Fp, Gp, fp, gp, t1, q; - FalconSmallPrime[] primes; + //FalconSmallPrime[] primes; len = MAX_BL_SMALL[logn_top]; - primes = this.primes.PRIMES; + //primes = this.primes.PRIMES; - Fp = tmp; + Fp = 0; Gp = Fp + len; fp = Gp + len; gp = fp + len; t1 = gp + len; - make_fg(srctmp, fp, srcf, f, srcg, g, logn_top, logn_top, 0); + make_fg(srctmp, fp, srcf, srcg, logn_top, logn_top, 0); /* * We use the CRT to rebuild the resultants as big integers. * There are two such big integers. The resultants are always * nonnegative. */ - zint_rebuild_CRT(srctmp, fp, len, len, 2, primes, 0, srctmp, t1); + zint_rebuild_CRT(srctmp, fp, len, len, 2, 0, srctmp, t1); /* * Apply the binary GCD. The zint_bezout() function works only @@ -2179,8 +2167,8 @@ int solve_NTRU_deepest(int logn_top, * * Returned value: 1 on success, 0 on error. */ - int solve_NTRU_intermediate(int logn_top, - byte[] srcf, int f, byte[] srcg, int g, int depth, int[] srctmp, int tmp) + private static int solve_NTRU_intermediate(int logn_top, + byte[] srcf, byte[] srcg, int depth, int[] srctmp) { /* * In this function, 'logn' is the log2 of the degree for @@ -2192,11 +2180,11 @@ int solve_NTRU_intermediate(int logn_top, int logn; int n, hn, slen, dlen, llen, rlen, FGlen, u; int Fd, Gd, Ft, Gt, ft, gt, t1; - FalconFPR[] rt1, rt2, rt3, rt4, rt5; + double[] rt1, rt2, rt3, rt4, rt5; int scale_fg, minbl_fg, maxbl_fg, maxbl_FG, scale_k; int x, y; int[] k; - FalconSmallPrime[] primes; + //FalconSmallPrime[] primes; logn = logn_top - depth; n = 1 << logn; @@ -2217,12 +2205,12 @@ int solve_NTRU_intermediate(int logn_top, slen = MAX_BL_SMALL[depth]; dlen = MAX_BL_SMALL[depth + 1]; llen = MAX_BL_LARGE[depth]; - primes = this.primes.PRIMES; + //primes = this.primes.PRIMES; /* * Fd and Gd are the F and G from the deeper level. */ - Fd = tmp; + Fd = 0; Gd = Fd + dlen * hn; /* @@ -2230,28 +2218,30 @@ int solve_NTRU_intermediate(int logn_top, * and g in RNS + NTT representation. */ ft = Gd + dlen * hn; - make_fg(srctmp, ft, srcf, f, srcg, g, logn_top, depth, 1); + make_fg(srctmp, ft, srcf, srcg, logn_top, depth, 1); /* * Move the newly computed f and g to make room for our candidate * F and G (unreduced). */ - Ft = tmp; + Ft = 0; Gt = Ft + n * llen; t1 = Gt + n * llen; // memmove(t1, ft, 2 * n * slen * sizeof *ft); - System.arraycopy(srctmp, ft, srctmp, t1, 2 * n * slen); + int tmp = n * slen; + System.arraycopy(srctmp, ft, srctmp, t1, tmp + tmp); ft = t1; - gt = ft + slen * n; - t1 = gt + slen * n; + gt = ft + tmp; + t1 = gt + tmp; /* * Move Fd and Gd _after_ f and g. */ // memmove(t1, Fd, 2 * hn * dlen * sizeof *Fd); - System.arraycopy(srctmp, Fd, srctmp, t1, 2 * hn * dlen); + tmp = hn * dlen; + System.arraycopy(srctmp, Fd, srctmp, t1, tmp + tmp); Fd = t1; - Gd = Fd + hn * dlen; + Gd = Fd + tmp; /* * We reduce Fd and Gd modulo all the small primes we will need, @@ -2263,7 +2253,7 @@ int solve_NTRU_intermediate(int logn_top, int v; int xs, ys, xd, yd; - p = primes[u].p; + p = FalconSmallPrimeList.PRIMES[u].p; p0i = modp_ninv31(p); R2 = modp_R2(p, p0i); Rx = modp_Rx(dlen, p, p0i, R2); @@ -2292,7 +2282,7 @@ int solve_NTRU_intermediate(int logn_top, /* * All computations are done modulo p. */ - p = primes[u].p; + p = FalconSmallPrimeList.PRIMES[u].p; p0i = modp_ninv31(p); R2 = modp_R2(p, p0i); @@ -2302,8 +2292,8 @@ int solve_NTRU_intermediate(int logn_top, */ if (u == slen) { - zint_rebuild_CRT(srctmp, ft, slen, slen, n, primes, 1, srctmp, t1); - zint_rebuild_CRT(srctmp, gt, slen, slen, n, primes, 1, srctmp, t1); + zint_rebuild_CRT(srctmp, ft, slen, slen, n, 1, srctmp, t1); + zint_rebuild_CRT(srctmp, gt, slen, slen, n, 1, srctmp, t1); } gm = t1; @@ -2311,7 +2301,7 @@ int solve_NTRU_intermediate(int logn_top, fx = igm + n; gx = fx + n; - modp_mkgm2(srctmp, gm, srctmp, igm, logn, primes[u].g, p, p0i); + modp_mkgm2(srctmp, gm, srctmp, igm, logn, FalconSmallPrimeList.PRIMES[u].g, p, p0i); if (u < slen) { @@ -2393,15 +2383,15 @@ int solve_NTRU_intermediate(int logn_top, int ftA, ftB, gtA, gtB; int mFp, mGp; - ftA = srctmp[fx + (v << 1) + 0]; + ftA = srctmp[fx + (v << 1)]; ftB = srctmp[fx + (v << 1) + 1]; - gtA = srctmp[gx + (v << 1) + 0]; + gtA = srctmp[gx + (v << 1)]; gtB = srctmp[gx + (v << 1) + 1]; mFp = modp_montymul(srctmp[Fp + v], R2, p, p0i); mGp = modp_montymul(srctmp[Gp + v], R2, p, p0i); - srctmp[x + 0] = modp_montymul(gtB, mFp, p, p0i); + srctmp[x] = modp_montymul(gtB, mFp, p, p0i); srctmp[x + llen] = modp_montymul(gtA, mFp, p, p0i); - srctmp[y + 0] = modp_montymul(ftB, mGp, p, p0i); + srctmp[y] = modp_montymul(ftB, mGp, p, p0i); srctmp[y + llen] = modp_montymul(ftA, mGp, p, p0i); } modp_iNTT2_ext(srctmp, Ft + u, llen, srctmp, igm, logn, p, p0i); @@ -2411,8 +2401,8 @@ int solve_NTRU_intermediate(int logn_top, /* * Rebuild F and G with the CRT. */ - zint_rebuild_CRT(srctmp, Ft, llen, llen, n, primes, 1, srctmp, t1); - zint_rebuild_CRT(srctmp, Gt, llen, llen, n, primes, 1, srctmp, t1); + zint_rebuild_CRT(srctmp, Ft, llen, llen, n, 1, srctmp, t1); + zint_rebuild_CRT(srctmp, Gt, llen, llen, n, 1, srctmp, t1); /* * At that point, Ft, Gt, ft and gt are consecutive in RAM (in that @@ -2477,11 +2467,11 @@ int solve_NTRU_intermediate(int logn_top, * We ensure that the base is at a properly aligned offset (the * source array tmp[] is supposed to be already aligned). */ - rt1 = new FalconFPR[n]; - rt2 = new FalconFPR[n]; - rt3 = new FalconFPR[n]; - rt4 = new FalconFPR[n]; - rt5 = new FalconFPR[n >> 1]; + rt1 = new double[n]; + rt2 = new double[n]; + rt3 = new double[n]; + rt4 = new double[n]; + rt5 = new double[n >> 1]; k = new int[n]; /* @@ -2494,9 +2484,9 @@ int solve_NTRU_intermediate(int logn_top, * computed so that average maximum length will fall in the * middle or the upper half of these top 10 words. */ - rlen = (slen > 10) ? 10 : slen; - poly_big_to_fp(rt3, 0, srctmp, ft + slen - rlen, rlen, slen, logn); - poly_big_to_fp(rt4, 0, srctmp, gt + slen - rlen, rlen, slen, logn); + rlen = Math.min(slen, 10); + poly_big_to_fp(rt3, srctmp, ft + slen - rlen, rlen, slen, logn); + poly_big_to_fp(rt4, srctmp, gt + slen - rlen, rlen, slen, logn); /* * Values in rt3 and rt4 are downscaled by 2^(scale_fg). @@ -2516,11 +2506,11 @@ int solve_NTRU_intermediate(int logn_top, * Compute 1/(f*adj(f)+g*adj(g)) in rt5. We also keep adj(f) * and adj(g) in rt3 and rt4, respectively. */ - fft.FFT(rt3, 0, logn); - fft.FFT(rt4, 0, logn); - fft.poly_invnorm2_fft(rt5, 0, rt3, 0, rt4, 0, logn); - fft.poly_adj_fft(rt3, 0, logn); - fft.poly_adj_fft(rt4, 0, logn); + FalconFFT.FFT(rt3, 0, logn); + FalconFFT.FFT(rt4, 0, logn); + FalconFFT.poly_invnorm2_fft(rt5, 0, rt3, 0, rt4, 0, logn); + FalconFFT.poly_adj_fft(rt3, 0, logn); + FalconFFT.poly_adj_fft(rt4, 0, logn); /* * Reduce F and G repeatedly. @@ -2563,27 +2553,27 @@ int solve_NTRU_intermediate(int logn_top, { int scale_FG, dc, new_maxbl_FG; int scl, sch; - FalconFPR pdc, pt; + double pdc, pt; /* * Convert current F and G into floating-point. We apply * scaling if the current length is more than 10 words. */ - rlen = (FGlen > 10) ? 10 : FGlen; - scale_FG = 31 * (int)(FGlen - rlen); - poly_big_to_fp(rt1, 0, srctmp, Ft + FGlen - rlen, rlen, llen, logn); - poly_big_to_fp(rt2, 0, srctmp, Gt + FGlen - rlen, rlen, llen, logn); + rlen = Math.min(FGlen, 10); + scale_FG = 31 * (FGlen - rlen); + poly_big_to_fp(rt1, srctmp, Ft + FGlen - rlen, rlen, llen, logn); + poly_big_to_fp(rt2, srctmp, Gt + FGlen - rlen, rlen, llen, logn); /* * Compute (F*adj(f)+G*adj(g))/(f*adj(f)+g*adj(g)) in rt2. */ - fft.FFT(rt1, 0, logn); - fft.FFT(rt2, 0, logn); - fft.poly_mul_fft(rt1, 0, rt3, 0, logn); - fft.poly_mul_fft(rt2, 0, rt4, 0, logn); - fft.poly_add(rt2, 0, rt1, 0, logn); - fft.poly_mul_autoadj_fft(rt2, 0, rt5, 0, logn); - fft.iFFT(rt2, 0, logn); + FalconFFT.FFT(rt1, 0, logn); + FalconFFT.FFT(rt2, 0, logn); + FalconFFT.poly_mul_fft(rt1, 0, rt3, 0, logn); + FalconFFT.poly_mul_fft(rt2, 0, rt4, 0, logn); + FalconFFT.poly_add(rt2, 0, rt1, 0, logn); + FalconFFT.poly_mul_autoadj_fft(rt2, 0, rt5, 0, logn); + FalconFFT.iFFT(rt2, 0, logn); /* * (f,g) are scaled by 'scale_fg', meaning that the @@ -2611,28 +2601,26 @@ int solve_NTRU_intermediate(int logn_top, if (dc < 0) { dc = -dc; - pt = fpr.fpr_two; + pt = FPREngine.fpr_two; } else { - pt = fpr.fpr_onehalf; + pt = FPREngine.fpr_onehalf; } - pdc = fpr.fpr_one; + pdc = FPREngine.fpr_one; while (dc != 0) { if ((dc & 1) != 0) { - pdc = fpr.fpr_mul(pdc, pt); + pdc = pdc * pt; } dc >>= 1; - pt = fpr.fpr_sqr(pt); + pt *= pt; } for (u = 0; u < n; u++) { - FalconFPR xv; - - xv = fpr.fpr_mul(rt2[u], pdc); + double xv = rt2[u] * pdc; /* * Sometimes the values can be out-of-bounds if @@ -2643,12 +2631,12 @@ int solve_NTRU_intermediate(int logn_top, * failure here implies that we discard the current * secret key (f,g). */ - if (!fpr.fpr_lt(fpr.fpr_mtwo31m1, xv) - || !fpr.fpr_lt(xv, fpr.fpr_ptwo31m1)) + if (FPREngine.fpr_mtwo31m1 >= xv + || xv >= FPREngine.fpr_ptwo31m1) { return 0; } - k[u] = (int)fpr.fpr_rint(xv); + k[u] = (int)FPREngine.fpr_rint(xv); } /* @@ -2663,16 +2651,16 @@ int solve_NTRU_intermediate(int logn_top, if (depth <= DEPTH_INT_FG) { poly_sub_scaled_ntt(srctmp, Ft, FGlen, llen, srctmp, ft, slen, slen, - k, 0, sch, scl, logn, srctmp, t1); + k, sch, scl, logn, srctmp, t1); poly_sub_scaled_ntt(srctmp, Gt, FGlen, llen, srctmp, gt, slen, slen, - k, 0, sch, scl, logn, srctmp, t1); + k, sch, scl, logn, srctmp, t1); } else { poly_sub_scaled(srctmp, Ft, FGlen, llen, srctmp, ft, slen, slen, - k, 0, sch, scl, logn); + k, sch, scl, logn); poly_sub_scaled(srctmp, Gt, FGlen, llen, srctmp, gt, slen, slen, - k, 0, sch, scl, logn); + k, sch, scl, logn); } /* @@ -2735,7 +2723,7 @@ int solve_NTRU_intermediate(int logn_top, * Compress encoding of all values to 'slen' words (this is the * expected output format). */ - for (u = 0, x = tmp, y = tmp; + for (u = 0, x = 0, y = 0; u < (n << 1); u++, x += slen, y += llen) { // memmove(x, y, slen * sizeof *y); @@ -2750,8 +2738,8 @@ int solve_NTRU_intermediate(int logn_top, * * Returned value: 1 on success, 0 on error. */ - int solve_NTRU_binary_depth1(int logn_top, - byte[] srcf, int f, byte[] srcg, int g, int[] srctmp, int tmp) + private static int solve_NTRU_binary_depth1(int logn_top, + byte[] srcf, byte[] srcg, int[] srctmp) { /* * The first half of this function is a copy of the corresponding @@ -2764,7 +2752,7 @@ int solve_NTRU_binary_depth1(int logn_top, int depth, logn; int n_top, n, hn, slen, dlen, llen, u; int Fd, Gd, Ft, Gt, ft, gt, t1; - FalconFPR[] rt1, rt2, rt3, rt4, rt5, rt6; + double[] rt1, rt2, rt3, rt4, rt5, rt6; int x, y; depth = 1; @@ -2806,7 +2794,7 @@ int solve_NTRU_binary_depth1(int logn_top, * Fd and Gd are the F and G from the deeper level. Ft and Gt * are the destination arrays for the unreduced F and G. */ - Fd = tmp; + Fd = 0; Gd = Fd + dlen * hn; Ft = Gd + dlen * hn; Gt = Ft + llen * n; @@ -2821,7 +2809,7 @@ int solve_NTRU_binary_depth1(int logn_top, int v; int xs, ys, xd, yd; - p = this.primes.PRIMES[u].p; + p = FalconSmallPrimeList.PRIMES[u].p; p0i = modp_ninv31(p); R2 = modp_R2(p, p0i); Rx = modp_Rx(dlen, p, p0i, R2); @@ -2838,8 +2826,8 @@ int solve_NTRU_binary_depth1(int logn_top, * Now Fd and Gd are not needed anymore; we can squeeze them out. */ // memmove(tmp, Ft, llen * n * sizeof(uint32_t)); - System.arraycopy(srctmp, Ft, srctmp, tmp, llen * n); - Ft = tmp; + System.arraycopy(srctmp, Ft, srctmp, 0, llen * n); + Ft = 0; // memmove(Ft + llen * n, Gt, llen * n * sizeof(uint32_t)); System.arraycopy(srctmp, Gt, srctmp, Ft + llen * n, llen * n); Gt = Ft + llen * n; @@ -2861,7 +2849,7 @@ int solve_NTRU_binary_depth1(int logn_top, /* * All computations are done modulo p. */ - p = this.primes.PRIMES[u].p; + p = FalconSmallPrimeList.PRIMES[u].p; p0i = modp_ninv31(p); R2 = modp_R2(p, p0i); @@ -2877,15 +2865,15 @@ int solve_NTRU_binary_depth1(int logn_top, igm = gm + n_top; fx = igm + n; gx = fx + n_top; - modp_mkgm2(srctmp, gm, srctmp, igm, logn_top, this.primes.PRIMES[u].g, p, p0i); + modp_mkgm2(srctmp, gm, srctmp, igm, logn_top, FalconSmallPrimeList.PRIMES[u].g, p, p0i); /* * Set ft and gt to f and g modulo p, respectively. */ for (v = 0; v < n_top; v++) { - srctmp[fx + v] = modp_set(srcf[f + v], p); - srctmp[gx + v] = modp_set(srcg[g + v], p); + srctmp[fx + v] = modp_set(srcf[v], p); + srctmp[gx + v] = modp_set(srcg[v], p); } /* @@ -2903,18 +2891,18 @@ int solve_NTRU_binary_depth1(int logn_top, * From that point onward, we only need tables for * degree n, so we can save some space. */ - if (depth > 0) - { /* always true */ +// if (depth > 0) +// { /* always true */ // memmove(gm + n, igm, n * sizeof *igm); - System.arraycopy(srctmp, igm, srctmp, gm + n, n); - igm = gm + n; + System.arraycopy(srctmp, igm, srctmp, gm + n, n); + igm = gm + n; // memmove(igm + n, fx, n * sizeof *ft); - System.arraycopy(srctmp, fx, srctmp, igm + n, n); - fx = igm + n; + System.arraycopy(srctmp, fx, srctmp, igm + n, n); + fx = igm + n; // memmove(fx + n, gx, n * sizeof *gt); - System.arraycopy(srctmp, gx, srctmp, fx + n, n); - gx = fx + n; - } + System.arraycopy(srctmp, gx, srctmp, fx + n, n); + gx = fx + n; +// } /* * Get F' and G' modulo p and in NTT representation @@ -2975,15 +2963,15 @@ int solve_NTRU_binary_depth1(int logn_top, int ftA, ftB, gtA, gtB; int mFp, mGp; - ftA = srctmp[fx + (v << 1) + 0]; + ftA = srctmp[fx + (v << 1)]; ftB = srctmp[fx + (v << 1) + 1]; - gtA = srctmp[gx + (v << 1) + 0]; + gtA = srctmp[gx + (v << 1)]; gtB = srctmp[gx + (v << 1) + 1]; mFp = modp_montymul(srctmp[Fp + v], R2, p, p0i); mGp = modp_montymul(srctmp[Gp + v], R2, p, p0i); - srctmp[x + 0] = modp_montymul(gtB, mFp, p, p0i); + srctmp[x] = modp_montymul(gtB, mFp, p, p0i); srctmp[x + llen] = modp_montymul(gtA, mFp, p, p0i); - srctmp[y + 0] = modp_montymul(ftB, mGp, p, p0i); + srctmp[y] = modp_montymul(ftB, mGp, p, p0i); srctmp[y + llen] = modp_montymul(ftA, mGp, p, p0i); } modp_iNTT2_ext(srctmp, Ft + u, llen, srctmp, igm, logn, p, p0i); @@ -3010,8 +2998,8 @@ int solve_NTRU_binary_depth1(int logn_top, * and G are consecutive, and thus can be rebuilt in a single * loop; similarly, the elements of f and g are consecutive. */ - zint_rebuild_CRT(srctmp, Ft, llen, llen, n << 1, this.primes.PRIMES, 1, srctmp, t1); - zint_rebuild_CRT(srctmp, ft, slen, slen, n << 1, this.primes.PRIMES, 1, srctmp, t1); + zint_rebuild_CRT(srctmp, Ft, llen, llen, n << 1, 1, srctmp, t1); + zint_rebuild_CRT(srctmp, ft, slen, slen, n << 1, 1, srctmp, t1); /* * Here starts the Babai reduction, specialized for depth = 1. @@ -3025,31 +3013,31 @@ int solve_NTRU_binary_depth1(int logn_top, * Convert F and G into floating point (rt1 and rt2). */ // rt1 = align_fpr(tmp, gt + slen * n); - rt1 = new FalconFPR[n]; - rt2 = new FalconFPR[n]; - poly_big_to_fp(rt1, 0, srctmp, Ft, llen, llen, logn); - poly_big_to_fp(rt2, 0, srctmp, Gt, llen, llen, logn); + rt1 = new double[n]; + rt2 = new double[n]; + poly_big_to_fp(rt1, srctmp, Ft, llen, llen, logn); + poly_big_to_fp(rt2, srctmp, Gt, llen, llen, logn); /* * Integer representation of F and G is no longer needed, we * can remove it. */ // memmove(tmp, ft, 2 * slen * n * sizeof *ft); - System.arraycopy(srctmp, ft, srctmp, tmp, 2 * slen * n); - ft = tmp; + System.arraycopy(srctmp, ft, srctmp, 0, 2 * slen * n); + ft = 0; gt = ft + slen * n; // rt3 = align_fpr(tmp, gt + slen * n); // memmove(rt3, rt1, 2 * n * sizeof *rt1); // rt1 = rt3; // rt2 = rt1 + n; - rt3 = new FalconFPR[n]; - rt4 = new FalconFPR[n]; + rt3 = new double[n]; + rt4 = new double[n]; /* * Convert f and g into floating point (rt3 and rt4). */ - poly_big_to_fp(rt3, 0, srctmp, ft, slen, slen, logn); - poly_big_to_fp(rt4, 0, srctmp, gt, slen, slen, logn); + poly_big_to_fp(rt3, srctmp, ft, slen, slen, logn); + poly_big_to_fp(rt4, srctmp, gt, slen, slen, logn); /* * Remove unneeded ft and gt. - not required as we have rt_ in separate array @@ -3068,10 +3056,10 @@ int solve_NTRU_binary_depth1(int logn_top, * rt4 = g * in that order in RAM. We convert all of them to FFT. */ - fft.FFT(rt1, 0, logn); - fft.FFT(rt2, 0, logn); - fft.FFT(rt3, 0, logn); - fft.FFT(rt4, 0, logn); + FalconFFT.FFT(rt1, 0, logn); + FalconFFT.FFT(rt2, 0, logn); + FalconFFT.FFT(rt3, 0, logn); + FalconFFT.FFT(rt4, 0, logn); /* * Compute: @@ -3079,16 +3067,16 @@ int solve_NTRU_binary_depth1(int logn_top, * rt6 = 1 / (f*adj(f) + g*adj(g)) * (Note that rt6 is half-length.) */ - rt5 = new FalconFPR[n]; - rt6 = new FalconFPR[n >> 1]; - fft.poly_add_muladj_fft(rt5, 0, rt1, 0, rt2, 0, rt3, 0, rt4, 0, logn); - fft.poly_invnorm2_fft(rt6, 0, rt3, 0, rt4, 0, logn); + rt5 = new double[n]; + rt6 = new double[n >> 1]; + FalconFFT.poly_add_muladj_fft(rt5, rt1, rt2, rt3, rt4, logn); + FalconFFT.poly_invnorm2_fft(rt6, 0, rt3, 0, rt4, 0, logn); /* * Compute: * rt5 = (F*adj(f)+G*adj(g)) / (f*adj(f)+g*adj(g)) */ - fft.poly_mul_autoadj_fft(rt5, 0, rt6, 0, logn); + FalconFFT.poly_mul_autoadj_fft(rt5, 0, rt6, 0, logn); /* * Compute k as the rounded version of rt5. Check that none of @@ -3097,34 +3085,35 @@ int solve_NTRU_binary_depth1(int logn_top, * note that any out-of-bounds value here implies a failure and * (f,g) will be discarded, so we can make a simple test. */ - fft.iFFT(rt5, 0, logn); + FalconFFT.iFFT(rt5, 0, logn); for (u = 0; u < n; u++) { - FalconFPR z; + double z; z = rt5[u]; - if (!fpr.fpr_lt(z, fpr.fpr_ptwo63m1) || !fpr.fpr_lt(fpr.fpr_mtwo63m1, z)) +// if (!FPREngine.fpr_lt(z, FPREngine.fpr_ptwo63m1) || !FPREngine.fpr_lt(FPREngine.fpr_mtwo63m1, z)) + if (z >= FPREngine.fpr_ptwo63m1 || FPREngine.fpr_mtwo63m1 >= z) { return 0; } - rt5[u] = fpr.fpr_of(fpr.fpr_rint(z)); + rt5[u] = FPREngine.fpr_rint(z); } - fft.FFT(rt5, 0, logn); + FalconFFT.FFT(rt5, 0, logn); /* * Subtract k*f from F, and k*g from G. */ - fft.poly_mul_fft(rt3, 0, rt5, 0, logn); - fft.poly_mul_fft(rt4, 0, rt5, 0, logn); - fft.poly_sub(rt1, 0, rt3, 0, logn); - fft.poly_sub(rt2, 0, rt4, 0, logn); - fft.iFFT(rt1, 0, logn); - fft.iFFT(rt2, 0, logn); + FalconFFT.poly_mul_fft(rt3, 0, rt5, 0, logn); + FalconFFT.poly_mul_fft(rt4, 0, rt5, 0, logn); + FalconFFT.poly_sub(rt1, 0, rt3, 0, logn); + FalconFFT.poly_sub(rt2, 0, rt4, 0, logn); + FalconFFT.iFFT(rt1, 0, logn); + FalconFFT.iFFT(rt2, 0, logn); /* * Convert back F and G to integers, and return. */ - Ft = tmp; + //Ft = 0; Gt = Ft + n; // rt3 = align_fpr(tmp, Gt + n); // memmove(rt3, rt1, 2 * n * sizeof *rt1); @@ -3132,8 +3121,8 @@ int solve_NTRU_binary_depth1(int logn_top, // rt2 = rt1 + n; for (u = 0; u < n; u++) { - srctmp[Ft + u] = (int)fpr.fpr_rint(rt1[u]); - srctmp[Gt + u] = (int)fpr.fpr_rint(rt2[u]); + srctmp[Ft + u] = (int)FPREngine.fpr_rint(rt1[u]); + srctmp[Gt + u] = (int)FPREngine.fpr_rint(rt2[u]); } return 1; @@ -3145,8 +3134,8 @@ int solve_NTRU_binary_depth1(int logn_top, * * Returned value: 1 on success, 0 on error. */ - int solve_NTRU_binary_depth0(int logn, - byte[] srcf, int f, byte[] srcg, int g, int[] srctmp, int tmp) + private static int solve_NTRU_binary_depth0(int logn, + byte[] srcf, byte[] srcg, int[] srctmp) { int n, hn, u; int p, p0i, R2; @@ -3172,18 +3161,18 @@ int solve_NTRU_binary_depth0(int logn, * Everything should fit in 31-bit integers, hence we can just use * the first small prime p = 2147473409. */ - p = this.primes.PRIMES[0].p; + p = FalconSmallPrimeList.PRIMES[0].p; p0i = modp_ninv31(p); R2 = modp_R2(p, p0i); - Fp = tmp; + Fp = 0; Gp = Fp + hn; ft = Gp + hn; gt = ft + n; gm = gt + n; igm = gm + n; - modp_mkgm2(srctmp, gm, srctmp, igm, logn, this.primes.PRIMES[0].g, p, p0i); + modp_mkgm2(srctmp, gm, srctmp, igm, logn, FalconSmallPrimeList.PRIMES[0].g, p, p0i); /* * Convert F' anf G' in NTT representation. @@ -3201,8 +3190,8 @@ int solve_NTRU_binary_depth0(int logn, */ for (u = 0; u < n; u++) { - srctmp[ft + u] = modp_set(srcf[f + u], p); - srctmp[gt + u] = modp_set(srcg[g + u], p); + srctmp[ft + u] = modp_set(srcf[u], p); + srctmp[gt + u] = modp_set(srcg[u], p); } modp_NTT2(srctmp, ft, srctmp, gm, logn, p, p0i); modp_NTT2(srctmp, gt, srctmp, gm, logn, p, p0i); @@ -3215,15 +3204,15 @@ int solve_NTRU_binary_depth0(int logn, int ftA, ftB, gtA, gtB; int mFp, mGp; - ftA = srctmp[ft + u + 0]; + ftA = srctmp[ft + u]; ftB = srctmp[ft + u + 1]; - gtA = srctmp[gt + u + 0]; + gtA = srctmp[gt + u]; gtB = srctmp[gt + u + 1]; mFp = modp_montymul(srctmp[Fp + (u >> 1)], R2, p, p0i); mGp = modp_montymul(srctmp[Gp + (u >> 1)], R2, p, p0i); - srctmp[ft + u + 0] = modp_montymul(gtB, mFp, p, p0i); + srctmp[ft + u] = modp_montymul(gtB, mFp, p, p0i); srctmp[ft + u + 1] = modp_montymul(gtA, mFp, p, p0i); - srctmp[gt + u + 0] = modp_montymul(ftB, mGp, p, p0i); + srctmp[gt + u] = modp_montymul(ftB, mGp, p, p0i); srctmp[gt + u + 1] = modp_montymul(ftA, mGp, p, p0i); } modp_iNTT2(srctmp, ft, srctmp, igm, logn, p, p0i); @@ -3251,7 +3240,7 @@ int solve_NTRU_binary_depth0(int logn, * Compute the NTT tables in t1 and t2. We do not keep t2 * (we'll recompute it later on). */ - modp_mkgm2(srctmp, t1, srctmp, t2, logn, this.primes.PRIMES[0].g, p, p0i); + modp_mkgm2(srctmp, t1, srctmp, t2, logn, FalconSmallPrimeList.PRIMES[0].g, p, p0i); /* * Convert F and G to NTT. @@ -3263,11 +3252,11 @@ int solve_NTRU_binary_depth0(int logn, * Load f and adj(f) in t4 and t5, and convert them to NTT * representation. */ - srctmp[t4 + 0] = srctmp[t5 + 0] = modp_set(srcf[f + 0], p); + srctmp[t4] = srctmp[t5] = modp_set(srcf[0], p); for (u = 1; u < n; u++) { - srctmp[t4 + u] = modp_set(srcf[f + u], p); - srctmp[t5 + n - u] = modp_set(-srcf[f + u], p); + srctmp[t4 + u] = modp_set(srcf[u], p); + srctmp[t5 + n - u] = modp_set(-srcf[u], p); } modp_NTT2(srctmp, t4, srctmp, t1, logn, p, p0i); modp_NTT2(srctmp, t5, srctmp, t1, logn, p, p0i); @@ -3288,11 +3277,11 @@ int solve_NTRU_binary_depth0(int logn, * Load g and adj(g) in t4 and t5, and convert them to NTT * representation. */ - srctmp[t4 + 0] = srctmp[t5 + 0] = modp_set(srcg[g + 0], p); + srctmp[t4] = srctmp[t5] = modp_set(srcg[0], p); for (u = 1; u < n; u++) { - srctmp[t4 + u] = modp_set(srcg[g + u], p); - srctmp[t5 + n - u] = modp_set(-srcg[g + u], p); + srctmp[t4 + u] = modp_set(srcg[u], p); + srctmp[t5 + n - u] = modp_set(-srcg[u], p); } modp_NTT2(srctmp, t4, srctmp, t1, logn, p, p0i); modp_NTT2(srctmp, t5, srctmp, t1, logn, p, p0i); @@ -3317,7 +3306,7 @@ int solve_NTRU_binary_depth0(int logn, * move them to t1 and t2. We first need to recompute the * inverse table for NTT. */ - modp_mkgm2(srctmp, t1, srctmp, t4, logn, this.primes.PRIMES[0].g, p, p0i); + modp_mkgm2(srctmp, t1, srctmp, t4, logn, FalconSmallPrimeList.PRIMES[0].g, p, p0i); modp_iNTT2(srctmp, t2, srctmp, t4, logn, p, p0i); modp_iNTT2(srctmp, t3, srctmp, t4, logn, p, p0i); // TODO fix binary_depth0 -> t1 value is wrong for (u = 0; u < n; u++) @@ -3344,17 +3333,16 @@ int solve_NTRU_binary_depth0(int logn, * representation are actually real, so we can truncate off * the imaginary parts. */ - FalconFPR[] - tmp2 = new FalconFPR[3 * n]; + double[] tmp2 = new double[3 * n]; // rt3 = align_fpr(tmp, t3); rt1 = 0; rt2 = rt1 + n; rt3 = rt2 + n; for (u = 0; u < n; u++) { - tmp2[rt3 + u] = fpr.fpr_of(srctmp[t2 + u]); + tmp2[rt3 + u] = srctmp[t2 + u]; } - fft.FFT(tmp2, rt3, logn); + FalconFFT.FFT(tmp2, rt3, logn); // rt2 = align_fpr(tmp, t2); // memmove(rt2, rt3, hn * sizeof *rt3); System.arraycopy(tmp2, rt3, tmp2, rt2, hn); @@ -3365,19 +3353,19 @@ int solve_NTRU_binary_depth0(int logn, rt3 = rt2 + hn; for (u = 0; u < n; u++) { - tmp2[rt3 + u] = fpr.fpr_of(srctmp[t1 + u]); + tmp2[rt3 + u] = srctmp[t1 + u]; } - fft.FFT(tmp2, rt3, logn); + FalconFFT.FFT(tmp2, rt3, logn); /* * Compute (F*adj(f)+G*adj(g))/(f*adj(f)+g*adj(g)) and get * its rounded normal representation in t1. */ - fft.poly_div_autoadj_fft(tmp2, rt3, tmp2, rt2, logn); - fft.iFFT(tmp2, rt3, logn); + FalconFFT.poly_div_autoadj_fft(tmp2, rt3, tmp2, rt2, logn); + FalconFFT.iFFT(tmp2, rt3, logn); for (u = 0; u < n; u++) { - srctmp[t1 + u] = modp_set((int)fpr.fpr_rint(tmp2[rt3 + u]), p); + srctmp[t1 + u] = modp_set((int)FPREngine.fpr_rint(tmp2[rt3 + u]), p); } /* @@ -3393,11 +3381,11 @@ int solve_NTRU_binary_depth0(int logn, t3 = t2 + n; t4 = t3 + n; t5 = t4 + n; - modp_mkgm2(srctmp, t2, srctmp, t3, logn, this.primes.PRIMES[0].g, p, p0i); + modp_mkgm2(srctmp, t2, srctmp, t3, logn, FalconSmallPrimeList.PRIMES[0].g, p, p0i); for (u = 0; u < n; u++) { - srctmp[t4 + u] = modp_set(srcf[f + u], p); - srctmp[t5 + u] = modp_set(srcg[g + u], p); + srctmp[t4 + u] = modp_set(srcf[u], p); + srctmp[t5 + u] = modp_set(srcg[u], p); } modp_NTT2(srctmp, t1, srctmp, t2, logn, p, p0i); modp_NTT2(srctmp, t4, srctmp, t2, logn, p, p0i); @@ -3429,17 +3417,16 @@ int solve_NTRU_binary_depth0(int logn, * If any of the coefficients of F and G exceeds lim (in absolute value), * then 0 is returned. */ - int solve_NTRU(int logn, byte[] srcF, int F, byte[] srcG, int G, - byte[] srcf, int f, byte[] srcg, int g, int lim, int[] srctmp, int tmp) + private static int solve_NTRU(int logn, byte[] srcF, //byte[] srcG, + byte[] srcf, byte[] srcg, int lim, int[] srctmp) { int n, u; int ft, gt, Ft, Gt, gm; int p, p0i, r; - FalconSmallPrime[] primes; - + int G = 0; n = mkn(logn); - if (solve_NTRU_deepest(logn, srcf, f, srcg, g, srctmp, tmp) == 0) + if (solve_NTRU_deepest(logn, srcf, srcg, srctmp) == 0) { return 0; } @@ -3456,7 +3443,7 @@ int solve_NTRU(int logn, byte[] srcF, int F, byte[] srcG, int G, depth = logn; while (depth-- > 0) { - if (solve_NTRU_intermediate(logn, srcf, f, srcg, g, depth, srctmp, tmp) == 0) + if (solve_NTRU_intermediate(logn, srcf, srcg, depth, srctmp) == 0) { return 0; } @@ -3464,21 +3451,19 @@ int solve_NTRU(int logn, byte[] srcF, int F, byte[] srcG, int G, } else { - int depth; - - depth = logn; + int depth = logn; while (depth-- > 2) { - if (solve_NTRU_intermediate(logn, srcf, f, srcg, g, depth, srctmp, tmp) == 0) + if (solve_NTRU_intermediate(logn, srcf, srcg, depth, srctmp) == 0) { return 0; } } - if (solve_NTRU_binary_depth1(logn, srcf, f, srcg, g, srctmp, tmp) == 0) + if (solve_NTRU_binary_depth1(logn, srcf, srcg, srctmp) == 0) { return 0; } - if (solve_NTRU_binary_depth0(logn, srcf, f, srcg, g, srctmp, tmp) == 0) + if (solve_NTRU_binary_depth0(logn, srcf, srcg, srctmp) == 0) { return 0; } @@ -3487,18 +3472,19 @@ int solve_NTRU(int logn, byte[] srcF, int F, byte[] srcG, int G, /* * If no buffer has been provided for G, use a temporary one. */ - if (srcG == null) - { - G = 0; - srcG = new byte[n]; - } +// if (srcG == null) +// { +// G = 0; +// srcG = new byte[n]; +// } + byte[] srcG = new byte[n]; /* * Final F and G are in fk->tmp, one word per coefficient * (signed value over 31 bits). */ - if (poly_big_to_small(srcF, F, srctmp, tmp, lim, logn) == 0 - || poly_big_to_small(srcG, G, srctmp, tmp + n, lim, logn) == 0) + if (poly_big_to_small(srcF, 0, srctmp, 0, lim, logn) == 0 + || poly_big_to_small(srcG, G, srctmp, n, lim, logn) == 0) { return 0; } @@ -3511,25 +3497,24 @@ int solve_NTRU(int logn, byte[] srcF, int F, byte[] srcG, int G, * We put Gt[] first in tmp[], and process it first, so that it does * not overlap with G[] in case we allocated it ourselves. */ - Gt = tmp; + Gt = 0; ft = Gt + n; gt = ft + n; Ft = gt + n; gm = Ft + n; - primes = this.primes.PRIMES; - p = primes[0].p; + p = FalconSmallPrimeList.PRIMES[0].p; p0i = modp_ninv31(p); - modp_mkgm2(srctmp, gm, srctmp, tmp, logn, primes[0].g, p, p0i); + modp_mkgm2(srctmp, gm, srctmp, 0, logn, FalconSmallPrimeList.PRIMES[0].g, p, p0i); for (u = 0; u < n; u++) { srctmp[Gt + u] = modp_set(srcG[G + u], p); } for (u = 0; u < n; u++) { - srctmp[ft + u] = modp_set(srcf[f + u], p); - srctmp[gt + u] = modp_set(srcg[g + u], p); - srctmp[Ft + u] = modp_set(srcF[F + u], p); + srctmp[ft + u] = modp_set(srcf[u], p); + srctmp[gt + u] = modp_set(srcg[u], p); + srctmp[Ft + u] = modp_set(srcF[u], p); } modp_NTT2(srctmp, ft, srctmp, gm, logn, p, p0i); modp_NTT2(srctmp, gt, srctmp, gm, logn, p, p0i); @@ -3555,7 +3540,7 @@ int solve_NTRU(int logn, byte[] srcF, int F, byte[] srcG, int G, * Generate a random polynomial with a Gaussian distribution. This function * also makes sure that the resultant of the polynomial with phi is odd. */ - void poly_small_mkgauss(SHAKE256 rng, byte[] srcf, int f, int logn) + private static void poly_small_mkgauss(SHAKEDigest rng, byte[] srcf, int logn) { int n, u; int mod2; @@ -3597,16 +3582,16 @@ void poly_small_mkgauss(SHAKE256 rng, byte[] srcf, int f, int logn) { mod2 ^= (s & 1); } - srcf[f + u] = (byte)s; + srcf[u] = (byte)s; break; } } } /* see falcon.h */ - void keygen(SHAKE256 rng, - byte[] srcf, int f, byte[] srcg, int g, byte[] srcF, int F, byte[] srcG, int G, short[] srch, int h, - int logn) + static void keygen(SHAKEDigest rc, + byte[] srcf, byte[] srcg, byte[] srcF, short[] srch, + int logn) { /* * Algorithm is the following: @@ -3629,14 +3614,14 @@ void keygen(SHAKE256 rng, */ int n, u; int[] itmp; - byte[] btmp; + //byte[] btmp; short[] stmp; - FalconFPR[] ftmp; + double[] ftmp; int h2, tmp2; - SHAKE256 rc; + //SHAKE256 rc; n = mkn(logn); - rc = rng; + //rc = rng; /* * We need to generate f and g randomly, until we find values @@ -3659,9 +3644,9 @@ void keygen(SHAKE256 rng, */ for (; ; ) { - ftmp = new FalconFPR[3 * n]; + ftmp = new double[3 * n]; int rt1, rt2, rt3; - FalconFPR bnorm; + double bnorm; int normf, normg, norm; int lim; @@ -3671,8 +3656,8 @@ void keygen(SHAKE256 rng, * (i.e. the resultant of the polynomial with phi * will be odd). */ - poly_small_mkgauss(rc, srcf, f, logn); - poly_small_mkgauss(rc, srcg, g, logn); + poly_small_mkgauss(rc, srcf, logn); + poly_small_mkgauss(rc, srcg, logn); /* * Verify that all coefficients are within the bounds @@ -3680,15 +3665,15 @@ void keygen(SHAKE256 rng, * overwhelming probability; this guarantees that the * key will be encodable with FALCON_COMP_TRIM. */ - lim = 1 << (codec.max_fg_bits[logn] - 1); + lim = 1 << (FalconCodec.max_fg_bits[logn] - 1); for (u = 0; u < n; u++) { /* * We can use non-CT tests since on any failure * we will discard f and g. */ - if (srcf[f + u] >= lim || srcf[f + u] <= -lim - || srcg[g + u] >= lim || srcg[g + u] <= -lim) + if (srcf[u] >= lim || srcf[u] <= -lim + || srcg[u] >= lim || srcg[u] <= -lim) { lim = -1; break; @@ -3706,8 +3691,8 @@ void keygen(SHAKE256 rng, * Since f and g are integral, the squared norm * of (g,-f) is an integer. */ - normf = poly_small_sqnorm(srcf, f, logn); - normg = poly_small_sqnorm(srcg, g, logn); + normf = poly_small_sqnorm(srcf, logn); + normg = poly_small_sqnorm(srcg, logn); norm = (normf + normg) | -((normf | normg) >>> 31); if ((norm & 0xffffffffL) >= 16823L) { @@ -3720,26 +3705,26 @@ void keygen(SHAKE256 rng, rt1 = 0; rt2 = rt1 + n; rt3 = rt2 + n; - poly_small_to_fp(ftmp, rt1, srcf, f, logn); - poly_small_to_fp(ftmp, rt2, srcg, g, logn); - fft.FFT(ftmp, rt1, logn); - fft.FFT(ftmp, rt2, logn); - fft.poly_invnorm2_fft(ftmp, rt3, ftmp, rt1, ftmp, rt2, logn); - fft.poly_adj_fft(ftmp, rt1, logn); - fft.poly_adj_fft(ftmp, rt2, logn); - fft.poly_mulconst(ftmp, rt1, fpr.fpr_q, logn); - fft.poly_mulconst(ftmp, rt2, fpr.fpr_q, logn); - fft.poly_mul_autoadj_fft(ftmp, rt1, ftmp, rt3, logn); - fft.poly_mul_autoadj_fft(ftmp, rt2, ftmp, rt3, logn); - fft.iFFT(ftmp, rt1, logn); - fft.iFFT(ftmp, rt2, logn); - bnorm = fpr.fpr_zero; + poly_small_to_fp(ftmp, rt1, srcf, logn); + poly_small_to_fp(ftmp, rt2, srcg, logn); + FalconFFT.FFT(ftmp, rt1, logn); + FalconFFT.FFT(ftmp, rt2, logn); + FalconFFT.poly_invnorm2_fft(ftmp, rt3, ftmp, rt1, ftmp, rt2, logn); + FalconFFT.poly_adj_fft(ftmp, rt1, logn); + FalconFFT.poly_adj_fft(ftmp, rt2, logn); + FalconFFT.poly_mulconst(ftmp, rt1, FPREngine.fpr_q, logn); + FalconFFT.poly_mulconst(ftmp, rt2, FPREngine.fpr_q, logn); + FalconFFT.poly_mul_autoadj_fft(ftmp, rt1, ftmp, rt3, logn); + FalconFFT.poly_mul_autoadj_fft(ftmp, rt2, ftmp, rt3, logn); + FalconFFT.iFFT(ftmp, rt1, logn); + FalconFFT.iFFT(ftmp, rt2, logn); + bnorm = FPREngine.fpr_zero; for (u = 0; u < n; u++) { - bnorm = fpr.fpr_add(bnorm, fpr.fpr_sqr(ftmp[rt1 + u])); - bnorm = fpr.fpr_add(bnorm, fpr.fpr_sqr(ftmp[rt2 + u])); + bnorm += ftmp[rt1 + u] * ftmp[rt1 + u] + ftmp[rt2 + u] * ftmp[rt2 + u]; } - if (!fpr.fpr_lt(bnorm, fpr.fpr_bnorm_max)) + //if (!FPREngine.fpr_lt(bnorm, FPREngine.fpr_bnorm_max)) + if (bnorm >= FPREngine.fpr_bnorm_max) { continue; } @@ -3757,10 +3742,10 @@ void keygen(SHAKE256 rng, } else { - h2 = h; + h2 = 0; tmp2 = 0; } - if (vrfy.compute_public(srch, h2, srcf, f, srcg, g, logn, stmp, tmp2) == 0) + if (FalconVrfy.compute_public(srch, h2, srcf, srcg, logn, stmp, tmp2) == 0) { continue; } @@ -3769,8 +3754,8 @@ void keygen(SHAKE256 rng, * Solve the NTRU equation to get F and G. */ itmp = logn > 2 ? new int[28 * n] : new int[28 * n * 3]; - lim = (1 << (codec.max_FG_bits[logn] - 1)) - 1; - if (solve_NTRU(logn, srcF, F, srcG, G, srcf, f, srcg, g, lim, itmp, 0) == 0) + lim = (1 << (FalconCodec.max_FG_bits[logn] - 1)) - 1; + if (solve_NTRU(logn, srcF, srcf, srcg, lim, itmp) == 0) { continue; } @@ -3782,7 +3767,7 @@ void keygen(SHAKE256 rng, } } - private long toUnsignedLong(int x) + private static long toUnsignedLong(int x) { return x & 0xffffffffL; } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconKeyPairGenerator.java index fcd94de366..1f2d6e02c7 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconKeyPairGenerator.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconKeyPairGenerator.java @@ -11,10 +11,7 @@ public class FalconKeyPairGenerator { private FalconKeyGenerationParameters params; - private SecureRandom random; private FalconNIST nist; - private int logn; - private int noncelen; private int pk_size; private int sk_size; @@ -22,11 +19,11 @@ public class FalconKeyPairGenerator public void init(KeyGenerationParameters param) { this.params = (FalconKeyGenerationParameters)param; - this.random = param.getRandom(); - this.logn = ((FalconKeyGenerationParameters)param).getParameters().getLogN(); - this.noncelen = ((FalconKeyGenerationParameters)param).getParameters().getNonceLength(); + SecureRandom random = param.getRandom(); + int logn = ((FalconKeyGenerationParameters)param).getParameters().getLogN(); + int noncelen = ((FalconKeyGenerationParameters)param).getParameters().getNonceLength(); this.nist = new FalconNIST(logn, noncelen, random); - int n = 1 << this.logn; + int n = 1 << logn; int sk_coeff_size = 8; if (n == 1024) { @@ -49,8 +46,8 @@ public AsymmetricCipherKeyPair generateKeyPair() byte[] pk, sk; pk = new byte[pk_size]; sk = new byte[sk_size]; - byte[][] keyData = nist.crypto_sign_keypair(pk, 0, sk, 0); - FalconParameters p = ((FalconKeyGenerationParameters)this.params).getParameters(); + byte[][] keyData = nist.crypto_sign_keypair(pk, sk); + FalconParameters p = this.params.getParameters(); FalconPrivateKeyParameters privk = new FalconPrivateKeyParameters(p, keyData[1], keyData[2], keyData[3], keyData[0]); FalconPublicKeyParameters pubk = new FalconPublicKeyParameters(p, keyData[0]); return new AsymmetricCipherKeyPair(pubk, privk); diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconNIST.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconNIST.java index a70ebb07dd..b3c47c5c81 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconNIST.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconNIST.java @@ -1,26 +1,25 @@ package org.bouncycastle.pqc.crypto.falcon; - import java.security.SecureRandom; +import org.bouncycastle.crypto.digests.SHAKEDigest; import org.bouncycastle.util.Arrays; class FalconNIST { + final int NONCELEN; + final int LOGN; + private final int N; + private final SecureRandom rand; + private final int CRYPTO_SECRETKEYBYTES; + private final int CRYPTO_PUBLICKEYBYTES; + final int CRYPTO_BYTES; - int NONCELEN; - int LOGN; - private int N; - private SecureRandom rand; - private int CRYPTO_SECRETKEYBYTES; - private int CRYPTO_PUBLICKEYBYTES; - int CRYPTO_BYTES; - - private FalconCodec codec; +// private FalconCodec codec; FalconNIST(int logn, int noncelen, SecureRandom random) { - codec = new FalconCodec(); +// codec = new FalconCodec(); this.rand = random; this.LOGN = logn; this.NONCELEN = noncelen; @@ -48,7 +47,7 @@ else if (logn == 7 || logn == 6) } } - byte[][] crypto_sign_keypair(byte[] srcpk, int pk, byte[] srcsk, int sk) + byte[][] crypto_sign_keypair(byte[] srcpk, byte[] srcsk) { // TODO: clean up required byte[] f = new byte[N], @@ -56,9 +55,10 @@ byte[][] crypto_sign_keypair(byte[] srcpk, int pk, byte[] srcsk, int sk) F = new byte[N]; short[] h = new short[N]; byte[] seed = new byte[48]; - SHAKE256 rng = new SHAKE256(); + //SHAKE256 rng = new SHAKE256(); + SHAKEDigest rng = new SHAKEDigest(256); int u, v; - FalconKeyGen keygen = new FalconKeyGen(); +// FalconKeyGen keygen = new FalconKeyGen(); // savcw = set_fpu_cw(2); @@ -70,12 +70,12 @@ byte[][] crypto_sign_keypair(byte[] srcpk, int pk, byte[] srcsk, int sk) // inner_shake256_init(&rng); // inner_shake256_inject(&rng, seed, sizeof seed); // inner_shake256_flip(&rng); - rng.inner_shake256_init(); - rng.inner_shake256_inject(seed, 0, seed.length); - rng.i_shake256_flip(); + //rng.inner_shake256_init(); + rng.update(seed, 0, seed.length); + //rng.i_shake256_flip(); // Zf(keygen)(&rng, f, g, F, NULL, h, 10, tmp.b); - keygen.keygen(rng, f, 0, g, 0, F, 0, null, 0, h, 0, LOGN); + FalconKeyGen.keygen(rng, f, g, F, h, LOGN); // set_fpu_cw(savcw); @@ -83,32 +83,32 @@ byte[][] crypto_sign_keypair(byte[] srcpk, int pk, byte[] srcsk, int sk) /* * Encode private key. */ - srcsk[sk + 0] = (byte)(0x50 + LOGN); // old python header + srcsk[0] = (byte)(0x50 + LOGN); // old python header u = 1; - v = codec.trim_i8_encode(srcsk, sk + u, CRYPTO_SECRETKEYBYTES - u, - f, 0, LOGN, codec.max_fg_bits[LOGN]); + v = FalconCodec.trim_i8_encode(srcsk, u, CRYPTO_SECRETKEYBYTES - u, + f, LOGN, FalconCodec.max_fg_bits[LOGN]); if (v == 0) { throw new IllegalStateException("f encode failed"); } - byte[] fEnc = Arrays.copyOfRange(srcsk, sk + u, u + v); + byte[] fEnc = Arrays.copyOfRange(srcsk, u, u + v); u += v; - v = codec.trim_i8_encode(srcsk, sk + u, CRYPTO_SECRETKEYBYTES - u, - g, 0, LOGN, codec.max_fg_bits[LOGN]); + v = FalconCodec.trim_i8_encode(srcsk, u, CRYPTO_SECRETKEYBYTES - u, + g, LOGN, FalconCodec.max_fg_bits[LOGN]); if (v == 0) { throw new IllegalStateException("g encode failed"); } - byte[] gEnc = Arrays.copyOfRange(srcsk, sk + u, u + v); + byte[] gEnc = Arrays.copyOfRange(srcsk, u, u + v); u += v; - v = codec.trim_i8_encode(srcsk, sk + u, CRYPTO_SECRETKEYBYTES - u, - F, 0, LOGN, codec.max_FG_bits[LOGN]); + v = FalconCodec.trim_i8_encode(srcsk, u, CRYPTO_SECRETKEYBYTES - u, + F, LOGN, FalconCodec.max_FG_bits[LOGN]); if (v == 0) { throw new IllegalStateException("F encode failed"); } - byte[] FEnc = Arrays.copyOfRange(srcsk, sk + u, u + v); + byte[] FEnc = Arrays.copyOfRange(srcsk, u, u + v); u += v; if (u != CRYPTO_SECRETKEYBYTES) { @@ -118,24 +118,24 @@ byte[][] crypto_sign_keypair(byte[] srcpk, int pk, byte[] srcsk, int sk) /* * Encode public key. */ - srcpk[pk + 0] = (byte)(0x00 + LOGN); - v = codec.modq_encode(srcpk, pk + 1, CRYPTO_PUBLICKEYBYTES - 1, h, 0, LOGN); + srcpk[0] = (byte)(LOGN); + v = FalconCodec.modq_encode(srcpk, CRYPTO_PUBLICKEYBYTES - 1, h, LOGN); if (v != CRYPTO_PUBLICKEYBYTES - 1) { throw new IllegalStateException("public key encoding failed"); } - return new byte[][] { Arrays.copyOfRange(srcpk, 1, srcpk.length), fEnc, gEnc, FEnc }; + return new byte[][]{Arrays.copyOfRange(srcpk, 1, srcpk.length), fEnc, gEnc, FEnc}; } - byte[] crypto_sign(boolean attached, byte[] srcsm, - byte[] srcm, int m, int mlen, - byte[] srcsk, int sk) + byte[] crypto_sign(byte[] srcsm, + byte[] srcm, int mlen, + byte[] srcsk) { byte[] f = new byte[N], - g = new byte[N], - F = new byte[N], - G = new byte[N]; + g = new byte[N], + F = new byte[N], + G = new byte[N]; short[] sig = new short[N]; short[] hm = new short[N]; @@ -144,11 +144,11 @@ byte[] crypto_sign(boolean attached, byte[] srcsm, nonce = new byte[NONCELEN]; - SHAKE256 sc = new SHAKE256(); + SHAKEDigest sc = new SHAKEDigest(256); int u, v, sig_len; FalconSign sign = new FalconSign(); - FalconVrfy vrfy = new FalconVrfy(); - FalconCommon common = new FalconCommon(); + //FalconVrfy vrfy = new FalconVrfy(); +// FalconCommon common = new FalconCommon(); /* * Decode the private key. @@ -158,22 +158,22 @@ byte[] crypto_sign(boolean attached, byte[] srcsm, // throw new IllegalArgumentException("private key header incorrect"); // } u = 0; - v = codec.trim_i8_decode(f, 0, LOGN, codec.max_fg_bits[LOGN], - srcsk, sk + u, CRYPTO_SECRETKEYBYTES - u); + v = FalconCodec.trim_i8_decode(f, LOGN, FalconCodec.max_fg_bits[LOGN], + srcsk, 0, CRYPTO_SECRETKEYBYTES - u); if (v == 0) { throw new IllegalStateException("f decode failed"); } u += v; - v = codec.trim_i8_decode(g, 0, LOGN, codec.max_fg_bits[LOGN], - srcsk, sk + u, CRYPTO_SECRETKEYBYTES - u); + v = FalconCodec.trim_i8_decode(g, LOGN, FalconCodec.max_fg_bits[LOGN], + srcsk, u, CRYPTO_SECRETKEYBYTES - u); if (v == 0) { throw new IllegalStateException("g decode failed"); } u += v; - v = codec.trim_i8_decode(F, 0, LOGN, codec.max_FG_bits[LOGN], - srcsk, sk + u, CRYPTO_SECRETKEYBYTES - u); + v = FalconCodec.trim_i8_decode(F, LOGN, FalconCodec.max_FG_bits[LOGN], + srcsk, u, CRYPTO_SECRETKEYBYTES - u); if (v == 0) { throw new IllegalArgumentException("F decode failed"); @@ -184,7 +184,7 @@ byte[] crypto_sign(boolean attached, byte[] srcsm, throw new IllegalStateException("full key not used"); } - if (!vrfy.complete_private(G, 0, f, 0, g, 0, F, 0, LOGN, new short[2 * N], 0)) + if (!FalconVrfy.complete_private(G, f, g, F, LOGN, new short[2 * N])) { throw new IllegalStateException("complete_private failed"); } @@ -202,12 +202,12 @@ byte[] crypto_sign(boolean attached, byte[] srcsm, // inner_shake256_inject(&sc, nonce, sizeof nonce); // inner_shake256_inject(&sc, m, mlen); // inner_shake256_flip(&sc); - sc.inner_shake256_init(); - sc.inner_shake256_inject(nonce, 0, NONCELEN); - sc.inner_shake256_inject(srcm, m, mlen); - sc.i_shake256_flip(); + //sc.inner_shake256_init(); + sc.update(nonce, 0, NONCELEN); + sc.update(srcm, 0, mlen); + //sc.i_shake256_flip(); // Zf(hash_to_point_vartime)(&sc, r.hm, 10); - common.hash_to_point_vartime(sc, hm, 0, LOGN); // TODO check if this needs to be ct + FalconCommon.hash_to_point_vartime(sc, hm, LOGN); // TODO check if this needs to be ct // System.out.println(String.format("%x %x %x %x %x %x %x %x", hm[0], hm[1], hm[2], hm[3], hm[4], hm[5], hm[6], hm[7])); /* @@ -218,9 +218,10 @@ byte[] crypto_sign(boolean attached, byte[] srcsm, // inner_shake256_init(&sc); // inner_shake256_inject(&sc, seed, sizeof seed); // inner_shake256_flip(&sc); - sc.inner_shake256_init(); - sc.inner_shake256_inject(seed, 0, seed.length); - sc.i_shake256_flip(); + sc.reset(); + //sc.inner_shake256_init(); + sc.update(seed, 0, seed.length); + //sc.i_shake256_flip(); // savcw = set_fpu_cw(2); @@ -228,35 +229,35 @@ byte[] crypto_sign(boolean attached, byte[] srcsm, * Compute the signature. */ // Zf(sign_dyn)(r.sig, &sc, f, g, F, G, r.hm, 10, tmp.b); - sign.sign_dyn(sig, 0, sc, f, 0, g, 0, F, 0, G, 0, hm, 0, LOGN, new FalconFPR[10 * N], 0); + sign.sign_dyn(sig, sc, f, g, F, G, hm, LOGN, new double[10 * N]); // set_fpu_cw(savcw); byte[] esig = new byte[CRYPTO_BYTES - 2 - NONCELEN]; - if (attached) - { - /* - * Encode the signature. Format is: - * signature header 1 bytes - * nonce 40 bytes - * signature slen bytes - */ - esig[0] = (byte)(0x20 + LOGN); - sig_len = codec.comp_encode(esig, 1, esig.length - 1, sig, 0, LOGN); - if (sig_len == 0) - { - throw new IllegalStateException("signature failed to generate"); - } - sig_len++; - } - else +// if (attached) +// { +// /* +// * Encode the signature. Format is: +// * signature header 1 bytes +// * nonce 40 bytes +// * signature slen bytes +// */ +// esig[0] = (byte)(0x20 + LOGN); +// sig_len = FalconCodec.comp_encode(esig, 1, esig.length - 1, sig, LOGN); +// if (sig_len == 0) +// { +// throw new IllegalStateException("signature failed to generate"); +// } +// sig_len++; +// } +// else +// { + sig_len = FalconCodec.comp_encode(esig, esig.length, sig, LOGN); + if (sig_len == 0) { - sig_len = codec.comp_encode(esig, 0, esig.length, sig, 0, LOGN); - if (sig_len == 0) - { - throw new IllegalStateException("signature failed to generate"); - } + throw new IllegalStateException("signature failed to generate"); } +// } // header srcsm[0] = (byte)(0x30 + LOGN); @@ -269,16 +270,17 @@ byte[] crypto_sign(boolean attached, byte[] srcsm, return Arrays.copyOfRange(srcsm, 0, 1 + NONCELEN + sig_len); } - int crypto_sign_open(boolean attached, byte[] sig_encoded, byte[] nonce, byte[] msg, - byte[] srcpk, int pk) + int crypto_sign_open(byte[] sig_encoded, byte[] nonce, byte[] msg, + byte[] srcpk) { short[] h = new short[N], hm = new short[N]; short[] sig = new short[N]; - SHAKE256 sc = new SHAKE256(); + //SHAKE256 sc = new SHAKE256(); + SHAKEDigest sc = new SHAKEDigest(256); int sig_len, msg_len; - FalconVrfy vrfy = new FalconVrfy(); - FalconCommon common = new FalconCommon(); + //FalconVrfy vrfy = new FalconVrfy(); +// FalconCommon common = new FalconCommon(); /* * Decode public key. @@ -287,12 +289,12 @@ int crypto_sign_open(boolean attached, byte[] sig_encoded, byte[] nonce, byte[] // { // return -1; // } - if (codec.modq_decode(h, 0, LOGN, srcpk, pk, CRYPTO_PUBLICKEYBYTES - 1) + if (FalconCodec.modq_decode(h, LOGN, srcpk, CRYPTO_PUBLICKEYBYTES - 1) != CRYPTO_PUBLICKEYBYTES - 1) { return -1; } - vrfy.to_ntt_monty(h, 0, LOGN); + FalconVrfy.to_ntt_monty(h, LOGN); /* * Find nonce, signature, message length. @@ -313,40 +315,40 @@ int crypto_sign_open(boolean attached, byte[] sig_encoded, byte[] nonce, byte[] * Decode signature. */ // Check only required for attached signatures - see 3.11.3 and 3.11.6 in the spec - if (attached) - { - if (sig_len < 1 || sig_encoded[0] != (byte)(0x20 + LOGN)) - { - return -1; - } - if (codec.comp_decode(sig, 0, LOGN, - sig_encoded, 1, sig_len - 1) != sig_len - 1) - { - return -1; - } - } - else +// if (attached) +// { +// if (sig_len < 1 || sig_encoded[0] != (byte)(0x20 + LOGN)) +// { +// return -1; +// } +// if (FalconCodec.comp_decode(sig, LOGN, +// sig_encoded, 1, sig_len - 1) != sig_len - 1) +// { +// return -1; +// } +// } +// else +// { + if (sig_len < 1 || FalconCodec.comp_decode(sig, LOGN, + sig_encoded, sig_len) != sig_len) { - if (sig_len < 1 || codec.comp_decode(sig, 0, LOGN, - sig_encoded, 0, sig_len) != sig_len) - { - return -1; - } + return -1; } +// } /* * Hash nonce + message into a vector. */ - sc.inner_shake256_init(); - sc.inner_shake256_inject(nonce, 0, NONCELEN); - sc.inner_shake256_inject(msg, 0, msg_len); - sc.i_shake256_flip(); - common.hash_to_point_vartime(sc, hm, 0, LOGN); // TODO check if this needs to become ct + //sc.inner_shake256_init(); + sc.update(nonce, 0, NONCELEN); + sc.update(msg, 0, msg_len); + //sc.i_shake256_flip(); + FalconCommon.hash_to_point_vartime(sc, hm, LOGN); // TODO check if this needs to become ct /* * Verify signature. */ - if (vrfy.verify_raw(hm, 0, sig, 0, h, 0, LOGN, new short[N], 0) == 0) + if (FalconVrfy.verify_raw(hm, sig, h, LOGN, new short[N]) == 0) { return -1; } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconPublicKeyParameters.java index 31f58be5a2..756341c56b 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconPublicKeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconPublicKeyParameters.java @@ -5,7 +5,7 @@ public class FalconPublicKeyParameters extends FalconKeyParameters { - private byte[] H; + private final byte[] H; public FalconPublicKeyParameters(FalconParameters parameters, byte[] H) { diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconRNG.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconRNG.java index bb191b0933..21e9e99baf 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconRNG.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconRNG.java @@ -1,57 +1,63 @@ package org.bouncycastle.pqc.crypto.falcon; +import org.bouncycastle.crypto.digests.SHAKEDigest; +import org.bouncycastle.util.Pack; + class FalconRNG { byte[] bd; - long bdummy_u64; + // long bdummy_u64; int ptr; byte[] sd; - long sdummy_u64; - int type; +// long sdummy_u64; +// int type; - FalconConversions convertor; + //FalconConversions convertor; FalconRNG() { this.bd = new byte[512]; - this.bdummy_u64 = 0; +// this.bdummy_u64 = 0; this.ptr = 0; this.sd = new byte[256]; - this.sdummy_u64 = 0; - this.type = 0; - this.convertor = new FalconConversions(); +// this.sdummy_u64 = 0; +// this.type = 0; + //this.convertor = new FalconConversions(); } - void prng_init(SHAKE256 src) + void prng_init(SHAKEDigest src) { /* * To ensure reproducibility for a given seed, we * must enforce little-endian interpretation of * the state words. */ - byte[] tmp = new byte[56]; - long th, tl; - int i; - - src.inner_shake256_extract(tmp, 0, 56); - for (i = 0; i < 14; i++) - { - int w; - - w = (tmp[(i << 2) + 0] & 0xff) - | ((tmp[(i << 2) + 1] & 0xff) << 8) - | ((tmp[(i << 2) + 2] & 0xff) << 16) - | ((tmp[(i << 2) + 3] & 0xff) << 24); +// byte[] tmp = new byte[56]; +// long th, tl; +// int i; - System.arraycopy(convertor.int_to_bytes(w), 0, this.sd, i << 2, 4); - } - - tl = (convertor.bytes_to_int(this.sd, 48) & 0xffffffffL); + src.doOutput(this.sd, 0, 56); +// System.arraycopy(tmp, 0, this.sd, 0, 56); +// for (i = 0; i < 14; i++) +// { +// int w = (tmp[(i << 2)] & 0xff) +// | ((tmp[(i << 2) + 1] & 0xff) << 8) +// | ((tmp[(i << 2) + 2] & 0xff) << 16) +// | ((tmp[(i << 2) + 3] & 0xff) << 24); +// +// +// System.arraycopy(Pack.intToLittleEndian(w), 0, this.sd, i << 2, 4); +// } - th = (convertor.bytes_to_int(this.sd, 52) & 0xffffffffL); + //tl = (convertor.bytes_to_int(this.sd, 48) & 0xffffffffL); +// tl = Pack.littleEndianToInt(this.sd, 48) & 0xffffffffL; +// +// //th = (convertor.bytes_to_int(this.sd, 52) & 0xffffffffL); +// th = Pack.littleEndianToInt(this.sd, 52) & 0xffffffffL; +// Pack.longToLittleEndian(tl + (th << 32), this.sd, 48); - System.arraycopy(convertor.long_to_bytes(tl + (th << 32)), 0, this.sd, 48, 8); + //System.arraycopy(convertor.long_to_bytes(tl + (th << 32)), 0, this.sd, 48, 8); this.prng_refill(); } @@ -84,17 +90,19 @@ void prng_refill() * converted to little endian (if used on a big-endian machine). */ // cc = *(uint64_t *)(p->state.d + 48); - cc = convertor.bytes_to_long(this.sd, 48); + cc = Pack.littleEndianToLong(this.sd, 48); + //cc = convertor.bytes_to_long(this.sd, 48); + int[] state = new int[16]; for (u = 0; u < 8; u++) { - int[] state = new int[16]; int v; int i; // memcpy(&state[0], CW, sizeof CW); System.arraycopy(CW, 0, state, 0, CW.length); // memcpy(&state[4], p->state.d, 48); - System.arraycopy(convertor.bytes_to_int_array(this.sd, 0, 12), 0, state, 4, 12); + Pack.littleEndianToInt(this.sd, 0, state, 4, 12); + //System.arraycopy(convertor.bytes_to_int_array(this.sd, 0, 12), 0, state, 4, 12); state[14] ^= (int)cc; state[15] ^= (int)(cc >>> 32); for (i = 0; i < 10; i++) @@ -117,14 +125,17 @@ void prng_refill() { // state[v] += ((uint32_t *)p->state.d)[v - 4]; // we multiply the -4 by 4 to account for 4 bytes per int - state[v] += convertor.bytes_to_int(sd, (4 * v) - 16); + //state[v] += convertor.bytes_to_int(sd, (4 * v) - 16); + state[v] += Pack.littleEndianToInt(sd, (4 * v) - 16); } // state[14] += ((uint32_t *)p->state.d)[10] // ^ (uint32_t)cc; - state[14] += convertor.bytes_to_int(sd, 40) ^ ((int)cc); + //state[14] += convertor.bytes_to_int(sd, 40) ^ ((int)cc); + state[14] += Pack.littleEndianToInt(sd, 40) ^ ((int)cc); // state[15] += ((uint32_t *)p->state.d)[11] // ^ (uint32_t)(cc >> 32); - state[15] += convertor.bytes_to_int(sd, 44) ^ ((int)(cc >>> 32)); + //state[15] += convertor.bytes_to_int(sd, 44) ^ ((int)(cc >>> 32)); + state[15] += Pack.littleEndianToInt(sd, 44) ^ ((int)(cc >>> 32)); cc++; /* @@ -141,49 +152,47 @@ void prng_refill() // (uint8_t)(state[v] >> 16); // p->buf.d[(u << 2) + (v << 5) + 3] = // (uint8_t)(state[v] >> 24); - bd[(u << 2) + (v << 5) + 0] = - (byte)state[v]; - bd[(u << 2) + (v << 5) + 1] = - (byte)(state[v] >>> 8); - bd[(u << 2) + (v << 5) + 2] = - (byte)(state[v] >>> 16); - bd[(u << 2) + (v << 5) + 3] = - (byte)(state[v] >>> 24); + Pack.intToLittleEndian(state[v], bd, (u << 2) + (v << 5)); +// bd[index] = (byte)state[v]; +// bd[index + 1] = (byte)(state[v] >>> 8); +// bd[index + 2] = (byte)(state[v] >>> 16); +// bd[index + 3] = (byte)(state[v] >>> 24); } } // *(uint64_t *)(p->state.d + 48) = cc; - System.arraycopy(convertor.long_to_bytes(cc), 0, sd, 48, 8); + //System.arraycopy(convertor.long_to_bytes(cc), 0, sd, 48, 8); + Pack.longToLittleEndian(cc, this.sd, 48); this.ptr = 0; } /* see inner.h */ - void prng_get_bytes(byte[] srcdst, int dst, int len) - { - int buf; - - buf = dst; - while (len > 0) - { - int clen; - - clen = (bd.length) - ptr; - if (clen > len) - { - clen = len; - } -// memcpy(buf, p->buf.d, clen); - System.arraycopy(bd, 0, srcdst, buf, clen); - buf += clen; - len -= clen; - ptr += clen; - if (ptr == bd.length) - { - this.prng_refill(); - } - } - } +// void prng_get_bytes(byte[] srcdst, int dst, int len) +// { +// int buf; +// +// buf = dst; +// while (len > 0) +// { +// int clen; +// +// clen = (bd.length) - ptr; +// if (clen > len) +// { +// clen = len; +// } +//// memcpy(buf, p->buf.d, clen); +// System.arraycopy(bd, 0, srcdst, buf, clen); +// buf += clen; +// len -= clen; +// ptr += clen; +// if (ptr == bd.length) +// { +// this.prng_refill(); +// } +// } +// } private void QROUND(int a, int b, int c, int d, int[] state) { @@ -223,14 +232,15 @@ long prng_get_u64() * On systems that use little-endian encoding and allow * unaligned accesses, we can simply read the data where it is. */ - return (this.bd[u + 0] & 0xffL) - | ((this.bd[u + 1] & 0xffL) << 8) - | ((this.bd[u + 2] & 0xffL) << 16) - | ((this.bd[u + 3] & 0xffL) << 24) - | ((this.bd[u + 4] & 0xffL) << 32) - | ((this.bd[u + 5] & 0xffL) << 40) - | ((this.bd[u + 6] & 0xffL) << 48) - | ((this.bd[u + 7] & 0xffL) << 56); + return Pack.littleEndianToLong(this.bd, u); +// return (this.bd[u] & 0xffL) +// | ((this.bd[u + 1] & 0xffL) << 8) +// | ((this.bd[u + 2] & 0xffL) << 16) +// | ((this.bd[u + 3] & 0xffL) << 24) +// | ((this.bd[u + 4] & 0xffL) << 32) +// | ((this.bd[u + 5] & 0xffL) << 40) +// | ((this.bd[u + 6] & 0xffL) << 48) +// | ((this.bd[u + 7] & 0xffL) << 56); } byte prng_get_u8() diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconSign.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconSign.java index ff25fb7ed8..f8ef315cf4 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconSign.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconSign.java @@ -1,23 +1,25 @@ package org.bouncycastle.pqc.crypto.falcon; +import org.bouncycastle.crypto.digests.SHAKEDigest; + class FalconSign { - FPREngine fpr; - FalconFFT fft; - FalconCommon common; + //FPREngine fpr; + //FalconFFT fft; +// FalconCommon common; FalconSign() { - this.fpr = new FPREngine(); - this.fft = new FalconFFT(); - this.common = new FalconCommon(); + //this.fpr = new FPREngine(); + //this.fft = new FalconFFT(); +// this.common = new FalconCommon(); } - private static int MKN(int logn) - { - return 1 << logn; - } +// private static int MKN(int logn) +// { +// return 1 << logn; +// } /* * Binary case: @@ -29,19 +31,19 @@ private static int MKN(int logn) * Get the size of the LDL tree for an input with polynomials of size * 2^logn. The size is expressed in the number of elements. */ - int ffLDL_treesize(int logn) - { - /* - * For logn = 0 (polynomials are constant), the "tree" is a - * single element. Otherwise, the tree node has size 2^logn, and - * has two child trees for size logn-1 each. Thus, treesize s() - * must fulfill these two relations: - * - * s(0) = 1 - * s(logn) = (2^logn) + 2*s(logn-1) - */ - return (logn + 1) << logn; - } +// int ffLDL_treesize(int logn) +// { +// /* +// * For logn = 0 (polynomials are constant), the "tree" is a +// * single element. Otherwise, the tree node has size 2^logn, and +// * has two child trees for size logn-1 each. Thus, treesize s() +// * must fulfill these two relations: +// * +// * s(0) = 1 +// * s(logn) = (2^logn) + 2*s(logn-1) +// */ +// return (logn + 1) << logn; +// } /* * Inner function for ffLDL_fft(). It expects the matrix to be both @@ -50,45 +52,45 @@ int ffLDL_treesize(int logn) * * tmp[] must have room for at least one polynomial. */ - void ffLDL_fft_inner(FalconFPR[] srctree, int tree, - FalconFPR[] srcg0, int g0, FalconFPR[] srcg1, int g1, - int logn, FalconFPR[] srctmp, int tmp) - { - int n, hn; - - n = MKN(logn); - if (n == 1) - { - srctree[tree + 0] = srcg0[g0 + 0]; - return; - } - hn = n >> 1; - - /* - * The LDL decomposition yields L (which is written in the tree) - * and the diagonal of D. Since d00 = g0, we just write d11 - * into tmp. - */ - fft.poly_LDLmv_fft(srctmp, tmp, srctree, tree, srcg0, g0, srcg1, g1, srcg0, g0, logn); - - /* - * Split d00 (currently in g0) and d11 (currently in tmp). We - * reuse g0 and g1 as temporary storage spaces: - * d00 splits into g1, g1+hn - * d11 splits into g0, g0+hn - */ - fft.poly_split_fft(srcg1, g1, srcg1, g1 + hn, srcg0, g0, logn); - fft.poly_split_fft(srcg0, g0, srcg0, g0 + hn, srctmp, tmp, logn); - - /* - * Each split result is the first row of a new auto-adjoint - * quasicyclic matrix for the next recursive step. - */ - ffLDL_fft_inner(srctree, tree + n, - srcg1, g1, srcg1, g1 + hn, logn - 1, srctmp, tmp); - ffLDL_fft_inner(srctree, tree + n + ffLDL_treesize(logn - 1), - srcg0, g0, srcg0, g0 + hn, logn - 1, srctmp, tmp); - } +// void ffLDL_fft_inner(double[] srctree, int tree, +// double[] srcg0, int g0, double[] srcg1, int g1, +// int logn, double[] srctmp, int tmp) +// { +// int n, hn; +// +// n = MKN(logn); +// if (n == 1) +// { +// srctree[tree] = srcg0[g0]; +// return; +// } +// hn = n >> 1; +// +// /* +// * The LDL decomposition yields L (which is written in the tree) +// * and the diagonal of D. Since d00 = g0, we just write d11 +// * into tmp. +// */ +// fft.poly_LDLmv_fft(srctmp, tmp, srctree, tree, srcg0, g0, srcg1, g1, srcg0, g0, logn); +// +// /* +// * Split d00 (currently in g0) and d11 (currently in tmp). We +// * reuse g0 and g1 as temporary storage spaces: +// * d00 splits into g1, g1+hn +// * d11 splits into g0, g0+hn +// */ +// fft.poly_split_fft(srcg1, g1, srcg1, g1 + hn, srcg0, g0, logn); +// fft.poly_split_fft(srcg0, g0, srcg0, g0 + hn, srctmp, tmp, logn); +// +// /* +// * Each split result is the first row of a new auto-adjoint +// * quasicyclic matrix for the next recursive step. +// */ +// ffLDL_fft_inner(srctree, tree + n, +// srcg1, g1, srcg1, g1 + hn, logn - 1, srctmp, tmp); +// ffLDL_fft_inner(srctree, tree + n + ffLDL_treesize(logn - 1), +// srcg0, g0, srcg0, g0 + hn, logn - 1, srctmp, tmp); +// } /* * Compute the ffLDL tree of an auto-adjoint matrix G. The matrix @@ -101,66 +103,66 @@ void ffLDL_fft_inner(FalconFPR[] srctree, int tree, * arrays g00, g01 and g11. tmp[] should have room for at least three * polynomials of 2^logn elements each. */ - void ffLDL_fft(FalconFPR[] srctree, int tree, FalconFPR[] srcg00, int g00, - FalconFPR[] srcg01, int g01, FalconFPR[] srcg11, int g11, - int logn, FalconFPR[] srctmp, int tmp) - { - int n, hn; - int d00, d11; - - n = MKN(logn); - if (n == 1) - { - srctree[tree + 0] = srcg00[g00 + 0]; - return; - } - hn = n >> 1; - d00 = tmp; - d11 = tmp + n; - tmp += n << 1; - -// memcpy(d00, g00, n * sizeof *g00); - System.arraycopy(srcg00, g00, srctmp, d00, n); - fft.poly_LDLmv_fft(srctmp, d11, srctree, tree, srcg00, g00, srcg01, g01, srcg11, g11, logn); - - fft.poly_split_fft(srctmp, tmp, srctmp, tmp + hn, srctmp, d00, logn); - fft.poly_split_fft(srctmp, d00, srctmp, d00 + hn, srctmp, d11, logn); -// memcpy(d11, tmp, n * sizeof *tmp); - System.arraycopy(srctmp, tmp, srctmp, d11, n); - ffLDL_fft_inner(srctree, tree + n, - srctmp, d11, srctmp, d11 + hn, logn - 1, srctmp, tmp); - ffLDL_fft_inner(srctree, tree + n + ffLDL_treesize(logn - 1), - srctmp, d00, srctmp, d00 + hn, logn - 1, srctmp, tmp); - } +// void ffLDL_fft(double[] srctree, int tree, double[] srcg00, int g00, +// double[] srcg01, int g01, double[] srcg11, int g11, +// int logn, double[] srctmp, int tmp) +// { +// int n, hn; +// int d00, d11; +// +// n = MKN(logn); +// if (n == 1) +// { +// srctree[tree + 0] = srcg00[g00 + 0]; +// return; +// } +// hn = n >> 1; +// d00 = tmp; +// d11 = tmp + n; +// tmp += n << 1; +// +//// memcpy(d00, g00, n * sizeof *g00); +// System.arraycopy(srcg00, g00, srctmp, d00, n); +// fft.poly_LDLmv_fft(srctmp, d11, srctree, tree, srcg00, g00, srcg01, g01, srcg11, g11, logn); +// +// fft.poly_split_fft(srctmp, tmp, srctmp, tmp + hn, srctmp, d00, logn); +// fft.poly_split_fft(srctmp, d00, srctmp, d00 + hn, srctmp, d11, logn); +//// memcpy(d11, tmp, n * sizeof *tmp); +// System.arraycopy(srctmp, tmp, srctmp, d11, n); +// ffLDL_fft_inner(srctree, tree + n, +// srctmp, d11, srctmp, d11 + hn, logn - 1, srctmp, tmp); +// ffLDL_fft_inner(srctree, tree + n + ffLDL_treesize(logn - 1), +// srctmp, d00, srctmp, d00 + hn, logn - 1, srctmp, tmp); +// } /* * Normalize an ffLDL tree: each leaf of value x is replaced with * sigma / sqrt(x). */ - void ffLDL_binary_normalize(FalconFPR[] srctree, int tree, int orig_logn, int logn) - { - /* - * TODO: make an iterative version. - */ - int n; - - n = MKN(logn); - if (n == 1) - { - /* - * We actually store in the tree leaf the inverse of - * the value mandated by the specification: this - * saves a division both here and in the sampler. - */ - srctree[tree + 0] = fpr.fpr_mul(fpr.fpr_sqrt(srctree[tree + 0]), fpr.fpr_inv_sigma[orig_logn]); - } - else - { - ffLDL_binary_normalize(srctree, tree + n, orig_logn, logn - 1); - ffLDL_binary_normalize(srctree, tree + n + ffLDL_treesize(logn - 1), - orig_logn, logn - 1); - } - } +// void ffLDL_binary_normalize(double[] srctree, int tree, int orig_logn, int logn) +// { +// /* +// * TODO: make an iterative version. +// */ +// int n; +// +// n = MKN(logn); +// if (n == 1) +// { +// /* +// * We actually store in the tree leaf the inverse of +// * the value mandated by the specification: this +// * saves a division both here and in the sampler. +// */ +// srctree[tree + 0] = fpr.fpr_mul(fpr.fpr_sqrt(srctree[tree + 0]), fpr.fpr_inv_sigma[orig_logn]); +// } +// else +// { +// ffLDL_binary_normalize(srctree, tree + n, orig_logn, logn - 1); +// ffLDL_binary_normalize(srctree, tree + n + ffLDL_treesize(logn - 1), +// orig_logn, logn - 1); +// } +// } /* =================================================================== */ @@ -168,14 +170,14 @@ void ffLDL_binary_normalize(FalconFPR[] srctree, int tree, int orig_logn, int lo * Convert an integer polynomial (with small values) into the * representation with complex numbers. */ - void smallints_to_fpr(FalconFPR[] srcr, int r, byte[] srct, int t, int logn) + void smallints_to_fpr(double[] srcr, int r, byte[] srct, int logn) { int n, u; - n = MKN(logn); + n = 1 << logn; for (u = 0; u < n; u++) { - srcr[r + u] = fpr.fpr_of(srct[t + u]); // t is signed + srcr[r + u] = srct[u]; // t is signed } } @@ -185,124 +187,124 @@ void smallints_to_fpr(FalconFPR[] srcr, int r, byte[] srct, int t, int logn) * - The ffLDL tree */ - int skoff_b00(int logn) - { -// (void)logn; - return 0; - } - - int skoff_b01(int logn) - { - return MKN(logn); - } - - int skoff_b10(int logn) - { - return 2 * MKN(logn); - } - - int skoff_b11(int logn) - { - return 3 * MKN(logn); - } - - int skoff_tree(int logn) - { - return 4 * MKN(logn); - } +// int skoff_b00(int logn) +// { +//// (void)logn; +// return 0; +// } +// +// int skoff_b01(int logn) +// { +// return MKN(logn); +// } +// +// int skoff_b10(int logn) +// { +// return 2 * MKN(logn); +// } +// +// int skoff_b11(int logn) +// { +// return 3 * MKN(logn); +// } +// +// int skoff_tree(int logn) +// { +// return 4 * MKN(logn); +// } /* see inner.h */ - void expand_privkey(FalconFPR[] srcexpanded_key, int expanded_key, - byte[] srcf, int f, byte[] srcg, int g, - byte[] srcF, int F, byte[] srcG, int G, - int logn, FalconFPR[] srctmp, int tmp) - { - int n; - int rf, rg, rF, rG; - int b00, b01, b10, b11; - int g00, g01, g11, gxx; - int tree; - - n = MKN(logn); - b00 = expanded_key + skoff_b00(logn); - b01 = expanded_key + skoff_b01(logn); - b10 = expanded_key + skoff_b10(logn); - b11 = expanded_key + skoff_b11(logn); - tree = expanded_key + skoff_tree(logn); - - /* - * We load the private key elements directly into the B0 matrix, - * since B0 = [[g, -f], [G, -F]]. - */ - rf = b01; - rg = b00; - rF = b11; - rG = b10; - - smallints_to_fpr(srcexpanded_key, rf, srcf, f, logn); - smallints_to_fpr(srcexpanded_key, rg, srcg, g, logn); - smallints_to_fpr(srcexpanded_key, rF, srcF, F, logn); - smallints_to_fpr(srcexpanded_key, rG, srcG, G, logn); - - /* - * Compute the FFT for the key elements, and negate f and F. - */ - fft.FFT(srcexpanded_key, rf, logn); - fft.FFT(srcexpanded_key, rg, logn); - fft.FFT(srcexpanded_key, rF, logn); - fft.FFT(srcexpanded_key, rG, logn); - fft.poly_neg(srcexpanded_key, rf, logn); - fft.poly_neg(srcexpanded_key, rF, logn); - - /* - * The Gram matrix is G = B·B*. Formulas are: - * g00 = b00*adj(b00) + b01*adj(b01) - * g01 = b00*adj(b10) + b01*adj(b11) - * g10 = b10*adj(b00) + b11*adj(b01) - * g11 = b10*adj(b10) + b11*adj(b11) - * - * For historical reasons, this implementation uses - * g00, g01 and g11 (upper triangle). - */ - g00 = tmp; // the b__ are in srcexpanded_key and g__ are int srctmp - g01 = g00 + n; - g11 = g01 + n; - gxx = g11 + n; - -// memcpy(g00, b00, n * sizeof *b00); - System.arraycopy(srcexpanded_key, b00, srctmp, g00, n); - fft.poly_mulselfadj_fft(srctmp, g00, logn); -// memcpy(gxx, b01, n * sizeof *b01); - System.arraycopy(srcexpanded_key, b01, srctmp, gxx, n); - fft.poly_mulselfadj_fft(srctmp, gxx, logn); - fft.poly_add(srctmp, g00, srctmp, gxx, logn); - -// memcpy(g01, b00, n * sizeof *b00); - System.arraycopy(srcexpanded_key, b00, srctmp, g01, n); - fft.poly_muladj_fft(srctmp, g01, srcexpanded_key, b10, logn); -// memcpy(gxx, b01, n * sizeof *b01); - System.arraycopy(srcexpanded_key, b01, srctmp, gxx, n); - fft.poly_muladj_fft(srctmp, gxx, srcexpanded_key, b11, logn); - fft.poly_add(srctmp, g01, srctmp, gxx, logn); - -// memcpy(g11, b10, n * sizeof *b10); - System.arraycopy(srcexpanded_key, b10, srctmp, g11, n); - fft.poly_mulselfadj_fft(srctmp, g11, logn); -// memcpy(gxx, b11, n * sizeof *b11); - System.arraycopy(srcexpanded_key, b11, srctmp, gxx, n); - fft.poly_mulselfadj_fft(srctmp, gxx, logn); - fft.poly_add(srctmp, g11, srctmp, gxx, logn); - - /* - * Compute the Falcon tree. - */ - ffLDL_fft(srcexpanded_key, tree, srctmp, g00, srctmp, g01, srctmp, g11, logn, srctmp, gxx); - - /* - * Normalize tree. - */ - ffLDL_binary_normalize(srcexpanded_key, tree, logn, logn); - } +// void expand_privkey(double[] srcexpanded_key, int expanded_key, +// byte[] srcf, int f, byte[] srcg, int g, +// byte[] srcF, int F, byte[] srcG, int G, +// int logn, double[] srctmp, int tmp) +// { +// int n; +// int rf, rg, rF, rG; +// int b00, b01, b10, b11; +// int g00, g01, g11, gxx; +// int tree; +// +// n = MKN(logn); +// b00 = expanded_key + skoff_b00(logn); +// b01 = expanded_key + skoff_b01(logn); +// b10 = expanded_key + skoff_b10(logn); +// b11 = expanded_key + skoff_b11(logn); +// tree = expanded_key + skoff_tree(logn); +// +// /* +// * We load the private key elements directly into the B0 matrix, +// * since B0 = [[g, -f], [G, -F]]. +// */ +// rf = b01; +// rg = b00; +// rF = b11; +// rG = b10; +// +// smallints_to_fpr(srcexpanded_key, rf, srcf, f, logn); +// smallints_to_fpr(srcexpanded_key, rg, srcg, g, logn); +// smallints_to_fpr(srcexpanded_key, rF, srcF, F, logn); +// smallints_to_fpr(srcexpanded_key, rG, srcG, G, logn); +// +// /* +// * Compute the FFT for the key elements, and negate f and F. +// */ +// fft.FFT(srcexpanded_key, rf, logn); +// fft.FFT(srcexpanded_key, rg, logn); +// fft.FFT(srcexpanded_key, rF, logn); +// fft.FFT(srcexpanded_key, rG, logn); +// fft.poly_neg(srcexpanded_key, rf, logn); +// fft.poly_neg(srcexpanded_key, rF, logn); +// +// /* +// * The Gram matrix is G = B·B*. Formulas are: +// * g00 = b00*adj(b00) + b01*adj(b01) +// * g01 = b00*adj(b10) + b01*adj(b11) +// * g10 = b10*adj(b00) + b11*adj(b01) +// * g11 = b10*adj(b10) + b11*adj(b11) +// * +// * For historical reasons, this implementation uses +// * g00, g01 and g11 (upper triangle). +// */ +// g00 = tmp; // the b__ are in srcexpanded_key and g__ are int srctmp +// g01 = g00 + n; +// g11 = g01 + n; +// gxx = g11 + n; +// +//// memcpy(g00, b00, n * sizeof *b00); +// System.arraycopy(srcexpanded_key, b00, srctmp, g00, n); +// fft.poly_mulselfadj_fft(srctmp, g00, logn); +//// memcpy(gxx, b01, n * sizeof *b01); +// System.arraycopy(srcexpanded_key, b01, srctmp, gxx, n); +// fft.poly_mulselfadj_fft(srctmp, gxx, logn); +// fft.poly_add(srctmp, g00, srctmp, gxx, logn); +// +//// memcpy(g01, b00, n * sizeof *b00); +// System.arraycopy(srcexpanded_key, b00, srctmp, g01, n); +// fft.poly_muladj_fft(srctmp, g01, srcexpanded_key, b10, logn); +//// memcpy(gxx, b01, n * sizeof *b01); +// System.arraycopy(srcexpanded_key, b01, srctmp, gxx, n); +// fft.poly_muladj_fft(srctmp, gxx, srcexpanded_key, b11, logn); +// fft.poly_add(srctmp, g01, srctmp, gxx, logn); +// +//// memcpy(g11, b10, n * sizeof *b10); +// System.arraycopy(srcexpanded_key, b10, srctmp, g11, n); +// fft.poly_mulselfadj_fft(srctmp, g11, logn); +//// memcpy(gxx, b11, n * sizeof *b11); +// System.arraycopy(srcexpanded_key, b11, srctmp, gxx, n); +// fft.poly_mulselfadj_fft(srctmp, gxx, logn); +// fft.poly_add(srctmp, g11, srctmp, gxx, logn); +// +// /* +// * Compute the Falcon tree. +// */ +// ffLDL_fft(srcexpanded_key, tree, srctmp, g00, srctmp, g01, srctmp, g11, logn, srctmp, gxx); +// +// /* +// * Normalize tree. +// */ +// ffLDL_binary_normalize(srcexpanded_key, tree, logn, logn); +// } /* * Perform Fast Fourier Sampling for target vector t. The Gram matrix @@ -310,10 +312,10 @@ void expand_privkey(FalconFPR[] srcexpanded_key, int expanded_key, * is written over (t0,t1). The Gram matrix is modified as well. The * tmp[] buffer must have room for four polynomials. */ - void ffSampling_fft_dyntree(SamplerZ samp, SamplerCtx samp_ctx, - FalconFPR[] srct0, int t0, FalconFPR[] srct1, int t1, - FalconFPR[] srcg00, int g00, FalconFPR[] srcg01, int g01, FalconFPR[] srcg11, int g11, - int orig_logn, int logn, FalconFPR[] srctmp, int tmp) + void ffSampling_fft_dyntree(SamplerCtx samp_ctx, + double[] srct0, int t0, double[] srct1, int t1, + double[] srcg00, int g00, double[] srcg01, int g01, double[] srcg11, int g11, + int orig_logn, int logn, double[] srctmp, int tmp) { int n, hn; int z0, z1; @@ -325,12 +327,16 @@ void ffSampling_fft_dyntree(SamplerZ samp, SamplerCtx samp_ctx, */ if (logn == 0) { - FalconFPR leaf; - - leaf = srcg00[g00 + 0]; - leaf = fpr.fpr_mul(fpr.fpr_sqrt(leaf), fpr.fpr_inv_sigma[orig_logn]); - srct0[t0 + 0] = fpr.fpr_of(samp.sample(samp_ctx, srct0[t0 + 0], leaf)); - srct1[t1 + 0] = fpr.fpr_of(samp.sample(samp_ctx, srct1[t1 + 0], leaf)); + double leaf; + +// leaf = srcg00[g00 + 0]; +// leaf = fpr.fpr_mul(fpr.fpr_sqrt(leaf), fpr.fpr_inv_sigma[orig_logn]); +// srct0[t0 + 0] = fpr.fpr_of(samp.sample(samp_ctx, srct0[t0 + 0], leaf)); +// srct1[t1 + 0] = fpr.fpr_of(samp.sample(samp_ctx, srct1[t1 + 0], leaf)); + leaf = srcg00[g00]; + leaf = Math.sqrt(leaf) * FPREngine.fpr_inv_sigma[orig_logn]; + srct0[t0] = SamplerZ.sample(samp_ctx, srct0[t0], leaf); + srct1[t1] = SamplerZ.sample(samp_ctx, srct1[t1], leaf); return; } @@ -341,16 +347,16 @@ void ffSampling_fft_dyntree(SamplerZ samp, SamplerCtx samp_ctx, * Decompose G into LDL. We only need d00 (identical to g00), * d11, and l10; we do that in place. */ - fft.poly_LDL_fft(srcg00, g00, srcg01, g01, srcg11, g11, logn); + FalconFFT.poly_LDL_fft(srcg00, g00, srcg01, g01, srcg11, g11, logn); /* * Split d00 and d11 and expand them into half-size quasi-cyclic * Gram matrices. We also save l10 in tmp[]. */ - fft.poly_split_fft(srctmp, tmp, srctmp, tmp + hn, srcg00, g00, logn); + FalconFFT.poly_split_fft(srctmp, tmp, srctmp, tmp + hn, srcg00, g00, logn); // memcpy(g00, tmp, n * sizeof *tmp); System.arraycopy(srctmp, tmp, srcg00, g00, n); - fft.poly_split_fft(srctmp, tmp, srctmp, tmp + hn, srcg11, g11, logn); + FalconFFT.poly_split_fft(srctmp, tmp, srctmp, tmp + hn, srcg11, g11, logn); // memcpy(g11, tmp, n * sizeof *tmp); System.arraycopy(srctmp, tmp, srcg11, g11, n); // memcpy(tmp, g01, n * sizeof *g01); @@ -374,10 +380,10 @@ void ffSampling_fft_dyntree(SamplerZ samp, SamplerCtx samp_ctx, * back into tmp + 2*n. */ z1 = tmp + n; - fft.poly_split_fft(srctmp, z1, srctmp, z1 + hn, srct1, t1, logn); - ffSampling_fft_dyntree(samp, samp_ctx, srctmp, z1, srctmp, z1 + hn, + FalconFFT.poly_split_fft(srctmp, z1, srctmp, z1 + hn, srct1, t1, logn); + ffSampling_fft_dyntree(samp_ctx, srctmp, z1, srctmp, z1 + hn, srcg11, g11, srcg11, g11 + hn, srcg01, g01 + hn, orig_logn, logn - 1, srctmp, z1 + n); - fft.poly_merge_fft(srctmp, tmp + (n << 1), srctmp, z1, srctmp, z1 + hn, logn); + FalconFFT.poly_merge_fft(srctmp, tmp + (n << 1), srctmp, z1, srctmp, z1 + hn, logn); /* * Compute tb0 = t0 + (t1 - z1) * l10. @@ -388,250 +394,250 @@ void ffSampling_fft_dyntree(SamplerZ samp, SamplerCtx samp_ctx, */ // memcpy(z1, t1, n * sizeof *t1); System.arraycopy(srct1, t1, srctmp, z1, n); - fft.poly_sub(srctmp, z1, srctmp, tmp + (n << 1), logn); + FalconFFT.poly_sub(srctmp, z1, srctmp, tmp + (n << 1), logn); // memcpy(t1, tmp + (n << 1), n * sizeof *tmp); System.arraycopy(srctmp, tmp + (n << 1), srct1, t1, n); - fft.poly_mul_fft(srctmp, tmp, srctmp, z1, logn); - fft.poly_add(srct0, t0, srctmp, tmp, logn); + FalconFFT.poly_mul_fft(srctmp, tmp, srctmp, z1, logn); + FalconFFT.poly_add(srct0, t0, srctmp, tmp, logn); /* * Second recursive invocation, on the split tb0 (currently in t0) * and the left sub-tree. */ z0 = tmp; - fft.poly_split_fft(srctmp, z0, srctmp, z0 + hn, srct0, t0, logn); - ffSampling_fft_dyntree(samp, samp_ctx, srctmp, z0, srctmp, z0 + hn, + FalconFFT.poly_split_fft(srctmp, z0, srctmp, z0 + hn, srct0, t0, logn); + ffSampling_fft_dyntree(samp_ctx, srctmp, z0, srctmp, z0 + hn, srcg00, g00, srcg00, g00 + hn, srcg01, g01, orig_logn, logn - 1, srctmp, z0 + n); - fft.poly_merge_fft(srct0, t0, srctmp, z0, srctmp, z0 + hn, logn); + FalconFFT.poly_merge_fft(srct0, t0, srctmp, z0, srctmp, z0 + hn, logn); } /* * Perform Fast Fourier Sampling for target vector t and LDL tree T. * tmp[] must have size for at least two polynomials of size 2^logn. */ - void ffSampling_fft(SamplerZ samp, SamplerCtx samp_ctx, - FalconFPR[] srcz0, int z0, FalconFPR[] srcz1, int z1, - FalconFPR[] srctree, int tree, - FalconFPR[] srct0, int t0, FalconFPR[] srct1, int t1, int logn, - FalconFPR[] srctmp, int tmp) - { - int n, hn; - int tree0, tree1; - - /* - * When logn == 2, we inline the last two recursion levels. - */ - if (logn == 2) - { - FalconFPR x0, x1, y0, y1, w0, w1, w2, w3, sigma; - FalconFPR a_re, a_im, b_re, b_im, c_re, c_im; - - tree0 = tree + 4; - tree1 = tree + 8; - - /* - * We split t1 into w*, then do the recursive invocation, - * with output in w*. We finally merge back into z1. - */ - a_re = srct1[t1 + 0]; - a_im = srct1[t1 + 2]; - b_re = srct1[t1 + 1]; - b_im = srct1[t1 + 3]; - c_re = fpr.fpr_add(a_re, b_re); - c_im = fpr.fpr_add(a_im, b_im); - w0 = fpr.fpr_half(c_re); - w1 = fpr.fpr_half(c_im); - c_re = fpr.fpr_sub(a_re, b_re); - c_im = fpr.fpr_sub(a_im, b_im); - w2 = fpr.fpr_mul(fpr.fpr_add(c_re, c_im), fpr.fpr_invsqrt8); - w3 = fpr.fpr_mul(fpr.fpr_sub(c_im, c_re), fpr.fpr_invsqrt8); - - x0 = w2; - x1 = w3; - sigma = srctree[tree1 + 3]; - w2 = fpr.fpr_of(samp.sample(samp_ctx, x0, sigma)); - w3 = fpr.fpr_of(samp.sample(samp_ctx, x1, sigma)); - a_re = fpr.fpr_sub(x0, w2); - a_im = fpr.fpr_sub(x1, w3); - b_re = srctree[tree1 + 0]; - b_im = srctree[tree1 + 1]; - c_re = fpr.fpr_sub(fpr.fpr_mul(a_re, b_re), fpr.fpr_mul(a_im, b_im)); - c_im = fpr.fpr_add(fpr.fpr_mul(a_re, b_im), fpr.fpr_mul(a_im, b_re)); - x0 = fpr.fpr_add(c_re, w0); - x1 = fpr.fpr_add(c_im, w1); - sigma = srctree[tree1 + 2]; - w0 = fpr.fpr_of(samp.sample(samp_ctx, x0, sigma)); - w1 = fpr.fpr_of(samp.sample(samp_ctx, x1, sigma)); - - a_re = w0; - a_im = w1; - b_re = w2; - b_im = w3; - c_re = fpr.fpr_mul(fpr.fpr_sub(b_re, b_im), fpr.fpr_invsqrt2); - c_im = fpr.fpr_mul(fpr.fpr_add(b_re, b_im), fpr.fpr_invsqrt2); - srcz1[z1 + 0] = w0 = fpr.fpr_add(a_re, c_re); - srcz1[z1 + 2] = w2 = fpr.fpr_add(a_im, c_im); - srcz1[z1 + 1] = w1 = fpr.fpr_sub(a_re, c_re); - srcz1[z1 + 3] = w3 = fpr.fpr_sub(a_im, c_im); - - /* - * Compute tb0 = t0 + (t1 - z1) * L. Value tb0 ends up in w*. - */ - w0 = fpr.fpr_sub(srct1[t1 + 0], w0); - w1 = fpr.fpr_sub(srct1[t1 + 1], w1); - w2 = fpr.fpr_sub(srct1[t1 + 2], w2); - w3 = fpr.fpr_sub(srct1[t1 + 3], w3); - - a_re = w0; - a_im = w2; - b_re = srctree[tree + 0]; - b_im = srctree[tree + 2]; - w0 = fpr.fpr_sub(fpr.fpr_mul(a_re, b_re), fpr.fpr_mul(a_im, b_im)); - w2 = fpr.fpr_add(fpr.fpr_mul(a_re, b_im), fpr.fpr_mul(a_im, b_re)); - a_re = w1; - a_im = w3; - b_re = srctree[tree + 1]; - b_im = srctree[tree + 3]; - w1 = fpr.fpr_sub(fpr.fpr_mul(a_re, b_re), fpr.fpr_mul(a_im, b_im)); - w3 = fpr.fpr_add(fpr.fpr_mul(a_re, b_im), fpr.fpr_mul(a_im, b_re)); - - w0 = fpr.fpr_add(w0, srct0[t0 + 0]); - w1 = fpr.fpr_add(w1, srct0[t0 + 1]); - w2 = fpr.fpr_add(w2, srct0[t0 + 2]); - w3 = fpr.fpr_add(w3, srct0[t0 + 3]); - - /* - * Second recursive invocation. - */ - a_re = w0; - a_im = w2; - b_re = w1; - b_im = w3; - c_re = fpr.fpr_add(a_re, b_re); - c_im = fpr.fpr_add(a_im, b_im); - w0 = fpr.fpr_half(c_re); - w1 = fpr.fpr_half(c_im); - c_re = fpr.fpr_sub(a_re, b_re); - c_im = fpr.fpr_sub(a_im, b_im); - w2 = fpr.fpr_mul(fpr.fpr_add(c_re, c_im), fpr.fpr_invsqrt8); - w3 = fpr.fpr_mul(fpr.fpr_sub(c_im, c_re), fpr.fpr_invsqrt8); - - x0 = w2; - x1 = w3; - sigma = srctree[tree0 + 3]; - w2 = y0 = fpr.fpr_of(samp.sample(samp_ctx, x0, sigma)); - w3 = y1 = fpr.fpr_of(samp.sample(samp_ctx, x1, sigma)); - a_re = fpr.fpr_sub(x0, y0); - a_im = fpr.fpr_sub(x1, y1); - b_re = srctree[tree0 + 0]; - b_im = srctree[tree0 + 1]; - c_re = fpr.fpr_sub(fpr.fpr_mul(a_re, b_re), fpr.fpr_mul(a_im, b_im)); - c_im = fpr.fpr_add(fpr.fpr_mul(a_re, b_im), fpr.fpr_mul(a_im, b_re)); - x0 = fpr.fpr_add(c_re, w0); - x1 = fpr.fpr_add(c_im, w1); - sigma = srctree[tree0 + 2]; - w0 = fpr.fpr_of(samp.sample(samp_ctx, x0, sigma)); - w1 = fpr.fpr_of(samp.sample(samp_ctx, x1, sigma)); - - a_re = w0; - a_im = w1; - b_re = w2; - b_im = w3; - c_re = fpr.fpr_mul(fpr.fpr_sub(b_re, b_im), fpr.fpr_invsqrt2); - c_im = fpr.fpr_mul(fpr.fpr_add(b_re, b_im), fpr.fpr_invsqrt2); - srcz0[z0 + 0] = fpr.fpr_add(a_re, c_re); - srcz0[z0 + 2] = fpr.fpr_add(a_im, c_im); - srcz0[z0 + 1] = fpr.fpr_sub(a_re, c_re); - srcz0[z0 + 3] = fpr.fpr_sub(a_im, c_im); - - return; - } - - /* - * Case logn == 1 is reachable only when using Falcon-2 (the - * smallest size for which Falcon is mathematically defined, but - * of course way too insecure to be of any use). - */ - if (logn == 1) - { - FalconFPR x0, x1, y0, y1, sigma; - FalconFPR a_re, a_im, b_re, b_im, c_re, c_im; - - x0 = srct1[t1 + 0]; - x1 = srct1[t1 + 1]; - sigma = srctree[tree + 3]; - srcz1[z1 + 0] = y0 = fpr.fpr_of(samp.sample(samp_ctx, x0, sigma)); - srcz1[z1 + 1] = y1 = fpr.fpr_of(samp.sample(samp_ctx, x1, sigma)); - a_re = fpr.fpr_sub(x0, y0); - a_im = fpr.fpr_sub(x1, y1); - b_re = srctree[tree + 0]; - b_im = srctree[tree + 1]; - c_re = fpr.fpr_sub(fpr.fpr_mul(a_re, b_re), fpr.fpr_mul(a_im, b_im)); - c_im = fpr.fpr_add(fpr.fpr_mul(a_re, b_im), fpr.fpr_mul(a_im, b_re)); - x0 = fpr.fpr_add(c_re, srct0[t0 + 0]); - x1 = fpr.fpr_add(c_im, srct0[t0 + 1]); - sigma = srctree[tree + 2]; - srcz0[z0 + 0] = fpr.fpr_of(samp.sample(samp_ctx, x0, sigma)); - srcz0[z0 + 1] = fpr.fpr_of(samp.sample(samp_ctx, x1, sigma)); - - return; - } - - /* - * Normal end of recursion is for logn == 0. Since the last - * steps of the recursions were inlined in the blocks above - * (when logn == 1 or 2), this case is not reachable, and is - * retained here only for documentation purposes. - - if (logn == 0) { - fpr x0, x1, sigma; - - x0 = t0[0]; - x1 = t1[0]; - sigma = tree[0]; - z0[0] = fpr_of(samp(samp_ctx, x0, sigma)); - z1[0] = fpr_of(samp(samp_ctx, x1, sigma)); - return; - } - - */ - - /* - * General recursive case (logn >= 3). - */ - - n = 1 << logn; - hn = n >> 1; - tree0 = tree + n; - tree1 = tree + n + ffLDL_treesize(logn - 1); - - /* - * We split t1 into z1 (reused as temporary storage), then do - * the recursive invocation, with output in tmp. We finally - * merge back into z1. - */ - fft.poly_split_fft(srcz1, z1, srcz1, z1 + hn, srct1, t1, logn); - ffSampling_fft(samp, samp_ctx, srctmp, tmp, srctmp, tmp + hn, - srctree, tree1, srcz1, z1, srcz1, z1 + hn, logn - 1, srctmp, tmp + n); - fft.poly_merge_fft(srcz1, z1, srctmp, tmp, srctmp, tmp + hn, logn); - - /* - * Compute tb0 = t0 + (t1 - z1) * L. Value tb0 ends up in tmp[]. - */ -// memcpy(tmp, t1, n * sizeof *t1); - System.arraycopy(srct1, t1, srctmp, tmp, n); - fft.poly_sub(srctmp, tmp, srcz1, z1, logn); - fft.poly_mul_fft(srctmp, tmp, srctree, tree, logn); - fft.poly_add(srctmp, tmp, srct0, t0, logn); - - /* - * Second recursive invocation. - */ - fft.poly_split_fft(srcz0, z0, srcz0, z0 + hn, srctmp, tmp, logn); - ffSampling_fft(samp, samp_ctx, srctmp, tmp, srctmp, tmp + hn, - srctree, tree0, srcz0, z0, srcz0, z0 + hn, logn - 1, srctmp, tmp + n); - fft.poly_merge_fft(srcz0, z0, srctmp, tmp, srctmp, tmp + hn, logn); - } +// void ffSampling_fft(SamplerZ samp, SamplerCtx samp_ctx, +// double[] srcz0, int z0, double[] srcz1, int z1, +// double[] srctree, int tree, +// double[] srct0, int t0, double[] srct1, int t1, int logn, +// double[] srctmp, int tmp) +// { +// int n, hn; +// int tree0, tree1; +// +// /* +// * When logn == 2, we inline the last two recursion levels. +// */ +// if (logn == 2) +// { +// double x0, x1, y0, y1, w0, w1, w2, w3, sigma; +// double a_re, a_im, b_re, b_im, c_re, c_im; +// +// tree0 = tree + 4; +// tree1 = tree + 8; +// +// /* +// * We split t1 into w*, then do the recursive invocation, +// * with output in w*. We finally merge back into z1. +// */ +// a_re = srct1[t1 + 0]; +// a_im = srct1[t1 + 2]; +// b_re = srct1[t1 + 1]; +// b_im = srct1[t1 + 3]; +// c_re = fpr.fpr_add(a_re, b_re); +// c_im = fpr.fpr_add(a_im, b_im); +// w0 = fpr.fpr_half(c_re); +// w1 = fpr.fpr_half(c_im); +// c_re = fpr.fpr_sub(a_re, b_re); +// c_im = fpr.fpr_sub(a_im, b_im); +// w2 = fpr.fpr_mul(fpr.fpr_add(c_re, c_im), fpr.fpr_invsqrt8); +// w3 = fpr.fpr_mul(fpr.fpr_sub(c_im, c_re), fpr.fpr_invsqrt8); +// +// x0 = w2; +// x1 = w3; +// sigma = srctree[tree1 + 3]; +// w2 = fpr.fpr_of(samp.sample(samp_ctx, x0, sigma)); +// w3 = fpr.fpr_of(samp.sample(samp_ctx, x1, sigma)); +// a_re = fpr.fpr_sub(x0, w2); +// a_im = fpr.fpr_sub(x1, w3); +// b_re = srctree[tree1 + 0]; +// b_im = srctree[tree1 + 1]; +// c_re = fpr.fpr_sub(fpr.fpr_mul(a_re, b_re), fpr.fpr_mul(a_im, b_im)); +// c_im = fpr.fpr_add(fpr.fpr_mul(a_re, b_im), fpr.fpr_mul(a_im, b_re)); +// x0 = fpr.fpr_add(c_re, w0); +// x1 = fpr.fpr_add(c_im, w1); +// sigma = srctree[tree1 + 2]; +// w0 = fpr.fpr_of(samp.sample(samp_ctx, x0, sigma)); +// w1 = fpr.fpr_of(samp.sample(samp_ctx, x1, sigma)); +// +// a_re = w0; +// a_im = w1; +// b_re = w2; +// b_im = w3; +// c_re = fpr.fpr_mul(fpr.fpr_sub(b_re, b_im), fpr.fpr_invsqrt2); +// c_im = fpr.fpr_mul(fpr.fpr_add(b_re, b_im), fpr.fpr_invsqrt2); +// srcz1[z1 + 0] = w0 = fpr.fpr_add(a_re, c_re); +// srcz1[z1 + 2] = w2 = fpr.fpr_add(a_im, c_im); +// srcz1[z1 + 1] = w1 = fpr.fpr_sub(a_re, c_re); +// srcz1[z1 + 3] = w3 = fpr.fpr_sub(a_im, c_im); +// +// /* +// * Compute tb0 = t0 + (t1 - z1) * L. Value tb0 ends up in w*. +// */ +// w0 = fpr.fpr_sub(srct1[t1 + 0], w0); +// w1 = fpr.fpr_sub(srct1[t1 + 1], w1); +// w2 = fpr.fpr_sub(srct1[t1 + 2], w2); +// w3 = fpr.fpr_sub(srct1[t1 + 3], w3); +// +// a_re = w0; +// a_im = w2; +// b_re = srctree[tree + 0]; +// b_im = srctree[tree + 2]; +// w0 = fpr.fpr_sub(fpr.fpr_mul(a_re, b_re), fpr.fpr_mul(a_im, b_im)); +// w2 = fpr.fpr_add(fpr.fpr_mul(a_re, b_im), fpr.fpr_mul(a_im, b_re)); +// a_re = w1; +// a_im = w3; +// b_re = srctree[tree + 1]; +// b_im = srctree[tree + 3]; +// w1 = fpr.fpr_sub(fpr.fpr_mul(a_re, b_re), fpr.fpr_mul(a_im, b_im)); +// w3 = fpr.fpr_add(fpr.fpr_mul(a_re, b_im), fpr.fpr_mul(a_im, b_re)); +// +// w0 = fpr.fpr_add(w0, srct0[t0 + 0]); +// w1 = fpr.fpr_add(w1, srct0[t0 + 1]); +// w2 = fpr.fpr_add(w2, srct0[t0 + 2]); +// w3 = fpr.fpr_add(w3, srct0[t0 + 3]); +// +// /* +// * Second recursive invocation. +// */ +// a_re = w0; +// a_im = w2; +// b_re = w1; +// b_im = w3; +// c_re = fpr.fpr_add(a_re, b_re); +// c_im = fpr.fpr_add(a_im, b_im); +// w0 = fpr.fpr_half(c_re); +// w1 = fpr.fpr_half(c_im); +// c_re = fpr.fpr_sub(a_re, b_re); +// c_im = fpr.fpr_sub(a_im, b_im); +// w2 = fpr.fpr_mul(fpr.fpr_add(c_re, c_im), fpr.fpr_invsqrt8); +// w3 = fpr.fpr_mul(fpr.fpr_sub(c_im, c_re), fpr.fpr_invsqrt8); +// +// x0 = w2; +// x1 = w3; +// sigma = srctree[tree0 + 3]; +// w2 = y0 = fpr.fpr_of(samp.sample(samp_ctx, x0, sigma)); +// w3 = y1 = fpr.fpr_of(samp.sample(samp_ctx, x1, sigma)); +// a_re = fpr.fpr_sub(x0, y0); +// a_im = fpr.fpr_sub(x1, y1); +// b_re = srctree[tree0 + 0]; +// b_im = srctree[tree0 + 1]; +// c_re = fpr.fpr_sub(fpr.fpr_mul(a_re, b_re), fpr.fpr_mul(a_im, b_im)); +// c_im = fpr.fpr_add(fpr.fpr_mul(a_re, b_im), fpr.fpr_mul(a_im, b_re)); +// x0 = fpr.fpr_add(c_re, w0); +// x1 = fpr.fpr_add(c_im, w1); +// sigma = srctree[tree0 + 2]; +// w0 = fpr.fpr_of(samp.sample(samp_ctx, x0, sigma)); +// w1 = fpr.fpr_of(samp.sample(samp_ctx, x1, sigma)); +// +// a_re = w0; +// a_im = w1; +// b_re = w2; +// b_im = w3; +// c_re = fpr.fpr_mul(fpr.fpr_sub(b_re, b_im), fpr.fpr_invsqrt2); +// c_im = fpr.fpr_mul(fpr.fpr_add(b_re, b_im), fpr.fpr_invsqrt2); +// srcz0[z0 + 0] = fpr.fpr_add(a_re, c_re); +// srcz0[z0 + 2] = fpr.fpr_add(a_im, c_im); +// srcz0[z0 + 1] = fpr.fpr_sub(a_re, c_re); +// srcz0[z0 + 3] = fpr.fpr_sub(a_im, c_im); +// +// return; +// } +// +// /* +// * Case logn == 1 is reachable only when using Falcon-2 (the +// * smallest size for which Falcon is mathematically defined, but +// * of course way too insecure to be of any use). +// */ +// if (logn == 1) +// { +// double x0, x1, y0, y1, sigma; +// double a_re, a_im, b_re, b_im, c_re, c_im; +// +// x0 = srct1[t1 + 0]; +// x1 = srct1[t1 + 1]; +// sigma = srctree[tree + 3]; +// srcz1[z1 + 0] = y0 = fpr.fpr_of(samp.sample(samp_ctx, x0, sigma)); +// srcz1[z1 + 1] = y1 = fpr.fpr_of(samp.sample(samp_ctx, x1, sigma)); +// a_re = fpr.fpr_sub(x0, y0); +// a_im = fpr.fpr_sub(x1, y1); +// b_re = srctree[tree + 0]; +// b_im = srctree[tree + 1]; +// c_re = fpr.fpr_sub(fpr.fpr_mul(a_re, b_re), fpr.fpr_mul(a_im, b_im)); +// c_im = fpr.fpr_add(fpr.fpr_mul(a_re, b_im), fpr.fpr_mul(a_im, b_re)); +// x0 = fpr.fpr_add(c_re, srct0[t0 + 0]); +// x1 = fpr.fpr_add(c_im, srct0[t0 + 1]); +// sigma = srctree[tree + 2]; +// srcz0[z0 + 0] = fpr.fpr_of(samp.sample(samp_ctx, x0, sigma)); +// srcz0[z0 + 1] = fpr.fpr_of(samp.sample(samp_ctx, x1, sigma)); +// +// return; +// } +// +// /* +// * Normal end of recursion is for logn == 0. Since the last +// * steps of the recursions were inlined in the blocks above +// * (when logn == 1 or 2), this case is not reachable, and is +// * retained here only for documentation purposes. +// +// if (logn == 0) { +// fpr x0, x1, sigma; +// +// x0 = t0[0]; +// x1 = t1[0]; +// sigma = tree[0]; +// z0[0] = fpr_of(samp(samp_ctx, x0, sigma)); +// z1[0] = fpr_of(samp(samp_ctx, x1, sigma)); +// return; +// } +// +// */ +// +// /* +// * General recursive case (logn >= 3). +// */ +// +// n = 1 << logn; +// hn = n >> 1; +// tree0 = tree + n; +// tree1 = tree + n + ffLDL_treesize(logn - 1); +// +// /* +// * We split t1 into z1 (reused as temporary storage), then do +// * the recursive invocation, with output in tmp. We finally +// * merge back into z1. +// */ +// fft.poly_split_fft(srcz1, z1, srcz1, z1 + hn, srct1, t1, logn); +// ffSampling_fft(samp, samp_ctx, srctmp, tmp, srctmp, tmp + hn, +// srctree, tree1, srcz1, z1, srcz1, z1 + hn, logn - 1, srctmp, tmp + n); +// fft.poly_merge_fft(srcz1, z1, srctmp, tmp, srctmp, tmp + hn, logn); +// +// /* +// * Compute tb0 = t0 + (t1 - z1) * L. Value tb0 ends up in tmp[]. +// */ +//// memcpy(tmp, t1, n * sizeof *t1); +// System.arraycopy(srct1, t1, srctmp, tmp, n); +// fft.poly_sub(srctmp, tmp, srcz1, z1, logn); +// fft.poly_mul_fft(srctmp, tmp, srctree, tree, logn); +// fft.poly_add(srctmp, tmp, srct0, t0, logn); +// +// /* +// * Second recursive invocation. +// */ +// fft.poly_split_fft(srcz0, z0, srcz0, z0 + hn, srctmp, tmp, logn); +// ffSampling_fft(samp, samp_ctx, srctmp, tmp, srctmp, tmp + hn, +// srctree, tree0, srcz0, z0, srcz0, z0 + hn, logn - 1, srctmp, tmp + n); +// fft.poly_merge_fft(srcz0, z0, srctmp, tmp, srctmp, tmp + hn, logn); +// } /* * Compute a signature: the signature contains two vectors, s1 and s2. @@ -643,123 +649,123 @@ void ffSampling_fft(SamplerZ samp, SamplerCtx samp_ctx, * * tmp[] must have room for at least six polynomials. */ - int do_sign_tree(SamplerZ samp, SamplerCtx samp_ctx, short[] srcs2, int s2, - FalconFPR[] srcexpanded_key, int expanded_key, - short[] srchm, int hm, - int logn, FalconFPR[] srctmp, int tmp) - { - int n, u; - int t0, t1, tx, ty; - int b00, b01, b10, b11, tree; - FalconFPR ni; - int sqn, ng; - short[] s1tmp, s2tmp; - - n = MKN(logn); - t0 = tmp; - t1 = t0 + n; - b00 = expanded_key + skoff_b00(logn); - b01 = expanded_key + skoff_b01(logn); - b10 = expanded_key + skoff_b10(logn); - b11 = expanded_key + skoff_b11(logn); - tree = expanded_key + skoff_tree(logn); - - /* - * Set the target vector to [hm, 0] (hm is the hashed message). - */ - for (u = 0; u < n; u++) - { - srctmp[t0 + u] = fpr.fpr_of(srchm[hm + u]); - /* This is implicit. - t1[u] = fpr_zero; - */ - } - - /* - * Apply the lattice basis to obtain the real target - * vector (after normalization with regards to modulus). - */ - fft.FFT(srctmp, t0, logn); - ni = fpr.fpr_inverse_of_q; -// memcpy(t1, t0, n * sizeof *t0); - System.arraycopy(srctmp, t0, srctmp, t1, n); - fft.poly_mul_fft(srctmp, t1, srcexpanded_key, b01, logn); - fft.poly_mulconst(srctmp, t1, fpr.fpr_neg(ni), logn); - fft.poly_mul_fft(srctmp, t0, srcexpanded_key, b11, logn); - fft.poly_mulconst(srctmp, t0, ni, logn); - - tx = t1 + n; - ty = tx + n; - - /* - * Apply sampling. Output is written back in [tx, ty]. - */ - ffSampling_fft(samp, samp_ctx, srctmp, tx, srctmp, ty, srcexpanded_key, tree, - srctmp, t0, srctmp, t1, logn, srctmp, ty + n); - - /* - * Get the lattice point corresponding to that tiny vector. - */ -// memcpy(t0, tx, n * sizeof *tx); - System.arraycopy(srctmp, tx, srctmp, t0, n); -// memcpy(t1, ty, n * sizeof *ty); - System.arraycopy(srctmp, ty, srctmp, t1, n); - fft.poly_mul_fft(srctmp, tx, srcexpanded_key, b00, logn); - fft.poly_mul_fft(srctmp, ty, srcexpanded_key, b10, logn); - fft.poly_add(srctmp, tx, srctmp, ty, logn); -// memcpy(ty, t0, n * sizeof *t0); - System.arraycopy(srctmp, t0, srctmp, ty, n); - fft.poly_mul_fft(srctmp, ty, srcexpanded_key, b01, logn); - -// memcpy(t0, tx, n * sizeof *tx); - System.arraycopy(srctmp, tx, srctmp, t0, n); - fft.poly_mul_fft(srctmp, t1, srcexpanded_key, b11, logn); - fft.poly_add(srctmp, t1, srctmp, ty, logn); - - fft.iFFT(srctmp, t0, logn); - fft.iFFT(srctmp, t1, logn); - - /* - * Compute the signature. - */ - s1tmp = new short[n]; - sqn = 0; - ng = 0; - for (u = 0; u < n; u++) - { - int z; - // note: hm is unsigned - z = (srchm[hm + u] & 0xffff) - (int)fpr.fpr_rint(srctmp[t0 + u]); - sqn += (z * z); - ng |= sqn; - s1tmp[u] = (short)z; - } - sqn |= -(ng >>> 31); - - /* - * With "normal" degrees (e.g. 512 or 1024), it is very - * improbable that the computed vector is not short enough; - * however, it may happen in practice for the very reduced - * versions (e.g. degree 16 or below). In that case, the caller - * will loop, and we must not write anything into s2[] because - * s2[] may overlap with the hashed message hm[] and we need - * hm[] for the next iteration. - */ - s2tmp = new short[n]; - for (u = 0; u < n; u++) - { - s2tmp[u] = (short)-fpr.fpr_rint(srctmp[t1 + u]); - } - if (common.is_short_half(sqn, s2tmp, 0, logn) != 0) - { -// memcpy(s2, s2tmp, n * sizeof *s2); - System.arraycopy(s2tmp, 0, srcs2, s2, n); -// memcpy(tmp, s1tmp, n * sizeof *s1tmp); - System.arraycopy(s1tmp, 0, srctmp, tmp, n); - return 1; - } - return 0; - } +// int do_sign_tree(SamplerZ samp, SamplerCtx samp_ctx, short[] srcs2, int s2, +// double[] srcexpanded_key, int expanded_key, +// short[] srchm, int hm, +// int logn, double[] srctmp, int tmp) +// { +// int n, u; +// int t0, t1, tx, ty; +// int b00, b01, b10, b11, tree; +// double ni; +// int sqn, ng; +// short[] s1tmp, s2tmp; +// +// n = MKN(logn); +// t0 = tmp; +// t1 = t0 + n; +// b00 = expanded_key + skoff_b00(logn); +// b01 = expanded_key + skoff_b01(logn); +// b10 = expanded_key + skoff_b10(logn); +// b11 = expanded_key + skoff_b11(logn); +// tree = expanded_key + skoff_tree(logn); +// +// /* +// * Set the target vector to [hm, 0] (hm is the hashed message). +// */ +// for (u = 0; u < n; u++) +// { +// srctmp[t0 + u] = fpr.fpr_of(srchm[hm + u]); +// /* This is implicit. +// t1[u] = fpr_zero; +// */ +// } +// +// /* +// * Apply the lattice basis to obtain the real target +// * vector (after normalization with regards to modulus). +// */ +// fft.FFT(srctmp, t0, logn); +// ni = fpr.fpr_inverse_of_q; +//// memcpy(t1, t0, n * sizeof *t0); +// System.arraycopy(srctmp, t0, srctmp, t1, n); +// fft.poly_mul_fft(srctmp, t1, srcexpanded_key, b01, logn); +// fft.poly_mulconst(srctmp, t1, fpr.fpr_neg(ni), logn); +// fft.poly_mul_fft(srctmp, t0, srcexpanded_key, b11, logn); +// fft.poly_mulconst(srctmp, t0, ni, logn); +// +// tx = t1 + n; +// ty = tx + n; +// +// /* +// * Apply sampling. Output is written back in [tx, ty]. +// */ +// ffSampling_fft(samp, samp_ctx, srctmp, tx, srctmp, ty, srcexpanded_key, tree, +// srctmp, t0, srctmp, t1, logn, srctmp, ty + n); +// +// /* +// * Get the lattice point corresponding to that tiny vector. +// */ +//// memcpy(t0, tx, n * sizeof *tx); +// System.arraycopy(srctmp, tx, srctmp, t0, n); +//// memcpy(t1, ty, n * sizeof *ty); +// System.arraycopy(srctmp, ty, srctmp, t1, n); +// fft.poly_mul_fft(srctmp, tx, srcexpanded_key, b00, logn); +// fft.poly_mul_fft(srctmp, ty, srcexpanded_key, b10, logn); +// fft.poly_add(srctmp, tx, srctmp, ty, logn); +//// memcpy(ty, t0, n * sizeof *t0); +// System.arraycopy(srctmp, t0, srctmp, ty, n); +// fft.poly_mul_fft(srctmp, ty, srcexpanded_key, b01, logn); +// +//// memcpy(t0, tx, n * sizeof *tx); +// System.arraycopy(srctmp, tx, srctmp, t0, n); +// fft.poly_mul_fft(srctmp, t1, srcexpanded_key, b11, logn); +// fft.poly_add(srctmp, t1, srctmp, ty, logn); +// +// fft.iFFT(srctmp, t0, logn); +// fft.iFFT(srctmp, t1, logn); +// +// /* +// * Compute the signature. +// */ +// s1tmp = new short[n]; +// sqn = 0; +// ng = 0; +// for (u = 0; u < n; u++) +// { +// int z; +// // note: hm is unsigned +// z = (srchm[hm + u] & 0xffff) - (int)fpr.fpr_rint(srctmp[t0 + u]); +// sqn += (z * z); +// ng |= sqn; +// s1tmp[u] = (short)z; +// } +// sqn |= -(ng >>> 31); +// +// /* +// * With "normal" degrees (e.g. 512 or 1024), it is very +// * improbable that the computed vector is not short enough; +// * however, it may happen in practice for the very reduced +// * versions (e.g. degree 16 or below). In that case, the caller +// * will loop, and we must not write anything into s2[] because +// * s2[] may overlap with the hashed message hm[] and we need +// * hm[] for the next iteration. +// */ +// s2tmp = new short[n]; +// for (u = 0; u < n; u++) +// { +// s2tmp[u] = (short)-fpr.fpr_rint(srctmp[t1 + u]); +// } +// if (common.is_short_half(sqn, s2tmp, logn) != 0) +// { +//// memcpy(s2, s2tmp, n * sizeof *s2); +// System.arraycopy(s2tmp, 0, srcs2, s2, n); +//// memcpy(tmp, s1tmp, n * sizeof *s1tmp); +// System.arraycopy(s1tmp, 0, srctmp, tmp, n); +// return 1; +// } +// return 0; +// } /* * Compute a signature: the signature contains two vectors, s1 and s2. @@ -770,19 +776,19 @@ int do_sign_tree(SamplerZ samp, SamplerCtx samp_ctx, short[] srcs2, int s2, * * tmp[] must have room for at least nine polynomials. */ - int do_sign_dyn(SamplerZ samp, SamplerCtx samp_ctx, short[] srcs2, int s2, - byte[] srcf, int f, byte[] srcg, int g, - byte[] srcF, int F, byte[] srcG, int G, - short[] srchm, int hm, int logn, FalconFPR[] srctmp, int tmp) + int do_sign_dyn(SamplerCtx samp_ctx, short[] srcs2, + byte[] srcf, byte[] srcg, + byte[] srcF, byte[] srcG, + short[] srchm, int logn, double[] srctmp, int tmp) { int n, u; int t0, t1, tx, ty; int b00, b01, b10, b11, g00, g01, g11; - FalconFPR ni; + double ni; int sqn, ng; - short[] s1tmp, s2tmp; + short[] s2tmp; //s1tmp, - n = MKN(logn); + n = 1 << logn; /* * Lattice basis is B = [[g, -f], [G, -F]]. We convert it to FFT. @@ -791,16 +797,16 @@ int do_sign_dyn(SamplerZ samp, SamplerCtx samp_ctx, short[] srcs2, int s2, b01 = b00 + n; b10 = b01 + n; b11 = b10 + n; - smallints_to_fpr(srctmp, b01, srcf, f, logn); - smallints_to_fpr(srctmp, b00, srcg, g, logn); - smallints_to_fpr(srctmp, b11, srcF, F, logn); - smallints_to_fpr(srctmp, b10, srcG, G, logn); - fft.FFT(srctmp, b01, logn); - fft.FFT(srctmp, b00, logn); - fft.FFT(srctmp, b11, logn); - fft.FFT(srctmp, b10, logn); - fft.poly_neg(srctmp, b01, logn); - fft.poly_neg(srctmp, b11, logn); + smallints_to_fpr(srctmp, b01, srcf, logn); + smallints_to_fpr(srctmp, b00, srcg, logn); + smallints_to_fpr(srctmp, b11, srcF, logn); + smallints_to_fpr(srctmp, b10, srcG, logn); + FalconFFT.FFT(srctmp, b01, logn); + FalconFFT.FFT(srctmp, b00, logn); + FalconFFT.FFT(srctmp, b11, logn); + FalconFFT.FFT(srctmp, b10, logn); + FalconFFT.poly_neg(srctmp, b01, logn); + FalconFFT.poly_neg(srctmp, b11, logn); /* * Compute the Gram matrix G = B·B*. Formulas are: @@ -821,23 +827,23 @@ int do_sign_dyn(SamplerZ samp, SamplerCtx samp_ctx, short[] srcs2, int s2, // memcpy(t0, b01, n * sizeof *b01); System.arraycopy(srctmp, b01, srctmp, t0, n); - fft.poly_mulselfadj_fft(srctmp, t0, logn); // t0 <- b01*adj(b01) + FalconFFT.poly_mulselfadj_fft(srctmp, t0, logn); // t0 <- b01*adj(b01) // memcpy(t1, b00, n * sizeof *b00); System.arraycopy(srctmp, b00, srctmp, t1, n); - fft.poly_muladj_fft(srctmp, t1, srctmp, b10, logn); // t1 <- b00*adj(b10) - fft.poly_mulselfadj_fft(srctmp, b00, logn); // b00 <- b00*adj(b00) - fft.poly_add(srctmp, b00, srctmp, t0, logn); // b00 <- g00 + FalconFFT.poly_muladj_fft(srctmp, t1, srctmp, b10, logn); // t1 <- b00*adj(b10) + FalconFFT.poly_mulselfadj_fft(srctmp, b00, logn); // b00 <- b00*adj(b00) + FalconFFT.poly_add(srctmp, b00, srctmp, t0, logn); // b00 <- g00 // memcpy(t0, b01, n * sizeof *b01); System.arraycopy(srctmp, b01, srctmp, t0, n); - fft.poly_muladj_fft(srctmp, b01, srctmp, b11, logn); // b01 <- b01*adj(b11) - fft.poly_add(srctmp, b01, srctmp, t1, logn); // b01 <- g01 + FalconFFT.poly_muladj_fft(srctmp, b01, srctmp, b11, logn); // b01 <- b01*adj(b11) + FalconFFT.poly_add(srctmp, b01, srctmp, t1, logn); // b01 <- g01 - fft.poly_mulselfadj_fft(srctmp, b10, logn); // b10 <- b10*adj(b10) + FalconFFT.poly_mulselfadj_fft(srctmp, b10, logn); // b10 <- b10*adj(b10) // memcpy(t1, b11, n * sizeof *b11); System.arraycopy(srctmp, b11, srctmp, t1, n); - fft.poly_mulselfadj_fft(srctmp, t1, logn); // t1 <- b11*adj(b11) - fft.poly_add(srctmp, b10, srctmp, t1, logn); // b10 <- g11 + FalconFFT.poly_mulselfadj_fft(srctmp, t1, logn); // t1 <- b11*adj(b11) + FalconFFT.poly_add(srctmp, b10, srctmp, t1, logn); // b10 <- g11 /* * We rename variables to make things clearer. The three elements @@ -861,7 +867,7 @@ int do_sign_dyn(SamplerZ samp, SamplerCtx samp_ctx, short[] srcs2, int s2, */ for (u = 0; u < n; u++) { - srctmp[t0 + u] = fpr.fpr_of(srchm[hm + u]); + srctmp[t0 + u] = srchm[u]; /* This is implicit. t1[u] = fpr_zero; */ @@ -871,14 +877,14 @@ int do_sign_dyn(SamplerZ samp, SamplerCtx samp_ctx, short[] srcs2, int s2, * Apply the lattice basis to obtain the real target * vector (after normalization with regards to modulus). */ - fft.FFT(srctmp, t0, logn); - ni = fpr.fpr_inverse_of_q; + FalconFFT.FFT(srctmp, t0, logn); + ni = FPREngine.fpr_inverse_of_q; // memcpy(t1, t0, n * sizeof *t0); System.arraycopy(srctmp, t0, srctmp, t1, n); - fft.poly_mul_fft(srctmp, t1, srctmp, b01, logn); - fft.poly_mulconst(srctmp, t1, fpr.fpr_neg(ni), logn); - fft.poly_mul_fft(srctmp, t0, srctmp, b11, logn); - fft.poly_mulconst(srctmp, t0, ni, logn); + FalconFFT.poly_mul_fft(srctmp, t1, srctmp, b01, logn); + FalconFFT.poly_mulconst(srctmp, t1, -ni, logn); + FalconFFT.poly_mul_fft(srctmp, t0, srctmp, b11, logn); + FalconFFT.poly_mulconst(srctmp, t0, ni, logn); /* * b01 and b11 can be discarded, so we move back (t0,t1). @@ -893,7 +899,7 @@ int do_sign_dyn(SamplerZ samp, SamplerCtx samp_ctx, short[] srcs2, int s2, /* * Apply sampling; result is written over (t0,t1). */ - ffSampling_fft_dyntree(samp, samp_ctx, + ffSampling_fft_dyntree(samp_ctx, srctmp, t0, srctmp, t1, srctmp, g00, srctmp, g01, srctmp, g11, logn, logn, srctmp, t1 + n); @@ -905,7 +911,7 @@ int do_sign_dyn(SamplerZ samp, SamplerCtx samp_ctx, short[] srcs2, int s2, * We did not conserve the matrix basis, so we must recompute * it now. */ - b00 = tmp; + //b00 = tmp; b01 = b00 + n; b10 = b01 + n; b11 = b10 + n; @@ -913,16 +919,16 @@ int do_sign_dyn(SamplerZ samp, SamplerCtx samp_ctx, short[] srcs2, int s2, System.arraycopy(srctmp, t0, srctmp, b11 + n, n * 2); t0 = b11 + n; t1 = t0 + n; - smallints_to_fpr(srctmp, b01, srcf, f, logn); - smallints_to_fpr(srctmp, b00, srcg, g, logn); - smallints_to_fpr(srctmp, b11, srcF, F, logn); - smallints_to_fpr(srctmp, b10, srcG, G, logn); - fft.FFT(srctmp, b01, logn); - fft.FFT(srctmp, b00, logn); - fft.FFT(srctmp, b11, logn); - fft.FFT(srctmp, b10, logn); - fft.poly_neg(srctmp, b01, logn); - fft.poly_neg(srctmp, b11, logn); + smallints_to_fpr(srctmp, b01, srcf, logn); + smallints_to_fpr(srctmp, b00, srcg, logn); + smallints_to_fpr(srctmp, b11, srcF, logn); + smallints_to_fpr(srctmp, b10, srcG, logn); + FalconFFT.FFT(srctmp, b01, logn); + FalconFFT.FFT(srctmp, b00, logn); + FalconFFT.FFT(srctmp, b11, logn); + FalconFFT.FFT(srctmp, b10, logn); + FalconFFT.poly_neg(srctmp, b01, logn); + FalconFFT.poly_neg(srctmp, b11, logn); tx = t1 + n; ty = tx + n; @@ -933,31 +939,31 @@ int do_sign_dyn(SamplerZ samp, SamplerCtx samp_ctx, short[] srcs2, int s2, System.arraycopy(srctmp, t0, srctmp, tx, n); // memcpy(ty, t1, n * sizeof *t1); System.arraycopy(srctmp, t1, srctmp, ty, n); - fft.poly_mul_fft(srctmp, tx, srctmp, b00, logn); - fft.poly_mul_fft(srctmp, ty, srctmp, b10, logn); - fft.poly_add(srctmp, tx, srctmp, ty, logn); + FalconFFT.poly_mul_fft(srctmp, tx, srctmp, b00, logn); + FalconFFT.poly_mul_fft(srctmp, ty, srctmp, b10, logn); + FalconFFT.poly_add(srctmp, tx, srctmp, ty, logn); // memcpy(ty, t0, n * sizeof *t0); System.arraycopy(srctmp, t0, srctmp, ty, n); - fft.poly_mul_fft(srctmp, ty, srctmp, b01, logn); + FalconFFT.poly_mul_fft(srctmp, ty, srctmp, b01, logn); // memcpy(t0, tx, n * sizeof *tx); System.arraycopy(srctmp, tx, srctmp, t0, n); - fft.poly_mul_fft(srctmp, t1, srctmp, b11, logn); - fft.poly_add(srctmp, t1, srctmp, ty, logn); - fft.iFFT(srctmp, t0, logn); - fft.iFFT(srctmp, t1, logn); + FalconFFT.poly_mul_fft(srctmp, t1, srctmp, b11, logn); + FalconFFT.poly_add(srctmp, t1, srctmp, ty, logn); + FalconFFT.iFFT(srctmp, t0, logn); + FalconFFT.iFFT(srctmp, t1, logn); - s1tmp = new short[n]; + //s1tmp = new short[n]; sqn = 0; ng = 0; for (u = 0; u < n; u++) { int z; - z = (srchm[hm + u] & 0xffff) - (int)fpr.fpr_rint(srctmp[t0 + u]); + z = (srchm[u] & 0xffff) - (int)FPREngine.fpr_rint(srctmp[t0 + u]); sqn += (z * z); ng |= sqn; - s1tmp[u] = (short)z; + //s1tmp[u] = (short)z; } sqn |= -(ng >>> 31); @@ -973,12 +979,12 @@ int do_sign_dyn(SamplerZ samp, SamplerCtx samp_ctx, short[] srcs2, int s2, s2tmp = new short[n]; for (u = 0; u < n; u++) { - s2tmp[u] = (short)-fpr.fpr_rint(srctmp[t1 + u]); + s2tmp[u] = (short)-FPREngine.fpr_rint(srctmp[t1 + u]); } - if (common.is_short_half(sqn, s2tmp, 0, logn) != 0) + if (FalconCommon.is_short_half(sqn, s2tmp, logn) != 0) { // memcpy(s2, s2tmp, n * sizeof *s2); - System.arraycopy(s2tmp, 0, srcs2, s2, n); + System.arraycopy(s2tmp, 0, srcs2, 0, n); // memcpy(tmp, s1tmp, n * sizeof *s1tmp); // System.arraycopy(s1tmp, 0, srctmp, tmp, n); return 1; @@ -988,57 +994,57 @@ int do_sign_dyn(SamplerZ samp, SamplerCtx samp_ctx, short[] srcs2, int s2, /* see inner.h */ - void sign_tree(short[] srcsig, int sig, SHAKE256 rng, - FalconFPR[] srcexpanded_key, int expanded_key, - short[] srchm, int hm, int logn, FalconFPR[] srctmp, int tmp) - { - int ftmp; - - ftmp = tmp; - for (; ; ) - { - /* - * Signature produces short vectors s1 and s2. The - * signature is acceptable only if the aggregate vector - * s1,s2 is short; we must use the same bound as the - * verifier. - * - * If the signature is acceptable, then we return only s2 - * (the verifier recomputes s1 from s2, the hashed message, - * and the public key). - */ - SamplerCtx spc = new SamplerCtx(); - SamplerZ samp = new SamplerZ(); - SamplerCtx samp_ctx; - - /* - * Normal sampling. We use a fast PRNG seeded from our - * SHAKE context ('rng'). - */ - spc.sigma_min = fpr.fpr_sigma_min[logn]; - spc.p.prng_init(rng); - samp_ctx = spc; - - /* - * Do the actual signature. - */ - if (do_sign_tree(samp, samp_ctx, srcsig, sig, - srcexpanded_key, expanded_key, srchm, hm, logn, srctmp, ftmp) != 0) - { - break; - } - } - } +// void sign_tree(short[] srcsig, int sig, SHAKE256 rng, +// double[] srcexpanded_key, int expanded_key, +// short[] srchm, int hm, int logn, double[] srctmp, int tmp) +// { +// int ftmp; +// +// ftmp = tmp; +// for (; ; ) +// { +// /* +// * Signature produces short vectors s1 and s2. The +// * signature is acceptable only if the aggregate vector +// * s1,s2 is short; we must use the same bound as the +// * verifier. +// * +// * If the signature is acceptable, then we return only s2 +// * (the verifier recomputes s1 from s2, the hashed message, +// * and the public key). +// */ +// SamplerCtx spc = new SamplerCtx(); +// SamplerZ samp = new SamplerZ(); +// SamplerCtx samp_ctx; +// +// /* +// * Normal sampling. We use a fast PRNG seeded from our +// * SHAKE context ('rng'). +// */ +// spc.sigma_min = fpr.fpr_sigma_min[logn]; +// spc.p.prng_init(rng); +// samp_ctx = spc; +// +// /* +// * Do the actual signature. +// */ +// if (do_sign_tree(samp, samp_ctx, srcsig, sig, +// srcexpanded_key, expanded_key, srchm, hm, logn, srctmp, ftmp) != 0) +// { +// break; +// } +// } +// } /* see inner.h */ - void sign_dyn(short[] srcsig, int sig, SHAKE256 rng, - byte[] srcf, int f, byte[] srcg, int g, - byte[] srcF, int F, byte[] srcG, int G, - short[] srchm, int hm, int logn, FalconFPR[] srctmp, int tmp) + void sign_dyn(short[] srcsig, SHAKEDigest rng, + byte[] srcf, byte[] srcg, + byte[] srcF, byte[] srcG, + short[] srchm, int logn, double[] srctmp) { int ftmp; - ftmp = tmp; + ftmp = 0; for (; ; ) { /* @@ -1052,22 +1058,22 @@ void sign_dyn(short[] srcsig, int sig, SHAKE256 rng, * and the public key). */ SamplerCtx spc = new SamplerCtx(); - SamplerZ samp = new SamplerZ(); - SamplerCtx samp_ctx; +// SamplerZ samp = new SamplerZ(); +// SamplerCtx samp_ctx; /* * Normal sampling. We use a fast PRNG seeded from our * SHAKE context ('rng'). */ - spc.sigma_min = fpr.fpr_sigma_min[logn]; + spc.sigma_min = FPREngine.fpr_sigma_min[logn]; spc.p.prng_init(rng); - samp_ctx = spc; +// samp_ctx = spc; /* * Do the actual signature. */ - if (do_sign_dyn(samp, samp_ctx, srcsig, sig, - srcf, f, srcg, g, srcF, F, srcG, G, srchm, hm, logn, srctmp, ftmp) != 0) + if (do_sign_dyn(spc, srcsig, + srcf, srcg, srcF, srcG, srchm, logn, srctmp, ftmp) != 0) { break; } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconSigner.java index 43e567df1e..f5c9bd18c7 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconSigner.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconSigner.java @@ -4,7 +4,6 @@ import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.pqc.crypto.MessageSigner; -import org.bouncycastle.util.encoders.Hex; public class FalconSigner implements MessageSigner @@ -47,7 +46,7 @@ public byte[] generateSignature(byte[] message) { byte[] sm = new byte[nist.CRYPTO_BYTES]; - return nist.crypto_sign(false, sm, message, 0, message.length, encodedkey, 0); + return nist.crypto_sign(sm, message, message.length, encodedkey); } public boolean verifySignature(byte[] message, byte[] signature) @@ -60,7 +59,6 @@ public boolean verifySignature(byte[] message, byte[] signature) byte[] sig = new byte[signature.length - nist.NONCELEN - 1]; System.arraycopy(signature, 1, nonce, 0, nist.NONCELEN); System.arraycopy(signature, nist.NONCELEN + 1, sig, 0, signature.length - nist.NONCELEN - 1); - boolean res = nist.crypto_sign_open(false, sig,nonce,message,encodedkey,0) == 0; - return res; + return nist.crypto_sign_open(sig,nonce,message,encodedkey) == 0; } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconVrfy.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconVrfy.java index f1bebf2ad0..636912ae46 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconVrfy.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/FalconVrfy.java @@ -3,11 +3,11 @@ class FalconVrfy { - FalconCommon common; +// FalconCommon common; FalconVrfy() { - this.common = new FalconCommon(); +// this.common = new FalconCommon(); } /* ===================================================================== */ /* @@ -25,10 +25,10 @@ class FalconVrfy // #define Q0I 12287 // #define R 4091 // #define R2 10952 - final int Q = 12289; - final int Q0I = 12287; - final int R = 4091; - final int R2 = 10952; + static final int Q = 12289; + static final int Q0I = 12287; + static final int R = 4091; + static final int R2 = 10952; /* * Table for NTT, binary case: @@ -36,7 +36,7 @@ class FalconVrfy * where g = 7 (it is a 2048-th primitive root of 1 modulo q) * and rev() is the bit-reversal function over 10 bits. */ - final short[] GMb = { + static final short[] GMb = { 4091, 7888, 11060, 11208, 6960, 4342, 6275, 9759, 1591, 6399, 9477, 5266, 586, 5825, 7538, 9710, 1134, 6407, 1711, 965, 7099, 7674, 3743, 6442, @@ -172,7 +172,7 @@ class FalconVrfy * iGMb[x] = R*((1/g)^rev(x)) mod q * Since g = 7, 1/g = 8778 mod 12289. */ - final short[] iGMb = { + static final short[] iGMb = { 4091, 4401, 1081, 1229, 2530, 6014, 7947, 5329, 2579, 4751, 6464, 11703, 7023, 2812, 5890, 10698, 3109, 2125, 1960, 10925, 10601, 10404, 4189, 1875, @@ -307,23 +307,23 @@ class FalconVrfy * Reduce a small signed integer modulo q. The source integer MUST * be between -q/2 and +q/2. */ - int mq_conv_small(int x) + static int mq_conv_small(int x) { /* * If x < 0, the cast to uint32_t will set the high bit to 1. * ^ in Java, integers already use 2s complement so high bit will be 1 if negative */ - int y; - - y = x; - y += Q & -(y >>> 31); - return y; +// int x; +// +// x = x; + x += Q & -(x >>> 31); + return x; } /* * Addition modulo q. Operands must be in the 0..q-1 range. */ - int mq_add(int x, int y) + static int mq_add(int x, int y) { /* * We compute x + y - q. If the result is negative, then the @@ -342,7 +342,7 @@ int mq_add(int x, int y) /* * Subtraction modulo q. Operands must be in the 0..q-1 range. */ - int mq_sub(int x, int y) + static int mq_sub(int x, int y) { /* * As in mq_add(), we use a conditional addition to ensure the @@ -358,7 +358,7 @@ int mq_sub(int x, int y) /* * Division by 2 modulo q. Operand must be in the 0..q-1 range. */ - int mq_rshift1(int x) + static int mq_rshift1(int x) { x += Q & -(x & 1); return (x >>> 1); @@ -369,7 +369,7 @@ int mq_rshift1(int x) * this function computes: x * y / R mod q * Operands must be in the 0..q-1 range. */ - int mq_montymul(int x, int y) + static int mq_montymul(int x, int y) { int z, w; @@ -404,7 +404,7 @@ int mq_montymul(int x, int y) /* * Montgomery squaring (computes (x^2)/R). */ - int mq_montysqr(int x) + static int mq_montysqr(int x) { return mq_montymul(x, x); } @@ -412,7 +412,7 @@ int mq_montysqr(int x) /* * Divide x by y modulo q = 12289. */ - int mq_div_12289(int x, int y) + static int mq_div_12289(int x, int y) { /* * We invert y by computing y^(q-2) mod q. @@ -477,7 +477,7 @@ int mq_div_12289(int x, int y) /* * Compute NTT on a ring element. */ - void mq_NTT(short[] srca, int a, int logn) + static void mq_NTT(short[] srca, int a, int logn) { int n, t, m; @@ -512,7 +512,7 @@ void mq_NTT(short[] srca, int a, int logn) /* * Compute the inverse NTT on a ring element, binary case. */ - void mq_iNTT(short[] srca, int a, int logn) + static void mq_iNTT(short[] srca, int a, int logn) { int n, t, m; int ni; @@ -571,7 +571,7 @@ void mq_iNTT(short[] srca, int a, int logn) /* * Convert a polynomial (mod q) to Montgomery representation. */ - void mq_poly_tomonty(short[] srcf, int f, int logn) + static void mq_poly_tomonty(short[] srcf, int f, int logn) { int u, n; @@ -586,7 +586,7 @@ void mq_poly_tomonty(short[] srcf, int f, int logn) * Multiply two polynomials together (NTT representation, and using * a Montgomery multiplication). Result f*g is written over f. */ - void mq_poly_montymul_ntt(short[] srcf, int f, short[] srcg, int g, int logn) + static void mq_poly_montymul_ntt(short[] srcf, int f, short[] srcg, int g, int logn) { int u, n; @@ -600,35 +600,35 @@ void mq_poly_montymul_ntt(short[] srcf, int f, short[] srcg, int g, int logn) /* * Subtract polynomial g from polynomial f. */ - void mq_poly_sub(short[] srcf, int f, short[] srcg, int g, int logn) + static void mq_poly_sub(short[] srcf, int f, short[] srcg, int logn) { int u, n; n = 1 << logn; for (u = 0; u < n; u++) { - srcf[f + u] = (short)mq_sub(srcf[f + u], srcg[g + u]); + srcf[f + u] = (short)mq_sub(srcf[f + u], srcg[u]); } } /* ===================================================================== */ /* see inner.h */ - void to_ntt_monty(short[] srch, int h, int logn) + static void to_ntt_monty(short[] srch, int logn) { - mq_NTT(srch, h, logn); - mq_poly_tomonty(srch, h, logn); + mq_NTT(srch, 0, logn); + mq_poly_tomonty(srch, 0, logn); } /* see inner.h */ - int verify_raw(short[] srcc0, int c0, short[] srcs2, int s2, - short[] srch, int h, int logn, short[] srctmp, int tmp) + static int verify_raw(short[] srcc0, short[] srcs2, + short[] srch, int logn, short[] srctmp) { int u, n; int tt; n = 1 << logn; - tt = tmp; + tt = 0; /* * Reduce s2 elements modulo q ([0..q-1] range). @@ -637,7 +637,7 @@ int verify_raw(short[] srcc0, int c0, short[] srcs2, int s2, { int w; - w = (int)srcs2[s2 + u]; // s2 is signed, so ( & 0xffff) is not needed + w = srcs2[u]; // s2 is signed, so ( & 0xffff) is not needed w += Q & -(w >>> 31); srctmp[tt + u] = (short)w; } @@ -646,9 +646,9 @@ int verify_raw(short[] srcc0, int c0, short[] srcs2, int s2, * Compute -s1 = s2*h - c0 mod phi mod q (in tt[]). */ mq_NTT(srctmp, tt, logn); - mq_poly_montymul_ntt(srctmp, tt, srch, h, logn); + mq_poly_montymul_ntt(srctmp, tt, srch, 0, logn); mq_iNTT(srctmp, tt, logn); - mq_poly_sub(srctmp, tt, srcc0, c0, logn); + mq_poly_sub(srctmp, tt, srcc0, logn); /* * Normalize -s1 elements into the [-q/2..q/2] range. @@ -666,12 +666,12 @@ int verify_raw(short[] srcc0, int c0, short[] srcs2, int s2, * Signature is valid if and only if the aggregate (-s1,s2) vector * is short enough. */ - return common.is_short(srctmp, tt, srcs2, s2, logn); + return FalconCommon.is_short(srctmp, tt, srcs2, logn); } /* see inner.h */ - int compute_public(short[] srch, int h, - byte[] srcf, int f, byte[] srcg, int g, int logn, short[] srctmp, int tmp) + static int compute_public(short[] srch, int h, + byte[] srcf, byte[] srcg, int logn, short[] srctmp, int tmp) { int u, n; int tt; @@ -680,8 +680,8 @@ int compute_public(short[] srch, int h, tt = tmp; for (u = 0; u < n; u++) { - srctmp[tt + u] = (short)mq_conv_small(srcf[f + u]); - srch[h + u] = (short)mq_conv_small(srcg[g + u]); + srctmp[tt + u] = (short)mq_conv_small(srcf[u]); + srch[h + u] = (short)mq_conv_small(srcg[u]); } mq_NTT(srch, h, logn); mq_NTT(srctmp, tt, logn); @@ -698,21 +698,21 @@ int compute_public(short[] srch, int h, } /* see inner.h */ - boolean complete_private(byte[] srcG, int G, - byte[] srcf, int f, byte[] srcg, int g, byte[] srcF, int F, - int logn, short[] srctmp, int tmp) + static boolean complete_private(byte[] srcG, + byte[] srcf, byte[] srcg, byte[] srcF, + int logn, short[] srctmp) { int success = -1; int u, n; int t1, t2; n = 1 << logn; - t1 = tmp; + t1 = 0; t2 = t1 + n; for (u = 0; u < n; u++) { - srctmp[t1 + u] = (short)mq_conv_small(srcg[g + u]); - srctmp[t2 + u] = (short)mq_conv_small(srcF[F + u]); + srctmp[t1 + u] = (short)mq_conv_small(srcg[u]); + srctmp[t2 + u] = (short)mq_conv_small(srcF[u]); } mq_NTT(srctmp, t1, logn); mq_NTT(srctmp, t2, logn); @@ -720,7 +720,7 @@ boolean complete_private(byte[] srcG, int G, mq_poly_montymul_ntt(srctmp, t1, srctmp, t2, logn); for (u = 0; u < n; u++) { - srctmp[t2 + u] = (short)mq_conv_small(srcf[f + u]); + srctmp[t2 + u] = (short)mq_conv_small(srcf[u]); } mq_NTT(srctmp, t2, logn); for (u = 0; u < n; u++) @@ -734,124 +734,124 @@ boolean complete_private(byte[] srcG, int G, { int w = srctmp[t1 + u] & 0xffff; int gi = w - (Q & (((Q >> 1) - w) >> 31)); - success &= +gi - 128; // check +gi < 128 + success &= gi - 128; // check +gi < 128 success &= -gi - 128; // check -gi < 128 - srcG[G + u] = (byte)gi; + srcG[u] = (byte)gi; } return success < 0; } /* see inner.h */ - int is_invertible(short[] srcs2, int s2, int logn, short[] srctmp, int tmp) - { - int u, n; - int tt; - int r; - - n = 1 << logn; - tt = tmp; - for (u = 0; u < n; u++) - { - int w; - - w = (int)srcs2[s2 + u]; // s2 is signed - w += Q & -(w >>> 31); - srctmp[tt + u] = (short)w; - } - mq_NTT(srctmp, tt, logn); - r = 0; - for (u = 0; u < n; u++) - { - r |= (srctmp[tt + u] & 0xffff) - 1; - } - return (1 - (r >>> 31)); - } +// int is_invertible(short[] srcs2, int s2, int logn, short[] srctmp, int tmp) +// { +// int u, n; +// int tt; +// int r; +// +// n = 1 << logn; +// tt = tmp; +// for (u = 0; u < n; u++) +// { +// int w; +// +// w = (int)srcs2[s2 + u]; // s2 is signed +// w += Q & -(w >>> 31); +// srctmp[tt + u] = (short)w; +// } +// mq_NTT(srctmp, tt, logn); +// r = 0; +// for (u = 0; u < n; u++) +// { +// r |= (srctmp[tt + u] & 0xffff) - 1; +// } +// return (1 - (r >>> 31)); +// } /* see inner.h */ - int verify_recover(short[] srch, int h, - short[] srcc0, int c0, short[] srcs1, int s1, short[] srcs2, int s2, - int logn, short[] srctmp, int tmp) - { - int u, n; - int tt; - int r; - - n = 1 << logn; - - /* - * Reduce elements of s1 and s2 modulo q; then write s2 into tt[] - * and c0 - s1 into h[]. - */ - tt = tmp; - for (u = 0; u < n; u++) - { - int w; - - w = (int)srcs2[s2 + u]; // s2 is signed - w += Q & -(w >> 31); - srctmp[tt + u] = (short)w; - - w = (int)srcs1[s1 + u]; // s2 is signed - w += Q & -(w >>> 31); - w = mq_sub((srcc0[c0 + u]), w & 0xffff); // c0 is unsigned - srch[h + u] = (short)w; - } - - /* - * Compute h = (c0 - s1) / s2. If one of the coefficients of s2 - * is zero (in NTT representation) then the operation fails. We - * keep that information into a flag so that we do not deviate - * from strict constant-time processing; if all coefficients of - * s2 are non-zero, then the high bit of r will be zero. - */ - mq_NTT(srctmp, tt, logn); - mq_NTT(srctmp, h, logn); - r = 0; - for (u = 0; u < n; u++) - { - r |= (srctmp[tt + u] & 0xffff) - 1; - srch[h + u] = (short)mq_div_12289((srch[h + u] & 0xffff), - (srctmp[tt + u]) & 0xffff); - } - mq_iNTT(srch, h, logn); - - /* - * Signature is acceptable if and only if it is short enough, - * and s2 was invertible mod phi mod q. The caller must still - * check that the rebuilt public key matches the expected - * value (e.g. through a hash). - */ - r = ~r & -common.is_short(srcs1, s1, srcs2, s2, logn); - return (int)(r >>> 31); - } +// int verify_recover(short[] srch, int h, +// short[] srcc0, int c0, short[] srcs1, int s1, short[] srcs2, int s2, +// int logn, short[] srctmp, int tmp) +// { +// int u, n; +// int tt; +// int r; +// +// n = 1 << logn; +// +// /* +// * Reduce elements of s1 and s2 modulo q; then write s2 into tt[] +// * and c0 - s1 into h[]. +// */ +// tt = tmp; +// for (u = 0; u < n; u++) +// { +// int w; +// +// w = (int)srcs2[s2 + u]; // s2 is signed +// w += Q & -(w >> 31); +// srctmp[tt + u] = (short)w; +// +// w = (int)srcs1[s1 + u]; // s2 is signed +// w += Q & -(w >>> 31); +// w = mq_sub((srcc0[c0 + u]), w & 0xffff); // c0 is unsigned +// srch[h + u] = (short)w; +// } +// +// /* +// * Compute h = (c0 - s1) / s2. If one of the coefficients of s2 +// * is zero (in NTT representation) then the operation fails. We +// * keep that information into a flag so that we do not deviate +// * from strict constant-time processing; if all coefficients of +// * s2 are non-zero, then the high bit of r will be zero. +// */ +// mq_NTT(srctmp, tt, logn); +// mq_NTT(srctmp, h, logn); +// r = 0; +// for (u = 0; u < n; u++) +// { +// r |= (srctmp[tt + u] & 0xffff) - 1; +// srch[h + u] = (short)mq_div_12289((srch[h + u] & 0xffff), +// (srctmp[tt + u]) & 0xffff); +// } +// mq_iNTT(srch, h, logn); +// +// /* +// * Signature is acceptable if and only if it is short enough, +// * and s2 was invertible mod phi mod q. The caller must still +// * check that the rebuilt public key matches the expected +// * value (e.g. through a hash). +// */ +// r = ~r & -FalconCommon.is_short(srcs1, s1, srcs2, s2, logn); +// return (int)(r >>> 31); +// } /* see inner.h */ - int count_nttzero(short[] srcsig, int sig, int logn, short[] srctmp, int tmp) - { - int s2; - int u, n; - int r; - - n = 1 << logn; - s2 = tmp; - for (u = 0; u < n; u++) - { - int w; - - w = (int)srcsig[sig + u]; // sig is signed - w += Q & -(w >>> 31); - srctmp[s2 + u] = (short)w; - } - mq_NTT(srctmp, s2, logn); - r = 0; - for (u = 0; u < n; u++) - { - int w; - - w = (srctmp[s2 + u] & 0xffff) - 1; // s2 is unsigned - r += (w >>> 31); - } - return (int)r; - } +// int count_nttzero(short[] srcsig, int sig, int logn, short[] srctmp, int tmp) +// { +// int s2; +// int u, n; +// int r; +// +// n = 1 << logn; +// s2 = tmp; +// for (u = 0; u < n; u++) +// { +// int w; +// +// w = (int)srcsig[sig + u]; // sig is signed +// w += Q & -(w >>> 31); +// srctmp[s2 + u] = (short)w; +// } +// mq_NTT(srctmp, s2, logn); +// r = 0; +// for (u = 0; u < n; u++) +// { +// int w; +// +// w = (srctmp[s2 + u] & 0xffff) - 1; // s2 is unsigned +// r += (w >>> 31); +// } +// return (int)r; +// } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/SHAKE256.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/SHAKE256.java deleted file mode 100644 index eae8ee6133..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/SHAKE256.java +++ /dev/null @@ -1,562 +0,0 @@ -package org.bouncycastle.pqc.crypto.falcon; - -class SHAKE256 -{ - long[] A; - byte[] dbuf; - long dptr; - - SHAKE256() - { - this.A = new long[25]; - this.dbuf = new byte[200]; - this.dptr = 0; - } - - /* - * Round constants. - */ - private long RC[] = { - 0x0000000000000001l, 0x0000000000008082l, - 0x800000000000808Al, 0x8000000080008000l, - 0x000000000000808Bl, 0x0000000080000001l, - 0x8000000080008081l, 0x8000000000008009l, - 0x000000000000008Al, 0x0000000000000088l, - 0x0000000080008009l, 0x000000008000000Al, - 0x000000008000808Bl, 0x800000000000008Bl, - 0x8000000000008089l, 0x8000000000008003l, - 0x8000000000008002l, 0x8000000000000080l, - 0x000000000000800Al, 0x800000008000000Al, - 0x8000000080008081l, 0x8000000000008080l, - 0x0000000080000001l, 0x8000000080008008l - }; - - /* - * Process the provided state. - */ - void process_block(long[] A) - { - long t0, t1, t2, t3, t4; - long tt0, tt1, tt2, tt3; - long t, kt; - long c0, c1, c2, c3, c4, bnn; - int j; - - /* - * Invert some words (alternate internal representation, which - * saves some operations). - */ - A[1] = ~A[1]; - A[2] = ~A[2]; - A[8] = ~A[8]; - A[12] = ~A[12]; - A[17] = ~A[17]; - A[20] = ~A[20]; - - /* - * Compute the 24 rounds. This loop is partially unrolled (each - * iteration computes two rounds). - */ - for (j = 0; j < 24; j += 2) - { - - tt0 = A[1] ^ A[6]; - tt1 = A[11] ^ A[16]; - tt0 ^= A[21] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[4] ^ A[9]; - tt3 = A[14] ^ A[19]; - tt0 ^= A[24]; - tt2 ^= tt3; - t0 = tt0 ^ tt2; - - tt0 = A[2] ^ A[7]; - tt1 = A[12] ^ A[17]; - tt0 ^= A[22] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[0] ^ A[5]; - tt3 = A[10] ^ A[15]; - tt0 ^= A[20]; - tt2 ^= tt3; - t1 = tt0 ^ tt2; - - tt0 = A[3] ^ A[8]; - tt1 = A[13] ^ A[18]; - tt0 ^= A[23] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[1] ^ A[6]; - tt3 = A[11] ^ A[16]; - tt0 ^= A[21]; - tt2 ^= tt3; - t2 = tt0 ^ tt2; - - tt0 = A[4] ^ A[9]; - tt1 = A[14] ^ A[19]; - tt0 ^= A[24] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[2] ^ A[7]; - tt3 = A[12] ^ A[17]; - tt0 ^= A[22]; - tt2 ^= tt3; - t3 = tt0 ^ tt2; - - tt0 = A[0] ^ A[5]; - tt1 = A[10] ^ A[15]; - tt0 ^= A[20] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[3] ^ A[8]; - tt3 = A[13] ^ A[18]; - tt0 ^= A[23]; - tt2 ^= tt3; - t4 = tt0 ^ tt2; - - A[0] = A[0] ^ t0; - A[5] = A[5] ^ t0; - A[10] = A[10] ^ t0; - A[15] = A[15] ^ t0; - A[20] = A[20] ^ t0; - A[1] = A[1] ^ t1; - A[6] = A[6] ^ t1; - A[11] = A[11] ^ t1; - A[16] = A[16] ^ t1; - A[21] = A[21] ^ t1; - A[2] = A[2] ^ t2; - A[7] = A[7] ^ t2; - A[12] = A[12] ^ t2; - A[17] = A[17] ^ t2; - A[22] = A[22] ^ t2; - A[3] = A[3] ^ t3; - A[8] = A[8] ^ t3; - A[13] = A[13] ^ t3; - A[18] = A[18] ^ t3; - A[23] = A[23] ^ t3; - A[4] = A[4] ^ t4; - A[9] = A[9] ^ t4; - A[14] = A[14] ^ t4; - A[19] = A[19] ^ t4; - A[24] = A[24] ^ t4; - A[5] = (A[5] << 36) | (A[5] >>> (64 - 36)); - A[10] = (A[10] << 3) | (A[10] >>> (64 - 3)); - A[15] = (A[15] << 41) | (A[15] >>> (64 - 41)); - A[20] = (A[20] << 18) | (A[20] >>> (64 - 18)); - A[1] = (A[1] << 1) | (A[1] >>> (64 - 1)); - A[6] = (A[6] << 44) | (A[6] >>> (64 - 44)); - A[11] = (A[11] << 10) | (A[11] >>> (64 - 10)); - A[16] = (A[16] << 45) | (A[16] >>> (64 - 45)); - A[21] = (A[21] << 2) | (A[21] >>> (64 - 2)); - A[2] = (A[2] << 62) | (A[2] >>> (64 - 62)); - A[7] = (A[7] << 6) | (A[7] >>> (64 - 6)); - A[12] = (A[12] << 43) | (A[12] >>> (64 - 43)); - A[17] = (A[17] << 15) | (A[17] >>> (64 - 15)); - A[22] = (A[22] << 61) | (A[22] >>> (64 - 61)); - A[3] = (A[3] << 28) | (A[3] >>> (64 - 28)); - A[8] = (A[8] << 55) | (A[8] >>> (64 - 55)); - A[13] = (A[13] << 25) | (A[13] >>> (64 - 25)); - A[18] = (A[18] << 21) | (A[18] >>> (64 - 21)); - A[23] = (A[23] << 56) | (A[23] >>> (64 - 56)); - A[4] = (A[4] << 27) | (A[4] >>> (64 - 27)); - A[9] = (A[9] << 20) | (A[9] >>> (64 - 20)); - A[14] = (A[14] << 39) | (A[14] >>> (64 - 39)); - A[19] = (A[19] << 8) | (A[19] >>> (64 - 8)); - A[24] = (A[24] << 14) | (A[24] >>> (64 - 14)); - - bnn = ~A[12]; - kt = A[6] | A[12]; - c0 = A[0] ^ kt; - kt = bnn | A[18]; - c1 = A[6] ^ kt; - kt = A[18] & A[24]; - c2 = A[12] ^ kt; - kt = A[24] | A[0]; - c3 = A[18] ^ kt; - kt = A[0] & A[6]; - c4 = A[24] ^ kt; - A[0] = c0; - A[6] = c1; - A[12] = c2; - A[18] = c3; - A[24] = c4; - bnn = ~A[22]; - kt = A[9] | A[10]; - c0 = A[3] ^ kt; - kt = A[10] & A[16]; - c1 = A[9] ^ kt; - kt = A[16] | bnn; - c2 = A[10] ^ kt; - kt = A[22] | A[3]; - c3 = A[16] ^ kt; - kt = A[3] & A[9]; - c4 = A[22] ^ kt; - A[3] = c0; - A[9] = c1; - A[10] = c2; - A[16] = c3; - A[22] = c4; - bnn = ~A[19]; - kt = A[7] | A[13]; - c0 = A[1] ^ kt; - kt = A[13] & A[19]; - c1 = A[7] ^ kt; - kt = bnn & A[20]; - c2 = A[13] ^ kt; - kt = A[20] | A[1]; - c3 = bnn ^ kt; - kt = A[1] & A[7]; - c4 = A[20] ^ kt; - A[1] = c0; - A[7] = c1; - A[13] = c2; - A[19] = c3; - A[20] = c4; - bnn = ~A[17]; - kt = A[5] & A[11]; - c0 = A[4] ^ kt; - kt = A[11] | A[17]; - c1 = A[5] ^ kt; - kt = bnn | A[23]; - c2 = A[11] ^ kt; - kt = A[23] & A[4]; - c3 = bnn ^ kt; - kt = A[4] | A[5]; - c4 = A[23] ^ kt; - A[4] = c0; - A[5] = c1; - A[11] = c2; - A[17] = c3; - A[23] = c4; - bnn = ~A[8]; - kt = bnn & A[14]; - c0 = A[2] ^ kt; - kt = A[14] | A[15]; - c1 = bnn ^ kt; - kt = A[15] & A[21]; - c2 = A[14] ^ kt; - kt = A[21] | A[2]; - c3 = A[15] ^ kt; - kt = A[2] & A[8]; - c4 = A[21] ^ kt; - A[2] = c0; - A[8] = c1; - A[14] = c2; - A[15] = c3; - A[21] = c4; - A[0] = A[0] ^ RC[j + 0]; - - tt0 = A[6] ^ A[9]; - tt1 = A[7] ^ A[5]; - tt0 ^= A[8] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[24] ^ A[22]; - tt3 = A[20] ^ A[23]; - tt0 ^= A[21]; - tt2 ^= tt3; - t0 = tt0 ^ tt2; - - tt0 = A[12] ^ A[10]; - tt1 = A[13] ^ A[11]; - tt0 ^= A[14] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[0] ^ A[3]; - tt3 = A[1] ^ A[4]; - tt0 ^= A[2]; - tt2 ^= tt3; - t1 = tt0 ^ tt2; - - tt0 = A[18] ^ A[16]; - tt1 = A[19] ^ A[17]; - tt0 ^= A[15] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[6] ^ A[9]; - tt3 = A[7] ^ A[5]; - tt0 ^= A[8]; - tt2 ^= tt3; - t2 = tt0 ^ tt2; - - tt0 = A[24] ^ A[22]; - tt1 = A[20] ^ A[23]; - tt0 ^= A[21] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[12] ^ A[10]; - tt3 = A[13] ^ A[11]; - tt0 ^= A[14]; - tt2 ^= tt3; - t3 = tt0 ^ tt2; - - tt0 = A[0] ^ A[3]; - tt1 = A[1] ^ A[4]; - tt0 ^= A[2] ^ tt1; - tt0 = (tt0 << 1) | (tt0 >>> 63); - tt2 = A[18] ^ A[16]; - tt3 = A[19] ^ A[17]; - tt0 ^= A[15]; - tt2 ^= tt3; - t4 = tt0 ^ tt2; - - A[0] = A[0] ^ t0; - A[3] = A[3] ^ t0; - A[1] = A[1] ^ t0; - A[4] = A[4] ^ t0; - A[2] = A[2] ^ t0; - A[6] = A[6] ^ t1; - A[9] = A[9] ^ t1; - A[7] = A[7] ^ t1; - A[5] = A[5] ^ t1; - A[8] = A[8] ^ t1; - A[12] = A[12] ^ t2; - A[10] = A[10] ^ t2; - A[13] = A[13] ^ t2; - A[11] = A[11] ^ t2; - A[14] = A[14] ^ t2; - A[18] = A[18] ^ t3; - A[16] = A[16] ^ t3; - A[19] = A[19] ^ t3; - A[17] = A[17] ^ t3; - A[15] = A[15] ^ t3; - A[24] = A[24] ^ t4; - A[22] = A[22] ^ t4; - A[20] = A[20] ^ t4; - A[23] = A[23] ^ t4; - A[21] = A[21] ^ t4; - A[3] = (A[3] << 36) | (A[3] >>> (64 - 36)); - A[1] = (A[1] << 3) | (A[1] >>> (64 - 3)); - A[4] = (A[4] << 41) | (A[4] >>> (64 - 41)); - A[2] = (A[2] << 18) | (A[2] >>> (64 - 18)); - A[6] = (A[6] << 1) | (A[6] >>> (64 - 1)); - A[9] = (A[9] << 44) | (A[9] >>> (64 - 44)); - A[7] = (A[7] << 10) | (A[7] >>> (64 - 10)); - A[5] = (A[5] << 45) | (A[5] >>> (64 - 45)); - A[8] = (A[8] << 2) | (A[8] >>> (64 - 2)); - A[12] = (A[12] << 62) | (A[12] >>> (64 - 62)); - A[10] = (A[10] << 6) | (A[10] >>> (64 - 6)); - A[13] = (A[13] << 43) | (A[13] >>> (64 - 43)); - A[11] = (A[11] << 15) | (A[11] >>> (64 - 15)); - A[14] = (A[14] << 61) | (A[14] >>> (64 - 61)); - A[18] = (A[18] << 28) | (A[18] >>> (64 - 28)); - A[16] = (A[16] << 55) | (A[16] >>> (64 - 55)); - A[19] = (A[19] << 25) | (A[19] >>> (64 - 25)); - A[17] = (A[17] << 21) | (A[17] >>> (64 - 21)); - A[15] = (A[15] << 56) | (A[15] >>> (64 - 56)); - A[24] = (A[24] << 27) | (A[24] >>> (64 - 27)); - A[22] = (A[22] << 20) | (A[22] >>> (64 - 20)); - A[20] = (A[20] << 39) | (A[20] >>> (64 - 39)); - A[23] = (A[23] << 8) | (A[23] >>> (64 - 8)); - A[21] = (A[21] << 14) | (A[21] >>> (64 - 14)); - - bnn = ~A[13]; - kt = A[9] | A[13]; - c0 = A[0] ^ kt; - kt = bnn | A[17]; - c1 = A[9] ^ kt; - kt = A[17] & A[21]; - c2 = A[13] ^ kt; - kt = A[21] | A[0]; - c3 = A[17] ^ kt; - kt = A[0] & A[9]; - c4 = A[21] ^ kt; - A[0] = c0; - A[9] = c1; - A[13] = c2; - A[17] = c3; - A[21] = c4; - bnn = ~A[14]; - kt = A[22] | A[1]; - c0 = A[18] ^ kt; - kt = A[1] & A[5]; - c1 = A[22] ^ kt; - kt = A[5] | bnn; - c2 = A[1] ^ kt; - kt = A[14] | A[18]; - c3 = A[5] ^ kt; - kt = A[18] & A[22]; - c4 = A[14] ^ kt; - A[18] = c0; - A[22] = c1; - A[1] = c2; - A[5] = c3; - A[14] = c4; - bnn = ~A[23]; - kt = A[10] | A[19]; - c0 = A[6] ^ kt; - kt = A[19] & A[23]; - c1 = A[10] ^ kt; - kt = bnn & A[2]; - c2 = A[19] ^ kt; - kt = A[2] | A[6]; - c3 = bnn ^ kt; - kt = A[6] & A[10]; - c4 = A[2] ^ kt; - A[6] = c0; - A[10] = c1; - A[19] = c2; - A[23] = c3; - A[2] = c4; - bnn = ~A[11]; - kt = A[3] & A[7]; - c0 = A[24] ^ kt; - kt = A[7] | A[11]; - c1 = A[3] ^ kt; - kt = bnn | A[15]; - c2 = A[7] ^ kt; - kt = A[15] & A[24]; - c3 = bnn ^ kt; - kt = A[24] | A[3]; - c4 = A[15] ^ kt; - A[24] = c0; - A[3] = c1; - A[7] = c2; - A[11] = c3; - A[15] = c4; - bnn = ~A[16]; - kt = bnn & A[20]; - c0 = A[12] ^ kt; - kt = A[20] | A[4]; - c1 = bnn ^ kt; - kt = A[4] & A[8]; - c2 = A[20] ^ kt; - kt = A[8] | A[12]; - c3 = A[4] ^ kt; - kt = A[12] & A[16]; - c4 = A[8] ^ kt; - A[12] = c0; - A[16] = c1; - A[20] = c2; - A[4] = c3; - A[8] = c4; - A[0] = A[0] ^ RC[j + 1]; - t = A[5]; - A[5] = A[18]; - A[18] = A[11]; - A[11] = A[10]; - A[10] = A[6]; - A[6] = A[22]; - A[22] = A[20]; - A[20] = A[12]; - A[12] = A[19]; - A[19] = A[15]; - A[15] = A[24]; - A[24] = A[8]; - A[8] = t; - t = A[1]; - A[1] = A[9]; - A[9] = A[14]; - A[14] = A[2]; - A[2] = A[13]; - A[13] = A[23]; - A[23] = A[4]; - A[4] = A[21]; - A[21] = A[16]; - A[16] = A[3]; - A[3] = A[17]; - A[17] = A[7]; - A[7] = t; - } - - /* - * Invert some words back to normal representation. - */ - A[1] = ~A[1]; - A[2] = ~A[2]; - A[8] = ~A[8]; - A[12] = ~A[12]; - A[17] = ~A[17]; - A[20] = ~A[20]; - } - - - /* see inner.h */ - void inner_shake256_init() - { - this.dptr = 0; - - /* - * Representation of an all-ones uint64_t is the same regardless - * of local endianness. - */ - for (int i = 0; i < this.A.length; i++) - { - this.A[i] = 0; - } - } - - /* see inner.h */ - void inner_shake256_inject(byte[] srcin, int in, int len) - { - long dptr; - - dptr = this.dptr; - while (len > 0) - { - long clen, u; - - clen = 136 - dptr; - if (clen > len) - { - clen = len; - } - for (u = 0; u < clen; u++) - { - long v; - - v = u + dptr; - this.A[(int)(v >> 3)] ^=(srcin[in + (int)u] & 0xffL) << ((v & 7) << 3); - } - dptr += clen; - in += clen; - len -= clen; - if (dptr == 136) - { - process_block(this.A); - dptr = 0; - } - } - this.dptr = dptr; - } - - /* see falcon.h */ - void i_shake256_flip() - { - /* - * We apply padding and pre-XOR the value into the state. We - * set dptr to the end of the buffer, so that first call to - * shake_extract() will process the block. - */ - int v; - - v = (int)this.dptr; - this.A[v >> 3] ^= (0x1FL) << ((v & 7) << 3); - this.A[16] ^= (0x80L) << 56; - this.dptr = 136; - } - - /* see falcon.h */ - void inner_shake256_extract(byte[] srcout, int out, int len) - { - int dptr; - int o = out; - - dptr = (int)this.dptr; - while (len > 0) - { - int clen; - - if (dptr == 136) - { - process_block(this.A); - dptr = 0; - } - clen = 136 - dptr; - if (clen > len) - { - clen = len; - } - len -= clen; - while (clen-- > 0) - { - srcout[o++] = (byte)(this.A[dptr >> 3] >>> ((dptr & 7) << 3)); - dptr++; - } - } - this.dptr = dptr; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/SamplerCtx.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/SamplerCtx.java index 351878f0ba..104c258c4d 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/SamplerCtx.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/SamplerCtx.java @@ -3,12 +3,12 @@ class SamplerCtx { - FalconFPR sigma_min; + double sigma_min; FalconRNG p; SamplerCtx() { - this.sigma_min = new FalconFPR(0.0); + this.sigma_min = 0.0; this.p = new FalconRNG(); } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/SamplerZ.java b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/SamplerZ.java index bde395f3fc..32e066ccd2 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/SamplerZ.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/falcon/SamplerZ.java @@ -3,14 +3,14 @@ class SamplerZ { - FPREngine fpr; + //FPREngine fpr; - SamplerZ() - { - this.fpr = new FPREngine(); - } +// SamplerZ() +// { +// //this.fpr = new FPREngine(); +// } - int sample(SamplerCtx ctx, FalconFPR mu, FalconFPR iSigma) + static int sample(SamplerCtx ctx, double mu, double iSigma) { return sampler(ctx, mu, iSigma); } @@ -19,7 +19,7 @@ int sample(SamplerCtx ctx, FalconFPR mu, FalconFPR iSigma) * Sample an integer value along a half-gaussian distribution centered * on zero and standard deviation 1.8205, with a precision of 72 bits. */ - int gaussian0_sampler(FalconRNG p) + static int gaussian0_sampler(FalconRNG p) { int[] dist = { @@ -68,11 +68,11 @@ int gaussian0_sampler(FalconRNG p) w0 = dist[u + 2]; w1 = dist[u + 1]; - w2 = dist[u + 0]; + w2 = dist[u]; cc = (v0 - w0) >>> 31; cc = (v1 - w1 - cc) >>> 31; cc = (v2 - w2 - cc) >>> 31; - z += (int)cc; + z += cc; } return z; @@ -81,10 +81,10 @@ int gaussian0_sampler(FalconRNG p) /* * Sample a bit with probability exp(-x) for some x >= 0. */ - int BerExp(FalconRNG p, FalconFPR x, FalconFPR ccs) + private static int BerExp(FalconRNG p, double x, double ccs) { int s, i; - FalconFPR r; + double r; int sw, w; long z; @@ -92,8 +92,8 @@ int BerExp(FalconRNG p, FalconFPR x, FalconFPR ccs) * Reduce x modulo log(2): x = s*log(2) + r, with s an integer, * and 0 <= r < log(2). Since x >= 0, we can use fpr_trunc(). */ - s = (int)fpr.fpr_trunc(fpr.fpr_mul(x, fpr.fpr_inv_log2)); - r = fpr.fpr_sub(x, fpr.fpr_mul(fpr.fpr_of(s), fpr.fpr_log2)); + s = (int)(x * FPREngine.fpr_inv_log2);//(int)fpr.fpr_trunc(fpr.fpr_mul(x, fpr.fpr_inv_log2)); + r = x - s * FPREngine.fpr_log2; /* * It may happen (quite rarely) that s >= 64; if sigma = 1.2 @@ -119,7 +119,7 @@ int BerExp(FalconRNG p, FalconFPR x, FalconFPR ccs) * case). The bias is negligible since fpr_expm_p63() only computes * with 51 bits of precision or so. */ - z = ((fpr.fpr_expm_p63(r, ccs) << 1) - 1) >>> s; + z = ((FPREngine.fpr_expm_p63(r, ccs) << 1) - 1) >>> s; /* * Sample a bit with probability exp(-x). Since x = s*log(2) + r, @@ -145,11 +145,11 @@ int BerExp(FalconRNG p, FalconFPR x, FalconFPR ccs) * The value of sigma MUST lie between 1 and 2 (i.e. isigma lies between * 0.5 and 1); in Falcon, sigma should always be between 1.2 and 1.9. */ - int sampler(SamplerCtx ctx, FalconFPR mu, FalconFPR isigma) + private static int sampler(SamplerCtx ctx, double mu, double isigma) { SamplerCtx spc; int s; - FalconFPR r, dss, ccs; + double r, dss, ccs; spc = ctx; @@ -157,18 +157,18 @@ int sampler(SamplerCtx ctx, FalconFPR mu, FalconFPR isigma) * Center is mu. We compute mu = s + r where s is an integer * and 0 <= r < 1. */ - s = (int)fpr.fpr_floor(mu); - r = fpr.fpr_sub(mu, fpr.fpr_of(s)); + s = (int)FPREngine.fpr_floor(mu); + r = mu - s; /* * dss = 1/(2*sigma^2) = 0.5*(isigma^2). */ - dss = fpr.fpr_half(fpr.fpr_sqr(isigma)); + dss = isigma * isigma * 0.5; /* * ccs = sigma_min / sigma = sigma_min * isigma. */ - ccs = fpr.fpr_mul(isigma, spc.sigma_min); + ccs = isigma * spc.sigma_min; /* * We now need to sample on center r. @@ -176,7 +176,7 @@ int sampler(SamplerCtx ctx, FalconFPR mu, FalconFPR isigma) for (; ; ) { int z0, z, b; - FalconFPR x; + double x; /* * Sample z for a Gaussian distribution. Then get a @@ -218,8 +218,9 @@ int sampler(SamplerCtx ctx, FalconFPR mu, FalconFPR isigma) * center and standard deviation that the whole sampler * can be said to be constant-time. */ - x = fpr.fpr_mul(fpr.fpr_sqr(fpr.fpr_sub(fpr.fpr_of(z), r)), dss); - x = fpr.fpr_sub(x, fpr.fpr_mul(fpr.fpr_of(z0 * z0), fpr.fpr_inv_2sqrsigma0)); + x = z - r; + x = x * x * dss; + x -= (double)(z0 * z0) * FPREngine.fpr_inv_2sqrsigma0; if (BerExp(spc.p, x, ccs) != 0) { /* diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSEngine.java deleted file mode 100644 index c0dec946d5..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSEngine.java +++ /dev/null @@ -1,3222 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -import java.math.BigInteger; -import java.security.SecureRandom; - -import org.bouncycastle.crypto.digests.SHA3Digest; -import org.bouncycastle.crypto.digests.SHAKEDigest; -import org.bouncycastle.util.Pack; - -class GeMSSEngine -{ - private SecureRandom random; - final int HFEn;// {174, 175, 177, 178, 265, 266, 268, 270, 271, 354, 358, 364, 366, 402, 537, 544} - final int HFEv;// {11, 12, 13, 14, 15, 18, 20, 21, 22, 23, 24, 25, 26, 29, 32, 33, 35} - final int HFEDELTA;// {10, 12, 13, 15, 18, 21, 22, 24, 25, 29, 30, 32, 33, 34, 35} - final int NB_ITE;//{1, 3, 4} - final int HFEDeg;// {17, 129, 513, 640, 1152} - //Pair of HFEDegI and HFEDegJ:{(9, 0), (7,0), (4,0), (9, 7), (10, 7)} - final int HFEDegI;// {4, 7, 9, 10} - final int HFEDegJ;// {7, 0} - final int HFEnv;//{186, 187, 189, 190, 192, 193, 277, 285, 288, 289, 291, 292, 295, 387, 390, 393, 396, 399, 420, 563, 576} - final int HFEm;//{162, 163, 243, 253, 256, 257, 324, 333, 384, 512} - final int NB_BITS_UINT = 64; - final int HFEnq; - final int HFEnr;//{9, 10, 12, 14, 15, 18, 24, 25, 32, 38, 44, 46, 47, 49, 50,} - int HFE_odd_degree; - int NB_WORD_GFqn;//{3, 5, 6, 7, 9} - int NB_WORD_GF2nv; - int NB_MONOMIAL_VINEGAR; - int NB_MONOMIAL_PK; - final int HFEnvq; - final int HFEnvr;//{0, 1, 3, 6, 9, 12, 15, 21, 29, 32, 35, 36, 39, 51, 58, 59, 61, 62} - int LTRIANGULAR_NV_SIZE; - final int LTRIANGULAR_N_SIZE; - final int SIZE_SEED_SK; - final int NB_WORD_MUL;//{6, 9, 12, 13, 17} - int NB_WORD_MMUL;//{6, 9, 12, 13, 17} - int MQv_GFqn_SIZE; - final boolean ENABLED_REMOVE_ODD_DEGREE; - final int MATRIXnv_SIZE; - /* Number of UINT of matrix m*m in GF(2) */ - final int HFEmq; - final int HFEmr;//{0, 4, 13, 34, 35, 51, 55} - int NB_WORD_GF2m; - final int HFEvq; - final int HFEvr; - final int NB_WORD_GFqv; - final int HFEmq8;//{20, 30, 32, 40, 41, 48, 64} - final int HFEmr8; //{0, 2, 3, 4, 5, 7} - final int NB_BYTES_GFqm; - final int ACCESS_last_equations8; - final int NB_BYTES_EQUATION; - final int HFENr8; - final int NB_WORD_UNCOMP_EQ; - final int HFENr8c; - final int LOST_BITS; - final int NB_WORD_GF2nvm; - final int SIZE_SIGN_UNCOMPRESSED; - final int SIZE_DIGEST; - final int SIZE_DIGEST_UINT; - final int HFEnvr8; - final int NB_BYTES_GFqnv; - final int VAL_BITS_M; - final long MASK_GF2m; - final int LEN_UNROLLED_64 = 4; - int NB_COEFS_HFEPOLY; - int NB_UINT_HFEVPOLY; - final int MATRIXn_SIZE; - final long MASK_GF2n; - final int NB_BYTES_GFqn; - private int buffer; - final int SIZE_ROW; - final int ShakeBitStrength; - final int Sha3BitStrength; - SHA3Digest sha3Digest; - final int MLv_GFqn_SIZE; - int II; - int POW_II; - int KP; - int KX; - int HFEn_1rightmost; - /* Search the position of the MSB of n-1 */ - int HFEn1h_rightmost; - Mul_GF2x mul; - Rem_GF2n rem; - Pointer Buffer_NB_WORD_MUL; - Pointer Buffer_NB_WORD_GFqn; - - public GeMSSEngine(int K, int HFEn, int HFEv, int HFEDELTA, int NB_ITE, int HFEDeg, int HFEDegI, int HFEDegJ) - { - this.HFEn = HFEn; - this.HFEv = HFEv; - this.HFEDELTA = HFEDELTA; - this.NB_ITE = NB_ITE; - this.HFEDeg = HFEDeg; - this.HFEDegI = HFEDegI; - this.HFEDegJ = HFEDegJ; - NB_BYTES_GFqn = (HFEn >>> 3) + (((HFEn & 7) != 0) ? 1 : 0); - SIZE_ROW = HFEDegI + 1; - HFEnv = HFEn + HFEv; - HFEnq = HFEn >>> 6; - HFEnr = HFEn & 63; - HFEnvq = HFEnv >>> 6; - HFEnvr = HFEnv & 63; - SIZE_SEED_SK = K >>> 3; - NB_WORD_MUL = ((((HFEn - 1) << 1) >>> 6) + 1); - switch (NB_WORD_MUL) - { - case 6: //gemss128, bluegemss128, redgemss128, whitegemss128, cyangemss128, magentagemss128 - mul = new Mul_GF2x.Mul6(); - break; - case 9: //gemss192, bluegemss192, redgemss192, whitegemss192, cyangemss192, magentagemss192, fgemss128, dualmodems128 - mul = new Mul_GF2x.Mul9(); - break; - case 12: //gemss256, bluegemss256, redgemss256, whitegemss256, cyangemss256, magentagemss256 - mul = new Mul_GF2x.Mul12(); - break; - case 13: //fgemss192, dualmodems192 - mul = new Mul_GF2x.Mul13(); - break; - case 17: //fgemss256, dualmodems256 - mul = new Mul_GF2x.Mul17(); - break; - } - int KI = HFEn & 63; - int KI64 = 64 - KI; - HFEm = HFEn - HFEDELTA; - HFEmq = HFEm >>> 6; - HFEmr = HFEm & 63; - HFEvq = HFEv >>> 6; - HFEvr = HFEv & 63; - NB_WORD_GFqv = HFEvr != 0 ? HFEvq + 1 : HFEvq; - HFEmq8 = HFEm >>> 3; - HFEmr8 = HFEm & 7; - NB_BYTES_GFqm = HFEmq8 + (HFEmr8 != 0 ? 1 : 0); - NB_WORD_UNCOMP_EQ = ((((HFEnvq * (HFEnvq + 1)) >>> 1) * NB_BITS_UINT) + (HFEnvq + 1) * HFEnvr); - HFEnvr8 = HFEnv & 7; - NB_BYTES_GFqnv = (HFEnv >>> 3) + ((HFEnvr8 != 0) ? 1 : 0); - VAL_BITS_M = Math.min(HFEDELTA + HFEv, 8 - HFEmr8); - MASK_GF2m = GeMSSUtils.maskUINT(HFEmr); - MASK_GF2n = GeMSSUtils.maskUINT(HFEnr); - NB_WORD_GFqn = HFEnq + (HFEnr != 0 ? 1 : 0); - /* To choose macro for NB_WORD_GFqn*64 bits */ - LTRIANGULAR_N_SIZE = (((HFEnq * (HFEnq + 1)) >>> 1) * NB_BITS_UINT + NB_WORD_GFqn * HFEnr); - MATRIXn_SIZE = HFEn * NB_WORD_GFqn; - NB_WORD_GF2nv = HFEnvq + (HFEnvr != 0 ? 1 : 0); - MATRIXnv_SIZE = HFEnv * NB_WORD_GF2nv; - LTRIANGULAR_NV_SIZE = (((HFEnvq * (HFEnvq + 1)) >>> 1) * NB_BITS_UINT + NB_WORD_GF2nv * HFEnvr); - NB_MONOMIAL_VINEGAR = (((HFEv * (HFEv + 1)) >>> 1) + 1); - NB_MONOMIAL_PK = (((HFEnv * (HFEnv + 1)) >>> 1) + 1); - MQv_GFqn_SIZE = NB_MONOMIAL_VINEGAR * NB_WORD_GFqn; - ACCESS_last_equations8 = NB_MONOMIAL_PK * HFEmq8; - NB_BYTES_EQUATION = (NB_MONOMIAL_PK + 7) >>> 3; - HFENr8 = NB_MONOMIAL_PK & 7; - HFENr8c = ((8 - HFENr8) & 7); - LOST_BITS = (HFEmr8 - 1) * HFENr8c; - NB_WORD_MMUL = ((((HFEn - 1) << 1) >>> 6) + 1); - int K1 = 0, K2 = 0, K3, K164 = 0, K264 = 0, K364; - switch (HFEn) - { - case 174://gemss128 - K3 = 13; - break; - case 175://bluegemss128, whitegemss128 - K3 = 16; - break; - case 177://redgemss128, cyangemss128 - K3 = 8; - break; - case 178://magentagemss128 - K3 = 31; - break; - case 265://gemss192, bluegemss192 - K3 = 42; - break; - case 266://redgemss192,fgemss128,dualmodems128 - K3 = 47; - break; - case 268://whitegemss192 - K3 = 25; - break; - case 270://cyangemss192 - K3 = 53; - break; - case 271://magentagemss192 - K3 = 58; - break; - case 354://gemss256 - K3 = 99; - break; - case 358://redgemss256, bluegemss256 - K3 = 57; - break; - case 364://whitegemss256, cyangemss256 - K3 = 9; - break; - case 366://magentagemss256 - K3 = 29; - break; - case 402://fgemss192,dualmodems192 - K3 = 171; - break; - case 537://fgemss256 - K3 = 10; - K2 = 2; - K1 = 1; - break; - case 544://dualmodems256 - K3 = 128; - K2 = 3; - K1 = 1; - break; - default: - throw new IllegalArgumentException("error: need to add support for HFEn=" + HFEn); - } - if (K2 != 0) - { - /* Choice of pentanomial for modular reduction in GF(2^n) */ - K164 = 64 - K1; - K264 = 64 - K2; - } - K364 = 64 - (K3 & 63); - if ((HFEDeg & 1) == 0) - { - // Set to 1 to remove terms which have an odd degree strictly greater than HFE_odd_degree - ENABLED_REMOVE_ODD_DEGREE = true; - /* HFE_odd_degree = 1 + 2^LOG_odd_degree */ - HFE_odd_degree = ((1 << HFEDegI) + 1); - if ((HFEDeg & 1) != 0) - { - throw new IllegalArgumentException("HFEDeg is odd, so to remove the leading term would decrease the degree."); - } - if (HFE_odd_degree > HFEDeg) - { - throw new IllegalArgumentException("It is useless to remove 0 term."); - } - if (HFE_odd_degree <= 1) - { - throw new IllegalArgumentException("The case where the term X^3 is removing is not implemented."); - } - NB_COEFS_HFEPOLY = (2 + HFEDegJ + ((HFEDegI * (HFEDegI - 1)) >>> 1) + HFEDegI); - } - else - { - ENABLED_REMOVE_ODD_DEGREE = false; - NB_COEFS_HFEPOLY = (2 + HFEDegJ + ((HFEDegI * (HFEDegI + 1)) >>> 1)); - } - NB_WORD_GF2m = HFEmq + (HFEmr != 0 ? 1 : 0); - NB_WORD_GF2nvm = NB_WORD_GF2nv - NB_WORD_GF2m + (HFEmr != 0 ? 1 : 0); - SIZE_SIGN_UNCOMPRESSED = NB_WORD_GF2nv + (NB_ITE - 1) * NB_WORD_GF2nvm; - if (K <= 128) - { - SIZE_DIGEST = 32; - SIZE_DIGEST_UINT = 4; - ShakeBitStrength = 128; - Sha3BitStrength = 256; - } - else if (K <= 192) - { - SIZE_DIGEST = 48; - SIZE_DIGEST_UINT = 6; - ShakeBitStrength = 256; - Sha3BitStrength = 384; - } - else - { - SIZE_DIGEST = 64; - SIZE_DIGEST_UINT = 8; - ShakeBitStrength = 256; - Sha3BitStrength = 512; - } - sha3Digest = new SHA3Digest(Sha3BitStrength); - NB_UINT_HFEVPOLY = (NB_COEFS_HFEPOLY + (NB_MONOMIAL_VINEGAR - 1) + (HFEDegI + 1) * HFEv) * NB_WORD_GFqn; - MLv_GFqn_SIZE = (HFEv + 1) * NB_WORD_GFqn; - if (HFEDeg <= 34 || (HFEn > 196 && HFEDeg < 256)) - { - if (HFEDeg == 17) //redgemss128, redgemss192, redgemss256 magentagemss128 magentagemss192 magentagemss256 - { - II = 4; - } - else //bluegemss192, bluegemss256 cyangemss192 cyangemss256 fgemss128 dualmodems - { - II = 6; - } - POW_II = 1 << II; - KP = (HFEDeg >>> II) + ((HFEDeg % POW_II != 0) ? 1 : 0); - KX = HFEDeg - KP; - } - if (K2 != 0) - { - if ((HFEn == 544) && (K3 == 128)) //dualmodems256 MASK_GF2n: 00000000FFFFFFFF - { - rem = new Rem_GF2n.REM544_PENTANOMIAL_K3_IS_128_GF2X(K1, K2, KI, KI64, K164, K264, MASK_GF2n); - } - else //fgemss256 1FFFFFFL - { - rem = new Rem_GF2n.REM544_PENTANOMIAL_GF2X(K1, K2, K3, KI, KI64, K164, K264, K364, MASK_GF2n); - } - } - else - { - if (HFEn > 256 && HFEn < 289 && K3 > 32 && K3 < 64) //whitegemss192, bluegemss192, redgemss192, magentagemss192, cyangemss192 - { - rem = new Rem_GF2n.REM288_SPECIALIZED_TRINOMIAL_GF2X(K3, KI, KI64, K364, MASK_GF2n); - } - else if (HFEn == 354) //gemss256, whitegemss256, cyangemss256, magentagemss256 - { - rem = new Rem_GF2n.REM384_SPECIALIZED_TRINOMIAL_GF2X(K3, KI, KI64, K364, MASK_GF2n); - } - else if (HFEn == 358) //bluegemss256, redgemss256 - { - rem = new Rem_GF2n.REM384_SPECIALIZED358_TRINOMIAL_GF2X(K3, KI, KI64, K364, MASK_GF2n); - } - else if (HFEn == 402) //fgemss192, dualmodems192 - { - rem = new Rem_GF2n.REM402_SPECIALIZED_TRINOMIAL_GF2X(K3, KI, KI64, K364, MASK_GF2n); - } - else - { - switch (NB_WORD_MUL) - { - case 6: //gemss128, bluegemss128, redgemss128, whitegemss128, magentagemss128 - rem = new Rem_GF2n.REM192_SPECIALIZED_TRINOMIAL_GF2X(K3, KI, KI64, K364, MASK_GF2n); - break; - case 9: //whitegemss192, bluegemss192 - rem = new Rem_GF2n.REM288_SPECIALIZED_TRINOMIAL_GF2X(K3, KI, KI64, K364, MASK_GF2n); - break; - case 12: - rem = new Rem_GF2n.REM384_TRINOMIAL_GF2X(K3, KI, KI64, K364, MASK_GF2n); - } - } - } - Buffer_NB_WORD_MUL = new Pointer(NB_WORD_MUL); - Buffer_NB_WORD_GFqn = new Pointer(NB_WORD_GFqn); - HFEn_1rightmost = 31; - int e = HFEn - 1; - while ((e >>> HFEn_1rightmost) == 0) - { - --HFEn_1rightmost; - } - e = (HFEn + 1) >>> 1; - /* Search the position of the MSB of n-1 */ - HFEn1h_rightmost = 31; - while ((e >>> HFEn1h_rightmost) == 0) - { - --HFEn1h_rightmost; - } - --HFEn1h_rightmost; - } - - void genSecretMQS_gf2_opt(Pointer MQS, Pointer F) - { - Pointer a_vec_k; - Pointer a_vec_kp, buf_k, buf_kp; - Pointer F_cp; - Pointer tmp3 = new Pointer(NB_WORD_GFqn); - int i, j, k, kp, a_vec_kp_orig, buf_k_orig, a_vec_k_orig, buf_kp_orig; - /* Vector with linear terms of F */ - Pointer F_lin = new Pointer((HFEDegI + 1) * (HFEv + 1) * NB_WORD_GFqn); - F_cp = new Pointer(F, MQv_GFqn_SIZE); - for (i = 0; i <= HFEDegI; ++i) - { - for (k = 0; k <= HFEv; ++k) - { - F_lin.copyFrom((k * (HFEDegI + 1) + i) * NB_WORD_GFqn, F_cp, 0, NB_WORD_GFqn); - F_cp.move(NB_WORD_GFqn); - } - F_cp.move(i * NB_WORD_GFqn); - } - /* Precompute alpha_vec is disabled in the submission */ - Pointer alpha_vec = new Pointer(SIZE_ROW * (HFEn - 1) * NB_WORD_GFqn); - /* Matrix in GF(2^n) with HFEn-1 rows and (HFEDegI+1) columns */ - /* calloc is useful when it initialises a multiple precision element to 1 */ - for (i = 1; i < HFEn; ++i) - { - /* j=0: a^i */ - alpha_vec.set(i >>> 6, 1L << (i & 63)); - /* Compute (a^i)^(2^j) */ - for (j = 0; j < HFEDegI; ++j) - { - sqr_gf2n(alpha_vec, NB_WORD_GFqn, alpha_vec, 0); - alpha_vec.move(NB_WORD_GFqn); - } - alpha_vec.move(NB_WORD_GFqn); - } - alpha_vec.indexReset(); - /* Constant: copy the first coefficient of F in MQS */ - MQS.copyFrom(F, NB_WORD_GFqn); - F.move(MQv_GFqn_SIZE); - MQS.move(NB_WORD_GFqn); - /* Precompute an other table */ - Pointer buf = new Pointer(HFEDegI * HFEn * NB_WORD_GFqn); - special_buffer(buf, F, alpha_vec); - /* k=0 */ - buf_k = new Pointer(buf); - /* kp=0 */ - buf_kp = new Pointer(buf); - /* x_0*x_0: quadratic terms of F */ - /* i=0 */ - MQS.copyFrom(buf_kp, NB_WORD_GFqn); - buf_kp.move(NB_WORD_GFqn); - MQS.setXorMatrix_NoMove(buf_kp, NB_WORD_GFqn, HFEDegI - 1); - /* At this step, buf_kp corresponds to kp=1 */ - /* x_0: linear terms of F */ - F_cp.changeIndex(F_lin); - /* X^(2^i) */ - MQS.setXorMatrix(F_cp, NB_WORD_GFqn, HFEDegI + 1); - /* kp=1 (because kp=0 is not stored, it is just (1,1,1,...,1) */ - /* +NB_WORD_GFqn to jump (alpha^kp)^(2^0) */ - a_vec_kp = new Pointer(alpha_vec, NB_WORD_GFqn); - /* k=0: x_0 x_kp */ - for (kp = 1; kp < HFEn; ++kp) - { - /* dot_product(a_vec_kp, buf_k) */ - dotProduct_gf2n(MQS, a_vec_kp, buf_k, HFEDegI); - a_vec_kp.move(SIZE_ROW * NB_WORD_GFqn); - /* dot_product(a_vec_k=(1,1,...,1) , buf_kp) */ - MQS.setXorMatrix(buf_kp, NB_WORD_GFqn, HFEDegI); - } - /* Vinegar variables */ - for (; kp < HFEnv; ++kp) - { - MQS.copyFrom(F_cp, NB_WORD_GFqn); - F_cp.move(NB_WORD_GFqn); - MQS.setXorMatrix(F_cp, NB_WORD_GFqn, HFEDegI); - } - /* k=0 becomes k=1 */ - /* +NB_WORD_GFqn to jump (alpha^k)^(2^0) */ - a_vec_k = new Pointer(alpha_vec, NB_WORD_GFqn); - Pointer acc = new Pointer(NB_WORD_MUL); - /* Compute the term x_k x_kp */ - for (k = 1; k < HFEn; ++k) - { - /* k=0 becomes k=1 */ - buf_k.move(HFEDegI * NB_WORD_GFqn); - /* kp=k: x_k + x_k*x_k */ - a_vec_kp.changeIndex(a_vec_k); - buf_kp.changeIndex(buf_k); - /* Term X^(2^0) of F */ - mul.mul_gf2x(Buffer_NB_WORD_MUL, F_lin, new Pointer(a_vec_kp, -NB_WORD_GFqn)); - /* dot_product(a_vec_k,buf_k) */ - /* i=0 */ - for (i = 1; i <= HFEDegI; ++i) - { - /* Next linear term of F: X^(2^i) */ - tmp3.setRangeFromXor(0, buf_kp, 0, F_lin, i * NB_WORD_GFqn, NB_WORD_GFqn); - mul_xorrange(Buffer_NB_WORD_MUL, tmp3, a_vec_kp); - buf_kp.move(NB_WORD_GFqn); - a_vec_kp.move(NB_WORD_GFqn); - } - /* Monic case */ - /* To jump (alpha^kp)^(2^0) */ - a_vec_kp.move(NB_WORD_GFqn); - rem_gf2n(MQS, 0, Buffer_NB_WORD_MUL); - MQS.move(NB_WORD_GFqn); - /* x_k*x_kp */ - for (kp = k + 1; kp < HFEn; ++kp) - { - a_vec_kp_orig = a_vec_kp.getIndex(); - buf_k_orig = buf_k.getIndex(); - a_vec_k_orig = a_vec_k.getIndex(); - buf_kp_orig = buf_kp.getIndex(); - /* i=0 */ - mul_move(acc, a_vec_kp, buf_k); - for_mul_xorrange_move(acc, a_vec_kp, buf_k, HFEDegI - 1); - for_mul_xorrange_move(acc, a_vec_k, buf_kp, HFEDegI); - rem_gf2n(MQS, 0, acc); - a_vec_kp.changeIndex(a_vec_kp_orig + SIZE_ROW * NB_WORD_GFqn); - buf_k.changeIndex(buf_k_orig); - a_vec_k.changeIndex(a_vec_k_orig); - buf_kp.changeIndex(buf_kp_orig + HFEDegI * NB_WORD_GFqn); - MQS.move(NB_WORD_GFqn); - } - /* Vinegar variables */ - F_cp.changeIndex(F_lin); - a_vec_k.move(-NB_WORD_GFqn); - for (; kp < HFEnv; ++kp) - { - F_cp.move((HFEDegI + 1) * NB_WORD_GFqn); - dotProduct_gf2n(MQS, a_vec_k, F_cp, HFEDegI + 1); - MQS.move(NB_WORD_GFqn); - } - a_vec_k.move(NB_WORD_GFqn + SIZE_ROW * NB_WORD_GFqn); - /* k becomes k+1 */ - } - /* MQS with v vinegar variables */ - F.move(NB_WORD_GFqn - MQv_GFqn_SIZE); - MQS.copyFrom(F, NB_WORD_GFqn * (NB_MONOMIAL_VINEGAR - 1)); - MQS.indexReset(); - F.indexReset(); - } - - private void special_buffer(Pointer buf, Pointer F, Pointer alpha_vec) - { - int i, k; - int F_orig = F.getIndex(); - /* Special case: alpha^0 */ - /* F begins to X^3, the first "quadratic" term */ - F.move((NB_WORD_GFqn * (HFEv + 1)) << 1); - /* X^3 */ - buf.copyFrom(F, NB_WORD_GFqn); - buf.move(NB_WORD_GFqn); - /* X^5: we jump X^4 because it is linear */ - Pointer F_cp = new Pointer(F, NB_WORD_GFqn * (HFEv + 2)); - /* A_i,j X^(2^i + 2^j) */ - /* min(L,SIZE_ROW-1) */ - for (i = 2; i < SIZE_ROW - 1; ++i) - { - /* j=0: A_i,0 */ - copy_move_matrix_move(buf, F_cp, i - 1); - } - if (ENABLED_REMOVE_ODD_DEGREE) - { - for (; i < (SIZE_ROW - 1); ++i) - { - /* j=0 is removed because the term is odd */ - /* j=1: A_i,1 */ - copy_move_matrix_move(buf, F_cp, i - 2); - } - } - /* Monic case */ - buf.set1_gf2n(0, NB_WORD_GFqn); - buf.setXorMatrix(F_cp, NB_WORD_GFqn, HFEDegJ); - /* Squares of (alpha^(k+1)) */ - for (k = 0; k < (HFEn - 1); ++k) - { - /* X^3: i=1,j=0 */ - mul_gf2n(buf, alpha_vec, F); - buf.move(NB_WORD_GFqn); - /* X^5: we jump X^4 because it is linear */ - F_cp.changeIndex(F, NB_WORD_GFqn * (HFEv + 2)); - /* A_i,j X^(2^i + 2^j) */ - for (i = 2; i < HFEDegI; ++i) - { - dotproduct_move_move(buf, F_cp, alpha_vec, i); - } - if (ENABLED_REMOVE_ODD_DEGREE) - { - alpha_vec.move(NB_WORD_GFqn); - for (; i < SIZE_ROW - 1; ++i) - { - dotproduct_move_move(buf, F_cp, alpha_vec, i - 1); - } - alpha_vec.move(-NB_WORD_GFqn); - } - /* j=0: A_i,0 */ - if (HFEDegJ == 0) - { - /* Monic case */ - buf.copyFrom(alpha_vec, NB_WORD_GFqn); - buf.move(NB_WORD_GFqn); - /* To change the row of alpha_vec */ - alpha_vec.move(SIZE_ROW * NB_WORD_GFqn); - } - else - { - dotProduct_gf2n(buf, alpha_vec, F_cp, HFEDegJ); - /* j=HFEDegJ: monic case */ - alpha_vec.move(HFEDegJ * NB_WORD_GFqn); - buf.setXorRange_SelfMove(alpha_vec, NB_WORD_GFqn); - /* To change the row of alpha_vec */ - alpha_vec.move((SIZE_ROW - HFEDegJ) * NB_WORD_GFqn); - } - } - buf.indexReset(); - F.changeIndex(F_orig); - alpha_vec.indexReset(); - } - - private void copy_move_matrix_move(Pointer buf, Pointer F_cp, int len) - { - buf.copyFrom(F_cp, NB_WORD_GFqn); - F_cp.move(NB_WORD_GFqn); - buf.setXorMatrix(F_cp, NB_WORD_GFqn, len); - /* To jump a linear term X^(2^i) */ - F_cp.move(NB_WORD_GFqn * (HFEv + 1)); - } - - private void dotproduct_move_move(Pointer buf, Pointer F_cp, Pointer alpha_vec, int len) - { - dotProduct_gf2n(buf, alpha_vec, F_cp, len); - buf.move(NB_WORD_GFqn); - /* To jump quadratic terms + a linear term X^(2^i) */ - F_cp.move((len + HFEv + 1) * NB_WORD_GFqn); - } - - private void dotProduct_gf2n(Pointer res, Pointer vec_x, Pointer vec_y, int len) - { - Pointer tmp_mul = new Pointer(NB_WORD_MUL); - int vec_x_orig = vec_x.getIndex(); - int vec_y_orig = vec_y.getIndex(); - /* i=0 */ - mul_move(tmp_mul, vec_x, vec_y); - for_mul_xorrange_move(tmp_mul, vec_x, vec_y, len - 1); - rem_gf2n(res, 0, tmp_mul); - vec_x.changeIndex(vec_x_orig); - vec_y.changeIndex(vec_y_orig); - } - - /* Function mul in GF(2^x), then modular reduction */ - void mul_gf2n(Pointer P, Pointer A, int AOff, Pointer B) - { - int A_orig = A.getIndex(); - A.move(AOff); - mul.mul_gf2x(Buffer_NB_WORD_MUL, A, B); - A.changeIndex(A_orig); - rem_gf2n(P, 0, Buffer_NB_WORD_MUL); - } - - void mul_gf2n(Pointer P, Pointer A, Pointer B) - { - mul.mul_gf2x(Buffer_NB_WORD_MUL, A, B); - rem_gf2n(P, 0, Buffer_NB_WORD_MUL); - } - - void for_mul_xorrange_move(Pointer res, Pointer A, Pointer B, int len) - { - for (int i = 0; i < len; ++i) - { - mul.mul_gf2x_xor(res, A, B); - A.move(NB_WORD_GFqn); - B.move(NB_WORD_GFqn); - } - } - - void mul_move(Pointer res, Pointer A, Pointer B) - { - mul.mul_gf2x(res, A, B); - A.move(NB_WORD_GFqn); - B.move(NB_WORD_GFqn); - } - - public void mul_xorrange(Pointer res, Pointer A, Pointer B) - { - mul.mul_gf2x_xor(res, A, B); - } - - public void mul_rem_xorrange(Pointer res, Pointer A, Pointer B) - { - mul.mul_gf2x(Buffer_NB_WORD_MUL, A, B); - rem.rem_gf2n_xor(res.array, res.cp, Buffer_NB_WORD_MUL.array); - } - - public void mul_rem_xorrange(Pointer res, Pointer A, Pointer B, int b_cp) - { - int B_orig = B.getIndex(); - B.move(b_cp); - mul.mul_gf2x(Buffer_NB_WORD_MUL, A, B); - rem.rem_gf2n_xor(res.array, res.cp, Buffer_NB_WORD_MUL.array); - B.changeIndex(B_orig); - } - - private void rem_gf2n(Pointer P, int p_cp, Pointer Pol) - { - p_cp += P.getIndex(); - rem.rem_gf2n(P.array, p_cp, Pol.array); - } - - /* Function sqr in GF(2^x), then modular reduction */ - private void sqr_gf2n(Pointer C, int c_shift, Pointer A, int a_shift) - { - a_shift += A.cp; - mul.sqr_gf2x(Buffer_NB_WORD_MUL.array, A.array, a_shift); - rem_gf2n(C, c_shift, Buffer_NB_WORD_MUL); - } - - private void sqr_gf2n(Pointer C, Pointer A) - { - mul.sqr_gf2x(Buffer_NB_WORD_MUL.array, A.array, A.cp); - rem.rem_gf2n(C.array, C.cp, Buffer_NB_WORD_MUL.array); - } - - void cleanLowerMatrix(Pointer L, FunctionParams cleanLowerMatrix) - { - int nq, nr; - int iq; - switch (cleanLowerMatrix) - { - case N: - nq = HFEnq; - nr = HFEnr; - break; - case NV: - nq = HFEnvq; - nr = HFEnvr; - break; - default: - throw new IllegalArgumentException(""); - } - Pointer L_cp = new Pointer(L); - /* for each row */ - for (iq = 1; iq <= nq; ++iq) - { - for_and_xor_shift_incre_move(L_cp, iq, NB_BITS_UINT); - /* Next column */ - L_cp.moveIncremental(); - } - /* iq = HFEnq */ - for_and_xor_shift_incre_move(L_cp, iq, nr); - } - - private void for_and_xor_shift_incre_move(Pointer L_cp, int iq, int len) - { - long mask = 0; - for (int ir = 0; ir < len; ++ir) - { - /* Put the bit of diagonal to 1 + zeros after the diagonal */ - L_cp.setAnd(mask); - L_cp.setXor(1L << ir); - mask <<= 1; - ++mask; - L_cp.move(iq); - } - } - - /** - * @brief Compute the inverse of S=LU a matrix (n,n) or (n+v, n+v) in GF(2), in-place. - * @details Gauss-Jordan: transform S to Identity and Identity to S^(-1). - * Here, we do not need to transform S to Identity. - * We use L to transform Identity to a lower triangular S', - * then we use U to transform S' to S^(-1). - * @param[in,out] S S_inv=L*U, an invertible matrix (n,n) in GF(2), - * its inverse will be computed in-place. - * @param[in] L_orig A lower triangular matrix (n,n) in GF(2). - * @param[in] U_orig An upper triangular matrix (n,n) in GF(2), but we - * require to store its transpose (i.e. contiguous following the columns). - * @param[in] imluParams chooses size of matrix (n,n) or (n+v, n+v) - * @remark Requirement: S is invertible. - * @remark Constant-time implementation. - */ - void invMatrixLU_gf2(Pointer S, Pointer L_orig, Pointer U_orig, FunctionParams imluParams) - { - Pointer Sinv_cpi, Sinv_cpj; - Pointer L_cpj = new Pointer(L_orig); - Pointer L = new Pointer(L_orig); - Pointer U = new Pointer(U_orig); - int i, iq, j; - int outloopbound, innerloopbound, nextrow, ifCondition, endOfU; - switch (imluParams) - { - case NV: - outloopbound = HFEnvq; - innerloopbound = HFEnv - 1; - nextrow = NB_WORD_GF2nv; - ifCondition = HFEnvr; - endOfU = LTRIANGULAR_NV_SIZE; - break; - case N: - S.setRangeClear(0, MATRIXn_SIZE); - outloopbound = HFEnq; - innerloopbound = HFEn - 1; - nextrow = NB_WORD_GFqn; - ifCondition = HFEnr; - endOfU = LTRIANGULAR_N_SIZE; - break; - default: - throw new IllegalArgumentException("Invalid Input"); - } - /* Initialize to 0 */ - Sinv_cpi = new Pointer(S); - Sinv_cpj = new Pointer(S); - /* for each row of S and of S_inv, excepted the last block */ - for (i = 0, iq = 0; iq < outloopbound; ++iq) - { - i = loop_xor_loop_move_xorandmask_move(Sinv_cpi, Sinv_cpj, L_cpj, L, i, iq, NB_BITS_UINT, innerloopbound, nextrow); - /* Next column */ - L.moveIncremental(); - } - if (ifCondition > 1) - { - loop_xor_loop_move_xorandmask_move(Sinv_cpi, Sinv_cpj, L_cpj, L, i, iq, ifCondition - 1, innerloopbound, nextrow); - /* ir = HFEnvr-1 */ - Sinv_cpi.setXor(iq, 1L << (ifCondition - 1)); - Sinv_cpi.move(nextrow); - } - else if (ifCondition == 1) - { - /* ir = 0 */ - Sinv_cpi.set(iq, 1L); - Sinv_cpi.move(nextrow); - } - /* Here, Sinv_cpi is at the end of S_inv */ - /* End of U */ - U.move(endOfU); - /* for each row excepted the first */ - for (i = innerloopbound; i > 0; --i) - { - /* Previous row */ - U.move(-1 - (i >>> 6)); - /* Row i of Sinv */ - Sinv_cpi.move(-nextrow); - /* Row j of Sinv */ - Sinv_cpj.changeIndex(S); - /* for the previous rows */ - for (j = 0; j < i; ++j) - { - /* pivot */ - Sinv_cpj.setXorRangeAndMask(Sinv_cpi, nextrow, -(((U.get(j >>> 6)) >>> (j & 63)) & 1L)); - /* next row */ - Sinv_cpj.move(nextrow); - } - } - } - - private int loop_xor_loop_move_xorandmask_move(Pointer Sinv_cpi, Pointer Sinv_cpj, Pointer L_cpj, Pointer L, int i, - int iq, int len, int innerloopbound, int nextrow) - { - int j, ir; - for (ir = 0; ir < len; ++ir, ++i) - { - /* The element of the diagonal is 1 */ - Sinv_cpi.setXor(iq, 1L << ir); - Sinv_cpj.changeIndex(Sinv_cpi); - L_cpj.changeIndex(L); - /* for the next rows */ - for (j = i; j < innerloopbound; ++j) - { - /* next row */ - Sinv_cpj.move(nextrow); - L_cpj.move((j >>> 6) + 1); - Sinv_cpj.setXorRangeAndMask(Sinv_cpi, iq + 1, -((L_cpj.get() >>> ir) & 1L)); - } - /* Next row */ - Sinv_cpi.move(nextrow); - L.move(iq + 1); - } - return i; - } - - enum FunctionParams - { - NV, - V, - N, - M - } - - void vecMatProduct(Pointer res, Pointer vec, Pointer S_orig, FunctionParams vecMatProduct) - { - int gf2_len, S_cp_increase, loopir_param, nq; - long bit_ir; - int iq = 0, ir = 0; - Pointer S = new Pointer(S_orig); - switch (vecMatProduct) - { - case NV: - res.setRangeClear(0, NB_WORD_GF2nv); - nq = HFEnvq; - gf2_len = NB_WORD_GF2nv; - S_cp_increase = NB_WORD_GF2nv; - break; - case V: - res.setRangeClear(0, NB_WORD_GFqn); - gf2_len = NB_WORD_GFqn; - S_cp_increase = NB_WORD_GFqn; - nq = HFEvq; - break; - case N: - res.setRangeClear(0, NB_WORD_GFqn); - gf2_len = NB_WORD_GFqn; - S_cp_increase = NB_WORD_GFqn; - nq = HFEnq; - break; - case M: - res.setRangeClear(0, NB_WORD_GF2m);//removal causes bugs in dualmodems256 - nq = HFEnq; - gf2_len = NB_WORD_GF2m; - S_cp_increase = NB_WORD_GFqn; - break; - default: - throw new IllegalArgumentException("Invalid input for vecMatProduct"); - } - /* for each bit of vec excepted the last block */ - for (; iq < nq; ++iq) - { - bit_ir = vec.get(iq); - for (; ir < 64; ++ir) - { - res.setXorRangeAndMask(S, gf2_len, -(bit_ir & 1L)); - /* next row of S */ - S.move(S_cp_increase); - bit_ir >>>= 1; - } - ir = 0; - } - /* the last block */ - switch (vecMatProduct) - { - case NV: - if (HFEnvr == 0) - { - return; - } - bit_ir = vec.get(HFEnvq); - loopir_param = HFEnvr; - break; - case V: - if (HFEvr == 0) - { - return; - } - bit_ir = vec.get(HFEvq); - loopir_param = HFEvr; - break; - case N: - case M: - bit_ir = vec.get(HFEnq); - loopir_param = HFEnr; - break; - default: - throw new IllegalArgumentException("Invalid input for vecMatProduct"); - } - for (; ir < loopir_param; ++ir) - { - res.setXorRangeAndMask(S, gf2_len, -(bit_ir & 1L)); - /* next row of S */ - S.move(S_cp_increase); - bit_ir >>>= 1; - } - if (vecMatProduct == FunctionParams.M && HFEmr != 0) - { - res.setAnd(NB_WORD_GF2m - 1, MASK_GF2m); - } - } - - /** - * @return The constant c of pk2, in GF(2). - * @brief Decompression of a compressed MQ equation in GF(2)[x1,...,x_(n+v)]. - * Both use a lower triangular matrix. - * @details pk = (c,Q), with c the constant part in GF(2) and Q is a lower - * triangular matrix of size (n+v)*(n+v) in GF(2). pk2 will have the same - * format, but the equation will be decompressed. Here, the last byte of pk is - * padded with null bits. - * @param[in] pk A MQ equation in GF(2)[x1,...,x_(n+v)]. - * @param[out] pk2_orig A MQ equation in GF(2)[x1,...,x_(n+v)]. - * @remark Requires to allocate NB_WORD_UNCOMP_EQ 64-bit words for pk2. - * @remark Requirement: at least NB_BYTES_EQUATION - * + ((8-(NB_BYTES_EQUATION mod 8)) mod 8) bytes have to be allocated for pk - * (because pk is cast in 64-bit, and the last memory access requires that - * is allocated a multiple of 64 bits). - * @remark Constant-time implementation. - */ - private long convMQ_uncompressL_gf2(Pointer pk2, PointerUnion pk) - { - int nb_bits; - PointerUnion pk64 = new PointerUnion(pk); - nb_bits = for_setpk2_end_move_plus(pk2, pk64, HFEnvq); - if (HFEnvr != 0) //except redgemss128 - { - setPk2Value(pk2, pk64, nb_bits, HFEnvq, HFEnvr + 1); - } - /* Constant */ - return pk.get() & 1; - } - - private int setPk2Value(Pointer pk2, PointerUnion pk64, int nb_bits, int iq, int len) - { - int ir; - for (ir = 1; ir < len; ++ir) - { - if ((nb_bits & 63) != 0) - { - pk2.setRangePointerUnion(pk64, iq, nb_bits & 63); - pk2.set(iq, pk64.get(iq) >>> (nb_bits & 63)); - if (((nb_bits & 63) + ir) > 64) - { - pk2.setXor(iq, pk64.get(iq + 1) << (64 - (nb_bits & 63))); - } - if (((nb_bits & 63) + ir) >= 64) - { - pk64.moveIncremental(); - } - } - else - { - pk2.setRangePointerUnion(pk64, iq + 1); - } - pk64.move(iq); - /* 0 padding on the last word */ - pk2.setAnd(iq, (1L << ir) - 1L); - pk2.move(iq + 1); - nb_bits += (iq << 6) + ir; - } - return nb_bits; - } - - private void setPk2_endValue(Pointer pk2, PointerUnion pk64, int nb_bits, int iq) - { - /* ir=64 */ - if ((nb_bits & 63) != 0) - { - pk2.setRangePointerUnion(pk64, iq + 1, nb_bits & 63); - } - else - { - pk2.setRangePointerUnion(pk64, iq + 1); - } - } - - /** - * @return The constant c of pk2, in GF(2). - * @brief Decompression of a compressed MQ equation in GF(2)[x1,...,x_(n+v)]. - * Both use a lower triangular matrix. - * @details pk = (c,Q), with c the constant part in GF(2) and Q is a lower - * triangular matrix of size (n+v)*(n+v) in GF(2). pk2 will have the same - * format, but the equation will be decompressed. Here, the last bits of pk - * are missing (cf. the output of convMQ_last_UL_gf2). Moreover, the last byte - * of pk is padded with null bits. - * @param[in] pk A MQ equation in GF(2)[x1,...,x_(n+v)]. - * @param[out] pk2 A MQ equation in GF(2)[x1,...,x_(n+v)]. - * @remark Requires to allocate NB_WORD_UNCOMP_EQ 64-bit words for pk2. - * @remark This function is a modified copy of convMQ_uncompressL_gf2. - * @remark Constant-time implementation. - */ - private long convMQ_last_uncompressL_gf2(Pointer pk2, PointerUnion pk) - { - PointerUnion pk64 = new PointerUnion(pk); - int iq, ir, k, nb_bits; - k = HFEnv - 1; - final int HFEnvqm1 = k >>> 6; - final int HFEnvrm1 = k & 63; - nb_bits = for_setpk2_end_move_plus(pk2, pk64, HFEnvqm1); - if (HFEnvrm1 != 0) - { - nb_bits = setPk2Value(pk2, pk64, nb_bits, HFEnvqm1, HFEnvrm1 + 1); - } - /* Last row */ - /* The size of the last row is HFEnv-LOST_BITS bits */ - k = HFEnv - LOST_BITS; - final int LAST_ROW_Q = k >>> 6; - final int LAST_ROW_R = k & 63; - iq = LAST_ROW_Q; - long end; - if (LAST_ROW_R != 0) - { - ir = LAST_ROW_R; - if ((nb_bits & 63) != 0) - { - if ((((NB_MONOMIAL_PK - LOST_BITS + 7) >>> 3) & 7) != 0)//Except cyangemss192, magentagemss192 - { - final int NB_WHOLE_BLOCKS = ((HFEnv - ((64 - ((NB_MONOMIAL_PK - LOST_BITS - HFEnvr) & 63)) & 63)) >>> 6); - pk2.setRangePointerUnion_Check(pk64, NB_WHOLE_BLOCKS, nb_bits); - k = NB_WHOLE_BLOCKS; - pk2.set(k, pk64.getWithCheck(k) >>> (nb_bits & 63)); - if (NB_WHOLE_BLOCKS < LAST_ROW_Q) - { - end = pk64.getWithCheck(k + 1); - pk2.setXor(k, end << (64 - (nb_bits & 63))); - pk2.set(k + 1, end >>> (nb_bits & 63)); - } - else if (((nb_bits & 63) + ir) > 64) - { - pk2.setXor(k, pk64.getWithCheck(k + 1) << (64 - (nb_bits & 63))); - } - } - else - { - pk2.setRangePointerUnion(pk64, iq, nb_bits & 63); - pk2.set(iq, pk64.get(iq) >>> (nb_bits & 63)); - if (((nb_bits & 63) + ir) > 64) - { - pk2.setXor(iq, pk64.get(iq + 1) << (64 - (nb_bits & 63))); - } - } - } - else - { - if ((((NB_MONOMIAL_PK - LOST_BITS + 7) >>> 3) & 7) != 0) - { - pk2.setRangePointerUnion(pk64, iq); - pk2.set(iq, pk64.getWithCheck(iq)); - } - else - { - pk2.setRangePointerUnion(pk64, iq + 1); - } - } - } - else if (LAST_ROW_Q != 0) - { - if ((nb_bits & 63) != 0) - { - if ((((NB_MONOMIAL_PK - LOST_BITS + 7) >>> 3) & 7) != 0) - { - pk2.setRangePointerUnion(pk64, iq - 1, nb_bits & 63); - k = iq - 1; - pk2.set(k, pk64.get(k) >>> (nb_bits & 63)); - pk2.setXor(k, pk64.getWithCheck(k + 1) << (64 - (nb_bits & 63))); - } - else - { - pk2.setRangePointerUnion(pk64, iq, nb_bits & 63); - } - } - else - { - pk2.setRangePointerUnion(pk64, iq); - } - } - /* Constant */ - return pk.get() & 1L; - } - - private int for_setpk2_end_move_plus(Pointer pk2, PointerUnion pk64, int len) - { - int nb_bits = 1; - /* For each row */ - for (int iq = 0; iq < len; ++iq) - { - nb_bits = setPk2Value(pk2, pk64, nb_bits, iq, 64); - setPk2_endValue(pk2, pk64, nb_bits, iq); - pk64.move(iq + 1); - pk2.move(iq + 1); - nb_bits += (iq + 1) << 6; - } - return nb_bits; - } - - /** - * @return 0 for a valid signature, !=0 else. - * @brief Verify the signature of the document m of length len bytes, using a - * (HFEv-)-based signature scheme. pk can be evaluated with the eval_pk - * function, and hpk is used during this evaluation. - * @details eval_pk takes 4 arguments here. - * @param[in] m A pointer on a document. - * @param[in] len The length in bytes of the document m. - * @param[in] sm8 A signature generated by a (HFEv-)-based signature scheme. - * @param[in] pk The original public-key, a MQ system with m equations in - * GF(2)[x1,...,x_(n+v)]. - * @param[in] hpk The hybrid representation of one part of the public-key pk. - * @remark Requirement: when SSE or AVX is enabled, the public-key must be - * aligned respectively on 16 or 32 bytes. However, this requirement and the - * alignment are disabled for the public/stable version of MQsoft (to be simple - * to use, generic for the allocation of pk and to avoid segmentation faults). - * @remark This function does not require a constant-time implementation. - */ - public int sign_openHFE_huncomp_pk(byte[] m, int len, byte[] sm8, PointerUnion pk, PointerUnion hpk) - { - Pointer sm = new Pointer(SIZE_SIGN_UNCOMPRESSED); - Pointer Si_tab = new Pointer(NB_WORD_GF2nv); - Pointer Si1_tab = new Pointer(NB_WORD_GF2nv); - /* Copy of pointer */ - Pointer Si = new Pointer(Si_tab); - Pointer Si1 = new Pointer(Si1_tab); - /* Vector of D_1, ..., D_(NB_ITE) */ - byte[] hash = new byte[64]; - Pointer D = new Pointer(NB_ITE * SIZE_DIGEST_UINT); - int i, index, m_cp = 0; - long cst = hpk.get(); - /* We jump the constant (stored on 8 bytes) */ - hpk.move(1); - uncompress_signHFE(sm, sm8); - /* Compute H1 = H(m), the m first bits are D1 */ - getSHA3Hash(D, 0, 64, m, m_cp, len, hash); - for (i = 1; i < NB_ITE; ++i) - { - /* Compute Hi = H(H_(i-1)), the m first bits are Di */ - getSHA3Hash(D, i * SIZE_DIGEST_UINT, 64, hash, 0, SIZE_DIGEST, hash); - /* Clean the previous hash (= extract D_(i-1) from H_(i-1)) */ - D.setAnd(SIZE_DIGEST_UINT * (i - 1) + NB_WORD_GF2m - 1, MASK_GF2m); - } - /* Clean the previous hash (= extract D_(i-1) from H_(i-1)) */ - D.setAnd(SIZE_DIGEST_UINT * (i - 1) + NB_WORD_GF2m - 1, MASK_GF2m); - /* Compute p(S_(NB_IT),X_(NB_IT)) */ - evalMQShybrid8_uncomp_nocst_gf2_m(Si, sm, pk, hpk); - Si.setXor(HFEmq, cst); - for (i = NB_ITE - 1; i > 0; --i) - { - /* Compute Si = xor(p(S_i+1,X_i+1),D_i+1) */ - Si.setXorRange(D, i * SIZE_DIGEST_UINT, NB_WORD_GF2m); - /* Compute Si||Xi */ - index = NB_WORD_GF2nv + (NB_ITE - 1 - i) * NB_WORD_GF2nvm; - Si.setAnd(NB_WORD_GF2m - 1, MASK_GF2m); - /* Concatenation(Si,Xi): the intersection between S1 and X1 is not null */ - Si.setXor(NB_WORD_GF2m - 1, sm.get(index)); - if (NB_WORD_GF2nvm != 1) - { - Si.copyFrom(NB_WORD_GF2m, sm, ++index, NB_WORD_GF2nvm - 1); - } - /* Compute p(Si,Xi) */ - evalMQShybrid8_uncomp_nocst_gf2_m(Si1, Si, pk, hpk); - Si1.setXor(HFEmq, cst); - /* Permutation of pointers */ - Si1.swap(Si); - } - /* D1'' == D1 */ - return Si.isEqual_nocst_gf2(D, NB_WORD_GF2m); - } - - private void getSHA3Hash(Pointer output, int outOff, int outLength, byte[] input, int inOff, int inputLenth, byte[] hash) - { - sha3Digest.update(input, inOff, inputLenth); - sha3Digest.doFinal(hash, 0); - output.fill(outOff, hash, 0, outLength); - } - - /** - * @brief Variable-time evaluation of a MQS in a vector. The MQS is stored - * with a hybrid representation. - * @details The FORMAT_HYBRID_CPK8 have to be used. The (m-(m mod 8)) first - * equations are stored as one multivariate quadratic equation in - * GF(2^(m-(m mod 8)))[x1,...,x_(n+v)], i.e. the monomial representation is - * used. This corresponds to mq_quo. The (m mod 8) last equations are stored - * separately in mq_rem. Here, the EVAL_HYBRID_CPK8_UNCOMP have to be used, i.e. - * the last equations are uncompressed. - * mq_quo = (c',Q'). - * mq_rem = (c_(m-(m mod 8)),Q_(m-(m mod 8)),...,c_(m-1),Q_(m-1)). - * c' is in GF(2^(m-(m mod 8))). - * Q' is upper triangular of size (n+v)*(n+v) in GF(2^(m-(m mod 8))). - * The (m mod 8) ci are in GF(2). - * The (m mod 8) Qi are lower triangular of size (n+v)*(n+v) in GF(2). - * For each Qi, the rows are stored separately (we take new words for each new - * row). - * @param[in] x A vector of n+v elements in GF(2). - * @param[in] mq_quo The (m-(m mod 8)) first equations, - * in GF(2^(m-(m mod 8)))[x1,...,x_(n+v)]. - * @param[in] mq_rem_orig The (m mod 8) last equations, - * in (GF(2)[x1,...,x_(n+v)])^(m mod 8). - * @param[out] res A vector of m elements in GF(2), evaluation of the MQS in x. - * @remark Requirement: at least ACCESS_last_equations8 + ((8-(HFEmq8 mod 8)) - * mod 8) bytes have to be allocated for mq_quo (because of the use of - * evalMQSnocst8_quo_gf2). - * @remark If a vector version of evalMQnocst_gf2 is used, maybe the last - * vector load read outside of memory. So, if this load reads z bits, let - * B be ceiling(z/64). The last equation requires NB_WORD_UNCOMP_EQ - * + ((B-(NB_WORD_GF2nv mod B)) mod B) 64-bit words. - * @remark Variable-time implementation. - */ - private void evalMQShybrid8_uncomp_nocst_gf2_m(Pointer res, Pointer x, PointerUnion mq_quo, PointerUnion mq_rem_orig) - { - PointerUnion mq_rem = new PointerUnion(mq_rem_orig); - evalMQSnocst8_quo_gf2(res, x, mq_quo); - if (HFEmr < 8) - { - res.set(HFEmq, 0); - } - for (int i = HFEmr - HFEmr8; i < HFEmr; ++i) - { - res.setXor(HFEmq, evalMQnocst_unrolled_no_simd_gf2(x, mq_rem) << i); - mq_rem.move(NB_WORD_UNCOMP_EQ); - } - } - - /* Uncompress the signature */ - private void uncompress_signHFE(Pointer sm, byte[] sm8) - { - PointerUnion sm64 = new PointerUnion(sm); - final int MASK8_GF2nv = (1 << HFEnvr8) - 1; - /* Take the (n+v) first bits */ - sm64.fillBytes(0, sm8, 0, NB_BYTES_GFqnv); - /* Clean the last byte */ - if (HFEnvr8 != 0) //except bluegemss192, redgemss128 - { - sm64.setAndByte(NB_BYTES_GFqnv - 1, MASK8_GF2nv); - } - /* Take the (Delta+v)*(nb_ite-1) bits */ - int k1, k2, nb_rem2, nb_rem_m, val_n, nb_rem; - /* HFEnv bits are already extracted from sm8 */ - int nb_bits = HFEnv; - sm64.moveNextBytes((NB_WORD_GF2nv << 3) + (HFEmq8 & 7)); - for (k1 = 1; k1 < NB_ITE; ++k1) - { - /* Number of bits to complete the byte of sm8, in [0,7] */ - val_n = Math.min((HFEDELTA + HFEv), ((8 - (nb_bits & 7)) & 7)); - /* First byte of sm8 */ - if ((nb_bits & 7) != 0) - { - sm64.setXorByte(((sm8[nb_bits >>> 3] & 0xFF) >>> (nb_bits & 7)) << HFEmr8); - /* Number of bits to complete the first byte of sm8 */ - nb_rem = val_n - VAL_BITS_M; - if (nb_rem >= 0) - { - /* We take the next byte since we used VAL_BITS_M bits */ - sm64.moveNextByte(); - } - if (nb_rem > 0) - { - nb_bits += VAL_BITS_M; - sm64.setXorByte((sm8[nb_bits >>> 3] & 0xFF) >>> (nb_bits & 7)); - nb_bits += nb_rem; - } - else - { - nb_bits += val_n; - } - } - /* Other bytes of sm8 */ - nb_rem2 = (HFEDELTA + HFEv) - val_n; - /*nb_rem2 can be zero only in this case */ - /* Number of bits used of sm64, mod 8 */ - nb_rem_m = (HFEm + val_n) & 7; - /* Other bytes */ - if (nb_rem_m != 0) - { - /* -1 to take the ceil of /8, -1 */ - for (k2 = 0; k2 < ((nb_rem2 - 1) >>> 3); ++k2) - { - sm64.setXorByte((sm8[nb_bits >>> 3] & 0xFF) << nb_rem_m); - sm64.moveNextByte(); - sm64.setXorByte((sm8[nb_bits >>> 3] & 0xFF) >>> (8 - nb_rem_m)); - nb_bits += 8; - } - /* The last byte of sm8, between 1 and 8 bits to put */ - sm64.setXorByte((sm8[nb_bits >>> 3] & 0xFF) << nb_rem_m); - sm64.moveNextByte(); - /* nb_rem2 between 1 and 8 bits */ - nb_rem2 = ((nb_rem2 + 7) & 7) + 1; - if (nb_rem2 > (8 - nb_rem_m)) - { - sm64.setByte((sm8[nb_bits >>> 3] & 0xFF) >>> (8 - nb_rem_m)); - sm64.moveNextByte(); - } - nb_bits += nb_rem2; - } - else - { - /* We are at the beginning of the bytes of sm8 and sm64 */ - /* +7 to take the ceil of /8 */ - for (k2 = 0; k2 < ((nb_rem2 + 7) >>> 3); ++k2) - { - sm64.setByte(sm8[nb_bits >>> 3]); - nb_bits += 8; - sm64.moveNextByte(); - } - /* The last byte has AT MOST 8 bits. */ - nb_bits -= (8 - (nb_rem2 & 7)) & 7; - } - /* Clean the last byte */ - if (HFEnvr8 != 0) - { - sm64.setAndByte(-1, MASK8_GF2nv); - } - /* We complete the word. Then we search the first byte. */ - sm64.moveNextBytes(((8 - (NB_BYTES_GFqnv & 7)) & 7) + (HFEmq8 & 7)); - } - } - - private void evalMQSnocst8_quo_gf2(Pointer c, Pointer m, PointerUnion pk_orig) - { - long xi, xj; - int iq, ir, i = HFEnv, jq; - final int NB_EQ = (HFEm >>> 3) != 0 ? ((HFEm >>> 3) << 3) : HFEm; - final int NB_BYTES_EQ = (NB_EQ & 7) != 0 ? ((NB_EQ >>> 3) + 1) : (NB_EQ >>> 3); - final int NB_WORD_EQ = (NB_BYTES_EQ >>> 3) + ((NB_BYTES_EQ & 7) != 0 ? 1 : 0); - /* Constant cst_pk */ - PointerUnion pk = new PointerUnion(pk_orig); - System.arraycopy(pk.getArray(), 0, c.getArray(), c.getIndex(), NB_WORD_EQ); - pk.moveNextBytes(NB_BYTES_EQ); - /* for each row of the quadratic matrix of pk, excepted the last block */ - for (iq = 0; iq < HFEnvq; ++iq) - { - xi = m.get(iq); - for (ir = 0; ir < NB_BITS_UINT; ++ir, --i) - { - if ((xi & 1) != 0) - { - /* for each column of the quadratic matrix of pk */ - /* xj=xi=1 */ - c.setXorRange(0, pk, 0, NB_WORD_EQ); - pk.moveNextBytes(NB_BYTES_EQ); - xj = xi >>> 1; - LOOPJR_UNROLLED_64(c, pk, ir + 1, NB_BITS_UINT, xj, NB_BYTES_EQ, NB_WORD_EQ); - for (jq = iq + 1; jq < HFEnvq; ++jq) - { - xj = m.get(jq); - LOOPJR_UNROLLED_64(c, pk, 0, NB_BITS_UINT, xj, NB_BYTES_EQ, NB_WORD_EQ); - } - if (HFEnvr != 0) - { - choose_LOOPJR(c, pk, 0, m.get(HFEnvq), NB_BYTES_EQ, NB_WORD_EQ); - } - } - else - { - pk.moveNextBytes(i * NB_BYTES_EQ); - } - xi >>>= 1; - } - } - /* the last block */ - if (HFEnvr != 0) - { - xi = m.get(HFEnvq); - for (ir = 0; ir < HFEnvr; ++ir, --i) - { - if ((xi & 1) != 0) - { - /* for each column of the quadratic matrix of pk */ - /* xj=xi=1 */ - c.setXorRange(0, pk, 0, NB_WORD_EQ); - pk.moveNextBytes(NB_BYTES_EQ); - choose_LOOPJR(c, pk, ir + 1, xi >>> 1, NB_BYTES_EQ, NB_WORD_EQ); - } - else - { - pk.moveNextBytes(i * NB_BYTES_EQ); - } - xi >>>= 1; - } - } - if ((NB_EQ & 63) != 0) - { - c.setAnd(NB_WORD_EQ - 1, (1L << (NB_EQ & 63)) - 1L); - } - } - - private void choose_LOOPJR(Pointer c, PointerUnion pk, int START, long xj, int NB_BYTES_EQ, int NB_WORD_EQ) - { - if (HFEnvr < (LEN_UNROLLED_64 << 1))//gemss256, bluegemss256,magentagemss128 - { - LOOPJR_NOCST_64(c, pk, START, HFEnvr, xj, NB_BYTES_EQ, NB_WORD_EQ); - } - else - { - LOOPJR_UNROLLED_64(c, pk, START, HFEnvr, xj, NB_BYTES_EQ, NB_WORD_EQ); - } - } - - private void LOOPJR_UNROLLED_64(Pointer c, PointerUnion pk64, int START, int NB_IT, long xj, int NB_BYTES_EQ, int NB_WORD_EQ) - { - int jr; - for (jr = START; jr < (NB_IT - LEN_UNROLLED_64 + 1); jr += LEN_UNROLLED_64) - { - xj = LOOPJR_NOCST_64(c, pk64, 0, LEN_UNROLLED_64, xj, NB_BYTES_EQ, NB_WORD_EQ); - } - LOOPJR_NOCST_64(c, pk64, jr, NB_IT, xj, NB_BYTES_EQ, NB_WORD_EQ); - } - - private long LOOPJR_NOCST_64(Pointer c, PointerUnion pk64, int START, int NB_IT, long xj, int NB_BYTES_EQ, int NB_WORD_EQ) - { - for (int jr = START; jr < NB_IT; ++jr) - { - if ((xj & 1L) != 0) - { - c.setXorRange(0, pk64, 0, NB_WORD_EQ); - } - pk64.moveNextBytes(NB_BYTES_EQ); - xj >>>= 1; - } - return xj; - } - - private long evalMQnocst_unrolled_no_simd_gf2(Pointer m, PointerUnion mq_orig) - { - long acc = 0; - int i; - int loop_end = 64; - PointerUnion mq = new PointerUnion(mq_orig); - long mj = m.get(); - for (i = 0; i < loop_end; ++i) - { - if (((mj >>> i) & 1L) != 0) - { - acc ^= mq.get(i) & mj; - } - } - mq.move(64); - for (int j = 1; j < NB_WORD_GF2nv; ++j) - { - loop_end = (NB_WORD_GF2nv == (j + 1) && HFEnvr != 0) ? HFEnvr : 64; - mj = m.get(j); - for (i = 0; i < loop_end; ++i) - { - if (((mj >>> i) & 1) != 0) - { - acc ^= mq.getDotProduct(0, m, 0, j + 1); - } - mq.move(j + 1); - } - } - acc = GeMSSUtils.XORBITS_UINT(acc); - return acc; - } - - public void signHFE_FeistelPatarin(SecureRandom random, byte[] sm8, byte[] m, int m_cp, int len, byte[] sk) - { - this.random = random; - Pointer U = new Pointer(NB_WORD_GFqn); - Pointer Hi_tab = new Pointer(SIZE_DIGEST_UINT); - Pointer Hi1_tab = new Pointer(SIZE_DIGEST_UINT); - Pointer Hi1 = new Pointer(Hi1_tab); - final int HFEvr8 = HFEv & 7; - /* Number of bytes that an element of GF(2^(n+v)) needs */ - final int NB_BYTES_GFqv = (HFEv >>> 3) + ((HFEvr8 != 0) ? 1 : 0); - final long HFE_MASKv = GeMSSUtils.maskUINT(HFEvr); - int i, k, index; - long rem_char = 0; - SecretKeyHFE sk_HFE = new SecretKeyHFE(this); - Pointer V = new Pointer(NB_WORD_GFqv); - Pointer[] linear_coefs = new Pointer[HFEDegI + 1]; - precSignHFE(sk_HFE, linear_coefs, sk); - Pointer F = new Pointer(sk_HFE.F_struct.poly); - /* Compute H1 = H(m) */ - Pointer Hi = new Pointer(Hi_tab); - byte[] hash = new byte[Sha3BitStrength >>> 3]; - getSHA3Hash(Hi, 0, hash.length, m, m_cp, len, hash); - /* It is to initialize S0 to 0, because Sk||Xk is stored in sm */ - Pointer sm = new Pointer(SIZE_SIGN_UNCOMPRESSED); - Pointer DR = new Pointer(NB_WORD_GF2nv); - PointerUnion DR_cp = new PointerUnion(DR); - for (k = 1; k <= NB_ITE; ++k) - { - /* Compute xor(D_k,S_(k-1)) */ - DR.setRangeFromXor(sm, Hi, NB_WORD_GF2m); - if (HFEmr8 != 0)//except fgemss and dualmodegs - /* Clean the last char to compute rem_char (the last word is cleaned) */ - { - DR.setAnd(NB_WORD_GF2m - 1, MASK_GF2m); - /* Save the last byte because we need to erase this value by randombytes */ - rem_char = DR_cp.getByte(HFEmq8); - } - /* When the root finding fails, the minus and vinegars are regenerated */ - do - { - /* Compute Dk||Rk: add random to have n bits, without erased the m bits */ - if (HFEmr8 != 0)//except fgemss and dualmodegs - { - /* Generation of Rk */ - DR_cp.fillRandomBytes(HFEmq8, random, NB_BYTES_GFqn - NB_BYTES_GFqm + 1); - /* Put HFEm&7 first bits to 0 */ - DR_cp.setAndThenXorByte(HFEmq8, -(1L << HFEmr8), rem_char); - } - else - { - DR_cp.fillRandomBytes(NB_BYTES_GFqm, random, NB_BYTES_GFqn - NB_BYTES_GFqm); - } - /* To clean the last char (because of randombytes), the last word is cleaned */ - if ((HFEn & 7) != 0)//except dualmodegs256 - { - DR.setAnd(NB_WORD_GFqn - 1, MASK_GF2n); - } - /* Compute Sk||Xk = Inv_p(Dk,Rk) */ - /* Firstly: compute c * T^(-1) */ - vecMatProduct(U, DR, sk_HFE.T, FunctionParams.N); - V.fillRandom(0, random, NB_BYTES_GFqv); - if (HFEvr8 != 0) // except bluegemss256, cyangemss256, magentagemss192 - { - /* Clean the last word */ - V.setAnd(NB_WORD_GFqv - 1, HFE_MASKv); - } - /* Evaluation of the constant, quadratic map with v vinegars */ - evalMQSv_unrolled_gf2(F, V, sk_HFE.F_HFEv); - for (i = 0; i <= HFEDegI; ++i) - { - vecMatProduct(Buffer_NB_WORD_GFqn, V, new Pointer(linear_coefs[i], NB_WORD_GFqn), FunctionParams.V); - F.setRangeFromXor(NB_WORD_GFqn * (((i * (i + 1)) >>> 1) + 1), linear_coefs[i], 0, Buffer_NB_WORD_GFqn, 0, NB_WORD_GFqn); - } - } - while (chooseRootHFE_gf2nx(DR, sk_HFE.F_struct, U) == 0); - /* Add the v bits to DR */ - DR.setXor(NB_WORD_GFqn - 1, V.get() << HFEnr); - DR.setRangeRotate(NB_WORD_GFqn, V, 0, NB_WORD_GFqv - 1, 64 - HFEnr); - if (NB_WORD_GFqn + NB_WORD_GFqv == NB_WORD_GF2nv)// for some 256 versions - { - DR.set(NB_WORD_GFqn + NB_WORD_GFqv - 1, V.get(NB_WORD_GFqv - 1) >>> (64 - HFEnr)); - } - /* Finally: compute Sk||Xk = v * S^(-1) */ - vecMatProduct(sm, DR, sk_HFE.S, FunctionParams.NV); - if (k != NB_ITE) - { - /* Store X1 in the signature */ - index = NB_WORD_GF2nv + (NB_ITE - 1 - k) * NB_WORD_GF2nvm; - sm.copyFrom(index, sm, NB_WORD_GF2nv - NB_WORD_GF2nvm, NB_WORD_GF2nvm); - /* To put zeros at the beginning of the first word of X1 */ - if (HFEmr != 0) - { - sm.setAnd(index, ~MASK_GF2m); - } - /* Compute H2 = H(H1) */ - byte[] Hi_bytes = Hi.toBytes(SIZE_DIGEST); - getSHA3Hash(Hi1, 0, SIZE_DIGEST, Hi_bytes, 0, Hi_bytes.length, Hi_bytes); - /* Permutation of pointers */ - Hi1.swap(Hi); - } - } - if (NB_ITE == 1) - { - /* Take the (n+v) first bits */ - byte[] sm64 = sm.toBytes(sm.getLength() << 3); - System.arraycopy(sm64, 0, sm8, 0, NB_BYTES_GFqnv); - } - else - { - compress_signHFE(sm8, sm); - } - } - - /* Precomputation for one secret-key */ - private void precSignHFE(SecretKeyHFE sk_HFE, Pointer[] linear_coefs, byte[] sk) - { - Pointer F_cp; - int i, j; - precSignHFESeed(sk_HFE, sk); - initListDifferences_gf2nx(sk_HFE.F_struct.L); - Pointer F_HFEv = new Pointer(sk_HFE.F_HFEv); - final int NB_UINT_HFEPOLY = NB_COEFS_HFEPOLY * NB_WORD_GFqn; - Pointer F = new Pointer(NB_UINT_HFEPOLY); - /* X^(2^0) */ - linear_coefs[0] = new Pointer(F_HFEv, MQv_GFqn_SIZE); - /* X^(2^1) */ - F_HFEv.changeIndex(linear_coefs[0], MLv_GFqn_SIZE); - F_cp = new Pointer(F, 2 * NB_WORD_GFqn); - for (i = 0; i < HFEDegI; ++i) - { - /* Copy i quadratic terms */ - j = i - (((((1 << i) + 1) > HFE_odd_degree) && ENABLED_REMOVE_ODD_DEGREE) ? 1 : 0); - F_cp.copyFrom(F_HFEv, j * NB_WORD_GFqn); - F_HFEv.move(j * NB_WORD_GFqn); - F_cp.move(j * NB_WORD_GFqn); - /* Store the address of X^(2^(i+1)) */ - linear_coefs[i + 1] = new Pointer(F_HFEv); - /* Linear term is not copied */ - F_HFEv.move(MLv_GFqn_SIZE); - F_cp.move(NB_WORD_GFqn); - } - if (HFEDegJ != 0) //fgemss192 and fgemss256 - { - /* X^(2^HFEDegI + 2^j) */ - j = (((1 << i) + 1) <= HFE_odd_degree) ? 0 : 1; - F_cp.copyFrom(F_HFEv, (HFEDegJ - j) * NB_WORD_GFqn); - } - sk_HFE.F_struct.poly = new Pointer(F); - } - - private void precSignHFESeed(SecretKeyHFE sk_HFE, byte[] sk) - { - Pointer L, U; - int length_tmp = NB_UINT_HFEVPOLY + ((LTRIANGULAR_NV_SIZE + LTRIANGULAR_N_SIZE) << 1); - sk_HFE.sk_uncomp = new Pointer(length_tmp + MATRIXnv_SIZE + MATRIXn_SIZE); - SHAKEDigest shakeDigest = new SHAKEDigest(ShakeBitStrength); - shakeDigest.update(sk, 0, SIZE_SEED_SK); - byte[] sk_uncomp_byte = new byte[(length_tmp) << 3]; - shakeDigest.doFinal(sk_uncomp_byte, 0, sk_uncomp_byte.length); - sk_HFE.sk_uncomp.fill(0, sk_uncomp_byte, 0, sk_uncomp_byte.length); - sk_HFE.S = new Pointer(sk_HFE.sk_uncomp, length_tmp); - sk_HFE.T = new Pointer(sk_HFE.S, MATRIXnv_SIZE); - /* zero padding for the HFEv polynomial F */ - sk_HFE.F_HFEv = new Pointer(sk_HFE.sk_uncomp); - cleanMonicHFEv_gf2nx(sk_HFE.F_HFEv); - /* The random bytes are already generated from a seed */ - L = new Pointer(sk_HFE.sk_uncomp, NB_UINT_HFEVPOLY); - U = new Pointer(L, LTRIANGULAR_NV_SIZE); - cleanLowerMatrix(L, FunctionParams.NV); - cleanLowerMatrix(U, FunctionParams.NV); - /* Generate S^(-1) = L*U */ - mulMatricesLU_gf2(sk_HFE.S, L, U, FunctionParams.NV); - /* The random bytes are already generated from a seed */ - L.move(LTRIANGULAR_NV_SIZE << 1); - U.changeIndex(L, LTRIANGULAR_N_SIZE); - cleanLowerMatrix(L, FunctionParams.N); - cleanLowerMatrix(U, FunctionParams.N); - /* Generate T^(-1) = L*U */ - mulMatricesLU_gf2(sk_HFE.T, L, U, FunctionParams.N); - } - - void cleanMonicHFEv_gf2nx(Pointer F) - { - /* zero padding for the last word of each element of GF(2^n) */ - for (int F_idx = NB_WORD_GFqn - 1; F_idx < NB_UINT_HFEVPOLY; F_idx += NB_WORD_GFqn) - { - F.setAnd(F_idx, MASK_GF2n); - } - } - - private void mulMatricesLU_gf2(Pointer S, Pointer L, Pointer U, FunctionParams functionParams) - { - final int nq, nr; - int iq; - boolean REM; - int S_orig = S.getIndex(); - switch (functionParams) - { - case N: - nq = HFEnq; - nr = HFEnr; - REM = true; - break; - case NV: - nq = HFEnvq; - nr = HFEnvr; - REM = HFEnvr != 0; - break; - default: - throw new IllegalArgumentException("Invalid parameter for MULMATRICESLU_GF2"); - } - /* Computation of S = L*U */ - Pointer L_cp = new Pointer(L); - /* for each row of L (and S) */ - for (iq = 1; iq <= nq; ++iq) - { - LOOPIR(S, L_cp, U, NB_BITS_UINT, nq, nr, iq, REM); - } - LOOPIR(S, L_cp, U, nr, nq, nr, iq, REM); - S.changeIndex(S_orig); - } - - private void LOOPIR(Pointer S, Pointer L_cp, Pointer U, int NB_IT, int nq, int nr, int iq, boolean REM) - { - int jq; - for (int ir = 0; ir < NB_IT; ++ir) - { - Pointer U_cp = new Pointer(U); - /* for each row of U (multiply by the transpose) */ - for (jq = 1; jq <= nq; ++jq) - { - LOOPJR(S, L_cp, U_cp, NB_BITS_UINT, iq, jq); - } - if (REM) - { - LOOPJR(S, L_cp, U_cp, nr, iq, jq); - } - L_cp.move(iq); - } - } - - private void LOOPJR(Pointer S, Pointer L, Pointer U, int NB_IT, int iq, int jq) - { - int mini = Math.min(iq, jq); - S.set(0L); - long tmp; - for (int jr = 0; jr < NB_IT; ++jr) - { - /* Dot product */ - tmp = L.getDotProduct(0, U, 0, mini); - tmp = GeMSSUtils.XORBITS_UINT(tmp); - S.setXor(tmp << jr); - U.move(jq); - } - S.moveIncremental(); - } - - private int setArrayL(int[] L, int k, int pos, int len) - { - for (int j = pos; j < len; ++j) - { - L[k++] = NB_WORD_GFqn << j; - } - return k; - } - - private void initListDifferences_gf2nx(int[] L) - { - int i, k = 2; - L[1] = NB_WORD_GFqn; - for (i = 0; i < HFEDegI; ++i) - { - if (ENABLED_REMOVE_ODD_DEGREE && ((1 << i) + 1) > HFE_odd_degree) - { - /* j=0 */ - if (i != 0) - { - L[k++] = NB_WORD_GFqn << 1; - } - /* j=1 to j=i */ - k = setArrayL(L, k, 1, i); - } - else - { - /* j=0 */ - L[k++] = NB_WORD_GFqn; - /* j=1 to j=i */ - k = setArrayL(L, k, 0, i); - } - } - if (HFEDegJ != 0) - { - if (ENABLED_REMOVE_ODD_DEGREE && ((1 << i) + 1) > HFE_odd_degree) - { - /* j=0 */ - L[k++] = NB_WORD_GFqn << 1; - /* j=1 to j=i */ - setArrayL(L, k, 1, HFEDegJ - 1); - } - else - { - /* j=0*/ - L[k++] = NB_WORD_GFqn; - setArrayL(L, k, 0, HFEDegJ - 1); - } - } - } - - void evalMQSv_unrolled_gf2(Pointer c, Pointer m, Pointer pk) - { - Pointer x = new Pointer(HFEv); - final int NB_VARq = HFEv >>> 6; - final int NB_VARr = HFEv & 63; - final int NB_WORD_EQ = (HFEn >>> 6) + ((HFEn & 63) != 0 ? 1 : 0); - int pk_orig = pk.getIndex(); - Pointer tmp = new Pointer(NB_WORD_EQ); - int i, j, k; - /* Compute one time all -((xi>>1)&UINT_1) */ - for (i = 0, k = 0; i < NB_VARq; ++i) - { - k = x.setRange_xi(m.get(i), k, NB_BITS_UINT); - } - if (NB_VARr != 0) - { - x.setRange_xi(m.get(i), k, NB_VARr); - } - /* Constant cst_pk */ - c.copyFrom(pk, NB_WORD_EQ); - pk.move(NB_WORD_EQ); - /* for each row of the quadratic matrix of pk, excepted the last block */ - for (i = 0; i < HFEv; ++i) - { - /* for each column of the quadratic matrix of pk */ - /* xj=xi */ - tmp.copyFrom(pk, NB_WORD_EQ); - pk.move(NB_WORD_EQ); - for (j = i + 1; j < HFEv - 3; j += 4) - { - tmp.setXorRangeAndMaskMove(pk, NB_WORD_EQ, x.get(j)); - tmp.setXorRangeAndMaskMove(pk, NB_WORD_EQ, x.get(j + 1)); - tmp.setXorRangeAndMaskMove(pk, NB_WORD_EQ, x.get(j + 2)); - tmp.setXorRangeAndMaskMove(pk, NB_WORD_EQ, x.get(j + 3)); - } - for (; j < HFEv; ++j) - { - tmp.setXorRangeAndMaskMove(pk, NB_WORD_EQ, x.get(j)); - } - /* Multiply by xi */ - c.setXorRangeAndMask(tmp, NB_WORD_EQ, x.get(i)); - } - pk.changeIndex(pk_orig); - } - - private int chooseRootHFE_gf2nx(Pointer root, SecretKeyHFE.complete_sparse_monic_gf2nx F, Pointer U) - { - Pointer hash = new Pointer(SIZE_DIGEST_UINT); - Pointer poly = new Pointer(((HFEDeg << 1) - 1) * NB_WORD_GFqn); - Pointer poly2 = new Pointer((HFEDeg + 1) * NB_WORD_GFqn); - Pointer cst = new Pointer(NB_WORD_GFqn); - /* Constant term of F-U */ - cst.setRangeFromXor(F.poly, U, NB_WORD_GFqn); - /* X^(2^n) - X mod (F-U) */ - if (HFEDeg <= 34 || (HFEn > 196 && HFEDeg < 256)) - { - //HFEDeg<=34: redgemss128, redgemss192, redgemss256, magentagemss128, magentagemss192, magentagemss256 - //HFEn>196: bluegemss192, bluegemss256, cyangemss192, cyangemss256, fgemss128, dualmodems128, dualmodems192, - // dualmodems256 - frobeniusMap_multisqr_HFE_gf2nx(poly, F, cst); - } - else //gemss128, gemss192, gemss256, whitegemss128, whitegemss192, whitegemss256, fgemss192, fgemss256, bluegemss128, cyangemss128 - { - /* For i=HFEDegI, we have X^(2^i) mod (F-U) = X^(2^i). The first term of degree >= HFEDeg is X^(2^(HFEDegI+1)): - 2^(HFEDegI+1) >= HFEDeg but 2^HFEDegI < HFEDeg. So, we begin at the step i=HFEDegI+1 */ - /* Compute X^(2^(HFEDegI+1)) mod (F-U) */ - /* Step 1: compute X^(2^(HFEDegI+1)) */ - int i = 2 << HFEDegI; - /* Xqn is initialized to 0 with calloc, so the multiprecision word is initialized to 1 just by setting the first word */ - poly.set(i * NB_WORD_GFqn, 1L); - /* Step 2: reduction of X^(2^(HFEDegI+1)) modulo (F-U) */ - divsqr_r_HFE_cstdeg_gf2nx(poly, i, i, HFEDeg, F, cst); - for_sqr_divsqr(poly, HFEDegI + 1, HFEn, F, cst); - } - /* (X^(2^n) mod (F-U)) - X */ - poly.setXor(NB_WORD_GFqn, 1L); - /* Initialize to F */ - int l = poly2.getIndex(); - /* i=0: constant of F */ - poly2.copyFrom(F.poly, NB_WORD_GFqn); - for_copy_move(poly2, F); - poly2.changeIndex(l); - /* Leading term: 1 */ - poly2.set(HFEDeg * NB_WORD_GFqn, 1L); - /* Initialize to F-U */ - poly2.setXorRange(U, NB_WORD_GFqn); - l = poly.getD_for_not0_or_plus(NB_WORD_GFqn, HFEDeg - 1); - /* GCD(F-U, X^(2^n)-X mod (F-U)) */ - l = gcd_gf2nx(poly2, HFEDeg, poly, l); - if (buffer != 0) //buffer is the result from gcd_gf2nx, it's the flag to swap - { - poly.swap(poly2); - } - if (poly.is0_gf2n(0, NB_WORD_GFqn) == 0) - { - /* The gcd is a constant (!=0) */ - /* Irreducible: 0 root */ - /* l=0; */ - return 0; - } - /* poly2 is the gcd */ - /* Here, it becomes monic */ - convMonic_gf2nx(poly2, l); - Pointer roots = new Pointer(l * NB_WORD_GFqn); - findRootsSplit_gf2nx(roots, poly2, l); - if (l == 1) - { - /* One root */ - root.copyFrom(roots, NB_WORD_GFqn); - } - else - { - /* Sort the roots */ - fast_sort_gf2n(roots, l); - /* Choose a root with a determinist hash */ - getSHA3Hash(hash, 0, Sha3BitStrength >>> 3, U.toBytes(NB_BYTES_GFqn), 0, - NB_BYTES_GFqn, new byte[Sha3BitStrength >>> 3]); - root.copyFrom(0, roots, (int)remainderUnsigned(hash.get(), l) * NB_WORD_GFqn, NB_WORD_GFqn); - } - return l; - } - - private int gcd_gf2nx(Pointer A, int da, Pointer B, int db) - { - Pointer inv = new Pointer(NB_WORD_GFqn); - Pointer tmp; - /* *b = 0: B is the last remainder - *b = 1: A is the last remainder */ - buffer = 0; - while (db != 0) - { - /* Computation of A = A mod B, of degree da */ - /* Minimizes the number of multiplications by an inverse */ - /* 2db > da */ - if ((db << 1) > da) - { - /* At most da-db+1 multiplications by an inverse */ - da = div_r_gf2nx(A, da, B, db); - } - else - { - /* B becomes monic: db multiplications by an inverse */ - inv_gf2n(inv, B, db * NB_WORD_GFqn); - B.set1_gf2n(db * NB_WORD_GFqn, NB_WORD_GFqn); - for_mul(B, inv, db - 1); - da = div_r_monic_gf2nx(A, da, B, db); - } - /* Swaps A and B */ - tmp = A; - A = B; - B = tmp; - /* Swaps da and db */ - int tmp_word = da; - da = db; - db = tmp_word; - /* 0 becomes 1 and 1 becomes 0 */ - buffer = 1 - buffer; - } - return da; - } - - private void for_mul(Pointer res_orig, Pointer inv, int start) - { - Pointer res = new Pointer(res_orig, start * NB_WORD_GFqn); - for (int i = start; i != -1; --i) - { - mul_gf2n(res, res, inv); - res.move(-NB_WORD_GFqn); - } - } - - /** - * @return The degree of Xqn. - * @brief Computation of (X^(2^n) - X) mod (F-U). - * @param[out] Xqn Xqn = (X^(2^n) - X) mod (F.poly-U) in GF(2^n)[X]. - * @param[in] F A HFE polynomial in GF(2^n)[X] stored with a sparse rep. - * @param[in] U An element of GF(2^n). - * @remark Requires to allocate (2*HFEDeg-1)*NB_WORD_GFqn words for Xqn. - * @remark Requirement: F is monic. - * @remark Requirement: F.L must be initialized with initListDifferences_gf2nx. - * @remark Constant-time implementation. - */ - private void frobeniusMap_multisqr_HFE_gf2nx(Pointer Xqn, SecretKeyHFE.complete_sparse_monic_gf2nx F, Pointer cst) - { - Pointer Xqn_cp = new Pointer(); - Pointer Xqn_sqr = new Pointer(HFEDeg * NB_WORD_GFqn); - Pointer current_coef = new Pointer(); - int i, j, k; - /* Table of the X^(k*2^II) mod F. */ - Pointer table = new Pointer((KX * HFEDeg + POW_II) * NB_WORD_GFqn); - /* j=POW_II*KP-D, we reduce X^(D+j) mod F. */ - j = POW_II * KP - HFEDeg; - /* i=0: constant of F */ - Pointer table_cp = new Pointer(table, NB_WORD_GFqn * j); - table_cp.copyFrom(cst, NB_WORD_GFqn); - for_copy_move(table_cp, F); - /* Second step: we compute X^(KP*(2^II)-D)*(F - X^D) mod F */ - /* We reduce one by one the coefficients leading_coef*X^(D+j) mod F, - by using X^(D+j) = X^j * X^D = X^j * (F-X^D) mod F. */ - divsqr_r_HFE_cstdeg_gf2nx(table, j - 1 + HFEDeg, j - 1, 0, F, cst); - /* Computation of the other elements of the table: X^(k*(2^II)) mod F. - X^(k*(2^II)) = (X^((k-1)*(2^II)) mod F) * X^(2^II) mod F. */ - for (k = KP + 1; k < HFEDeg; ++k) - { - /* Update the current polynomial */ - table_cp.changeIndex(table, HFEDeg * NB_WORD_GFqn); - /* Multiplication of (X^((k-1)*(2^II)) mod F) by X^(2^II) */ - table_cp.setRangeClear(0, POW_II * NB_WORD_GFqn); - table_cp.copyFrom(POW_II * NB_WORD_GFqn, table, 0, HFEDeg * NB_WORD_GFqn); - /* Update the current polynomial */ - table.changeIndex(table_cp); - /* Reduction of (X^((k-1)*(2^II)) mod F) * X^(2^II) modulo F */ - /* We reduce one by one the coefficients leading_coef*X^(D+j) mod F, - by using X^(D+j) = X^j * X^D = X^j * (F-X^D) mod F. */ - divsqr_r_HFE_cstdeg_gf2nx(table, POW_II - 1 + HFEDeg, POW_II - 1, 0, F, cst); - } - table.indexReset(); - /* X^(2^(HFEDegI+II)) = X^( (2^HFEDegI) * (2^II)) */ - /* We take the polynomial from the table */ - Xqn.copyFrom(0, table, (((1 << HFEDegI) - KP) * HFEDeg) * NB_WORD_GFqn, HFEDeg * NB_WORD_GFqn); - for (i = 0; i < ((HFEn - HFEDegI - II) / II); ++i) - { - /* Step 1: Xqn^(2^II) with II squarings */ - /* Xqn_sqr is the list of the coefficients of Xqn at the power 2^II */ - /* j=0, first squaring */ - loop_sqr(Xqn_sqr, Xqn); - /* The other squarings */ - for (j = 1; j < II; ++j) - { - loop_sqr(Xqn_sqr, Xqn_sqr); - } - /* Step 2: Reduction of Xqn^(2^II) modulo F, by using the table. Multiplication of ((X^(k*2^II)) mod F) by - the current coefficient. */ - /* j=KP, initialization of the new Xqn */ - current_coef.changeIndex(Xqn_sqr, KP * NB_WORD_GFqn); - table_cp.changeIndex(table); - Xqn_cp.changeIndex(Xqn); - for (k = 0; k < HFEDeg; ++k) - { - mul_gf2n(Xqn_cp, table_cp, current_coef); - Xqn_cp.move(NB_WORD_GFqn); - table_cp.move(NB_WORD_GFqn); - } - for (j = KP + 1; j < HFEDeg; ++j) - { - current_coef.move(NB_WORD_GFqn); - Xqn_cp.changeIndex(Xqn); - for (k = 0; k < HFEDeg; ++k) - { - mul_rem_xorrange(Xqn_cp, table_cp, current_coef); - Xqn_cp.move(NB_WORD_GFqn); - table_cp.move(NB_WORD_GFqn); - } - } - /* The coefficients such as X^(k*2^II) mod F = X^(k*2^II). */ - for (j = 0; j < KP; ++j) - { - /* (X^j)^II */ - Xqn.setXorRange(j * POW_II * NB_WORD_GFqn, Xqn_sqr, j * NB_WORD_GFqn, NB_WORD_GFqn); - } - } - for_sqr_divsqr(Xqn, 0, (HFEn - HFEDegI) % II, F, cst); - } - - private void for_sqr_divsqr(Pointer Xqn, int start, int end, SecretKeyHFE.complete_sparse_monic_gf2nx F, Pointer cst) - { - for (int i = start; i < end; ++i) - { - /* Step 1: (X^(2^i) mod (F-U))^2 = X^(2^(i+1)) */ - sqr_gf2nx(Xqn, HFEDeg - 1); - /* Step 2: X^(2^(i+1)) mod (F-U) */ - divsqr_r_HFE_cstdeg_gf2nx(Xqn, (HFEDeg - 1) << 1, (HFEDeg - 1) << 1, HFEDeg, F, cst); - } - } - - private void loop_sqr(Pointer Xqn_sqr, Pointer Xqn) - { - for (int k = 0; k < HFEDeg; ++k) - { - sqr_gf2n(Xqn_sqr, k * NB_WORD_GFqn, Xqn, k * NB_WORD_GFqn); - } - } - - private void for_copy_move(Pointer table, SecretKeyHFE.complete_sparse_monic_gf2nx F) - { - for (int i = 1, shift = NB_WORD_GFqn; i < NB_COEFS_HFEPOLY; ++i, shift += NB_WORD_GFqn) - { - table.move(F.L[i]); - table.copyFrom(0, F.poly, i * NB_WORD_GFqn, NB_WORD_GFqn); - } - } - - private void divsqr_r_HFE_cstdeg_gf2nx(Pointer poly, int idx, int start, int end, SecretKeyHFE.complete_sparse_monic_gf2nx F, Pointer cst) - { - Pointer leading_coef = new Pointer(poly, idx * NB_WORD_GFqn); - Pointer res = new Pointer(); - for (int j = start; j >= end; --j) - { - res.changeIndex(leading_coef, -HFEDeg * NB_WORD_GFqn); - /* i=0: Constant of F-U */ - mul_rem_xorrange(res, leading_coef, cst); - for (int i = 1; i < NB_COEFS_HFEPOLY; ++i) - { - res.move(F.L[i]); - mul_rem_xorrange(res, leading_coef, F.poly, i * NB_WORD_GFqn); - } - leading_coef.move(-NB_WORD_GFqn); - } - } - - private void sqr_gf2nx(Pointer poly, int d) - { - int i = NB_WORD_GFqn * d; - /* Pointer on the last coefficient of poly */ - int poly_orig = poly.getIndex(); - poly.move(i); - /* A pointer on X^(2*(d-i)) */ - /* Pointer on the last coefficient of the square of poly */ - Pointer poly_2i = new Pointer(poly, i); - /* Square of each coefficient, a_i X^i becomes a_i^2 X^(2i). Order: X^d X^(d-1) X^(d-2) ... X^(d-i) ... X^2 X^1 */ - for (i = 0; i < d; ++i) - { - sqr_gf2n(poly_2i, poly); - poly.move(-NB_WORD_GFqn); - poly_2i.move(-NB_WORD_GFqn); - /* The coefficient of X^(2(d-i)-1) is set to 0 (odd exponent) */ - poly_2i.setRangeClear(0, NB_WORD_GFqn); - poly_2i.move(-NB_WORD_GFqn); - } - /* Square of the coefficient of X^0 */ - sqr_gf2n(poly, poly); - poly.changeIndex(poly_orig); - } - - int div_r_gf2nx(Pointer A, int da, Pointer B, int db) - { - Pointer leading_coef = new Pointer(NB_WORD_GFqn); - Pointer inv = new Pointer(NB_WORD_GFqn); - Pointer res = new Pointer(A); - /* Compute the inverse of the leading term of B */ - inv_gf2n(inv, B, db * NB_WORD_GFqn); - /* modular reduction */ - while (da >= db) - { - /* Search the current degree of A */ - da = A.searchDegree(da, db, NB_WORD_GFqn); - if (da < db) - { - /* The computation of the remainder is finished */ - break; - } - res.changeIndex((da - db) * NB_WORD_GFqn); - mul_gf2n(leading_coef, A, da * NB_WORD_GFqn, inv); - /* i=0: Constant of B */ - for_mul_rem_xor_move(res, leading_coef, B, 0, db); - /* The leading term becomes 0 */ - /* useless because every coefficients >= db will be never used */ - --da; - } - /* Here, da=db-1 */ - da = A.searchDegree(da, 1, NB_WORD_GFqn); - /* Degree of the remainder */ - return da; - } - - private void div_q_monic_gf2nx(Pointer A, int da, Pointer B, int db) - { - Pointer leading_coef = new Pointer(); - Pointer res = new Pointer(); - int i; - /* modular reduction */ - while (da >= db) - { - /* Search the current degree of A */ - da = A.searchDegree(da, db, NB_WORD_GFqn); - if (da < db) - { - /* The computation of the remainder is finished */ - break; - } - leading_coef.changeIndex(A, da * NB_WORD_GFqn); - i = Math.max(0, (db << 1) - da); - res.changeIndex(A, (da - db + i) * NB_WORD_GFqn); - for_mul_rem_xor_move(res, leading_coef, B, i, db); - --da; - } - } - - private int div_r_monic_gf2nx(Pointer A, int da, Pointer B, int db) - { - Pointer leading_coef = new Pointer(); - Pointer res = new Pointer(); - /* modular reduction */ - while (da >= db) - { - /* Search the current degree of A */ - da = A.searchDegree(da, db, NB_WORD_GFqn); - if (da < db) - { - /* The computation of the remainder is finished */ - break; - } - leading_coef.changeIndex(A, da * NB_WORD_GFqn); - res.changeIndex(leading_coef, -db * NB_WORD_GFqn); - for_mul_rem_xor_move(res, leading_coef, B, 0, db); - /* The leading term of A is a term of the quotient */ - --da; - } - if (da == -1) - { - ++da; - } - /* Here, da=db-1 */ - da = A.searchDegree(da, 1, NB_WORD_GFqn); - /* Degree of the remainder */ - return da; - } - - private void for_mul_rem_xor_move(Pointer res, Pointer leading_coef, Pointer B, int start, int end) - { - for (int i = start, shift = start * NB_WORD_GFqn; i < end; ++i, shift += NB_WORD_GFqn) - { - mul_rem_xorrange(res, leading_coef, B, shift); - res.move(NB_WORD_GFqn); - } - } - - private void inv_gf2n(Pointer res, Pointer A, int AOff) - { - int A_orig = A.getIndex(); - A.move(AOff); - Pointer multi_sqr = new Pointer(NB_WORD_GFqn); - int nb_sqr, i, j; - /* i=pos */ - res.copyFrom(A, NB_WORD_GFqn); - for (i = HFEn_1rightmost - 1; i != (-1); --i) - { - nb_sqr = (HFEn - 1) >>> (i + 1); - /* j=0 */ - sqr_gf2n(multi_sqr, res); - for (j = 1; j < nb_sqr; ++j) - { - sqr_gf2n(multi_sqr, multi_sqr); - } - mul_gf2n(res, res, multi_sqr); - if ((((HFEn - 1) >>> i) & 1) != 0) - { - sqr_gf2n(multi_sqr, res); - mul_gf2n(res, A, multi_sqr); - } - } - sqr_gf2n(res, res); - A.changeIndex(A_orig); - } - - private void convMonic_gf2nx(Pointer F, int d) - { - Pointer inv = new Pointer(NB_WORD_GFqn); - int F_orig = F.getIndex(); - F.move(d * NB_WORD_GFqn); - /* At this step, F is the pointer on the term X^d of F */ - inv_gf2n(inv, F, 0); - F.set1_gf2n(0, NB_WORD_GFqn); - for (int i = d - 1; i != -1; --i) - { - F.move(-NB_WORD_GFqn); - /* At this step, F is the pointer on the term X^i of F */ - mul_gf2n(F, F, inv); - } - F.changeIndex(F_orig); - } - - private void findRootsSplit_gf2nx(Pointer roots, Pointer f, int deg) - { - if (deg == 1) - { - /* Extract the unique root which is the constant of f */ - roots.copyFrom(f, NB_WORD_GFqn); - return; - } - if ((HFEn & 1) != 0 && deg == 2) - { - findRootsSplit2_HT_gf2nx(roots, f); - return; - } - int b, l, d; - Pointer poly_frob = new Pointer(((deg << 1) - 1) * NB_WORD_GFqn); - /* poly_trace is modulo f, this degree is strictly less than deg */ - Pointer poly_trace = new Pointer(deg * NB_WORD_GFqn); - /* f_cp a copy of f */ - Pointer f_cp = new Pointer((deg + 1) * NB_WORD_GFqn); - Pointer inv = new Pointer(NB_WORD_GFqn); - do - { - /* Set poly_frob to zero */ - poly_frob.setRangeClear(0, ((deg << 1) - 1) * NB_WORD_GFqn); - /* Set poly_trace to zero */ - poly_trace.setRangeClear(0, deg * NB_WORD_GFqn); - /* Initialization to rX */ - /* Probability 2^(-n) to find 0 with a correct RNG */ - do - { - poly_trace.fillRandom(NB_WORD_GFqn, random, NB_BYTES_GFqn); - /* Clean the last word (included the zero padding) */ - poly_trace.setAnd((NB_WORD_GFqn << 1) - 1, MASK_GF2n); - } - while (poly_trace.is0_gf2n(NB_WORD_GFqn, NB_WORD_GFqn) != 0); - /* copy of f because the gcd modifies f */ - f_cp.copyFrom(f, (deg + 1) * NB_WORD_GFqn); - traceMap_gf2nx(poly_trace, poly_frob, f_cp, deg); - /* Degree of poly_trace */ - d = poly_trace.searchDegree(deg - 1, 1, NB_WORD_GFqn); - l = gcd_gf2nx(f_cp, deg, poly_trace, d); - b = buffer; - } - while ((l == 0) || (l == deg)); - if (b != 0) - { - poly_trace.swap(f_cp); - } - /* Here, f_cp is a non-trivial divisor of degree l */ - /* f_cp is the gcd */ - /* Here, it becomes monic */ - inv_gf2n(inv, f_cp, l * NB_WORD_GFqn); - f_cp.set1_gf2n(l * NB_WORD_GFqn, NB_WORD_GFqn); - for_mul(f_cp, inv, l - 1); - /* f = f_cp * Q */ - /* This function destroyes f */ - div_q_monic_gf2nx(f, deg, f_cp, l); - /* Necessarily, the polynomial f is null here */ - /* f_cp is monic */ - /* We can apply findRootsSplit_gf2nx recursively */ - findRootsSplit_gf2nx(roots, f_cp, l); - /* f is monic and f_cp is monic so Q is monic */ - /* We can apply findRootsSplit_gf2nx recursively */ - findRootsSplit_gf2nx(new Pointer(roots, l * NB_WORD_GFqn), new Pointer(f, l * NB_WORD_GFqn), deg - l); - } - - void findRootsSplit2_HT_gf2nx(Pointer roots, Pointer f) - { - Pointer c = new Pointer(NB_WORD_GFqn); - Pointer alpha = new Pointer(NB_WORD_GFqn); - int f_orig = f.getIndex(); - sqr_gf2n(c, 0, f, NB_WORD_GFqn); - inv_gf2n(roots, c, 0); - mul_gf2n(c, f, roots); - findRootsSplit_x2_x_c_HT_gf2nx(alpha, c); - f.move(NB_WORD_GFqn); - mul_gf2n(roots, alpha, f); - roots.setRangeFromXor(NB_WORD_GFqn, roots, 0, f, 0, NB_WORD_GFqn); - f.changeIndex(f_orig); - } - - void findRootsSplit_x2_x_c_HT_gf2nx(Pointer root, Pointer c) - { - Pointer alpha = new Pointer(NB_WORD_GFqn); - final int e = (HFEn + 1) >>> 1; - int i, j, e2; - /* i=pos */ - root.copyFrom(c, NB_WORD_GFqn); - for (i = HFEn1h_rightmost, e2 = 1; i != -1; --i) - { - e2 <<= 1; - /* j=0 */ - sqr_gf2n(alpha, root); - for (j = 1; j < e2; ++j) - { - sqr_gf2n(alpha, alpha); - } - root.setXorRange(alpha, NB_WORD_GFqn); - e2 = e >>> i; - if ((e2 & 1) != 0) - { - sqr_gf2n(alpha, root); - sqr_gf2n(root, alpha); - root.setXorRange(c, NB_WORD_GFqn); - } - } - } - - private void traceMap_gf2nx(Pointer poly_trace, Pointer poly_frob, Pointer f, int deg) - { - int i = 1; - /* (2^i) < deg does not require modular reduction by f */ - for (; (1 << i) < deg; ++i) - { - /* poly_trace += ((rX)^(2^i)) mod f. Here, ((rX)^(2^i)) mod f == (rX)^(2^i) since (2^i) < deg */ - sqr_gf2n(poly_trace, NB_WORD_GFqn << i, poly_trace, NB_WORD_GFqn << (i - 1)); - } - /* Here, (rX)^(2^i) is the first time where we need modular reduction */ - if (i < HFEn) - { - /* poly_frob = (rX)^(2^i) = ((rX)^(2^(i-1)))^2 */ - sqr_gf2n(poly_frob, NB_WORD_GFqn << i, poly_trace, NB_WORD_GFqn << (i - 1)); - /* poly_frob = ((rX)^(2^i)) mod f */ - div_r_monic_cst_gf2nx(poly_frob, 1 << i, f, deg); - /* poly_trace += ((rX)^(2^i)) mod f */ - poly_trace.setXorRange(poly_frob, deg * NB_WORD_GFqn); - for (++i; i < HFEn; ++i) - { - /* poly_frob = (rX)^(2^i) = ((rX)^(2^(i-1)) mod f)^2 */ - sqr_gf2nx(poly_frob, deg - 1); - /* poly_frob = ((rX)^(2^i)) mod f */ - div_r_monic_cst_gf2nx(poly_frob, (deg - 1) << 1, f, deg); - /* poly_trace += ((rX)^(2^i)) mod f */ - poly_trace.setXorRange(poly_frob, deg * NB_WORD_GFqn); - } - } - } - - private void div_r_monic_cst_gf2nx(Pointer A, int da, Pointer B, int db) - { - Pointer res = new Pointer(); - int A_orig = A.getIndex(); - /* Pointer on the current leading term of A */ - A.move(da * NB_WORD_GFqn); - for (; da >= db; --da) - { - res.changeIndex(A, -db * NB_WORD_GFqn); - for_mul_rem_xor_move(res, A, B, 0, db); - /* useless because every coefficients >= db will be never used */ - A.move(-NB_WORD_GFqn); - } - A.changeIndex(A_orig); - } - - /** - * @brief Sort in ascending order of a vector in GF(2^n), in-place. - * @details The fastest constant-time sort of this library. - * The elements of GF(2^n) are seen as unsigned integers. - * @param[in,out] tab A vector of l elements of GF(2^n). Will be sorted. - * @param[in] l The length of tab. - * @remark Requirement: l>1. - * @remark Constant-time implementation when l is not secret. - */ - void fast_sort_gf2n(Pointer tab, int l) - { - Pointer tmp = new Pointer(NB_WORD_GFqn); - Pointer prod = new Pointer(NB_WORD_GFqn); - Pointer tab_i = new Pointer(); - Pointer tab_ipa = new Pointer(); - /* pow2_prev,pa,pb,pc are powers of two */ - int i, quo, rem, pow2_prev, pa, pb; - /* The power of 2 before l, which is 1< 1; pa >>>= 1) - { - /* Number of complete blocks */ - quo = l / (pa << 1); - /* Size of the remainder block */ - /* Impact on the sort */ - rem = Math.max(0, l - (pa << 1) * quo - pa); - tab_i.changeIndex(tab); - tab_ipa.changeIndex(tab, pa * NB_WORD_GFqn); - for (i = 0; i < quo; ++i) - { - for_casct_move(tab_i, tab_ipa, prod, pa, 1); - tab_i.move(pa * NB_WORD_GFqn); - tab_ipa.move(pa * NB_WORD_GFqn); - } - for_casct_move(tab_i, tab_ipa, prod, rem, 1); - for (pb = pow2_prev, i = 0; pb > pa; pb >>>= 1) - { - /* l>1 implies pb 1; pb >>>= 1) - { - /* l>1 implies pb 1; pc >>>= 1) - { - tab_i.changeIndex(tab, (i + pc) * NB_WORD_GFqn); - CMP_AND_SWAP_CST_TIME(tmp, tab_i, prod); - } - } - - private void for_casct_move(Pointer tab_i, Pointer tab_ipa, Pointer prod, int len, int shift) - { - int move = NB_WORD_GFqn * shift; - for (int j = 0; j < len; j += shift) - { - CMP_AND_SWAP_CST_TIME(tab_i, tab_ipa, prod); - tab_i.move(move); - tab_ipa.move(move); - } - } - - private void CMP_AND_SWAP_CST_TIME(Pointer tab, Pointer tab_j, Pointer prod) - { - long d, bo, mask; - int i; - /* Compute d the larger index such as a[d]!=b[d], in constant-time */ - for (i = NB_WORD_GFqn - 1, mask = 0L, d = 0L; i > 0; --i) - { - bo = tab_j.get(i) ^ tab.get(i); - bo = GeMSSUtils.ORBITS_UINT(bo); - mask |= bo; - d += mask; - } - /* Return a[d]>> 3] ^= ((sm64[sm64_cp] & 0xFF) >>> HFEmr8) << (nb_bits & 7); - /* Number of bits to complete the first byte of sm8 */ - nb_rem = ((val_n - VAL_BITS_M)); - if (nb_rem >= 0) - { - /* We take the next byte since we used VAL_BITS_M bits */ - sm64_cp++; - } - if (nb_rem > 0) - { - nb_bits += VAL_BITS_M; - sm8[nb_bits >>> 3] ^= (sm64[sm64_cp] & 0xFF) << (nb_bits & 7); - nb_bits += nb_rem; - } - else - { - nb_bits += val_n; - } - } - else - { - /* We can take 8 bits, and we want at most 7 bits. */ - sm8[nb_bits >>> 3] ^= (sm64[sm64_cp] & 0xFF) << (nb_bits & 7); - nb_bits += val_n; - } - } - /* Other bytes of sm8 */ - nb_rem2 = HFEDELTA + HFEv - val_n; - /*nb_rem2 can be zero only in this case */ - /* Number of bits used of sm64, mod 8 */ - nb_rem_m = (HFEm + val_n) & 7; - /* Other bytes */ - if (nb_rem_m != 0) - { - /* -1 to take the ceil of /8, -1 */ - for (k2 = 0; k2 < ((nb_rem2 - 1) >>> 3); ++k2) - { - sm8[nb_bits >>> 3] = (byte)(((sm64[sm64_cp] & 0xFF) >>> nb_rem_m) ^ ((sm64[++sm64_cp] & 0xFF) << (8 - nb_rem_m))); - nb_bits += 8; - } - /* The last byte of sm8, between 1 and 8 bits to put */ - sm8[nb_bits >>> 3] = (byte)((sm64[sm64_cp++] & 0xFF) >>> nb_rem_m); - /* nb_rem2 between 1 and 8 bits */ - nb_rem2 = ((nb_rem2 + 7) & 7) + 1; - if (nb_rem2 > (8 - nb_rem_m)) - { - sm8[nb_bits >>> 3] ^= (byte)((sm64[sm64_cp++] & 0xFF) << (8 - nb_rem_m)); - } - nb_bits += nb_rem2; - } - else - { - /* We are at the beginning of the bytes of sm8 and sm64 */ - /* +7 to take the ceil of /8 */ - for (k2 = 0; k2 < ((nb_rem2 + 7) >>> 3); ++k2) - { - sm8[nb_bits >>> 3] = sm64[sm64_cp++]; - nb_bits += 8; - } - /* The last byte has AT MOST 8 bits. */ - nb_bits -= (8 - (nb_rem2 & 7)) & 7; - } - /* We complete the word. Then we search the first byte. */ - sm64_cp += ((8 - (NB_BYTES_GFqnv & 7)) & 7) + (HFEmq8 & 7); - } - } - - void convMQS_one_to_last_mr8_equations_gf2(byte[] pk_U, PointerUnion pk_cp) - { - int ir, jq, jr, tmp, pk_U_cp = 0; - /* To have equivalence between *pk and pk[iq] */ - pk_cp.moveNextBytes(HFEmq8); - PointerUnion pk_cp2 = new PointerUnion(pk_cp); - final int HFENq8 = NB_MONOMIAL_PK >>> 3; - /* For each equation of result */ - for (ir = 0; ir < HFEmr8; ++ir) - { - /* Loop on every monomials */ - pk_cp2.changeIndex(pk_cp); - for (jq = 0; jq < HFENq8; ++jq) - { - /* jr=0 */ - tmp = ((pk_cp2.getByte() >>> ir) & 1); - pk_cp2.moveNextBytes(NB_BYTES_GFqm); - for (jr = 1; jr < 8; ++jr) - { - tmp ^= ((pk_cp2.getByte() >>> ir) & 1) << jr; - pk_cp2.moveNextBytes(NB_BYTES_GFqm); - } - pk_U[pk_U_cp++] = (byte)tmp; - } - if (HFENr8 != 0) - { - /* jr=0 */ - long tmp1 = ((pk_cp2.getWithCheck() >>> ir) & 1); - pk_cp2.moveNextBytes(NB_BYTES_GFqm); - for (jr = 1; jr < HFENr8; ++jr) - { - tmp1 ^= ((pk_cp2.getWithCheck() >>> ir) & 1) << jr; - pk_cp2.moveNextBytes(NB_BYTES_GFqm); - } - pk_U[pk_U_cp++] = (byte)tmp1; - } - } - } - - void convMQ_UL_gf2(byte[] pk, byte[] pk_U, int end) - { - int pk_p, pk_U_cp; - for (int j = 0; j < end; ++j) - { - pk_p = ACCESS_last_equations8 + j * NB_BYTES_EQUATION; - pk_U_cp = j * NB_BYTES_EQUATION; - for_setPK(pk, pk_U, pk_p, pk_U_cp, HFEnv + 1); - } - } - - private int for_setPK(byte[] pk, byte[] pk_U, int pk_p, int pk_U_cp, int end) - { - int i, k; - /* Constant + x_0*x_0 */ - pk[pk_p] = (byte)(pk_U[pk_U_cp] & 3); - /* For each row of the output (the first is already done) */ - for (k = 2, i = 2; i < end; ++i) - { - k = setPK(pk, pk_U, i, pk_p, pk_U_cp, k, HFEnv - 1, HFEnv - i); - } - return k; - } - - private int setPK(byte[] pk, byte[] pk_U, int nb_bits, int pk_p, int pk_U_cp, int k, int start, int end) - { - /* For each column */ - for (int j = start; j >= end; --j, ++k) - { - pk[pk_p + (k >>> 3)] ^= ((pk_U[pk_U_cp + (nb_bits >>> 3)] >>> (nb_bits & 7)) & 1) << (k & 7); - nb_bits += j; - } - buffer = nb_bits;// support for convMQS_one_eq_to_hybrid_rep8_uncomp_gf2 - return k; - } - - void convMQS_one_eq_to_hybrid_rep8_comp_gf2(byte[] pk, PointerUnion pk_cp, byte[] pk_U) - { - int i, pk_p = 0; - convMQ_UL_gf2(pk, pk_U, HFEmr8); - /* Monomial representation */ - for (i = 0; i < NB_MONOMIAL_PK; ++i) - { - pk_p = pk_cp.toBytesMove(pk, pk_p, HFEmq8); - /* Jump the coefficients of the HFEmr8 last equations */ - if (HFEmr8 != 0)//gemss128 - { - pk_cp.moveNextByte(); - } - } - } - - void convMQS_one_eq_to_hybrid_rep8_uncomp_gf2(byte[] pk, PointerUnion pk_cp, byte[] pk_U) - { - int i, j = HFEmr8 - 1, k, nb_bits; - long val = 0; - convMQ_UL_gf2(pk, pk_U, j); - /* The last equation is smaller because compressed */ - int pk2_cp = ACCESS_last_equations8 + j * NB_BYTES_EQUATION; - int pk_U_cp = j * NB_BYTES_EQUATION; - k = for_setPK(pk, pk_U, pk2_cp, pk_U_cp, HFEnv); - /* i == HFEnv */ - nb_bits = HFEnv; - /* For each column */ - k = setPK(pk, pk_U, nb_bits, pk2_cp, pk_U_cp, k, HFEnv - 1, LOST_BITS); - for (j = LOST_BITS - 1, nb_bits = buffer; j >= 0; --j, ++k) - { - val ^= ((long)((pk_U[pk_U_cp + (nb_bits >>> 3)] >>> (nb_bits & 7)) & 1)) << (LOST_BITS - 1 - j); - nb_bits += j; - } - /* We put the last bits (stored in val) and we put it in the zero padding of each equation (excepted in - the last since it is not complete since we use its last bits to fill the paddings) */ - pk2_cp = ACCESS_last_equations8 - 1; - for (j = 0; j < HFEmr8 - 1; ++j) - { - /* Last byte of the equation */ - pk2_cp += NB_BYTES_EQUATION; - pk[pk2_cp] ^= ((byte)(val >>> (j * HFENr8c))) << HFENr8; - } - /* Monomial representation */ - pk_cp.indexReset(); - for (i = 0, pk2_cp = 0; i < NB_MONOMIAL_PK; ++i) - { - pk2_cp = pk_cp.toBytesMove(pk, pk2_cp, HFEmq8); - /* Jump the coefficients of the HFEmr8 last equations */ - pk_cp.moveNextByte(); - } - } - - public int crypto_sign_open(byte[] PK, byte[] message, byte[] signature) - { - PointerUnion pk = new PointerUnion(PK); - int i; - long val = 0; - if (HFENr8 != 0 && HFEmr8 > 1) //except gemss128, fgemss and dualmodems - { - PointerUnion pk_cp = new PointerUnion(pk); - pk_cp.moveNextBytes(ACCESS_last_equations8 - 1); - for (i = 0; i < HFEmr8 - 1; ++i) - { - /* Last byte of the equation */ - pk_cp.moveNextBytes(NB_BYTES_EQUATION); - val ^= ((pk_cp.getByte() & 0xFFL) >>> HFENr8) << (i * HFENr8c); - } - } - if (HFEmr8 != 0) - { - Pointer pk_tmp = new Pointer(1 + NB_WORD_UNCOMP_EQ * HFEmr8); - long cst = 0; - PointerUnion pk64 = new PointerUnion(pk); - for (i = 0; i < HFEmr8 - 1; i++) - { - pk64.setByteIndex(ACCESS_last_equations8 + i * NB_BYTES_EQUATION); - cst ^= convMQ_uncompressL_gf2(new Pointer(pk_tmp, 1 + i * NB_WORD_UNCOMP_EQ), pk64) << i; - } - pk64.setByteIndex(ACCESS_last_equations8 + i * NB_BYTES_EQUATION); - /* The last equation in input is smaller because compressed */ - cst ^= convMQ_last_uncompressL_gf2(new Pointer(pk_tmp, 1 + i * NB_WORD_UNCOMP_EQ), pk64) << i; - if (HFENr8 != 0) - { - /* Number of lost bits by the zero padding of each equation (without the last) */ - if (HFEnvr == 0) //redgemss128 - { - pk_tmp.setXor((i + 1) * NB_WORD_UNCOMP_EQ, val << (64 - LOST_BITS)); - } - else if (HFEnvr > LOST_BITS) - { - //gemss192, bluegemss128, bluegemss192, redgemss192, redgemss256, whitegemss128, whitegemss256 - //cyangemss128, cyangemss192, cyangemss256, magentagemss192 - pk_tmp.setXor((i + 1) * NB_WORD_UNCOMP_EQ, val << (HFEnvr - LOST_BITS)); - } - else if (HFEnvr == LOST_BITS) //gemss256, bluegemss256 - { - pk_tmp.set((i + 1) * NB_WORD_UNCOMP_EQ, val); - } - else // whitegemss192, magentagemss128, magentagemss256 - { - pk_tmp.setXor((i + 1) * NB_WORD_UNCOMP_EQ - 1, val << (64 - (LOST_BITS - HFEnvr))); - pk_tmp.set((i + 1) * NB_WORD_UNCOMP_EQ, val >>> (LOST_BITS - HFEnvr)); - } - } - pk_tmp.set(cst << (HFEmr - HFEmr8)); - return sign_openHFE_huncomp_pk(message, message.length, signature, pk, new PointerUnion(pk_tmp)); - } - else - { - Pointer sm = new Pointer(SIZE_SIGN_UNCOMPRESSED); - Pointer Si_tab = new Pointer(NB_WORD_GF2nv); - /* Copy of pointer */ - Pointer Si = new Pointer(Si_tab); - /* Vector of D_1, ..., D_(NB_ITE) */ - Pointer D = new Pointer(SIZE_DIGEST_UINT); - /* Take the (n+v) first bits */ - sm.fill(0, signature, 0, NB_BYTES_GFqnv); - byte[] hashbuffer = new byte[64]; - /* Compute H1 = H(m), the m first bits are D1 */ - getSHA3Hash(D, 0, 64, message, 0, message.length, hashbuffer); - /* Compute p(S_(NB_IT),X_(NB_IT)) */ - evalMQSnocst8_quo_gf2(Si, sm, pk); - /* D1'' == D1 */ - return Si.isEqual_nocst_gf2(D, NB_WORD_GF2m); - } - } - - /** - * @return 0 if the result is correct, ERROR_ALLOC for error from - * malloc/calloc functions. - * @brief Apply the change of variables x'=xS to a MQS stored with a monomial - * representation. - * @details MQS = (c,Q), with c the constant part in GF(2^n) and Q is an upper - * triangular matrix of size (n+v)*(n+v) in GF(2^n). We have MQS = c + xQxt - * with x = (x0 x1 ... x_(n+v)). At the end of the function, we have - * MQS = c + xQ'xt with Q' = SQSt. We multiply S by Q, then SQ by St. - * @param[in,out] MQS A MQS in GF(2^n)[x1,...,x_(n+v)] (n equations, - * n+v variables). - * @param[in] S A matrix (n+v)*(n+v) in GF(2). S should be invertible - * (by definition of a change of variables). - * @remark This function should be faster than changeVariablesMQS_simd_gf2 - * when SIMD is not used. - * @remark Constant-time implementation. - */ - void changeVariablesMQS64_gf2(Pointer MQS, Pointer S) - { - Pointer MQS_cpj = new Pointer(); - int iq, ir, j, jq, jr; - /* Tmp matrix (n+v)*(n+v) of quadratic terms to compute S*Q */ - Pointer MQS2 = new Pointer(HFEnv * HFEnv * NB_WORD_GFqn); - /* To avoid the constant of MQS */ - Pointer MQS_cpi = new Pointer(MQS, NB_WORD_GFqn); - Pointer MQS2_cp = new Pointer(MQS2); - Pointer S_cpj = new Pointer(S); - /* Step 1 : compute MQS2 = S*Q */ - /* Use multiplication by transpose (so by rows of Q) */ - /* It is possible because X*Q*tX = X*tQ*tX (with X = (x1 ... xn)) */ - /* Warning : Q is a upper triangular matrix in GF(q^n) */ - /* In this code, we have : */ - /* i = iq*NB_BITS_UINT + ir */ - /* k = kq*NB_BITS_UINT + kr */ - /* *MQS_cpi = MQS[NB_WORD_GFqn] */ - /* *MQS_cpj = MQS_cpi[(((i*(2n-i+1))/2) + k)*NB_WORD_GFqn] */ - /* The previous formula is a bit complicated, so the idea is : - *MQS_cpj would equal MQS_cpi[i][i+k] if MQS used n*n in memory */ - /* *MQS2_cp = MQS2[i*NB_WORD_GFqn] */ - /* *S_cpj = S[j*NB_WORD_GFqn+iq] */ - /* for each row j of S */ - for (j = 0; j < HFEnv; ++j) - { - /* initialisation at the first row of Q */ - MQS_cpj.changeIndex(MQS_cpi); - /* for each row of Q excepted the last block */ - for (iq = 0; iq < HFEnvq; ++iq) - { - for (ir = 0; ir < NB_BITS_UINT; ++ir) - { - /* Compute a dot product */ - LOOPKR(MQS_cpj, MQS2_cp, S_cpj.get() >>> ir, ir, NB_BITS_UINT); - LOOPK_COMPLETE(MQS2_cp, S_cpj, MQS_cpj, 1, HFEnvq - iq); - } - /* 64 bits of zero in Q */ - S_cpj.moveIncremental(); - } - /* the last block */ - if (HFEnvr != 0) //except dualmodems256 - { - for (ir = 0; ir < HFEnvr; ++ir) - { - /* Compute a dot product */ - LOOPKR(MQS_cpj, MQS2_cp, S_cpj.get() >>> ir, ir, HFEnvr); - /* update the next element to compute */ - MQS2_cp.move(NB_WORD_GFqn); - } - /* Next row of S */ - S_cpj.moveIncremental(); - } - } - /* Step 2 : compute MQS = MQS2*tS = (S*Q)*tS */ - /* Use multiplication by transpose (so by rows of S) */ - /* Permute MQS and MQS2 */ - MQS_cpi.changeIndex(MQS2); - MQS2_cp.changeIndex(MQS, NB_WORD_GFqn); - Pointer S_cpi = new Pointer(S); - /* First : compute upper triangular result */ - /* In this code, we have : */ - /* *MQS_cpi = MQS2[j*n*NB_WORD_GFqn] */ - /* *MQS_cpj = MQS2[(j*n+k)*NB_WORD_GFqn] */ - /* *MQS2_cp = MQS[(((j*(2n-j+1))/2) + i-j)*NB_WORD_GFqn] */ - /* The previous formula is a bit complicated, so the idea is : - *MQS2_cp would equal MQS[j][i] if MQS used n*n in memory */ - /* *S_cpi = S[j*NB_WORD_GFqn] */ - /* *S_cpj = S[i*NB_WORD_GFqn] */ - /* for each row j of MQS2 excepted the last block */ - for (jq = 0; jq < HFEnvq; ++jq) - { - for (jr = 0; jr < NB_BITS_UINT; ++jr) - { - S_cpj.changeIndex(S_cpi); - /* for each row >=j of S */ - LOOPIR_INIT(MQS2_cp, MQS_cpj, MQS_cpi, S_cpj, jr, NB_BITS_UINT); - for (iq = jq + 1; iq < HFEnvq; ++iq) - { - LOOPIR_INIT(MQS2_cp, MQS_cpj, MQS_cpi, S_cpj, 0, NB_BITS_UINT); - } - /* the last block */ - if (HFEnvr != 0)//except dualmodems256 - { - LOOPIR_INIT(MQS2_cp, MQS_cpj, MQS_cpi, S_cpj, 0, HFEnvr); - } - /* Next row of MQS2 */ - MQS_cpi.changeIndex(MQS_cpj); - /* Next row of S because of upper triangular */ - S_cpi.move(NB_WORD_GF2nv); - } - } - /* the last block */ - if (HFEnvr != 0)//except dualmodems256 - { - for (jr = 0; jr < HFEnvr; ++jr) - { - S_cpj.changeIndex(S_cpi); - MQS_cpj.changeIndex(MQS_cpi); - /* for each row >=j of S, the last block */ - LOOPIR_INIT(MQS2_cp, MQS_cpj, MQS_cpi, S_cpj, jr, HFEnvr); - MQS_cpi.changeIndex(MQS_cpj); - S_cpi.move(NB_WORD_GF2nv); - } - } - /* Second : compute lower triangular result */ - MQS_cpi.changeIndex(MQS2); - MQS2_cp.changeIndex(MQS, NB_WORD_GFqn); - S_cpj.changeIndex(S); - /* In this code, we have : */ - /* *MQS_cpi = MQS2[(j+1)*n*NB_WORD_GFqn] */ - /* *MQS_cpj = MQS2[(j+1)*n+k)*NB_WORD_GFqn] */ - /* *MQS2_cp = MQS[(((j*(2n-j+1))/2) + i-j)*NB_WORD_GFqn] */ - /* The previous formula is a bit complicated, so the idea is : - *MQS2_cp would equal MQS[j][i] if MQS used n*n in memory */ - /* *S_cpj = S[j*NB_WORD_GFqn] */ - /* for each row j of S excepted the last block */ - for (jq = 0; jq < HFEnvq; ++jq) - { - for (jr = 0; jr < NB_BITS_UINT; ++jr) - { - /* i=j : the diagonal is already computing */ - MQS2_cp.move(NB_WORD_GFqn); - /* The line j of MQS2 is useless */ - MQS_cpi.move(HFEnv * NB_WORD_GFqn); - MQS_cpj.changeIndex(MQS_cpi); - /* for each row >j of MQS2 */ - LOOPIR_LOOPK_COMPLETE(MQS2_cp, S_cpj, MQS_cpj, jr + 1, NB_BITS_UINT); - for (iq = jq + 1; iq < HFEnvq; ++iq) - { - LOOPIR_LOOPK_COMPLETE(MQS2_cp, S_cpj, MQS_cpj, 0, NB_BITS_UINT); - } - /* the last block */ - if (HFEnvr != 0)//except dualmodems256 - { - LOOPIR_LOOPK_COMPLETE(MQS2_cp, S_cpj, MQS_cpj, 0, HFEnvr); - } - /* Next row of S */ - S_cpj.move(NB_WORD_GF2nv); - } - } - /* the last block excepted the last row */ - if (HFEnvr != 0)//except dualmodems256 - { - for (jr = 0; jr < HFEnvr - 1; ++jr) - { - /* i=j : the diagonal is already computing */ - MQS2_cp.move(NB_WORD_GFqn); - /* The line j of MQS2 is useless */ - MQS_cpi.move(HFEnv * NB_WORD_GFqn); - MQS_cpj.changeIndex(MQS_cpi); - /* for each row >=j of S */ - /* the last block */ - LOOPIR_LOOPK_COMPLETE(MQS2_cp, S_cpj, MQS_cpj, jr + 1, HFEnvr); - /* Next row of S */ - S_cpj.move(NB_WORD_GF2nv); - } - } - MQS.indexReset(); - S.indexReset(); - } - - private void LOOPIR_INIT(Pointer MQS2_cp, Pointer MQS_cpj, Pointer MQS_cpi, Pointer S_cpj, int STARTIR, int NB_ITIR) - { - for (int ir = STARTIR; ir < NB_ITIR; ++ir) - { - MQS2_cp.setRangeClear(0, NB_WORD_GFqn); - MQS_cpj.changeIndex(MQS_cpi); - /* Compute a dot product */ - LOOPK_COMPLETE(MQS2_cp, S_cpj, MQS_cpj, 0, HFEnvq); - /* update the next row of S to use */ - S_cpj.move(NB_WORD_GF2nv); - } - } - - private void LOOPIR_LOOPK_COMPLETE(Pointer MQS2_cp, Pointer S_cpj, Pointer MQS_cpj, int STARTIR, int NB_ITIR) - { - for (int ir = STARTIR; ir < NB_ITIR; ++ir) - { - /* Compute a dot product */ - LOOPK_COMPLETE(MQS2_cp, S_cpj, MQS_cpj, 0, HFEnvq); - } - } - - private void LOOPK_COMPLETE(Pointer MQS2_cp, Pointer S_cpj, Pointer MQS_cpj, int start, int end) - { - for (int kq = start; kq < end; ++kq) - { - LOOPKR(MQS_cpj, MQS2_cp, S_cpj.get(kq), 0, NB_BITS_UINT); - } - if (HFEnvr != 0) //except dualmodems256 - { - LOOPKR(MQS_cpj, MQS2_cp, S_cpj.get(end), 0, HFEnvr); - } - /* update the next element to compute */ - MQS2_cp.move(NB_WORD_GFqn); - } - - private void LOOPKR(Pointer MQS_cpj, Pointer MQS2_cp, long bit_kr, int START, int NB_IT) - { - for (int kr = START; kr < NB_IT; ++kr) - { - /* multiply one bit of S by one element of MQS_cpj */ - MQS2_cp.setXorRangeAndMaskMove(MQS_cpj, NB_WORD_GFqn, -(bit_kr & 1L)); - bit_kr >>>= 1; - } - } - - /** - * @return 0 if the result is correct, ERROR_ALLOC for error from - * malloc/calloc functions. - * @brief Computation of the multivariate representation of a HFEv - * polynomial, then a change of variables is applied. - * @details Computation of the multivariate representation of F(XS), - * by evaluation/interpolation. We take the following N points in GF(2)^(n+v) : - * n0=(0 ... 0), - * e1,e2,...,e_(n+v) with ei the i-th row of the identity matrix, - * all ei+ej, with i>> HFEnr); - } - /* Evaluation of the vinegar constant */ - evalMQSv_unrolled_gf2(cur_acc, V, F); - F.move(MQv_GFqn_SIZE); - /* Evaluation of the linear terms in the vinegars */ - /* + evaluation of the linear and quadratic terms in X */ - /* j=0 */ - /* Degree 1 term */ - /* Linear term */ - vmpv_xorrange_move(acc, V, F); - tab_Xqj_cp.changeIndex(tab_Xqj); - /* mul by X */ - mul_xorrange(cur_acc, tab_Xqj_cp, acc); - /* X^(q^j) * (sum a_j,k X^q^k) */ - for (j = 1; j < HFEDegI; ++j) - { - /* Linear term */ - vmpv_xorrange_move(acc, V, F); - acc.setRangeClear(NB_WORD_GFqn, NB_WORD_MMUL - NB_WORD_GFqn); - /* Quadratic terms */ - tab_Xqj_cp2.changeIndex(tab_Xqj_cp); - for_mul_xorrange_move(acc, F, tab_Xqj_cp2, j); - rem_gf2n(acc, 0, acc); - mul_xorrange(cur_acc, tab_Xqj_cp2, acc); - } - /* j=HFEDegI */ - vmpv_xorrange_move(acc, V, F); - /* Quadratic terms */ - tab_Xqj_cp2.changeIndex(tab_Xqj_cp); - if (HFEDegJ != 0) - { - acc.setRangeClear(NB_WORD_GFqn, NB_WORD_MMUL - NB_WORD_GFqn); - for_mul_xorrange_move(acc, F, tab_Xqj_cp2, HFEDegJ); - /* k=HFEDegJ : monic case */ - acc.setXorRange(tab_Xqj_cp2, NB_WORD_GFqn); - rem_gf2n(acc, 0, acc); - } - else - { - /* k=HFEDegJ : monic case */ - acc.setRangeFromXor(acc, tab_Xqj_cp2, NB_WORD_GFqn); - } - tab_Xqj_cp.move(HFEDegI * NB_WORD_GFqn); - mul_xorrange(cur_acc, tab_Xqj_cp, acc); - /* Final reduction of F(xv) */ - rem_gf2n(Fxv, 0, cur_acc); - F.changeIndex(F_orig); - } - - private void vmpv_xorrange_move(Pointer acc, Pointer V, Pointer F) - { - vecMatProduct(acc, V, new Pointer(F, NB_WORD_GFqn), FunctionParams.V); - acc.setXorRange(F, NB_WORD_GFqn); - F.move(MLv_GFqn_SIZE); - } - - private static long remainderUnsigned(long dividend, long divisor) - { - if (dividend > 0L && divisor > 0L) - { - return dividend % divisor; - } - else - { - return new BigInteger(1, Pack.longToBigEndian(dividend)).mod(new BigInteger(1, Pack.longToBigEndian(divisor))).longValue(); - } - } -} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSEngineProvider.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSEngineProvider.java deleted file mode 100644 index 8fad283be1..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSEngineProvider.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -public interface GeMSSEngineProvider -{ - GeMSSEngine get(); - - int getN(); -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSKeyGenerationParameters.java deleted file mode 100644 index adfd87efc7..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSKeyGenerationParameters.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.KeyGenerationParameters; - -public class GeMSSKeyGenerationParameters - extends KeyGenerationParameters -{ - final GeMSSParameters parameters; - - public GeMSSKeyGenerationParameters(SecureRandom random, GeMSSParameters parameters) - { - super(random, -1); - this.parameters = parameters; - } - - public GeMSSParameters getParameters() - { - return parameters; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSKeyPairGenerator.java deleted file mode 100644 index f16272d316..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSKeyPairGenerator.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.crypto.digests.SHAKEDigest; - - -public class GeMSSKeyPairGenerator - implements AsymmetricCipherKeyPairGenerator -{ - private SecureRandom random; - private GeMSSParameters parameters; - - @Override - public void init(KeyGenerationParameters param) - { - random = param.getRandom(); - parameters = ((GeMSSKeyGenerationParameters)param).getParameters(); - } - - @Override - public AsymmetricCipherKeyPair generateKeyPair() - { - GeMSSEngine engine = parameters.getEngine(); - int i, ret; - byte[] seed = sec_rand(engine.SIZE_SEED_SK); - int NB_COEFS_HFEPOLY = (2 + engine.HFEDegJ + ((engine.HFEDegI * (engine.HFEDegI + 1)) >>> 1)); - int NB_COEFS_HFEVPOLY = (NB_COEFS_HFEPOLY + (engine.NB_MONOMIAL_VINEGAR - 1) + (engine.HFEDegI + 1) * engine.HFEv); - int NB_UINT_HFEVPOLY = NB_COEFS_HFEVPOLY * engine.NB_WORD_GFqn; - int sk_uncomp_length = ((NB_UINT_HFEVPOLY + (engine.LTRIANGULAR_NV_SIZE << 1) + (engine.LTRIANGULAR_N_SIZE << 1))) << 3; - Pointer F = new Pointer(sk_uncomp_length >>> 3); - byte[] sk_uncomp = new byte[sk_uncomp_length]; - SHAKEDigest shakeDigest = new SHAKEDigest(engine.ShakeBitStrength); - shakeDigest.update(seed, 0, engine.SIZE_SEED_SK); - shakeDigest.doFinal(sk_uncomp, 0, sk_uncomp_length); - byte[] sk = new byte[engine.SIZE_SEED_SK]; - final int SIZE_PK_HFE = (engine.NB_MONOMIAL_PK * engine.HFEm + 7) >> 3; - byte[] pk = new byte[SIZE_PK_HFE]; - System.arraycopy(seed, 0, sk, 0, sk.length); - F.fill(0, sk_uncomp, 0, sk_uncomp.length); - engine.cleanMonicHFEv_gf2nx(F); - Pointer Q = new Pointer(engine.NB_MONOMIAL_PK * engine.NB_WORD_GFqn); - if (engine.HFEDeg > 34) - { - engine.genSecretMQS_gf2_opt(Q, F); - } - Pointer S = new Pointer(engine.MATRIXnv_SIZE); - Pointer T = new Pointer(S); - Pointer L = new Pointer(F, NB_UINT_HFEVPOLY); - Pointer U = new Pointer(L, engine.LTRIANGULAR_NV_SIZE); - engine.cleanLowerMatrix(L, GeMSSEngine.FunctionParams.NV); - engine.cleanLowerMatrix(U, GeMSSEngine.FunctionParams.NV); - /* Compute Q'=S*Q*St (with Q an upper triangular matrix) */ - engine.invMatrixLU_gf2(S, L, U, GeMSSEngine.FunctionParams.NV); - if (engine.HFEDeg <= 34) - { - ret = engine.interpolateHFE_FS_ref(Q, F, S); - if (ret != 0) - { - throw new IllegalArgumentException("Error"); - } - } - else - { - engine.changeVariablesMQS64_gf2(Q, S); - } - L.move(engine.LTRIANGULAR_NV_SIZE << 1); - U.changeIndex(L.getIndex() + engine.LTRIANGULAR_N_SIZE); - engine.cleanLowerMatrix(L, GeMSSEngine.FunctionParams.N); - engine.cleanLowerMatrix(U, GeMSSEngine.FunctionParams.N); - engine.invMatrixLU_gf2(T, L, U, GeMSSEngine.FunctionParams.N); - if (engine.HFEmr8 != 0) - { - final int MQ_GFqm8_SIZE = (engine.NB_MONOMIAL_PK * engine.NB_BYTES_GFqm + ((8 - (engine.NB_BYTES_GFqm & 7)) & 7)); - PointerUnion pk_cp = new PointerUnion(MQ_GFqm8_SIZE); - /* for each monomial of MQS and pk */ - for (i = (engine.NB_BYTES_GFqm & 7) != 0 ? 1 : 0; i < engine.NB_MONOMIAL_PK; ++i) - { - engine.vecMatProduct(pk_cp, Q, T, GeMSSEngine.FunctionParams.M); - /* next monomial */ - Q.move(engine.NB_WORD_GFqn); - pk_cp.moveNextBytes(engine.NB_BYTES_GFqm); - } - /* Last monomial: we fill the last bytes of pk without 64-bit cast. */ - if ((engine.NB_BYTES_GFqm & 7) != 0) - { - Pointer pk_last = new Pointer(engine.NB_WORD_GF2m); - engine.vecMatProduct(pk_last, Q, T, GeMSSEngine.FunctionParams.M); - for (i = 0; i < engine.NB_WORD_GF2m; ++i) - { - pk_cp.set(i, pk_last.get(i)); - } - } - pk_cp.indexReset(); - byte[] pk_U = new byte[engine.HFEmr8 * engine.NB_BYTES_EQUATION]; - engine.convMQS_one_to_last_mr8_equations_gf2(pk_U, pk_cp); - pk_cp.indexReset(); - if (engine.HFENr8 != 0 && engine.HFEmr8 > 1) - { - engine.convMQS_one_eq_to_hybrid_rep8_uncomp_gf2(pk, pk_cp, pk_U); - } - else - { - engine.convMQS_one_eq_to_hybrid_rep8_comp_gf2(pk, pk_cp, pk_U); - } - } - else - { - PointerUnion pk_last = new PointerUnion(engine.NB_WORD_GF2m << 3); - int pk_p = 0; - for (i = 0; i < engine.NB_MONOMIAL_PK; ++i) - { - engine.vecMatProduct(pk_last, Q, T, GeMSSEngine.FunctionParams.M); - pk_p = pk_last.toBytesMove(pk, pk_p, engine.NB_BYTES_GFqm); - pk_last.indexReset(); - Q.move(engine.NB_WORD_GFqn); - } - } - return new AsymmetricCipherKeyPair(new GeMSSPublicKeyParameters(parameters, pk), - new GeMSSPrivateKeyParameters(parameters, sk)); - } - - private byte[] sec_rand(int n) - { - byte[] rv = new byte[n]; - random.nextBytes(rv); - return rv; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSKeyParameters.java deleted file mode 100644 index 507d71c39d..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSKeyParameters.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; - -public class GeMSSKeyParameters - extends AsymmetricKeyParameter -{ - final GeMSSParameters parameters; - - protected GeMSSKeyParameters(boolean isPrivate, GeMSSParameters parameters) - { - super(isPrivate); - this.parameters = parameters; - } - - public GeMSSParameters getParameters() - { - return parameters; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSParameters.java deleted file mode 100644 index 4c23af6dcf..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSParameters.java +++ /dev/null @@ -1,166 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.util.Integers; -import org.bouncycastle.util.Pack; - -public class GeMSSParameters -{ - public static final GeMSSParameters gemss128 = new GeMSSParameters("gemss128", 128, 174, 12, 12, 4, 513, 9, 0); - public static final GeMSSParameters gemss192 = new GeMSSParameters("gemss192", 192, 265, 20, 22, 4, 513, 9, 0); - public static final GeMSSParameters gemss256 = new GeMSSParameters("gemss256", 256, 354, 33, 30, 4, 513, 9, 0); - public static final GeMSSParameters bluegemss128 = new GeMSSParameters("bluegemss128", 128, 175, 14, 13, 4, 129, 7, 0); - public static final GeMSSParameters bluegemss192 = new GeMSSParameters("bluegemss192", 192, 265, 23, 22, 4, 129, 7, 0); - public static final GeMSSParameters bluegemss256 = new GeMSSParameters("bluegemss256", 256, 358, 32, 34, 4, 129, 7, 0); - public static final GeMSSParameters redgemss128 = new GeMSSParameters("redgemss128", 128, 177, 15, 15, 4, 17, 4, 0); - public static final GeMSSParameters redgemss192 = new GeMSSParameters("redgemss192", 192, 266, 25, 23, 4, 17, 4, 0); - public static final GeMSSParameters redgemss256 = new GeMSSParameters("redgemss256", 256, 358, 35, 34, 4, 17, 4, 0); - public static final GeMSSParameters whitegemss128 = new GeMSSParameters("whitegemss128", 128, 175, 12, 12, 3, 513, 9, 0); - public static final GeMSSParameters whitegemss192 = new GeMSSParameters("whitegemss192", 192, 268, 21, 21, 3, 513, 9, 0); - public static final GeMSSParameters whitegemss256 = new GeMSSParameters("whitegemss256", 256, 364, 29, 31, 3, 513, 9, 0); - public static final GeMSSParameters cyangemss128 = new GeMSSParameters("cyangemss128", 128, 177, 13, 14, 3, 129, 7, 0); - public static final GeMSSParameters cyangemss192 = new GeMSSParameters("cyangemss192", 192, 270, 22, 23, 3, 129, 7, 0); - public static final GeMSSParameters cyangemss256 = new GeMSSParameters("cyangemss256", 256, 364, 32, 31, 3, 129, 7, 0); - public static final GeMSSParameters magentagemss128 = new GeMSSParameters("magentagemss128", 128, 178, 15, 15, 3, 17, 4, 0); - public static final GeMSSParameters magentagemss192 = new GeMSSParameters("magentagemss192", 192, 271, 24, 24, 3, 17, 4, 0); - public static final GeMSSParameters magentagemss256 = new GeMSSParameters("magentagemss256", 256, 366, 33, 33, 3, 17, 4, 0); - public static final GeMSSParameters fgemss128 = new GeMSSParameters("fgemss128", 128, 266, 11, 10, 1, 129, 7, 0); - public static final GeMSSParameters fgemss192 = new GeMSSParameters("fgemss192", 192, 402, 18, 18, 1, 640, 9, 7); - public static final GeMSSParameters fgemss256 = new GeMSSParameters("fgemss256", 256, 537, 26, 25, 1, 1152, 10, 7); - public static final GeMSSParameters dualmodems128 = new GeMSSParameters("dualmodems128", 128, 266, 11, 10, 1, 129, 7, 0); - public static final GeMSSParameters dualmodems192 = new GeMSSParameters("dualmodems192", 192, 402, 18, 18, 1, 129, 7, 0); - public static final GeMSSParameters dualmodems256 = new GeMSSParameters("dualmodems256", 256, 544, 32, 32, 1, 129, 7, 0); - - private static final Integer gemss_128 = Integers.valueOf(0x0101); - private static final Integer gemss_192 = Integers.valueOf(0x0102); - private static final Integer gemss_256 = Integers.valueOf(0x0103); - private static final Integer bluegemss_128 = Integers.valueOf(0x0201); - private static final Integer bluegemss_192 = Integers.valueOf(0x0202); - private static final Integer bluegemss_256 = Integers.valueOf(0x0203); - private static final Integer redgemss_128 = Integers.valueOf(0x0301); - private static final Integer redgemss_192 = Integers.valueOf(0x0302); - private static final Integer redgemss_256 = Integers.valueOf(0x0303); - private static final Integer whitegemss_128 = Integers.valueOf(0x0401); - private static final Integer whitegemss_192 = Integers.valueOf(0x0402); - private static final Integer whitegemss_256 = Integers.valueOf(0x0403); - private static final Integer cyangemss_128 = Integers.valueOf(0x0501); - private static final Integer cyangemss_192 = Integers.valueOf(0x0502); - private static final Integer cyangemss_256 = Integers.valueOf(0x0503); - private static final Integer magentagemss_128 = Integers.valueOf(0x0601); - private static final Integer magentagemss_192 = Integers.valueOf(0x0602); - private static final Integer magentagemss_256 = Integers.valueOf(0x0603); - private static final Integer fgemss_128 = Integers.valueOf(0x0701); - private static final Integer fgemss_192 = Integers.valueOf(0x0702); - private static final Integer fgemss_256 = Integers.valueOf(0x0703); - private static final Integer dualmodems_128 = Integers.valueOf(0x0801); - private static final Integer dualmodems_192 = Integers.valueOf(0x0802); - private static final Integer dualmodems_256 = Integers.valueOf(0x0803); - private static final Map oidToParams = new HashMap(); - private static final Map paramsToOid = new HashMap(); - - static - { - oidToParams.put(gemss_128, gemss128); - oidToParams.put(gemss_192, gemss192); - oidToParams.put(gemss_256, gemss256); - oidToParams.put(bluegemss_128, bluegemss128); - oidToParams.put(bluegemss_192, bluegemss192); - oidToParams.put(bluegemss_256, bluegemss256); - oidToParams.put(redgemss_128, redgemss128); - oidToParams.put(redgemss_192, redgemss192); - oidToParams.put(redgemss_256, redgemss256); - oidToParams.put(whitegemss_128, whitegemss128); - oidToParams.put(whitegemss_192, whitegemss192); - oidToParams.put(whitegemss_256, whitegemss256); - oidToParams.put(cyangemss_128, cyangemss128); - oidToParams.put(cyangemss_192, cyangemss192); - oidToParams.put(cyangemss_256, cyangemss256); - oidToParams.put(magentagemss_128, magentagemss128); - oidToParams.put(magentagemss_192, magentagemss192); - oidToParams.put(magentagemss_256, magentagemss256); - oidToParams.put(fgemss_128, fgemss128); - oidToParams.put(fgemss_192, fgemss192); - oidToParams.put(fgemss_256, fgemss256); - oidToParams.put(dualmodems_128, dualmodems128); - oidToParams.put(dualmodems_192, dualmodems192); - oidToParams.put(dualmodems_256, dualmodems256); - - paramsToOid.put(gemss128, gemss_128); - paramsToOid.put(gemss192, gemss_192); - paramsToOid.put(gemss256, gemss_256); - paramsToOid.put(bluegemss128, bluegemss_128); - paramsToOid.put(bluegemss192, bluegemss_192); - paramsToOid.put(bluegemss256, bluegemss_256); - paramsToOid.put(redgemss128, redgemss_128); - paramsToOid.put(redgemss192, redgemss_192); - paramsToOid.put(redgemss256, redgemss_256); - paramsToOid.put(whitegemss128, whitegemss_128); - paramsToOid.put(whitegemss192, whitegemss_192); - paramsToOid.put(whitegemss256, whitegemss_256); - paramsToOid.put(cyangemss128, cyangemss_128); - paramsToOid.put(cyangemss192, cyangemss_192); - paramsToOid.put(cyangemss256, cyangemss_256); - paramsToOid.put(magentagemss128, magentagemss_128); - paramsToOid.put(magentagemss192, magentagemss_192); - paramsToOid.put(magentagemss256, magentagemss_256); - paramsToOid.put(fgemss128, fgemss_128); - paramsToOid.put(fgemss192, fgemss_192); - paramsToOid.put(fgemss256, fgemss_256); - paramsToOid.put(dualmodems128, dualmodems_128); - paramsToOid.put(dualmodems192, dualmodems_192); - paramsToOid.put(dualmodems256, dualmodems_256); - } - - private final String name; - private final GeMSSEngine engine; - - private GeMSSParameters(String name, int K, int HFEn, int HFEv, int HFEDELTA, int NB_ITE, int HFEDeg, - int HFEDegI, int HFEDegJ) - { - this.name = name; - //System.out.print(name + " "); - this.engine = new GeMSSEngine(K, HFEn, HFEv, HFEDELTA, NB_ITE, HFEDeg, HFEDegI, HFEDegJ); - } - - public String getName() - { - return name; - } - - - /** - * Return the SPHINCS+ parameters that map to the passed in parameter ID. - * - * @param id the oid of interest. - * @return the parameter set. - */ - public static GeMSSParameters getParams(Integer id) - { - return (GeMSSParameters)oidToParams.get(id); - } - - /** - * Return the OID that maps to the passed in SPHINCS+ parameters. - * - * @param params the parameters of interest. - * @return the OID for the parameter set. - */ - public static Integer getID(GeMSSParameters params) - { - return (Integer)paramsToOid.get(params); - } - - public byte[] getEncoded() - { - return Pack.intToBigEndian(getID(this).intValue()); - } - - public GeMSSEngine getEngine() - { - return this.engine; - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSPrivateKeyParameters.java deleted file mode 100644 index c270d897c7..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSPrivateKeyParameters.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -import org.bouncycastle.util.Arrays; - -public class GeMSSPrivateKeyParameters - extends GeMSSKeyParameters -{ - final byte[] sk; - public GeMSSPrivateKeyParameters(GeMSSParameters parameters, byte[] skValues) - { - super(false, parameters); - sk = new byte[skValues.length]; - System.arraycopy(skValues, 0, sk, 0, sk.length); - } - - public byte[] getEncoded() - { - return Arrays.clone(sk); - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSPublicKeyParameters.java deleted file mode 100644 index 9d841bcb66..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSPublicKeyParameters.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -import org.bouncycastle.util.Arrays; - -public class GeMSSPublicKeyParameters - extends GeMSSKeyParameters -{ - private final byte[] pk; - - public GeMSSPublicKeyParameters(GeMSSParameters parameters, byte[] pkValues) - { - super(false, parameters); - pk = new byte[pkValues.length]; - System.arraycopy(pkValues, 0, pk, 0, pk.length); - } - - public byte[] getPK() - { - return pk; - } - - public byte[] getEncoded() - { - return Arrays.clone(pk); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSSigner.java deleted file mode 100644 index a84d7f93bf..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSSigner.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.CryptoServicesRegistrar; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.MessageSigner; - - -public class GeMSSSigner - implements MessageSigner -{ - private GeMSSPrivateKeyParameters privKey; - private GeMSSPublicKeyParameters pubKey; - private SecureRandom random; - - public GeMSSSigner() - { - - } - - public void init(boolean forSigning, CipherParameters param) - { - if (forSigning) - { - if (param instanceof ParametersWithRandom) - { - privKey = ((GeMSSPrivateKeyParameters)((ParametersWithRandom)param).getParameters()); - random = ((ParametersWithRandom)param).getRandom(); - } - else - { - privKey = (GeMSSPrivateKeyParameters)param; - random = CryptoServicesRegistrar.getSecureRandom(); - } - } - else - { - pubKey = (GeMSSPublicKeyParameters)param; - } - - } - - public byte[] generateSignature(byte[] message) - { - GeMSSEngine engine = privKey.getParameters().getEngine(); - final int SIZE_SIGN_HFE = ((engine.HFEnv + (engine.NB_ITE - 1) * (engine.HFEnv - engine.HFEm)) + 7) >>> 3; - byte[] sm8 = new byte[message.length + SIZE_SIGN_HFE]; - System.arraycopy(message, 0, sm8, SIZE_SIGN_HFE, message.length); - engine.signHFE_FeistelPatarin(random, sm8, message, 0, message.length, privKey.sk); - return sm8; - } - - public boolean verifySignature(byte[] message, byte[] signature) - { - GeMSSEngine engine = pubKey.getParameters().getEngine(); - int ret = engine.crypto_sign_open(pubKey.getPK(), message, signature); - return ret != 0; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSUtils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSUtils.java deleted file mode 100644 index 0af8f7bd32..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/GeMSSUtils.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -public class GeMSSUtils -{ - static long NORBITS_UINT(long n) - { - n |= n << 32; - n >>>= 32; - --n; - return n >>> 63; -// n |= n >>> 32; -// n |= n >>> 16; -// n |= n >>> 8; -// n |= n >>> 4; -// n |= n >>> 2; -// n |= n >>> 1; -// n = ~n; -// return n & 1L; - } - - static long XORBITS_UINT(long n) - { - //TODO: need to test which one is faster. -// n ^= n >>> 32; -// n ^= n >>> 16; -// n ^= n >>> 8; -// n ^= n >>> 4; -// n ^= n >>> 2; -// n ^= n >>> 1; -// return n & 1L; - n ^= n << 1; - n ^= n << 2; - return ((n & (0x8888888888888888L)) * (0x1111111111111111L)) >>> 63; - } - - static long ORBITS_UINT(long n) - { - n |= n << 32; - n >>>= 32; - n += 0xFFFFFFFFL; - return n >>> 32; -// n |= n >>> 32; -// n |= n >>> 16; -// n |= n >>> 8; -// n |= n >>> 4; -// n |= n >>> 2; -// n |= n >>> 1; -// return n & 1L; - } - - /* Compare two UINT in constant-time */ - static long CMP_LT_UINT(long a, long b) - { - return ((((a >>> 63) ^ (b >>> 63)) & (((a >>> 63) - (b >>> 63)) >>> 63)) - ^ (((a >>> 63) ^ (b >>> 63) ^ 1L) & (((a & (0x7FFFFFFFFFFFFFFFL)) - - (b & (0x7FFFFFFFFFFFFFFFL))) >>> 63))); - } - - static long maskUINT(int k) - { - return k != 0 ? (1L << k) - 1L : -1L; - } - - static int Highest_One(int x) - { - x |= x >>> 1; - x |= x >>> 2; - x |= x >>> 4; - x |= x >>> 8; - x |= x >>> 16; - return x ^ (x >>> 1); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/Mul_GF2x.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/Mul_GF2x.java deleted file mode 100644 index 3f2d1f1671..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/Mul_GF2x.java +++ /dev/null @@ -1,1053 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -abstract class Mul_GF2x -{ - public abstract void mul_gf2x(Pointer C, Pointer A, Pointer B); - - public abstract void sqr_gf2x(long[] res, long[] A, int a_cp); - - public abstract void mul_gf2x_xor(Pointer res, Pointer A, Pointer B); - - public static class Mul6 - extends Mul_GF2x - { - private long[] Buffer; - - public Mul6() - { - Buffer = new long[6]; - } - - public void mul_gf2x(Pointer C, Pointer A, Pointer B) - { - mul192_no_simd_gf2x(C.array, 0, A.array, A.cp, B.array, B.cp); - } - - public void sqr_gf2x(long[] res, long[] A, int a_cp) - { - SQR64_NO_SIMD_GF2X(res, 4, A[a_cp + 2]); - SQR128_NO_SIMD_GF2X(res, 0, A, a_cp); - } - - public void mul_gf2x_xor(Pointer res, Pointer A, Pointer B) - { - mul192_no_simd_gf2x_xor(res.array, res.cp, A.array, A.cp, B.array, B.cp, Buffer); - } - - } - - public static class Mul9 - extends Mul_GF2x - { - private long[] Buffer; - - public Mul9() - { - Buffer = new long[9]; - } - - public void mul_gf2x(Pointer C, Pointer A, Pointer B) - { - mul288_no_simd_gf2x(C.array, 0, A.array, A.cp, B.array, B.cp, Buffer); - } - - public void sqr_gf2x(long[] res, long[] A, int a_cp) - { - res[8] = SQR32_NO_SIMD_GF2X(A[a_cp + 4]); - SQR256_NO_SIMD_GF2X(res, 0, A, a_cp); - } - - public void mul_gf2x_xor(Pointer res, Pointer A, Pointer B) - { - mul288_no_simd_gf2x_xor(res.array, res.cp, A.array, A.cp, B.array, B.cp, Buffer); - } - } - - public static class Mul12 - extends Mul_GF2x - { - private long[] Buffer; - - public Mul12() - { - Buffer = new long[12]; - } - - public void mul_gf2x(Pointer C, Pointer A, Pointer B) - { - mul384_no_simd_gf2x(C.array, A.array, A.cp, B.array, B.cp, Buffer); - } - - public void sqr_gf2x(long[] res, long[] A, int a_cp) - { - SQR128_NO_SIMD_GF2X(res, 8, A, a_cp + 4); - SQR256_NO_SIMD_GF2X(res, 0, A, a_cp); - } - - public void mul_gf2x_xor(Pointer res, Pointer A, Pointer B) - { - mul384_no_simd_gf2x_xor(res.array, A.array, A.cp, B.array, B.cp, Buffer); - } - } - - public static class Mul13 - extends Mul_GF2x - { - private long[] Buffer; - private long[] Buffer2; - - public Mul13() - { - Buffer = new long[13]; - Buffer2 = new long[4]; - } - - public void mul_gf2x(Pointer C, Pointer A, Pointer B) - { - mul416_no_simd_gf2x(C.array, A.array, A.cp, B.array, B.cp, Buffer); - } - - public void sqr_gf2x(long[] res, long[] A, int a_cp) - { - res[12] = SQR32_NO_SIMD_GF2X(A[a_cp + 6]); - SQR128_NO_SIMD_GF2X(res, 8, A, a_cp + 4); - SQR256_NO_SIMD_GF2X(res, 0, A, a_cp); - } - - public void mul_gf2x_xor(Pointer res, Pointer A, Pointer B) - { - mul416_no_simd_gf2x_xor(res.array, A.array, A.cp, B.array, B.cp, Buffer, Buffer2); - } - } - - public static class Mul17 - extends Mul_GF2x - { - private long[] AA, BB, Buffer1, Buffer2; - - public Mul17() - { - AA = new long[5]; - BB = new long[5]; - Buffer1 = new long[17]; - Buffer2 = new long[4]; - } - - public void mul_gf2x(Pointer C, Pointer A, Pointer B) - { - mul544_no_simd_gf2x(C.array, A.array, A.cp, B.array, B.cp, AA, BB, Buffer1); - } - - public void sqr_gf2x(long[] res, long[] A, int a_cp) - { - res[16] = SQR32_NO_SIMD_GF2X(A[a_cp + 8]); - SQR256_NO_SIMD_GF2X(res, 8, A, a_cp + 4); - SQR256_NO_SIMD_GF2X(res, 0, A, a_cp); - } - - public void mul_gf2x_xor(Pointer res, Pointer A, Pointer B) - { - mul544_no_simd_gf2x_xor(res.array, A.array, A.cp, B.array, B.cp, AA, BB, Buffer1, Buffer2); - } - } - - private static long SQR32_NO_SIMD_GF2X(long A) - { - A = (A ^ (A << 16)) & (0x0000FFFF0000FFFFL); - A = (A ^ (A << 8)) & (0x00FF00FF00FF00FFL); - A = (A ^ (A << 4)) & (0x0F0F0F0F0F0F0F0FL); - A = (A ^ (A << 2)) & (0x3333333333333333L); - return (A ^ (A << 1)) & 0x5555555555555555L; - } - - /* 1+log_2(32)*3 = 1+5*3 = 16 instructions */ - private static long SQR64LOW_NO_SIMD_GF2X(long A) - { - A = ((A & 0xFFFFFFFFL) ^ (A << 16)) & (0x0000FFFF0000FFFFL); - A = (A ^ (A << 8)) & (0x00FF00FF00FF00FFL); - A = (A ^ (A << 4)) & (0x0F0F0F0F0F0F0F0FL); - A = (A ^ (A << 2)) & (0x3333333333333333L); - return (A ^ (A << 1)) & (0x5555555555555555L); - } - - private static void SQR64_NO_SIMD_GF2X(long[] C, int c_cp, long A) - { - C[c_cp + 1] = SQR32_NO_SIMD_GF2X(A >>> 32); - C[c_cp] = SQR64LOW_NO_SIMD_GF2X(A); - } - - private static void SQR128_NO_SIMD_GF2X(long[] C, int c_cp, long[] A, int a_cp) - { - SQR64_NO_SIMD_GF2X(C, c_cp + 2, A[a_cp + 1]); - SQR64_NO_SIMD_GF2X(C, c_cp, A[a_cp]); - } - - private static void SQR256_NO_SIMD_GF2X(long[] C, int c_cp, long[] A, int a_cp) - { - SQR128_NO_SIMD_GF2X(C, c_cp + 4, A, a_cp + 2); - SQR128_NO_SIMD_GF2X(C, c_cp, A, a_cp); - } - - private static long MUL32_NO_SIMD_GF2X(long a, long b) - { - long tmp = (-(b & 1L)) & a; - tmp ^= ((-((b >>> 1) & 1L)) & a) << 1; - tmp ^= ((-((b >>> 2) & 1L)) & a) << 2; - tmp ^= ((-((b >>> 3) & 1L)) & a) << 3; - tmp ^= ((-((b >>> 4) & 1L)) & a) << 4; - tmp ^= ((-((b >>> 5) & 1L)) & a) << 5; - tmp ^= ((-((b >>> 6) & 1L)) & a) << 6; - tmp ^= ((-((b >>> 7) & 1L)) & a) << 7; - tmp ^= ((-((b >>> 8) & 1L)) & a) << 8; - tmp ^= ((-((b >>> 9) & 1L)) & a) << 9; - tmp ^= ((-((b >>> 10) & 1L)) & a) << 10; - tmp ^= ((-((b >>> 11) & 1L)) & a) << 11; - tmp ^= ((-((b >>> 12) & 1L)) & a) << 12; - tmp ^= ((-((b >>> 13) & 1L)) & a) << 13; - tmp ^= ((-((b >>> 14) & 1L)) & a) << 14; - tmp ^= ((-((b >>> 15) & 1L)) & a) << 15; - tmp ^= ((-((b >>> 16) & 1L)) & a) << 16; - tmp ^= ((-((b >>> 17) & 1L)) & a) << 17; - tmp ^= ((-((b >>> 18) & 1L)) & a) << 18; - tmp ^= ((-((b >>> 19) & 1L)) & a) << 19; - tmp ^= ((-((b >>> 20) & 1L)) & a) << 20; - tmp ^= ((-((b >>> 21) & 1L)) & a) << 21; - tmp ^= ((-((b >>> 22) & 1L)) & a) << 22; - tmp ^= ((-((b >>> 23) & 1L)) & a) << 23; - tmp ^= ((-((b >>> 24) & 1L)) & a) << 24; - tmp ^= ((-((b >>> 25) & 1L)) & a) << 25; - tmp ^= ((-((b >>> 26) & 1L)) & a) << 26; - tmp ^= ((-((b >>> 27) & 1L)) & a) << 27; - tmp ^= ((-((b >>> 28) & 1L)) & a) << 28; - tmp ^= ((-((b >>> 29) & 1L)) & a) << 29; - tmp ^= ((-((b >>> 30) & 1L)) & a) << 30; - tmp ^= ((-((b >>> 31) & 1L)) & a) << 31; - return tmp; - } - - private static void MUL64_NO_SIMD_GF2X(long[] C, int c_cp, long A, long B) - { - long c0, c1, tmp; - c0 = (-(B & 1L)) & A; - /* Optimization: the '&1' is removed */ - tmp = ((-(B >>> 63)) & A); - c0 ^= tmp << 63; - c1 = tmp >>> 1; - tmp = ((-((B >>> 1) & 1L)) & A); - c0 ^= tmp << 1; - c1 ^= tmp >>> 63; - tmp = ((-((B >>> 2) & 1L)) & A); - c0 ^= tmp << 2; - c1 ^= tmp >>> 62; - tmp = ((-((B >>> 3) & 1L)) & A); - c0 ^= tmp << 3; - c1 ^= tmp >>> 61; - tmp = ((-((B >>> 4) & 1L)) & A); - c0 ^= tmp << 4; - c1 ^= tmp >>> 60; - tmp = ((-((B >>> 5) & 1L)) & A); - c0 ^= tmp << 5; - c1 ^= tmp >>> 59; - tmp = ((-((B >>> 6) & 1L)) & A); - c0 ^= tmp << 6; - c1 ^= tmp >>> 58; - tmp = ((-((B >>> 7) & 1L)) & A); - c0 ^= tmp << 7; - c1 ^= tmp >>> 57; - tmp = ((-((B >>> 8) & 1L)) & A); - c0 ^= tmp << 8; - c1 ^= tmp >>> 56; - tmp = ((-((B >>> 9) & 1L)) & A); - c0 ^= tmp << 9; - c1 ^= tmp >>> 55; - tmp = ((-((B >>> 10) & 1L)) & A); - c0 ^= tmp << 10; - c1 ^= tmp >>> 54; - tmp = ((-((B >>> 11) & 1L)) & A); - c0 ^= tmp << 11; - c1 ^= tmp >>> 53; - tmp = ((-((B >>> 12) & 1L)) & A); - c0 ^= tmp << 12; - c1 ^= tmp >>> 52; - tmp = ((-((B >>> 13) & 1L)) & A); - c0 ^= tmp << 13; - c1 ^= tmp >>> 51; - tmp = ((-((B >>> 14) & 1L)) & A); - c0 ^= tmp << 14; - c1 ^= tmp >>> 50; - tmp = ((-((B >>> 15) & 1L)) & A); - c0 ^= tmp << 15; - c1 ^= tmp >>> 49; - tmp = ((-((B >>> 16) & 1L)) & A); - c0 ^= tmp << 16; - c1 ^= tmp >>> 48; - tmp = ((-((B >>> 17) & 1L)) & A); - c0 ^= tmp << 17; - c1 ^= tmp >>> 47; - tmp = ((-((B >>> 18) & 1L)) & A); - c0 ^= tmp << 18; - c1 ^= tmp >>> 46; - tmp = ((-((B >>> 19) & 1L)) & A); - c0 ^= tmp << 19; - c1 ^= tmp >>> 45; - tmp = ((-((B >>> 20) & 1L)) & A); - c0 ^= tmp << 20; - c1 ^= tmp >>> 44; - tmp = ((-((B >>> 21) & 1L)) & A); - c0 ^= tmp << 21; - c1 ^= tmp >>> 43; - tmp = ((-((B >>> 22) & 1L)) & A); - c0 ^= tmp << 22; - c1 ^= tmp >>> 42; - tmp = ((-((B >>> 23) & 1L)) & A); - c0 ^= tmp << 23; - c1 ^= tmp >>> 41; - tmp = ((-((B >>> 24) & 1L)) & A); - c0 ^= tmp << 24; - c1 ^= tmp >>> 40; - tmp = ((-((B >>> 25) & 1L)) & A); - c0 ^= tmp << 25; - c1 ^= tmp >>> 39; - tmp = ((-((B >>> 26) & 1L)) & A); - c0 ^= tmp << 26; - c1 ^= tmp >>> 38; - tmp = ((-((B >>> 27) & 1L)) & A); - c0 ^= tmp << 27; - c1 ^= tmp >>> 37; - tmp = ((-((B >>> 28) & 1L)) & A); - c0 ^= tmp << 28; - c1 ^= tmp >>> 36; - tmp = ((-((B >>> 29) & 1L)) & A); - c0 ^= tmp << 29; - c1 ^= tmp >>> 35; - tmp = ((-((B >>> 30) & 1L)) & A); - c0 ^= tmp << 30; - c1 ^= tmp >>> 34; - tmp = ((-((B >>> 31) & 1L)) & A); - c0 ^= tmp << 31; - c1 ^= tmp >>> 33; - tmp = ((-((B >>> 32) & 1L)) & A); - c0 ^= tmp << 32; - c1 ^= tmp >>> 32; - tmp = ((-((B >>> 33) & 1L)) & A); - c0 ^= tmp << 33; - c1 ^= tmp >>> 31; - tmp = ((-((B >>> 34) & 1L)) & A); - c0 ^= tmp << 34; - c1 ^= tmp >>> 30; - tmp = ((-((B >>> 35) & 1L)) & A); - c0 ^= tmp << 35; - c1 ^= tmp >>> 29; - tmp = ((-((B >>> 36) & 1L)) & A); - c0 ^= tmp << 36; - c1 ^= tmp >>> 28; - tmp = ((-((B >>> 37) & 1L)) & A); - c0 ^= tmp << 37; - c1 ^= tmp >>> 27; - tmp = ((-((B >>> 38) & 1L)) & A); - c0 ^= tmp << 38; - c1 ^= tmp >>> 26; - tmp = ((-((B >>> 39) & 1L)) & A); - c0 ^= tmp << 39; - c1 ^= tmp >>> 25; - tmp = ((-((B >>> 40) & 1L)) & A); - c0 ^= tmp << 40; - c1 ^= tmp >>> 24; - tmp = ((-((B >>> 41) & 1L)) & A); - c0 ^= tmp << 41; - c1 ^= tmp >>> 23; - tmp = ((-((B >>> 42) & 1L)) & A); - c0 ^= tmp << 42; - c1 ^= tmp >>> 22; - tmp = ((-((B >>> 43) & 1L)) & A); - c0 ^= tmp << 43; - c1 ^= tmp >>> 21; - tmp = ((-((B >>> 44) & 1L)) & A); - c0 ^= tmp << 44; - c1 ^= tmp >>> 20; - tmp = ((-((B >>> 45) & 1L)) & A); - c0 ^= tmp << 45; - c1 ^= tmp >>> 19; - tmp = ((-((B >>> 46) & 1L)) & A); - c0 ^= tmp << 46; - c1 ^= tmp >>> 18; - tmp = ((-((B >>> 47) & 1L)) & A); - c0 ^= tmp << 47; - c1 ^= tmp >>> 17; - tmp = ((-((B >>> 48) & 1L)) & A); - c0 ^= tmp << 48; - c1 ^= tmp >>> 16; - tmp = ((-((B >>> 49) & 1L)) & A); - c0 ^= tmp << 49; - c1 ^= tmp >>> 15; - tmp = ((-((B >>> 50) & 1L)) & A); - c0 ^= tmp << 50; - c1 ^= tmp >>> 14; - tmp = ((-((B >>> 51) & 1L)) & A); - c0 ^= tmp << 51; - c1 ^= tmp >>> 13; - tmp = ((-((B >>> 52) & 1L)) & A); - c0 ^= tmp << 52; - c1 ^= tmp >>> 12; - tmp = ((-((B >>> 53) & 1L)) & A); - c0 ^= tmp << 53; - c1 ^= tmp >>> 11; - tmp = ((-((B >>> 54) & 1L)) & A); - c0 ^= tmp << 54; - c1 ^= tmp >>> 10; - tmp = ((-((B >>> 55) & 1L)) & A); - c0 ^= tmp << 55; - c1 ^= tmp >>> 9; - tmp = ((-((B >>> 56) & 1L)) & A); - c0 ^= tmp << 56; - c1 ^= tmp >>> 8; - tmp = ((-((B >>> 57) & 1L)) & A); - c0 ^= tmp << 57; - c1 ^= tmp >>> 7; - tmp = ((-((B >>> 58) & 1L)) & A); - c0 ^= tmp << 58; - c1 ^= tmp >>> 6; - tmp = ((-((B >>> 59) & 1L)) & A); - c0 ^= tmp << 59; - c1 ^= tmp >>> 5; - tmp = ((-((B >>> 60) & 1L)) & A); - c0 ^= tmp << 60; - c1 ^= tmp >>> 4; - tmp = ((-((B >>> 61) & 1L)) & A); - c0 ^= tmp << 61; - c1 ^= tmp >>> 3; - tmp = ((-((B >>> 62) & 1L)) & A); - C[c_cp] = c0 ^ (tmp << 62); - C[c_cp + 1] = c1 ^ (tmp >>> 2); - } - - private static void MUL64_NO_SIMD_GF2X_XOR(long[] C, int c_cp, long A, long B) - { - long c0, c1, tmp; - c0 = (-(B & 1L)) & A; - /* Optimization: the '&1' is removed */ - tmp = ((-(B >>> 63)) & A); - c0 ^= tmp << 63; - c1 = tmp >>> 1; - tmp = ((-((B >>> 1) & 1L)) & A); - c0 ^= tmp << 1; - c1 ^= tmp >>> 63; - tmp = ((-((B >>> 2) & 1L)) & A); - c0 ^= tmp << 2; - c1 ^= tmp >>> 62; - tmp = ((-((B >>> 3) & 1L)) & A); - c0 ^= tmp << 3; - c1 ^= tmp >>> 61; - tmp = ((-((B >>> 4) & 1L)) & A); - c0 ^= tmp << 4; - c1 ^= tmp >>> 60; - tmp = ((-((B >>> 5) & 1L)) & A); - c0 ^= tmp << 5; - c1 ^= tmp >>> 59; - tmp = ((-((B >>> 6) & 1L)) & A); - c0 ^= tmp << 6; - c1 ^= tmp >>> 58; - tmp = ((-((B >>> 7) & 1L)) & A); - c0 ^= tmp << 7; - c1 ^= tmp >>> 57; - tmp = ((-((B >>> 8) & 1L)) & A); - c0 ^= tmp << 8; - c1 ^= tmp >>> 56; - tmp = ((-((B >>> 9) & 1L)) & A); - c0 ^= tmp << 9; - c1 ^= tmp >>> 55; - tmp = ((-((B >>> 10) & 1L)) & A); - c0 ^= tmp << 10; - c1 ^= tmp >>> 54; - tmp = ((-((B >>> 11) & 1L)) & A); - c0 ^= tmp << 11; - c1 ^= tmp >>> 53; - tmp = ((-((B >>> 12) & 1L)) & A); - c0 ^= tmp << 12; - c1 ^= tmp >>> 52; - tmp = ((-((B >>> 13) & 1L)) & A); - c0 ^= tmp << 13; - c1 ^= tmp >>> 51; - tmp = ((-((B >>> 14) & 1L)) & A); - c0 ^= tmp << 14; - c1 ^= tmp >>> 50; - tmp = ((-((B >>> 15) & 1L)) & A); - c0 ^= tmp << 15; - c1 ^= tmp >>> 49; - tmp = ((-((B >>> 16) & 1L)) & A); - c0 ^= tmp << 16; - c1 ^= tmp >>> 48; - tmp = ((-((B >>> 17) & 1L)) & A); - c0 ^= tmp << 17; - c1 ^= tmp >>> 47; - tmp = ((-((B >>> 18) & 1L)) & A); - c0 ^= tmp << 18; - c1 ^= tmp >>> 46; - tmp = ((-((B >>> 19) & 1L)) & A); - c0 ^= tmp << 19; - c1 ^= tmp >>> 45; - tmp = ((-((B >>> 20) & 1L)) & A); - c0 ^= tmp << 20; - c1 ^= tmp >>> 44; - tmp = ((-((B >>> 21) & 1L)) & A); - c0 ^= tmp << 21; - c1 ^= tmp >>> 43; - tmp = ((-((B >>> 22) & 1L)) & A); - c0 ^= tmp << 22; - c1 ^= tmp >>> 42; - tmp = ((-((B >>> 23) & 1L)) & A); - c0 ^= tmp << 23; - c1 ^= tmp >>> 41; - tmp = ((-((B >>> 24) & 1L)) & A); - c0 ^= tmp << 24; - c1 ^= tmp >>> 40; - tmp = ((-((B >>> 25) & 1L)) & A); - c0 ^= tmp << 25; - c1 ^= tmp >>> 39; - tmp = ((-((B >>> 26) & 1L)) & A); - c0 ^= tmp << 26; - c1 ^= tmp >>> 38; - tmp = ((-((B >>> 27) & 1L)) & A); - c0 ^= tmp << 27; - c1 ^= tmp >>> 37; - tmp = ((-((B >>> 28) & 1L)) & A); - c0 ^= tmp << 28; - c1 ^= tmp >>> 36; - tmp = ((-((B >>> 29) & 1L)) & A); - c0 ^= tmp << 29; - c1 ^= tmp >>> 35; - tmp = ((-((B >>> 30) & 1L)) & A); - c0 ^= tmp << 30; - c1 ^= tmp >>> 34; - tmp = ((-((B >>> 31) & 1L)) & A); - c0 ^= tmp << 31; - c1 ^= tmp >>> 33; - tmp = ((-((B >>> 32) & 1L)) & A); - c0 ^= tmp << 32; - c1 ^= tmp >>> 32; - tmp = ((-((B >>> 33) & 1L)) & A); - c0 ^= tmp << 33; - c1 ^= tmp >>> 31; - tmp = ((-((B >>> 34) & 1L)) & A); - c0 ^= tmp << 34; - c1 ^= tmp >>> 30; - tmp = ((-((B >>> 35) & 1L)) & A); - c0 ^= tmp << 35; - c1 ^= tmp >>> 29; - tmp = ((-((B >>> 36) & 1L)) & A); - c0 ^= tmp << 36; - c1 ^= tmp >>> 28; - tmp = ((-((B >>> 37) & 1L)) & A); - c0 ^= tmp << 37; - c1 ^= tmp >>> 27; - tmp = ((-((B >>> 38) & 1L)) & A); - c0 ^= tmp << 38; - c1 ^= tmp >>> 26; - tmp = ((-((B >>> 39) & 1L)) & A); - c0 ^= tmp << 39; - c1 ^= tmp >>> 25; - tmp = ((-((B >>> 40) & 1L)) & A); - c0 ^= tmp << 40; - c1 ^= tmp >>> 24; - tmp = ((-((B >>> 41) & 1L)) & A); - c0 ^= tmp << 41; - c1 ^= tmp >>> 23; - tmp = ((-((B >>> 42) & 1L)) & A); - c0 ^= tmp << 42; - c1 ^= tmp >>> 22; - tmp = ((-((B >>> 43) & 1L)) & A); - c0 ^= tmp << 43; - c1 ^= tmp >>> 21; - tmp = ((-((B >>> 44) & 1L)) & A); - c0 ^= tmp << 44; - c1 ^= tmp >>> 20; - tmp = ((-((B >>> 45) & 1L)) & A); - c0 ^= tmp << 45; - c1 ^= tmp >>> 19; - tmp = ((-((B >>> 46) & 1L)) & A); - c0 ^= tmp << 46; - c1 ^= tmp >>> 18; - tmp = ((-((B >>> 47) & 1L)) & A); - c0 ^= tmp << 47; - c1 ^= tmp >>> 17; - tmp = ((-((B >>> 48) & 1L)) & A); - c0 ^= tmp << 48; - c1 ^= tmp >>> 16; - tmp = ((-((B >>> 49) & 1L)) & A); - c0 ^= tmp << 49; - c1 ^= tmp >>> 15; - tmp = ((-((B >>> 50) & 1L)) & A); - c0 ^= tmp << 50; - c1 ^= tmp >>> 14; - tmp = ((-((B >>> 51) & 1L)) & A); - c0 ^= tmp << 51; - c1 ^= tmp >>> 13; - tmp = ((-((B >>> 52) & 1L)) & A); - c0 ^= tmp << 52; - c1 ^= tmp >>> 12; - tmp = ((-((B >>> 53) & 1L)) & A); - c0 ^= tmp << 53; - c1 ^= tmp >>> 11; - tmp = ((-((B >>> 54) & 1L)) & A); - c0 ^= tmp << 54; - c1 ^= tmp >>> 10; - tmp = ((-((B >>> 55) & 1L)) & A); - c0 ^= tmp << 55; - c1 ^= tmp >>> 9; - tmp = ((-((B >>> 56) & 1L)) & A); - c0 ^= tmp << 56; - c1 ^= tmp >>> 8; - tmp = ((-((B >>> 57) & 1L)) & A); - c0 ^= tmp << 57; - c1 ^= tmp >>> 7; - tmp = ((-((B >>> 58) & 1L)) & A); - c0 ^= tmp << 58; - c1 ^= tmp >>> 6; - tmp = ((-((B >>> 59) & 1L)) & A); - c0 ^= tmp << 59; - c1 ^= tmp >>> 5; - tmp = ((-((B >>> 60) & 1L)) & A); - c0 ^= tmp << 60; - c1 ^= tmp >>> 4; - tmp = ((-((B >>> 61) & 1L)) & A); - c0 ^= tmp << 61; - c1 ^= tmp >>> 3; - tmp = ((-((B >>> 62) & 1L)) & A); - C[c_cp] ^= c0 ^ (tmp << 62); - C[c_cp + 1] ^= c1 ^ (tmp >>> 2); - } - - private static void mul128_no_simd_gf2x(long[] C, int c_cp, long[] A, int a_cp, long[] B, int b_cp) - { - MUL64_NO_SIMD_GF2X(C, c_cp, A[a_cp], B[b_cp]);//x0, x1 - MUL64_NO_SIMD_GF2X(C, c_cp + 2, A[a_cp + 1], B[b_cp + 1]);//x2, x3 - C[c_cp + 2] ^= C[c_cp + 1];//c2=x1+x2 - C[c_cp + 1] = C[c_cp] ^ C[c_cp + 2];//c1=x0+x1+x2 - C[c_cp + 2] ^= C[c_cp + 3];//c2=x1+x2+x3 - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 1, A[a_cp] ^ A[a_cp + 1], B[b_cp] ^ B[b_cp + 1]);//x4, x5 - } - - private static void mul128_no_simd_gf2x(long[] C, int c_cp, long a0, long a1, long b0, long b1) - { - MUL64_NO_SIMD_GF2X(C, c_cp, a0, b0);//x0, x1 - MUL64_NO_SIMD_GF2X(C, c_cp + 2, a1, b1);//x2, x3 - C[c_cp + 2] ^= C[c_cp + 1];//c2=x1+x2 - C[c_cp + 1] = C[c_cp] ^ C[c_cp + 2];//c1=x0+x1+x2 - C[c_cp + 2] ^= C[c_cp + 3];//c2=x1+x2+x3 - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 1, a0 ^ a1, b0 ^ b1);//x4, x5 - } - - private static void mul128_no_simd_gf2x_xor(long[] C, int c_cp, long a0, long a1, long b0, long b1, long[] RESERVED_BUF) - { - MUL64_NO_SIMD_GF2X(RESERVED_BUF, 0, a0, b0);//x0, x1 - //c0=x0, c1=x1 - MUL64_NO_SIMD_GF2X(RESERVED_BUF, 2, a1, b1);//x2, x3 - //c2=x2, c3=x3 - C[c_cp] ^= RESERVED_BUF[0]; //x0 - RESERVED_BUF[2] ^= RESERVED_BUF[1];//x1+x2 - C[c_cp + 1] ^= RESERVED_BUF[0] ^ RESERVED_BUF[2];//x0+x1+x2 - C[c_cp + 2] ^= RESERVED_BUF[2] ^ RESERVED_BUF[3];//x1+x2+x3 - C[c_cp + 3] ^= RESERVED_BUF[3];//x3 - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 1, a0 ^ a1, b0 ^ b1);//x4, x5 - } - - public static void mul192_no_simd_gf2x(long[] C, int c_cp, long[] A, int a_cp, long[] B, int b_cp) - { - /* A0*B0 */ - MUL64_NO_SIMD_GF2X(C, c_cp, A[a_cp], B[b_cp]);//x0, x1 - /* A2*B2 */ - MUL64_NO_SIMD_GF2X(C, c_cp + 4, A[a_cp + 2], B[b_cp + 2]);//x4,x5 - /* A1*B1 */ - MUL64_NO_SIMD_GF2X(C, c_cp + 2, A[a_cp + 1], B[b_cp + 1]);//x2, x3 - C[c_cp + 1] ^= C[c_cp + 2];//C1=x1^x2 - C[c_cp + 3] ^= C[c_cp + 4];//c3=x3^x4 - C[c_cp + 4] = C[c_cp + 3] ^ C[c_cp + 5];//c4=x3+x4+x5 - C[c_cp + 2] = C[c_cp + 3] ^ C[c_cp + 1] ^ C[c_cp];//c2=x1+x2+x3+x4 - C[c_cp + 3] = C[c_cp + 1] ^ C[c_cp + 4];//c3=x1+x2+x4+x5 - C[c_cp + 1] ^= C[c_cp]; - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 1, A[a_cp] ^ A[a_cp + 1], B[b_cp] ^ B[b_cp + 1]);//x6, x7 - /* (A1+A2)*(B1+B2) */ - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 3, A[a_cp + 1] ^ A[a_cp + 2], B[b_cp + 1] ^ B[b_cp + 2]);//x10, x11 - /* (A0+A2)*(B0+B2) */ - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 2, A[a_cp] ^ A[a_cp + 2], B[b_cp] ^ B[b_cp + 2]);//x8, x9 - } - - public static void mul192_no_simd_gf2x_xor(long[] C, int c_cp, long[] A, int a_cp, long[] B, int b_cp, long[] Buffer) - { - /* A0*B0 */ - MUL64_NO_SIMD_GF2X(Buffer, 0, A[a_cp], B[b_cp]);//x0, x1 - /* A2*B2 */ - MUL64_NO_SIMD_GF2X(Buffer, 4, A[a_cp + 2], B[b_cp + 2]);//x4,x5 - /* A1*B1 */ - MUL64_NO_SIMD_GF2X(Buffer, 2, A[a_cp + 1], B[b_cp + 1]);//x2, x3 - C[c_cp] ^= Buffer[0]; - Buffer[1] ^= Buffer[2];//C1=x1^x2 - Buffer[3] ^= Buffer[4];//c3=x3^x4 - Buffer[4] = Buffer[3] ^ Buffer[5];//c4=x3+x4+x5 - Buffer[0] ^= Buffer[1]; - C[c_cp + 1] ^= Buffer[0]; - C[c_cp + 2] ^= Buffer[3] ^ Buffer[0];//c2=x1+x2+x3+x4 - C[c_cp + 3] ^= Buffer[1] ^ Buffer[4];//c3=x1+x2+x4+x5 - C[c_cp + 4] ^= Buffer[4]; - C[c_cp + 5] ^= Buffer[5]; - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 1, A[a_cp] ^ A[a_cp + 1], B[b_cp] ^ B[b_cp + 1]);//x6, x7 - /* (A1+A2)*(B1+B2) */ - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 3, A[a_cp + 1] ^ A[a_cp + 2], B[b_cp + 1] ^ B[b_cp + 2]);//x10, x11 - /* (A0+A2)*(B0+B2) */ - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 2, A[a_cp] ^ A[a_cp + 2], B[b_cp] ^ B[b_cp + 2]);//x8, x9 - } - - private static void mul288_no_simd_gf2x(long[] C, int c_cp, long[] A, int a_cp, long[] B, int b_cp, long[] RESERVED_BUF) - { - mul128_no_simd_gf2x(C, c_cp, A[a_cp], A[a_cp + 1], B[b_cp], B[b_cp + 1]); - MUL64_NO_SIMD_GF2X(C, c_cp + 4, A[a_cp + 2], B[b_cp + 2]); //x0,x1 - MUL64_NO_SIMD_GF2X(C, c_cp + 7, A[a_cp + 3], B[b_cp + 3]);//x2,x3 - C[c_cp + 7] ^= C[c_cp + 5];//x1+x2 - C[c_cp + 8] ^= MUL32_NO_SIMD_GF2X(A[a_cp + 4], B[b_cp + 4]);//x3+x4 - C[c_cp + 5] = C[c_cp + 7] ^ C[c_cp + 4];//x0+x1+x2 - C[c_cp + 7] ^= C[c_cp + 8];//x1+x2+x3+x4 - C[c_cp + 6] = C[c_cp + 7] ^ C[c_cp + 4];//x0+x1+x2+x3+x4 - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 5, A[a_cp + 2] ^ A[a_cp + 3], B[b_cp + 2] ^ B[b_cp + 3]);//x4, x5 - /* (A1+A2)*(B1+B2) */ - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 7, A[a_cp + 3] ^ A[a_cp + 4], B[b_cp + 3] ^ B[b_cp + 4]);//x6, x7 - /* (A0+A2)*(B0+B2) */ - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 6, A[a_cp + 2] ^ A[a_cp + 4], B[b_cp + 2] ^ B[b_cp + 4]);//x2,x3 - C[c_cp + 4] ^= C[c_cp + 2]; - C[c_cp + 5] ^= C[c_cp + 3]; - long AA0 = A[a_cp] ^ A[a_cp + 2]; - long AA1 = A[a_cp + 1] ^ A[a_cp + 3]; - long BB0 = B[b_cp] ^ B[b_cp + 2]; - long BB1 = B[b_cp + 1] ^ B[b_cp + 3]; - MUL64_NO_SIMD_GF2X(RESERVED_BUF, 0, AA0, BB0); //x0,x1 - MUL64_NO_SIMD_GF2X(RESERVED_BUF, 2, AA1, BB1);//x2,x3 - RESERVED_BUF[2] ^= RESERVED_BUF[1];//x1+x2 - RESERVED_BUF[3] ^= MUL32_NO_SIMD_GF2X(A[a_cp + 4], B[b_cp + 4]);//x3+x4 - C[c_cp + 2] = C[c_cp + 4] ^ C[c_cp] ^ RESERVED_BUF[0]; - C[c_cp + 3] = C[c_cp + 5] ^ C[c_cp + 1] ^ RESERVED_BUF[2] ^ RESERVED_BUF[0];//x0+x1+x2 - RESERVED_BUF[2] ^= RESERVED_BUF[3];//x1+x2+x3+x4 - C[c_cp + 4] ^= C[c_cp + 6] ^ RESERVED_BUF[2] ^ RESERVED_BUF[0];//x0+x1+x2+x3+x4 - C[c_cp + 5] ^= C[c_cp + 7] ^ RESERVED_BUF[2]; - C[c_cp + 6] ^= C[c_cp + 8] ^ RESERVED_BUF[3]; - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 3, AA0 ^ AA1, BB0 ^ BB1);//x4, x5 - /* (A1+A2)*(B1+B2) */ - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 5, AA1 ^ A[a_cp + 4], BB1 ^ B[b_cp + 4]);//x6, x7 - /* (A0+A2)*(B0+B2) */ - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 4, AA0 ^ A[a_cp + 4], BB0 ^ B[b_cp + 4]);//x2,x3 - } - - private static void mul288_no_simd_gf2x_xor(long[] C, int c_cp, long[] A, int a_cp, long[] B, int b_cp, long[] Buffer) - { - mul128_no_simd_gf2x(Buffer, 0, A[a_cp], A[a_cp + 1], B[b_cp], B[b_cp + 1]); - MUL64_NO_SIMD_GF2X(Buffer, 4, A[a_cp + 2], B[b_cp + 2]); //x0,x1 - MUL64_NO_SIMD_GF2X(Buffer, 7, A[a_cp + 3], B[b_cp + 3]);//x2,x3 - Buffer[7] ^= Buffer[5];//x1+x2 - Buffer[8] ^= MUL32_NO_SIMD_GF2X(A[a_cp + 4], B[b_cp + 4]);//x3+x4 - Buffer[5] = Buffer[7] ^ Buffer[4];//x0+x1+x2 - Buffer[7] ^= Buffer[8];//x1+x2+x3+x4 - Buffer[6] = Buffer[7] ^ Buffer[4];//x0+x1+x2+x3+x4 - Buffer[4] ^= Buffer[2]; - Buffer[5] ^= Buffer[3]; - C[c_cp] ^= Buffer[0]; - C[c_cp + 1] ^= Buffer[1]; - C[c_cp + 2] ^= Buffer[4] ^ Buffer[0]; - MUL64_NO_SIMD_GF2X_XOR(Buffer, 5, A[a_cp + 2] ^ A[a_cp + 3], B[b_cp + 2] ^ B[b_cp + 3]);//x4, x5 - /* (A1+A2)*(B1+B2) */ - MUL64_NO_SIMD_GF2X_XOR(Buffer, 7, A[a_cp + 3] ^ A[a_cp + 4], B[b_cp + 3] ^ B[b_cp + 4]);//x6, x7 - /* (A0+A2)*(B0+B2) */ - MUL64_NO_SIMD_GF2X_XOR(Buffer, 6, A[a_cp + 2] ^ A[a_cp + 4], B[b_cp + 2] ^ B[b_cp + 4]);//x2,x3 - C[c_cp + 3] ^= Buffer[5] ^ Buffer[1]; - C[c_cp + 4] ^= Buffer[4] ^ Buffer[6]; - C[c_cp + 5] ^= Buffer[5] ^ Buffer[7]; - C[c_cp + 6] ^= Buffer[6] ^ Buffer[8]; - C[c_cp + 7] ^= Buffer[7]; - C[c_cp + 8] ^= Buffer[8]; - long AA0 = A[a_cp] ^ A[a_cp + 2]; - long AA1 = A[a_cp + 1] ^ A[a_cp + 3]; - long BB0 = B[b_cp] ^ B[b_cp + 2]; - long BB1 = B[b_cp + 1] ^ B[b_cp + 3]; - MUL64_NO_SIMD_GF2X(Buffer, 0, AA0, BB0); //x0,x1 - MUL64_NO_SIMD_GF2X(Buffer, 2, AA1, BB1);//x2,x3 - Buffer[2] ^= Buffer[1];//x1+x2 - Buffer[3] ^= MUL32_NO_SIMD_GF2X(A[a_cp + 4], B[b_cp + 4]);//x3+x4 - C[c_cp + 2] ^= Buffer[0]; - C[c_cp + 3] ^= Buffer[2] ^ Buffer[0];//x0+x1+x2 - Buffer[2] ^= Buffer[3];//x1+x2+x3+x4 - C[c_cp + 4] ^= Buffer[2] ^ Buffer[0];//x0+x1+x2+x3+x4 - C[c_cp + 5] ^= Buffer[2]; - C[c_cp + 6] ^= Buffer[3]; - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 3, AA0 ^ AA1, BB0 ^ BB1);//x4, x5 - /* (A1+A2)*(B1+B2) */ - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 5, AA1 ^ A[a_cp + 4], BB1 ^ B[b_cp + 4]);//x6, x7 - /* (A0+A2)*(B0+B2) */ - MUL64_NO_SIMD_GF2X_XOR(C, c_cp + 4, AA0 ^ A[a_cp + 4], BB0 ^ B[b_cp + 4]);//x2,x3 - } - - private static void mul384_no_simd_gf2x(long[] C, long[] A, int a_cp, long[] B, int b_cp, long[] Buffer) - { - mul192_no_simd_gf2x(C, 0, A, a_cp, B, b_cp); - mul192_no_simd_gf2x(C, 6, A, a_cp + 3, B, b_cp + 3); - long AA0 = A[a_cp] ^ A[a_cp + 3]; - long AA1 = A[a_cp + 1] ^ A[a_cp + 4]; - long AA2 = A[a_cp + 2] ^ A[a_cp + 5]; - long BB0 = B[b_cp] ^ B[b_cp + 3]; - long BB1 = B[b_cp + 1] ^ B[b_cp + 4]; - long BB2 = B[b_cp + 2] ^ B[b_cp + 5]; - C[6] ^= C[3]; - C[7] ^= C[4]; - C[8] ^= C[5]; - MUL64_NO_SIMD_GF2X(Buffer, 0, AA0, BB0);//x0, x1 - /* A2*B2 */ - MUL64_NO_SIMD_GF2X(Buffer, 4, AA2, BB2);//x4,x5 - /* A1*B1 */ - MUL64_NO_SIMD_GF2X(Buffer, 2, AA1, BB1);//x2, x3 - C[3] = C[6] ^ C[0] ^ Buffer[0]; - Buffer[1] ^= Buffer[2];//C1=x1^x2 - Buffer[0] ^= Buffer[1]; - Buffer[3] ^= Buffer[4];//c3=x3^x4 - Buffer[4] = Buffer[3] ^ Buffer[5];//c4=x3+x4+x5 - C[5] = C[8] ^ C[2] ^ Buffer[3] ^ Buffer[0];//c2=x1+x2+x3+x4 - C[6] ^= C[9] ^ Buffer[1] ^ Buffer[4];//c3=x1+x2+x4+x5 - C[4] = C[7] ^ C[1] ^ Buffer[0]; - C[7] ^= C[10] ^ Buffer[4]; - C[8] ^= C[11] ^ Buffer[5]; - MUL64_NO_SIMD_GF2X_XOR(C, 4, AA0 ^ AA1, BB0 ^ BB1);//x6, x7 - /* (A1+A2)*(B1+B2) */ - MUL64_NO_SIMD_GF2X_XOR(C, 6, AA1 ^ AA2, BB1 ^ BB2);//x10, x11 - /* (A0+A2)*(B0+B2) */ - MUL64_NO_SIMD_GF2X_XOR(C, 5, AA0 ^ AA2, BB0 ^ BB2);//x8, x9 - } - - private static void mul384_no_simd_gf2x_xor(long[] C, long[] A, int a_cp, long[] B, int b_cp, long[] Buffer) - { - mul192_no_simd_gf2x(Buffer, 0, A, a_cp, B, b_cp); - mul192_no_simd_gf2x(Buffer, 6, A, a_cp + 3, B, b_cp + 3); - long AA0 = A[a_cp] ^ A[a_cp + 3]; - long AA1 = A[a_cp + 1] ^ A[a_cp + 4]; - long AA2 = A[a_cp + 2] ^ A[a_cp + 5]; - long BB0 = B[b_cp] ^ B[b_cp + 3]; - long BB1 = B[b_cp + 1] ^ B[b_cp + 4]; - long BB2 = B[b_cp + 2] ^ B[b_cp + 5]; - Buffer[6] ^= Buffer[3]; - Buffer[7] ^= Buffer[4]; - Buffer[8] ^= Buffer[5]; - C[0] ^= Buffer[0]; - C[1] ^= Buffer[1]; - C[2] ^= Buffer[2]; - C[3] ^= Buffer[6] ^ Buffer[0]; - C[5] ^= Buffer[8] ^ Buffer[2]; - C[6] ^= Buffer[6] ^ Buffer[9]; - C[4] ^= Buffer[7] ^ Buffer[1]; - C[7] ^= Buffer[7] ^ Buffer[10]; - C[8] ^= Buffer[8] ^ Buffer[11]; - C[9] ^= Buffer[9]; - C[10] ^= Buffer[10]; - C[11] ^= Buffer[11]; - MUL64_NO_SIMD_GF2X(Buffer, 0, AA0, BB0);//x0, x1 - /* A2*B2 */ - MUL64_NO_SIMD_GF2X(Buffer, 4, AA2, BB2);//x4,x5 - /* A1*B1 */ - MUL64_NO_SIMD_GF2X(Buffer, 2, AA1, BB1);//x2, x3 - C[3] ^= Buffer[0]; - Buffer[1] ^= Buffer[2];//C1=x1^x2 - Buffer[0] ^= Buffer[1]; - Buffer[3] ^= Buffer[4];//c3=x3^x4 - Buffer[4] = Buffer[3] ^ Buffer[5];//c4=x3+x4+x5 - C[5] ^= Buffer[3] ^ Buffer[0];//c2=x1+x2+x3+x4 - C[6] ^= Buffer[1] ^ Buffer[4];//c3=x1+x2+x4+x5 - C[4] ^= Buffer[0]; - C[7] ^= Buffer[4]; - C[8] ^= Buffer[5]; - MUL64_NO_SIMD_GF2X_XOR(C, 4, AA0 ^ AA1, BB0 ^ BB1);//x6, x7 - /* (A1+A2)*(B1+B2) */ - MUL64_NO_SIMD_GF2X_XOR(C, 6, AA1 ^ AA2, BB1 ^ BB2);//x10, x11 - /* (A0+A2)*(B0+B2) */ - MUL64_NO_SIMD_GF2X_XOR(C, 5, AA0 ^ AA2, BB0 ^ BB2);//x8, x9 - } - - private static void mul416_no_simd_gf2x(long[] C, long[] A, int a_cp, long[] B, int b_cp, long[] RESERVED_BUF) - { - mul192_no_simd_gf2x(C, 0, A, a_cp, B, b_cp); - mul128_no_simd_gf2x(C, 6, A[a_cp + 3], A[a_cp + 4], B[b_cp + 3], B[b_cp + 4]); - MUL64_NO_SIMD_GF2X(C, 10, A[a_cp + 5], B[b_cp + 5]); - C[12] = MUL32_NO_SIMD_GF2X(A[a_cp + 6], B[b_cp + 6]) ^ C[11]; - C[11] = C[10] ^ C[12]; - MUL64_NO_SIMD_GF2X_XOR(C, 11, A[a_cp + 5] ^ A[a_cp + 6], B[b_cp + 5] ^ B[b_cp + 6]); - C[8] ^= C[10]; - C[11] ^= C[9]; - C[10] = C[8] ^ C[12]; - C[8] ^= C[6]; - C[9] = C[11] ^ C[7]; - mul128_no_simd_gf2x_xor(C, 8, A[a_cp + 3] ^ A[a_cp + 5], A[a_cp + 4] ^ A[a_cp + 6], - B[b_cp + 3] ^ B[b_cp + 5], B[b_cp + 4] ^ B[b_cp + 6], RESERVED_BUF); - long AA0 = A[a_cp] ^ A[a_cp + 3]; - long AA1 = A[a_cp + 1] ^ A[a_cp + 4]; - long AA2 = A[a_cp + 2] ^ A[a_cp + 5]; - long AA3 = A[a_cp + 6]; - long BB0 = B[b_cp] ^ B[b_cp + 3]; - long BB1 = B[b_cp + 1] ^ B[b_cp + 4]; - long BB2 = B[b_cp + 2] ^ B[b_cp + 5]; - long BB3 = B[b_cp + 6]; - C[6] ^= C[3]; - C[7] ^= C[4]; - C[8] ^= C[5]; - mul128_no_simd_gf2x(RESERVED_BUF, 0, AA0, AA1, BB0, BB1); - MUL64_NO_SIMD_GF2X(RESERVED_BUF, 4, AA2, BB2); - RESERVED_BUF[6] = MUL32_NO_SIMD_GF2X(AA3, BB3) ^ RESERVED_BUF[5]; - RESERVED_BUF[5] = RESERVED_BUF[4] ^ RESERVED_BUF[6]; - MUL64_NO_SIMD_GF2X_XOR(RESERVED_BUF, 5, AA2 ^ AA3, BB2 ^ BB3); - C[3] = C[6] ^ C[0] ^ RESERVED_BUF[0]; - C[4] = C[7] ^ C[1] ^ RESERVED_BUF[1]; - RESERVED_BUF[2] ^= RESERVED_BUF[4]; - RESERVED_BUF[3] ^= RESERVED_BUF[5]; - C[5] = C[8] ^ C[2] ^ RESERVED_BUF[2] ^ RESERVED_BUF[0]; - C[6] ^= C[9] ^ RESERVED_BUF[3] ^ RESERVED_BUF[1]; - C[7] ^= C[10] ^ RESERVED_BUF[2] ^ RESERVED_BUF[6]; - C[8] ^= C[11] ^ RESERVED_BUF[3]; - C[9] ^= C[12] ^ RESERVED_BUF[6]; - mul128_no_simd_gf2x_xor(C, 5, AA0 ^ AA2, AA1 ^ AA3, BB0 ^ BB2, BB1 ^ BB3, RESERVED_BUF); - } - - private static void mul416_no_simd_gf2x_xor(long[] C, long[] A, int a_cp, long[] B, int b_cp, long[] Buffer, long[] Buffer2) - { - mul192_no_simd_gf2x(Buffer, 0, A, a_cp, B, b_cp); - mul128_no_simd_gf2x(Buffer, 6, A[a_cp + 3], A[a_cp + 4], B[b_cp + 3], B[b_cp + 4]); - MUL64_NO_SIMD_GF2X(Buffer, 10, A[a_cp + 5], B[b_cp + 5]); - Buffer[12] = MUL32_NO_SIMD_GF2X(A[a_cp + 6], B[b_cp + 6]) ^ Buffer[11]; - Buffer[11] = Buffer[10] ^ Buffer[12]; - MUL64_NO_SIMD_GF2X_XOR(Buffer, 11, A[a_cp + 5] ^ A[a_cp + 6], B[b_cp + 5] ^ B[b_cp + 6]); - Buffer[8] ^= Buffer[10]; - Buffer[11] ^= Buffer[9]; - Buffer[10] = Buffer[8] ^ Buffer[12]; - Buffer[8] ^= Buffer[6]; - Buffer[9] = Buffer[11] ^ Buffer[7]; - Buffer[6] ^= Buffer[3]; - Buffer[7] ^= Buffer[4]; - Buffer[8] ^= Buffer[5]; - mul128_no_simd_gf2x_xor(Buffer, 8, A[a_cp + 3] ^ A[a_cp + 5], A[a_cp + 4] ^ A[a_cp + 6], - B[b_cp + 3] ^ B[b_cp + 5], B[b_cp + 4] ^ B[b_cp + 6], Buffer2); - C[0] ^= Buffer[0]; - C[1] ^= Buffer[1]; - C[2] ^= Buffer[2]; - C[3] ^= Buffer[6] ^ Buffer[0]; - C[4] ^= Buffer[7] ^ Buffer[1]; - C[5] ^= Buffer[8] ^ Buffer[2]; - C[6] ^= Buffer[6] ^ Buffer[9]; - C[7] ^= Buffer[7] ^ Buffer[10]; - C[8] ^= Buffer[8] ^ Buffer[11]; - C[9] ^= Buffer[9] ^ Buffer[12]; - C[10] ^= Buffer[10]; - C[11] ^= Buffer[11]; - C[12] ^= Buffer[12]; - long AA0 = A[a_cp] ^ A[a_cp + 3]; - long AA1 = A[a_cp + 1] ^ A[a_cp + 4]; - long AA2 = A[a_cp + 2] ^ A[a_cp + 5]; - long AA3 = A[a_cp + 6]; - long BB0 = B[b_cp] ^ B[b_cp + 3]; - long BB1 = B[b_cp + 1] ^ B[b_cp + 4]; - long BB2 = B[b_cp + 2] ^ B[b_cp + 5]; - long BB3 = B[b_cp + 6]; - mul128_no_simd_gf2x(Buffer, 0, AA0, AA1, BB0, BB1); - MUL64_NO_SIMD_GF2X(Buffer, 4, AA2, BB2); - Buffer[6] = MUL32_NO_SIMD_GF2X(AA3, BB3) ^ Buffer[5]; - Buffer[5] = Buffer[4] ^ Buffer[6]; - MUL64_NO_SIMD_GF2X_XOR(Buffer, 5, AA2 ^ AA3, BB2 ^ BB3); - C[3] ^= Buffer[0]; - C[4] ^= Buffer[1]; - Buffer[2] ^= Buffer[4]; - Buffer[3] ^= Buffer[5]; - C[5] ^= Buffer[2] ^ Buffer[0]; - C[6] ^= Buffer[3] ^ Buffer[1]; - C[7] ^= Buffer[2] ^ Buffer[6]; - C[8] ^= Buffer[3]; - C[9] ^= Buffer[6]; - mul128_no_simd_gf2x_xor(C, 5, AA0 ^ AA2, AA1 ^ AA3, BB0 ^ BB2, BB1 ^ BB3, Buffer); - } - - private static void mul544_no_simd_gf2x(long[] C, long[] A, int a_cp, long[] B, int b_cp, long[] AA, long[] BB, - long[] RESERVED_BUF9) - { - mul128_no_simd_gf2x(C, 0, A[a_cp], A[a_cp + 1], B[b_cp], B[b_cp + 1]); - mul128_no_simd_gf2x(C, 4, A[a_cp + 2], A[a_cp + 3], B[b_cp + 2], B[b_cp + 3]); - C[4] ^= C[2]; - C[5] ^= C[3]; - C[2] = C[4] ^ C[0]; - C[3] = C[5] ^ C[1]; - C[4] ^= C[6]; - C[5] ^= C[7]; - mul128_no_simd_gf2x_xor(C, 2, A[a_cp] ^ A[a_cp + 2], A[a_cp + 1] ^ A[a_cp + 3], - B[b_cp] ^ B[b_cp + 2], B[b_cp + 1] ^ B[b_cp + 3], RESERVED_BUF9); - mul288_no_simd_gf2x(C, 8, A, a_cp + 4, B, b_cp + 4, RESERVED_BUF9); - C[8] ^= C[4]; - C[9] ^= C[5]; - C[10] ^= C[6]; - C[11] ^= C[7]; - C[4] = C[8] ^ C[0]; - C[5] = C[9] ^ C[1]; - C[6] = C[10] ^ C[2]; - C[7] = C[11] ^ C[3]; - C[8] ^= C[12]; - C[9] ^= C[13]; - C[10] ^= C[14]; - C[11] ^= C[15]; - C[12] ^= C[16]; - AA[0] = A[a_cp] ^ A[a_cp + 4]; - AA[1] = A[a_cp + 1] ^ A[a_cp + 5]; - AA[2] = A[a_cp + 2] ^ A[a_cp + 6]; - AA[3] = A[a_cp + 3] ^ A[a_cp + 7]; - AA[4] = A[a_cp + 8]; - BB[0] = B[b_cp] ^ B[b_cp + 4]; - BB[1] = B[b_cp + 1] ^ B[b_cp + 5]; - BB[2] = B[b_cp + 2] ^ B[b_cp + 6]; - BB[3] = B[b_cp + 3] ^ B[b_cp + 7]; - BB[4] = B[b_cp + 8]; - mul288_no_simd_gf2x_xor(C, 4, AA, 0, BB, 0, RESERVED_BUF9); - } - - private static void mul544_no_simd_gf2x_xor(long[] C, long[] A, int a_cp, long[] B, int b_cp, long[] AA, long[] BB, - long[] Buffer, long[] Buffer2) - { - mul128_no_simd_gf2x(Buffer, 0, A[a_cp], A[a_cp + 1], B[b_cp], B[b_cp + 1]); - mul128_no_simd_gf2x(Buffer, 4, A[a_cp + 2], A[a_cp + 3], B[b_cp + 2], B[b_cp + 3]); - Buffer[4] ^= Buffer[2]; - Buffer[5] ^= Buffer[3]; - Buffer[2] = Buffer[4] ^ Buffer[0]; - Buffer[3] = Buffer[5] ^ Buffer[1]; - Buffer[4] ^= Buffer[6]; - Buffer[5] ^= Buffer[7]; - mul128_no_simd_gf2x_xor(Buffer, 2, A[a_cp] ^ A[a_cp + 2], A[a_cp + 1] ^ A[a_cp + 3], - B[b_cp] ^ B[b_cp + 2], B[b_cp + 1] ^ B[b_cp + 3], Buffer2); - mul288_no_simd_gf2x(Buffer, 8, A, a_cp + 4, B, b_cp + 4, Buffer2); - Buffer[8] ^= Buffer[4]; - Buffer[9] ^= Buffer[5]; - Buffer[10] ^= Buffer[6]; - Buffer[11] ^= Buffer[7]; - C[0] ^= Buffer[0]; - C[1] ^= Buffer[1]; - C[2] ^= Buffer[2]; - C[3] ^= Buffer[3]; - C[4] ^= Buffer[8] ^ Buffer[0]; - C[5] ^= Buffer[9] ^ Buffer[1]; - C[6] ^= Buffer[10] ^ Buffer[2]; - C[7] ^= Buffer[11] ^ Buffer[3]; - C[8] ^= Buffer[8] ^ Buffer[12]; - C[9] ^= Buffer[9] ^ Buffer[13]; - C[10] ^= Buffer[10] ^ Buffer[14]; - C[11] ^= Buffer[11] ^ Buffer[15]; - C[12] ^= Buffer[12] ^ Buffer[16]; - C[13] ^= Buffer[13]; - C[14] ^= Buffer[14]; - C[15] ^= Buffer[15]; - C[16] ^= Buffer[16]; - AA[0] = A[a_cp] ^ A[a_cp + 4]; - AA[1] = A[a_cp + 1] ^ A[a_cp + 5]; - AA[2] = A[a_cp + 2] ^ A[a_cp + 6]; - AA[3] = A[a_cp + 3] ^ A[a_cp + 7]; - AA[4] = A[a_cp + 8]; - BB[0] = B[b_cp] ^ B[b_cp + 4]; - BB[1] = B[b_cp + 1] ^ B[b_cp + 5]; - BB[2] = B[b_cp + 2] ^ B[b_cp + 6]; - BB[3] = B[b_cp + 3] ^ B[b_cp + 7]; - BB[4] = B[b_cp + 8]; - mul288_no_simd_gf2x_xor(C, 4, AA, 0, BB, 0, Buffer); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/Pointer.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/Pointer.java deleted file mode 100644 index 140024c63c..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/Pointer.java +++ /dev/null @@ -1,513 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -import java.security.SecureRandom; -import java.util.Arrays; - -import org.bouncycastle.util.Pack; - -class Pointer -{ - protected long[] array; - protected int cp; - - public Pointer() - { - cp = 0; - } - - public Pointer(int len) - { - array = new long[len]; - cp = 0; - } - - public Pointer(Pointer pointer) - { - array = pointer.array; - cp = pointer.cp; - } - - public Pointer(Pointer pointer, int shift) - { - array = pointer.array; - cp = pointer.cp + shift; - } - - public long get(int p) - { - return array[cp + p]; - } - - public long get() - { - return array[cp]; - } - - public void set(int p, long v) - { - array[cp + p] = v; - } - - public void set(long v) - { - array[cp] = v; - } - - public void setXor(int p, long v) - { - array[cp + p] ^= v; - } - - public void setXor(long v) - { - array[cp] ^= v; - } - - public void setXorRange(Pointer p, int len) - { - int outOff = cp; - int inOff = p.cp; - for (int i = 0; i < len; ++i) - { - array[outOff++] ^= p.array[inOff++]; - } - } - - public void setXorRange(Pointer p, int inOff, int len) - { - int outOff = cp; - inOff += p.cp; - for (int i = 0; i < len; ++i) - { - array[outOff++] ^= p.array[inOff++]; - } - } - - public void setXorRange(int outOff, Pointer p, int inOff, int len) - { - outOff += cp; - inOff += p.cp; - for (int i = 0; i < len; ++i) - { - array[outOff++] ^= p.array[inOff++]; - } - } - - public void setXorRange_SelfMove(Pointer p, int len) - { - int inOff = p.cp; - for (int i = 0; i < len; ++i) - { - array[cp++] ^= p.array[inOff++]; - } - } - - public void setXorMatrix_NoMove(Pointer p, int len1, int len2) - { - int outOff = cp; - int pos, i, j; - for (i = 0; i < len2; ++i) - { - for (j = 0, pos = outOff; j < len1; ++j) - { - array[pos++] ^= p.array[p.cp++]; - } - } - } - - public void setXorMatrix(Pointer p, int len1, int len2) - { - int outOff = cp; - int pos, i, j; - for (i = 0; i < len2; ++i) - { - for (j = 0, pos = outOff; j < len1; ++j) - { - array[pos++] ^= p.array[p.cp++]; - } - } - cp += len1; - } - - public void setXorRangeXor(int outOff, Pointer a, int a_cp, Pointer b, int b_cp, int len) - { - outOff += cp; - a_cp += a.cp; - b_cp += b.cp; - for (int i = 0; i < len; ++i) - { - array[outOff++] ^= a.array[a_cp++] ^ b.array[b_cp++]; - } - } - - public void setXorRange(int outOff, PointerUnion p, int inOff, int len) - { - outOff += cp; - inOff += p.cp; - if (p.remainder == 0) - { - for (int i = 0; i < len; ++i) - { - array[outOff++] ^= p.array[inOff++]; - } - } - else - { - int right = p.remainder << 3; - int left = ((8 - p.remainder) << 3); - for (int i = 0; i < len; ++i) - { - array[outOff++] ^= (p.array[inOff] >>> right) | (p.array[++inOff] << left); - } - } - } - - public void setXorRangeAndMask(Pointer p, int len, long mask) - { - int outOff = cp; - int inOff = p.cp; - for (int i = 0; i < len; ++i) - { - array[outOff++] ^= p.array[inOff++] & mask; - } - } - - public void setXorRangeAndMaskMove(Pointer p, int len, long mask) - { - int outOff = cp; - for (int i = 0; i < len; ++i) - { - array[outOff++] ^= p.array[p.cp++] & mask; - } - } - - public void setRangeRotate(int outOff, Pointer p, int inOff, int len, int right) - { - int left = 64 - right; - outOff += cp; - inOff += p.cp; - for (int i = 0; i < len; ++i) - { - array[outOff++] = (p.array[inOff] >>> left) ^ (p.array[++inOff] << right); - } - } - - public void move(int p) - { - cp += p; - } - - public void moveIncremental() - { - cp++; - } - - public long[] getArray() - { - return array; - } - - public int getIndex() - { - return cp; - } - - public void setAnd(int p, long v) - { - array[cp + p] &= v; - } - - public void setAnd(long v) - { - array[cp] &= v; - } - - public void setClear(int p) - { - array[cp + p] = 0; - } - - public void changeIndex(Pointer p) - { - array = p.array; - cp = p.cp; - } - - public void changeIndex(int p) - { - cp = p; - } - - public void changeIndex(Pointer p, int idx) - { - array = p.array; - cp = p.cp + idx; - } - - public void setRangeClear(int pos, int size) - { - pos += cp; - Arrays.fill(array, pos, pos + size, 0L); - } - - public int getLength() - { - return array.length - cp; - } - - public void copyFrom(Pointer src, int len) - { - System.arraycopy(src.array, src.cp, array, cp, len); - } - - public void copyFrom(int shift, Pointer src, int inOff, int len) - { - System.arraycopy(src.array, src.cp + inOff, array, cp + shift, len); - } - - public void set1_gf2n(int startPos, int size) - { - int pos = cp + startPos; - array[pos++] = 1L; - for (int i = 1; i < size; ++i) - { - array[pos++] = 0L; - } - } - - public byte[] toBytes(int length) - { - byte[] res = new byte[length]; - for (int i = 0; i < res.length; ++i) - { - res[i] = (byte)(array[cp + (i >>> 3)] >>> ((i & 7) << 3)); - } - return res; - } - - public void indexReset() - { - cp = 0; - } - - public void fillRandom(int shift, SecureRandom random, int length) - { - byte[] rv = new byte[length]; - random.nextBytes(rv); - fill(shift, rv, 0, rv.length); - } - - public void fill(int shift, byte[] arr, int input_cp, int len) - { - int i, q; - for (i = 0, q = cp + shift; q < array.length && i + 8 <= len; ++q) - { - array[q] = Pack.littleEndianToLong(arr, input_cp); - input_cp += 8; - i += 8; - } - if (i < len && q < array.length) - { - int r = 0; - array[q] = 0; - for (; r < 8 && i < len; ++r, ++input_cp, ++i) - { - array[q] |= (arr[input_cp] & 0xFFL) << (r << 3); - } - } - } - - public void setRangeFromXor(int outOff, Pointer a, int aOff, Pointer b, int bOff, int len) - { - outOff += cp; - aOff += a.cp; - bOff += b.cp; - for (int i = 0; i < len; ++i) - { - array[outOff++] = a.array[aOff++] ^ b.array[bOff++]; - } - } - - public void setRangeFromXor(Pointer a, Pointer b, int len) - { - for (int i = 0, outOff = cp, aOff = a.cp, bOff = b.cp; i < len; ++i) - { - array[outOff++] = a.array[aOff++] ^ b.array[bOff++]; - } - } - - public void setRangeFromXorAndMask_xor(Pointer a, Pointer b, long mask, int len) - { - int outOff = cp; - int a_cp = a.cp; - int b_cp = b.cp; - for (int i = 0; i < len; ++i) - { - array[outOff] = (a.array[a_cp] ^ b.array[b_cp]) & mask; - a.array[a_cp++] ^= array[outOff]; - b.array[b_cp++] ^= array[outOff++]; - } - } - - public int is0_gf2n(int p, int size) - { - long r = get(p); - for (int i = 1; i < size; ++i) - { - r |= get(p + i); - } - return (int)GeMSSUtils.NORBITS_UINT(r); - } - - public long getDotProduct(int off, Pointer b, int bOff, int len) - { - off += cp; - bOff += b.cp; - long res = array[off++] & b.array[bOff++]; - for (int i = 1; i < len; ++i) - { - res ^= array[off++] & b.array[bOff++]; - } - return res; - } - - public int getD_for_not0_or_plus(int NB_WORD_GFqn, int start) - { - int i, j, d, pos; - long mask, b; - /* Search the degree of X^(2^n) - X mod (F-U) */ - for (i = start, d = 0, mask = 0L, pos = cp; i > 0; --i) - { - b = array[pos++]; - for (j = 1; j < NB_WORD_GFqn; ++j) - { - b |= array[pos++]; - } - mask |= GeMSSUtils.ORBITS_UINT(b); - /* We add 1 to d as soon as we exceed all left zero coefficients */ - d += mask; - } - return d; - } - - public int setRange_xi(long xi, int k, int len) - { - for (int j = 0; j < len; ++j, ++k) - { - array[cp + k] = -((xi >>> j) & 1L); - } - return k; - } - - public int searchDegree(int da, int db, int NB_WORD_GFqn) - { - while (is0_gf2n(da * NB_WORD_GFqn, NB_WORD_GFqn) != 0 && da >= db) - { - --da; - } - return da; - } - - public void setRangePointerUnion(PointerUnion p, int len) - { - if (p.remainder == 0) - { - System.arraycopy(p.array, p.cp, array, cp, len); - } - else - { - int left = (8 - p.remainder) << 3; - int right = p.remainder << 3; - int outOff = cp; - int inOff = p.cp; - for (int i = 0; i < len; ++i) - { - array[outOff++] = (p.array[inOff] >>> right) ^ (p.array[++inOff] << left); - } - } - } - - public void setRangePointerUnion(PointerUnion p, int len, int shift) - { - int right2 = shift & 63; - int left2 = 64 - right2; - int outOff = cp; - int inOff = p.cp; - if (p.remainder == 0) - { - for (int i = 0; i < len; ++i) - { - array[outOff++] = (p.array[inOff] >>> right2) ^ (p.array[++inOff] << left2); - } - } - else - { - int right1 = p.remainder << 3; - int left1 = ((8 - p.remainder) << 3); - for (int i = 0; i < len; ++i) - { - array[outOff++] = (((p.array[inOff] >>> right1) | (p.array[++inOff] << left1)) >>> right2) ^ - (((p.array[inOff] >>> right1) | (p.array[inOff + 1] << left1)) << left2); - } - } - } - - public void setRangePointerUnion_Check(PointerUnion p, int len, int shift) - { - int right2 = shift & 63; - int left2 = 64 - right2; - int outOff = cp; - int inOff = p.cp; - int i; - if (p.remainder == 0) - { - for (i = 0; i < len && inOff < p.array.length - 1; ++i) - { - array[outOff++] = (p.array[inOff] >>> right2) ^ (p.array[++inOff] << left2); - } - if (i < len) - { - array[outOff] = (p.array[inOff] >>> right2); - } - } - else - { - int right1 = p.remainder << 3; - int left1 = ((8 - p.remainder) << 3); - for (i = 0; i < len && inOff < p.array.length - 2; ++i) - { - array[outOff++] = (((p.array[inOff] >>> right1) | (p.array[++inOff] << left1)) >>> right2) ^ - (((p.array[inOff] >>> right1) | (p.array[inOff + 1] << left1)) << left2); - } - if (i < len) - { - array[outOff] = (((p.array[inOff] >>> right1) | (p.array[++inOff] << left1)) >>> right2) ^ - ((p.array[inOff] >>> right1) << left2); - } - } - } - - public int isEqual_nocst_gf2(Pointer b, int len) - { - int inOff = b.cp; - int outOff = cp; - for (int i = 0; i < len; ++i) - { - if (array[outOff++] != b.array[inOff++]) - { - return 0; - } - } - return 1; - } - - public void swap(Pointer b) - { - long[] tmp_array = b.array; - int tmp_cp = b.cp; - b.array = array; - b.cp = cp; - array = tmp_array; - cp = tmp_cp; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/PointerUnion.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/PointerUnion.java deleted file mode 100644 index 02512b0676..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/PointerUnion.java +++ /dev/null @@ -1,332 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -import java.security.SecureRandom; - -class PointerUnion - extends Pointer -{ - protected int remainder; - - public PointerUnion(byte[] arr) - { - super((arr.length >> 3) + ((arr.length & 7) != 0 ? 1 : 0)); - for (int i = 0, q = 0, r; i < arr.length && q < array.length; ++q) - { - for (r = 0; r < 8 && i < arr.length; ++r, ++i) - { - array[q] |= (arr[i] & 0xFFL) << (r << 3); - } - } - remainder = 0; - } - - public PointerUnion(int p) - { - super((p >>> 3) + ((p & 7) != 0 ? 1 : 0)); - remainder = 0; - } - - public PointerUnion(PointerUnion p) - { - super(p); - remainder = p.remainder; - } - - public PointerUnion(Pointer p) - { - super(p); - remainder = 0; - } - - public void moveNextBytes(int p) - { - remainder += p; - cp += remainder >>> 3; - remainder &= 7; - } - - public void moveNextByte() - { - remainder++; - cp += remainder >>> 3; - remainder &= 7; - } - - @Override - public long get() - { - if (remainder == 0) - { - return array[cp]; - } - return (array[cp] >>> (remainder << 3)) | (array[cp + 1] << ((8 - remainder) << 3)); - } - - public long getWithCheck() - { - if (cp >= array.length) - { - return 0; - } - if (remainder == 0) - { - return array[cp]; - } - if (cp == array.length - 1) - { - return array[cp] >>> (remainder << 3); - } - return (array[cp] >>> (remainder << 3)) | (array[cp + 1] << ((8 - remainder) << 3)); - } - - public long getWithCheck(int p) - { - p += cp; - if (p >= array.length) - { - return 0; - } - if (remainder == 0) - { - return array[p]; - } - if (p == array.length - 1) - { - return array[p] >>> (remainder << 3); - } - return (array[p] >>> (remainder << 3)) | (array[p + 1] << ((8 - remainder) << 3)); - } - - @Override - public long get(int q) - { - if (remainder == 0) - { - return array[cp + q]; - } - return (array[cp + q] >>> (remainder << 3)) | (array[cp + q + 1] << ((8 - remainder) << 3)); - } - - public byte getByte() - { - return (byte)(array[cp] >>> (remainder << 3)); - } - - public byte getByte(int p) - { - int q = cp + ((p + remainder) >>> 3); - int r = (remainder + p) & 7; - return (byte)(array[q] >>> (r << 3)); - } - - @Override - public void setRangeClear(int startPos, int endPos) - { - if (remainder == 0) - { - super.setRangeClear(startPos, endPos); - } - else - { - array[cp + startPos] &= -1L >>> ((8 - remainder) << 3); - super.setRangeClear(startPos + 1, endPos); - array[cp + endPos + 1] &= -1L << (remainder << 3); - } - } - - @Override - public void setAnd(int p, long v) - { - if (remainder == 0) - { - super.setAnd(p, v); - } - else - { - int shift1 = remainder << 3, shift2 = (8 - remainder) << 3; - array[cp + p] &= (v << shift1) | (-1L >>> shift2); - array[cp + p + 1] &= (v >>> shift2) | (-1L << shift1); - } - } - - @Override - public void indexReset() - { - cp = 0; - remainder = 0; - } - - public void setByteIndex(int p) - { - remainder = p & 7; - cp = p >>> 3; - } - - @Override - public byte[] toBytes(int length) - { - byte[] res = new byte[length]; - for (int i = remainder; i < res.length + remainder; ++i) - { - res[i - remainder] = (byte)(array[cp + (i >>> 3)] >>> ((i & 7) << 3)); - } - return res; - } - - public int toBytesMove(byte[] output, int outOff, int length) - { - for (int i = 0; i < length; ++i) - { - output[outOff++] = (byte)(array[cp] >>> (remainder++ << 3)); - if (remainder == 8) - { - remainder = 0; - cp++; - } - } - return outOff; - } - - @Override - public void setXor(int p, long v) - { - if (remainder == 0) - { - super.setXor(p, v); - } - else - { - array[cp + p] ^= v << (remainder << 3); - array[cp + p + 1] ^= v >>> ((8 - remainder) << 3); - } - } - - @Override - public void setXor(long v) - { - if (remainder == 0) - { - super.setXor(v); - } - else - { - array[cp] ^= v << (remainder << 3); - array[cp + 1] ^= v >>> ((8 - remainder) << 3); - } - } - - public void setXorRangeAndMask(Pointer p, int len, long mask) - { - if (remainder == 0) - { - super.setXorRangeAndMask(p, len, mask); - return; - } - int outOff = cp, inOff = p.cp; - long v; - int left = remainder << 3, right = ((8 - remainder) << 3); - for (int i = 0; i < len; ++i) - { - //v = p.get(i) & mask; - v = p.array[inOff++] & mask; - array[outOff] ^= v << left; - array[++outOff] ^= v >>> right; - } - } - - public void setXorByte(int v) - { - array[cp] ^= (v & 0xFFL) << (remainder << 3); - } - - public void setAndByte(int p, long v) - { - int r = p + remainder + (cp << 3); - int q = r >>> 3; - r &= 7; - array[q] &= ((v & 0xFFL) << (r << 3)) | ~(0xFFL << (r << 3)); - } - - public void setAndThenXorByte(int p, long v1, long v2) - { - int r = p + remainder + (cp << 3); - int q = r >>> 3; - r &= 7; - array[q] &= ((v1 & 0xFFL) << (r << 3)) | ~(0xFFL << (r << 3)); - array[q] ^= (v2 & 0xFFL) << (r << 3); - } - - @Override - public void set(int p, long v) - { - if (remainder == 0) - { - super.setXor(p, v); - } - else - { - int shift1 = remainder << 3, shift2 = (8 - remainder) << 3; - array[cp + p] = (v << shift1) | (array[cp + p] & (-1L >>> shift2)); - array[cp + p + 1] = (v >>> shift2) | (array[cp + p + 1] & (-1L << shift1)); - } - } - - public void setByte(int v) - { - array[cp] = ((v & 0xFFL) << (remainder << 3)) | (array[cp] & (-1L >>> ((8 - remainder) << 3))); - } - - @Override - public void fill(int shift, byte[] arr, int input_cp, int len) - { - if (remainder != 0) - { - int q = cp + shift, r = remainder, i; - array[q] &= ~(-1L << (r << 3)); - for (i = 0; r < 8 && i < len; ++r) - { - array[q] |= (arr[input_cp] & 0xFFL) << (r << 3); - ++input_cp; - ++i; - } - shift++; - len -= 8 - remainder; - } - super.fill(shift, arr, input_cp, len); - } - - public void fillBytes(int shift, byte[] arr, int input_cp, int len) - { - int r = shift + remainder; - int q = cp + (r >>> 3); - r &= 7; - if (r != 0) - { - array[q] &= ~(-1L << (r << 3)); - int i = 0; - for (; r < 8 && i < len; ++r) - { - array[q] |= (arr[input_cp] & 0xFFL) << (r << 3); - ++input_cp; - ++i; - } - q++; - len -= i; - } - super.fill(q - cp, arr, input_cp, len); - } - - public void fillRandomBytes(int shift, SecureRandom random, int length) - { - byte[] rv = new byte[length]; - random.nextBytes(rv); - fillBytes(shift, rv, 0, rv.length); - } - - public void changeIndex(PointerUnion p) - { - array = p.array; - cp = p.cp; - remainder = p.remainder; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/Rem_GF2n.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/Rem_GF2n.java deleted file mode 100644 index 175158a2a9..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/Rem_GF2n.java +++ /dev/null @@ -1,463 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -abstract class Rem_GF2n -{ - public abstract void rem_gf2n(long[] P, int p_cp, long[] Pol); - - public abstract void rem_gf2n_xor(long[] P, int p_cp, long[] Pol); - - protected long mask; - protected int ki; - protected int ki64; - - public static class REM192_SPECIALIZED_TRINOMIAL_GF2X - extends Rem_GF2n - { - //gemss128, bluegemss128, redgemss128, whitegemss128, cyangemss128, magentagemss128 - private final int k3; - private final int k364; - private final int ki_k3;//(46, 13), (47, 16), (49, 8), (50, 31) - - REM192_SPECIALIZED_TRINOMIAL_GF2X(int k3, int ki, int ki64, int k364, long mask) - { - this.k3 = k3; - this.ki = ki; - this.ki64 = ki64; - this.k364 = k364; - this.mask = mask; - ki_k3 = ki - k3; - } - - public void rem_gf2n(long[] P, int p_cp, long[] Pol) - { - long Q0 = (Pol[2] >>> ki) ^ (Pol[3] << ki64); - long Q1 = (Pol[3] >>> ki) ^ (Pol[4] << ki64); - long Q2 = (Pol[4] >>> ki) ^ (Pol[5] << ki64);//min(ki64)=14 - P[p_cp + 1] = Pol[1] ^ Q1 ^ (Q0 >>> k364) ^ (Q1 << k3); - P[p_cp + 2] = (Pol[2] ^ Q2 ^ (Q1 >>> k364) ^ (Q2 << k3)) & mask; - Q0 ^= Q2 >>> ki_k3; - P[p_cp] = Pol[0] ^ Q0 ^ (Q0 << k3); - } - - public void rem_gf2n_xor(long[] P, int p_cp, long[] Pol) - { - long Q0 = (Pol[2] >>> ki) ^ (Pol[3] << ki64); - long Q1 = (Pol[3] >>> ki) ^ (Pol[4] << ki64); - long Q2 = (Pol[4] >>> ki) ^ (Pol[5] << ki64); - P[p_cp + 1] ^= Pol[1] ^ Q1 ^ (Q0 >>> k364) ^ (Q1 << k3); - P[p_cp + 2] ^= (Pol[2] ^ Q2 ^ (Q1 >>> k364) ^ (Q2 << k3)) & mask; - Q0 ^= Q2 >>> ki_k3; - P[p_cp] ^= Pol[0] ^ Q0 ^ (Q0 << k3); - } - } - - - public static class REM288_SPECIALIZED_TRINOMIAL_GF2X - extends Rem_GF2n - { - //gemss192, bluegemss192, redgemss192, whitegemss192, cyangemss192, magentagemss192, fgemss128, dualmodems128 - private final int k3; - private final int k364; - private final int k364ki; - private final int k3_ki; - - public REM288_SPECIALIZED_TRINOMIAL_GF2X(int k3, int ki, int ki64, int k364, long mask) - { - this.k3 = k3; - this.ki = ki; - this.ki64 = ki64; - this.k364 = k364; - this.mask = mask; - k364ki = k364 + ki; - k3_ki = k3 - ki; - } - - public void rem_gf2n(long[] P, int p_cp, long[] Pol) - { - long Q1 = (Pol[5] >>> ki) ^ (Pol[6] << ki64); - long Q2 = (Pol[6] >>> ki) ^ (Pol[7] << ki64); - P[p_cp + 2] = Pol[2] ^ Q2 ^ (Q1 >>> k364) ^ (Q2 << k3); - long Q3 = (Pol[7] >>> ki) ^ (Pol[8] << ki64); - P[p_cp + 3] = Pol[3] ^ Q3 ^ (Q2 >>> k364) ^ (Q3 << k3); - long Q4 = (Pol[8] >>> ki); - Q2 = (Pol[4] >>> ki) ^ (Pol[5] << ki64) ^ (Q3 >>> k364ki) ^ (Q4 << k3_ki); - P[p_cp + 4] = (Pol[4] ^ Q4 ^ (Q3 >>> k364) ^ (Q4 << k3)) & mask; - P[p_cp] = Pol[0] ^ Q2 ^ (Q2 << k3); - P[p_cp + 1] = Pol[1] ^ Q1 ^ (Q1 << k3) ^ (Q2 >>> k364); - } - - public void rem_gf2n_xor(long[] P, int p_cp, long[] Pol) - { - long Q1 = (Pol[5] >>> ki) ^ (Pol[6] << ki64); - long Q2 = (Pol[6] >>> ki) ^ (Pol[7] << ki64); - P[p_cp + 2] ^= Pol[2] ^ Q2 ^ (Q1 >>> k364) ^ (Q2 << k3); - long Q3 = (Pol[7] >>> ki) ^ (Pol[8] << ki64); - P[p_cp + 3] ^= Pol[3] ^ Q3 ^ (Q2 >>> k364) ^ (Q3 << k3); - Q2 = Pol[8] >>> ki; - P[p_cp + 4] ^= (Pol[4] ^ Q2 ^ (Q3 >>> k364) ^ (Q2 << k3)) & mask; - Q3 = (Pol[4] >>> ki) ^ (Pol[5] << ki64) ^ (Q3 >>> k364ki) ^ (Q2 << k3_ki); - P[p_cp] ^= Pol[0] ^ Q3 ^ (Q3 << k3); - P[p_cp + 1] ^= Pol[1] ^ Q1 ^ (Q1 << k3) ^ (Q3 >>> k364); - } - } - - public static class REM544_PENTANOMIAL_K3_IS_128_GF2X - extends Rem_GF2n - { - //dualmodems256 - private final int k1; - private final int k2; - private final int k164; - private final int k264; - - public REM544_PENTANOMIAL_K3_IS_128_GF2X(int k1, int k2, int ki, int ki64, int k164, int k264, long mask) - { - this.k1 = k1; - this.k2 = k2; - this.ki = ki; - this.ki64 = ki64; - this.k164 = k164; - this.k264 = k264; - this.mask = mask; - } - - public void rem_gf2n(long[] P, int p_cp, long[] Pol) - { - long Q2 = (Pol[10] >>> ki) ^ (Pol[11] << ki64); - long Q3 = (Pol[11] >>> ki) ^ (Pol[12] << ki64); - long Q1 = (Pol[12] >>> ki) ^ (Pol[13] << ki64); - P[p_cp + 4] = Pol[4] ^ Q1 ^ Q2 ^ (Q3 >>> k164) ^ (Q1 << k1) ^ (Q3 >>> k264) ^ (Q1 << k2); - long Q5 = (Pol[13] >>> ki) ^ (Pol[14] << ki64); - P[p_cp + 5] = Pol[5] ^ Q5 ^ Q3 ^ (Q1 >>> k164) ^ (Q5 << k1) ^ (Q1 >>> k264) ^ (Q5 << k2); - long Q0 = (Pol[14] >>> ki) ^ (Pol[15] << ki64); - P[p_cp + 6] = Pol[6] ^ Q0 ^ Q1 ^ (Q5 >>> k164) ^ (Q0 << k1) ^ (Q5 >>> k264) ^ (Q0 << k2); - Q1 = (Pol[15] >>> ki) ^ (Pol[16] << ki64); - P[p_cp + 7] = Pol[7] ^ Q1 ^ Q5 ^ (Q0 >>> k164) ^ (Q1 << k1) ^ (Q0 >>> k264) ^ (Q1 << k2); - Q5 = Pol[16] >>> ki; - P[p_cp + 8] = (Pol[8] ^ Q5 ^ Q0 ^ (Q1 >>> k164) ^ (Q5 << k1) ^ (Q1 >>> k264) ^ (Q5 << k2)) & mask; - Q0 = ((Pol[8] ^ Q0) >>> ki) ^ ((Pol[9] ^ Q1) << ki64) ^ (Pol[16] >>> k264); - Q1 = ((Pol[9] ^ Q1) >>> ki) ^ ((Pol[10] ^ Q5) << ki64); - P[p_cp] = Pol[0] ^ Q0 ^ (Q0 << k1) ^ (Q0 << k2); - P[p_cp + 1] = Pol[1] ^ Q1 ^ (Q0 >>> k164) ^ (Q1 << k1) ^ (Q0 >>> k264) ^ (Q1 << k2); - P[p_cp + 2] = Pol[2] ^ Q2 ^ Q0 ^ (Q1 >>> k164) ^ (Q2 << k1) ^ (Q1 >>> k264) ^ (Q2 << k2); - P[p_cp + 3] = Pol[3] ^ Q3 ^ Q1 ^ (Q2 >>> k164) ^ (Q3 << k1) ^ (Q2 >>> k264) ^ (Q3 << k2); - } - - public void rem_gf2n_xor(long[] P, int p_cp, long[] Pol) - { - long Q2 = (Pol[10] >>> ki) ^ (Pol[11] << ki64); - long Q3 = (Pol[11] >>> ki) ^ (Pol[12] << ki64); - long Q1 = (Pol[12] >>> ki) ^ (Pol[13] << ki64); - P[p_cp + 4] ^= Pol[4] ^ Q1 ^ Q2 ^ (Q3 >>> k164) ^ (Q1 << k1) ^ (Q3 >>> k264) ^ (Q1 << k2); - long Q5 = (Pol[13] >>> ki) ^ (Pol[14] << ki64); - P[p_cp + 5] ^= Pol[5] ^ Q5 ^ Q3 ^ (Q1 >>> k164) ^ (Q5 << k1) ^ (Q1 >>> k264) ^ (Q5 << k2); - long Q0 = (Pol[14] >>> ki) ^ (Pol[15] << ki64); - P[p_cp + 6] ^= Pol[6] ^ Q0 ^ Q1 ^ (Q5 >>> k164) ^ (Q0 << k1) ^ (Q5 >>> k264) ^ (Q0 << k2); - Q1 = (Pol[15] >>> ki) ^ (Pol[16] << ki64); - P[p_cp + 7] ^= Pol[7] ^ Q1 ^ Q5 ^ (Q0 >>> k164) ^ (Q1 << k1) ^ (Q0 >>> k264) ^ (Q1 << k2); - Q5 = Pol[16] >>> ki; - P[p_cp + 8] ^= (Pol[8] ^ Q5 ^ Q0 ^ (Q1 >>> k164) ^ (Q5 << k1) ^ (Q1 >>> k264) ^ (Q5 << k2)) & mask; - Q0 = ((Pol[8] ^ Q0) >>> ki) ^ ((Pol[9] ^ Q1) << ki64) ^ (Pol[16] >>> k264); - Q1 = ((Pol[9] ^ Q1) >>> ki) ^ ((Pol[10] ^ Q5) << ki64); - P[p_cp] ^= Pol[0] ^ Q0 ^ (Q0 << k1) ^ (Q0 << k2); - P[p_cp + 1] ^= Pol[1] ^ Q1 ^ (Q0 >>> k164) ^ (Q1 << k1) ^ (Q0 >>> k264) ^ (Q1 << k2); - P[p_cp + 2] ^= Pol[2] ^ Q2 ^ Q0 ^ (Q1 >>> k164) ^ (Q2 << k1) ^ (Q1 >>> k264) ^ (Q2 << k2); - P[p_cp + 3] ^= Pol[3] ^ Q3 ^ Q1 ^ (Q2 >>> k164) ^ (Q3 << k1) ^ (Q2 >>> k264) ^ (Q3 << k2); - } - } - - - public static class REM544_PENTANOMIAL_GF2X - extends Rem_GF2n - { - //fgemss256 - private final int k1; - private final int k2; - private final int k3; - private final int k164; - private final int k264; - private final int k364; - private final int ki_k3; - private final int ki_k2; - private final int ki_k1; - - public REM544_PENTANOMIAL_GF2X(int k1, int k2, int k3, int ki, int ki64, int k164, - int k264, int k364, long mask) - { - this.k1 = k1; - this.k2 = k2; - this.k3 = k3; - this.ki = ki; - this.ki64 = ki64; - this.k164 = k164; - this.k264 = k264; - this.k364 = k364; - this.mask = mask; - ki_k3 = ki - k3; - ki_k2 = ki - k2; - ki_k1 = ki - k1; - } - - public void rem_gf2n(long[] P, int p_cp, long[] Pol) - { - long Q8 = Pol[16] >>> ki; - long Q0 = (Pol[8] >>> ki) ^ (Pol[9] << ki64); - long Q1 = (Pol[9] >>> ki) ^ (Pol[10] << ki64); - P[p_cp + 1] = Pol[1] ^ Q1 ^ (Q0 >>> k164) ^ (Q1 << k1) ^ (Q0 >>> k264) ^ (Q1 << k2) ^ (Q0 >>> k364) ^ (Q1 << k3); - /* 64-(k364+ki) == (k3-ki) */ - Q0 ^= (Q8 >>> ki_k3) ^ (Q8 >>> ki_k2) ^ (Q8 >>> ki_k1); - P[p_cp] = Pol[0] ^ Q0 ^ (Q0 << k1) ^ (Q0 << k2) ^ (Q0 << k3); - Q0 = (Pol[10] >>> ki) ^ (Pol[11] << ki64); - P[p_cp + 2] = Pol[2] ^ Q0 ^ (Q1 >>> k164) ^ (Q0 << k1) ^ (Q1 >>> k264) ^ (Q0 << k2) ^ (Q1 >>> k364) ^ (Q0 << k3); - Q1 = (Pol[11] >>> ki) ^ (Pol[12] << ki64); - P[p_cp + 3] = Pol[3] ^ Q1 ^ (Q0 >>> k164) ^ (Q1 << k1) ^ (Q0 >>> k264) ^ (Q1 << k2) ^ (Q0 >>> k364) ^ (Q1 << k3); - Q0 = (Pol[12] >>> ki) ^ (Pol[13] << ki64); - P[p_cp + 4] = Pol[4] ^ Q0 ^ (Q1 >>> k164) ^ (Q0 << k1) ^ (Q1 >>> k264) ^ (Q0 << k2) ^ (Q1 >>> k364) ^ (Q0 << k3); - Q1 = (Pol[13] >>> ki) ^ (Pol[14] << ki64); - P[p_cp + 5] = Pol[5] ^ Q1 ^ (Q0 >>> k164) ^ (Q1 << k1) ^ (Q0 >>> k264) ^ (Q1 << k2) ^ (Q0 >>> k364) ^ (Q1 << k3); - Q0 = (Pol[14] >>> ki) ^ (Pol[15] << ki64); - P[p_cp + 6] = Pol[6] ^ Q0 ^ (Q1 >>> k164) ^ (Q0 << k1) ^ (Q1 >>> k264) ^ (Q0 << k2) ^ (Q1 >>> k364) ^ (Q0 << k3); - Q1 = (Pol[15] >>> ki) ^ (Pol[16] << ki64); - P[p_cp + 7] = Pol[7] ^ Q1 ^ (Q0 >>> k164) ^ (Q1 << k1) ^ (Q0 >>> k264) ^ (Q1 << k2) ^ (Q0 >>> k364) ^ (Q1 << k3); - P[p_cp + 8] = (Pol[8] ^ Q8 ^ (Q1 >>> k164) ^ (Q8 << k1) ^ (Q1 >>> k264) ^ (Q8 << k2) ^ (Q1 >>> k364) ^ (Q8 << k3)) & mask; - } - - public void rem_gf2n_xor(long[] P, int p_cp, long[] Pol) - {//KI: 25 - long Q8 = Pol[16] >>> ki; - long Q0 = (Pol[8] >>> ki) ^ (Pol[9] << ki64); - long Q1 = (Pol[9] >>> ki) ^ (Pol[10] << ki64); - P[p_cp + 1] ^= Pol[1] ^ Q1 ^ (Q0 >>> k164) ^ (Q1 << k1) ^ (Q0 >>> k264) ^ (Q1 << k2) ^ (Q0 >>> k364) ^ (Q1 << k3); - /* 64-(k364+ki) == (k3-ki) */ - Q0 ^= (Q8 >>> ki_k3) ^ (Q8 >>> ki_k2) ^ (Q8 >>> ki_k1); - P[p_cp] ^= Pol[0] ^ Q0 ^ (Q0 << k1) ^ (Q0 << k2) ^ (Q0 << k3); - Q0 = (Pol[10] >>> ki) ^ (Pol[11] << ki64); - P[p_cp + 2] ^= Pol[2] ^ Q0 ^ (Q1 >>> k164) ^ (Q0 << k1) ^ (Q1 >>> k264) ^ (Q0 << k2) ^ (Q1 >>> k364) ^ (Q0 << k3); - Q1 = (Pol[11] >>> ki) ^ (Pol[12] << ki64); - P[p_cp + 3] ^= Pol[3] ^ Q1 ^ (Q0 >>> k164) ^ (Q1 << k1) ^ (Q0 >>> k264) ^ (Q1 << k2) ^ (Q0 >>> k364) ^ (Q1 << k3); - Q0 = (Pol[12] >>> ki) ^ (Pol[13] << ki64); - P[p_cp + 4] ^= Pol[4] ^ Q0 ^ (Q1 >>> k164) ^ (Q0 << k1) ^ (Q1 >>> k264) ^ (Q0 << k2) ^ (Q1 >>> k364) ^ (Q0 << k3); - Q1 = (Pol[13] >>> ki) ^ (Pol[14] << ki64); - P[p_cp + 5] ^= Pol[5] ^ Q1 ^ (Q0 >>> k164) ^ (Q1 << k1) ^ (Q0 >>> k264) ^ (Q1 << k2) ^ (Q0 >>> k364) ^ (Q1 << k3); - Q0 = (Pol[14] >>> ki) ^ (Pol[15] << ki64); - P[p_cp + 6] ^= Pol[6] ^ Q0 ^ (Q1 >>> k164) ^ (Q0 << k1) ^ (Q1 >>> k264) ^ (Q0 << k2) ^ (Q1 >>> k364) ^ (Q0 << k3); - Q1 = (Pol[15] >>> ki) ^ (Pol[16] << ki64); - P[p_cp + 7] ^= Pol[7] ^ Q1 ^ (Q0 >>> k164) ^ (Q1 << k1) ^ (Q0 >>> k264) ^ (Q1 << k2) ^ (Q0 >>> k364) ^ (Q1 << k3); - P[p_cp + 8] ^= (Pol[8] ^ Q8 ^ (Q1 >>> k164) ^ (Q8 << k1) ^ (Q1 >>> k264) ^ (Q8 << k2) ^ (Q1 >>> k364) ^ (Q8 << k3)) & mask; - } - } - - public static class REM384_SPECIALIZED_TRINOMIAL_GF2X - extends Rem_GF2n - { - //gemss256 - private final int k3; - private final int k364; - private final int k364ki; - private final int k3_ki; - - public REM384_SPECIALIZED_TRINOMIAL_GF2X(int k3, int ki, int ki64, int k364, long mask) - { - this.k3 = k3; - this.ki = ki; - this.ki64 = ki64; - this.k364 = k364; - this.mask = mask; - k364ki = k364 + ki; - k3_ki = k3 - ki; - } - - public void rem_gf2n(long[] P, int p_cp, long[] Pol) - { - long Q2 = (Pol[7] >>> ki) ^ (Pol[8] << ki64); - long Q3 = (Pol[8] >>> ki) ^ (Pol[9] << ki64); - long Q4 = (Pol[9] >>> ki) ^ (Pol[10] << ki64); - long Q5 = (Pol[10] >>> ki) ^ (Pol[11] << ki64); - long Q0 = (Pol[5] >>> ki) ^ (Pol[6] << ki64) ^ (Q3 >>> (k364ki)) ^ (Q4 << (k3_ki)); - long Q1 = (Pol[6] >>> ki) ^ (Pol[7] << ki64) ^ (Q4 >>> (k364ki)) ^ (Q5 << (k3_ki)); - P[p_cp] = Pol[0] ^ Q0; - P[p_cp + 1] = Pol[1] ^ Q1 ^ (Q0 << k3); - P[p_cp + 2] = Pol[2] ^ Q2 ^ (Q0 >>> k364) ^ (Q1 << k3); - P[p_cp + 3] = Pol[3] ^ Q3 ^ (Q1 >>> k364) ^ (Q2 << k3); - P[p_cp + 4] = Pol[4] ^ Q4 ^ (Q2 >>> k364) ^ (Q3 << k3); - P[p_cp + 5] = (Pol[5] ^ Q5 ^ (Q3 >>> k364)) & mask; - } - - public void rem_gf2n_xor(long[] P, int p_cp, long[] Pol) - { - long Q2 = (Pol[7] >>> ki) ^ (Pol[8] << ki64); - long Q3 = (Pol[8] >>> ki) ^ (Pol[9] << ki64); - long Q4 = (Pol[9] >>> ki) ^ (Pol[10] << ki64); - long Q5 = (Pol[10] >>> ki) ^ (Pol[11] << ki64); - long Q0 = (Pol[5] >>> ki) ^ (Pol[6] << ki64) ^ (Q3 >>> (k364ki)) ^ (Q4 << (k3_ki)); - long Q1 = (Pol[6] >>> ki) ^ (Pol[7] << ki64) ^ (Q4 >>> (k364ki)) ^ (Q5 << (k3_ki)); - P[p_cp] ^= Pol[0] ^ Q0; - P[p_cp + 1] ^= Pol[1] ^ Q1 ^ (Q0 << k3); - P[p_cp + 2] ^= Pol[2] ^ Q2 ^ (Q0 >>> k364) ^ (Q1 << k3); - P[p_cp + 3] ^= Pol[3] ^ Q3 ^ (Q1 >>> k364) ^ (Q2 << k3); - P[p_cp + 4] ^= Pol[4] ^ Q4 ^ (Q2 >>> k364) ^ (Q3 << k3); - P[p_cp + 5] ^= (Pol[5] ^ Q5 ^ (Q3 >>> k364)) & mask; - } - } - - public static class REM384_SPECIALIZED358_TRINOMIAL_GF2X - extends Rem_GF2n - { - //bluegemss256, redgemss256 - private final int k3; - private final int k364; - private final int k364ki; - private final int k3_ki; - - public REM384_SPECIALIZED358_TRINOMIAL_GF2X(int k3, int ki, int ki64, int k364, long mask) - { - this.k3 = k3; - this.ki = ki; - this.ki64 = ki64; - this.k364 = k364; - this.mask = mask; - k364ki = k364 + ki; - k3_ki = k3 - ki; - } - - public void rem_gf2n(long[] P, int p_cp, long[] Pol) - { - long Q1 = (Pol[6] >>> ki) ^ (Pol[7] << ki64); - long Q2 = (Pol[7] >>> ki) ^ (Pol[8] << ki64); - P[p_cp + 2] = Pol[2] ^ Q2 ^ (Q1 >>> k364) ^ (Q2 << k3); - long Q3 = (Pol[8] >>> ki) ^ (Pol[9] << ki64); - P[p_cp + 3] = Pol[3] ^ Q3 ^ (Q2 >>> k364) ^ (Q3 << k3); - Q2 = (Pol[9] >>> ki) ^ (Pol[10] << ki64); - P[p_cp + 4] = Pol[4] ^ Q2 ^ (Q3 >>> k364) ^ (Q2 << k3); - Q3 = (Pol[10] >>> ki) ^ (Pol[11] << ki64); - long Q0 = (Pol[5] >>> ki) ^ (Pol[6] << ki64) ^ (Q2 >>> k364ki) ^ (Q3 << k3_ki); - P[p_cp + 5] = (Pol[5] ^ Q3 ^ (Q2 >>> k364)) & mask; - /* 64-(k364+ki) == (k3-ki) */ - P[p_cp] = Pol[0] ^ Q0 ^ (Q0 << k3); - P[p_cp + 1] = Pol[1] ^ Q1 ^ (Q0 >>> k364) ^ (Q1 << k3); - } - - public void rem_gf2n_xor(long[] P, int p_cp, long[] Pol) - { - long Q1 = (Pol[6] >>> ki) ^ (Pol[7] << ki64); - long Q2 = (Pol[7] >>> ki) ^ (Pol[8] << ki64); - P[p_cp + 2] ^= Pol[2] ^ Q2 ^ (Q1 >>> k364) ^ (Q2 << k3); - long Q3 = (Pol[8] >>> ki) ^ (Pol[9] << ki64); - P[p_cp + 3] ^= Pol[3] ^ Q3 ^ (Q2 >>> k364) ^ (Q3 << k3); - Q2 = (Pol[9] >>> ki) ^ (Pol[10] << ki64); - P[p_cp + 4] ^= Pol[4] ^ Q2 ^ (Q3 >>> k364) ^ (Q2 << k3); - Q3 = (Pol[10] >>> ki) ^ (Pol[11] << ki64); - P[p_cp + 5] ^= (Pol[5] ^ Q3 ^ (Q2 >>> k364)) & mask; - Q2 = (Pol[5] >>> ki) ^ (Pol[6] << ki64) ^ (Q2 >>> k364ki) ^ (Q3 << k3_ki); - /* 64-(k364+ki) == (k3-ki) */ - P[p_cp] ^= Pol[0] ^ Q2 ^ (Q2 << k3); - P[p_cp + 1] ^= Pol[1] ^ Q1 ^ (Q2 >>> k364) ^ (Q1 << k3); - } - } - - public static class REM384_TRINOMIAL_GF2X - extends Rem_GF2n - { - //whitegemss256, cyangemss256, magentagemss256 - private final int k3; - private final int k364; - private final int ki_k3; - - public REM384_TRINOMIAL_GF2X(int k3, int ki, int ki64, int k364, long mask) - { - this.k3 = k3; - this.ki = ki; - this.ki64 = ki64; - this.k364 = k364; - this.mask = mask; - ki_k3 = ki - k3; - } - - public void rem_gf2n(long[] P, int p_cp, long[] Pol) - { - long Q0 = (Pol[5] >>> ki) ^ (Pol[6] << ki64); - long Q1 = (Pol[6] >>> ki) ^ (Pol[7] << ki64); - long Q2 = (Pol[7] >>> ki) ^ (Pol[8] << ki64); - long Q3 = (Pol[8] >>> ki) ^ (Pol[9] << ki64); - long Q4 = (Pol[9] >>> ki) ^ (Pol[10] << ki64); - long Q5 = (Pol[10] >>> ki) ^ (Pol[11] << ki64); - long R = Q0 ^ (Q5 >>> ki_k3); - P[p_cp] = Pol[0] ^ R ^ (R << k3); - P[p_cp + 1] = Pol[1] ^ Q1 ^ (Q0 >>> k364) ^ (Q1 << k3); - P[p_cp + 2] = Pol[2] ^ Q2 ^ (Q1 >>> k364) ^ (Q2 << k3); - P[p_cp + 3] = Pol[3] ^ Q3 ^ (Q2 >>> k364) ^ (Q3 << k3); - P[p_cp + 4] = Pol[4] ^ Q4 ^ (Q3 >>> k364) ^ (Q4 << k3); - P[p_cp + 5] = (Pol[5] ^ Q5 ^ (Q4 >>> k364) ^ (Q5 << k3)) & mask; - } - - public void rem_gf2n_xor(long[] P, int p_cp, long[] Pol) - { - long Q0 = (Pol[5] >>> ki) ^ (Pol[6] << ki64); - long Q1 = (Pol[6] >>> ki) ^ (Pol[7] << ki64); - long Q2 = (Pol[7] >>> ki) ^ (Pol[8] << ki64); - long Q3 = (Pol[8] >>> ki) ^ (Pol[9] << ki64); - long Q4 = (Pol[9] >>> ki) ^ (Pol[10] << ki64); - long Q5 = (Pol[10] >>> ki) ^ (Pol[11] << ki64); - long R = Q0 ^ (Q5 >>> ki_k3); - P[p_cp] ^= Pol[0] ^ R ^ (R << k3); - P[p_cp + 1] ^= Pol[1] ^ Q1 ^ (Q0 >>> k364) ^ (Q1 << k3); - P[p_cp + 2] ^= Pol[2] ^ Q2 ^ (Q1 >>> k364) ^ (Q2 << k3); - P[p_cp + 3] ^= Pol[3] ^ Q3 ^ (Q2 >>> k364) ^ (Q3 << k3); - P[p_cp + 4] ^= Pol[4] ^ Q4 ^ (Q3 >>> k364) ^ (Q4 << k3); - P[p_cp + 5] ^= (Pol[5] ^ Q5 ^ (Q4 >>> k364) ^ (Q5 << k3)) & mask; - } - } - - public static class REM402_SPECIALIZED_TRINOMIAL_GF2X - extends Rem_GF2n - { - //fgmess192 - private final int k3; - private final int k364; - - public REM402_SPECIALIZED_TRINOMIAL_GF2X(int k3, int ki, int ki64, int k364, long mask) - { - this.k3 = k3; - this.ki = ki; - this.ki64 = ki64; - this.k364 = k364; - this.mask = mask; - } - - public void rem_gf2n(long[] P, int p_cp, long[] Pol) - { - long Q3 = (Pol[9] >>> ki) ^ (Pol[10] << ki64); - long Q4 = (Pol[10] >>> ki) ^ (Pol[11] << ki64); - long Q5 = (Pol[11] >>> ki) ^ (Pol[12] << ki64); - long Q6 = (Pol[12] >>> ki); - long Q0 = (Q3 >>> 39) ^ (Q4 << 25) ^ (Pol[6] >>> ki) ^ (Pol[7] << ki64); - long Q1 = (Q4 >>> 39) ^ (Q5 << 25) ^ (Pol[7] >>> ki) ^ (Pol[8] << ki64); - long Q2 = (Q5 >>> 39) ^ (Q6 << 25) ^ (Pol[8] >>> ki) ^ (Pol[9] << ki64); - P[p_cp] = Pol[0] ^ Q0; - P[p_cp + 1] = Pol[1] ^ Q1; - P[p_cp + 2] = Pol[2] ^ Q2 ^ (Q0 << k3); - P[p_cp + 3] = Pol[3] ^ Q3 ^ (Q0 >>> k364) ^ (Q1 << k3); - P[p_cp + 4] = Pol[4] ^ Q4 ^ (Q1 >>> k364) ^ (Q2 << k3); - P[p_cp + 5] = Pol[5] ^ Q5 ^ (Q2 >>> k364) ^ (Q3 << k3); - P[p_cp + 6] = (Pol[6] ^ Q6 ^ (Q3 >>> k364)) & mask; - } - - public void rem_gf2n_xor(long[] P, int p_cp, long[] Pol) - { - long Q3 = (Pol[9] >>> ki) ^ (Pol[10] << ki64); - long Q4 = (Pol[10] >>> ki) ^ (Pol[11] << ki64); - long Q5 = (Pol[11] >>> ki) ^ (Pol[12] << ki64); - long Q6 = (Pol[12] >>> ki); - long Q0 = (Q3 >>> 39) ^ (Q4 << 25) ^ (Pol[6] >>> ki) ^ (Pol[7] << ki64); - long Q1 = (Q4 >>> 39) ^ (Q5 << 25) ^ (Pol[7] >>> ki) ^ (Pol[8] << ki64); - long Q2 = (Q5 >>> 39) ^ (Q6 << 25) ^ (Pol[8] >>> ki) ^ (Pol[9] << ki64); - P[p_cp] ^= Pol[0] ^ Q0; - P[p_cp + 1] ^= Pol[1] ^ Q1; - P[p_cp + 2] ^= Pol[2] ^ Q2 ^ (Q0 << k3); - P[p_cp + 3] ^= Pol[3] ^ Q3 ^ (Q0 >>> k364) ^ (Q1 << k3); - P[p_cp + 4] ^= Pol[4] ^ Q4 ^ (Q1 >>> k364) ^ (Q2 << k3); - P[p_cp + 5] ^= Pol[5] ^ Q5 ^ (Q2 >>> k364) ^ (Q3 << k3); - P[p_cp + 6] ^= (Pol[6] ^ Q6 ^ (Q3 >>> k364)) & mask; - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/SecretKeyHFE.java b/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/SecretKeyHFE.java deleted file mode 100644 index 7b431bea66..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/gemss/SecretKeyHFE.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.bouncycastle.pqc.crypto.gemss; - -class SecretKeyHFE -{ - static class complete_sparse_monic_gf2nx - { - public Pointer poly; - /* List of the successive differences of the exponents of the monomials of - poly multiplied by NB_WORD_GFqn */ - public int[] L; - - public complete_sparse_monic_gf2nx() - { - } - } - - complete_sparse_monic_gf2nx F_struct; - public Pointer F_HFEv; - - public Pointer S; - - public Pointer T; - - public Pointer sk_uncomp; - - - public SecretKeyHFE(GeMSSEngine engine) - { - F_struct = new complete_sparse_monic_gf2nx(); - F_struct.L = new int[engine.NB_COEFS_HFEPOLY]; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/FastFourierTransform.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/FastFourierTransform.java index 96fb29de84..fd14ca1743 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/FastFourierTransform.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/FastFourierTransform.java @@ -36,7 +36,7 @@ static void fastFourierTransform(int[] output, int[] elements, int noCoefs, int computeFFTRec(v, f1, noCoefs / 2, m - 1, fft - 1, deltas, fft, m); // Step 6.7 - int k = 1; + int k; k = 1 << (m - 1); System.arraycopy(v, 0, output, k, k); @@ -131,13 +131,13 @@ static void computeRadixBig(int[] f0, int[] f1, int[] f, int mf, int fft) n <<= (mf - 2); int fftSize = 1 << (fft - 2); - int Q[] = new int[2 * fftSize + 1]; - int R[] = new int[2 * fftSize + 1]; + int[] Q = new int[2 * fftSize + 1]; + int[] R = new int[2 * fftSize + 1]; - int Q0[] = new int[fftSize]; - int Q1[] = new int[fftSize]; - int R0[] = new int[fftSize]; - int R1[] = new int[fftSize]; + int[] Q0 = new int[fftSize]; + int[] Q1 = new int[fftSize]; + int[] R0 = new int[fftSize]; + int[] R1 = new int[fftSize]; Utils.copyBytes(f, 3 * n, Q, 0, 2 * n); @@ -168,13 +168,13 @@ static void computeFFTRec(int[] output, int[] func, int noCoeffs, int noOfBetas, int[] fx1 = new int[fftSize]; int[] gammaSet = new int[m - 2]; int[] deltaSet = new int[m - 2]; - int k = 1; + int k; int[] gammaSumSet = new int[mSize]; int[] uSet = new int[mSize]; int[] vSet = new int[mSize]; int[] tempSet = new int[m - fft + 1]; - int x = 0; + int x; if (noCoeffsPlus == 1) { for (int i = 0; i < noOfBetas; i++) @@ -235,9 +235,6 @@ static void computeFFTRec(int[] output, int[] func, int noCoeffs, int noOfBetas, { computeFFTRec(vSet, fx1, noCoeffs / 2, noOfBetas - 1, noCoeffsPlus - 1, deltaSet, fft, m); -// int[] tmp = new int[3*k]; -// System.arraycopy(output, 0, tmp, 0 , output.length); -// System.arraycopy(vSet, 0, tmp, k , 2*k); System.arraycopy(vSet, 0, output, k, k); output[0] = uSet[0]; @@ -247,8 +244,6 @@ static void computeFFTRec(int[] output, int[] func, int noCoeffs, int noOfBetas, output[i] = uSet[i] ^ GFCalculator.mult(gammaSumSet[i], vSet[i]); output[k + i] ^= output[i]; } - - } } @@ -259,21 +254,20 @@ static void fastFourierTransformGetError(byte[] errorSet, int[] input, int mSize int[] gammaSet = new int[m - 1]; int[] gammaSumSet = new int[mSize]; - int k = mSize; computeFFTBetas(gammaSet, m); computeSubsetSum(gammaSumSet, gammaSet, m - 1); errorSet[0] ^= 1 ^ Utils.toUnsigned16Bits(-input[0] >> 15); - errorSet[0] ^= 1 ^ Utils.toUnsigned16Bits(-input[k] >> 15); + errorSet[0] ^= 1 ^ Utils.toUnsigned16Bits(-input[mSize] >> 15); - for (int i = 1; i < k; i++) + for (int i = 1; i < mSize; i++) { int tmp = gfMulOrder - logArrays[gammaSumSet[i]]; errorSet[tmp] ^= 1 ^ Math.abs(-input[i] >> 15); tmp = gfMulOrder - logArrays[gammaSumSet[i] ^ 1]; - errorSet[tmp] ^= 1 ^ Math.abs(-input[k + i] >> 15); + errorSet[tmp] ^= 1 ^ Math.abs(-input[mSize + i] >> 15); } } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/GF2PolynomialCalculator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/GF2PolynomialCalculator.java index 60afde32eb..059f7459cd 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/GF2PolynomialCalculator.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/GF2PolynomialCalculator.java @@ -1,5 +1,7 @@ package org.bouncycastle.pqc.crypto.hqc; +import org.bouncycastle.util.Arrays; + class GF2PolynomialCalculator { private final int VEC_N_SIZE_64; @@ -13,218 +15,122 @@ class GF2PolynomialCalculator RED_MASK = red_mask; } - protected void multLongs(long[] res, long[] a, long[] b) + public void vectMul(long[] o, long[] a1, long[] a2) { - long[] stack = new long[VEC_N_SIZE_64 << 3]; - long[] o_karat = new long[(VEC_N_SIZE_64 << 1) + 1]; - - karatsuba(o_karat, 0, a, 0, b, 0, VEC_N_SIZE_64, stack, 0); - reduce(res, o_karat); + long[] unreduced = new long[VEC_N_SIZE_64 << 1]; + long[] tmpBuffer = new long[VEC_N_SIZE_64 << 4]; + karatsuba(unreduced, 0, a1, 0, a2, 0, VEC_N_SIZE_64, tmpBuffer, 0); + reduce(o, unreduced); } - - private void base_mul(long[] c, int cOffset, long a, long b) + /** + * Performs schoolbook multiplication over GF(2). + * + *

    This method computes {@code r = a * b}, where {@code a} and {@code b} are + * polynomials over GF(2), each represented as {@code n} 64-bit words. The result + * is stored in {@code r} as {@code 2 * n} 64-bit words.

    + */ + private void schoolbookMul(long[] r, int rOff, long[] a, int aOff, long[] b, int bOff, int n) { - long h = 0; - long l = 0; - long g; - long[] u = new long[16]; - long[] mask_tab = new long[4]; - - // Step 1 - u[0] = 0; - u[1] = b & ((1L << (64 - 4)) - 1L); - u[2] = u[1] << 1; - u[3] = u[2] ^ u[1]; - u[4] = u[2] << 1; - u[5] = u[4] ^ u[1]; - u[6] = u[3] << 1; - u[7] = u[6] ^ u[1]; - u[8] = u[4] << 1; - u[9] = u[8] ^ u[1]; - u[10] = u[5] << 1; - u[11] = u[10] ^ u[1]; - u[12] = u[6] << 1; - u[13] = u[12] ^ u[1]; - u[14] = u[7] << 1; - u[15] = u[14] ^ u[1]; - - g=0; - long tmp1 = a & 15; + Arrays.fill(r, rOff, rOff + (n << 1), 0L); - for(int i = 0; i < 16; i++) + for (int i = 0; i < n; i++, rOff++) { - long tmp2 = tmp1 - i; - g ^= (u[i] & -(1 - ((tmp2 | -tmp2) >>> 63))); - } - l = g; - h = 0; - - // Step 2 - for (byte i = 4; i < 64; i += 4) - { - g = 0; - long temp1 = (a >> i) & 15; - for (int j = 0; j < 16; ++j) + long ai = a[i + aOff]; + for (int bit = 0; bit < 64; bit++) { - long tmp2 = temp1 - j; - g ^= (u[j] & -(1 - ((tmp2 | -tmp2) >>> 63))); + long mask = -((ai >> bit) & 1L); + if (bit == 0) + { + for (int j = 0, rOff1 = rOff, bOff1 = bOff; j < n; j++, rOff1++, bOff1++) + { + r[rOff1] ^= b[bOff1] & mask; + } + } + else + { + int inv = 64 - bit; + for (int j = 0, rOff1 = rOff, bOff1 = bOff; j < n; j++, bOff1++) + { + r[rOff1++] ^= (b[bOff1] << bit) & mask; + r[rOff1] ^= (b[bOff1] >>> inv) & mask; + } + } } - - l ^= g << i; - h ^= g >>> (64 - i); - } - - // Step 3 - mask_tab [0] = - ((b >> 60) & 1); - mask_tab [1] = - ((b >> 61) & 1); - mask_tab [2] = - ((b >> 62) & 1); - mask_tab [3] = - ((b >> 63) & 1); - - l ^= ((a << 60) & mask_tab[0]); - h ^= ((a >>> 4) & mask_tab[0]); - - l ^= ((a << 61) & mask_tab[1]); - h ^= ((a >>> 3) & mask_tab[1]); - - l ^= ((a << 62) & mask_tab[2]); - h ^= ((a >>> 2) & mask_tab[2]); - - l ^= ((a << 63) & mask_tab[3]); - h ^= ((a >>> 1) & mask_tab[3]); - - c[0 + cOffset] = l; - c[1 + cOffset] = h; - } - - - - - private void karatsuba_add1(long[] alh, int alhOffset, - long[] blh, int blhOffset, - long[] a, int aOffset, - long[] b, int bOffset, - int size_l, int size_h) - { - for (int i = 0; i < size_h; i++) - { - alh[i + alhOffset] = a[i+ aOffset] ^ a[i + size_l + aOffset]; - blh[i + blhOffset] = b[i+ bOffset] ^ b[i + size_l + bOffset]; - } - - if (size_h < size_l) - { - alh[size_h + alhOffset] = a[size_h + aOffset]; - blh[size_h + blhOffset] = b[size_h + bOffset]; } } - - - private void karatsuba_add2(long[] o, int oOffset, - long[] tmp1, int tmp1Offset, - long[] tmp2, int tmp2Offset, - int size_l, int size_h) - { - for (int i = 0; i < (2 * size_l) ; i++) - { - tmp1[i + tmp1Offset] = tmp1[i + tmp1Offset] ^ o[i + oOffset]; - } - - for (int i = 0; i < ( 2 * size_h); i++) - { - tmp1[i + tmp1Offset] = tmp1[i + tmp1Offset] ^ tmp2[i + tmp2Offset]; - } - - for (int i = 0; i < (2 * size_l); i++) - { - o[i + size_l + oOffset] = o[i + size_l + oOffset] ^ tmp1[i + tmp1Offset]; - } - } - - - /** - * Karatsuba multiplication of a and b, Implementation inspired from the NTL library. + * Performs Karatsuba multiplication over GF(2) using a caller-supplied temporary buffer. + * + *

    If {@code n <= 16}, this method falls back to + * {@link #schoolbookMul(long[], int, long[], int, long[], int, int)}. + * Otherwise, the operands are split in half and the algorithm is applied recursively.

    * - * \param[out] o Polynomial - * \param[in] a Polynomial - * \param[in] b Polynomial - * \param[in] size Length of polynomial - * \param[in] stack Length of polynomial */ - private void karatsuba(long[] o, int oOffset, long[] a, int aOffset, long[] b, int bOffset, int size, long[] stack, int stackOffset) + private void karatsuba(long[] r, int rOffset, long[] a, int aOffset, + long[] b, int bOffset, int n, long[] tmpBuffer, int tmpOffset) { - int size_l, size_h; - int ahOffset, bhOffset; - - if (size == 1) + if (n <= 16) { - base_mul(o, oOffset, a[0 + aOffset], b[0 + bOffset]); + schoolbookMul(r, rOffset, a, aOffset, b, bOffset, n); return; } - size_h = size / 2; - size_l = (size + 1) / 2; - - // alh = stack - int alhOffset = stackOffset; - // blh = stack with size_l offset - int blhOffset = alhOffset + size_l; - // tmp1 = stack with size_l * 2 offset; - int tmp1Offset = blhOffset + size_l; - // tmp2 = o with size_l * 2 offset; - int tmp2Offset = oOffset + size_l*2; - - stackOffset += 4 * size_l; + int m = n >> 1; + int n1 = n - m; + int nx2 = n << 1; + int mx2 = m << 1; + int n1x2 = n1 << 1; - ahOffset = aOffset + size_l; - bhOffset = bOffset + size_l; + int z2Offset = tmpOffset + nx2; + int zMidOffset = z2Offset + nx2; + int taOffset = zMidOffset + nx2; + int tbOffset = taOffset + n; + int childBufferOffset = tmpOffset + (n << 3); - karatsuba(o, oOffset, a, aOffset, b, bOffset, size_l, stack, stackOffset); + karatsuba(tmpBuffer, tmpOffset, a, aOffset, b, bOffset, m, tmpBuffer, childBufferOffset); + karatsuba(tmpBuffer, z2Offset, a, aOffset + m, b, bOffset + m, n1, tmpBuffer, childBufferOffset); - karatsuba(o, tmp2Offset, a, ahOffset, b, bhOffset, size_h, stack, stackOffset); + for (int i = 0; i < n1; i++) + { + long loa = (i < m) ? a[aOffset + i] : 0; + long lob = (i < m) ? b[bOffset + i] : 0; + tmpBuffer[taOffset + i] = loa ^ a[aOffset + m + i]; + tmpBuffer[tbOffset + i] = lob ^ b[bOffset + m + i]; + } - karatsuba_add1(stack, alhOffset, stack, blhOffset, a, aOffset, b, bOffset, size_l, size_h); + karatsuba(tmpBuffer, zMidOffset, tmpBuffer, taOffset, tmpBuffer, tbOffset, n1, tmpBuffer, childBufferOffset); - karatsuba(stack, tmp1Offset, stack, alhOffset, stack, blhOffset, size_l, stack, stackOffset); + System.arraycopy(tmpBuffer, tmpOffset, r, rOffset, mx2); + System.arraycopy(tmpBuffer, z2Offset, r, rOffset + mx2, n1x2); - karatsuba_add2(o, oOffset, stack, tmp1Offset, o, tmp2Offset, size_l, size_h); + for (int i = 0; i < 2 * n1; i++) + { + long z0i = (i < mx2) ? tmpBuffer[tmpOffset + i] : 0; + long z2i = (i < n1x2) ? tmpBuffer[z2Offset + i] : 0; + r[rOffset + m + i] ^= tmpBuffer[zMidOffset + i] ^ z0i ^ z2i; + } } - - /** - * @brief Compute o(x) = a(x) mod \f$ X^n - 1\f$ + * Reduces a polynomial modulo {@code X^n - 1}. * - * This function computes the modular reduction of the polynomial a(x) + *

    This computes {@code o(x) = a(x) mod (X^n - 1)}, where + * {@code a(x)} may have degree up to {@code 2n - 2}. The result + * is a polynomial of degree less than {@code n}, represented as + * {@code n} 64-bit words.

    * - * @param[in] a Pointer to the polynomial a(x) - * @param[out] o Pointer to the result + * @param o the result buffer of length {@code n} words, + * where the reduced polynomial is stored + * @param a the input polynomial to be reduced */ private void reduce(long[] o, long[] a) { - int i; - long r; - long carry; - - for (i = 0; i < VEC_N_SIZE_64; i++) + for (int i = 0; i < VEC_N_SIZE_64; i++) { - r = a[i + VEC_N_SIZE_64 - 1] >>> (PARAM_N & 0x3F); - carry = (long) (a[i + VEC_N_SIZE_64 ] << (64 - (PARAM_N & 0x3FL))); - o[i] = a[i] ^ r ^ carry; + o[i] = a[i] ^ (a[i + VEC_N_SIZE_64 - 1] >>> (PARAM_N & 0x3F)) ^ ((a[i + VEC_N_SIZE_64] << (64 - (PARAM_N & 0x3FL)))); } o[VEC_N_SIZE_64 - 1] &= RED_MASK; } - - - - static void addLongs(long[] res, long[] a, long[] b) - { - for (int i = 0; i < a.length; i++) - { - res[i] = a[i] ^ b[i]; - } - } - } \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/GFCalculator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/GFCalculator.java index 715c0d8777..06b1be0924 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/GFCalculator.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/GFCalculator.java @@ -8,8 +8,7 @@ class GFCalculator static int mult(int a, int b) { - int mask; - mask = Utils.toUnsigned16Bits(-a >> 31); // a != 0 + int mask = Utils.toUnsigned16Bits(-a >> 31); // a != 0 mask &= Utils.toUnsigned16Bits(-b >> 31); // b != 0 return Utils.toUnsigned16Bits(mask & exp[mod(log[a] + log[b])]); } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCEngine.java index 49244d85fd..050c4ff682 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCEngine.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCEngine.java @@ -1,78 +1,66 @@ package org.bouncycastle.pqc.crypto.hqc; +import java.security.SecureRandom; + +import org.bouncycastle.crypto.digests.SHA3Digest; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Longs; import org.bouncycastle.util.Pack; class HQCEngine { - private int n; - private int n1; - private int n2; - private int k; - private int delta; - private int w; - private int wr; - private int we; - private int g; - private int rejectionThreshold; - private int fft; - private int mulParam; - - private int SEED_SIZE = 40; - private byte G_FCT_DOMAIN = 3; - private byte K_FCT_DOMAIN = 4; - - private int N_BYTE; - private int n1n2; - private int N_BYTE_64; - private int K_BYTE; - private int K_BYTE_64; - private int N1_BYTE_64; - private int N1N2_BYTE_64; - private int N1N2_BYTE; - private int N1_BYTE; - - private int GF_POLY_WT = 5; - private int GF_POLY_M2 = 4; - private int SALT_SIZE_BYTES = 16; - private int SALT_SIZE_64 = 2; - - private int[] generatorPoly; - private int SHA512_BYTES = 512 / 8; - - private long RED_MASK; - - private GF2PolynomialCalculator gfCalculator; - - public HQCEngine(int n, int n1, int n2, int k, int g, int delta, int w, int wr, int we, int rejectionThreshold, int fft, int[] generatorPoly) + private final int n; + private final int n1; + private final int k; + private final int delta; + private final int w; + private final int wr; + private final int g; + private final int fft; + private final int mulParam; + private static final int SEED_BYTES = 32; + private final int N_BYTE; + private final int N_BYTE_64; + private final int K_BYTE; + private final int N1N2_BYTE_64; + private final int N1N2_BYTE; + private static final int SALT_SIZE_BYTES = 16; + private final int[] generatorPoly; + private final int N_MU; + private final int pkSize; + private final GF2PolynomialCalculator gf; + private final long rejectionThreshold; + private final int cipherTextBytes; + + HQCEngine(int n, int n1, int n2, int k, int g, int delta, int w, int wr, int fft, int nmu, int pkSize, + int[] generatorPoly) { this.n = n; this.k = k; this.delta = delta; this.w = w; this.wr = wr; - this.we = we; this.n1 = n1; - this.n2 = n2; - this.n1n2 = n1 * n2; this.generatorPoly = generatorPoly; this.g = g; - this.rejectionThreshold = rejectionThreshold; this.fft = fft; - - this.mulParam = (int)Math.ceil(n2 / 128); + this.N_MU = nmu; + this.pkSize = pkSize; + this.mulParam = n2 >> 7; this.N_BYTE = Utils.getByteSizeFromBitSize(n); this.K_BYTE = k; this.N_BYTE_64 = Utils.getByte64SizeFromBitSize(n); - this.K_BYTE_64 = Utils.getByteSizeFromBitSize(k); - this.N1_BYTE_64 = Utils.getByteSizeFromBitSize(n1); this.N1N2_BYTE_64 = Utils.getByte64SizeFromBitSize(n1 * n2); this.N1N2_BYTE = Utils.getByteSizeFromBitSize(n1 * n2); - this.N1_BYTE = Utils.getByteSizeFromBitSize(n1); - - this.RED_MASK = ((1L << ((long)n % 64)) - 1); + long RED_MASK = ((1L << (n & 63)) - 1); + this.gf = new GF2PolynomialCalculator(N_BYTE_64, n, RED_MASK); + this.rejectionThreshold = ((1L << 24) / n) * n; + this.cipherTextBytes = N_BYTE + N1N2_BYTE + 16; + } - this.gfCalculator = new GF2PolynomialCalculator(N_BYTE_64, n, RED_MASK); + int getCipherTextBytes() + { + return cipherTextBytes; } /** @@ -82,49 +70,39 @@ public HQCEngine(int n, int n1, int n2, int k, int g, int delta, int w, int wr, * * @param pk output pk = (publicSeed||s) **/ - public void genKeyPair(byte[] pk, byte[] sk, byte[] seed) + public void genKeyPair(byte[] pk, byte[] sk, SecureRandom secureRandom) { // Randomly generate seeds for secret keys and public keys - byte[] secretKeySeed = new byte[SEED_SIZE]; - byte[] sigma = new byte[K_BYTE]; - - KeccakRandomGenerator randomGenerator = new KeccakRandomGenerator(256); - randomGenerator.randomGeneratorInit(seed, null, seed.length, 0); - randomGenerator.squeeze(secretKeySeed, 40); - randomGenerator.squeeze(sigma, K_BYTE); - - // 1. Randomly generate secret keys x, y - KeccakRandomGenerator secretKeySeedExpander = new KeccakRandomGenerator(256); - secretKeySeedExpander.seedExpanderInit(secretKeySeed, secretKeySeed.length); - + byte[] seedKem = new byte[SEED_BYTES]; // seedKem + byte[] keypairSeed = new byte[SEED_BYTES << 1]; long[] xLongBytes = new long[N_BYTE_64]; long[] yLongBytes = new long[N_BYTE_64]; - - generateRandomFixedWeight(yLongBytes, secretKeySeedExpander, w); - generateRandomFixedWeight(xLongBytes, secretKeySeedExpander, w); - - // 2. Randomly generate h - byte[] publicKeySeed = new byte[SEED_SIZE]; - randomGenerator.squeeze(publicKeySeed, 40); - - KeccakRandomGenerator randomPublic = new KeccakRandomGenerator(256); - randomPublic.seedExpanderInit(publicKeySeed, publicKeySeed.length); - - long[] hLongBytes = new long[N_BYTE_64]; - generatePublicKeyH(hLongBytes, randomPublic); - - // 3. Compute s - long[] s = new long[N_BYTE_64]; - gfCalculator.multLongs(s, yLongBytes, hLongBytes); - GF2PolynomialCalculator.addLongs(s, s, xLongBytes); - byte[] sBytes = new byte[N_BYTE]; - Utils.fromLongArrayToByteArray(sBytes, s); - - byte[] tmpPk = Arrays.concatenate(publicKeySeed, sBytes); - byte[] tmpSk = Arrays.concatenate(secretKeySeed, sigma, tmpPk); - - System.arraycopy(tmpPk, 0, pk, 0, tmpPk.length); - System.arraycopy(tmpSk, 0, sk, 0, tmpSk.length); + long[] h = new long[N_BYTE_64]; // s + + secureRandom.nextBytes(seedKem); + Shake256RandomGenerator ctxKem = new Shake256RandomGenerator(seedKem, (byte)1); + System.arraycopy(seedKem, 0, sk, pkSize + SEED_BYTES + K_BYTE, SEED_BYTES); + + ctxKem.nextBytes(seedKem); + ctxKem.nextBytes(sk, pkSize + SEED_BYTES, K_BYTE); + + hashHI(keypairSeed, 512, seedKem, seedKem.length, (byte)2); + ctxKem.init(keypairSeed, 0, SEED_BYTES, (byte)1); + + vectSampleFixedWeight1(yLongBytes, ctxKem, w); + vectSampleFixedWeight1(xLongBytes, ctxKem, w); + System.arraycopy(keypairSeed, SEED_BYTES, pk, 0, SEED_BYTES); + ctxKem.init(keypairSeed, SEED_BYTES, SEED_BYTES, (byte)1); + vectSetRandom(ctxKem, h); + gf.vectMul(h, yLongBytes, h); // h is s as the output + Longs.xorTo(N_BYTE_64, xLongBytes, 0, h, 0); // h is s + Utils.fromLongArrayToByteArray(pk, SEED_BYTES, pk.length - SEED_BYTES, h); + System.arraycopy(keypairSeed, 0, sk, pkSize, SEED_BYTES); + System.arraycopy(pk, 0, sk, 0, pkSize); + Arrays.clear(keypairSeed); + Arrays.clear(xLongBytes); + Arrays.clear(yLongBytes); + Arrays.clear(h); } /** @@ -132,56 +110,31 @@ public void genKeyPair(byte[] pk, byte[] sk, byte[] seed) * - Input: pk, seed * - Output: c = (u,v,d), K * - * @param u u - * @param v v - * @param K session key - * @param pk public key - * @param seed seed + * @param u u + * @param v v + * @param kTheta session key + * @param pk public key **/ - public void encaps(byte[] u, byte[] v, byte[] K, byte[] pk, byte[] seed, byte[] salt) + public void encaps(byte[] u, byte[] v, byte[] kTheta, byte[] pk, byte[] salt, SecureRandom secureRandom) { // 1. Randomly generate m byte[] m = new byte[K_BYTE]; - - byte[] secretKeySeed = new byte[SEED_SIZE]; - KeccakRandomGenerator randomGenerator = new KeccakRandomGenerator(256); - randomGenerator.randomGeneratorInit(seed, null, seed.length, 0); - randomGenerator.squeeze(secretKeySeed, 40); - - byte[] sigma = new byte[K_BYTE]; - randomGenerator.squeeze(sigma, K_BYTE); - - byte[] publicKeySeed = new byte[SEED_SIZE]; - randomGenerator.squeeze(publicKeySeed, 40); - - // gen m - randomGenerator.squeeze(m, K_BYTE); - - // 2. Generate theta - byte[] theta = new byte[SHA512_BYTES]; - byte[] tmp = new byte[K_BYTE + (SALT_SIZE_BYTES * 2) + SALT_SIZE_BYTES]; - randomGenerator.squeeze(salt, SALT_SIZE_BYTES); - - System.arraycopy(m, 0, tmp, 0, m.length); - System.arraycopy(pk, 0, tmp, K_BYTE, SALT_SIZE_BYTES * 2); - System.arraycopy(salt, 0, tmp, K_BYTE + (SALT_SIZE_BYTES * 2), SALT_SIZE_BYTES); - KeccakRandomGenerator shakeDigest = new KeccakRandomGenerator(256); - shakeDigest.SHAKE256_512_ds(theta, tmp, tmp.length, new byte[]{G_FCT_DOMAIN}); - - // 3. Generate ciphertext c = (u,v) - // Extract public keys - long[] h = new long[N_BYTE_64]; - byte[] s = new byte[N_BYTE]; - extractPublicKeys(h, s, pk); - - long[] vTmp = new long[N1N2_BYTE_64]; - encrypt(u, vTmp, h, s, m, theta); - - Utils.fromLongArrayToByteArray(v, vTmp); - - // 5. Compute session key K - byte[] hashInputK = Arrays.concatenate(m, u, v); - shakeDigest.SHAKE256_512_ds(K, hashInputK, hashInputK.length, new byte[]{K_FCT_DOMAIN}); + byte[] hashEkKem = new byte[SEED_BYTES]; + long[] u64 = new long[N_BYTE_64]; + long[] v64 = new long[N1N2_BYTE_64]; + + secureRandom.nextBytes(m); + secureRandom.nextBytes(salt); + + hashHI(hashEkKem, 256, pk, pk.length, (byte)1); + hashGJ(kTheta, 512, hashEkKem, m, 0, m.length, salt, 0, SALT_SIZE_BYTES, (byte)0); + pkeEncrypt(u64, v64, pk, m, kTheta, SEED_BYTES); + Utils.fromLongArrayToByteArray(u, u64); + Utils.fromLongArrayToByteArray(v, v64); + Arrays.clear(u64); + Arrays.clear(v64); + Arrays.clear(m); + Arrays.clear(hashEkKem); } /** @@ -197,53 +150,48 @@ public void encaps(byte[] u, byte[] v, byte[] K, byte[] pk, byte[] seed, byte[] public int decaps(byte[] ss, byte[] ct, byte[] sk) { //Extract Y and Public Keys from sk - long[] y = new long[N_BYTE_64]; - byte[] pk = new byte[40 + N_BYTE]; - byte[] sigma = new byte[K_BYTE]; - extractKeysFromSecretKeys(y, sigma, pk, sk); + long[] u64 = new long[N_BYTE_64]; + long[] v64 = new long[N_BYTE_64]; + long[] cKemPrimeU64 = new long[N_BYTE_64]; // tmpLong + long[] cKemPrimeV64 = new long[N_BYTE_64]; // y + byte[] hashEkKem = new byte[SEED_BYTES]; + byte[] kThetaPrime = new byte[32 + SEED_BYTES]; + byte[] mPrime = new byte[k]; + byte[] kBar = new byte[32]; + byte[] tmp = new byte[n1]; + + Shake256RandomGenerator generator = new Shake256RandomGenerator(sk, pkSize, SEED_BYTES, (byte)1); + vectSampleFixedWeight1(cKemPrimeV64, generator, w); // cKemPrimeV64 is y // Extract u, v, d from ciphertext - byte[] u = new byte[N_BYTE]; - byte[] v = new byte[N1N2_BYTE]; - byte[] salt = new byte[SALT_SIZE_BYTES]; - extractCiphertexts(u, v, salt, ct); - - // 1. Decrypt -> m' - byte[] mPrimeBytes = new byte[k]; - int result = decrypt(mPrimeBytes, mPrimeBytes, sigma, u, v, y); - - // 2. Compute theta' - byte[] theta = new byte[SHA512_BYTES]; - byte[] tmp = new byte[K_BYTE + (SALT_SIZE_BYTES * 2) + SALT_SIZE_BYTES]; - System.arraycopy(mPrimeBytes, 0, tmp, 0, mPrimeBytes.length); - System.arraycopy(pk, 0, tmp, K_BYTE, SALT_SIZE_BYTES * 2); - System.arraycopy(salt, 0, tmp, K_BYTE + (SALT_SIZE_BYTES * 2), SALT_SIZE_BYTES); - - KeccakRandomGenerator shakeDigest = new KeccakRandomGenerator(256); - shakeDigest.SHAKE256_512_ds(theta, tmp, tmp.length, new byte[]{G_FCT_DOMAIN}); - - // 3. Compute c' = Enc(pk, m', theta') - // Extract public keys - long[] h = new long[N_BYTE_64]; - byte[] s = new byte[N_BYTE]; - extractPublicKeys(h, s, pk); - - byte[] u2Bytes = new byte[N_BYTE]; - byte[] v2Bytes = new byte[N1N2_BYTE]; - long[] vTmp = new long[N1N2_BYTE_64]; - encrypt(u2Bytes, vTmp, h, s, mPrimeBytes, theta); - Utils.fromLongArrayToByteArray(v2Bytes, vTmp); - - // 5. Compute session key KPrime - byte[] hashInputK = new byte[K_BYTE + N_BYTE + N1N2_BYTE]; - - // Compare u, v, d - if (!Arrays.constantTimeAreEqual(u, u2Bytes)) + Utils.fromByteArrayToLongArray(u64, ct, 0, N_BYTE); + Utils.fromByteArrayToLongArray(v64, ct, N_BYTE, N1N2_BYTE); + + // cKemPrimeU64 is tmpLong + gf.vectMul(cKemPrimeU64, cKemPrimeV64, u64); + vectTruncate(cKemPrimeU64); + Longs.xorTo(N_BYTE_64, v64, 0, cKemPrimeU64, 0); + + ReedMuller.decode(tmp, cKemPrimeU64, n1, mulParam); + ReedSolomon.decode(mPrime, tmp, n1, fft, delta, k, g); + + int result = 0; + + // Compute shared key K_prime and ciphertext cKemPrime + hashHI(hashEkKem, 256, sk, pkSize, (byte)1); + hashGJ(kThetaPrime, 512, hashEkKem, mPrime, 0, mPrime.length, ct, + N_BYTE + N1N2_BYTE, SALT_SIZE_BYTES, (byte)0); + System.arraycopy(kThetaPrime, 0, ss, 0, 32); + Arrays.fill(cKemPrimeV64, 0L); + pkeEncrypt(cKemPrimeU64, cKemPrimeV64, sk, mPrime, kThetaPrime, 32); + hashGJ(kBar, 256, hashEkKem, sk, pkSize + SEED_BYTES, K_BYTE, ct, 0, ct.length, (byte)3); + + if (!Arrays.constantTimeAreEqual(N_BYTE_64, u64, 0, cKemPrimeU64, 0)) { result = 1; } - if (!Arrays.constantTimeAreEqual(v, v2Bytes)) + if (!Arrays.constantTimeAreEqual(N_BYTE_64, v64, 0, cKemPrimeV64, 0)) { result = 1; } @@ -252,191 +200,182 @@ public int decaps(byte[] ss, byte[] ct, byte[] sk) for (int i = 0; i < K_BYTE; i++) { - hashInputK[i] = (byte)(((mPrimeBytes[i] & result) ^ (sigma[i] & ~result)) & 0xff); + ss[i] = (byte)(((ss[i] & result) ^ (kBar[i] & ~result)) & 0xff); } - System.arraycopy(u, 0, hashInputK, K_BYTE, N_BYTE); - System.arraycopy(v, 0, hashInputK, K_BYTE + N_BYTE, N1N2_BYTE); - - shakeDigest.SHAKE256_512_ds(ss, hashInputK, hashInputK.length, new byte[]{K_FCT_DOMAIN}); + Arrays.clear(u64); + Arrays.clear(v64); + Arrays.clear(cKemPrimeU64); + Arrays.clear(cKemPrimeV64); + Arrays.clear(hashEkKem); + Arrays.clear(kThetaPrime); + Arrays.clear(mPrime); + Arrays.clear(kBar); + Arrays.clear(tmp); return -result; } - int getSessionKeySize() - { - return SHA512_BYTES; - } - - /** - * HQC Encryption - * - Input: (h,s, m) - * - Output: (u,v) = c - * - * @param h public key - * @param s public key - * @param m message - * @param u ciphertext - * @param v ciphertext - **/ - private void encrypt(byte[] u, long[] v, long[] h, byte[] s, byte[] m, byte[] theta) + private void pkeEncrypt(long[] u, long[] v, byte[] ekPke, byte[] m, byte[] theta, int thetaOff) { - // Randomly generate e, r1, r2 - KeccakRandomGenerator randomGenerator = new KeccakRandomGenerator(256); - randomGenerator.seedExpanderInit(theta, SEED_SIZE); - long[] e = new long[N_BYTE_64]; - long[] r1 = new long[N_BYTE_64]; - long[] r2 = new long[N_BYTE_64]; - generateRandomFixedWeight(r2, randomGenerator, wr); - generateRandomFixedWeight(e, randomGenerator, we); - generateRandomFixedWeight(r1, randomGenerator, wr); - - // Calculate u - long[] uLong = new long[N_BYTE_64]; - gfCalculator.multLongs(uLong, r2, h); - GF2PolynomialCalculator.addLongs(uLong, uLong, r1); - Utils.fromLongArrayToByteArray(u, uLong); - - // Calculate v - // encode m + long[] e = new long[N_BYTE_64]; // r2 + long[] tmp = new long[N_BYTE_64]; // s, h1, h byte[] res = new byte[n1]; - long[] vLong = new long[N1N2_BYTE_64]; - long[] tmpVLong = new long[N_BYTE_64]; - ReedSolomon.encode(res, m, K_BYTE * 8, n1, k, g, generatorPoly); - ReedMuller.encode(vLong, res, n1, mulParam); - System.arraycopy(vLong, 0, tmpVLong, 0, vLong.length); - - //Compute v - long[] sLong = new long[N_BYTE_64]; - Utils.fromByteArrayToLongArray(sLong, s); - - long[] tmpLong = new long[N_BYTE_64]; - gfCalculator.multLongs(tmpLong, r2, sLong); - GF2PolynomialCalculator.addLongs(tmpLong, tmpLong, tmpVLong); - GF2PolynomialCalculator.addLongs(tmpLong, tmpLong, e); - - Utils.resizeArray(v, n1n2, tmpLong, n, N1N2_BYTE_64, N1N2_BYTE_64); + + ReedSolomon.encode(res, m, n1, k, g, generatorPoly); + ReedMuller.encode(v, res, n1, mulParam); + + Shake256RandomGenerator randomGenerator = new Shake256RandomGenerator(ekPke, 0, SEED_BYTES, (byte)1); + vectSetRandom(randomGenerator, tmp); + + randomGenerator.init(theta, thetaOff, SEED_BYTES, (byte)1); + vectSampleFixedWeights2(randomGenerator, e, wr); // e is r2 + gf.vectMul(u, e, tmp); // e is r2 + Utils.fromByteArrayToLongArray(tmp, ekPke, SEED_BYTES, pkSize - SEED_BYTES); + gf.vectMul(tmp, e, tmp); + vectSampleFixedWeights2(randomGenerator, e, wr); + Longs.xorTo(N_BYTE_64, e, 0, tmp, 0); + vectTruncate(tmp); + Longs.xorTo(N1N2_BYTE_64, tmp, 0, v, 0); + + vectSampleFixedWeights2(randomGenerator, tmp, wr);// tmp is r1 + Longs.xorTo(N_BYTE_64, tmp, 0, u, 0); + Arrays.clear(e); + Arrays.clear(tmp); + Arrays.clear(res); } - private int decrypt(byte[] output, byte[] m, byte[] sigma, byte[] u, byte[] v, long[] y) + private int barrettReduce(int x) { - long[] uLongs = new long[N_BYTE_64]; - Utils.fromByteArrayToLongArray(uLongs, u); - - long[] vLongs = new long[N1N2_BYTE_64]; - Utils.fromByteArrayToLongArray(vLongs, v); - - long[] tmpV = new long[N_BYTE_64]; - System.arraycopy(vLongs, 0, tmpV, 0, vLongs.length); - - long[] tmpLong = new long[N_BYTE_64]; - gfCalculator.multLongs(tmpLong, y, uLongs); - GF2PolynomialCalculator.addLongs(tmpLong, tmpLong, tmpV); - - // Decode res - byte[] tmp = new byte[n1]; - ReedMuller.decode(tmp, tmpLong, n1, mulParam); - ReedSolomon.decode(m, tmp, n1, fft, delta, k, g); - - System.arraycopy(m, 0, output, 0, output.length); - return 0; + long q = ((long)x * N_MU) >>> 32; + int r = x - (int)(q * n); + r -= (-(((r - n) >>> 31) ^ 1)) & n; + return r; } - private void generateRandomFixedWeight(long[] output, KeccakRandomGenerator random, int weight) + private void generateRandomSupport(int[] support, int weight, Shake256RandomGenerator random) { - int[] rand_u32 = new int[this.wr]; - byte[] rand_bytes = new byte[this.wr * 4]; - int[] support = new int[this.wr]; - int[] index_tab = new int[this.wr]; - long[] bit_tab = new long[this.wr]; - - random.expandSeed(rand_bytes, 4 * weight); - Pack.littleEndianToInt(rand_bytes, 0, rand_u32, 0, rand_u32.length); + int randomBytesSize = 3 * weight; + byte[] randBytes = new byte[randomBytesSize]; + int j = randomBytesSize; - for (int i = 0; i < weight; i++) + int count = 0; + while (count < weight) { - support[i] = (int) (i + ((rand_u32[i]&0xFFFFFFFFL) % (n - i))); - } + if (j == randomBytesSize) + { + random.xofGetBytes(randBytes, randomBytesSize); + j = 0; + } + int candidate = ((randBytes[j++] & 0xFF) << 16) | ((randBytes[j++] & 0xFF) << 8) | randBytes[j++] & 0xFF; + if (candidate >= rejectionThreshold) + { + continue; + } + candidate = barrettReduce(candidate); + boolean duplicate = false; - for (int i = (weight - 1); i >= 0; i--) - { - int found = 0; - for (int j = i + 1; j < weight; j++) + for (int k = 0; k < count; k++) { - if (support[j] == support[i]) + if (support[k] == candidate) { - found |= 1; + duplicate = true; + break; } } - int mask = -found; - support[i] = (mask & i) ^ (~mask & support[i]); + if (!duplicate) + { + support[count++] = candidate; + } } + } + private void writeSupportToVector(long[] v, int[] support, int weight) + { + int[] indexTab = new int[wr]; + long[] bitTab = new long[wr]; for (int i = 0; i < weight; i++) { - index_tab[i] = support[i] >>> 6; - int pos = support[i] & 0x3f; - bit_tab[i] = (1L) << pos; + indexTab[i] = support[i] >>> 6; + bitTab[i] = 1L << (support[i] & 0x3F); } - long val = 0; - for (int i = 0; i < N_BYTE_64; i++) + for (int i = 0; i < v.length; i++) { - val = 0; + long val = 0; for (int j = 0; j < weight; j++) { - int tmp = i - index_tab[j]; - int val1 = 1 ^ ((tmp | -tmp) >>> 31); - long mask = -val1; - val |= (bit_tab[j] & mask); + int tmp = i - indexTab[j]; + val |= (bitTab[j] & -(1 ^ ((tmp | -tmp) >>> 31))); } - output[i] |= val; + v[i] = val; } } - void generatePublicKeyH(long[] out, KeccakRandomGenerator random) + public void vectSampleFixedWeight1(long[] output, Shake256RandomGenerator random, int weight) { - byte[] randBytes = new byte[N_BYTE]; - random.expandSeed(randBytes, N_BYTE); - long[] tmp = new long[N_BYTE_64]; - Utils.fromByteArrayToLongArray(tmp, randBytes); - tmp[N_BYTE_64 - 1] &= Utils.bitMask(n, 64); - System.arraycopy(tmp, 0, out, 0, out.length); + int[] support = new int[wr]; + generateRandomSupport(support, weight, random); + writeSupportToVector(output, support, weight); } - private void extractPublicKeys(long[] h, byte[] s, byte[] pk) + private static void hashHI(byte[] output, int bitLength, byte[] in, int inLen, byte domain) { - byte[] publicKeySeed = new byte[SEED_SIZE]; - System.arraycopy(pk, 0, publicKeySeed, 0, publicKeySeed.length); - - KeccakRandomGenerator randomPublic = new KeccakRandomGenerator(256); - randomPublic.seedExpanderInit(publicKeySeed, publicKeySeed.length); - - long[] hLongBytes = new long[N_BYTE_64]; - generatePublicKeyH(hLongBytes, randomPublic); + SHA3Digest digest = new SHA3Digest(bitLength); + digest.update(in, 0, inLen); + digest.update(domain); + digest.doFinal(output, 0); + } - System.arraycopy(hLongBytes, 0, h, 0, h.length); - System.arraycopy(pk, 40, s, 0, s.length); + private void hashGJ(byte[] output, int bitLength, byte[] hashEkKem, byte[] mOrSigma, int mOrSigmaOff, int mOrSigmaLen, + byte[] saltOrCt, int saltOrCtOff, int saltOrCtOffLen, byte domain) + { + SHA3Digest digest = new SHA3Digest(bitLength); + digest.update(hashEkKem, 0, hashEkKem.length); + digest.update(mOrSigma, mOrSigmaOff, mOrSigmaLen); + digest.update(saltOrCt, saltOrCtOff, saltOrCtOffLen); + digest.update(domain); + digest.doFinal(output, 0); } - private void extractKeysFromSecretKeys(long[] y, byte[] sigma, byte[] pk, byte[] sk) + private void vectSetRandom(Shake256RandomGenerator generator, long[] v) { - byte[] secretKeySeed = new byte[SEED_SIZE]; - System.arraycopy(sk, 0, secretKeySeed, 0, secretKeySeed.length); - System.arraycopy(sk, SEED_SIZE, sigma, 0, K_BYTE); + byte[] tmp = new byte[v.length << 3]; + generator.xofGetBytes(tmp, N_BYTE); + Pack.littleEndianToLong(tmp, 0, v); + v[N_BYTE_64 - 1] &= Utils.bitMask(n, 64); + } - // Randomly generate secret keys x, y - KeccakRandomGenerator secretKeySeedExpander = new KeccakRandomGenerator(256); - secretKeySeedExpander.seedExpanderInit(secretKeySeed, secretKeySeed.length); + private void vectSampleFixedWeights2(Shake256RandomGenerator generator, long[] v, int weight) + { + int[] support = new int[wr]; + byte[] rand = new byte[wr << 2]; + generator.xofGetBytes(rand, rand.length); + Pack.littleEndianToInt(rand, 0, support); + for (int i = 0; i < weight; ++i) + { + support[i] = i + (int)(((support[i] & 0xFFFFFFFFL) * (n - i)) >> 32); + } - generateRandomFixedWeight(y, secretKeySeedExpander, w); + for (int i = weight - 1; i-- > 0; ) + { + int found = 0; + for (int j = i + 1; j < weight; ++j) + { + found |= compareU32(support[j], support[i]); + } + found = -found; + support[i] = (found & i) ^ (~found & support[i]); + } + writeSupportToVector(v, support, weight); + } - System.arraycopy(sk, SEED_SIZE + K_BYTE, pk, 0, pk.length); + private static int compareU32(int v1, int v2) + { + return 1 ^ (((v1 - v2) | (v2 - v1)) >>> 31); } - private void extractCiphertexts(byte[] u, byte[] v, byte[] salt, byte[] ct) + private void vectTruncate(long[] v) { - System.arraycopy(ct, 0, u, 0, u.length); - System.arraycopy(ct, u.length, v, 0, v.length); - System.arraycopy(ct, u.length + v.length, salt, 0, salt.length); + Arrays.fill(v, N1N2_BYTE_64, (n + 63) >> 6, 0L); } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMExtractor.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMExtractor.java index b565ea41c6..d59b0585cc 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMExtractor.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMExtractor.java @@ -1,40 +1,37 @@ package org.bouncycastle.pqc.crypto.hqc; - import org.bouncycastle.crypto.EncapsulatedSecretExtractor; import org.bouncycastle.util.Arrays; public class HQCKEMExtractor implements EncapsulatedSecretExtractor { - private HQCEngine engine; - - private HQCKeyParameters key; + private final HQCPrivateKeyParameters privateKey; + private final HQCEngine engine; - public HQCKEMExtractor(HQCPrivateKeyParameters privParams) + public HQCKEMExtractor(HQCPrivateKeyParameters privateKey) { - this.key = privParams; - initCipher(key.getParameters()); - } + if (privateKey == null) + { + throw new NullPointerException("'privateKey' cannot be null"); + } - private void initCipher(HQCParameters param) - { - engine = param.getEngine(); + this.privateKey = privateKey; + this.engine = privateKey.getParameters().getEngine(); } public byte[] extractSecret(byte[] encapsulation) { - byte[] session_key = new byte[engine.getSessionKeySize()]; - HQCPrivateKeyParameters secretKey = (HQCPrivateKeyParameters)key; - byte[] sk = secretKey.getPrivateKey(); + byte[] session_key = new byte[64]; + byte[] sk = privateKey.getPrivateKey(); engine.decaps(session_key, encapsulation, sk); - return Arrays.copyOfRange(session_key, 0, key.getParameters().getK()); + return Arrays.copyOfRange(session_key, 0, 32); } public int getEncapsulationLength() - { // Hash + salt - return key.getParameters().getN_BYTES() + key.getParameters().getN1N2_BYTES() + 16; + { + return engine.getCipherTextBytes(); } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMGenerator.java index 85cc4750d0..e374930d16 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMGenerator.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKEMGenerator.java @@ -2,6 +2,7 @@ import java.security.SecureRandom; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.EncapsulatedSecretGenerator; import org.bouncycastle.crypto.SecretWithEncapsulation; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; @@ -11,11 +12,11 @@ public class HQCKEMGenerator implements EncapsulatedSecretGenerator { - private final SecureRandom sr; + private final SecureRandom random; public HQCKEMGenerator(SecureRandom random) { - this.sr = random; + this.random = CryptoServicesRegistrar.getSecureRandom(random); } public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recipientKey) @@ -28,14 +29,11 @@ public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recip byte[] v = new byte[key.getParameters().getN1N2_BYTES()]; byte[] salt = new byte[key.getParameters().getSALT_SIZE_BYTES()]; byte[] pk = key.getPublicKey(); - byte[] seed = new byte[48]; - sr.nextBytes(seed); - - engine.encaps(u, v, K, pk, seed, salt); + engine.encaps(u, v, K, pk, salt, random); byte[] cipherText = Arrays.concatenate(u, v, salt); - return new SecretWithEncapsulationImpl(Arrays.copyOfRange(K, 0, key.getParameters().getK()), cipherText); + return new SecretWithEncapsulationImpl(Arrays.copyOfRange(K, 0, 32), cipherText); } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKeyGenerationParameters.java index ebd37766d5..4ce1662820 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKeyGenerationParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKeyGenerationParameters.java @@ -7,7 +7,7 @@ public class HQCKeyGenerationParameters extends KeyGenerationParameters { - private HQCParameters params; + private final HQCParameters params; public HQCKeyGenerationParameters( SecureRandom random, diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKeyPairGenerator.java index 0a85e3f875..287cf0c70a 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKeyPairGenerator.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKeyPairGenerator.java @@ -9,18 +9,7 @@ public class HQCKeyPairGenerator implements AsymmetricCipherKeyPairGenerator { - private int n; - private int k; - - private int delta; - - private int w; - - private int wr; - - private int we; - private int N_BYTE; private HQCKeyGenerationParameters hqcKeyGenerationParameters; private SecureRandom random; @@ -30,24 +19,15 @@ public void init(KeyGenerationParameters params) { this.hqcKeyGenerationParameters = (HQCKeyGenerationParameters)params; this.random = params.getRandom(); - - // get parameters - this.n = this.hqcKeyGenerationParameters.getParameters().getN(); - this.k = this.hqcKeyGenerationParameters.getParameters().getK(); - this.delta = this.hqcKeyGenerationParameters.getParameters().getDelta(); - this.w = this.hqcKeyGenerationParameters.getParameters().getW(); - this.wr = this.hqcKeyGenerationParameters.getParameters().getWr(); - this.we = this.hqcKeyGenerationParameters.getParameters().getWe(); - this.N_BYTE = (n + 7) / 8; } - private AsymmetricCipherKeyPair genKeyPair(byte[] seed) + private AsymmetricCipherKeyPair genKeyPair() { HQCEngine engine = hqcKeyGenerationParameters.getParameters().getEngine(); - byte[] pk = new byte[40 + N_BYTE]; - byte[] sk = new byte[40 + 40 + k + N_BYTE]; + byte[] pk = new byte[hqcKeyGenerationParameters.getParameters().getPublicKeyBytes()]; + byte[] sk = new byte[hqcKeyGenerationParameters.getParameters().getSecretKeyBytes()]; - engine.genKeyPair(pk, sk, seed); + engine.genKeyPair(pk, sk, random); // form keys HQCPublicKeyParameters publicKey = new HQCPublicKeyParameters(hqcKeyGenerationParameters.getParameters(), pk); @@ -59,15 +39,6 @@ private AsymmetricCipherKeyPair genKeyPair(byte[] seed) @Override public AsymmetricCipherKeyPair generateKeyPair() { - byte[] seed = new byte[48]; - - random.nextBytes(seed); - - return genKeyPair(seed); - } - - public AsymmetricCipherKeyPair generateKeyPairWithSeed(byte[] seed) - { - return genKeyPair(seed); + return genKeyPair(); } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKeyParameters.java index ad524ff4db..bdfaa251de 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCKeyParameters.java @@ -5,7 +5,7 @@ public class HQCKeyParameters extends AsymmetricKeyParameter { - private HQCParameters params; + private final HQCParameters params; public HQCKeyParameters( boolean isPrivate, diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCParameters.java index 1090848fa8..0192b18361 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCParameters.java @@ -6,96 +6,50 @@ public class HQCParameters implements KEMParameters { // 128 bits security - public static final HQCParameters hqc128 = new HQCParameters("hqc-128", 17669, 46, 384, 16, 31, 15, 66, 75, 75, 16767881, 4, new int[]{89, 69, 153, 116, 176, 117, 111, 75, 73, 233, 242, 233, 65, 210, 21, 139, 103, 173, 67, 118, 105, 210, 174, 110, 74, 69, 228, 82, 255, 181, 1}); + public static final HQCParameters hqc128 = new HQCParameters("hqc-128", 17669, 46, 384, 16, + 31, 15, 66, 75, 4, 243079, 2241, 2321, + new int[]{89, 69, 153, 116, 176, 117, 111, 75, 73, 233, 242, 233, 65, 210, 21, 139, 103, 173, 67, 118, 105, 210, 174, 110, 74, 69, 228, 82, 255, 181, 1}); // 192 bits security - public static final HQCParameters hqc192 = new HQCParameters("hqc-192", 35851, 56, 640, 24, 33, 16, 100, 114, 114, 16742417, 5, new int[]{45, 216, 239, 24, 253, 104, 27, 40, 107, 50, 163, 210, 227, 134, 224, 158, 119, 13, 158, 1, 238, 164, 82, 43, 15, 232, 246, 142, 50, 189, 29, 232, 1}); + public static final HQCParameters hqc192 = new HQCParameters("hqc-192", 35851, 56, 640, 24, + 33, 16, 100, 114, 5, 119800, 4514, 4602, + new int[]{45, 216, 239, 24, 253, 104, 27, 40, 107, 50, 163, 210, 227, 134, 224, 158, 119, 13, 158, 1, 238, 164, 82, 43, 15, 232, 246, 142, 50, 189, 29, 232, 1}); // 256 bits security - public static final HQCParameters hqc256 = new HQCParameters("hqc-256", 57637, 90, 640, 32, 59, 29, 131, 149, 149, 16772367, 5, new int[]{49, 167, 49, 39, 200, 121, 124, 91, 240, 63, 148, 71, 150, 123, 87, 101, 32, 215, 159, 71, 201, 115, 97, 210, 186, 183, 141, 217, 123, 12, 31, 243, 180, 219, 152, 239, 99, 141, 4, 246, 191, 144, 8, 232, 47, 27, 141, 178, 130, 64, 124, 47, 39, 188, 216, 48, 199, 187, 1}); + public static final HQCParameters hqc256 = new HQCParameters("hqc-256", 57637, 90, 640, 32, + 59, 29, 131, 149, 5, 74517, 7237, 7333, + new int[]{49, 167, 49, 39, 200, 121, 124, 91, 240, 63, 148, 71, 150, 123, 87, 101, 32, 215, 159, 71, 201, 115, 97, 210, 186, 183, 141, 217, 123, 12, 31, 243, 180, 219, 152, 239, 99, 141, 4, 246, 191, 144, 8, 232, 47, 27, 141, 178, 130, 64, 124, 47, 39, 188, 216, 48, 199, 187, 1}); private final String name; - private int n; - private int n1; - private int n2; - private int k; - private int g; - private int delta; - private int w; - private int wr; - private int we; - private int utilRejectionThreshold; - private int fft; - - private int[] generatorPoly; + private final int n; + private final int n1; + private final int n2; + + private final int publicKeyBytes; + private final int secretKeyBytes; final static int PARAM_M = 8; final static int GF_MUL_ORDER = 255; - private HQCEngine hqcEngine; + private final HQCEngine engine; - private HQCParameters(String name, int n, int n1, int n2, int k, int g, int delta, int w, int wr, int we, int utilRejectionThreshold, int fft, int[] generatorPoly) + private HQCParameters(String name, int n, int n1, int n2, int k, int g, int delta, int w, int wr, int fft, int nMu, + int pkSize, int skSize, int[] generatorPoly) { this.name = name; this.n = n; this.n1 = n1; this.n2 = n2; - this.k = k; - this.delta = delta; - this.w = w; - this.wr = wr; - this.we = we; - this.generatorPoly = generatorPoly; - this.g = g; - this.utilRejectionThreshold = utilRejectionThreshold; - this.fft = fft; - hqcEngine = new HQCEngine(n, n1, n2, k, g, delta, w, wr, we, utilRejectionThreshold, fft, generatorPoly); - } - - int getN() - { - return n; - } - - int getK() - { - return k; - } - - int getDelta() - { - return delta; - } - - int getW() - { - return w; - } - - int getWr() - { - return wr; - } - - int getWe() - { - return we; - } - - int getN1() - { - return n1; - } - - int getN2() - { - return n2; + this.publicKeyBytes = pkSize; + this.secretKeyBytes = skSize; + this.engine = new HQCEngine(n, n1, n2, k, g, delta, w, wr, fft, nMu, pkSize, generatorPoly); } int getSHA512_BYTES() { return 512 / 8; } + int getSALT_SIZE_BYTES() { return 16; @@ -113,16 +67,31 @@ int getN1N2_BYTES() HQCEngine getEngine() { - return hqcEngine; + return engine; + } + + public int getEncapsulationLength() + { + return engine.getCipherTextBytes(); } public int getSessionKeySize() { - return k * 8; + return 32 * 8; } public String getName() { return name; } + + public int getPublicKeyBytes() + { + return publicKeyBytes; + } + + public int getSecretKeyBytes() + { + return secretKeyBytes; + } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCPrivateKeyParameters.java index cb2286b6b6..cc187c746c 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCPrivateKeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCPrivateKeyParameters.java @@ -5,7 +5,7 @@ public class HQCPrivateKeyParameters extends HQCKeyParameters { - private byte[] sk; + private final byte[] sk; public HQCPrivateKeyParameters(HQCParameters params, byte[] sk) { diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCPublicKeyParameters.java index 0baba48d1c..c478bebac8 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCPublicKeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/HQCPublicKeyParameters.java @@ -5,7 +5,7 @@ public class HQCPublicKeyParameters extends HQCKeyParameters { - private byte[] pk; + private final byte[] pk; public HQCPublicKeyParameters(HQCParameters params, byte[] pk) { diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/KeccakRandomGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/KeccakRandomGenerator.java deleted file mode 100644 index 9f34c9c62b..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/KeccakRandomGenerator.java +++ /dev/null @@ -1,325 +0,0 @@ -package org.bouncycastle.pqc.crypto.hqc; - -import org.bouncycastle.util.Arrays; - -/** - * implementation of Incremental version for Keccak - */ -class KeccakRandomGenerator -{ - private static long[] KeccakRoundConstants = new long[]{0x0000000000000001L, 0x0000000000008082L, - 0x800000000000808aL, 0x8000000080008000L, 0x000000000000808bL, 0x0000000080000001L, 0x8000000080008081L, - 0x8000000000008009L, 0x000000000000008aL, 0x0000000000000088L, 0x0000000080008009L, 0x000000008000000aL, - 0x000000008000808bL, 0x800000000000008bL, 0x8000000000008089L, 0x8000000000008003L, 0x8000000000008002L, - 0x8000000000000080L, 0x000000000000800aL, 0x800000008000000aL, 0x8000000080008081L, 0x8000000000008080L, - 0x0000000080000001L, 0x8000000080008008L}; - - protected long[] state = new long[26]; - protected byte[] dataQueue = new byte[192]; - protected int rate; - protected int bitsInQueue; - protected int fixedOutputLength; - - public KeccakRandomGenerator() - { - this(288); - } - - public KeccakRandomGenerator(int bitLength) - { - init(bitLength); - } - - private void init(int bitLength) - { - switch (bitLength) - { - case 128: - case 224: - case 256: - case 288: - case 384: - case 512: - initSponge(1600 - (bitLength << 1)); - break; - default: - throw new IllegalArgumentException("bitLength must be one of 128, 224, 256, 288, 384, or 512."); - } - } - - private void initSponge(int rate) - { - if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0)) - { - throw new IllegalStateException("invalid rate value"); - } - - this.rate = rate; - Arrays.fill(state, 0L); - Arrays.fill(this.dataQueue, (byte)0); - this.bitsInQueue = 0; - this.fixedOutputLength = (1600 - rate) / 2; - } - - // TODO Somehow just use the one in KeccakDigest - private static void keccakPermutation(long[] A) - { - long a00 = A[0], a01 = A[1], a02 = A[2], a03 = A[3], a04 = A[4]; - long a05 = A[5], a06 = A[6], a07 = A[7], a08 = A[8], a09 = A[9]; - long a10 = A[10], a11 = A[11], a12 = A[12], a13 = A[13], a14 = A[14]; - long a15 = A[15], a16 = A[16], a17 = A[17], a18 = A[18], a19 = A[19]; - long a20 = A[20], a21 = A[21], a22 = A[22], a23 = A[23], a24 = A[24]; - - for (int i = 0; i < 24; i++) - { - // theta - long c0 = a00 ^ a05 ^ a10 ^ a15 ^ a20; - long c1 = a01 ^ a06 ^ a11 ^ a16 ^ a21; - long c2 = a02 ^ a07 ^ a12 ^ a17 ^ a22; - long c3 = a03 ^ a08 ^ a13 ^ a18 ^ a23; - long c4 = a04 ^ a09 ^ a14 ^ a19 ^ a24; - - long d1 = (c1 << 1 | c1 >>> -1) ^ c4; - long d2 = (c2 << 1 | c2 >>> -1) ^ c0; - long d3 = (c3 << 1 | c3 >>> -1) ^ c1; - long d4 = (c4 << 1 | c4 >>> -1) ^ c2; - long d0 = (c0 << 1 | c0 >>> -1) ^ c3; - - a00 ^= d1; - a05 ^= d1; - a10 ^= d1; - a15 ^= d1; - a20 ^= d1; - a01 ^= d2; - a06 ^= d2; - a11 ^= d2; - a16 ^= d2; - a21 ^= d2; - a02 ^= d3; - a07 ^= d3; - a12 ^= d3; - a17 ^= d3; - a22 ^= d3; - a03 ^= d4; - a08 ^= d4; - a13 ^= d4; - a18 ^= d4; - a23 ^= d4; - a04 ^= d0; - a09 ^= d0; - a14 ^= d0; - a19 ^= d0; - a24 ^= d0; - - // rho/pi - c1 = a01 << 1 | a01 >>> 63; - a01 = a06 << 44 | a06 >>> 20; - a06 = a09 << 20 | a09 >>> 44; - a09 = a22 << 61 | a22 >>> 3; - a22 = a14 << 39 | a14 >>> 25; - a14 = a20 << 18 | a20 >>> 46; - a20 = a02 << 62 | a02 >>> 2; - a02 = a12 << 43 | a12 >>> 21; - a12 = a13 << 25 | a13 >>> 39; - a13 = a19 << 8 | a19 >>> 56; - a19 = a23 << 56 | a23 >>> 8; - a23 = a15 << 41 | a15 >>> 23; - a15 = a04 << 27 | a04 >>> 37; - a04 = a24 << 14 | a24 >>> 50; - a24 = a21 << 2 | a21 >>> 62; - a21 = a08 << 55 | a08 >>> 9; - a08 = a16 << 45 | a16 >>> 19; - a16 = a05 << 36 | a05 >>> 28; - a05 = a03 << 28 | a03 >>> 36; - a03 = a18 << 21 | a18 >>> 43; - a18 = a17 << 15 | a17 >>> 49; - a17 = a11 << 10 | a11 >>> 54; - a11 = a07 << 6 | a07 >>> 58; - a07 = a10 << 3 | a10 >>> 61; - a10 = c1; - - // chi - c0 = a00 ^ (~a01 & a02); - c1 = a01 ^ (~a02 & a03); - a02 ^= ~a03 & a04; - a03 ^= ~a04 & a00; - a04 ^= ~a00 & a01; - a00 = c0; - a01 = c1; - - c0 = a05 ^ (~a06 & a07); - c1 = a06 ^ (~a07 & a08); - a07 ^= ~a08 & a09; - a08 ^= ~a09 & a05; - a09 ^= ~a05 & a06; - a05 = c0; - a06 = c1; - - c0 = a10 ^ (~a11 & a12); - c1 = a11 ^ (~a12 & a13); - a12 ^= ~a13 & a14; - a13 ^= ~a14 & a10; - a14 ^= ~a10 & a11; - a10 = c0; - a11 = c1; - - c0 = a15 ^ (~a16 & a17); - c1 = a16 ^ (~a17 & a18); - a17 ^= ~a18 & a19; - a18 ^= ~a19 & a15; - a19 ^= ~a15 & a16; - a15 = c0; - a16 = c1; - - c0 = a20 ^ (~a21 & a22); - c1 = a21 ^ (~a22 & a23); - a22 ^= ~a23 & a24; - a23 ^= ~a24 & a20; - a24 ^= ~a20 & a21; - a20 = c0; - a21 = c1; - - // iota - a00 ^= KeccakRoundConstants[i]; - } - - A[0] = a00; - A[1] = a01; - A[2] = a02; - A[3] = a03; - A[4] = a04; - A[5] = a05; - A[6] = a06; - A[7] = a07; - A[8] = a08; - A[9] = a09; - A[10] = a10; - A[11] = a11; - A[12] = a12; - A[13] = a13; - A[14] = a14; - A[15] = a15; - A[16] = a16; - A[17] = a17; - A[18] = a18; - A[19] = a19; - A[20] = a20; - A[21] = a21; - A[22] = a22; - A[23] = a23; - A[24] = a24; - } - - private void keccakIncAbsorb(byte[] input, int inputLen) - { - int count = 0; - int rateBytes = rate >> 3; - while (inputLen + state[25] >= rateBytes) - { - for (int i = 0; i < rateBytes - state[25]; i++) - { - int tmp = (int)(state[25] + i) >> 3; - state[tmp] ^= toUnsignedLong(input[i + count] & 0xff) << (8 * ((state[25] + i) & 0x07)); - } - inputLen -= rateBytes - state[25]; - count += rateBytes - state[25]; - state[25] = 0; - keccakPermutation(state); - } - - for (int i = 0; i < inputLen; i++) - { - int tmp = (int)(state[25] + i) >> 3; - state[tmp] ^= toUnsignedLong(input[i + count] & 0xff) << (8 * ((state[25] + i) & 0x07)); - } - - state[25] += inputLen; - } - - private void keccakIncFinalize(int p) - { - int rateBytes = rate >> 3; - - state[(int)state[25] >> 3] ^= toUnsignedLong(p) << (8 * ((state[25]) & 0x07)); - state[(rateBytes - 1) >> 3] ^= toUnsignedLong(128) << (8 * ((rateBytes - 1) & 0x07)); - - - state[25] = 0; - } - - private void keccakIncSqueeze(byte[] output, int outLen) - { - int rateBytes = rate >> 3; - int i; - for (i = 0; i < outLen && i < state[25]; i++) - { - output[i] = (byte)(state[(int)((rateBytes - state[25] + i) >> 3)] >> (8 * ((rateBytes - state[25] + i) & 0x07))); - } - - int count = i; - outLen -= i; - state[25] -= i; - - while (outLen > 0) - { - keccakPermutation(state); - - for (i = 0; i < outLen && i < rateBytes; i++) - { - output[count + i] = (byte)(state[i >> 3] >> (8 * (i & 0x07))); - } - count = count + i; - outLen -= i; - state[25] = rateBytes - i; - } - } - - public void squeeze(byte[] output, int outLen) - { - keccakIncSqueeze(output, outLen); - } - - public void randomGeneratorInit(byte[] entropyInput, byte[] personalizationString, int entropyLen, int perLen) - { - byte[] domain = new byte[]{1}; - keccakIncAbsorb(entropyInput, entropyLen); - keccakIncAbsorb(personalizationString, perLen); - keccakIncAbsorb(domain, domain.length); - keccakIncFinalize(0x1F); - } - - public void seedExpanderInit(byte[] seed, int seedLen) - { - byte[] domain = new byte[]{2}; - keccakIncAbsorb(seed, seedLen); - keccakIncAbsorb(domain, 1); - keccakIncFinalize(0x1F); - } - - public void expandSeed(byte[] output, int outLen) - { - int r = outLen & 7; - keccakIncSqueeze(output, outLen - r); - - if (r != 0) - { - byte[] tmp = new byte[8]; - keccakIncSqueeze(tmp, 8); - System.arraycopy(tmp, 0, output, outLen - r, r); - } - } - - public void SHAKE256_512_ds(byte[] output, byte[] input, int inLen, byte[] domain) - { - Arrays.fill(state, 0L); - keccakIncAbsorb(input, inLen); - keccakIncAbsorb(domain, domain.length); - keccakIncFinalize(0x1F); - keccakIncSqueeze(output, 512 / 8); - } - - private static long toUnsignedLong(int x) - { - return x & 0xffffffffL; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/ReedMuller.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/ReedMuller.java index a3000ea0e7..8a8ba76923 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/ReedMuller.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/ReedMuller.java @@ -22,7 +22,7 @@ static void encodeSub(Codeword codeword, int m) int word1; word1 = Bit0Mask(m >> 7); - word1 ^= Bit0Mask(m >> 0) & 0xaaaaaaaa; + word1 ^= Bit0Mask(m) & 0xaaaaaaaa; word1 ^= Bit0Mask(m >> 1) & 0xcccccccc; word1 ^= Bit0Mask(m >> 2) & 0xf0f0f0f0; word1 ^= Bit0Mask(m >> 3) & 0xff00ff00; @@ -69,8 +69,7 @@ private static void expandThenSum(int[] desCode, Codeword[] srcCode, int off, in { for (int j = 0; j < 32; j++) { - long ii = srcCode[0 + off].type32[i] >> j & 1; - desCode[i * 32 + j] = srcCode[0 + off].type32[i] >> j & 1; + desCode[i * 32 + j] = srcCode[off].type32[i] >> j & 1; } } @@ -102,7 +101,7 @@ private static int findPeaks(int[] input) peakVal = abs > peakAbsVal ? t : peakVal; peakPos = abs > peakAbsVal ? i : peakPos; - peakAbsVal = abs > peakAbsVal ? abs : peakAbsVal; + peakAbsVal = Math.max(abs, peakAbsVal); } int tmp = peakVal > 0 ? 1 : 0; peakPos |= 128 * tmp; @@ -112,7 +111,7 @@ private static int findPeaks(int[] input) private static int Bit0Mask(int b) { - return (-(b & 1)) & 0xffffffff; + return (-(b & 1)); } public static void encode(long[] codeword, byte[] m, int n1, int mulParam) @@ -136,6 +135,11 @@ public static void encode(long[] codeword, byte[] m, int n1, int mulParam) } } + CopyCWD(codeword, codewordCopy); + } + + private static void CopyCWD(long[] codeword, Codeword[] codewordCopy) + { int[] cwd64 = new int[codewordCopy.length * 4]; int off = 0; for (int i = 0; i < codewordCopy.length; i++) @@ -159,35 +163,21 @@ public static void decode(byte[] m, long[] codeword, int n1, int mulParam) for (int i = 0; i < codewordCopy.length; i++) { codewordCopy[i] = new Codeword(); - for (int j = 0; j < 4; j++) - { - codewordCopy[i].type32[j] = byteCodeWords[i * 4 + j]; - } + System.arraycopy(byteCodeWords, i * 4, codewordCopy[i].type32, 0, 4); } int[] expandedCodeword = new int[128]; - + int[] tmp = new int[128]; for (int i = 0; i < n1; i++) { expandThenSum(expandedCodeword, codewordCopy, i * mulParam, mulParam); - - - int[] tmp = new int[128]; hadamardTransform(expandedCodeword, tmp); - tmp[0] -= 64 * mulParam; mBytes[i] = (byte)findPeaks(tmp); } - int[] cwd64 = new int[codewordCopy.length * 4]; - int off = 0; - for (int i = 0; i < codewordCopy.length; i++) - { - System.arraycopy(codewordCopy[i].type32, 0, cwd64, off, codewordCopy[i].type32.length); - off += 4; - } - Utils.fromByte32ArrayToLongArray(codeword, cwd64); + CopyCWD(codeword, codewordCopy); System.arraycopy(mBytes, 0, m, 0, m.length); } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/ReedSolomon.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/ReedSolomon.java index 8da0b7035d..560b7ccd8a 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/ReedSolomon.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/ReedSolomon.java @@ -12,9 +12,9 @@ class ReedSolomon static int[] expArrays = {1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1, 2, 4}; // Encode - static void encode(byte[] codeWord, byte[] message, int mBitSize, int n1, int paramK, int paramG, int[] rsPoly) + static void encode(byte[] codeWord, byte[] message, int n1, int paramK, int paramG, int[] rsPoly) { - int gateValue = 0; + int gateValue; byte[] encodedBytes = new byte[n1]; int[] tmp = new int[paramG]; @@ -27,7 +27,6 @@ static void encode(byte[] codeWord, byte[] message, int mBitSize, int n1, int pa for (int j = 0; j < paramG; j++) { tmp[j] = GFCalculator.mult(gateValue, rsPoly[j]); - int n = 1; } for (int j = n1 - paramK - 1; j > 0; j--) @@ -85,36 +84,27 @@ private static void computeSyndromes(int[] syndromes, byte[] codeWord, int delta { if (n1 == 46) { - for (int i = 0; i < 2 * delta; i++) - { - for (int j = 1; j < n1; j++) - { - syndromes[i] ^= GFCalculator.mult(Utils.toUnsigned8bits(codeWord[j]), alpha128[i][j - 1]); - } - syndromes[i] ^= Utils.toUnsigned8bits(codeWord[0]); - } + computeSyndromes(syndromes, codeWord, delta, n1, alpha128); } else if (n1 == 56) { - for (int i = 0; i < 2 * delta; i++) - { - for (int j = 1; j < n1; j++) - { - syndromes[i] ^= GFCalculator.mult(Utils.toUnsigned8bits(codeWord[j]), alpha192[i][j - 1]); - } - syndromes[i] ^= Utils.toUnsigned8bits(codeWord[0]); - } + computeSyndromes(syndromes, codeWord, delta, n1, alpha192); } else if (n1 == 90) { - for (int i = 0; i < 2 * delta; i++) + computeSyndromes(syndromes, codeWord, delta, n1, alpha256); + } + } + + private static void computeSyndromes(int[] syndromes, byte[] codeWord, int delta, int n1, int[][] alpha128) + { + for (int i = 0; i < 2 * delta; i++) + { + for (int j = 1; j < n1; j++) { - for (int j = 1; j < n1; j++) - { - syndromes[i] ^= GFCalculator.mult(Utils.toUnsigned8bits(codeWord[j]), alpha256[i][j - 1]); - } - syndromes[i] ^= Utils.toUnsigned8bits(codeWord[0]); + syndromes[i] ^= GFCalculator.mult(Utils.toUnsigned8bits(codeWord[j]), alpha128[i][j - 1]); } + syndromes[i] ^= Utils.toUnsigned8bits(codeWord[0]); } } @@ -125,7 +115,7 @@ private static int computeELP(int[] sigma, int[] syndromes, int delta) int degSigmaP = 0; int[] sigmaDup = new int[delta + 1]; int[] sigmaP = new int[delta + 1]; - int degSigmaDup = 0; + int degSigmaDup; int pp = Utils.toUnsigned16Bits(-1); int dp = 1; int d = syndromes[0]; @@ -191,8 +181,7 @@ private static void computeZx(int[] output, int[] sigma, int deg, int[] syndrome for (int i = 2; i <= delta; i++) { int mask = i - deg < 1 ? 0xffff : 0; - output[i] = mask & sigma[i - 1]; - + output[i] ^= (mask) & syndromes[i - 1]; for (int j = 1; j < i; j++) { output[i] ^= (mask) & GFCalculator.mult(sigma[j], syndromes[i - j - 1]); @@ -205,9 +194,7 @@ private static void computeErrors(int[] res, int[] zx, byte[] errorCompactSet, i int[] betaSet = new int[delta]; int[] eSet = new int[delta]; - int deltaCount = 0; - int deltaVal = 0; - int mask1 = 0; + int deltaCount = 0, deltaVal, mask1; for (int i = 0; i < n1; i++) { int mark = 0; diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/Shake256RandomGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/Shake256RandomGenerator.java new file mode 100644 index 0000000000..0fa87e362f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/Shake256RandomGenerator.java @@ -0,0 +1,50 @@ +package org.bouncycastle.pqc.crypto.hqc; + +import org.bouncycastle.crypto.digests.SHAKEDigest; + +class Shake256RandomGenerator +{ + private final SHAKEDigest digest = new SHAKEDigest(256); + + public Shake256RandomGenerator(byte[] seed, byte domain) + { + digest.update(seed, 0, seed.length); + digest.update(domain); + } + + public Shake256RandomGenerator(byte[] seed, int off, int len, byte domain) + { + digest.update(seed, off, len); + digest.update(domain); + } + + public void init(byte[] seed, int off, int len, byte domain) + { + digest.reset(); + digest.update(seed, off, len); + digest.update(domain); + } + + public void nextBytes(byte[] bytes) + { + digest.doOutput(bytes, 0, bytes.length); + } + + public void nextBytes(byte[] output, int off, int len) + { + digest.doOutput(output, off, len); + } + + public void xofGetBytes(byte[] output, int outLen) + { + final int remainder = outLen & 7; + int tmpLen = outLen - remainder; + digest.doOutput(output, 0, tmpLen); + if (remainder != 0) + { + byte[] tmp = new byte[8]; + digest.doOutput(tmp, 0, 8); + System.arraycopy(tmp, 0, output, tmpLen, remainder); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/Utils.java index 764602cef5..3142c37928 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/Utils.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/hqc/Utils.java @@ -4,73 +4,40 @@ class Utils { - static void resizeArray(long[] out, int sizeOutBits, long[] in, int sizeInBits, int n1n2ByteSize, int n1n2Byte64Size) - { - long mask = 0x7FFFFFFFFFFFFFFFl; - int val = 0; - if (sizeOutBits < sizeInBits) - { - if (sizeOutBits % 64 != 0) - { - val = 64 - (sizeOutBits % 64); - } - - System.arraycopy(in, 0, out, 0, n1n2ByteSize); - - for (int i = 0; i < val; ++i) - { - out[n1n2Byte64Size - 1] &= (mask >> i); - } - } - else - { - System.arraycopy(in, 0, out, 0, (sizeInBits + 7) / 8); - } - } - - static void fromByte16ArrayToLongArray(long[] output, int[] input) - { - for (int i = 0; i != input.length; i += 4) - { - output[i / 4] = (long)input[i] & 0xffffL; - output[i / 4] |= (long)input[i + 1] << 16; - output[i / 4] |= (long)input[i + 2] << 32; - output[i / 4] |= (long)input[i + 3] << 48; - } - } - - static void fromByteArrayToByte16Array(int[] output, byte[] input) + static void fromLongArrayToByteArray(byte[] out, long[] in) { - byte[] tmp = input; - if (input.length % 2 != 0) + int max = out.length / 8; + for (int i = 0; i != max; i++) { - tmp = new byte[((input.length + 1) / 2) * 2]; - System.arraycopy(input, 0, tmp, 0, input.length); + Pack.longToLittleEndian(in[i], out, i * 8); } - int off = 0; - for (int i = 0; i < output.length; i++) + if (out.length % 8 != 0) { - output[i] = (int)Pack.littleEndianToShort(tmp, off) & 0xffff; - off += 2; + int off = max * 8; + int count = 0; + while (off < out.length) + { + out[off++] = (byte)(in[max] >>> (count++ * 8)); + } } } - static void fromLongArrayToByteArray(byte[] out, long[] in) + static void fromLongArrayToByteArray(byte[] out, int outOff, int outLen, long[] in) { - int max = out.length / 8; + int max = outLen >> 3; for (int i = 0; i != max; i++) { - Pack.longToLittleEndian(in[i], out, i * 8); + Pack.longToLittleEndian(in[i], out, outOff); + outOff += 8; } - if (out.length % 8 != 0) + if ((outLen & 7) != 0) { - int off = max * 8; int count = 0; - while (off < out.length) + while (outOff < out.length) { - out[off++] = (byte)(in[max] >>> (count++ * 8)); + out[outOff++] = (byte)(in[max] >>> (count++ * 8)); } } } @@ -80,17 +47,18 @@ static long bitMask(long a, long b) return ((1L << (a % b)) - 1); } - static void fromByteArrayToLongArray(long[] out, byte[] in) + static void fromByteArrayToLongArray(long[] out, byte[] in, int off, int inLen) { byte[] tmp = in; - if (in.length % 8 != 0) + if (inLen % 8 != 0) { - tmp = new byte[((in.length + 7) / 8) * 8]; - System.arraycopy(in, 0, tmp, 0, in.length); + tmp = new byte[((inLen + 7) / 8) * 8]; + System.arraycopy(in, off, tmp, 0, inLen); + off = 0; } - int off = 0; - for (int i = 0; i < out.length; i++) + int len = Math.min(out.length, (inLen + 7) >>> 3); + for (int i = 0; i < len; i++) { out[i] = Pack.littleEndianToLong(tmp, off); off += 8; @@ -139,12 +107,4 @@ static int toUnsigned16Bits(int a) { return a & 0xffff; } - - static void xorLongToByte16Array(int[] output, long input, int startIndex) - { - output[startIndex + 0] ^= (int)input & 0xffff; - output[startIndex + 1] ^= (int)(input >>> 16) & 0xffff; - output[startIndex + 2] ^= (int)(input >>> 32) & 0xffff; - output[startIndex + 3] ^= (int)(input >>> 48) & 0xffff; - } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java new file mode 100644 index 0000000000..20d993d0c5 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/GF16Utils.java @@ -0,0 +1,245 @@ +package org.bouncycastle.pqc.crypto.mayo; + +import org.bouncycastle.util.GF16; + +class GF16Utils +{ + static final long NIBBLE_MASK_MSB = 0x7777777777777777L; + static final long MASK_MSB = 0x8888888888888888L; + static final long MASK_LSB = 0x1111111111111111L; + static final long NIBBLE_MASK_LSB = ~MASK_LSB; + + /** + * Multiplies each limb of a GF(16) vector (subarray of 'in') by the GF(16) element 'a' + * and XORs the result into the corresponding subarray of acc. + *

    + * This version uses explicit array offsets. + * + * @param mVecLimbs the number of limbs in the vector + * @param in the input long array containing the vector; the vector starts at index inOffset + * @param inOffset the starting index in 'in' + * @param b the GF(16) element (0–255) to multiply by + * @param acc the accumulator long array; the target vector starts at index accOffset + * @param accOffset the starting index in 'acc' + */ + static void mVecMulAdd(int mVecLimbs, long[] in, int inOffset, int b, long[] acc, int accOffset) + { + long a, r64, a_msb, a_msb3; + long b32 = b & 0x00000000FFFFFFFFL; + long b32and1 = b32 & 1; + long b32_1_1 = ((b32 >>> 1) & 1); + long b32_2_1 = ((b32 >>> 2) & 1); + long b32_3_1 = ((b32 >>> 3) & 1); + for (int i = 0; i < mVecLimbs; i++) + { + // In the original code there is a conditional XOR with unsigned_char_blocker; + // here we simply use b directly. + a = in[inOffset++]; + r64 = a & -b32and1; + + a_msb = a & MASK_MSB; + a &= NIBBLE_MASK_MSB; + a_msb3 = a_msb >>> 3; + a = (a << 1) ^ (a_msb3 + (a_msb3 << 1)); + r64 ^= a & -b32_1_1; + + a_msb = a & MASK_MSB; + a &= NIBBLE_MASK_MSB; + a_msb3 = a_msb >>> 3; + a = (a << 1) ^ (a_msb3 + (a_msb3 << 1)); + r64 ^= a & -b32_2_1; + + a_msb = a & MASK_MSB; + a &= NIBBLE_MASK_MSB; + a_msb3 = a_msb >>> 3; + a = (a << 1) ^ (a_msb3 + (a_msb3 << 1)); + acc[accOffset++] ^= r64 ^ (a & -b32_3_1); + } + } + + + /** + * Performs the multiplication and accumulation of a block of an upper‐triangular matrix + * times a second matrix. + * + * @param mVecLimbs number of limbs per m-vector. + * @param bsMat the “basis” matrix (as a flat long[] array); each entry occupies mVecLimbs elements. + * @param mat the second matrix (as a flat byte[] array) stored row‐major, + * with dimensions (bsMatCols x matCols). + * @param acc the accumulator (as a flat long[] array) with dimensions (bsMatRows x matCols); + * each “entry” is an m‐vector (length mVecLimbs). + * @param bsMatRows number of rows in the bsMat (the “triangular” matrix’s row count). + * @param matCols number of columns in the matrix “mat.” + */ + static void mulAddMUpperTriangularMatXMat(int mVecLimbs, long[] bsMat, byte[] mat, long[] acc, int accOff, + int bsMatRows, int matCols) + { + int bsMatEntriesUsed = 0; + int matColsmVecLimbs = matCols * mVecLimbs; + for (int r = 0, rmatCols = 0, rmatColsmVecLimbs = 0; r < bsMatRows; r++, rmatCols += matCols, rmatColsmVecLimbs += matColsmVecLimbs) + { + // For each row r, the inner loop goes from column triangular*r to bsMatCols-1. + for (int c = r, cmatCols = rmatCols; c < bsMatRows; c++, cmatCols += matCols) + { + for (int k = 0, kmVecLimbs = 0; k < matCols; k++, kmVecLimbs += mVecLimbs) + { + // For acc: add into the m-vector at row r, column k. + mVecMulAdd(mVecLimbs, bsMat, bsMatEntriesUsed, mat[cmatCols + k], acc, accOff + rmatColsmVecLimbs + kmVecLimbs); + } + bsMatEntriesUsed += mVecLimbs; + } + } + } + + /** + * Multiplies the transpose of a single matrix with m matrices and adds the result into acc. + * + * @param mVecLimbs number of limbs per m-vector. + * @param mat the matrix to be transposed (as a flat byte[] array), dimensions: (matRows x matCols). + * @param bsMat the m-matrix (as a flat long[] array), with each entry of length mVecLimbs. + * Its logical dimensions: (matRows x bsMatCols). + * @param acc the accumulator (as a flat long[] array) with dimensions (matCols x bsMatCols); + * each entry is an m-vector. + * @param matRows number of rows in the matrix “mat.” + * @param matCols number of columns in “mat.” + */ + static void mulAddMatTransXMMat(int mVecLimbs, byte[] mat, long[] bsMat, int bsMatOff, long[] acc, + int matRows, int matCols) + { + int multiply = matCols * mVecLimbs; + for (int r = 0, rmultiply = 0; r < matCols; r++, rmultiply += multiply) + { + for (int c = 0, cmatCols = 0, cmultiply = 0; c < matRows; c++, cmatCols += matCols, cmultiply += multiply) + { + byte matVal = mat[cmatCols + r]; + for (int k = 0, kmVecLimbs = 0; k < matCols; k++, kmVecLimbs += mVecLimbs) + { + mVecMulAdd(mVecLimbs, bsMat, bsMatOff + cmultiply + kmVecLimbs, matVal, acc, rmultiply + kmVecLimbs); + } + } + } + } + + /** + * Multiplies a matrix (given as a byte array) with a bit‐sliced matrix (given as a long array) + * and accumulates the result into the acc array. + * + *

    + * The operation iterates over the rows and columns of the matrix. For each element in the matrix, + * it multiplies a corresponding vector (from bsMat) by the scalar value (from mat) and adds the + * result to the accumulator vector in acc. + *

    + * + * @param mVecLimbs the number of limbs (elements) in each vector + * @param mat the matrix as a byte array with dimensions [matRows x matCols] + * @param bsMat the bit‐sliced matrix as a long array + * @param acc the accumulator array (long[]) where results are accumulated + * @param matRows the number of rows in the matrix + * @param matCols the number of columns in the matrix + */ + static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, long[] acc, int matRows, int matCols) + { + int multiply = mVecLimbs * matRows; + for (int r = 0, rmatCols = 0, rmultiply = 0; r < matRows; r++, rmatCols += matCols, rmultiply += multiply) + { + for (int c = 0, cmultiply = 0; c < matCols; c++, cmultiply += multiply) + { + // Retrieve the scalar from the matrix for row r and column c. + byte matVal = mat[rmatCols + c]; + for (int k = 0, kmVecLimbs = 0; k < matRows; k++, kmVecLimbs += mVecLimbs) + { + mVecMulAdd(mVecLimbs, bsMat, cmultiply + kmVecLimbs, matVal, acc, rmultiply + kmVecLimbs); + } + } + } + } + + static void mulAddMatXMMat(int mVecLimbs, byte[] mat, long[] bsMat, int bsMatOff, long[] acc, + int matRows, int matCols, int bsMatCols) + { + int multiply = mVecLimbs * bsMatCols; + for (int r = 0, rmultiply = 0, rmatCols = 0; r < matRows; r++, rmultiply += multiply, rmatCols += matCols) + { + for (int c = 0, cmultiply = 0; c < matCols; c++, cmultiply += multiply) + { + // Retrieve the scalar from the matrix for row r and column c. + byte matVal = mat[rmatCols + c]; + for (int k = 0, kmVecLimbs = 0; k < bsMatCols; k++, kmVecLimbs += mVecLimbs) + { + mVecMulAdd(mVecLimbs, bsMat, cmultiply + kmVecLimbs + bsMatOff, matVal, acc, rmultiply + kmVecLimbs); + } + } + } + } + + /** + * Multiplies m (possibly upper triangular) matrices with the transpose of a single matrix + * and adds the result to the accumulator. + * + *

    + * For each row {@code r} in the bit‑sliced matrix and for each column {@code c} (starting from + * {@code triangular * r}) in the bit‑sliced matrix, this method iterates over all rows {@code k} + * of the single matrix, and for each element, it multiplies the vector (from {@code bsMat}) + * by the scalar (from {@code mat}) and adds the result to the corresponding vector in {@code acc}. + *

    + * + * @param mVecLimbs the number of limbs (elements) in each vector. + * @param bsMat the bit‑sliced matrix stored as a long array. + * @param mat the matrix stored as a byte array. + * @param acc the accumulator array where the results are added. + * @param bsMatRows the number of rows in the bit‑sliced matrix. + * @param matRows the number of rows in the matrix. + */ + static void mulAddMUpperTriangularMatXMatTrans(int mVecLimbs, long[] bsMat, byte[] mat, long[] acc, int bsMatRows, int matRows) + { + int bsMatEntriesUsed = 0; + int multiply = mVecLimbs * matRows; + for (int r = 0, rmultiply = 0; r < bsMatRows; r++, rmultiply += multiply) + { + // For upper triangular, start c at triangular * r; otherwise, triangular is zero. + for (int c = r; c < bsMatRows; c++) + { + for (int k = 0, kbsMatRows = 0, kmVecLimbs = 0; k < matRows; k++, kbsMatRows += bsMatRows, kmVecLimbs += mVecLimbs) + { + mVecMulAdd(mVecLimbs, bsMat, bsMatEntriesUsed, mat[kbsMatRows + c], acc, rmultiply + kmVecLimbs); + } + bsMatEntriesUsed += mVecLimbs; + } + } + } + + /** + * Performs a GF(16) carryless multiplication of a nibble (lower 4 bits of a) + * with a 64-bit word b, then reduces modulo the polynomial x⁴ + x + 1 on each byte. + * + * @param a a GF(16) element (only the low 4 bits are used) + * @param b a 64-bit word representing 16 GF(16) elements (packed 4 bits per element) + * @return the reduced 64-bit word after multiplication + */ + static long mulFx8(byte a, long b) + { + // Convert 'a' to an unsigned int so that bit operations work as expected. + int aa = a & 0xFF; + // Carryless multiplication: for each bit in 'aa' (considering only the lower 4 bits), + // if that bit is set, multiply 'b' (by 1, 2, 4, or 8) and XOR the result. + long p = (-(aa & 1) & b) ^ (-((aa >> 1) & 1) & (b << 1)) ^ (-((aa >> 2) & 1) & (b << 2)) ^ (-((aa >> 3) & 1) & (b << 3)); + + // Reduction mod (x^4 + x + 1): process each byte in parallel. + long topP = p & 0xf0f0f0f0f0f0f0f0L; + return (p ^ (topP >>> 4) ^ (topP >>> 3)) & 0x0f0f0f0f0f0f0f0fL; + } + + static void matMul(byte[] a, byte[] b, int bOff, byte[] c, int colrowAB, int rowA) + { + for (int i = 0, aRowStart = 0, cOff = 0; i < rowA; i++) + { + byte result = 0; + for (int k = 0; k < colrowAB; k++) + { + result ^= GF16.mul(a[aRowStart++], b[bOff + k]); + } + c[cOff++] = result; + } + } +} + diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyGenerationParameters.java new file mode 100644 index 0000000000..0ca1b7f1b4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyGenerationParameters.java @@ -0,0 +1,24 @@ +package org.bouncycastle.pqc.crypto.mayo; + +import java.security.SecureRandom; + +import org.bouncycastle.crypto.KeyGenerationParameters; + +public class MayoKeyGenerationParameters + extends KeyGenerationParameters +{ + private final MayoParameters params; + + public MayoKeyGenerationParameters( + SecureRandom random, + MayoParameters mayoParameters) + { + super(random, 256); + this.params = mayoParameters; + } + + public MayoParameters getParameters() + { + return params; + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java new file mode 100644 index 0000000000..4d0df2b02b --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyPairGenerator.java @@ -0,0 +1,149 @@ +package org.bouncycastle.pqc.crypto.mayo; + +import java.security.SecureRandom; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import org.bouncycastle.crypto.KeyGenerationParameters; +import org.bouncycastle.crypto.digests.SHAKEDigest; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.GF16; +import org.bouncycastle.util.Longs; + +/** + * Implementation of the MAYO asymmetric key pair generator following the MAYO signature scheme specifications. + *

    + * This generator produces {@link MayoPublicKeyParameters} and {@link MayoPrivateKeyParameters} based on the + * MAYO algorithm parameters. The implementation follows the specification defined in the official MAYO + * documentation and reference implementation. + *

    + * + *

    References:

    + * + * + */ +public class MayoKeyPairGenerator + implements AsymmetricCipherKeyPairGenerator +{ + private MayoParameters p; + private SecureRandom random; + + public void init(KeyGenerationParameters param) + { + this.p = ((MayoKeyGenerationParameters)param).getParameters(); + this.random = param.getRandom(); + } + + /** + * Generates a new asymmetric key pair following the MAYO algorithm specifications. + *

    + * The key generation process follows these steps: + *

    + *
      + *
    1. Initializes parameter dimensions from {@link MayoParameters}
    2. + *
    3. Generates secret key seed using a secure random generator
    4. + *
    5. Derives public key seed using SHAKE-256
    6. + *
    7. Expands matrix parameters P1 and P2
    8. + *
    9. Performs GF(16) matrix operations for key material generation
    10. + *
    11. Assembles and packages the public key components
    12. + *
    13. Securely clears temporary buffers containing sensitive data
    14. + *
    + * + * @return A valid MAYO key pair containing public and private key parameters + */ + @Override + public AsymmetricCipherKeyPair generateKeyPair() + { + // Retrieve parameters from p. + int mVecLimbs = p.getMVecLimbs(); + int m = p.getM(); + int v = p.getV(); + int o = p.getO(); + int oBytes = p.getOBytes(); + int p1Limbs = p.getP1Limbs(); + int p3Limbs = p.getP3Limbs(); + int pkSeedBytes = p.getPkSeedBytes(); + int skSeedBytes = p.getSkSeedBytes(); + + byte[] cpk = new byte[p.getCpkBytes()]; + // seed_sk points to csk. + byte[] seed_sk = new byte[p.getCskBytes()]; + + // Allocate S = new byte[PK_SEED_BYTES_MAX + O_BYTES_MAX] + byte[] seed_pk = new byte[pkSeedBytes + oBytes]; + + // Allocate P as a long array of size (P1_LIMBS_MAX + P2_LIMBS_MAX) + long[] P = new long[p1Limbs + p.getP2Limbs()]; + + // Allocate P3 as a long array of size (O_MAX * O_MAX * M_VEC_LIMBS_MAX), zero-initialized. + long[] P3 = new long[o * o * mVecLimbs]; + + byte[] O = new byte[v * o]; + + // Generate secret key seed (seed_sk) using a secure random generator. + random.nextBytes(seed_sk); + + // S ← shake256(seed_sk, pk_seed_bytes + O_bytes) + SHAKEDigest shake = new SHAKEDigest(256); + shake.update(seed_sk, 0, skSeedBytes); + shake.doFinal(seed_pk, 0, pkSeedBytes + oBytes); + + // o ← Decode_o(S[ param_pk_seed_bytes : param_pk_seed_bytes + O_bytes ]) + // Decode nibbles from S starting at offset param_pk_seed_bytes into O, + // with expected output length = param_v * param_o. + GF16.decode(seed_pk, pkSeedBytes, O, 0, O.length); + + // Expand P1 and P2 into the array P using seed_pk. + Utils.expandP1P2(p, P, seed_pk); + + // Compute P1 * O + P2 and store the result in P2. + // GF16Utils.P1TimesO(p, P, O, P2); + // Here, bsMatRows and bsMatCols are both paramV, and matCols is paramO, triangular=1. + GF16Utils.mulAddMUpperTriangularMatXMat(mVecLimbs, P, O, P, p1Limbs, v, o); + + // Compute P3 = O^T * (P1*O + P2). + // Here, treat P2 as the bsMat for the multiplication. + // Dimensions: mat = O (size: paramV x paramO), bsMat = P2 (size: paramV x paramO), + // and acc (P3) will have dimensions: (paramO x paramO), each entry being an m-vector. + GF16Utils.mulAddMatTransXMMat(mVecLimbs, O, P, p1Limbs, P3, v, o); + + // Store seed_pk into the public key cpk. + System.arraycopy(seed_pk, 0, cpk, 0, pkSeedBytes); + + // Allocate an array for the "upper" part of P3. + long[] P3_upper = new long[p3Limbs]; + + // Compute Upper(P3) and store the result in P3_upper. + int mVecsStored = 0; + int omVecLimbs = o * mVecLimbs; + for (int r = 0, rmVecLimbs = 0, romVecLimbs = 0; r < o; r++, romVecLimbs += omVecLimbs, rmVecLimbs += mVecLimbs) + { + for (int c = r, cmVecLimbs = rmVecLimbs, comVecLimbs = romVecLimbs; c < o; c++, cmVecLimbs += mVecLimbs, comVecLimbs += omVecLimbs) + { + // Copy the vector at (r, c) into the output. + System.arraycopy(P3, romVecLimbs + cmVecLimbs, P3_upper, mVecsStored, mVecLimbs); + + // If off-diagonal, add (XOR) the vector at (c, r) into the same output vector. + if (r != c) + { + Longs.xorTo(mVecLimbs, P3, comVecLimbs + rmVecLimbs, P3_upper, mVecsStored); + } + mVecsStored += mVecLimbs; + } + } + + // Pack the m-vectors in P3_upper into cpk (after the seed_pk). + // The number of m-vectors to pack is (param_P3_limbs / m_vec_limbs), + // and param_m is used as the m value. + Utils.packMVecs(P3_upper, cpk, pkSeedBytes, p3Limbs / mVecLimbs, m); + // Securely clear sensitive data. + Arrays.clear(O); + Arrays.clear(P3); + + return new AsymmetricCipherKeyPair(new MayoPublicKeyParameters(p, cpk), new MayoPrivateKeyParameters(p, seed_sk)); + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2KeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyParameters.java similarity index 51% rename from core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2KeyParameters.java rename to core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyParameters.java index 4c13a35e2d..4b932949dc 100644 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2KeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoKeyParameters.java @@ -1,25 +1,22 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; +package org.bouncycastle.pqc.crypto.mayo; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; - -public class McElieceCCA2KeyParameters +public class MayoKeyParameters extends AsymmetricKeyParameter { - private String params; + private final MayoParameters params; - public McElieceCCA2KeyParameters( + public MayoKeyParameters( boolean isPrivate, - String params) + MayoParameters params) { super(isPrivate); this.params = params; } - - public String getDigest() + public MayoParameters getParameters() { return params; } - } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java new file mode 100644 index 0000000000..28c01ad0c4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoParameters.java @@ -0,0 +1,288 @@ +package org.bouncycastle.pqc.crypto.mayo; + +public class MayoParameters +{ + public static final MayoParameters mayo1 = new MayoParameters( + "MAYO_1", // name + 86, // n + 78, // m + 5, // m_vec_limbs + 8, // o + 86 - 8, // v = n - o = 78 + 10 * 8 + 1, // A_cols = k * o + 1 = 10 * 8 + 1 = 81 + 10, // k + // q + 39, // m_bytes + 312, // O_bytes + 39, // v_bytes + 40, // r_bytes + 120159, // P1_bytes + 24336, // P2_bytes + 24, // csk_bytes + 1420, // cpk_bytes + 454, // sig_bytes + new int[]{8, 1, 1, 0}, // F_TAIL_78 + 24, // salt_bytes + 32, // digest_bytes + 24 // sk_seed_bytes + ); + + public static final MayoParameters mayo2 = new MayoParameters( + "MAYO_2", // name + 81, // n + 64, // m + 4, // m_vec_limbs + 17, // o + 81 - 17, // v = 64 + 4 * 17 + 1, // A_cols = 4 * 17 + 1 = 69 + 4, // k + 32, // m_bytes + 544, // O_bytes + 32, // v_bytes + 34, // r_bytes + 66560, // P1_bytes + 34816, // P2_bytes + 24, // csk_bytes + 4912, // cpk_bytes + 186, // sig_bytes + new int[]{8, 0, 2, 8}, //F_TAIL_64 + 24, // salt_bytes + 32, // digest_bytes + 24 // sk_seed_bytes + ); + + public static final MayoParameters mayo3 = new MayoParameters( + "MAYO_3", // name + 118, // n + 108, // m + 7, // m_vec_limbs + 10, // o + 118 - 10, // v = 108 + 11 * 10 + 1, // A_cols = 11 * 10 + 1 = 111 + 11, // k + 54, // m_bytes + 540, // O_bytes + 54, // v_bytes + 55, // r_bytes + 317844, // P1_bytes + 58320, // P2_bytes + 32, // csk_bytes + 2986, // cpk_bytes + 681, // sig_bytes + new int[]{8, 0, 1, 7}, //F_TAIL_108 + 32, // salt_bytes + 48, // digest_bytes + 32 // sk_seed_bytes + ); + + public static final MayoParameters mayo5 = new MayoParameters( + "MAYO_5", // name + 154, // n + 142, // m + 9, // m_vec_limbs + 12, // o + 154 - 12, // v = 142 + 12 * 12 + 1, // A_cols = 12 * 12 + 1 = 145 + 12, // k + 71, // m_bytes + 852, // O_bytes + 71, // v_bytes + 72, // r_bytes + 720863, // P1_bytes + 120984, // P2_bytes + 40, // csk_bytes + 5554, // cpk_bytes + 964, // sig_bytes + new int[]{4, 0, 8, 1}, //F_TAIL_142 + 40, // salt_bytes + 64, // digest_bytes + 40 // sk_seed_bytes + ); + + private final String name; + private final int n; + private final int m; + private final int mVecLimbs; + private final int o; + private final int v; + private final int ACols; + private final int k; + //private final int q; q = 16 + private final int mBytes; + private final int OBytes; + private final int vBytes; + private final int rBytes; + private final int P1Bytes; + private final int P2Bytes; + private final int cskBytes; + private final int cpkBytes; + private final int sigBytes; + private final int[] fTail; + private final int saltBytes; + private final int digestBytes; + private static final int pkSeedBytes = 16; + private final int skSeedBytes; + + private MayoParameters(String name, int n, int m, int mVecLimbs, int o, int v, int ACols, int k, + int mBytes, int OBytes, int vBytes, int rBytes, int P1Bytes, int P2Bytes, + int cskBytes, int cpkBytes, int sigBytes, int[] fTail, + int saltBytes, int digestBytes, int skSeedBytes) + { + this.name = name; + this.n = n; + this.m = m; + this.mVecLimbs = mVecLimbs; + this.o = o; + this.v = v; + this.ACols = ACols; + this.k = k; + this.mBytes = mBytes; + this.OBytes = OBytes; + this.vBytes = vBytes; + this.rBytes = rBytes; + this.P1Bytes = P1Bytes; + this.P2Bytes = P2Bytes; + this.cskBytes = cskBytes; + this.cpkBytes = cpkBytes; + this.sigBytes = sigBytes; + this.fTail = fTail; + this.saltBytes = saltBytes; + this.digestBytes = digestBytes; + this.skSeedBytes = skSeedBytes; + } + + public String getName() + { + return name; + } + + public int getN() + { + return n; + } + + public int getM() + { + return m; + } + + public int getMVecLimbs() + { + return mVecLimbs; + } + + public int getO() + { + return o; + } + + public int getV() + { + return v; + } + + public int getACols() + { + return ACols; + } + + public int getK() + { + return k; + } + + public int getMBytes() + { + return mBytes; + } + + public int getOBytes() + { + return OBytes; + } + + public int getVBytes() + { + return vBytes; + } + + public int getRBytes() + { + return rBytes; + } + + public int getP1Bytes() + { + return P1Bytes; + } + + public int getP2Bytes() + { + return P2Bytes; + } + + public int getCskBytes() + { + return cskBytes; + } + + public int getCpkBytes() + { + return cpkBytes; + } + + public int getSigBytes() + { + return sigBytes; + } + + public int[] getFTail() + { + return fTail; + } + + public int getSaltBytes() + { + return saltBytes; + } + + public int getDigestBytes() + { + return digestBytes; + } + + public int getPkSeedBytes() + { + return pkSeedBytes; + } + + public int getSkSeedBytes() + { + return skSeedBytes; + } + + /** + * Computes: (v * (v + 1) / 2) * mVecLimbs + */ + public int getP1Limbs() + { + return ((v * (v + 1)) >> 1) * mVecLimbs; + } + + /** + * Computes: v * o * mVecLimbs + */ + public int getP2Limbs() + { + return v * o * mVecLimbs; + } + + /** + * Computes: (o * (o + 1) / 2) * mVecLimbs + */ + public int getP3Limbs() + { + return ((o * (o + 1)) >> 1) * mVecLimbs; + } +} + diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameters.java new file mode 100644 index 0000000000..1dcc6324dd --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPrivateKeyParameters.java @@ -0,0 +1,25 @@ +package org.bouncycastle.pqc.crypto.mayo; + +import org.bouncycastle.util.Arrays; + +public class MayoPrivateKeyParameters + extends MayoKeyParameters +{ + private final byte[] seed_sk; + + public MayoPrivateKeyParameters(MayoParameters params, byte[] seed_sk) + { + super(true, params); + this.seed_sk = Arrays.clone(seed_sk); + } + + public byte[] getEncoded() + { + return Arrays.clone(seed_sk); + } + + public byte[] getSeedSk() + { + return Arrays.clone(seed_sk); + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameters.java new file mode 100644 index 0000000000..f7df56fb69 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoPublicKeyParameters.java @@ -0,0 +1,25 @@ +package org.bouncycastle.pqc.crypto.mayo; + +import org.bouncycastle.util.Arrays; + +public class MayoPublicKeyParameters + extends MayoKeyParameters +{ + private final byte[] p; + + public MayoPublicKeyParameters(MayoParameters params, byte[] p) + { + super(false, params); + this.p = Arrays.clone(p); + } + + public byte[] getP() + { + return Arrays.clone(p); + } + + public byte[] getEncoded() + { + return Arrays.clone(p); + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java new file mode 100644 index 0000000000..3909641eb6 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/MayoSigner.java @@ -0,0 +1,1011 @@ +package org.bouncycastle.pqc.crypto.mayo; + +import java.security.SecureRandom; + +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.crypto.digests.SHAKEDigest; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.pqc.crypto.MessageSigner; + +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Bytes; +import org.bouncycastle.util.GF16; +import org.bouncycastle.util.Longs; +import org.bouncycastle.util.Pack; + +/** + * Implementation of the MAYO digital signature scheme as specified in the MAYO documentation. + * This class provides functionality for both signature generation and verification. + * + *

    MAYO is a candidate in the NIST Post-Quantum Cryptography: Additional Digital Signature Schemes project, + * currently in Round 2 of evaluations. For more details about the NIST standardization process, see: + * NIST PQC Additional Digital Signatures.

    + * + *

    References:

    + * + */ +public class MayoSigner + implements MessageSigner +{ + private SecureRandom random; + private MayoParameters params; + private MayoPublicKeyParameters pubKey; + private MayoPrivateKeyParameters privKey; + + /** + * Initializes the signer for either signature generation or verification. + * + * @param forSigning {@code true} for signing mode, {@code false} for verification + * @param param CipherParameters containing: + *
      + *
    • {@link ParametersWithRandom} with {@link MayoPrivateKeyParameters} (for signing)
    • + *
    • {@link MayoPublicKeyParameters} (for verification)
    • + *
    + * @throws IllegalArgumentException if invalid parameters are provided + */ + @Override + public void init(boolean forSigning, CipherParameters param) + { + if (forSigning) + { + pubKey = null; + + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom withRandom = (ParametersWithRandom)param; + privKey = (MayoPrivateKeyParameters)withRandom.getParameters(); + random = withRandom.getRandom(); + } + else + { + privKey = (MayoPrivateKeyParameters)param; + random = CryptoServicesRegistrar.getSecureRandom(); + } + params = privKey.getParameters(); + } + else + { + pubKey = (MayoPublicKeyParameters)param; + params = pubKey.getParameters(); + privKey = null; + random = null; + } + } + + /** + * Generates a MAYO signature for the given message using the initialized private key. + * Follows the signature generation process outlined in the MAYO specification document. + * + * @param message The message to be signed + * @return The signature bytes concatenated with the original message + * @see MAYO Spec Algorithm 8 and 10 + */ + @Override + public byte[] generateSignature(byte[] message) + { + int k = params.getK(); + int v = params.getV(); + int o = params.getO(); + int n = params.getN(); + int m = params.getM(); + int vbytes = params.getVBytes(); + int oBytes = params.getOBytes(); + int saltBytes = params.getSaltBytes(); + int mVecLimbs = params.getMVecLimbs(); + int p1Limbs = params.getP1Limbs(); + int pk_seed_bytes = params.getPkSeedBytes(); + int digestBytes = params.getDigestBytes(); + int skSeedBytes = params.getSkSeedBytes(); + byte[] tenc = new byte[params.getMBytes()]; + byte[] t = new byte[m]; + byte[] y = new byte[m]; + byte[] salt = new byte[saltBytes]; + byte[] V = new byte[k * vbytes + params.getRBytes()]; + byte[] Vdec = new byte[v * k]; + int ok = k * o; + int nk = k * n; + byte[] A = new byte[((m + 7) / 8 * 8) * (ok + 1)]; + byte[] x = new byte[nk]; + byte[] r = new byte[ok + 1]; + byte[] s = new byte[nk]; + byte[] tmp = new byte[digestBytes + saltBytes + skSeedBytes + 1]; + byte[] sig = new byte[params.getSigBytes()]; + long[] P = new long[p1Limbs + params.getP2Limbs()]; + byte[] O = new byte[v * o]; + long[] Mtmp = new long[ok * mVecLimbs]; + long[] vPv = new long[k * k * mVecLimbs]; + SHAKEDigest shake = new SHAKEDigest(256); + try + { + byte[] seed_sk = privKey.getSeedSk(); + // Expand secret key + //MayoEngine.mayoExpandSk(params, seed_sk, P, O); + int totalS = pk_seed_bytes + oBytes; + byte[] seed_pk = new byte[totalS]; + + // Generate S = seed_pk || (additional bytes), using SHAKE256. + // Output length is param_pk_seed_bytes + param_O_bytes. + shake.update(seed_sk, 0, seed_sk.length); + shake.doFinal(seed_pk, 0, totalS); + + // Decode the portion of S after the first param_pk_seed_bytes into O. + // (In C, this is: decode(S + param_pk_seed_bytes, O, param_v * param_o)) + GF16.decode(seed_pk, pk_seed_bytes, O, 0, O.length); + + // Expand P1 and P2 into the long array P using seed_pk. + Utils.expandP1P2(params, P, seed_pk); + + // Compute L_i = (P1 + P1^t)*O + P2. + // Here, we assume that P1P1tTimesO writes into the portion of P starting at offsetP2. + //MayoEngine.P1P1tTimesO(params, P, O, P, p1Limbs); + int bsMatEntriesUsed = 0; + int omVecLimbs = o * mVecLimbs; + for (int i = 0, io = 0, iomVecLimbs = 0; i < v; i++, io += o, iomVecLimbs += omVecLimbs) + { + for (int c = i, co = io, comVecLimbs = iomVecLimbs; c < v; c++, co += o, comVecLimbs += omVecLimbs) + { + if (c == i) + { + bsMatEntriesUsed += mVecLimbs; + continue; + } + for (int j = 0, jmVecLimbs = p1Limbs; j < o; j++, jmVecLimbs += mVecLimbs) + { + // Multiply the m-vector at P1 for the current matrix entry, + // and accumulate into acc for row r. + GF16Utils.mVecMulAdd(mVecLimbs, P, bsMatEntriesUsed, O[co + j], P, iomVecLimbs + jmVecLimbs); + // Similarly, accumulate into acc for row c. + GF16Utils.mVecMulAdd(mVecLimbs, P, bsMatEntriesUsed, O[io + j], P, comVecLimbs + jmVecLimbs); + } + bsMatEntriesUsed += mVecLimbs; + } + } + // Securely clear sensitive temporary data. + Arrays.fill(seed_pk, (byte)0); + + // Hash message + shake.update(message, 0, message.length); + shake.doFinal(tmp, 0, digestBytes); + + // Generate random salt + random.nextBytes(salt); + + System.arraycopy(salt, 0, tmp, digestBytes, salt.length); + + // Hash to salt + System.arraycopy(seed_sk, 0, tmp, digestBytes + saltBytes, skSeedBytes); + + shake.update(tmp, 0, digestBytes + saltBytes + skSeedBytes); + shake.doFinal(salt, 0, saltBytes); + + // Hash to t + System.arraycopy(salt, 0, tmp, digestBytes, saltBytes); + shake.update(tmp, 0, digestBytes + saltBytes); + shake.doFinal(tenc, 0, params.getMBytes()); + GF16.decode(tenc, t, m); + int size = v * k * mVecLimbs; + long[] Pv = new long[size]; + byte[] Ox = new byte[v]; + for (int ctr = 0; ctr <= 255; ctr++) + { + tmp[tmp.length - 1] = (byte)ctr; + + // Generate V + shake.update(tmp, 0, tmp.length); + shake.doFinal(V, 0, V.length); + + // Decode vectors + for (int i = 0; i < k; i++) + { + GF16.decode(V, i * vbytes, Vdec, i * v, v); + } + + //computeMandVPV(params, Vdec, P, params.getP1Limbs(), P, Mtmp, vPv); + // Compute VL: VL = Vdec * L + GF16Utils.mulAddMatXMMat(mVecLimbs, Vdec, P, p1Limbs, Mtmp, k, v, o); + + // Compute VP1V: + // Allocate temporary array for Pv. Its length is V_MAX * K_MAX * M_VEC_LIMBS_MAX. + // Compute Pv = P1 * V^T (using upper triangular multiplication) + GF16Utils.mulAddMUpperTriangularMatXMatTrans(mVecLimbs, P, Vdec, Pv, v, k); + // Compute VP1V = Vdec * Pv + GF16Utils.mulAddMatXMMat(mVecLimbs, Vdec, Pv, vPv, k, v); + + computeRHS(vPv, t, y); + computeA(Mtmp, A); + + // Clear trailing bytes +// for (int i = 0; i < m; ++i) +// { +// A[(i + 1) * (ok + 1) - 1] = 0; +// } + + GF16.decode(V, k * vbytes, r, 0, ok); + + if (sampleSolution(A, y, r, x)) + { + break; + } + else + { + Arrays.fill(Mtmp, 0L); + Arrays.fill(vPv, 0L); + } + } + + // Compute final signature components + + for (int i = 0, io = 0, in = 0, iv = 0; i < k; i++, io += o, in += n, iv += v) + { + GF16Utils.matMul(O, x, io, Ox, o, v); + Bytes.xor(v, Vdec, iv, Ox, s, in); + System.arraycopy(x, io, s, in + v, o); + } + + // Encode and add salt + GF16.encode(s, sig, nk); + System.arraycopy(salt, 0, sig, sig.length - saltBytes, saltBytes); + + return Arrays.concatenate(sig, message); + } + finally + { + // Secure cleanup + Arrays.fill(tenc, (byte)0); + Arrays.fill(t, (byte)0); + Arrays.fill(y, (byte)0); + Arrays.fill(salt, (byte)0); + Arrays.fill(V, (byte)0); + Arrays.fill(Vdec, (byte)0); + Arrays.fill(A, (byte)0); + Arrays.fill(x, (byte)0); + Arrays.fill(r, (byte)0); + Arrays.fill(s, (byte)0); + Arrays.fill(tmp, (byte)0); + } + } + + /** + * Verifies a MAYO signature against the initialized public key and message. + * Implements the verification process specified in the MAYO documentation. + * + * @param message The original message + * @param signature The signature to verify + * @return {@code true} if the signature is valid, {@code false} otherwise + * @see MAYO Spec Algorithm 9 and 11 + */ + @Override + public boolean verifySignature(byte[] message, byte[] signature) + { + final int m = params.getM(); + final int n = params.getN(); + final int k = params.getK(); + int kn = k * n; + int p1Limbs = params.getP1Limbs(); + int p2Limbs = params.getP2Limbs(); + int p3Limbs = params.getP3Limbs(); + final int mBytes = params.getMBytes(); + final int sigBytes = params.getSigBytes(); + final int digestBytes = params.getDigestBytes(); + final int saltBytes = params.getSaltBytes(); + int mVecLimbs = params.getMVecLimbs(); + byte[] tEnc = new byte[mBytes]; + byte[] t = new byte[m]; + byte[] y = new byte[m << 1]; + byte[] s = new byte[kn]; + long[] pk = new long[p1Limbs + p2Limbs + p3Limbs]; + byte[] tmp = new byte[digestBytes + saltBytes]; + byte[] cpk = pubKey.getEncoded(); + + // Expand public key + // mayo_expand_pk + Utils.expandP1P2(params, pk, cpk); + Utils.unpackMVecs(cpk, params.getPkSeedBytes(), pk, p1Limbs + p2Limbs, p3Limbs / mVecLimbs, m); + + // Hash message + SHAKEDigest shake = new SHAKEDigest(256); + shake.update(message, 0, message.length); + shake.doFinal(tmp, 0, digestBytes); + + // Compute t + shake.update(tmp, 0, digestBytes); + shake.update(signature, sigBytes - saltBytes, saltBytes); + shake.doFinal(tEnc, 0, mBytes); + GF16.decode(tEnc, t, m); + + // Decode signature + GF16.decode(signature, s, kn); + + // Evaluate public map + //evalPublicMap(params, s, P1, P2, P3, y); + long[] SPS = new long[k * k * mVecLimbs]; + long[] PS = new long[kn * mVecLimbs]; + mayoGenericMCalculatePS(params, pk, p1Limbs, p1Limbs + p2Limbs, s, params.getV(), params.getO(), k, PS); + mayoGenericMCalculateSPS(PS, s, mVecLimbs, k, n, SPS); + byte[] zero = new byte[m]; + computeRHS(SPS, zero, y); + + // Compare results + return Arrays.constantTimeAreEqual(m, y, 0, t, 0); + } + + void computeRHS(long[] vPv, byte[] t, byte[] y) + { + final int m = params.getM(); + final int mVecLimbs = params.getMVecLimbs(); + final int k = params.getK(); + final int[] fTail = params.getFTail(); + + final int topPos = ((m - 1) & 15) << 2; + + // Zero out tails of m_vecs if necessary + if ((m & 15) != 0) + { + long mask = (1L << ((m & 15) << 2)) - 1; + final int kSquared = k * k; + + for (int i = 0, index = mVecLimbs - 1; i < kSquared; i++, index += mVecLimbs) + { + vPv[index] &= mask; + } + } + + long[] temp = new long[mVecLimbs]; + byte[] tempBytes = new byte[mVecLimbs << 3]; + int kmVecLimbs = k * mVecLimbs; + + for (int i = k - 1, imVecLimbs = i * mVecLimbs, ikmVecLimbs = imVecLimbs * k; i >= 0; i--, + imVecLimbs -= mVecLimbs, ikmVecLimbs -= kmVecLimbs) + { + for (int j = i, jmVecLimbs = imVecLimbs, jkmVecLimbs = ikmVecLimbs; j < k; j++, + jmVecLimbs += mVecLimbs, jkmVecLimbs += kmVecLimbs) + { + // Multiply by X (shift up 4 bits) + int top = (int)((temp[mVecLimbs - 1] >>> topPos) & 0xF); + temp[mVecLimbs - 1] <<= 4; + + for (int limb = mVecLimbs - 2; limb >= 0; limb--) + { + temp[limb + 1] ^= temp[limb] >>> 60; + temp[limb] <<= 4; + } + Pack.longToLittleEndian(temp, tempBytes, 0); + + // Reduce mod f(X) + for (int jj = 0; jj < 4; jj++) + { + int ft = fTail[jj]; + if (ft == 0) + { + continue; + } + + long product = GF16.mul(top, ft); + if ((jj & 1) == 0) + { + tempBytes[jj >> 1] ^= (byte)(product & 0xF); + } + else + { + tempBytes[jj >> 1] ^= (byte)((product & 0xF) << 4); + } + } + Pack.littleEndianToLong(tempBytes, 0, temp); + + // Extract from vPv and add + int matrixIndex = ikmVecLimbs + jmVecLimbs; + int symmetricIndex = jkmVecLimbs + imVecLimbs; + boolean isDiagonal = (i == j); + + for (int limb = 0; limb < mVecLimbs; limb++) + { + long value = vPv[matrixIndex + limb]; + if (!isDiagonal) + { + value ^= vPv[symmetricIndex + limb]; + } + temp[limb] ^= value; + } + } + } + Pack.longToLittleEndian(temp, tempBytes, 0); + // Compute y + for (int i = 0; i < m; i += 2) + { + int bytePos = i >> 1; + y[i] = (byte)(t[i] ^ (tempBytes[bytePos] & 0xF)); + y[i + 1] = (byte)(t[i + 1] ^ ((tempBytes[bytePos] >>> 4) & 0xF)); + } + } + + private static final int F_TAIL_LEN = 4; + private static final long EVEN_BYTES = 0x00FF00FF00FF00FFL; + private static final long EVEN_2BYTES = 0x0000FFFF0000FFFFL; + + void computeA(long[] Mtmp, byte[] AOut) + { + final int k = params.getK(); + final int o = params.getO(); + final int m = params.getM(); + final int mVecLimbs = params.getMVecLimbs(); + final int ACols = params.getACols(); + final int[] fTailArr = params.getFTail(); + + int bitsToShift = 0; + int wordsToShift = 0; + final int MAYO_M_OVER_8 = (m + 7) >>> 3; + int ok = o * k; + int omVecLimbs = o * mVecLimbs; + final int AWidth = ((ok + 15) >> 4) << 4; + long[] A = new long[(AWidth * MAYO_M_OVER_8) << 4]; + + // Zero out tails of m_vecs if necessary + if ((m & 15) != 0) + { + long mask = 1L << ((m & 15) << 2); + mask -= 1; + for (int i = 0, idx = mVecLimbs - 1; i < ok; i++, idx += mVecLimbs) + { + Mtmp[idx] &= mask; + } + } + + for (int i = 0, io = 0, iomVecLimbs = 0; i < k; i++, io += o, iomVecLimbs += omVecLimbs) + { + for (int j = k - 1, jomVecLimbs = j * omVecLimbs, jo = j * o; j >= i; j--, jomVecLimbs -= omVecLimbs, jo -= o) + { + // Process Mj + for (int c = 0, cmVecLimbs = 0; c < o; c++, cmVecLimbs += mVecLimbs) + { + for (int limb = 0, limbAWidhth = 0; limb < mVecLimbs; limb++, limbAWidhth += AWidth) + { + long value = Mtmp[jomVecLimbs + limb + cmVecLimbs]; + + int aIndex = io + c + wordsToShift + limbAWidhth; + A[aIndex] ^= value << bitsToShift; + + if (bitsToShift > 0) + { + A[aIndex + AWidth] ^= value >>> (64 - bitsToShift); + } + } + } + + if (i != j) + { + // Process Mi + for (int c = 0, cmVecLimbs = 0; c < o; c++, cmVecLimbs += mVecLimbs) + { + for (int limb = 0, limbAWidhth = 0; limb < mVecLimbs; limb++, limbAWidhth += AWidth) + { + long value = Mtmp[iomVecLimbs + limb + cmVecLimbs]; + int aIndex = jo + c + wordsToShift + limbAWidhth; + A[aIndex] ^= value << bitsToShift; + + if (bitsToShift > 0) + { + A[aIndex + AWidth] ^= value >>> (64 - bitsToShift); + } + } + } + } + + bitsToShift += 4; + if (bitsToShift == 64) + { + wordsToShift += AWidth; + bitsToShift = 0; + } + } + } + + // Transpose blocks + for (int c = 0; c < AWidth * ((m + (((k + 1) * k) >> 1) + 15) >>> 4); c += 16) + { + transpose16x16Nibbles(A, c); + } + + // Generate tab array + byte[] tab = new byte[F_TAIL_LEN << 2]; + for (int i = 0, idx = 0; i < F_TAIL_LEN; i++) + { + int ft = fTailArr[i]; + tab[idx++] = (byte)GF16.mul(ft, 1); + tab[idx++] = (byte)GF16.mul(ft, 2); + tab[idx++] = (byte)GF16.mul(ft, 4); + tab[idx++] = (byte)GF16.mul(ft, 8); + } + + // Final processing + for (int c = 0; c < AWidth; c += 16) + { + for (int r = m; r < m + (((k + 1) * k) >>> 1); r++) + { + int pos = (r >>> 4) * AWidth + c + (r & 15); + long t0 = A[pos] & GF16Utils.MASK_LSB; + long t1 = (A[pos] >>> 1) & GF16Utils.MASK_LSB; + long t2 = (A[pos] >>> 2) & GF16Utils.MASK_LSB; + long t3 = (A[pos] >>> 3) & GF16Utils.MASK_LSB; + + for (int t = 0, t4 = 0; t < F_TAIL_LEN; t++, t4 += 4) + { + int targetRow = r + t - m; + int targetPos = (targetRow >> 4) * AWidth + c + (targetRow & 15); + A[targetPos] ^= (t0 * tab[t4]) ^ (t1 * tab[t4 + 1]) + ^ (t2 * tab[t4 + 2]) ^ (t3 * tab[t4 + 3]); + } + } + } + + byte[] Abytes = Pack.longToLittleEndian(A); + // Decode to output + for (int r = 0; r < m; r += 16) + { + for (int c = 0; c < ACols - 1; c += 16) + { + for (int i = 0; i + r < m; i++) + { + GF16.decode(Abytes, (((r * AWidth) >> 4) + c + i) << 3, + AOut, (r + i) * ACols + c, Math.min(16, ACols - 1 - c)); + } + } + } + } + + private static void transpose16x16Nibbles(long[] M, int offset) + { + for (int i = 0; i < 16; i += 2) + { + int idx1 = offset + i; + int idx2 = idx1 + 1; + long t = ((M[idx1] >>> 4) ^ M[idx2]) & 0x0F0F0F0F0F0F0F0FL; + M[idx1] ^= t << 4; + M[idx2] ^= t; + } + + for (int i = 0, base = offset; i < 16; i += 4) + { + long t0 = ((M[base] >>> 8) ^ M[base + 2]) & EVEN_BYTES; + long t1 = ((M[base + 1] >>> 8) ^ M[base + 3]) & EVEN_BYTES; + M[base++] ^= t0 << 8; + M[base++] ^= t1 << 8; + M[base++] ^= t0; + M[base++] ^= t1; + } + + for (int i = 0; i < 4; i++) + { + int base = offset + i; + long t0 = ((M[base] >>> 16) ^ M[base + 4]) & EVEN_2BYTES; + long t1 = ((M[base + 8] >>> 16) ^ M[base + 12]) & EVEN_2BYTES; + M[base] ^= t0 << 16; + M[base + 8] ^= t1 << 16; + M[base + 4] ^= t0; + M[base + 12] ^= t1; + } + + for (int i = 0; i < 8; i++) + { + int base = offset + i; + long t = ((M[base] >>> 32) ^ M[base + 8]) & 0x00000000FFFFFFFFL; + M[base] ^= t << 32; + M[base + 8] ^= t; + } + } + + /** + * Samples a solution for the MAYO signature equation using the provided parameters. + * + * @param A Coefficient matrix + * @param y Target vector + * @param r Randomness vector + * @param x Output solution vector + * @return {@code true} if a valid solution was found, {@code false} otherwise + * @see MAYO Spec Algorithm 2 + */ + boolean sampleSolution(byte[] A, byte[] y, byte[] r, byte[] x) + { + final int k = params.getK(); + final int o = params.getO(); + final int m = params.getM(); + final int aCols = params.getACols(); + int ok = k * o; + // Initialize x with r values + System.arraycopy(r, 0, x, 0, ok); + + // Compute Ar matrix product + byte[] Ar = new byte[m]; + + // Clear last column of A +// for (int i = 0; i < m; i++) +// { +// A[ok + i * (ok + 1)] = 0; +// } + GF16Utils.matMul(A, r, 0, Ar, ok + 1, m); + + // Update last column of A with y - Ar + for (int i = 0, idx = ok; i < m; i++, idx += ok + 1) + { + A[idx] = (byte)(y[i] ^ Ar[i]); + } + + // Perform row echelon form transformation + ef(A, m, aCols); + + // Check matrix rank + boolean fullRank = false; + for (int i = 0, idx = (m - 1) * aCols; i < aCols - 1; i++, idx++) + { + fullRank |= (A[idx] != 0); + } + if (!fullRank) + { + return false; + } + + // Constant-time back substitution + for (int row = m - 1, rowAcols = row * aCols; row >= 0; row--, rowAcols -= aCols) + { + byte finished = 0; + int colUpperBound = Math.min(row + (32 / (m - row)), ok); + + for (int col = row; col <= colUpperBound; col++) + { + byte correctCol = (byte)((-(A[rowAcols + col] & 0xFF)) >> 31); + + // Update x[col] using constant-time mask + byte u = (byte)(correctCol & ~finished & A[rowAcols + aCols - 1]); + x[col] ^= u; + + // Update matrix entries + for (int i = 0, iaCols_col = col, iaCols_aCols1 = aCols - 1; i < row; i += 8, + iaCols_col += aCols << 3, iaCols_aCols1 += aCols << 3) + { + long tmp = 0; + // Pack 8 GF(16) elements into long + for (int j = 0, jaCols = 0; j < 8; j++, jaCols += aCols) + { + tmp ^= (long)(A[iaCols_col + jaCols] & 0xFF) << (j << 3); + } + + // GF(16) multiplication + tmp = GF16Utils.mulFx8(u, tmp); + + // Unpack and update + for (int j = 0, jaCols = 0; j < 8; j++, jaCols += aCols) + { + A[iaCols_aCols1 + jaCols] ^= (byte)((tmp >> (j << 3)) & 0x0F); + } + } + finished |= correctCol; + } + } + return true; + } + + /** + * Converts a matrix A (given as a flat array of GF(16) elements, one per byte) + * into row echelon form (with ones on the first nonzero entries) in constant time. + * + * @param A the input matrix, stored rowwise; each element is in [0,15] + * @param nrows the number of rows + * @param ncols the number of columns (GF(16) elements per row) + * @see MAYO Spec Algorithm 1 + */ + void ef(byte[] A, int nrows, int ncols) + { + // Each 64-bit long can hold 16 nibbles (16 GF(16) elements). + int rowLen = (ncols + 15) >> 4; + + // Allocate temporary arrays. + long[] pivotRow = new long[rowLen]; + long[] pivotRow2 = new long[rowLen]; + // The packed matrix: one contiguous array storing nrows rows, each rowLen longs long. + long[] packedA = new long[nrows * rowLen]; + int len = params.getO() * params.getK() + 16; + byte[] bytes = new byte[len >> 1]; + int len_4 = len >> 4; + + // Pack the matrix rows. + for (int i = 0, incols = 0, irowLen = 0; i < nrows; i++, incols += ncols, irowLen += rowLen) + { + //packRow(A, i, ncols); + // Process each 64-bit word (each holds 16 nibbles). + for (int word = 0; word < rowLen; word++) + { + long wordVal = 0; + for (int nibble = 0; nibble < 16; nibble++) + { + int col = (word << 4) + nibble; + if (col < ncols) + { + wordVal |= ((long)A[incols + col] & 0xF) << (nibble << 2); + } + } + packedA[word + irowLen] = wordVal; + } + } + + int pivotRowIndex = 0; + // Loop over each pivot column (each column corresponds to one GF(16) element) + for (int pivotCol = 0; pivotCol < ncols; pivotCol++) + { + int lowerBound = Math.max(0, pivotCol + nrows - ncols); + int upperBound = Math.min(nrows - 1, pivotCol); + + // Zero out pivot row buffers. + Arrays.clear(pivotRow); + Arrays.clear(pivotRow2); + + // Try to select a pivot row in constant time. + int pivot = 0; + long pivotIsZero = -1L; // all bits set (0xFFFFFFFFFFFFFFFF) + int searchUpper = Math.min(nrows - 1, upperBound + 32); + for (int row = lowerBound, rowRowLen = lowerBound * rowLen; row <= searchUpper; row++, rowRowLen += rowLen) + { + long isPivotRow = ~ctCompare64(row, pivotRowIndex); + //ct64IsGreaterThan(a, b): Returns 0xFFFFFFFFFFFFFFFF if a > b, 0 otherwise. + long belowPivotRow = ((long)pivotRowIndex - (long)row) >> 63; + for (int j = 0; j < rowLen; j++) + { + // The expression below accumulates (in constant time) the candidate pivot row. + pivotRow[j] ^= (isPivotRow | (belowPivotRow & pivotIsZero)) & packedA[rowRowLen + j]; + } + // Extract candidate pivot element from the packed row. + pivot = (int)((pivotRow[pivotCol >>> 4] >>> ((pivotCol & 15) << 2)) & 0xF); + pivotIsZero = ~((-(long)pivot) >> 63); + } + + // Multiply the pivot row by the inverse of the pivot element. + vecMulAddU64(rowLen, pivotRow, GF16.inv((byte)pivot), pivotRow2); + + // Conditionally write the pivot row back into the correct row (if pivot is nonzero). + for (int row = lowerBound, rowRowLen = lowerBound * rowLen; row <= upperBound; row++, rowRowLen += rowLen) + { + long doCopy = ~ctCompare64(row, pivotRowIndex) & ~pivotIsZero; + long doNotCopy = ~doCopy; + for (int col = 0, rowRowLen_col = rowRowLen; col < rowLen; col++, rowRowLen_col++) + { + // Since the masks are disjoint, addition is equivalent to OR. + packedA[rowRowLen_col] = (doNotCopy & packedA[rowRowLen_col]) | (doCopy & pivotRow2[col]); + } + } + + // Eliminate entries below the pivot. + for (int row = lowerBound, rowRowLen = lowerBound * rowLen; row < nrows; row++, rowRowLen += rowLen) + { + int belowPivot = (row > pivotRowIndex) ? -1 : 0; + //int eltToElim = mExtractElementFromPacked(packedA, row, rowLen, pivotCol); + int eltToElim = (int)((packedA[rowRowLen + (pivotCol >>> 4)] >>> ((pivotCol & 15) << 2)) & 0xF); + vecMulAddU64(rowLen, pivotRow2, (byte)(belowPivot & eltToElim), packedA, rowRowLen); + } + + // If pivot is nonzero, increment pivotRowIndex. + if (pivot != 0) + { + pivotRowIndex++; + } + } + + int outIndex = 0; + // At this point, packedA holds the row-echelon form of the original matrix. + // (Depending on your application you might want to unpack it back to A.) + for (int i = 0, irowLen = 0; i < nrows; i++, irowLen += rowLen) + { + Pack.longToLittleEndian(packedA, irowLen, len_4, bytes, 0); + GF16.decode(bytes, 0, A, outIndex, ncols); + outIndex += ncols; + } + } + + /** + * Constant-time comparison: returns 0 if a==b, else returns all 1s (0xFFFFFFFFFFFFFFFF). + */ + private static long ctCompare64(int a, int b) + { + // Compute (-(a XOR b)) >> 63 then XOR with UINT64_BLOCKER. + return (-(long)(a ^ b)) >> 63; + } + + /** + * Multiplies each word of the input vector (in) by a GF(16) scalar (a), + * then XORs the result into the accumulator vector (acc). + *

    + * This version updates the acc array starting at index 0. + * + * @param legs the number of 64-bit words in the vector. + * @param in the input vector. + * @param a the GF(16) scalar (as a byte; only low 4 bits used). + * @param acc the accumulator vector which is updated. + */ + private static void vecMulAddU64(int legs, long[] in, byte a, long[] acc) + { + int tab = mulTable(a & 0xFF); + for (int i = 0; i < legs; i++) + { + long val = ((in[i] & GF16Utils.MASK_LSB) * (tab & 0xFF)) + ^ (((in[i] >>> 1) & GF16Utils.MASK_LSB) * ((tab >>> 8) & 0xF)) + ^ (((in[i] >>> 2) & GF16Utils.MASK_LSB) * ((tab >>> 16) & 0xF)) + ^ (((in[i] >>> 3) & GF16Utils.MASK_LSB) * ((tab >>> 24) & 0xF)); + acc[i] ^= val; + } + } + + /** + * Overloaded version of vecMulAddU64 that writes to acc starting at accOffset. + * + * @param legs the number of 64-bit words. + * @param in the input vector. + * @param a the GF(16) scalar. + * @param acc the accumulator vector. + * @param accOffset the starting index in acc. + */ + private static void vecMulAddU64(int legs, long[] in, byte a, long[] acc, int accOffset) + { + int tab = mulTable(a & 0xFF); + for (int i = 0; i < legs; i++) + { + long val = ((in[i] & GF16Utils.MASK_LSB) * (tab & 0xFF)) + ^ (((in[i] >>> 1) & GF16Utils.MASK_LSB) * ((tab >>> 8) & 0xF)) + ^ (((in[i] >>> 2) & GF16Utils.MASK_LSB) * ((tab >>> 16) & 0xF)) + ^ (((in[i] >>> 3) & GF16Utils.MASK_LSB) * ((tab >>> 24) & 0xF)); + acc[accOffset + i] ^= val; + } + } + + /** + * Computes a multiplication table for nibble-packed vectors. + *

    + * Implements arithmetic for GF(16) elements modulo (x^4 + x + 1). + * + * @param b a GF(16) element (only lower 4 bits are used) + * @return a 32-bit integer representing the multiplication table. + */ + private static int mulTable(int b) + { + int x = b * 0x08040201; + int highHalf = x & 0xf0f0f0f0; + return x ^ (highHalf >>> 4) ^ (highHalf >>> 3); + } + + private static void mayoGenericMCalculatePS(MayoParameters p, long[] P1, int p2, int p3, byte[] S, + int v, int o, int k, long[] PS) + { + int n = o + v; + int mVecLimbs = p.getMVecLimbs(); + long[] accumulator = new long[(mVecLimbs * p.getK() * p.getN() * mVecLimbs) << 4]; + int o_mVecLimbs = o * mVecLimbs; + int pUsed = 0; + for (int row = 0, krow = 0, orow_mVecLimbs = 0; row < v; row++, krow += k, orow_mVecLimbs += o_mVecLimbs) + { + for (int j = row; j < v; j++) + { + for (int col = 0, ncol = 0; col < k; col++, ncol += n) + { + Longs.xorTo(mVecLimbs, P1, pUsed, accumulator, (((krow + col) << 4) + (S[ncol + j] & 0xFF)) * mVecLimbs); + } + pUsed += mVecLimbs; + } + + for (int j = 0, orow_j_mVecLimbs = orow_mVecLimbs; j < o; j++, orow_j_mVecLimbs += mVecLimbs) + { + for (int col = 0, ncol = 0; col < k; col++, ncol += n) + { + Longs.xorTo(mVecLimbs, P1, p2 + orow_j_mVecLimbs, accumulator, (((krow + col) << 4) + (S[ncol + j + v] & 0xFF)) * mVecLimbs); + } + } + } + + pUsed = 0; + for (int row = v, krow = v * k; row < n; row++, krow += k) + { + for (int j = row; j < n; j++) + { + for (int col = 0, ncol = 0; col < k; col++, ncol += n) + { + Longs.xorTo(mVecLimbs, P1, p3 + pUsed, accumulator, (((krow + col) << 4) + (S[ncol + j] & 0xFF)) * mVecLimbs); + } + pUsed += mVecLimbs; + } + } + + mVecMultiplyBins(mVecLimbs, n * k, accumulator, PS); + } + + private static void mayoGenericMCalculateSPS(long[] PS, byte[] S, int mVecLimbs, int k, int n, long[] SPS) + { + int kk = k * k; + final int accumulatorSize = (mVecLimbs * kk) << 4; + final long[] accumulator = new long[accumulatorSize]; + int kmVecLimbs = k * mVecLimbs; + + // Accumulation phase + for (int row = 0, nrow = 0, krowmVecLimbs16 = 0; row < k; row++, nrow += n, krowmVecLimbs16 += kmVecLimbs << 4) + { + for (int j = 0, jkmVecLimbs = 0; j < n; j++, jkmVecLimbs += kmVecLimbs) + { + final int sValmVecLimbs = (S[nrow + j] & 0xFF) * mVecLimbs + krowmVecLimbs16; // Unsigned byte value + for (int col = 0, colmVecLimbs = 0; col < k; col++, colmVecLimbs += mVecLimbs) + { + Longs.xorTo(mVecLimbs, PS, jkmVecLimbs + colmVecLimbs, accumulator, sValmVecLimbs + (colmVecLimbs << 4)); + } + } + } + + // Processing phase + mVecMultiplyBins(mVecLimbs, kk, accumulator, SPS); + } + + private static void mVecMultiplyBins(int mVecLimbs, int len, long[] bins, long[] ps) + { + long a, b, t; + int mVecLimbs2 = mVecLimbs + mVecLimbs, + mVecLimbs3 = mVecLimbs2 + mVecLimbs, + mVecLimbs4 = mVecLimbs3 + mVecLimbs, + mVecLimbs5 = mVecLimbs4 + mVecLimbs, + mVecLimbs6 = mVecLimbs5 + mVecLimbs, + mVecLimbs7 = mVecLimbs6 + mVecLimbs, + mVecLimbs8 = mVecLimbs7 + mVecLimbs, + mVecLimbs9 = mVecLimbs8 + mVecLimbs, + mVecLimbs10 = mVecLimbs9 + mVecLimbs, + mVecLimbs11 = mVecLimbs10 + mVecLimbs, + mVecLimbs12 = mVecLimbs11 + mVecLimbs, + mVecLimbs13 = mVecLimbs12 + mVecLimbs, + mVecLimbs14 = mVecLimbs13 + mVecLimbs, + mVecLimbs15 = mVecLimbs14 + mVecLimbs; + for (int i = 0, imVecLimbs4 = 0; i < len; i++, imVecLimbs4 += (mVecLimbs << 4)) + { + for (int j = 0, off = imVecLimbs4; j < mVecLimbs; j++, off++) + { + b = bins[off + mVecLimbs5]; + t = b & GF16Utils.MASK_LSB; + b = bins[off + mVecLimbs10] ^ ((b & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t); + + a = bins[off + mVecLimbs11]; + t = (a & GF16Utils.MASK_MSB) >>> 3; + a = bins[off + mVecLimbs12] ^ ((a & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t); + + t = b & GF16Utils.MASK_LSB; + b = bins[off + mVecLimbs7] ^ ((b & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t); + + t = (a & GF16Utils.MASK_MSB) >>> 3; + a = bins[off + mVecLimbs6] ^ ((a & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t); + + t = b & GF16Utils.MASK_LSB; + b = bins[off + mVecLimbs14] ^ ((b & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t); + + t = (a & GF16Utils.MASK_MSB) >>> 3; + a = bins[off + mVecLimbs3] ^ ((a & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t); + + t = b & GF16Utils.MASK_LSB; + b = bins[off + mVecLimbs15] ^ ((b & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t); + + t = (a & GF16Utils.MASK_MSB) >>> 3; + a = bins[off + mVecLimbs8] ^ ((a & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t); + + t = b & GF16Utils.MASK_LSB; + b = bins[off + mVecLimbs13] ^ ((b & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t); + + t = (a & GF16Utils.MASK_MSB) >>> 3; + a = bins[off + mVecLimbs4] ^ ((a & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t); + + t = b & GF16Utils.MASK_LSB; + b = bins[off + mVecLimbs9] ^ ((b & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t); + + t = (a & GF16Utils.MASK_MSB) >>> 3; + a = bins[off + mVecLimbs2] ^ ((a & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t); + + t = b & GF16Utils.MASK_LSB; + b = bins[off + mVecLimbs] ^ ((b & GF16Utils.NIBBLE_MASK_LSB) >>> 1) ^ ((t << 3) + t); + + t = (a & GF16Utils.MASK_MSB) >>> 3; + ps[(imVecLimbs4 >> 4) + j] = b ^ ((a & GF16Utils.NIBBLE_MASK_MSB) << 1) ^ ((t << 1) + t); + } + } + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java new file mode 100644 index 0000000000..25f75f03ac --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mayo/Utils.java @@ -0,0 +1,118 @@ +package org.bouncycastle.pqc.crypto.mayo; + +import org.bouncycastle.crypto.BlockCipher; +import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.modes.CTRModeCipher; +import org.bouncycastle.crypto.modes.SICBlockCipher; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Pack; + +class Utils +{ + public static void unpackMVecs(byte[] in, int inOff, long[] out, int outOff, int vecs, int m) + { + int mVecLimbs = (m + 15) >> 4; + int bytesToCopy = m >> 1; // Number of bytes to copy per vector + // Temporary buffer to hold mVecLimbs longs (each long is 8 bytes) + int lastblockLen = 8 - (mVecLimbs << 3) + bytesToCopy; + int i, j; + // Process vectors in reverse order + for (i = vecs - 1, outOff += i * mVecLimbs, inOff += i * bytesToCopy; i >= 0; i--, outOff -= mVecLimbs, inOff -= bytesToCopy) + { + // Convert each 8-byte block in tmp into a long using Pack + for (j = 0; j < mVecLimbs - 1; j++) + { + out[outOff + j] = Pack.littleEndianToLong(in, inOff + (j << 3)); + } + out[outOff + j] = lastblockLen <= 0 ? 0L : Pack.littleEndianToLong_Low(in, inOff + (j << 3), lastblockLen); + } + } + + /** + * Packs m-vectors from an array of 64-bit limbs into a packed byte array. + * + * @param in the input long array containing the m-vectors + * @param out the output byte array that will contain the packed data + * @param vecs the number of vectors + * @param m the m parameter (used to compute m_vec_limbs and copy lengths) + */ + public static void packMVecs(long[] in, byte[] out, int outOff, int vecs, int m) + { + int mVecLimbs = (m + 15) >> 4; + int bytesToCopy = m >> 1; // Number of bytes per vector to write + int lastBlockLen = 8 - (mVecLimbs << 3) + bytesToCopy; + int j; + // Process each vector in order + for (int i = 0, inOff = 0; i < vecs; i++, outOff += bytesToCopy, inOff += mVecLimbs) + { + // Convert each long into 8 bytes using Pack + for (j = 0; j < mVecLimbs - 1; j++) + { + Pack.longToLittleEndian(in[inOff + j], out, outOff + (j << 3)); + } + if (lastBlockLen > 0) + { + Pack.longToLittleEndian_Low(in[inOff + j], out, outOff + (j << 3), lastBlockLen); + } + } + } + + /** + * Expands P1 and P2 using AES_128_CTR as a PRF and then unpacks the resulting bytes + * into an array of 64-bit limbs. + * + * @param p Mayo parameters + * @param P The output long array which will hold the unpacked limbs. + * Its length should be at least ((P1_bytes + P2_bytes) / 8) limbs. + * @param seed_pk The seed (used as the key) for the PRF. + */ + public static void expandP1P2(MayoParameters p, long[] P, byte[] seed_pk) + { + // Compute total number of bytes to generate: P1_bytes + P2_bytes. + int outLen = p.getP1Bytes() + p.getP2Bytes(); + // Temporary byte array to hold the PRF output. + byte[] temp = new byte[outLen]; + + //AES_128_CTR(temp, outLen, seed_pk, p.getPkSeedBytes()); + // Create a 16-byte IV (all zeros) + byte[] iv = new byte[16]; // automatically zero-initialized + + // Set up AES engine in CTR (SIC) mode. + BlockCipher aesEngine = AESEngine.newInstance(); + // SICBlockCipher implements CTR mode for AES. + CTRModeCipher ctrCipher = SICBlockCipher.newInstance(aesEngine); + // Wrap the key with the IV. + ParametersWithIV params = new ParametersWithIV(new KeyParameter(Arrays.copyOf(seed_pk, p.getPkSeedBytes())), iv); + ctrCipher.init(true, params); + + // CTR mode is a stream cipher: encrypting zero bytes produces the keystream. + int blockSize = ctrCipher.getBlockSize(); // typically 16 bytes + byte[] zeroBlock = new byte[blockSize]; // block of zeros + byte[] blockOut = new byte[blockSize]; + + int offset = 0; + // Process full blocks + while (offset + blockSize <= outLen) + { + ctrCipher.processBlock(zeroBlock, 0, blockOut, 0); + System.arraycopy(blockOut, 0, temp, offset, blockSize); + offset += blockSize; + } + // Process any remaining partial block. + if (offset < outLen) + { + ctrCipher.processBlock(zeroBlock, 0, blockOut, 0); + int remaining = outLen - offset; + System.arraycopy(blockOut, 0, temp, offset, remaining); + } + + // The number of vectors is the total limbs divided by mVecLimbs. + int numVectors = (p.getP1Limbs() + p.getP2Limbs()) / p.getMVecLimbs(); + + // Unpack the byte array 'temp' into the long array 'P' + // using our previously defined unpackMVecs method. + unpackMVecs(temp, 0, P, 0, numVectors, p.getM()); + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/HashMLDSASigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/HashMLDSASigner.java index 02736081fe..71ebaa56fc 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/HashMLDSASigner.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/HashMLDSASigner.java @@ -119,8 +119,9 @@ public byte[] generateSignature() throws CryptoException, DataLengthException { random.nextBytes(rnd); } + byte[] mu = engine.generateMu(msgDigest); - return engine.generateSignature(msgDigest, privKey.rho, privKey.k, privKey.t0, privKey.s1, privKey.s2, rnd); + return engine.generateSignature(mu, msgDigest, privKey.rho, privKey.k, privKey.t0, privKey.s1, privKey.s2, rnd); } public boolean verifySignature(byte[] signature) diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/MLDSAEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/MLDSAEngine.java index 7fa39f5da3..bc38163492 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/MLDSAEngine.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/MLDSAEngine.java @@ -8,14 +8,13 @@ class MLDSAEngine { private final SecureRandom random; - - private final SHAKEDigest shake256Digest = new SHAKEDigest(256); + final SHAKEDigest shake256Digest = new SHAKEDigest(256); public final static int DilithiumN = 256; public final static int DilithiumQ = 8380417; public final static int DilithiumQinv = 58728449; // q^(-1) mod 2^32 public final static int DilithiumD = 13; - public final static int DilithiumRootOfUnity = 1753; + //public final static int DilithiumRootOfUnity = 1753; public final static int SeedBytes = 32; public final static int CrhBytes = 64; public final static int RndBytes = 32; @@ -30,8 +29,6 @@ class MLDSAEngine private final int DilithiumPolyW1PackedBytes; private final int DilithiumPolyEtaPackedBytes; - private final int DilithiumMode; - private final int DilithiumK; private final int DilithiumL; private final int DilithiumEta; @@ -43,7 +40,7 @@ class MLDSAEngine private final int DilithiumCTilde; private final int CryptoPublicKeyBytes; - private final int CryptoSecretKeyBytes; +// private final int CryptoSecretKeyBytes; private final int CryptoBytes; private final int PolyUniformGamma1NBlocks; @@ -55,10 +52,10 @@ protected Symmetric GetSymmetric() return symmetric; } - int getDilithiumPolyVecHPackedBytes() - { - return DilithiumPolyVecHPackedBytes; - } +// int getDilithiumPolyVecHPackedBytes() +// { +// return DilithiumPolyVecHPackedBytes; +// } int getDilithiumPolyZPackedBytes() { @@ -75,10 +72,10 @@ int getDilithiumPolyEtaPackedBytes() return DilithiumPolyEtaPackedBytes; } - int getDilithiumMode() - { - return DilithiumMode; - } +// int getDilithiumMode() +// { +// return DilithiumMode; +// } int getDilithiumK() { @@ -130,15 +127,15 @@ int getCryptoPublicKeyBytes() return CryptoPublicKeyBytes; } - int getCryptoSecretKeyBytes() - { - return CryptoSecretKeyBytes; - } - - int getCryptoBytes() - { - return CryptoBytes; - } +// int getCryptoSecretKeyBytes() +// { +// return CryptoSecretKeyBytes; +// } +// +// int getCryptoBytes() +// { +// return CryptoBytes; +// } int getPolyUniformGamma1NBlocks() { @@ -147,7 +144,6 @@ int getPolyUniformGamma1NBlocks() MLDSAEngine(int mode, SecureRandom random) { - this.DilithiumMode = mode; switch (mode) { case 2: @@ -201,14 +197,14 @@ int getPolyUniformGamma1NBlocks() this.random = random; this.DilithiumPolyVecHPackedBytes = this.DilithiumOmega + this.DilithiumK; this.CryptoPublicKeyBytes = SeedBytes + this.DilithiumK * DilithiumPolyT1PackedBytes; - this.CryptoSecretKeyBytes = - ( - 2 * SeedBytes - + TrBytes - + DilithiumL * this.DilithiumPolyEtaPackedBytes - + DilithiumK * this.DilithiumPolyEtaPackedBytes - + DilithiumK * DilithiumPolyT0PackedBytes - ); +// this.CryptoSecretKeyBytes = +// ( +// 2 * SeedBytes +// + TrBytes +// + DilithiumL * this.DilithiumPolyEtaPackedBytes +// + DilithiumK * this.DilithiumPolyEtaPackedBytes +// + DilithiumK * DilithiumPolyT0PackedBytes +// ); this.CryptoBytes = DilithiumCTilde + DilithiumL * this.DilithiumPolyZPackedBytes + this.DilithiumPolyVecHPackedBytes; if (this.DilithiumGamma1 == (1 << 17)) @@ -269,7 +265,7 @@ byte[][] generateKeyPairInternal(byte[] seed) s1hat = new PolyVecL(this); - s1.copyPolyVecL(s1hat); + s1.copyTo(s1hat); s1hat.polyVecNtt(); // System.out.println(s1hat.toString("s1hat")); @@ -323,7 +319,7 @@ byte[] deriveT1(byte[] rho, byte[] key, byte[] tr, byte[] s1Enc, byte[] s2Enc, b s1hat = new PolyVecL(this); - s1.copyPolyVecL(s1hat); + s1.copyTo(s1hat); s1hat.polyVecNtt(); // System.out.println(s1hat.toString("s1hat")); @@ -357,12 +353,7 @@ SHAKEDigest getShake256Digest() void initSign(byte[] tr, boolean isPreHash, byte[] ctx) { shake256Digest.update(tr, 0, TrBytes); - if (ctx != null) - { - shake256Digest.update(isPreHash ? (byte)1 : (byte)0); - shake256Digest.update((byte)ctx.length); - shake256Digest.update(ctx, 0, ctx.length); - } + absorbCtx(isPreHash, ctx); } void initVerify(byte[] rho, byte[] encT1, boolean isPreHash, byte[] ctx) @@ -374,6 +365,11 @@ void initVerify(byte[] rho, byte[] encT1, boolean isPreHash, byte[] ctx) shake256Digest.doFinal(mu, 0, TrBytes); shake256Digest.update(mu, 0, TrBytes); + absorbCtx(isPreHash, ctx); + } + + void absorbCtx(boolean isPreHash, byte[] ctx) + { if (ctx != null) { shake256Digest.update(isPreHash ? (byte)1 : (byte)0); @@ -382,22 +378,25 @@ void initVerify(byte[] rho, byte[] encT1, boolean isPreHash, byte[] ctx) } } - public byte[] signInternal(byte[] msg, int msglen, byte[] rho, byte[] key, byte[] t0Enc, byte[] s1Enc, byte[] s2Enc, byte[] rnd) + byte[] signInternal(byte[] msg, int msglen, byte[] rho, byte[] key, byte[] t0Enc, byte[] s1Enc, byte[] s2Enc, byte[] rnd) { SHAKEDigest shake256 = new SHAKEDigest(shake256Digest); shake256.update(msg, 0, msglen); - return generateSignature(shake256, rho, key, t0Enc, s1Enc, s2Enc, rnd); + return generateSignature(generateMu(shake256), shake256, rho, key, t0Enc, s1Enc, s2Enc, rnd); } - byte[] generateSignature(SHAKEDigest shake256Digest, byte[] rho, byte[] key, byte[] t0Enc, byte[] s1Enc, byte[] s2Enc, byte[] rnd) + byte[] generateMu(SHAKEDigest shake256Digest) { byte[] mu = new byte[CrhBytes]; shake256Digest.doFinal(mu, 0, CrhBytes); + return mu; + } - int n; + byte[] generateSignature(byte[] mu, SHAKEDigest shake256Digest, byte[] rho, byte[] key, byte[] t0Enc, byte[] s1Enc, byte[] s2Enc, byte[] rnd) + { byte[] outSig = new byte[CryptoBytes]; byte[] rhoPrime = new byte[CrhBytes]; short nonce = 0; @@ -428,7 +427,7 @@ byte[] generateSignature(SHAKEDigest shake256Digest, byte[] rho, byte[] key, byt // Sample intermediate vector y.uniformGamma1(rhoPrime, nonce++); - y.copyPolyVecL(z); + y.copyTo(z); z.polyVecNtt(); // Matrix-vector multiplication @@ -440,13 +439,13 @@ byte[] generateSignature(SHAKEDigest shake256Digest, byte[] rho, byte[] key, byt w1.conditionalAddQ(); w1.decompose(w0); - System.arraycopy(w1.packW1(), 0, outSig, 0, DilithiumK * DilithiumPolyW1PackedBytes); + w1.packW1(this, outSig, 0); shake256Digest.update(mu, 0, CrhBytes); shake256Digest.update(outSig, 0, DilithiumK * DilithiumPolyW1PackedBytes); shake256Digest.doFinal(outSig, 0, DilithiumCTilde); - cp.challenge(Arrays.copyOfRange(outSig, 0, DilithiumCTilde)); // uses only the first DilithiumCTilde bytes of sig + cp.challenge(outSig, 0, DilithiumCTilde); cp.polyNtt(); // Compute z, reject if it reveals secret @@ -478,235 +477,108 @@ byte[] generateSignature(SHAKEDigest shake256Digest, byte[] rho, byte[] key, byt w0.addPolyVecK(h); w0.conditionalAddQ(); - n = h.makeHint(w0, w1); + int n = h.makeHint(w0, w1); if (n > DilithiumOmega) { continue; } - return Packing.packSignature(outSig, z, h, this); + Packing.packSignature(outSig, z, h, this); + return outSig; } + // TODO[pqc] Shouldn't this throw an exception here (or in caller)? return null; } - public boolean verifyInternal(byte[] sig, int siglen, SHAKEDigest shake256Digest, byte[] rho, byte[] encT1) + boolean verifyInternalMu(byte[] providedMu) { - if (siglen != CryptoBytes) - { - return false; - } - - // System.out.println("publickey = "); - // Helper.printByteArray(publicKey); - byte[] buf, - mu = new byte[CrhBytes], - c, - c2 = new byte[DilithiumCTilde]; - Poly cp = new Poly(this); - PolyVecMatrix aMatrix = new PolyVecMatrix(this); - PolyVecL z = new PolyVecL(this); - PolyVecK t1 = new PolyVecK(this), w1 = new PolyVecK(this), h = new PolyVecK(this); - - t1 = Packing.unpackPublicKey(t1, encT1, this); - - // System.out.println(t1.toString("t1")); - - // System.out.println("rho = "); - // Helper.printByteArray(rho); - - if (!Packing.unpackSignature(z, h, sig, this)) - { - return false; - } - c = Arrays.copyOfRange(sig, 0, DilithiumCTilde); - - // System.out.println(z.toString("z")); - // System.out.println(h.toString("h")); - - if (z.checkNorm(getDilithiumGamma1() - getDilithiumBeta())) - { - return false; - } + byte[] mu = new byte[CrhBytes]; shake256Digest.doFinal(mu, 0); - // System.out.println("mu after = "); - // Helper.printByteArray(mu); - - // Matrix-vector multiplication; compute Az - c2^dt1 - cp.challenge(Arrays.copyOfRange(c, 0, DilithiumCTilde)); // use only first DilithiumCTilde of c. - // System.out.println("cp = "); - // System.out.println(cp.toString()); - - aMatrix.expandMatrix(rho); - // System.out.println(aMatrix.toString("aMatrix = ")); - - - z.polyVecNtt(); - aMatrix.pointwiseMontgomery(w1, z); - - cp.polyNtt(); - // System.out.println("cp = "); - // System.out.println(cp.toString()); - - t1.shiftLeft(); - t1.polyVecNtt(); - t1.pointwisePolyMontgomery(cp, t1); - - // System.out.println(t1.toString("t1")); - - w1.subtract(t1); - w1.reduce(); - w1.invNttToMont(); - - // System.out.println(w1.toString("w1 before caddq")); - - // Reconstruct w1 - w1.conditionalAddQ(); - // System.out.println(w1.toString("w1 before hint")); - w1.useHint(w1, h); - // System.out.println(w1.toString("w1")); - - buf = w1.packW1(); - - // System.out.println("buf = "); - // Helper.printByteArray(buf); + return Arrays.constantTimeAreEqual(mu, providedMu); + } - // System.out.println("mu = "); - // Helper.printByteArray(mu); + boolean verifyInternalMuSignature(byte[] mu, byte[] sig, int siglen, SHAKEDigest shake256Digest, byte[] rho, byte[] encT1) + { + byte[] buf = new byte[Math.max(CrhBytes + DilithiumK * DilithiumPolyW1PackedBytes, DilithiumCTilde)]; - SHAKEDigest shakeDigest256 = new SHAKEDigest(256); - shakeDigest256.update(mu, 0, CrhBytes); - shakeDigest256.update(buf, 0, DilithiumK * DilithiumPolyW1PackedBytes); - shakeDigest256.doFinal(c2, 0, DilithiumCTilde); + // Mu + System.arraycopy(mu, 0, buf, 0, mu.length); - // System.out.println("c = "); - // Helper.printByteArray(c); + return doVerifyInternal(buf, sig, siglen, shake256Digest, rho, encT1); + } - // System.out.println("c2 = "); - // Helper.printByteArray(c2); + boolean verifyInternal(byte[] sig, int siglen, SHAKEDigest shake256Digest, byte[] rho, byte[] encT1) + { + byte[] buf = new byte[Math.max(CrhBytes + DilithiumK * DilithiumPolyW1PackedBytes, DilithiumCTilde)]; + // Mu + shake256Digest.doFinal(buf, 0); - return Arrays.constantTimeAreEqual(c, c2); + return doVerifyInternal(buf, sig, siglen, shake256Digest, rho, encT1); } - public boolean verifyInternal(byte[] sig, int siglen, byte[] msg, int msglen, byte[] rho, byte[] encT1) + private boolean doVerifyInternal(byte[] buf, byte[] sig, int siglen, SHAKEDigest shake256Digest, byte[] rho, byte[] encT1) { if (siglen != CryptoBytes) { return false; } - // System.out.println("publickey = "); - // Helper.printByteArray(publicKey); - byte[] buf, - mu = new byte[CrhBytes], - c, - c2 = new byte[DilithiumCTilde]; - Poly cp = new Poly(this); - PolyVecMatrix aMatrix = new PolyVecMatrix(this); + PolyVecK h = new PolyVecK(this); PolyVecL z = new PolyVecL(this); - PolyVecK t1 = new PolyVecK(this), w1 = new PolyVecK(this), h = new PolyVecK(this); - - t1 = Packing.unpackPublicKey(t1, encT1, this); - - // System.out.println(t1.toString("t1")); - - // System.out.println("rho = "); - // Helper.printByteArray(rho); if (!Packing.unpackSignature(z, h, sig, this)) { return false; } - c = Arrays.copyOfRange(sig, 0, DilithiumCTilde); - - // System.out.println(z.toString("z")); - // System.out.println(h.toString("h")); if (z.checkNorm(getDilithiumGamma1() - getDilithiumBeta())) { return false; } - // Compute crh(crh(rho, t1), msg) -// shake256Digest.update(rho, 0, rho.length); -// shake256Digest.update(encT1, 0, encT1.length); -// shake256Digest.doFinal(mu, 0, TrBytes); - // System.out.println("mu before = "); - // Helper.printByteArray(mu); - - //shake256Digest.update(mu, 0, TrBytes); - shake256Digest.update(msg, 0, msglen); - shake256Digest.doFinal(mu, 0); + Poly cp = new Poly(this); + PolyVecMatrix aMatrix = new PolyVecMatrix(this); + PolyVecK t1 = new PolyVecK(this), w1 = new PolyVecK(this); - // System.out.println("mu after = "); - // Helper.printByteArray(mu); + t1 = Packing.unpackPublicKey(t1, encT1, this); // Matrix-vector multiplication; compute Az - c2^dt1 - cp.challenge(Arrays.copyOfRange(c, 0, DilithiumCTilde)); // use only first DilithiumCTilde of c. - // System.out.println("cp = "); - // System.out.println(cp.toString()); + cp.challenge(sig, 0, DilithiumCTilde); aMatrix.expandMatrix(rho); - // System.out.println(aMatrix.toString("aMatrix = ")); - z.polyVecNtt(); aMatrix.pointwiseMontgomery(w1, z); cp.polyNtt(); - // System.out.println("cp = "); - // System.out.println(cp.toString()); t1.shiftLeft(); t1.polyVecNtt(); t1.pointwisePolyMontgomery(cp, t1); - // System.out.println(t1.toString("t1")); - w1.subtract(t1); w1.reduce(); w1.invNttToMont(); - // System.out.println(w1.toString("w1 before caddq")); - - // Reconstruct w1 w1.conditionalAddQ(); - // System.out.println(w1.toString("w1 before hint")); w1.useHint(w1, h); - // System.out.println(w1.toString("w1")); - - buf = w1.packW1(); - // System.out.println("buf = "); - // Helper.printByteArray(buf); + w1.packW1(this, buf, CrhBytes); - // System.out.println("mu = "); - // Helper.printByteArray(mu); + shake256Digest.update(buf, 0, CrhBytes + DilithiumK * DilithiumPolyW1PackedBytes); + shake256Digest.doFinal(buf, 0, DilithiumCTilde); - SHAKEDigest shakeDigest256 = new SHAKEDigest(256); - shakeDigest256.update(mu, 0, CrhBytes); - shakeDigest256.update(buf, 0, DilithiumK * DilithiumPolyW1PackedBytes); - shakeDigest256.doFinal(c2, 0, DilithiumCTilde); - - // System.out.println("c = "); - // Helper.printByteArray(c); - - // System.out.println("c2 = "); - // Helper.printByteArray(c2); - - - return Arrays.constantTimeAreEqual(c, c2); + return Arrays.constantTimeAreEqual(DilithiumCTilde, sig, 0, buf, 0); } - public byte[][] generateKeyPair() + byte[][] generateKeyPair() { byte[] seedBuf = new byte[SeedBytes]; random.nextBytes(seedBuf); return generateKeyPairInternal(seedBuf); - } - } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/MLDSAPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/MLDSAPrivateKeyParameters.java index e9e6562d6c..0a04942bc7 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/MLDSAPrivateKeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/MLDSAPrivateKeyParameters.java @@ -5,6 +5,10 @@ public class MLDSAPrivateKeyParameters extends MLDSAKeyParameters { + public static final int BOTH = 0; + public static final int SEED_ONLY = 1; + public static final int EXPANDED_KEY = 2; + final byte[] rho; final byte[] k; final byte[] tr; @@ -15,6 +19,8 @@ public class MLDSAPrivateKeyParameters private final byte[] t1; private final byte[] seed; + private final int prefFormat; + public MLDSAPrivateKeyParameters(MLDSAParameters params, byte[] encoding) { this(params, encoding, null); @@ -36,6 +42,7 @@ public MLDSAPrivateKeyParameters(MLDSAParameters params, byte[] rho, byte[] K, b this.t0 = Arrays.clone(t0); this.t1 = Arrays.clone(t1); this.seed = Arrays.clone(seed); + this.prefFormat = (seed != null) ? BOTH : EXPANDED_KEY; } public MLDSAPrivateKeyParameters(MLDSAParameters params, byte[] encoding, MLDSAPublicKeyParameters pubKey) @@ -75,17 +82,65 @@ public MLDSAPrivateKeyParameters(MLDSAParameters params, byte[] encoding, MLDSAP this.t0 = Arrays.copyOfRange(encoding, index, index + delta); index += delta; this.t1 = eng.deriveT1(rho, k, tr, s1, s2, t0); + this.seed = null; + } - if (pubKey != null) + if (pubKey != null) + { + if (!Arrays.constantTimeAreEqual(this.t1, pubKey.getT1())) { - if (!Arrays.constantTimeAreEqual(this.t1, pubKey.getT1())) - { - throw new IllegalArgumentException("passed in public key does not match private values"); - } + throw new IllegalArgumentException("passed in public key does not match private values"); } + } - this.seed = null; + this.prefFormat = (seed != null) ? BOTH : EXPANDED_KEY; + } + + private MLDSAPrivateKeyParameters(MLDSAPrivateKeyParameters params, int preferredFormat) + { + super(true, params.getParameters()); + + this.rho = params.rho; + this.k = params.k; + this.tr = params.tr; + this.s1 = params.s1; + this.s2 = params.s2; + this.t0 = params.t0; + this.t1 = params.t1; + this.seed = params.seed; + this.prefFormat = preferredFormat; + } + + public MLDSAPrivateKeyParameters getParametersWithFormat(int format) + { + if (this.prefFormat == format) + { + return this; } + + switch (format) + { + case BOTH: + case SEED_ONLY: + { + if (this.seed == null) + { + throw new IllegalStateException("no seed available"); + } + break; + } + case EXPANDED_KEY: + break; + default: + throw new IllegalArgumentException("unknown format"); + } + + return new MLDSAPrivateKeyParameters(this, format); + } + + public int getPreferredFormat() + { + return prefFormat; } public byte[] getEncoded() @@ -101,6 +156,8 @@ public byte[] getK() /** * @deprecated Use {@link #getEncoded()} instead. */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public byte[] getPrivateKey() { return getEncoded(); diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/MLDSASigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/MLDSASigner.java index 4ceac5c22d..521a9aede2 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/MLDSASigner.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/MLDSASigner.java @@ -14,11 +14,9 @@ public class MLDSASigner implements Signer { private static final byte[] EMPTY_CONTEXT = new byte[0]; - private MLDSAPublicKeyParameters pubKey; private MLDSAPrivateKeyParameters privKey; private SecureRandom random; - private MLDSAEngine engine; private SHAKEDigest msgDigest; @@ -93,6 +91,38 @@ public void update(byte[] in, int off, int len) msgDigest.update(in, off, len); } + public byte[] generateMu() + throws CryptoException, DataLengthException + { + byte[] mu = engine.generateMu(msgDigest); + + reset(); + + return mu; + } + + public byte[] generateMuSignature(byte[] mu) + throws CryptoException, DataLengthException + { + if (mu.length != MLDSAEngine.CrhBytes) + { + throw new DataLengthException("mu value must be " + MLDSAEngine.CrhBytes + " bytes"); + } + byte[] rnd = new byte[MLDSAEngine.RndBytes]; + if (random != null) + { + random.nextBytes(rnd); + } + + msgDigest.reset(); + + byte[] sig = engine.generateSignature(mu, msgDigest, privKey.rho, privKey.k, privKey.t0, privKey.s1, privKey.s2, rnd); + + reset(); + + return sig; + } + public byte[] generateSignature() throws CryptoException, DataLengthException { @@ -102,13 +132,28 @@ public byte[] generateSignature() random.nextBytes(rnd); } - byte[] sig = engine.generateSignature(msgDigest, privKey.rho, privKey.k, privKey.t0, privKey.s1, privKey.s2, rnd); + byte[] mu = engine.generateMu(msgDigest); + byte[] sig = engine.generateSignature(mu, msgDigest, privKey.rho, privKey.k, privKey.t0, privKey.s1, privKey.s2, rnd); reset(); return sig; } + public boolean verifyMu(byte[] mu) + { + if (mu.length != MLDSAEngine.CrhBytes) + { + throw new DataLengthException("mu value must be " + MLDSAEngine.CrhBytes + " bytes"); + } + + boolean isTrue = engine.verifyInternalMu(mu); + + reset(); + + return isTrue; + } + public boolean verifySignature(byte[] signature) { boolean isTrue = engine.verifyInternal(signature, signature.length, msgDigest, pubKey.rho, pubKey.t1); @@ -118,6 +163,22 @@ public boolean verifySignature(byte[] signature) return isTrue; } + public boolean verifyMuSignature(byte[] mu, byte[] signature) + { + if (mu.length != MLDSAEngine.CrhBytes) + { + throw new DataLengthException("mu value must be " + MLDSAEngine.CrhBytes + " bytes"); + } + + msgDigest.reset(); + + boolean isTrue = engine.verifyInternalMuSignature(mu, signature, signature.length, msgDigest, pubKey.rho, pubKey.t1); + + reset(); + + return isTrue; + } + public void reset() { msgDigest = engine.getShake256Digest(); diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/Packing.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/Packing.java index 51ed681bd2..c577fea200 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/Packing.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/Packing.java @@ -4,7 +4,6 @@ class Packing { - static byte[] packPublicKey(PolyVecK t1, MLDSAEngine engine) { byte[] out = new byte[engine.getCryptoPublicKeyBytes() - MLDSAEngine.SeedBytes]; @@ -62,7 +61,6 @@ static byte[][] packSecretKey(byte[] rho, byte[] tr, byte[] key, PolyVecK t0, Po * @param engine * @return Byte matrix where byte[0] = rho, byte[1] = tr, byte[2] = key */ - static void unpackSecretKey(PolyVecK t0, PolyVecL s1, PolyVecK s2, byte[] t0Enc, byte[] s1Enc, byte[] s2Enc, MLDSAEngine engine) { for (int i = 0; i < engine.getDilithiumL(); ++i) @@ -81,40 +79,32 @@ static void unpackSecretKey(PolyVecK t0, PolyVecL s1, PolyVecK s2, byte[] t0Enc, } } - static byte[] packSignature(byte[] c, PolyVecL z, PolyVecK h, MLDSAEngine engine) + static void packSignature(byte[] sig, PolyVecL z, PolyVecK h, MLDSAEngine engine) { - int i, j, k, end = 0; - byte[] outBytes = new byte[engine.getCryptoBytes()]; - - System.arraycopy(c, 0, outBytes, 0, engine.getDilithiumCTilde()); - end += engine.getDilithiumCTilde(); - - for (i = 0; i < engine.getDilithiumL(); ++i) + int end = engine.getDilithiumCTilde(); + for (int i = 0; i < engine.getDilithiumL(); ++i) { - System.arraycopy(z.getVectorIndex(i).zPack(), 0, outBytes, end + i * engine.getDilithiumPolyZPackedBytes(), engine.getDilithiumPolyZPackedBytes()); + z.getVectorIndex(i).zPack(sig, end); + end += engine.getDilithiumPolyZPackedBytes(); } - end += engine.getDilithiumL() * engine.getDilithiumPolyZPackedBytes(); - for (i = 0; i < engine.getDilithiumOmega() + engine.getDilithiumK(); ++i) + for (int i = 0; i < engine.getDilithiumOmega() + engine.getDilithiumK(); ++i) { - outBytes[end + i] = 0; + sig[end + i] = 0; } - k = 0; - for (i = 0; i < engine.getDilithiumK(); ++i) + int k = 0; + for (int i = 0; i < engine.getDilithiumK(); ++i) { - for (j = 0; j < MLDSAEngine.DilithiumN; ++j) + for (int j = 0; j < MLDSAEngine.DilithiumN; ++j) { if (h.getVectorIndex(i).getCoeffIndex(j) != 0) { - outBytes[end + k++] = (byte)j; + sig[end + k++] = (byte)j; } } - outBytes[end + engine.getDilithiumOmega() + i] = (byte)k; + sig[end + engine.getDilithiumOmega() + i] = (byte)k; } - - return outBytes; - } static boolean unpackSignature(PolyVecL z, PolyVecK h, byte[] sig, MLDSAEngine engine) @@ -161,5 +151,4 @@ static boolean unpackSignature(PolyVecL z, PolyVecK h, byte[] sig, MLDSAEngine e } return true; } - } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/Poly.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/Poly.java index 2066d8607e..03ac1604da 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/Poly.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/Poly.java @@ -4,23 +4,27 @@ class Poly { + private final static int DilithiumN = MLDSAEngine.DilithiumN; + private final int polyUniformNBlocks; private int[] coeffs; private final MLDSAEngine engine; - private final int dilithiumN; private final Symmetric symmetric; - public Poly(MLDSAEngine engine) { - this.dilithiumN = MLDSAEngine.DilithiumN; - this.coeffs = new int[dilithiumN]; + this.coeffs = new int[DilithiumN]; this.engine = engine; this.symmetric = engine.GetSymmetric(); this.polyUniformNBlocks = (768 + symmetric.stream128BlockBytes - 1) / symmetric.stream128BlockBytes; } + void copyTo(Poly z) + { + System.arraycopy(coeffs, 0, z.coeffs, 0, DilithiumN); + } + public int getCoeffIndex(int i) { return this.coeffs[i]; @@ -51,11 +55,11 @@ public void uniformBlocks(byte[] seed, short nonce) symmetric.stream128squeezeBlocks(buf, 0, buflen); - ctr = rejectUniform(this, 0, dilithiumN, buf, buflen); + ctr = rejectUniform(this, 0, DilithiumN, buf, buflen); // ctr can be less than N - while (ctr < dilithiumN) + while (ctr < DilithiumN) { off = buflen % 3; for (i = 0; i < off; ++i) @@ -64,7 +68,7 @@ public void uniformBlocks(byte[] seed, short nonce) } symmetric.stream128squeezeBlocks(buf, off, symmetric.stream128BlockBytes); buflen = symmetric.stream128BlockBytes + off; - ctr += rejectUniform(this, ctr, dilithiumN - ctr, buf, buflen); + ctr += rejectUniform(this, ctr, DilithiumN - ctr, buf, buflen); } } @@ -117,12 +121,12 @@ else if (engine.getDilithiumEta() == 4) symmetric.stream256init(seed, nonce); symmetric.stream256squeezeBlocks(buf, 0, buflen); - ctr = rejectEta(this, 0, dilithiumN, buf, buflen, eta); + ctr = rejectEta(this, 0, DilithiumN, buf, buflen, eta); while (ctr < MLDSAEngine.DilithiumN) { symmetric.stream256squeezeBlocks(buf, 0, symmetric.stream256BlockBytes); - ctr += rejectEta(this, ctr, dilithiumN - ctr, buf, symmetric.stream256BlockBytes, eta); + ctr += rejectEta(this, ctr, DilithiumN - ctr, buf, symmetric.stream256BlockBytes, eta); } } @@ -179,7 +183,7 @@ public void polyNtt() public void pointwiseMontgomery(Poly v, Poly w) { int i; - for (i = 0; i < dilithiumN; ++i) + for (i = 0; i < DilithiumN; ++i) { this.setCoeffIndex(i, Reduce.montgomeryReduce((long)((long)v.getCoeffIndex(i) * (long)w.getCoeffIndex(i)))); } @@ -204,7 +208,7 @@ public void pointwiseAccountMontgomery(PolyVecL u, PolyVecL v) public void addPoly(Poly a) { int i; - for (i = 0; i < dilithiumN; i++) + for (i = 0; i < DilithiumN; i++) { this.setCoeffIndex(i, this.getCoeffIndex(i) + a.getCoeffIndex(i)); } @@ -213,7 +217,7 @@ public void addPoly(Poly a) public void reduce() { - for (int i = 0; i < dilithiumN; ++i) + for (int i = 0; i < DilithiumN; ++i) { this.setCoeffIndex(i, Reduce.reduce32(this.getCoeffIndex(i))); } @@ -226,7 +230,7 @@ public void invNttToMont() public void conditionalAddQ() { - for (int i = 0; i < dilithiumN; ++i) + for (int i = 0; i < DilithiumN; ++i) { this.setCoeffIndex(i, Reduce.conditionalAddQ(this.getCoeffIndex(i))); } @@ -234,19 +238,14 @@ public void conditionalAddQ() public void power2Round(Poly a) { - for (int i = 0; i < dilithiumN; ++i) - { - int[] p2r = Rounding.power2Round(this.getCoeffIndex(i)); - this.setCoeffIndex(i, p2r[0]); - a.setCoeffIndex(i, p2r[1]); - } + Rounding.power2RoundAll(this.coeffs, a.coeffs); } public byte[] polyt1Pack() { byte[] out = new byte[MLDSAEngine.DilithiumPolyT1PackedBytes]; - for (int i = 0; i < dilithiumN / 4; ++i) + for (int i = 0; i < DilithiumN / 4; ++i) { out[5 * i + 0] = (byte)(this.coeffs[4 * i + 0] >> 0); out[5 * i + 1] = (byte)((this.coeffs[4 * i + 0] >> 8) | (this.coeffs[4 * i + 1] << 2)); @@ -261,7 +260,7 @@ public void polyt1Unpack(byte[] a) { int i; - for (i = 0; i < dilithiumN / 4; ++i) + for (i = 0; i < DilithiumN / 4; ++i) { this.setCoeffIndex(4 * i + 0, (((a[5 * i + 0] & 0xFF) >> 0) | ((int)(a[5 * i + 1] & 0xFF) << 8)) & 0x3FF); this.setCoeffIndex(4 * i + 1, (((a[5 * i + 1] & 0xFF) >> 2) | ((int)(a[5 * i + 2] & 0xFF) << 6)) & 0x3FF); @@ -277,7 +276,7 @@ public byte[] polyEtaPack(byte[] out, int outOff) if (engine.getDilithiumEta() == 2) { - for (i = 0; i < dilithiumN / 8; ++i) + for (i = 0; i < DilithiumN / 8; ++i) { t[0] = (byte)(engine.getDilithiumEta() - this.getCoeffIndex(8 * i + 0)); t[1] = (byte)(engine.getDilithiumEta() - this.getCoeffIndex(8 * i + 1)); @@ -295,7 +294,7 @@ public byte[] polyEtaPack(byte[] out, int outOff) } else if (engine.getDilithiumEta() == 4) { - for (i = 0; i < dilithiumN / 2; ++i) + for (i = 0; i < DilithiumN / 2; ++i) { t[0] = (byte)(engine.getDilithiumEta() - this.getCoeffIndex(2 * i + 0)); t[1] = (byte)(engine.getDilithiumEta() - this.getCoeffIndex(2 * i + 1)); @@ -315,7 +314,7 @@ public void polyEtaUnpack(byte[] a, int aOff) if (engine.getDilithiumEta() == 2) { - for (i = 0; i < dilithiumN / 8; ++i) + for (i = 0; i < DilithiumN / 8; ++i) { int base = aOff + 3 * i; this.setCoeffIndex(8 * i + 0, (((a[base + 0] & 0xFF) >> 0)) & 7); @@ -339,7 +338,7 @@ public void polyEtaUnpack(byte[] a, int aOff) } else if (engine.getDilithiumEta() == 4) { - for (i = 0; i < dilithiumN / 2; ++i) + for (i = 0; i < DilithiumN / 2; ++i) { this.setCoeffIndex(2 * i + 0, a[aOff + i] & 0x0F); this.setCoeffIndex(2 * i + 1, (a[aOff + i] & 0xFF) >> 4); @@ -354,7 +353,7 @@ public byte[] polyt0Pack(byte[] out, int outOff) int i; int[] t = new int[8]; - for (i = 0; i < dilithiumN / 8; ++i) + for (i = 0; i < DilithiumN / 8; ++i) { t[0] = (1 << (MLDSAEngine.DilithiumD - 1)) - this.getCoeffIndex(8 * i + 0); t[1] = (1 << (MLDSAEngine.DilithiumD - 1)) - this.getCoeffIndex(8 * i + 1); @@ -393,7 +392,7 @@ public byte[] polyt0Pack(byte[] out, int outOff) public void polyt0Unpack(byte[] a, int aOff) { int i; - for (i = 0; i < dilithiumN / 8; ++i) + for (i = 0; i < DilithiumN / 8; ++i) { int base = aOff + 13 * i; this.setCoeffIndex(8 * i + 0, @@ -472,10 +471,10 @@ public void uniformGamma1(byte[] seed, short nonce) private void unpackZ(byte[] a) { - int i; - if (engine.getDilithiumGamma1() == (1 << 17)) + int gamma1 = engine.getDilithiumGamma1(); + if (gamma1 == (1 << 17)) { - for (i = 0; i < dilithiumN / 4; ++i) + for (int i = 0; i < DilithiumN / 4; ++i) { this.setCoeffIndex(4 * i + 0, ( @@ -503,15 +502,15 @@ private void unpackZ(byte[] a) ) & 0x3FFFF); - this.setCoeffIndex(4 * i + 0, engine.getDilithiumGamma1() - this.getCoeffIndex(4 * i + 0)); - this.setCoeffIndex(4 * i + 1, engine.getDilithiumGamma1() - this.getCoeffIndex(4 * i + 1)); - this.setCoeffIndex(4 * i + 2, engine.getDilithiumGamma1() - this.getCoeffIndex(4 * i + 2)); - this.setCoeffIndex(4 * i + 3, engine.getDilithiumGamma1() - this.getCoeffIndex(4 * i + 3)); + this.setCoeffIndex(4 * i + 0, gamma1 - this.getCoeffIndex(4 * i + 0)); + this.setCoeffIndex(4 * i + 1, gamma1 - this.getCoeffIndex(4 * i + 1)); + this.setCoeffIndex(4 * i + 2, gamma1 - this.getCoeffIndex(4 * i + 2)); + this.setCoeffIndex(4 * i + 3, gamma1 - this.getCoeffIndex(4 * i + 3)); } } - else if (engine.getDilithiumGamma1() == (1 << 19)) + else if (gamma1 == (1 << 19)) { - for (i = 0; i < dilithiumN / 2; ++i) + for (int i = 0; i < DilithiumN / 2; ++i) { this.setCoeffIndex(2 * i + 0, ( @@ -526,8 +525,8 @@ else if (engine.getDilithiumGamma1() == (1 << 19)) ((a[5 * i + 4] & 0xFF) << 12) ) & 0xFFFFF); - this.setCoeffIndex(2 * i + 0, engine.getDilithiumGamma1() - this.getCoeffIndex(2 * i + 0)); - this.setCoeffIndex(2 * i + 1, engine.getDilithiumGamma1() - this.getCoeffIndex(2 * i + 1)); + this.setCoeffIndex(2 * i + 0, gamma1 - this.getCoeffIndex(2 * i + 0)); + this.setCoeffIndex(2 * i + 1, gamma1 - this.getCoeffIndex(2 * i + 1)); } } else @@ -538,49 +537,46 @@ else if (engine.getDilithiumGamma1() == (1 << 19)) public void decompose(Poly a) { - int i; - for (i = 0; i < dilithiumN; ++i) + int gamma2 = engine.getDilithiumGamma2(); + for (int i = 0; i < DilithiumN; ++i) { - int[] decomp = Rounding.decompose(this.getCoeffIndex(i), engine.getDilithiumGamma2()); + int[] decomp = Rounding.decompose(this.getCoeffIndex(i), gamma2); this.setCoeffIndex(i, decomp[1]); a.setCoeffIndex(i, decomp[0]); } } - public byte[] w1Pack() + void packW1(byte[] r, int rOff) { - int i; - - byte[] out = new byte[engine.getDilithiumPolyW1PackedBytes()]; +// byte[] out = new byte[engine.getDilithiumPolyW1PackedBytes()]; - if (engine.getDilithiumGamma2() == (MLDSAEngine.DilithiumQ - 1) / 88) + int gamma2 = engine.getDilithiumGamma2(); + if (gamma2 == (MLDSAEngine.DilithiumQ - 1) / 88) { - for (i = 0; i < dilithiumN / 4; ++i) + for (int i = 0; i < DilithiumN / 4; ++i) { - out[3 * i + 0] = (byte)(((byte)this.getCoeffIndex(4 * i + 0)) | (this.getCoeffIndex(4 * i + 1) << 6)); - out[3 * i + 1] = (byte)((byte)(this.getCoeffIndex(4 * i + 1) >> 2) | (this.getCoeffIndex(4 * i + 2) << 4)); - out[3 * i + 2] = (byte)((byte)(this.getCoeffIndex(4 * i + 2) >> 4) | (this.getCoeffIndex(4 * i + 3) << 2)); + r[rOff + 3 * i + 0] = (byte)(((byte)getCoeffIndex(4 * i + 0)) | (getCoeffIndex(4 * i + 1) << 6)); + r[rOff + 3 * i + 1] = (byte)((byte)(getCoeffIndex(4 * i + 1) >> 2) | (getCoeffIndex(4 * i + 2) << 4)); + r[rOff + 3 * i + 2] = (byte)((byte)(getCoeffIndex(4 * i + 2) >> 4) | (getCoeffIndex(4 * i + 3) << 2)); } } else if (engine.getDilithiumGamma2() == (MLDSAEngine.DilithiumQ - 1) / 32) { - for (i = 0; i < dilithiumN / 2; ++i) + for (int i = 0; i < DilithiumN / 2; ++i) { - out[i] = (byte)(this.getCoeffIndex(2 * i + 0) | (this.getCoeffIndex(2 * i + 1) << 4)); + r[rOff + i] = (byte)(getCoeffIndex(2 * i + 0) | (getCoeffIndex(2 * i + 1) << 4)); } } - - return out; } - public void challenge(byte[] seed) + public void challenge(byte[] seed, int seedOff, int seedLen) { int i, b = 0, pos; long signs; byte[] buf = new byte[symmetric.stream256BlockBytes]; SHAKEDigest shake256Digest = new SHAKEDigest(256); - shake256Digest.update(seed, 0, engine.getDilithiumCTilde()); + shake256Digest.update(seed, seedOff, seedLen); shake256Digest.doOutput(buf, 0, symmetric.stream256BlockBytes); signs = (long)0; @@ -591,11 +587,11 @@ public void challenge(byte[] seed) pos = 8; - for (i = 0; i < dilithiumN; ++i) + for (i = 0; i < DilithiumN; ++i) { this.setCoeffIndex(i, 0); } - for (i = dilithiumN - engine.getDilithiumTau(); i < dilithiumN; ++i) + for (i = DilithiumN - engine.getDilithiumTau(); i < DilithiumN; ++i) { do { @@ -623,7 +619,7 @@ public boolean checkNorm(int B) return true; } - for (i = 0; i < dilithiumN; ++i) + for (i = 0; i < DilithiumN; ++i) { t = this.getCoeffIndex(i) >> 31; t = this.getCoeffIndex(i) - (t & 2 * this.getCoeffIndex(i)); @@ -638,7 +634,7 @@ public boolean checkNorm(int B) public void subtract(Poly inpPoly) { - for (int i = 0; i < dilithiumN; ++i) + for (int i = 0; i < DilithiumN; ++i) { this.setCoeffIndex(i, this.getCoeffIndex(i) - inpPoly.getCoeffIndex(i)); } @@ -648,7 +644,7 @@ public int polyMakeHint(Poly a0, Poly a1) { int i, s = 0; - for (i = 0; i < dilithiumN; ++i) + for (i = 0; i < DilithiumN; ++i) { this.setCoeffIndex(i, Rounding.makeHint(a0.getCoeffIndex(i), a1.getCoeffIndex(i), engine)); s += this.getCoeffIndex(i); @@ -658,57 +654,53 @@ public int polyMakeHint(Poly a0, Poly a1) public void polyUseHint(Poly a, Poly h) { - for (int i = 0; i < dilithiumN; ++i) + for (int i = 0; i < DilithiumN; ++i) { this.setCoeffIndex(i, Rounding.useHint(a.getCoeffIndex(i), h.getCoeffIndex(i), engine.getDilithiumGamma2())); } } - public byte[] zPack() + public void zPack(byte[] z, int zOff) { - byte[] outBytes = new byte[engine.getDilithiumPolyZPackedBytes()]; - int i; - int[] t = new int[4]; - if (engine.getDilithiumGamma1() == (1 << 17)) + int gamma1 = engine.getDilithiumGamma1(); + if (gamma1 == (1 << 17)) { - for (i = 0; i < dilithiumN / 4; ++i) + for (int i = 0; i < DilithiumN / 4; ++i) { - t[0] = engine.getDilithiumGamma1() - this.getCoeffIndex(4 * i + 0); - t[1] = engine.getDilithiumGamma1() - this.getCoeffIndex(4 * i + 1); - t[2] = engine.getDilithiumGamma1() - this.getCoeffIndex(4 * i + 2); - t[3] = engine.getDilithiumGamma1() - this.getCoeffIndex(4 * i + 3); - - outBytes[9 * i + 0] = (byte)t[0]; - outBytes[9 * i + 1] = (byte)(t[0] >> 8); - outBytes[9 * i + 2] = (byte)((byte)(t[0] >> 16) | (t[1] << 2)); - outBytes[9 * i + 3] = (byte)(t[1] >> 6); - outBytes[9 * i + 4] = (byte)((byte)(t[1] >> 14) | (t[2] << 4)); - outBytes[9 * i + 5] = (byte)(t[2] >> 4); - outBytes[9 * i + 6] = (byte)((byte)(t[2] >> 12) | (t[3] << 6)); - outBytes[9 * i + 7] = (byte)(t[3] >> 2); - outBytes[9 * i + 8] = (byte)(t[3] >> 10); + int t0 = gamma1 - getCoeffIndex(4 * i + 0); + int t1 = gamma1 - getCoeffIndex(4 * i + 1); + int t2 = gamma1 - getCoeffIndex(4 * i + 2); + int t3 = gamma1 - getCoeffIndex(4 * i + 3); + + z[zOff + 9 * i + 0] = (byte)t0; + z[zOff + 9 * i + 1] = (byte)(t0 >> 8); + z[zOff + 9 * i + 2] = (byte)((byte)(t0 >> 16) | (t1 << 2)); + z[zOff + 9 * i + 3] = (byte)(t1 >> 6); + z[zOff + 9 * i + 4] = (byte)((byte)(t1 >> 14) | (t2 << 4)); + z[zOff + 9 * i + 5] = (byte)(t2 >> 4); + z[zOff + 9 * i + 6] = (byte)((byte)(t2 >> 12) | (t3 << 6)); + z[zOff + 9 * i + 7] = (byte)(t3 >> 2); + z[zOff + 9 * i + 8] = (byte)(t3 >> 10); } } - else if (engine.getDilithiumGamma1() == (1 << 19)) + else if (gamma1 == (1 << 19)) { - for (i = 0; i < dilithiumN / 2; ++i) + for (int i = 0; i < DilithiumN / 2; ++i) { - t[0] = engine.getDilithiumGamma1() - this.getCoeffIndex(2 * i + 0); - t[1] = engine.getDilithiumGamma1() - this.getCoeffIndex(2 * i + 1); - - outBytes[5 * i + 0] = (byte)t[0]; - outBytes[5 * i + 1] = (byte)(t[0] >> 8); - outBytes[5 * i + 2] = (byte)((byte)(t[0] >> 16) | (t[1] << 4)); - outBytes[5 * i + 3] = (byte)(t[1] >> 4); - outBytes[5 * i + 4] = (byte)(t[1] >> 12); - + int t0 = gamma1 - getCoeffIndex(2 * i + 0); + int t1 = gamma1 - getCoeffIndex(2 * i + 1); + + z[zOff + 5 * i + 0] = (byte)t0; + z[zOff + 5 * i + 1] = (byte)(t0 >> 8); + z[zOff + 5 * i + 2] = (byte)((byte)(t0 >> 16) | (t1 << 4)); + z[zOff + 5 * i + 3] = (byte)(t1 >> 4); + z[zOff + 5 * i + 4] = (byte)(t1 >> 12); } } else { throw new RuntimeException("Wrong Dilithium Gamma1!"); } - return outBytes; } void zUnpack(byte[] a) @@ -716,7 +708,7 @@ void zUnpack(byte[] a) int i; if (engine.getDilithiumGamma1() == (1 << 17)) { - for (i = 0; i < dilithiumN / 4; ++i) + for (i = 0; i < DilithiumN / 4; ++i) { this.setCoeffIndex(4 * i + 0, (((int)(a[9 * i + 0] & 0xFF) @@ -750,7 +742,7 @@ void zUnpack(byte[] a) } else if (engine.getDilithiumGamma1() == (1 << 19)) { - for (i = 0; i < dilithiumN / 2; ++i) + for (i = 0; i < DilithiumN / 2; ++i) { this.setCoeffIndex(2 * i + 0, (int)(((((int)(a[5 * i + 0] & 0xFF)) @@ -778,7 +770,7 @@ else if (engine.getDilithiumGamma1() == (1 << 19)) public void shiftLeft() { - for (int i = 0; i < dilithiumN; ++i) + for (int i = 0; i < DilithiumN; ++i) { this.setCoeffIndex(i, this.getCoeffIndex(i) << MLDSAEngine.DilithiumD); } @@ -786,7 +778,7 @@ public void shiftLeft() public String toString() { - StringBuffer out = new StringBuffer(); + StringBuilder out = new StringBuilder(); out.append("["); for (int i = 0; i < coeffs.length; i++) { diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/PolyVecK.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/PolyVecK.java index ec8890056e..ba00307d12 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/PolyVecK.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/PolyVecK.java @@ -2,19 +2,11 @@ class PolyVecK { - Poly[] vec; - private MLDSAEngine engine; - private int mode; - private int polyVecBytes; - private int dilithiumK; - private int dilithiumL; + private final Poly[] vec; - public PolyVecK(MLDSAEngine engine) + PolyVecK(MLDSAEngine engine) { - this.engine = engine; - this.mode = engine.getDilithiumMode(); - this.dilithiumK = engine.getDilithiumK(); - this.dilithiumL = engine.getDilithiumL(); + int dilithiumK = engine.getDilithiumK(); this.vec = new Poly[dilithiumK]; for (int i = 0; i < dilithiumK; i++) @@ -23,36 +15,28 @@ public PolyVecK(MLDSAEngine engine) } } - public PolyVecK() - throws Exception - { - throw new Exception("Requires Parameter"); - } - - public Poly getVectorIndex(int i) + Poly getVectorIndex(int i) { return vec[i]; } - public void setVectorIndex(int i, Poly p) + void setVectorIndex(int i, Poly p) { this.vec[i] = p; } public void uniformEta(byte[] seed, short nonce) { - int i; short n = nonce; - for (i = 0; i < dilithiumK; ++i) + for (int i = 0; i < vec.length; ++i) { - getVectorIndex(i).uniformEta(seed, n++); + vec[i].uniformEta(seed, n++); } - } public void reduce() { - for (int i = 0; i < dilithiumK; ++i) + for (int i = 0; i < vec.length; ++i) { this.getVectorIndex(i).reduce(); } @@ -60,7 +44,7 @@ public void reduce() public void invNttToMont() { - for (int i = 0; i < dilithiumK; ++i) + for (int i = 0; i < vec.length; ++i) { this.getVectorIndex(i).invNttToMont(); } @@ -68,7 +52,7 @@ public void invNttToMont() public void addPolyVecK(PolyVecK b) { - for (int i = 0; i < dilithiumK; ++i) + for (int i = 0; i < vec.length; ++i) { this.getVectorIndex(i).addPoly(b.getVectorIndex(i)); } @@ -76,7 +60,7 @@ public void addPolyVecK(PolyVecK b) public void conditionalAddQ() { - for (int i = 0; i < dilithiumK; ++i) + for (int i = 0; i < vec.length; ++i) { this.getVectorIndex(i).conditionalAddQ(); } @@ -84,7 +68,7 @@ public void conditionalAddQ() public void power2Round(PolyVecK pvk) { - for (int i = 0; i < dilithiumK; ++i) + for (int i = 0; i < vec.length; ++i) { this.getVectorIndex(i).power2Round(pvk.getVectorIndex(i)); } @@ -93,7 +77,7 @@ public void power2Round(PolyVecK pvk) public void polyVecNtt() { int i; - for (i = 0; i < dilithiumK; ++i) + for (i = 0; i < vec.length; ++i) { this.vec[i].polyNtt(); } @@ -101,26 +85,23 @@ public void polyVecNtt() public void decompose(PolyVecK v) { - for (int i = 0; i < dilithiumK; ++i) + for (int i = 0; i < vec.length; ++i) { this.getVectorIndex(i).decompose(v.getVectorIndex(i)); } } - public byte[] packW1() + public void packW1(MLDSAEngine engine, byte[] r, int rOff) { - byte[] out = new byte[dilithiumK * engine.getDilithiumPolyW1PackedBytes()]; - int i; - for (i = 0; i < dilithiumK; ++i) + for (int i = 0; i < vec.length; ++i) { - System.arraycopy(this.getVectorIndex(i).w1Pack(), 0, out, i * engine.getDilithiumPolyW1PackedBytes(), engine.getDilithiumPolyW1PackedBytes()); + getVectorIndex(i).packW1(r, rOff + i * engine.getDilithiumPolyW1PackedBytes()); } - return out; } public void pointwisePolyMontgomery(Poly a, PolyVecK v) { - for (int i = 0; i < dilithiumK; ++i) + for (int i = 0; i < vec.length; ++i) { this.getVectorIndex(i).pointwiseMontgomery(a, v.getVectorIndex(i)); } @@ -128,7 +109,7 @@ public void pointwisePolyMontgomery(Poly a, PolyVecK v) public void subtract(PolyVecK inpVec) { - for (int i = 0; i < dilithiumK; ++i) + for (int i = 0; i < vec.length; ++i) { this.getVectorIndex(i).subtract(inpVec.getVectorIndex(i)); } @@ -136,7 +117,7 @@ public void subtract(PolyVecK inpVec) public boolean checkNorm(int bound) { - for (int i = 0; i < dilithiumK; ++i) + for (int i = 0; i < vec.length; ++i) { if (this.getVectorIndex(i).checkNorm(bound)) { @@ -149,8 +130,8 @@ public boolean checkNorm(int bound) public int makeHint(PolyVecK v0, PolyVecK v1) { - int i, s = 0; - for (i = 0; i < dilithiumK; ++i) + int s = 0; + for (int i = 0; i < vec.length; ++i) { s += this.getVectorIndex(i).polyMakeHint(v0.getVectorIndex(i), v1.getVectorIndex(i)); } @@ -160,7 +141,7 @@ public int makeHint(PolyVecK v0, PolyVecK v1) public void useHint(PolyVecK u, PolyVecK h) { - for (int i = 0; i < dilithiumK; ++i) + for (int i = 0; i < vec.length; ++i) { this.getVectorIndex(i).polyUseHint(u.getVectorIndex(i), h.getVectorIndex(i)); } @@ -168,7 +149,7 @@ public void useHint(PolyVecK u, PolyVecK h) public void shiftLeft() { - for (int i = 0; i < dilithiumK; ++i) + for (int i = 0; i < vec.length; ++i) { this.getVectorIndex(i).shiftLeft(); } @@ -178,10 +159,10 @@ public void shiftLeft() public String toString() { String out = "["; - for (int i = 0; i < dilithiumK; i++) + for (int i = 0; i < vec.length; i++) { out += i + " " + this.getVectorIndex(i).toString(); - if (i == dilithiumK - 1) + if (i == vec.length - 1) { continue; } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/PolyVecL.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/PolyVecL.java index 1bff4cfd37..045f67c99d 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/PolyVecL.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/PolyVecL.java @@ -2,19 +2,11 @@ class PolyVecL { - Poly[] vec; - private MLDSAEngine engine; - private int mode; - private int polyVecBytes; - private int dilithiumL; - private int dilithiumK; - - public PolyVecL(MLDSAEngine engine) + private final Poly[] vec; + + PolyVecL(MLDSAEngine engine) { - this.engine = engine; - this.mode = engine.getDilithiumMode(); - this.dilithiumL = engine.getDilithiumL(); - this.dilithiumK = engine.getDilithiumK(); + int dilithiumL = engine.getDilithiumL(); this.vec = new Poly[dilithiumL]; for (int i = 0; i < dilithiumL; i++) @@ -34,12 +26,11 @@ public Poly getVectorIndex(int i) return vec[i]; } - public void expandMatrix(byte[] rho, int i) + void uniformBlocks(byte[] rho, int t) { - int j; - for (j = 0; j < dilithiumL; j++) + for (int i = 0; i < vec.length; ++i) { - vec[j].uniformBlocks(rho, (short)((i << 8) + j)); + vec[i].uniformBlocks(rho, (short)(t + i)); } } @@ -47,28 +38,24 @@ public void uniformEta(byte[] seed, short nonce) { int i; short n = nonce; - for (i = 0; i < dilithiumL; ++i) + for (i = 0; i < vec.length; ++i) { getVectorIndex(i).uniformEta(seed, n++); } } - public void copyPolyVecL(PolyVecL outPoly) + void copyTo(PolyVecL z) { - for (int i = 0; i < dilithiumL; i++) + for (int i = 0; i < vec.length; i++) { - for (int j = 0; j < MLDSAEngine.DilithiumN; j++) - { - outPoly.getVectorIndex(i).setCoeffIndex(j, this.getVectorIndex(i).getCoeffIndex(j)); - } + vec[i].copyTo(z.vec[i]); } } public void polyVecNtt() { - int i; - for (i = 0; i < dilithiumL; ++i) + for (int i = 0; i < vec.length; ++i) { this.vec[i].polyNtt(); } @@ -76,17 +63,15 @@ public void polyVecNtt() public void uniformGamma1(byte[] seed, short nonce) { - int i; - for (i = 0; i < dilithiumL; ++i) + for (int i = 0; i < vec.length; ++i) { - this.getVectorIndex(i).uniformGamma1(seed, (short)(dilithiumL * nonce + i)); + this.getVectorIndex(i).uniformGamma1(seed, (short)(vec.length * nonce + i)); } - } public void pointwisePolyMontgomery(Poly a, PolyVecL v) { - for (int i = 0; i < dilithiumL; ++i) + for (int i = 0; i < vec.length; ++i) { this.getVectorIndex(i).pointwiseMontgomery(a, v.getVectorIndex(i)); } @@ -94,7 +79,7 @@ public void pointwisePolyMontgomery(Poly a, PolyVecL v) public void invNttToMont() { - for (int i = 0; i < dilithiumL; ++i) + for (int i = 0; i < vec.length; ++i) { this.getVectorIndex(i).invNttToMont(); } @@ -102,7 +87,7 @@ public void invNttToMont() public void addPolyVecL(PolyVecL v) { - for (int i = 0; i < dilithiumL; ++i) + for (int i = 0; i < vec.length; ++i) { this.getVectorIndex(i).addPoly(v.getVectorIndex(i)); } @@ -110,7 +95,7 @@ public void addPolyVecL(PolyVecL v) public void reduce() { - for (int i = 0; i < dilithiumL; ++i) + for (int i = 0; i < vec.length; ++i) { this.getVectorIndex(i).reduce(); } @@ -118,7 +103,7 @@ public void reduce() public boolean checkNorm(int bound) { - for (int i = 0; i < dilithiumL; ++i) + for (int i = 0; i < vec.length; ++i) { if (this.getVectorIndex(i).checkNorm(bound)) { @@ -132,10 +117,10 @@ public boolean checkNorm(int bound) public String toString() { String out = "\n["; - for (int i = 0; i < dilithiumL; i++) + for (int i = 0; i < vec.length; i++) { out += "Inner Matrix " + i + " " + this.getVectorIndex(i).toString(); - if (i == dilithiumL - 1) + if (i == vec.length - 1) { continue; } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/PolyVecMatrix.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/PolyVecMatrix.java index d1d36a58de..562377fa97 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/PolyVecMatrix.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/PolyVecMatrix.java @@ -2,58 +2,48 @@ class PolyVecMatrix { - private final int dilithiumK; - private final int dilithiumL; - - private final PolyVecL[] mat; + private final PolyVecL[] matrix; /** * PolyVecL Matrix of size K * * @param engine source engine for the matrix to be used by. */ - public PolyVecMatrix(MLDSAEngine engine) + PolyVecMatrix(MLDSAEngine engine) { - this.dilithiumK = engine.getDilithiumK(); - this.dilithiumL = engine.getDilithiumL(); - this.mat = new PolyVecL[dilithiumK]; + int K = engine.getDilithiumK(); - for (int i = 0; i < dilithiumK; i++) + this.matrix = new PolyVecL[K]; + for (int i = 0; i < K; i++) { - mat[i] = new PolyVecL(engine); + matrix[i] = new PolyVecL(engine); } } public void pointwiseMontgomery(PolyVecK t, PolyVecL v) { - int i; - for (i = 0; i < dilithiumK; ++i) + for (int i = 0; i < matrix.length; ++i) { - t.getVectorIndex(i).pointwiseAccountMontgomery(mat[i], v); + t.getVectorIndex(i).pointwiseAccountMontgomery(matrix[i], v); } } public void expandMatrix(byte[] rho) { - int i, j; - for (i = 0; i < dilithiumK; ++i) + for (int i = 0; i < matrix.length; ++i) { - for (j = 0; j < dilithiumL; ++j) - { - this.mat[i].getVectorIndex(j).uniformBlocks(rho, (short)((i << 8) + j)); - } + matrix[i].uniformBlocks(rho, i << 8); } } private String addString() { String out = "["; - int i; - for (i = 0; i < dilithiumK; i++) + for (int i = 0; i < matrix.length; i++) { out += "Outer Matrix " + i + " ["; - out += this.mat[i].toString(); - if (i == dilithiumK - 1) + out += matrix[i].toString(); + if (i == matrix.length - 1) { out += "]\n"; continue; diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/Rounding.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/Rounding.java index a7428b9c7c..7622265078 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/Rounding.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mldsa/Rounding.java @@ -2,15 +2,23 @@ class Rounding { - public static int[] power2Round(int a) + static void power2RoundAll(int[] c0, int[] c1) { - int[] out = new int[2]; + int d = MLDSAEngine.DilithiumD, n = MLDSAEngine.DilithiumN; + int u = (1 << (d - 1)) - 1, v = -1 << d; - out[0] = (a + (1 << (MLDSAEngine.DilithiumD - 1)) - 1) >> MLDSAEngine.DilithiumD; - out[1] = a - (out[0] << MLDSAEngine.DilithiumD); - return out; - } + for (int i = 0; i < n; ++i) + { + int a = c0[i]; + + int t = a + u; + int r1 = a - (t & v); + c0[i] = t >> d; + c1[i] = r1; + } + } + public static int[] decompose(int a, int gamma2) { int a1, a0; diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/CBD.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/CBD.java index a7df3c7fc8..d2c2799206 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/CBD.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/CBD.java @@ -1,84 +1,39 @@ package org.bouncycastle.pqc.crypto.mlkem; -final class CBD -{ +import org.bouncycastle.util.Pack; - public static void mlkemCBD(Poly r, byte[] bytes, int eta) +class CBD +{ + static void eta2(Poly r, byte[] bytes) { - long t, d; - int a, b; - - switch (eta) + for (int i = 0; i < MLKEMEngine.N / 8; i++) { - case 3: - for (int i = 0; i < MLKEMEngine.KyberN / 4; i++) - { - t = convertByteTo24BitUnsignedInt(bytes, 3 * i); - d = t & 0x00249249; - d = d + ((t >> 1) & 0x00249249); - d = d + ((t >> 2) & 0x00249249); - for (int j = 0; j < 4; j++) - { - a = (short)((d >> (6 * j + 0)) & 0x7); - b = (short)((d >> (6 * j + 3)) & 0x7); - // System.out.printf("a = %d, b = %d\n", a, b); - r.setCoeffIndex(4 * i + j, (short)(a - b)); - } - } - break; - default: - // Only for Kyber512 where eta = 2 - for (int i = 0; i < MLKEMEngine.KyberN / 8; i++) + int t = Pack.littleEndianToInt(bytes, 4 * i); + int d = t & 0x55555555; + d += (t >>> 1) & 0x55555555; + for (int j = 0; j < 8; j++) { - t = convertByteTo32BitUnsignedInt(bytes, 4 * i); // ? Problem - d = t & 0x55555555; - d = d + ((t >> 1) & 0x55555555); - for (int j = 0; j < 8; j++) - { - a = (short)((d >> (4 * j + 0)) & 0x3); - b = (short)((d >> (4 * j + eta)) & 0x3); - r.setCoeffIndex(8 * i + j, (short)(a - b)); - } + int a = (short)((d >>> (4 * j + 0)) & 0x3); + int b = (short)((d >>> (4 * j + 2)) & 0x3); + r.setCoeffIndex(8 * i + j, (short)(a - b)); } } } - /** - * Converts an Array of Bytes to a 32-bit Unsigned Integer - * Returns a 32-bit unsigned integer as a long - * - * @param x - * @return - */ - private static long convertByteTo32BitUnsignedInt(byte[] x, int offset) + static void eta3(Poly r, byte[] bytes) { - // Convert first byte to an unsigned integer - // byte x & 0xFF allows us to grab the last 8 bits - long r = (long)(x[offset] & 0xFF); - - // Perform the same operation then left bit shift to store the next 8 bits without - // altering the previous bits - r = r | (long)((long)(x[offset + 1] & 0xFF) << 8); - r = r | (long)((long)(x[offset + 2] & 0xFF) << 16); - r = r | (long)((long)(x[offset + 3] & 0xFF) << 24); - return r; - } - - /** - * Converts an Array of Bytes to a 24-bit Unsigned Integer - * Returns a 24-bit unsigned integer as a long from byte x - * - * @param x - * @return - */ - private static long convertByteTo24BitUnsignedInt(byte[] x, int offset) - { - // Refer to convertByteTo32-BitUnsignedInt for explanation - long r = (long)(x[offset] & 0xFF); - r = r | (long)((long)(x[offset + 1] & 0xFF) << 8); - r = r | (long)((long)(x[offset + 2] & 0xFF) << 16); - return r; + for (int i = 0; i < MLKEMEngine.N / 4; i++) + { + int t = Pack.littleEndianToInt24(bytes, 3 * i); + int d = t & 0x00249249; + d += (t >>> 1) & 0x00249249; + d += (t >>> 2) & 0x00249249; + for (int j = 0; j < 4; j++) + { + int a = (short)((d >>> (6 * j + 0)) & 0x7); + int b = (short)((d >>> (6 * j + 3)) & 0x7); + r.setCoeffIndex(4 * i + j, (short)(a - b)); + } + } } - - } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMEngine.java index b41116e7a2..3c6bc5d9d8 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMEngine.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMEngine.java @@ -2,195 +2,144 @@ import java.security.SecureRandom; +import org.bouncycastle.crypto.digests.SHA3Digest; +import org.bouncycastle.crypto.digests.SHAKEDigest; import org.bouncycastle.util.Arrays; class MLKEMEngine { - private SecureRandom random; - private MLKEMIndCpa indCpa; + private final MLKEMIndCpa indCpa; // constant parameters - public final static int KyberN = 256; - public final static int KyberQ = 3329; - public final static int KyberQinv = 62209; + final static int N = 256; + final static int Q = 3329; + final static int Qinv = 62209; - public final static int KyberSymBytes = 32; // Number of bytes for Hashes and Seeds - private final static int KyberSharedSecretBytes = 32; // Number of Bytes for Shared Secret + final static int SymBytes = 32; // Number of bytes for Hashes and Seeds + final static int SharedSecretBytes = 32; // Number of Bytes for Shared Secret - public final static int KyberPolyBytes = 384; + final static int PolyBytes = 384; - private final static int KyberEta2 = 2; + final static int Eta2 = 2; - private final static int KyberIndCpaMsgBytes = KyberSymBytes; + final static int SeedBytes = SymBytes * 2; + private final int K; + private final int PolyVecBytes; + private final int PolyCompressedBytes; + private final int PolyVecCompressedBytes; + private final int Eta1; + private final int IndCpaPublicKeyBytes; + private final int IndCpaSecretKeyBytes; + private final int SecretKeyBytes; + private final int CipherTextBytes; - // parameters for Kyber{k} - private final int KyberK; - private final int KyberPolyVecBytes; - private final int KyberPolyCompressedBytes; - private final int KyberPolyVecCompressedBytes; - private final int KyberEta1; - private final int KyberIndCpaPublicKeyBytes; - private final int KyberIndCpaSecretKeyBytes; - private final int KyberIndCpaBytes; - private final int KyberPublicKeyBytes; - private final int KyberSecretKeyBytes; - private final int KyberCipherTextBytes; - - // Crypto - private final int CryptoBytes; - private final int CryptoSecretKeyBytes; - private final int CryptoPublicKeyBytes; - private final int CryptoCipherTextBytes; - - private final int sessionKeyLength; - private final Symmetric symmetric; - - public Symmetric getSymmetric() - { - return symmetric; - } - public static int getKyberEta2() - { - return KyberEta2; - } - - public static int getKyberIndCpaMsgBytes() + int getCipherTextBytes() { - return KyberIndCpaMsgBytes; + return CipherTextBytes; } - public int getCryptoCipherTextBytes() + int getSecretKeyBytes() { - return CryptoCipherTextBytes; + return SecretKeyBytes; } - public int getCryptoPublicKeyBytes() + int getIndCpaPublicKeyBytes() { - return CryptoPublicKeyBytes; + return IndCpaPublicKeyBytes; } - public int getCryptoSecretKeyBytes() + int getIndCpaSecretKeyBytes() { - return CryptoSecretKeyBytes; + return IndCpaSecretKeyBytes; } - public int getCryptoBytes() + int getPublicKeyBytes() { - return CryptoBytes; + return getIndCpaPublicKeyBytes(); } - public int getKyberCipherTextBytes() + int getPolyCompressedBytes() { - return KyberCipherTextBytes; + return PolyCompressedBytes; } - public int getKyberSecretKeyBytes() + int getK() { - return KyberSecretKeyBytes; + return K; } - public int getKyberIndCpaPublicKeyBytes() + int getPolyVecBytes() { - return KyberIndCpaPublicKeyBytes; + return PolyVecBytes; } - - public int getKyberIndCpaSecretKeyBytes() - { - return KyberIndCpaSecretKeyBytes; - } - - public int getKyberIndCpaBytes() + int getPolyVecCompressedBytes() { - return KyberIndCpaBytes; + return PolyVecCompressedBytes; } - public int getKyberPublicKeyBytes() + int getEta1() { - return KyberPublicKeyBytes; + return Eta1; } - public int getKyberPolyCompressedBytes() + MLKEMEngine(int k) { - return KyberPolyCompressedBytes; - } - - public int getKyberK() - { - return KyberK; - } - - public int getKyberPolyVecBytes() - { - return KyberPolyVecBytes; - } - - public int getKyberPolyVecCompressedBytes() - { - return KyberPolyVecCompressedBytes; - } - - public int getKyberEta1() - { - return KyberEta1; - } - - public MLKEMEngine(int k) - { - this.KyberK = k; + this.K = k; switch (k) { case 2: - KyberEta1 = 3; - KyberPolyCompressedBytes = 128; - KyberPolyVecCompressedBytes = k * 320; - sessionKeyLength = 32; + Eta1 = 3; + PolyCompressedBytes = 128; + PolyVecCompressedBytes = k * 320; break; case 3: - KyberEta1 = 2; - KyberPolyCompressedBytes = 128; - KyberPolyVecCompressedBytes = k * 320; - sessionKeyLength = 32; + Eta1 = 2; + PolyCompressedBytes = 128; + PolyVecCompressedBytes = k * 320; break; case 4: - KyberEta1 = 2; - KyberPolyCompressedBytes = 160; - KyberPolyVecCompressedBytes = k * 352; - sessionKeyLength = 32; + Eta1 = 2; + PolyCompressedBytes = 160; + PolyVecCompressedBytes = k * 352; break; default: - throw new IllegalArgumentException("K: " + k + " is not supported for Crystals Kyber"); + throw new IllegalArgumentException("K: " + k + " is not supported for ML-KEM"); } - this.KyberPolyVecBytes = k * KyberPolyBytes; - this.KyberIndCpaPublicKeyBytes = KyberPolyVecBytes + KyberSymBytes; - this.KyberIndCpaSecretKeyBytes = KyberPolyVecBytes; - this.KyberIndCpaBytes = KyberPolyVecCompressedBytes + KyberPolyCompressedBytes; - this.KyberPublicKeyBytes = KyberIndCpaPublicKeyBytes; - this.KyberSecretKeyBytes = KyberIndCpaSecretKeyBytes + KyberIndCpaPublicKeyBytes + 2 * KyberSymBytes; - this.KyberCipherTextBytes = KyberIndCpaBytes; - - // Define Crypto Params - this.CryptoBytes = KyberSharedSecretBytes; - this.CryptoSecretKeyBytes = KyberSecretKeyBytes; - this.CryptoPublicKeyBytes = KyberPublicKeyBytes; - this.CryptoCipherTextBytes = KyberCipherTextBytes; - - this.symmetric = new Symmetric.ShakeSymmetric(); + this.PolyVecBytes = k * PolyBytes; + this.IndCpaPublicKeyBytes = PolyVecBytes + SymBytes; + this.IndCpaSecretKeyBytes = PolyVecBytes; + this.CipherTextBytes = PolyVecCompressedBytes + PolyCompressedBytes; + this.SecretKeyBytes = IndCpaSecretKeyBytes + IndCpaPublicKeyBytes + 2 * SymBytes; this.indCpa = new MLKEMIndCpa(this); } - public void init(SecureRandom random) + boolean checkModulus(byte[] t) { - this.random = random; + return PolyVec.checkModulus(this, t) < 0; } - public byte[][] generateKemKeyPair() + boolean checkPrivateKey(byte[] encoding) { - byte[] d = new byte[KyberSymBytes]; - byte[] z = new byte[KyberSymBytes]; + int k = getK(), k384 = k * 384, k768 = k * 768; + + if ((k768 + 96) != encoding.length) + { + throw new IllegalArgumentException("'encoding' has invalid length"); + } + + byte[] kH = new byte[SymBytes]; + hash_H(encoding, k384, k384 + 32, kH, 0); + return Arrays.constantTimeAreEqual(SymBytes, kH, 0, encoding, k768 + 32); + } + + public byte[][] generateKemKeyPair(SecureRandom random) + { + byte[] d = new byte[SymBytes]; + byte[] z = new byte[SymBytes]; random.nextBytes(d); random.nextBytes(z); @@ -202,16 +151,16 @@ public byte[][] generateKemKeyPairInternal(byte[] d, byte[] z) { byte[][] indCpaKeyPair = indCpa.generateKeyPair(d); - byte[] s = new byte[KyberIndCpaSecretKeyBytes]; + byte[] s = new byte[IndCpaSecretKeyBytes]; - System.arraycopy(indCpaKeyPair[1], 0, s, 0, KyberIndCpaSecretKeyBytes); + System.arraycopy(indCpaKeyPair[1], 0, s, 0, IndCpaSecretKeyBytes); byte[] hashedPublicKey = new byte[32]; - symmetric.hash_h(hashedPublicKey, indCpaKeyPair[0], 0); + hash_H(indCpaKeyPair[0], 0, indCpaKeyPair[0].length, hashedPublicKey, 0); - byte[] outputPublicKey = new byte[KyberIndCpaPublicKeyBytes]; - System.arraycopy(indCpaKeyPair[0], 0, outputPublicKey, 0, KyberIndCpaPublicKeyBytes); + byte[] outputPublicKey = new byte[IndCpaPublicKeyBytes]; + System.arraycopy(indCpaKeyPair[0], 0, outputPublicKey, 0, IndCpaPublicKeyBytes); return new byte[][] { Arrays.copyOfRange(outputPublicKey, 0, outputPublicKey.length - 32), @@ -223,25 +172,42 @@ public byte[][] generateKemKeyPairInternal(byte[] d, byte[] z) }; } - public byte[][] kemEncryptInternal(byte[] publicKeyInput, byte[] randBytes) + static void hash_G(byte[] input, byte[] output) { - byte[] outputCipherText; + implDigest(new SHA3Digest(512), input, 0, input.length, output, 0); + } - byte[] buf = new byte[2 * KyberSymBytes]; - byte[] kr = new byte[2 * KyberSymBytes]; + private static void hash_H(byte[] inBuf, int inOff, int inLen, byte[] outBuf, int outOff) + { + implDigest(new SHA3Digest(256), inBuf, inOff, inLen, outBuf, outOff); + } - System.arraycopy(randBytes, 0, buf, 0, KyberSymBytes); + private static void implDigest(SHA3Digest digest, byte[] inBuf, int inOff, int inLen, byte[] outBuf, int outOff) + { + digest.update(inBuf, inOff, inLen); + digest.doFinal(outBuf, outOff); + } + + byte[][] kemEncrypt(MLKEMPublicKeyParameters publicKey, byte[] randBytes) + { + byte[] publicKeyInput = publicKey.getEncoded(); + + byte[] buf = new byte[2 * SymBytes]; + byte[] kr = new byte[2 * SymBytes]; + + System.arraycopy(randBytes, 0, buf, 0, SymBytes); // SHA3-256 Public Key - symmetric.hash_h(buf, publicKeyInput, KyberSymBytes); + hash_H(publicKeyInput, 0, publicKeyInput.length, buf, SymBytes); // SHA3-512( SHA3-256(RandBytes) || SHA3-256(PublicKey) ) - symmetric.hash_g(kr, buf); + hash_G(buf, kr); // IndCpa Encryption - outputCipherText = indCpa.encrypt(publicKeyInput, Arrays.copyOfRange(buf, 0, KyberSymBytes), Arrays.copyOfRange(kr, 32, kr.length)); + byte[] outputCipherText = indCpa.encrypt(publicKeyInput, Arrays.copyOfRange(buf, 0, SymBytes), + Arrays.copyOfRange(kr, 32, kr.length)); - byte[] outputSharedSecret = new byte[sessionKeyLength]; + byte[] outputSharedSecret = new byte[SharedSecretBytes]; System.arraycopy(kr, 0, outputSharedSecret, 0, outputSharedSecret.length); @@ -251,76 +217,59 @@ public byte[][] kemEncryptInternal(byte[] publicKeyInput, byte[] randBytes) return outBuf; } - public byte[] kemDecryptInternal(byte[] secretKey, byte[] cipherText) + byte[] kemDecrypt(MLKEMPrivateKeyParameters privateKey, byte[] cipherText) { - byte[] buf = new byte[2 * KyberSymBytes], - kr = new byte[2 * KyberSymBytes]; - - byte[] publicKey = Arrays.copyOfRange(secretKey, KyberIndCpaSecretKeyBytes, secretKey.length); + byte[] secretKey = privateKey.getEncoded(); - System.arraycopy(indCpa.decrypt(secretKey, cipherText), 0, buf, 0, KyberSymBytes); + byte[] buf = new byte[2 * SymBytes]; + indCpa.decrypt(secretKey, cipherText, buf); + System.arraycopy(secretKey, SecretKeyBytes - 2 * SymBytes, buf, SymBytes, SymBytes); - System.arraycopy(secretKey, KyberSecretKeyBytes - 2 * KyberSymBytes, buf, KyberSymBytes, KyberSymBytes); + byte[] kr = new byte[2 * SymBytes]; + hash_G(buf, kr); - symmetric.hash_g(kr, buf); + byte[] publicKey = Arrays.copyOfRange(secretKey, IndCpaSecretKeyBytes, secretKey.length); - byte[] implicit_rejection = new byte[KyberSymBytes + KyberCipherTextBytes]; + byte[] cmp = indCpa.encrypt(publicKey, Arrays.copyOfRange(buf, 0, SymBytes), + Arrays.copyOfRange(kr, SymBytes, kr.length)); - System.arraycopy(secretKey, KyberSecretKeyBytes - KyberSymBytes, implicit_rejection, 0, KyberSymBytes); + int fail = constantTimeZeroOnEqual(cipherText, cmp); - System.arraycopy(cipherText, 0, implicit_rejection, KyberSymBytes, KyberCipherTextBytes); - - symmetric.kdf(implicit_rejection, implicit_rejection ); // J(z||c) - - byte[] cmp = indCpa.encrypt(publicKey, Arrays.copyOfRange(buf, 0, KyberSymBytes), Arrays.copyOfRange(kr, KyberSymBytes, kr.length)); + // if ciphertexts do not match, “implicitly reject” + { + byte[] implicit_rejection = new byte[SharedSecretBytes]; - boolean fail = !(Arrays.constantTimeAreEqual(cipherText, cmp)); + // J(z||c) + SHAKEDigest xof = new SHAKEDigest(256); + xof.update(secretKey, SecretKeyBytes - SymBytes, SymBytes); + xof.update(cipherText, 0, CipherTextBytes); + xof.doFinal(implicit_rejection, 0, SharedSecretBytes); - cmov(kr, implicit_rejection, KyberSymBytes, fail); + cmov(kr, implicit_rejection, SharedSecretBytes, fail); + } - return Arrays.copyOfRange(kr, 0, sessionKeyLength); + return Arrays.copyOfRange(kr, 0, SharedSecretBytes); } - public byte[][] kemEncrypt(byte[] publicKeyInput, byte[] randBytes) + private void cmov(byte[] r, byte[] x, int xlen, int fail) { - //TODO: do input validation elsewhere? - // Input validation (6.2 ML-KEM Encaps) - // Type Check - if (publicKeyInput.length != KyberIndCpaPublicKeyBytes) - { - throw new IllegalArgumentException("Input validation Error: Type check failed for ml-kem encapsulation"); - } - // Modulus Check - PolyVec polyVec = new PolyVec(this); - byte[] seed = indCpa.unpackPublicKey(polyVec, publicKeyInput); - byte[] ek = indCpa.packPublicKey(polyVec, seed); - if (!Arrays.areEqual(ek, publicKeyInput)) + int mask = (0 - fail) >> 24; + + for (int i = 0; i != xlen; i++) { - throw new IllegalArgumentException("Input validation: Modulus check failed for ml-kem encapsulation"); + r[i] = (byte)((x[i] & mask) | (r[i] & ~mask)); } - - return kemEncryptInternal(publicKeyInput, randBytes); - } - public byte[] kemDecrypt(byte[] secretKey, byte[] cipherText) - { - //TODO: do input validation - return kemDecryptInternal(secretKey, cipherText); } - private void cmov(byte[] r, byte[] x, int xlen, boolean b) + private int constantTimeZeroOnEqual(byte[] input, byte[] expected) { - if (b) - { - System.arraycopy(x, 0, r, 0, xlen); - } - else + int result = expected.length ^ input.length; + + for (int i = 0; i != expected.length; i++) { - System.arraycopy(r, 0, r, 0, xlen); + result |= input[i] ^ expected[i]; } - } - public void getRandomBytes(byte[] buf) - { - this.random.nextBytes(buf); + return result & 0xff; } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMExtractor.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMExtractor.java index 6f19f835e6..f7eaa18880 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMExtractor.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMExtractor.java @@ -21,11 +21,15 @@ public MLKEMExtractor(MLKEMPrivateKeyParameters privateKey) public byte[] extractSecret(byte[] encapsulation) { - return engine.kemDecrypt(privateKey.getEncoded(), encapsulation); + if (encapsulation.length != this.getEncapsulationLength()) + { + throw new IllegalArgumentException("encapsulation wrong length"); + } + return engine.kemDecrypt(privateKey, encapsulation); } public int getEncapsulationLength() { - return engine.getCryptoCipherTextBytes(); + return engine.getCipherTextBytes(); } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMGenerator.java index 61c693724d..49264e3bda 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMGenerator.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMGenerator.java @@ -2,6 +2,7 @@ import java.security.SecureRandom; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.EncapsulatedSecretGenerator; import org.bouncycastle.crypto.SecretWithEncapsulation; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; @@ -10,33 +11,27 @@ public class MLKEMGenerator implements EncapsulatedSecretGenerator { - // the source of randomness - private final SecureRandom sr; + private final SecureRandom random; public MLKEMGenerator(SecureRandom random) { - this.sr = random; + this.random = CryptoServicesRegistrar.getSecureRandom(random); } public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recipientKey) { - MLKEMPublicKeyParameters key = (MLKEMPublicKeyParameters)recipientKey; - MLKEMEngine engine = key.getParameters().getEngine(); - engine.init(sr); - byte[] randBytes = new byte[32]; - engine.getRandomBytes(randBytes); + random.nextBytes(randBytes); - byte[][] kemEncrypt = engine.kemEncrypt(key.getEncoded(), randBytes); - return new SecretWithEncapsulationImpl(kemEncrypt[0], kemEncrypt[1]); + return internalGenerateEncapsulated(recipientKey, randBytes); } + public SecretWithEncapsulation internalGenerateEncapsulated(AsymmetricKeyParameter recipientKey, byte[] randBytes) { MLKEMPublicKeyParameters key = (MLKEMPublicKeyParameters)recipientKey; MLKEMEngine engine = key.getParameters().getEngine(); - engine.init(sr); - byte[][] kemEncrypt = engine.kemEncryptInternal(key.getEncoded(), randBytes); + byte[][] kemEncrypt = engine.kemEncrypt(key, randBytes); return new SecretWithEncapsulationImpl(kemEncrypt[0], kemEncrypt[1]); } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMIndCpa.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMIndCpa.java index c5d7527c33..e0a9b06960 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMIndCpa.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMIndCpa.java @@ -1,42 +1,22 @@ package org.bouncycastle.pqc.crypto.mlkem; +import org.bouncycastle.crypto.digests.SHAKEDigest; import org.bouncycastle.util.Arrays; class MLKEMIndCpa { - private MLKEMEngine engine; - private int kyberK; - private int indCpaPublicKeyBytes; - private int polyVecBytes; - private int indCpaBytes; - private int polyVecCompressedBytes; - private int polyCompressedBytes; + private static final int SHAKE128_RATE = 168; - private Symmetric symmetric; + private static final int NUM_MATRIX_BLOCKS = + (((12 * MLKEMEngine.N / 8) << 12) / MLKEMEngine.Q + SHAKE128_RATE) / SHAKE128_RATE; - public MLKEMIndCpa(MLKEMEngine engine) + private final MLKEMEngine engine; + + MLKEMIndCpa(MLKEMEngine engine) { this.engine = engine; - this.kyberK = engine.getKyberK(); - this.indCpaPublicKeyBytes = engine.getKyberPublicKeyBytes(); - this.polyVecBytes = engine.getKyberPolyVecBytes(); - this.indCpaBytes = engine.getKyberIndCpaBytes(); - this.polyVecCompressedBytes = engine.getKyberPolyVecCompressedBytes(); - this.polyCompressedBytes = engine.getKyberPolyCompressedBytes(); - this.symmetric = engine.getSymmetric(); - - KyberGenerateMatrixNBlocks = - ( - ( - 12 * MLKEMEngine.KyberN - / 8 * (1 << 12) - / MLKEMEngine.KyberQ + symmetric.xofBlockBytes - ) - / symmetric.xofBlockBytes - ); } - /** * Generates IndCpa Key Pair * @@ -44,401 +24,298 @@ public MLKEMIndCpa(MLKEMEngine engine) */ byte[][] generateKeyPair(byte[] d) { - PolyVec secretKey = new PolyVec(engine), - publicKey = new PolyVec(engine), - e = new PolyVec(engine); + int K = engine.getK(); + + PolyVec secretKey = new PolyVec(K), publicKey = new PolyVec(K), e = new PolyVec(K); // (p, sigma) <- G(d || k) byte[] buf = new byte[64]; - symmetric.hash_g(buf, Arrays.append(d, (byte)kyberK)); + MLKEMEngine.hash_G(Arrays.append(d, (byte)K), buf); byte[] publicSeed = new byte[32]; // p in docs byte[] noiseSeed = new byte[32]; // sigma in docs System.arraycopy(buf, 0, publicSeed, 0, 32); System.arraycopy(buf, 32, noiseSeed, 0, 32); - byte count = (byte)0; + PolyVec[] matrixA = new PolyVec[K]; - // Helper.printByteArray(buf); + for (int i = 0; i < K; i++) + { + matrixA[i] = new PolyVec(K); + } + generateMatrixA(matrixA, publicSeed, false); - PolyVec[] aMatrix = new PolyVec[kyberK]; + SHAKEDigest xof = new SHAKEDigest(256); - int i; - for (i = 0; i < kyberK; i++) + byte nonce = 0; + if (engine.getEta1() == 2) { - aMatrix[i] = new PolyVec(engine); - } + for (int i = 0; i < K; i++) + { + secretKey.getVectorIndex(i).getNoiseEta2(xof, noiseSeed, nonce++); + } - generateMatrix(aMatrix, publicSeed, false); - - // System.out.println("aMatrix = "); - // for(i = 0; i < kyberK; i++) { - // System.out.print("["); - // for (int j = 0; j < kyberK; j++) { - // System.out.print("["); - // for (int k = 0; k < KyberEngine.KyberN; k++) { - // System.out.printf("%d ,", aMatrix[i].getVectorIndex(j).getCoeffIndex(k)); - // } - // System.out.print("], \n"); - // } - // System.out.print("]\n"); - // } - - for (i = 0; i < kyberK; i++) - { - secretKey.getVectorIndex(i).getEta1Noise(noiseSeed, count); - - // System.out.print("SecretKeyPolyVec["+i+"] = ["); - // for (int j =0; j < KyberEngine.KyberN; j++) { - // System.out.print(secretKey.getVectorIndex(i).getCoeffIndex(j) + ", "); - // } - // System.out.println("]"); - count = (byte)(count + (byte)1); + for (int i = 0; i < K; i++) + { + e.getVectorIndex(i).getNoiseEta2(xof, noiseSeed, nonce++); + } } - - for (i = 0; i < kyberK; i++) + else { - e.getVectorIndex(i).getEta1Noise(noiseSeed, count); - count = (byte)(count + (byte)1); + for (int i = 0; i < K; i++) + { + secretKey.getVectorIndex(i).getNoiseEta3(xof, noiseSeed, nonce++); + } + + for (int i = 0; i < K; i++) + { + e.getVectorIndex(i).getNoiseEta3(xof, noiseSeed, nonce++); + } } secretKey.polyVecNtt(); - // System.out.print("SecretKeyPolyVec = ["); - // for (i = 0; i < kyberK; i++) { - // System.out.print("["); - // for (int j =0; j < KyberEngine.KyberN; j++) { - // System.out.print(secretKey.getVectorIndex(i).getCoeffIndex(j) + ", "); - // } - // System.out.println("],"); - // } - // System.out.println("]"); - - e.polyVecNtt(); - for (i = 0; i < kyberK; i++) + for (int i = 0; i < K; i++) { - PolyVec.pointwiseAccountMontgomery(publicKey.getVectorIndex(i), aMatrix[i], secretKey, engine); + PolyVec.pointwiseAccountMontgomery(publicKey.getVectorIndex(i), matrixA[i], secretKey, engine); publicKey.getVectorIndex(i).convertToMont(); } - // System.out.print("PublicKey PolyVec = ["); - // Helper.printPolyVec(publicKey, kyberK); - publicKey.addPoly(e); publicKey.reducePoly(); - return new byte[][]{packPublicKey(publicKey, publicSeed), packSecretKey(secretKey)}; + return new byte[][]{ packPublicKey(publicKey, publicSeed), packSecretKey(secretKey) }; } - public byte[] encrypt(byte[] publicKeyInput, byte[] msg, byte[] coins) + void decrypt(byte[] secretKey, byte[] cipherText, byte[] m) { - int i; - byte[] seed; - byte nonce = (byte)0; - PolyVec sp = new PolyVec(engine), - publicKeyPolyVec = new PolyVec(engine), - errorPolyVector = new PolyVec(engine), - bp = new PolyVec(engine); - PolyVec[] aMatrixTranspose = new PolyVec[engine.getKyberK()]; - Poly errorPoly = new Poly(engine), - v = new Poly(engine), - k = new Poly(engine); + int K = engine.getK(); + + PolyVec bp = new PolyVec(K), skpv = new PolyVec(K); + Poly v = new Poly(), mp = new Poly(); + + unpackCipherText(bp, v, cipherText, 0); + unpackSecretKey(skpv, secretKey); + + bp.polyVecNtt(); + PolyVec.pointwiseAccountMontgomery(mp, skpv, bp, engine); - // System.out.print("publickeyinput = "); - // Helper.printByteArray(publicKeyInput); - // System.out.println(); + mp.polyInverseNttToMont(); + mp.subtract(v); + mp.reduce(); + mp.toMsg(m); + } - seed = unpackPublicKey(publicKeyPolyVec, publicKeyInput); + byte[] encrypt(byte[] publicKeyInput, byte[] msg, byte[] coins) + { + int K = engine.getK(); - // System.out.print("publickeyPolyVec = ["); - // for (i = 0; i < kyberK; i++) { - // Helper.printShortArray(publicKeyPolyVec.getVectorIndex(i).getCoeffs()); - // System.out.print("], \n"); - // } - // System.out.println("]"); + byte nonce = (byte)0; + PolyVec sp = new PolyVec(K), pkpv = new PolyVec(K), ep = new PolyVec(K), bp = new PolyVec(K); + PolyVec[] matrixATransposed = new PolyVec[engine.getK()]; + Poly errorPoly = new Poly(), v = new Poly(), k = new Poly(); - // System.out.print("seed = "); - // Helper.printByteArray(seed); - // System.out.println(); + byte[] seed = unpackPublicKey(pkpv, publicKeyInput); k.fromMsg(msg); - for (i = 0; i < kyberK; i++) + for (int i = 0; i < K; i++) { - aMatrixTranspose[i] = new PolyVec(engine); + matrixATransposed[i] = new PolyVec(K); } - generateMatrix(aMatrixTranspose, seed, true); + generateMatrixA(matrixATransposed, seed, true); - // System.out.print("matrix transposed = "); - // for (i = 0; i < kyberK; i++) { - // System.out.print("["); - // for(int j = 0; j < kyberK; j++) { - // System.out.print("["); - // for (int l = 0; l < 256; l++) { - // System.out.printf("%d ,", aMatrixTranspose[i].getVectorIndex(j).getCoeffIndex(l)); - // } - // System.out.print("] ,\n"); - // } - // System.out.println("] ,"); - // } + SHAKEDigest xof = new SHAKEDigest(256); - - for (i = 0; i < kyberK; i++) + if (engine.getEta1() == 2) { - sp.getVectorIndex(i).getEta1Noise(coins, nonce); - nonce = (byte)(nonce + (byte)1); + for (int i = 0; i < K; i++) + { + sp.getVectorIndex(i).getNoiseEta2(xof, coins, nonce++); + } + } + else + { + for (int i = 0; i < K; i++) + { + sp.getVectorIndex(i).getNoiseEta3(xof, coins, nonce++); + } } - - for (i = 0; i < kyberK; i++) + for (int i = 0; i < K; i++) { - errorPolyVector.getVectorIndex(i).getEta2Noise(coins, nonce); - nonce = (byte)(nonce + (byte)1); + ep.getVectorIndex(i).getNoiseEta2(xof, coins, nonce++); } - errorPoly.getEta2Noise(coins, nonce); + errorPoly.getNoiseEta2(xof, coins, nonce); sp.polyVecNtt(); - // System.out.print("sp = ["); - // for (i = 0; i < kyberK; i++) { - // Helper.printShortArray(sp.getVectorIndex(i).getCoeffs()); - // System.out.print("], \n"); - // } - // System.out.println("]"); - - - // System.out.print("sp = ["); - // for (i = 0; i < kyberK; i++) { - // Helper.printShortArray(sp.getVectorIndex(i).getCoeffs()); - // System.out.print("], \n"); - // } - // System.out.println("]"); - - for (i = 0; i < kyberK; i++) + for (int i = 0; i < K; i++) { - - PolyVec.pointwiseAccountMontgomery(bp.getVectorIndex(i), aMatrixTranspose[i], sp, engine); + PolyVec.pointwiseAccountMontgomery(bp.getVectorIndex(i), matrixATransposed[i], sp, engine); } - // System.out.print("bp = ["); - // for (i = 0; i < kyberK; i++) { - // Helper.printShortArray(bp.getVectorIndex(i).getCoeffs()); - // System.out.print("], \n"); - // } - // System.out.println("]"); - PolyVec.pointwiseAccountMontgomery(v, publicKeyPolyVec, sp, engine); + PolyVec.pointwiseAccountMontgomery(v, pkpv, sp, engine); bp.polyVecInverseNttToMont(); v.polyInverseNttToMont(); - bp.addPoly(errorPolyVector); + bp.addPoly(ep); - - v.addCoeffs(errorPoly); - v.addCoeffs(k); + v.add(errorPoly); + v.add(k); bp.reducePoly(); v.reduce(); - // System.out.print("bp = ["); - // for (i = 0; i < kyberK; i++) { - // Helper.printShortArray(bp.getVectorIndex(i).getCoeffs()); - // System.out.print("], \n"); - // } - // System.out.println("]"); - - - // System.out.print("v = "); - // Helper.printShortArray(v.getCoeffs()); - // System.out.println(); - - - byte[] outputCipherText = packCipherText(bp, v); - - return outputCipherText; + return packCipherText(bp, v); } private byte[] packCipherText(PolyVec b, Poly v) { - byte[] outBuf = new byte[indCpaBytes]; - System.arraycopy(b.compressPolyVec(), 0, outBuf, 0, polyVecCompressedBytes); - System.arraycopy(v.compressPoly(), 0, outBuf, polyVecCompressedBytes, polyCompressedBytes); - // System.out.print("outBuf = ["); - // Helper.printByteArray(outBuf); + int polyVecCompressedBytes = engine.getPolyVecCompressedBytes(); + + byte[] outBuf = new byte[engine.getCipherTextBytes()]; + b.compressPolyVec(outBuf, 0); + + byte[] compressedPoly; + if (engine.getK() == 4) + { + compressedPoly = v.compressPoly160(); + } + else + { + compressedPoly = v.compressPoly128(); + } + + System.arraycopy(compressedPoly, 0, outBuf, polyVecCompressedBytes, engine.getPolyCompressedBytes()); return outBuf; } - private void unpackCipherText(PolyVec b, Poly v, byte[] cipherText) + private void unpackCipherText(PolyVec b, Poly v, byte[] cBuf, int cOff) { - byte[] compressedPolyVecCipherText = Arrays.copyOfRange(cipherText, 0, engine.getKyberPolyVecCompressedBytes()); - b.decompressPolyVec(compressedPolyVecCipherText); + b.decompressPolyVec(cBuf, cOff); + cOff += engine.getPolyVecCompressedBytes(); - byte[] compressedPolyCipherText = Arrays.copyOfRange(cipherText, engine.getKyberPolyVecCompressedBytes(), cipherText.length); - v.decompressPoly(compressedPolyCipherText); + if (engine.getK() == 4) + { + v.decompressPoly160(cBuf, cOff); + } + else + { + v.decompressPoly128(cBuf, cOff); + } } - public byte[] packPublicKey(PolyVec publicKeyPolyVec, byte[] seed) + byte[] packPublicKey(PolyVec publicKeyPolyVec, byte[] seed) { + int indCpaPublicKeyBytes = engine.getPublicKeyBytes(); + int polyVecBytes = engine.getPolyVecBytes(); + byte[] buf = new byte[indCpaPublicKeyBytes]; - System.arraycopy(publicKeyPolyVec.toBytes(), 0, buf, 0, polyVecBytes); - System.arraycopy(seed, 0, buf, polyVecBytes, MLKEMEngine.KyberSymBytes); + publicKeyPolyVec.toBytes(buf, 0); + System.arraycopy(seed, 0, buf, polyVecBytes, MLKEMEngine.SymBytes); return buf; } - public byte[] unpackPublicKey(PolyVec publicKeyPolyVec, byte[] publicKey) + byte[] unpackPublicKey(PolyVec publicKeyPolyVec, byte[] publicKey) { - byte[] outputSeed = new byte[MLKEMEngine.KyberSymBytes]; + int polyVecBytes = engine.getPolyVecBytes(); + + byte[] outputSeed = new byte[MLKEMEngine.SymBytes]; publicKeyPolyVec.fromBytes(publicKey); - System.arraycopy(publicKey, polyVecBytes, outputSeed, 0, MLKEMEngine.KyberSymBytes); + System.arraycopy(publicKey, polyVecBytes, outputSeed, 0, MLKEMEngine.SymBytes); return outputSeed; } - public byte[] packSecretKey(PolyVec secretKeyPolyVec) + byte[] packSecretKey(PolyVec secretKeyPolyVec) { - return secretKeyPolyVec.toBytes(); + byte[] r = new byte[engine.getPolyVecBytes()]; + secretKeyPolyVec.toBytes(r, 0); + return r; } - public void unpackSecretKey(PolyVec secretKeyPolyVec, byte[] secretKey) + void unpackSecretKey(PolyVec secretKeyPolyVec, byte[] secretKey) { secretKeyPolyVec.fromBytes(secretKey); } - public final int KyberGenerateMatrixNBlocks; - - public void generateMatrix(PolyVec[] aMatrix, byte[] seed, boolean transposed) + void generateMatrixA(PolyVec[] aMatrix, byte[] seed, boolean transpose) { - int i, j, k, ctr, off; - byte[] buf = new byte[KyberGenerateMatrixNBlocks * symmetric.xofBlockBytes + 2]; - for (i = 0; i < kyberK; i++) + int K = engine.getK(); + SHAKEDigest xof = new SHAKEDigest(128); + + byte[] buf = new byte[NUM_MATRIX_BLOCKS * SHAKE128_RATE + 2]; + for (int i = 0; i < K; i++) { - for (j = 0; j < kyberK; j++) + for (int j = 0; j < K; j++) { - if (transposed) + xof.reset(); + + xof.update(seed, 0, seed.length); + + if (transpose) { - symmetric.xofAbsorb(seed, (byte) i, (byte) j); + xof.update((byte)i); + xof.update((byte)j); } else { - symmetric.xofAbsorb(seed, (byte) j, (byte) i); + xof.update((byte)j); + xof.update((byte)i); } - symmetric.xofSqueezeBlocks(buf, 0, symmetric.xofBlockBytes * KyberGenerateMatrixNBlocks); - int buflen = KyberGenerateMatrixNBlocks * symmetric.xofBlockBytes; - ctr = rejectionSampling(aMatrix[i].getVectorIndex(j), 0, MLKEMEngine.KyberN, buf, buflen); + int buflen = NUM_MATRIX_BLOCKS * SHAKE128_RATE; + xof.doOutput(buf, 0, buflen); - while (ctr < MLKEMEngine.KyberN) + int ctr = rejectionSampling(aMatrix[i].getVectorIndex(j), 0, MLKEMEngine.N, buf, buflen); + while (ctr < MLKEMEngine.N) { - off = buflen % 3; - for (k = 0; k < off; k++) + int off = buflen % 3; + for (int k = 0; k < off; k++) { buf[k] = buf[buflen - off + k]; } - symmetric.xofSqueezeBlocks(buf, off, symmetric.xofBlockBytes * 2); - buflen = off + symmetric.xofBlockBytes; + + xof.doOutput(buf, off, SHAKE128_RATE * 2); + + buflen = off + SHAKE128_RATE; // Error in code Section Unsure - ctr += rejectionSampling(aMatrix[i].getVectorIndex(j), ctr, MLKEMEngine.KyberN - ctr, buf, buflen); + ctr += rejectionSampling(aMatrix[i].getVectorIndex(j), ctr, MLKEMEngine.N - ctr, buf, buflen); } } } - } private static int rejectionSampling(Poly outputBuffer, int coeffOff, int len, byte[] inpBuf, int inpBufLen) { - int ctr, pos; - short val0, val1; - ctr = pos = 0; + short Q = (short)MLKEMEngine.Q; + + int ctr = 0, pos = 0; while (ctr < len && pos + 3 <= inpBufLen) { - val0 = (short)(((((short)(inpBuf[pos] & 0xFF)) >> 0) | (((short)(inpBuf[pos + 1] & 0xFF)) << 8)) & 0xFFF); - val1 = (short)(((((short)(inpBuf[pos + 1] & 0xFF)) >> 4) | (((short)(inpBuf[pos + 2] & 0xFF)) << 4)) & 0xFFF); - pos = pos + 3; - if (val0 < (short)MLKEMEngine.KyberQ) + short d1 = (short)(((((short)(inpBuf[pos + 0] & 0xFF)) >> 0) | (((short)(inpBuf[pos + 1] & 0xFF)) << 8)) & 0xFFF); + short d2 = (short)(((((short)(inpBuf[pos + 1] & 0xFF)) >> 4) | (((short)(inpBuf[pos + 2] & 0xFF)) << 4)) & 0xFFF); + pos += 3; + + if (d1 < Q) { - outputBuffer.setCoeffIndex(coeffOff + ctr, (short)val0); + outputBuffer.setCoeffIndex(coeffOff + ctr, (short)d1); ctr++; } - if (ctr < len && val1 < (short)MLKEMEngine.KyberQ) + if (ctr < len && d2 < Q) { - outputBuffer.setCoeffIndex(coeffOff + ctr, (short)val1); + outputBuffer.setCoeffIndex(coeffOff + ctr, (short)d2); ctr++; } } return ctr; - - } - - public byte[] decrypt(byte[] secretKey, byte[] cipherText) - { - byte[] outputMessage = new byte[MLKEMEngine.getKyberIndCpaMsgBytes()]; - - PolyVec bp = new PolyVec(engine), secretKeyPolyVec = new PolyVec(engine); - Poly v = new Poly(engine), mp = new Poly(engine); - - unpackCipherText(bp, v, cipherText); - - // System.out.print("bp = ["); - // for (i = 0; i < kyberK; i++) { - // Helper.printShortArray(bp.getVectorIndex(i).getCoeffs()); - // System.out.print("], \n"); - // } - // System.out.println("]"); - - - // System.out.print("v = "); - // Helper.printShortArray(v.getCoeffs()); - // System.out.println(); - - unpackSecretKey(secretKeyPolyVec, secretKey); - - // System.out.print("decrypt secretkey = ");; - // Helper.printByteArray(secretKey); - - // System.out.print("SecretKeyPolyVec = ["); - // for (i = 0; i < kyberK; i++) { - // System.out.print("["); - // for (int j =0; j < KyberEngine.KyberN; j++) { - // System.out.print(secretKeyPolyVec.getVectorIndex(i).getCoeffIndex(j) + ", "); - // } - // System.out.println("],"); - // } - // System.out.println("]"); - - // System.out.print("bp before ntt = ["); - // for (i = 0; i < kyberK; i++) { - // Helper.printShortArray(bp.getVectorIndex(i).getCoeffs()); - // System.out.print("], \n"); - // } - // System.out.println("]"); - - bp.polyVecNtt(); - - // System.out.print("bp after ntt = ["); - // for (i = 0; i < kyberK; i++) { - // Helper.printShortArray(bp.getVectorIndex(i).getCoeffs()); - // System.out.print("], \n"); - // } - // System.out.println("]"); - - PolyVec.pointwiseAccountMontgomery(mp, secretKeyPolyVec, bp, engine); - - - mp.polyInverseNttToMont(); - - mp.polySubtract(v); - - mp.reduce(); - - outputMessage = mp.toMsg(); - - return outputMessage; } - } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMKeyPairGenerator.java index 22c1d686db..ffad2c37b2 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMKeyPairGenerator.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMKeyPairGenerator.java @@ -25,9 +25,7 @@ private AsymmetricCipherKeyPair genKeyPair() { MLKEMEngine engine = mlkemParams.getEngine(); - engine.init(random); - - byte[][] keyPair = engine.generateKemKeyPair(); + byte[][] keyPair = engine.generateKemKeyPair(random); MLKEMPublicKeyParameters pubKey = new MLKEMPublicKeyParameters(mlkemParams, keyPair[0], keyPair[1]); MLKEMPrivateKeyParameters privKey = new MLKEMPrivateKeyParameters(mlkemParams, keyPair[2], keyPair[3], keyPair[4], keyPair[0], keyPair[1], keyPair[5]); @@ -44,14 +42,4 @@ public AsymmetricCipherKeyPair generateKeyPair() { return genKeyPair(); } - - public AsymmetricCipherKeyPair internalGenerateKeyPair(byte[] d, byte[] z) - { - byte[][] keyPair = mlkemParams.getEngine().generateKemKeyPairInternal(d, z); - - MLKEMPublicKeyParameters pubKey = new MLKEMPublicKeyParameters(mlkemParams, keyPair[0], keyPair[1]); - MLKEMPrivateKeyParameters privKey = new MLKEMPrivateKeyParameters(mlkemParams, keyPair[2], keyPair[3], keyPair[4], keyPair[0], keyPair[1], keyPair[5]); - - return new AsymmetricCipherKeyPair(pubKey, privKey); - } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMParameters.java index 0dbc69bece..5c1adccd25 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMParameters.java @@ -5,33 +5,41 @@ public class MLKEMParameters implements KEMParameters { - public static final MLKEMParameters ml_kem_512 = new MLKEMParameters("ML-KEM-512", 2, 256); - public static final MLKEMParameters ml_kem_768 = new MLKEMParameters("ML-KEM-768", 3, 256); - public static final MLKEMParameters ml_kem_1024 = new MLKEMParameters("ML-KEM-1024", 4, 256); + public static final MLKEMParameters ml_kem_512 = new MLKEMParameters("ML-KEM-512", 2); + public static final MLKEMParameters ml_kem_768 = new MLKEMParameters("ML-KEM-768", 3); + public static final MLKEMParameters ml_kem_1024 = new MLKEMParameters("ML-KEM-1024", 4); private final String name; - private final int k; - private final int sessionKeySize; + private final MLKEMEngine engine; - private MLKEMParameters(String name, int k, int sessionKeySize) + private MLKEMParameters(String name, int k) { + if (name == null) + { + throw new NullPointerException("'name' cannot be null"); + } + this.name = name; - this.k = k; - this.sessionKeySize = sessionKeySize; + this.engine = new MLKEMEngine(k); } - public String getName() + MLKEMEngine getEngine() { - return name; + return engine; + } + + public int getEncapsulationLength() + { + return engine.getCipherTextBytes(); } - public MLKEMEngine getEngine() + public String getName() { - return new MLKEMEngine(k); + return name; } public int getSessionKeySize() { - return sessionKeySize; + return 256; } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMPrivateKeyParameters.java index b59198a6f1..25a7cc0267 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMPrivateKeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMPrivateKeyParameters.java @@ -5,13 +5,19 @@ public class MLKEMPrivateKeyParameters extends MLKEMKeyParameters { + public static final int BOTH = 0; + public static final int SEED_ONLY = 1; + public static final int EXPANDED_KEY = 2; + final byte[] s; final byte[] hpk; final byte[] nonce; final byte[] t; final byte[] rho; final byte[] seed; - + + private final int prefFormat; + public MLKEMPrivateKeyParameters(MLKEMParameters params, byte[] s, byte[] hpk, byte[] nonce, byte[] t, byte[] rho) { this(params, s, hpk, nonce, t, rho, null); @@ -27,18 +33,26 @@ public MLKEMPrivateKeyParameters(MLKEMParameters params, byte[] s, byte[] hpk, b this.t = Arrays.clone(t); this.rho = Arrays.clone(rho); this.seed = Arrays.clone(seed); + this.prefFormat = BOTH; + + validate(); } public MLKEMPrivateKeyParameters(MLKEMParameters params, byte[] encoding) + { + this(params, encoding, null); + } + + public MLKEMPrivateKeyParameters(MLKEMParameters params, byte[] encoding, MLKEMPublicKeyParameters pubKey) { super(true, params); MLKEMEngine eng = params.getEngine(); - if (encoding.length == MLKEMEngine.KyberSymBytes * 2) + if (encoding.length == MLKEMEngine.SeedBytes) { byte[][] keyData = eng.generateKemKeyPairInternal( - Arrays.copyOfRange(encoding, 0, MLKEMEngine.KyberSymBytes), - Arrays.copyOfRange(encoding, MLKEMEngine.KyberSymBytes, encoding.length)); + Arrays.copyOfRange(encoding, 0, MLKEMEngine.SymBytes), + Arrays.copyOfRange(encoding, MLKEMEngine.SymBytes, encoding.length)); this.s = keyData[2]; this.hpk = keyData[3]; this.nonce = keyData[4]; @@ -49,22 +63,96 @@ public MLKEMPrivateKeyParameters(MLKEMParameters params, byte[] encoding) else { int index = 0; - this.s = Arrays.copyOfRange(encoding, 0, eng.getKyberIndCpaSecretKeyBytes()); - index += eng.getKyberIndCpaSecretKeyBytes(); - this.t = Arrays.copyOfRange(encoding, index, index + eng.getKyberIndCpaPublicKeyBytes() - MLKEMEngine.KyberSymBytes); - index += eng.getKyberIndCpaPublicKeyBytes() - MLKEMEngine.KyberSymBytes; + this.s = Arrays.copyOfRange(encoding, 0, eng.getIndCpaSecretKeyBytes()); + index += eng.getIndCpaSecretKeyBytes(); + this.t = Arrays.copyOfRange(encoding, index, index + eng.getIndCpaPublicKeyBytes() - MLKEMEngine.SymBytes); + index += eng.getIndCpaPublicKeyBytes() - MLKEMEngine.SymBytes; this.rho = Arrays.copyOfRange(encoding, index, index + 32); index += 32; this.hpk = Arrays.copyOfRange(encoding, index, index + 32); index += 32; - this.nonce = Arrays.copyOfRange(encoding, index, index + MLKEMEngine.KyberSymBytes); + this.nonce = Arrays.copyOfRange(encoding, index, index + MLKEMEngine.SymBytes); this.seed = null; } + + validate(); + + if (pubKey != null) + { + if (!Arrays.constantTimeAreEqual(this.t, pubKey.t) || !Arrays.constantTimeAreEqual(this.rho, pubKey.rho)) + { + throw new IllegalArgumentException("passed in public key does not match private values"); + } + } + + this.prefFormat = (seed == null) ? EXPANDED_KEY : BOTH; + } + + private MLKEMPrivateKeyParameters(MLKEMPrivateKeyParameters params, int preferredFormat) + { + super(true, params.getParameters()); + + this.s = params.s; + this.t = params.t; + this.rho = params.rho; + this.hpk = params.hpk; + this.nonce = params.nonce; + this.seed = params.seed; + this.prefFormat = preferredFormat; + + validate(); + } + + private void validate() + { + MLKEMEngine engine = getParameters().getEngine(); + if (!engine.checkPrivateKey(getEncoded())) + { + throw new IllegalArgumentException("'encoding' fails hash check"); + } + } + + /** @deprecated Use {@link #withPreferredFormat(int)} instead. */ + public MLKEMPrivateKeyParameters getParametersWithFormat(int format) + { + return withPreferredFormat(format); + } + + public MLKEMPrivateKeyParameters withPreferredFormat(int format) + { + if (this.prefFormat == format) + { + return this; + } + + switch (format) + { + case BOTH: + case SEED_ONLY: + { + if (this.seed == null) + { + throw new IllegalStateException("no seed available"); + } + break; + } + case EXPANDED_KEY: + break; + default: + throw new IllegalArgumentException("unknown format"); + } + + return new MLKEMPrivateKeyParameters(this, format); + } + + public int getPreferredFormat() + { + return prefFormat; } public byte[] getEncoded() { - return Arrays.concatenate(new byte[][]{ s, t, rho, hpk, nonce }); + return Arrays.concatenate(new byte[][]{s, t, rho, hpk, nonce}); } public byte[] getHPK() diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMPublicKeyParameters.java index 5f2676d730..c3d89a68f9 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMPublicKeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/MLKEMPublicKeyParameters.java @@ -16,15 +16,45 @@ static byte[] getEncoded(byte[] t, byte[] rho) public MLKEMPublicKeyParameters(MLKEMParameters params, byte[] t, byte[] rho) { super(false, params); + + MLKEMEngine engine = params.getEngine(); + + if (t.length != engine.getPolyVecBytes()) + { + throw new IllegalArgumentException("'t' has invalid length"); + } + if (rho.length != MLKEMEngine.SymBytes) + { + throw new IllegalArgumentException("'rho' has invalid length"); + } + this.t = Arrays.clone(t); this.rho = Arrays.clone(rho); + + if (!engine.checkModulus(this.t)) + { + throw new IllegalArgumentException("Modulus check failed for ML-KEM public key"); + } } public MLKEMPublicKeyParameters(MLKEMParameters params, byte[] encoding) { super(false, params); - this.t = Arrays.copyOfRange(encoding, 0, encoding.length - MLKEMEngine.KyberSymBytes); - this.rho = Arrays.copyOfRange(encoding, encoding.length - MLKEMEngine.KyberSymBytes, encoding.length); + + MLKEMEngine engine = params.getEngine(); + + if (encoding.length != engine.getIndCpaPublicKeyBytes()) + { + throw new IllegalArgumentException("'encoding' has invalid length"); + } + + this.t = Arrays.copyOfRange(encoding, 0, encoding.length - MLKEMEngine.SymBytes); + this.rho = Arrays.copyOfRange(encoding, encoding.length - MLKEMEngine.SymBytes, encoding.length); + + if (!engine.checkModulus(this.t)) + { + throw new IllegalArgumentException("Modulus check failed for ML-KEM public key"); + } } public byte[] getEncoded() diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Ntt.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Ntt.java index 100647de08..1589d0dfe5 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Ntt.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Ntt.java @@ -2,8 +2,7 @@ class Ntt { - - public static final short[] nttZetas = new short[]{ + static final short[] ZETAS = new short[]{ 2285, 2571, 2970, 1812, 1493, 1422, 287, 202, 3158, 622, 1577, 182, 962, 2127, 1855, 1468, 573, 2004, 264, 383, 2500, 1458, 1727, 3199, 2648, 1017, 732, 608, 1787, 411, 3124, 1758, 1223, 652, 2777, 1015, 2036, 1491, 3047, @@ -15,7 +14,7 @@ class Ntt 1218, 1994, 2455, 220, 2142, 1670, 2144, 1799, 2051, 794, 1819, 2475, 2459, 478, 3221, 3021, 996, 991, 958, 1869, 1522, 1628}; - public static final short[] nttZetasInv = new short[]{ + static final short[] ZETAS_INV = new short[]{ 1701, 1807, 1460, 2371, 2338, 2333, 308, 108, 2851, 870, 854, 1510, 2535, 1278, 1530, 1185, 1659, 1187, 3109, 874, 1335, 2111, 136, 1215, 2945, 1465, 1285, 2007, 2719, 2726, 2232, 2512, 75, 156, 3000, 2911, 2980, 872, 2685, @@ -27,74 +26,60 @@ class Ntt 829, 2946, 3065, 1325, 2756, 1861, 1474, 1202, 2367, 3147, 1752, 2707, 171, 3127, 3042, 1907, 1836, 1517, 359, 758, 1441}; - public static short[] ntt(short[] inp) + static short mulMont(short a, short b) { - short[] r = new short[MLKEMEngine.KyberN]; - System.arraycopy(inp, 0, r, 0, r.length); - int len, start, j, k; - short t, zeta; + return Reduce.montgomeryReduce((int)(a * b)); + } - k = 1; - for (len = 128; len >= 2; len >>= 1) + static void ntt(short[] r) + { + int j, k = 1; + for (int len = 128; len >= 2; len >>= 1) { - for (start = 0; start < 256; start = j + len) + for (int start = 0; start < 256; start = j + len) { - zeta = nttZetas[k++]; + short zeta = ZETAS[k++]; for (j = start; j < start + len; ++j) { - t = factorQMulMont(zeta, r[j + len]); - r[j + len] = (short)(r[j] - t); - r[j] = (short)(r[j] + t); + short t = r[j], u = mulMont(zeta, r[j + len]); + r[j + len] = (short)(t - u); + r[j ] = (short)(t + u); } } } - return r; } - public static short[] invNtt(short[] inp) + static void invNtt(short[] r) { - short[] r = new short[MLKEMEngine.KyberN]; - System.arraycopy(inp, 0, r, 0, MLKEMEngine.KyberN); - int len, start, j, k; - short t, zeta; - k = 0; - for (len = 2; len <= 128; len <<= 1) + int j, k = 0; + for (int len = 2; len <= 128; len <<= 1) { - for (start = 0; start < 256; start = j + len) + for (int start = 0; start < 256; start = j + len) { - zeta = nttZetasInv[k++]; + short zeta = ZETAS_INV[k++]; for (j = start; j < start + len; ++j) { - t = r[j]; - r[j] = Reduce.barretReduce((short)(t + r[j + len])); - r[j + len] = (short)(t - r[j + len]); - r[j + len] = factorQMulMont(zeta, r[j + len]); - + short t = r[j], u = r[j + len]; + r[j ] = Reduce.barrettReduce((short)(t + u)); + r[j + len] = mulMont(zeta, (short)(t - u)); } } } - - for (j = 0; j < 256; ++j) + for (int i = 0; i < 256; ++i) { - r[j] = factorQMulMont(r[j], Ntt.nttZetasInv[127]); + r[i] = mulMont(r[i], ZETAS_INV[127]); } - return r; - } - - public static short factorQMulMont(short a, short b) - { - return Reduce.montgomeryReduce((int)(a * b)); } - public static void baseMult(Poly outPoly, int outIndex, short a0, short a1, short b0, short b1, short zeta) + static void baseMult(short[] r, int off, short a0, short a1, short b0, short b1, short zeta) { - short outVal0 = factorQMulMont(a1, b1); - outVal0 = factorQMulMont(outVal0, zeta); - outVal0 += factorQMulMont(a0, b0); - outPoly.setCoeffIndex(outIndex, outVal0); + short outVal0 = mulMont(a1, b1); + outVal0 = mulMont(outVal0, zeta); + outVal0 += mulMont(a0, b0); + r[off] = outVal0; - short outVal1 = factorQMulMont(a0, b1); - outVal1 += factorQMulMont(a1, b0); - outPoly.setCoeffIndex(outIndex + 1, outVal1); + short outVal1 = mulMont(a0, b1); + outVal1 += mulMont(a1, b0); + r[off + 1] = outVal1; } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Poly.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Poly.java index d7402a5ea7..b43524092c 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Poly.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Poly.java @@ -1,276 +1,227 @@ package org.bouncycastle.pqc.crypto.mlkem; +import org.bouncycastle.crypto.Xof; + class Poly { - private short[] coeffs; - private MLKEMEngine engine; - private int polyCompressedBytes; - private int eta1; - private int eta2; - - private Symmetric symmetric; + private final short[] coeffs = new short[MLKEMEngine.N]; - public Poly(MLKEMEngine engine) + short getCoeffIndex(int i) { - this.coeffs = new short[MLKEMEngine.KyberN]; - this.engine = engine; - polyCompressedBytes = engine.getKyberPolyCompressedBytes(); - this.eta1 = engine.getKyberEta1(); - this.eta2 = MLKEMEngine.getKyberEta2(); - this.symmetric = engine.getSymmetric(); + return coeffs[i]; } - public short getCoeffIndex(int i) + short[] getCoeffs() { - return this.coeffs[i]; + return coeffs; } - public short[] getCoeffs() + void setCoeffIndex(int i, short val) { - return this.coeffs; + coeffs[i] = val; } - public void setCoeffIndex(int i, short val) + void polyNtt() { - this.coeffs[i] = val; + Ntt.ntt(coeffs); + reduce(); } - public void setCoeffs(short[] coeffs) + void polyInverseNttToMont() { - this.coeffs = coeffs; + Ntt.invNtt(coeffs); } - public void polyNtt() + void reduce() { - this.setCoeffs(Ntt.ntt(this.getCoeffs())); - this.reduce(); - } - - public void polyInverseNttToMont() - { - this.setCoeffs(Ntt.invNtt(this.getCoeffs())); - } - - public void reduce() - { - int i; - for (i = 0; i < MLKEMEngine.KyberN; i++) + for (int i = 0; i < MLKEMEngine.N; i++) { - this.setCoeffIndex(i, Reduce.barretReduce(this.getCoeffIndex(i))); + coeffs[i] = Reduce.barrettReduce(coeffs[i]); } } - public static void baseMultMontgomery(Poly r, Poly a, Poly b) + static void baseMultMontgomery(Poly r, Poly a, Poly b) { - int i; - for (i = 0; i < MLKEMEngine.KyberN / 4; i++) + for (int i = 0; i < MLKEMEngine.N / 4; i++) { - Ntt.baseMult(r, 4 * i, + Ntt.baseMult(r.coeffs, 4 * i, a.getCoeffIndex(4 * i), a.getCoeffIndex(4 * i + 1), b.getCoeffIndex(4 * i), b.getCoeffIndex(4 * i + 1), - Ntt.nttZetas[64 + i]); - Ntt.baseMult(r, 4 * i + 2, + Ntt.ZETAS[64 + i]); + Ntt.baseMult(r.coeffs, 4 * i + 2, a.getCoeffIndex(4 * i + 2), a.getCoeffIndex(4 * i + 3), b.getCoeffIndex(4 * i + 2), b.getCoeffIndex(4 * i + 3), - (short)(-1 * Ntt.nttZetas[64 + i])); + (short)(-1 * Ntt.ZETAS[64 + i])); } } - public void addCoeffs(Poly b) + void add(Poly b) { - int i; - for (i = 0; i < MLKEMEngine.KyberN; i++) + for (int i = 0; i < MLKEMEngine.N; i++) { - this.setCoeffIndex(i, (short)(this.getCoeffIndex(i) + b.getCoeffIndex(i))); + coeffs[i] = (short)(coeffs[i] + b.coeffs[i]); } } - public void convertToMont() + void convertToMont() { - int i; - final short f = (short)(((long)1 << 32) % MLKEMEngine.KyberQ); - for (i = 0; i < MLKEMEngine.KyberN; i++) + final short f = (short)(((long)1 << 32) % MLKEMEngine.Q); + for (int i = 0; i < MLKEMEngine.N; i++) { this.setCoeffIndex(i, Reduce.montgomeryReduce(this.getCoeffIndex(i) * f)); } } - public byte[] compressPoly() + byte[] compressPoly128() { - int i, j; byte[] t = new byte[8]; - byte[] r = new byte[polyCompressedBytes]; + byte[] r = new byte[128]; int count = 0; - this.conditionalSubQ(); - // System.out.print("v = ["); - // Helper.printShortArray(this.coeffs); - // System.out.print("]\n"); + condSubQ(); - if (polyCompressedBytes == 128) + for (int i = 0; i < MLKEMEngine.N / 8; i++) { - for (i = 0; i < MLKEMEngine.KyberN / 8; i++) + for (int j = 0; j < 8; j++) { - for (j = 0; j < 8; j++) - { - /*t[j] = - (byte)((((((short)this.getCoeffIndex(8 * i + j)) << 4) - + - (KyberEngine.KyberQ / 2) - ) / KyberEngine.KyberQ) - & 15);*/ - // Fix for KyberSlash2: division by KyberQ above is not - // constant time. - int t_j = this.getCoeffIndex(8 * i + j); - t_j <<= 4; - t_j += 1665; - t_j *= 80635; - t_j >>= 28; - t_j &= 15; - t[j] = (byte)t_j; - } - - r[count + 0] = (byte)(t[0] | (t[1] << 4)); - r[count + 1] = (byte)(t[2] | (t[3] << 4)); - r[count + 2] = (byte)(t[4] | (t[5] << 4)); - r[count + 3] = (byte)(t[6] | (t[7] << 4)); - count += 4; + /*t[j] = + (byte)((((((short)this.getCoeffIndex(8 * i + j)) << 4) + + + (KyberEngine.KyberQ / 2) + ) / KyberEngine.KyberQ) + & 15);*/ + // Fix for KyberSlash2: division by KyberQ above is not + // constant time. + int t_j = this.getCoeffIndex(8 * i + j); + t_j <<= 4; + t_j += 1665; + t_j *= 80635; + t_j >>= 28; + t_j &= 15; + t[j] = (byte)t_j; } + + r[count + 0] = (byte)(t[0] | (t[1] << 4)); + r[count + 1] = (byte)(t[2] | (t[3] << 4)); + r[count + 2] = (byte)(t[4] | (t[5] << 4)); + r[count + 3] = (byte)(t[6] | (t[7] << 4)); + count += 4; } - else if (polyCompressedBytes == 160) + + return r; + } + + byte[] compressPoly160() + { + byte[] t = new byte[8]; + byte[] r = new byte[160]; + int count = 0; + + condSubQ(); + + for (int i = 0; i < MLKEMEngine.N / 8; i++) { - for (i = 0; i < MLKEMEngine.KyberN / 8; i++) + for (int j = 0; j < 8; j++) { - for (j = 0; j < 8; j++) - { - /*t[j] = - (byte)(((((this.getCoeffIndex(8 * i + j) << 5)) - + - (KyberEngine.KyberQ / 2) - ) / KyberEngine.KyberQ - ) & 31 - );*/ - // Fix for KyberSlash2: division by KyberQ above is not - // constant time. - int t_j = this.getCoeffIndex(8 * i + j); - t_j <<= 5; - t_j += 1664; - t_j *= 40318; - t_j >>= 27; - t_j &= 31; - t[j] = (byte)t_j; - } - r[count + 0] = (byte)((t[0] >> 0) | (t[1] << 5)); - r[count + 1] = (byte)((t[1] >> 3) | (t[2] << 2) | (t[3] << 7)); - r[count + 2] = (byte)((t[3] >> 1) | (t[4] << 4)); - r[count + 3] = (byte)((t[4] >> 4) | (t[5] << 1) | (t[6] << 6)); - r[count + 4] = (byte)((t[6] >> 2) | (t[7] << 3)); - count += 5; + /*t[j] = + (byte)(((((this.getCoeffIndex(8 * i + j) << 5)) + + + (KyberEngine.KyberQ / 2) + ) / KyberEngine.KyberQ + ) & 31 + );*/ + // Fix for KyberSlash2: division by KyberQ above is not + // constant time. + int t_j = this.getCoeffIndex(8 * i + j); + t_j <<= 5; + t_j += 1664; + t_j *= 40318; + t_j >>= 27; + t_j &= 31; + t[j] = (byte)t_j; } - } - else - { - throw new RuntimeException("PolyCompressedBytes is neither 128 or 160!"); + r[count + 0] = (byte)((t[0] >> 0) | (t[1] << 5)); + r[count + 1] = (byte)((t[1] >> 3) | (t[2] << 2) | (t[3] << 7)); + r[count + 2] = (byte)((t[3] >> 1) | (t[4] << 4)); + r[count + 3] = (byte)((t[4] >> 4) | (t[5] << 1) | (t[6] << 6)); + r[count + 4] = (byte)((t[6] >> 2) | (t[7] << 3)); + count += 5; } - // System.out.print("r = "); - // Helper.printByteArray(r); - // System.out.println(); - return r; } - public void decompressPoly(byte[] compressedPolyCipherText) + void decompressPoly128(byte[] cBuf, int cOff) { - int i, count = 0; - - if (engine.getKyberPolyCompressedBytes() == 128) + int pos = cOff; + for (int i = 0; i < MLKEMEngine.N / 2; i++) { - for (i = 0; i < MLKEMEngine.KyberN / 2; i++) - { - this.setCoeffIndex(2 * i + 0, (short)((((short)((compressedPolyCipherText[count] & 0xFF) & 15) * MLKEMEngine.KyberQ) + 8) >> 4)); - this.setCoeffIndex(2 * i + 1, (short)((((short)((compressedPolyCipherText[count] & 0xFF) >> 4) * MLKEMEngine.KyberQ) + 8) >> 4)); - count += 1; - } + this.setCoeffIndex(2 * i + 0, (short)((((short)((cBuf[pos] & 0xFF) & 15) * MLKEMEngine.Q) + 8) >> 4)); + this.setCoeffIndex(2 * i + 1, (short)((((short)((cBuf[pos] & 0xFF) >> 4) * MLKEMEngine.Q) + 8) >> 4)); + pos += 1; } - else if (engine.getKyberPolyCompressedBytes() == 160) + } + + void decompressPoly160(byte[] cBuf, int cOff) + { + int pos = cOff; + + byte[] t = new byte[8]; + for (int i = 0; i < MLKEMEngine.N / 8; i++) { - int j; - byte[] t = new byte[8]; - for (i = 0; i < MLKEMEngine.KyberN / 8; i++) + t[0] = (byte)((cBuf[pos + 0] & 0xFF) >> 0); + t[1] = (byte)(((cBuf[pos + 0] & 0xFF) >> 5) | ((cBuf[pos + 1] & 0xFF) << 3)); + t[2] = (byte)((cBuf[pos + 1] & 0xFF) >> 2); + t[3] = (byte)(((cBuf[pos + 1] & 0xFF) >> 7) | ((cBuf[pos + 2] & 0xFF) << 1)); + t[4] = (byte)(((cBuf[pos + 2] & 0xFF) >> 4) | ((cBuf[pos + 3] & 0xFF) << 4)); + t[5] = (byte)((cBuf[pos + 3] & 0xFF) >> 1); + t[6] = (byte)(((cBuf[pos + 3] & 0xFF) >> 6) | ((cBuf[pos + 4] & 0xFF) << 2)); + t[7] = (byte)((cBuf[pos + 4] & 0xFF) >> 3); + pos += 5; + for (int j = 0; j < 8; j++) { - t[0] = (byte)((compressedPolyCipherText[count + 0] & 0xFF) >> 0); - t[1] = (byte)(((compressedPolyCipherText[count + 0] & 0xFF) >> 5) | ((compressedPolyCipherText[count + 1] & 0xFF) << 3)); - t[2] = (byte)((compressedPolyCipherText[count + 1] & 0xFF) >> 2); - t[3] = (byte)(((compressedPolyCipherText[count + 1] & 0xFF) >> 7) | ((compressedPolyCipherText[count + 2] & 0xFF) << 1)); - t[4] = (byte)(((compressedPolyCipherText[count + 2] & 0xFF) >> 4) | ((compressedPolyCipherText[count + 3] & 0xFF) << 4)); - t[5] = (byte)((compressedPolyCipherText[count + 3] & 0xFF) >> 1); - t[6] = (byte)(((compressedPolyCipherText[count + 3] & 0xFF) >> 6) | ((compressedPolyCipherText[count + 4] & 0xFF) << 2)); - t[7] = (byte)((compressedPolyCipherText[count + 4] & 0xFF) >> 3); - count += 5; - for (j = 0; j < 8; j++) - { - this.setCoeffIndex(8 * i + j, (short)(((t[j] & 31) * MLKEMEngine.KyberQ + 16) >> 5)); - } + this.setCoeffIndex(8 * i + j, (short)(((t[j] & 31) * MLKEMEngine.Q + 16) >> 5)); } } - else - { - throw new RuntimeException("PolyCompressedBytes is neither 128 or 160!"); - } - } - public byte[] toBytes() + void toBytes(byte[] r, int off) { - byte[] r = new byte[MLKEMEngine.KyberPolyBytes]; - short t0, t1; - this.conditionalSubQ(); - for (int i = 0; i < MLKEMEngine.KyberN / 2; i++) + condSubQ(); + + for (int i = 0; i < MLKEMEngine.N / 2; i++) { - t0 = this.getCoeffIndex(2 * i); - t1 = this.getCoeffIndex(2 * i + 1); - r[3 * i] = (byte)(t0 >> 0); - r[3 * i + 1] = (byte)((t0 >> 8) | (t1 << 4)); - r[3 * i + 2] = (byte)(t1 >> 4); + short t0 = coeffs[2 * i + 0]; + short t1 = coeffs[2 * i + 1]; + r[off + 3 * i + 0] = (byte)(t0 >> 0); + r[off + 3 * i + 1] = (byte)((t0 >> 8) | (t1 << 4)); + r[off + 3 * i + 2] = (byte)(t1 >> 4); } - - return r; - } - public void fromBytes(byte[] inpBytes) + void fromBytes(byte[] inpBytes, int inOff) { - int i; - for (i = 0; i < MLKEMEngine.KyberN / 2; i++) + for (int i = 0; i < MLKEMEngine.N / 2; ++i) { - this.setCoeffIndex(2 * i, (short)( - ( - ((inpBytes[3 * i + 0] & 0xFF) >> 0) - | ((inpBytes[3 * i + 1] & 0xFF) << 8) - ) & 0xFFF) - ); - this.setCoeffIndex(2 * i + 1, (short)( - ( - ((inpBytes[3 * i + 1] & 0xFF) >> 4) - | (long)((inpBytes[3 * i + 2] & 0xFF) << 4) - ) & 0xFFF) - ); + int index = inOff + (3 * i); + int a0 = inpBytes[index + 0] & 0xFF; + int a1 = inpBytes[index + 1] & 0xFF; + int a2 = inpBytes[index + 2] & 0xFF; + coeffs[2 * i + 0] = (short)(((a0 >> 0) | (a1 << 8)) & 0xFFF); + coeffs[2 * i + 1] = (short)(((a1 >> 4) | (a2 << 4)) & 0xFFF); } } - public byte[] toMsg() + void toMsg(byte[] msg) { - int LOWER = MLKEMEngine.KyberQ >>> 2; - int UPPER = MLKEMEngine.KyberQ - LOWER; - - byte[] outMsg = new byte[MLKEMEngine.getKyberIndCpaMsgBytes()]; + int LOWER = MLKEMEngine.Q >>> 2; + int UPPER = MLKEMEngine.Q - LOWER; - this.conditionalSubQ(); + condSubQ(); - for (int i = 0; i < MLKEMEngine.KyberN / 8; i++) + for (int i = 0; i < MLKEMEngine.N / 8; i++) { - outMsg[i] = 0; + msg[i] = 0; for (int j = 0; j < 8; j++) { int c_j = this.getCoeffIndex(8 * i + j); @@ -279,76 +230,73 @@ public byte[] toMsg() // int t = (((c_j << 1) + (KyberEngine.KyberQ / 2)) / KyberEngine.KyberQ) & 1; int t = ((LOWER - c_j) & (c_j - UPPER)) >>> 31; - outMsg[i] |= (byte)(t << j); + msg[i] |= (byte)(t << j); } } - return outMsg; } - public void fromMsg(byte[] msg) + void fromMsg(byte[] msg) { - int i, j; - short mask; - if (msg.length != MLKEMEngine.KyberN / 8) + for (int i = 0; i < MLKEMEngine.N / 8; i++) { - throw new RuntimeException("KYBER_INDCPA_MSGBYTES must be equal to KYBER_N/8 bytes!"); - } - for (i = 0; i < MLKEMEngine.KyberN / 8; i++) - { - for (j = 0; j < 8; j++) + for (int j = 0; j < 8; j++) { - mask = (short)((-1) * (short)(((msg[i] & 0xFF) >> j) & 1)); - this.setCoeffIndex(8 * i + j, (short)(mask & (short)((MLKEMEngine.KyberQ + 1) / 2))); + short mask = (short)((-1) * (short)(((msg[i] & 0xFF) >> j) & 1)); + this.setCoeffIndex(8 * i + j, (short)(mask & (short)((MLKEMEngine.Q + 1) / 2))); } } } - public void conditionalSubQ() + void condSubQ() { - int i; - for (i = 0; i < MLKEMEngine.KyberN; i++) + for (int i = 0; i < MLKEMEngine.N; i++) { - this.setCoeffIndex(i, Reduce.conditionalSubQ(this.getCoeffIndex(i))); + coeffs[i] = Reduce.condSubQ(coeffs[i]); } } - public void getEta1Noise(byte[] seed, byte nonce) + void getNoiseEta2(Xof xof, byte[] seed, byte nonce) { - byte[] buf = new byte[MLKEMEngine.KyberN * eta1 / 4]; - symmetric.prf(buf, seed, nonce); - CBD.mlkemCBD(this, buf, eta1); + byte[] buf = new byte[2 * MLKEMEngine.N / 4]; + prf(xof, seed, nonce, buf); + CBD.eta2(this, buf); } - public void getEta2Noise(byte[] seed, byte nonce) + void getNoiseEta3(Xof xof, byte[] seed, byte nonce) { - byte[] buf = new byte[MLKEMEngine.KyberN * eta2 / 4]; - symmetric.prf(buf, seed, nonce); - CBD.mlkemCBD(this, buf, eta2); + byte[] buf = new byte[3 * MLKEMEngine.N / 4]; + prf(xof, seed, nonce, buf); + CBD.eta3(this, buf); } - public void polySubtract(Poly b) + private static void prf(Xof xof, byte[] seed, byte nonce, byte[] output) { - int i; - for (i = 0; i < MLKEMEngine.KyberN; i++) + xof.update(seed, 0, seed.length); + xof.update(nonce); + xof.doFinal(output, 0, output.length); + } + + void subtract(Poly b) + { + for (int i = 0; i < MLKEMEngine.N; i++) { - this.setCoeffIndex(i, (short)(b.getCoeffIndex(i) - this.getCoeffIndex(i))); + coeffs[i] = (short)(b.coeffs[i] - coeffs[i]); } } - public String toString() + static int checkModulus(byte[] a, int off) { - StringBuffer out = new StringBuffer(); - out.append("["); - for (int i = 0; i < coeffs.length; i++) + int result = -1; + for (int i = 0; i < MLKEMEngine.N / 2; ++i) { - out.append(coeffs[i]); - if (i != coeffs.length - 1) - { - out.append(", "); - } + int a0 = a[off + 3 * i + 0] & 0xFF; + int a1 = a[off + 3 * i + 1] & 0xFF; + int a2 = a[off + 3 * i + 2] & 0xFF; + short c0 = (short)(((a0 >> 0) | (a1 << 8)) & 0xFFF); + short c1 = (short)(((a1 >> 4) | (a2 << 4)) & 0xFFF); + result &= Reduce.checkModulus(c0); + result &= Reduce.checkModulus(c1); } - out.append("]"); - return out.toString(); + return result; } } - diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/PolyVec.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/PolyVec.java index d6613e904f..b2259f2de6 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/PolyVec.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/PolyVec.java @@ -1,272 +1,239 @@ package org.bouncycastle.pqc.crypto.mlkem; -import org.bouncycastle.util.Arrays; - class PolyVec { - Poly[] vec; - private MLKEMEngine engine; - private int kyberK; - private int polyVecBytes; + final Poly[] vec; - public PolyVec(MLKEMEngine engine) + PolyVec(int K) { - this.engine = engine; - this.kyberK = engine.getKyberK(); - this.polyVecBytes = engine.getKyberPolyVecBytes(); - - this.vec = new Poly[kyberK]; - for (int i = 0; i < kyberK; i++) + this.vec = new Poly[K]; + for (int i = 0; i < K; i++) { - vec[i] = new Poly(engine); + vec[i] = new Poly(); } } - public PolyVec() - throws Exception - { - throw new Exception("Requires Parameter"); - } - - public Poly getVectorIndex(int i) + Poly getVectorIndex(int i) { return vec[i]; } - public void polyVecNtt() + void polyVecNtt() { - int i; - for (i = 0; i < kyberK; i++) + for (int i = 0; i < vec.length; i++) { - this.getVectorIndex(i).polyNtt(); + vec[i].polyNtt(); } } - public void polyVecInverseNttToMont() + void polyVecInverseNttToMont() { - for (int i = 0; i < kyberK; i++) + for (int i = 0; i < vec.length; i++) { - this.getVectorIndex(i).polyInverseNttToMont(); + vec[i].polyInverseNttToMont(); } } - public byte[] compressPolyVec() + void compressPolyVec(byte[] rBuf, int rOff) { - int i, j, k; + int pos = rOff; + + condSubQ(); - this.conditionalSubQ(); - short[] t; - byte[] r = new byte[engine.getKyberPolyVecCompressedBytes()]; - int count = 0; - if (engine.getKyberPolyVecCompressedBytes() == kyberK * 320) + if (vec.length == 4) { - t = new short[4]; - for (i = 0; i < kyberK; i++) + // PolyVecCompressedBytes == K * 352 + + short[] t = new short[8]; + for (int i = 0; i < vec.length; i++) { - for (j = 0; j < MLKEMEngine.KyberN / 4; j++) + for (int j = 0; j < MLKEMEngine.N / 8; j++) { - for (k = 0; k < 4; k++) + for (int k = 0; k < 8; k++) { /*t[k] = (short) ( ( - ((this.getVectorIndex(i).getCoeffIndex(4 * j + k) << 10) + ((this.getVectorIndex(i).getCoeffIndex(8 * j + k) << 11) + (KyberEngine.KyberQ / 2)) / KyberEngine.KyberQ) - & 0x3ff);*/ + & 0x7ff);*/ // Fix for KyberSlash2: division by KyberQ above is not // constant time. - long t_k = this.getVectorIndex(i).getCoeffIndex(4 * j + k); - t_k <<= 10; - t_k += 1665; - t_k *= 1290167; - t_k >>= 32; - t_k &= 0x3ff; + long t_k = vec[i].getCoeffIndex(8 * j + k); + t_k <<= 11; + t_k += 1664; + t_k *= 645084; + t_k >>= 31; + t_k &= 0x7ff; t[k] = (short)t_k; } - r[count + 0] = (byte)(t[0] >> 0); - r[count + 1] = (byte)((t[0] >> 8) | (t[1] << 2)); - r[count + 2] = (byte)((t[1] >> 6) | (t[2] << 4)); - r[count + 3] = (byte)((t[2] >> 4) | (t[3] << 6)); - r[count + 4] = (byte)((t[3] >> 2)); - count += 5; + rBuf[pos + 0] = (byte)((t[0] >> 0)); + rBuf[pos + 1] = (byte)((t[0] >> 8) | (t[1] << 3)); + rBuf[pos + 2] = (byte)((t[1] >> 5) | (t[2] << 6)); + rBuf[pos + 3] = (byte)((t[2] >> 2)); + rBuf[pos + 4] = (byte)((t[2] >> 10) | (t[3] << 1)); + rBuf[pos + 5] = (byte)((t[3] >> 7) | (t[4] << 4)); + rBuf[pos + 6] = (byte)((t[4] >> 4) | (t[5] << 7)); + rBuf[pos + 7] = (byte)((t[5] >> 1)); + rBuf[pos + 8] = (byte)((t[5] >> 9) | (t[6] << 2)); + rBuf[pos + 9] = (byte)((t[6] >> 6) | (t[7] << 5)); + rBuf[pos + 10] = (byte)((t[7] >> 3)); + pos += 11; } } } - else if (engine.getKyberPolyVecCompressedBytes() == kyberK * 352) + else { - t = new short[8]; - for (i = 0; i < kyberK; i++) + // PolyVecCompressedBytes == K * 320 + + short[] t = new short[4]; + for (int i = 0; i < vec.length; i++) { - for (j = 0; j < MLKEMEngine.KyberN / 8; j++) + for (int j = 0; j < MLKEMEngine.N / 4; j++) { - for (k = 0; k < 8; k++) + for (int k = 0; k < 4; k++) { /*t[k] = (short) ( ( - ((this.getVectorIndex(i).getCoeffIndex(8 * j + k) << 11) + ((this.getVectorIndex(i).getCoeffIndex(4 * j + k) << 10) + (KyberEngine.KyberQ / 2)) / KyberEngine.KyberQ) - & 0x7ff);*/ + & 0x3ff);*/ // Fix for KyberSlash2: division by KyberQ above is not // constant time. - long t_k = this.getVectorIndex(i).getCoeffIndex(8 * j + k); - t_k <<= 11; - t_k += 1664; - t_k *= 645084; - t_k >>= 31; - t_k &= 0x7ff; + long t_k = vec[i].getCoeffIndex(4 * j + k); + t_k <<= 10; + t_k += 1665; + t_k *= 1290167; + t_k >>= 32; + t_k &= 0x3ff; t[k] = (short)t_k; } - r[count + 0] = (byte)((t[0] >> 0)); - r[count + 1] = (byte)((t[0] >> 8) | (t[1] << 3)); - r[count + 2] = (byte)((t[1] >> 5) | (t[2] << 6)); - r[count + 3] = (byte)((t[2] >> 2)); - r[count + 4] = (byte)((t[2] >> 10) | (t[3] << 1)); - r[count + 5] = (byte)((t[3] >> 7) | (t[4] << 4)); - r[count + 6] = (byte)((t[4] >> 4) | (t[5] << 7)); - r[count + 7] = (byte)((t[5] >> 1)); - r[count + 8] = (byte)((t[5] >> 9) | (t[6] << 2)); - r[count + 9] = (byte)((t[6] >> 6) | (t[7] << 5)); - r[count + 10] = (byte)((t[7] >> 3)); - count += 11; + rBuf[pos + 0] = (byte)(t[0] >> 0); + rBuf[pos + 1] = (byte)((t[0] >> 8) | (t[1] << 2)); + rBuf[pos + 2] = (byte)((t[1] >> 6) | (t[2] << 4)); + rBuf[pos + 3] = (byte)((t[2] >> 4) | (t[3] << 6)); + rBuf[pos + 4] = (byte)((t[3] >> 2)); + pos += 5; } } } - else - { - throw new RuntimeException("Kyber PolyVecCompressedBytes neither 320 * KyberK or 352 * KyberK!"); - } - return r; } - public void decompressPolyVec(byte[] compressedPolyVecCipherText) + void decompressPolyVec(byte[] cBuf, int cOff) { - int i, j, k, count = 0; + int pos = cOff; - if (engine.getKyberPolyVecCompressedBytes() == (kyberK * 320)) + if (vec.length == 4) { - short[] t = new short[4]; - for (i = 0; i < kyberK; i++) + // PolyVecCompressedBytes == K * 352 + + short[] t = new short[8]; + for (int i = 0; i < vec.length; i++) { - for (j = 0; j < MLKEMEngine.KyberN / 4; j++) + for (int j = 0; j < MLKEMEngine.N / 8; j++) { - t[0] = (short)(((compressedPolyVecCipherText[count] & 0xFF) >> 0) | (short)((compressedPolyVecCipherText[count + 1] & 0xFF) << 8)); - t[1] = (short)(((compressedPolyVecCipherText[count + 1] & 0xFF) >> 2) | (short)((compressedPolyVecCipherText[count + 2] & 0xFF) << 6)); - t[2] = (short)(((compressedPolyVecCipherText[count + 2] & 0xFF) >> 4) | (short)((compressedPolyVecCipherText[count + 3] & 0xFF) << 4)); - t[3] = (short)(((compressedPolyVecCipherText[count + 3] & 0xFF) >> 6) | (short)((compressedPolyVecCipherText[count + 4] & 0xFF) << 2)); - count += 5; - for (k = 0; k < 4; k++) + t[0] = (short)(((cBuf[pos] & 0xFF) >> 0) | ((short)(cBuf[pos + 1] & 0xFF) << 8)); + t[1] = (short)(((cBuf[pos + 1] & 0xFF) >> 3) | ((short)(cBuf[pos + 2] & 0xFF) << 5)); + t[2] = (short)(((cBuf[pos + 2] & 0xFF) >> 6) | ((short)(cBuf[pos + 3] & 0xFF) << 2) | ((short)((cBuf[pos + 4] & 0xFF) << 10))); + t[3] = (short)(((cBuf[pos + 4] & 0xFF) >> 1) | ((short)(cBuf[pos + 5] & 0xFF) << 7)); + t[4] = (short)(((cBuf[pos + 5] & 0xFF) >> 4) | ((short)(cBuf[pos + 6] & 0xFF) << 4)); + t[5] = (short)(((cBuf[pos + 6] & 0xFF) >> 7) | ((short)(cBuf[pos + 7] & 0xFF) << 1) | ((short)((cBuf[pos + 8] & 0xFF) << 9))); + t[6] = (short)(((cBuf[pos + 8] & 0xFF) >> 2) | ((short)(cBuf[pos + 9] & 0xFF) << 6)); + t[7] = (short)(((cBuf[pos + 9] & 0xFF) >> 5) | ((short)(cBuf[pos + 10] & 0xFF) << 3)); + pos += 11; + for (int k = 0; k < 8; k++) { - this.vec[i].setCoeffIndex(4 * j + k, (short)(((t[k] & 0x3FF) * MLKEMEngine.KyberQ + 512) >> 10)); + this.vec[i].setCoeffIndex(8 * j + k, (short)(((t[k] & 0x7FF) * MLKEMEngine.Q + 1024) >> 11)); } } - } - } - else if (engine.getKyberPolyVecCompressedBytes() == (kyberK * 352)) + else { - short[] t = new short[8]; - for (i = 0; i < kyberK; i++) + // PolyVecCompressedBytes == K * 320 + + short[] t = new short[4]; + for (int i = 0; i < vec.length; i++) { - for (j = 0; j < MLKEMEngine.KyberN / 8; j++) + for (int j = 0; j < MLKEMEngine.N / 4; j++) { - t[0] = (short)(((compressedPolyVecCipherText[count] & 0xFF) >> 0) | ((short)(compressedPolyVecCipherText[count + 1] & 0xFF) << 8)); - t[1] = (short)(((compressedPolyVecCipherText[count + 1] & 0xFF) >> 3) | ((short)(compressedPolyVecCipherText[count + 2] & 0xFF) << 5)); - t[2] = (short)(((compressedPolyVecCipherText[count + 2] & 0xFF) >> 6) | ((short)(compressedPolyVecCipherText[count + 3] & 0xFF) << 2) | ((short)((compressedPolyVecCipherText[count + 4] & 0xFF) << 10))); - t[3] = (short)(((compressedPolyVecCipherText[count + 4] & 0xFF) >> 1) | ((short)(compressedPolyVecCipherText[count + 5] & 0xFF) << 7)); - t[4] = (short)(((compressedPolyVecCipherText[count + 5] & 0xFF) >> 4) | ((short)(compressedPolyVecCipherText[count + 6] & 0xFF) << 4)); - t[5] = (short)(((compressedPolyVecCipherText[count + 6] & 0xFF) >> 7) | ((short)(compressedPolyVecCipherText[count + 7] & 0xFF) << 1) | ((short)((compressedPolyVecCipherText[count + 8] & 0xFF) << 9))); - t[6] = (short)(((compressedPolyVecCipherText[count + 8] & 0xFF) >> 2) | ((short)(compressedPolyVecCipherText[count + 9] & 0xFF) << 6)); - t[7] = (short)(((compressedPolyVecCipherText[count + 9] & 0xFF) >> 5) | ((short)(compressedPolyVecCipherText[count + 10] & 0xFF) << 3)); - count += 11; - for (k = 0; k < 8; k++) + t[0] = (short)(((cBuf[pos] & 0xFF) >> 0) | (short)((cBuf[pos + 1] & 0xFF) << 8)); + t[1] = (short)(((cBuf[pos + 1] & 0xFF) >> 2) | (short)((cBuf[pos + 2] & 0xFF) << 6)); + t[2] = (short)(((cBuf[pos + 2] & 0xFF) >> 4) | (short)((cBuf[pos + 3] & 0xFF) << 4)); + t[3] = (short)(((cBuf[pos + 3] & 0xFF) >> 6) | (short)((cBuf[pos + 4] & 0xFF) << 2)); + pos += 5; + for (int k = 0; k < 4; k++) { - this.vec[i].setCoeffIndex(8 * j + k, (short)(((t[k] & 0x7FF) * MLKEMEngine.KyberQ + 1024) >> 11)); + this.vec[i].setCoeffIndex(4 * j + k, (short)(((t[k] & 0x3FF) * MLKEMEngine.Q + 512) >> 10)); } } } } - else - { - throw new RuntimeException("Kyber PolyVecCompressedBytes neither 320 * KyberK or 352 * KyberK!"); - } } - public static void pointwiseAccountMontgomery(Poly out, PolyVec inp1, PolyVec inp2, MLKEMEngine engine) + static void pointwiseAccountMontgomery(Poly out, PolyVec inp1, PolyVec inp2, MLKEMEngine engine) { - int i; - Poly t = new Poly(engine); + Poly t = new Poly(); - Poly.baseMultMontgomery(out, inp1.getVectorIndex(0), inp2.getVectorIndex(0)); - for (i = 1; i < engine.getKyberK(); i++) + Poly.baseMultMontgomery(out, inp1.vec[0], inp2.vec[0]); + for (int i = 1; i < engine.getK(); i++) { - Poly.baseMultMontgomery(t, inp1.getVectorIndex(i), inp2.getVectorIndex(i)); - out.addCoeffs(t); + Poly.baseMultMontgomery(t, inp1.vec[i], inp2.vec[i]); + out.add(t); } out.reduce(); } - public void reducePoly() + void reducePoly() { - int i; - for (i = 0; i < kyberK; i++) + for (int i = 0; i < vec.length; i++) { - this.getVectorIndex(i).reduce(); + vec[i].reduce(); } } - public void addPoly(PolyVec b) + void addPoly(PolyVec b) { - int i; - for (i = 0; i < kyberK; i++) + for (int i = 0; i < vec.length; i++) { - this.getVectorIndex(i).addCoeffs(b.getVectorIndex(i)); + vec[i].add(b.vec[i]); } } - public byte[] toBytes() + void toBytes(byte[] r, int rOff) { - byte[] r = new byte[polyVecBytes]; - for (int i = 0; i < kyberK; i++) + for (int i = 0; i < vec.length; i++) { - System.arraycopy(this.vec[i].toBytes(), 0, r, i * MLKEMEngine.KyberPolyBytes, MLKEMEngine.KyberPolyBytes); + vec[i].toBytes(r, rOff + i * MLKEMEngine.PolyBytes); } - - return r; } - public void fromBytes(byte[] inputBytes) + void fromBytes(byte[] inputBytes) { - for (int i = 0; i < kyberK; i++) + for (int i = 0; i < vec.length; i++) { - this.getVectorIndex(i).fromBytes(Arrays.copyOfRange(inputBytes, i * MLKEMEngine.KyberPolyBytes, (i + 1) * MLKEMEngine.KyberPolyBytes)); + vec[i].fromBytes(inputBytes, i * MLKEMEngine.PolyBytes); } } - public void conditionalSubQ() + private void condSubQ() { - for (int i = 0; i < kyberK; i++) + for (int i = 0; i < vec.length; i++) { - this.getVectorIndex(i).conditionalSubQ(); + vec[i].condSubQ(); } } - public String toString() + static int checkModulus(MLKEMEngine engine, byte[] inputBytes) { - StringBuffer out = new StringBuffer(); - out.append("["); - for (int i = 0; i < kyberK; i++) + int result = -1; + for (int i = 0, k = engine.getK(); i < k; i++) { - out.append(vec[i].toString()); - if (i != kyberK - 1) - { - out.append(", "); - } + result &= Poly.checkModulus(inputBytes, i * MLKEMEngine.PolyBytes); } - out.append("]"); - return out.toString(); + return result; } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Reduce.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Reduce.java index c0b51d2c07..9abfba060c 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Reduce.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Reduce.java @@ -2,34 +2,33 @@ class Reduce { - - public static short montgomeryReduce(int a) + static short montgomeryReduce(int a) { - int t; - short u; - - u = (short)(a * MLKEMEngine.KyberQinv); - t = (int)(u * MLKEMEngine.KyberQ); + short u = (short)(a * MLKEMEngine.Qinv); + int t = (int)(u * MLKEMEngine.Q); t = a - t; t >>= 16; return (short)t; } - public static short barretReduce(short a) + static short barrettReduce(short a) { - short t; - long shift = (((long)1) << 26); - short v = (short)((shift + (MLKEMEngine.KyberQ / 2)) / MLKEMEngine.KyberQ); - t = (short)((v * a) >> 26); - t = (short)(t * MLKEMEngine.KyberQ); + short v = (short)(((1L << 26) + (MLKEMEngine.Q / 2)) / MLKEMEngine.Q); + short t = (short)((v * a) >> 26); + t = (short)(t * MLKEMEngine.Q); return (short)(a - t); } - public static short conditionalSubQ(short a) + static short condSubQ(short a) { - a -= MLKEMEngine.KyberQ; - a += (a >> 15) & MLKEMEngine.KyberQ; + a -= MLKEMEngine.Q; + a += (a >> 15) & MLKEMEngine.Q; return a; } + // NB: We only care about the sign bit of the result: it will be 1 iff the argument was in range + static int checkModulus(short a) + { + return a - MLKEMEngine.Q; + } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Symmetric.java b/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Symmetric.java deleted file mode 100644 index 40c309dedf..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/mlkem/Symmetric.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.bouncycastle.pqc.crypto.mlkem; - -import org.bouncycastle.crypto.digests.SHA3Digest; -import org.bouncycastle.crypto.digests.SHAKEDigest; - -abstract class Symmetric -{ - - final int xofBlockBytes; - - abstract void hash_h(byte[] out, byte[] in, int outOffset); - - abstract void hash_g(byte[] out, byte[] in); - - abstract void xofAbsorb(byte[] seed, byte x, byte y); - - abstract void xofSqueezeBlocks(byte[] out, int outOffset, int outLen); - - abstract void prf(byte[] out, byte[] key, byte nonce); - - abstract void kdf(byte[] out, byte[] in); - - Symmetric(int blockBytes) - { - this.xofBlockBytes = blockBytes; - } - - - static class ShakeSymmetric - extends Symmetric - { - private final SHAKEDigest xof; - private final SHA3Digest sha3Digest512; - private final SHA3Digest sha3Digest256; - private final SHAKEDigest shakeDigest; - - ShakeSymmetric() - { - super(168); - this.xof = new SHAKEDigest(128); - this.shakeDigest = new SHAKEDigest(256); - this.sha3Digest256 = new SHA3Digest(256); - this.sha3Digest512 = new SHA3Digest(512); - } - - @Override - void hash_h(byte[] out, byte[] in, int outOffset) - { - sha3Digest256.update(in, 0, in.length); - sha3Digest256.doFinal(out, outOffset); - } - - @Override - void hash_g(byte[] out, byte[] in) - { - sha3Digest512.update(in, 0, in.length); - sha3Digest512.doFinal(out, 0); - } - - @Override - void xofAbsorb(byte[] seed, byte a, byte b) - { - xof.reset(); - byte[] buf = new byte[seed.length + 2]; - System.arraycopy(seed, 0, buf, 0, seed.length); - buf[seed.length] = a; - buf[seed.length + 1] = b; - xof.update(buf, 0, seed.length + 2); - } - - @Override - void xofSqueezeBlocks(byte[] out, int outOffset, int outLen) - { - xof.doOutput(out, outOffset, outLen); - } - - @Override - void prf(byte[] out, byte[] seed, byte nonce) - { - byte[] extSeed = new byte[seed.length + 1]; - System.arraycopy(seed, 0, extSeed, 0, seed.length); - extSeed[seed.length] = nonce; - shakeDigest.update(extSeed, 0, extSeed.length); - shakeDigest.doFinal(out, 0, out.length); - } - - @Override - void kdf(byte[] out, byte[] in) - { - shakeDigest.update(in, 0, in.length); - shakeDigest.doFinal(out, 0, out.length); - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUKEMExtractor.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUKEMExtractor.java index b6b0b13b51..81f4316024 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUKEMExtractor.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUKEMExtractor.java @@ -81,6 +81,6 @@ private void cmov(byte[] r, byte[] x, byte b) public int getEncapsulationLength() { - return ntruPrivateKey.getParameters().getParameterSet().ntruCiphertextBytes(); + return ntruPrivateKey.getParameters().getEncapsulationLength(); } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUKEMGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUKEMGenerator.java index 43d9c98219..532cf659d3 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUKEMGenerator.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUKEMGenerator.java @@ -2,6 +2,7 @@ import java.security.SecureRandom; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.EncapsulatedSecretGenerator; import org.bouncycastle.crypto.SecretWithEncapsulation; import org.bouncycastle.crypto.digests.SHA3Digest; @@ -22,19 +23,9 @@ public class NTRUKEMGenerator { private final SecureRandom random; - /** - * Constructor - * - * @param random a secure random number generator - */ public NTRUKEMGenerator(SecureRandom random) { - if (random == null) - { - throw new NullPointerException("'random' cannot be null"); - } - - this.random = random; + this.random = CryptoServicesRegistrar.getSecureRandom(random); } public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recipientKey) diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java index c334f0cc8a..c5e9f343fe 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java @@ -52,6 +52,11 @@ private NTRUParameters(String name, NTRUParameterSet parameterSet) this.parameterSet = parameterSet; } + public int getEncapsulationLength() + { + return getParameterSet().ntruCiphertextBytes(); + } + public String getName() { return name; diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/package-info.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/package-info.java index b6e4a7dfb3..03820c3b73 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/package-info.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/package-info.java @@ -1,6 +1,5 @@ /** - * The NTRU algorithm based on the round 3 submission of the NIST post-quantum cryptography. For the old NTRU, see - * {@link org.bouncycastle.pqc.legacy.crypto.ntru}. + * The NTRU algorithm based on the round 3 submission of the NIST post-quantum cryptography. * *

    * This implementation is based on the C reference implementation submitted for the round 3 NIST PQC competition, diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusEngine.java new file mode 100644 index 0000000000..113f565188 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusEngine.java @@ -0,0 +1,942 @@ +package org.bouncycastle.pqc.crypto.ntruplus; + +import org.bouncycastle.crypto.digests.SHAKEDigest; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Bytes; + +class NTRUPlusEngine +{ + private static final short QINV = 12929; + private static final short OMEGA = -886; + private static final short RINV = -682; + private static final short RSQ = 867; + private static final short Q = 3457; + private static final short Q_HALF = Q >> 1; + private static final short QPlus1_Half = (Q + 1) >> 1; + private static final short QMinus1_Half = (Q - 1) >> 1; + private static final short V = ((1 << 26) + Q_HALF) / Q; + private static final byte hash_f_domain = (byte) 0x00; + private static final byte hash_g_domain = (byte) 0x01; + private static final byte hash_h_domain = (byte) 0x02; + static final int SSBytes = 32; + + private final int n; + private final int halfN; + private final int quarterN; + private final int eighthN; + private final int blockSize; + private final int doubleBlockSize; + private final int zetaOffset; + public short polyBytes; + public short[] zetas; + private final NTRUPlusParameters params; + private final SHAKEDigest shakeDigest = new SHAKEDigest(256); + + public NTRUPlusEngine(NTRUPlusParameters params) + { + this.params = params; + this.n = params.getN(); + this.halfN = this.n >> 1; + this.quarterN = this.n >> 2; + this.eighthN = this.n >> 3; + this.blockSize = n == 864 ? 3 : 4; + this.doubleBlockSize = blockSize << 1; + this.zetaOffset = params.getZetasOffset(); + this.polyBytes = (short)params.getPublicKeyBytes(); + this.zetas = params.getZetas(); + } + + /************************************************* + * Name: genf_derand + * Description: Deterministically generates a secret polynomial f and its + * multiplicative inverse finv in the NTT domain. + * Returns 0 on success; non-zero if f is not invertible in the NTT domain. + **************************************************/ + public int genf_derand(short[] f, short[] finv, byte[] coins) + { + byte[] buf = new byte[quarterN]; + + shake256(buf, 0, buf.length, coins, 32); + + poly_cbd1(f, buf, 0); + poly_triple(f, f); + f[0] += 1; + + poly_ntt(f); + + return poly_baseinv(finv, f); + } + + /************************************************* + * Name: poly_cbd1 + * Description: Sample a polynomial deterministically from a random, + * with output polynomial close to centered binomial distribution + **************************************************/ + private void poly_cbd1(short[] r, byte[] buf, int bufPos) + { + for (int i = 0, pos = 0; i < eighthN; i++, pos += 8) + { + int t1 = buf[bufPos + i] & 0xFF; // Convert to unsigned + int t2 = buf[bufPos + i + eighthN] & 0xFF; + + for (int j = 0; j < 8; j++) + { + r[pos + j] = (short)((t1 & 0x1) - (t2 & 0x1)); + t1 >>= 1; + t2 >>= 1; + } + } + } + + /************************************************* + * Name: poly_triple + * Description: Multiply polynomial by 3; no modular reduction is performed + **************************************************/ + public void poly_triple(short[] r, short[] a) + { + for (int i = 0; i < n; ++i) + { + r[i] = (short)(3 * a[i]); + } + } + + /** + * Number-theoretic transform (NTT) in R_q. + * Transforms the coefficient representation into NTT representation. + *

    + * This merged function supports N=768 (4-coefficient blocks), + * N=864 (3-coefficient blocks), and N=1152 (4-coefficient blocks). + * + * @param r Output vector in NTT representation + */ + private void poly_ntt(short[] r) + { + short t1, t2, t3; + short zeta1, zeta2; + int k = 1; + + zeta1 = zetas[k++]; + + for (int i = 0, pos = halfN; i < halfN; i++, pos++) + { + t1 = fqmul(zeta1, r[pos]); + r[pos] = (short)(r[i] + r[pos] - t1); + r[i] = (short)(r[i] + t1); + } + int baseStep = params.getBaseStep(); + int minStep = params.getMinStep(); + for (int step = n / 6; step >= (baseStep << 1); step /= 3) + { + int twoSteps = step << 1; + int threeSteps = twoSteps + step; + for (int start = 0; start < n; start += threeSteps) + { + zeta1 = zetas[k++]; + zeta2 = zetas[k++]; + + for (int i = start, pos1 = start + step, pos2 = start + twoSteps; i < start + step; i++, pos1++, pos2++) + { + t1 = fqmul(zeta1, r[pos1]); + t2 = fqmul(zeta2, r[pos2]); + t3 = fqmul(OMEGA, (short)(t1 - t2)); + + r[pos2] = (short)(r[i] - t1 - t3); + r[pos1] = (short)(r[i] - t2 + t3); + r[i] = (short)(r[i] + t1 + t2); + } + } + } + + // Final butterflies: step from 24 down to 3 + for (int step = baseStep; step >= minStep; step >>= 1) + { + for (int start = 0; start < n; start += (step << 1)) + { + zeta1 = zetas[k++]; + + for (int i = start, pos = start + step; i < start + step; i++, pos++) + { + t1 = fqmul(zeta1, r[pos]); + r[pos] = barrett_reduce((short)(r[i] - t1)); + r[i] = barrett_reduce((short)(r[i] + t1)); + } + } + } + } + + /************************************************* + * Name: fqmul + * Description: Multiplication followed by Montgomery reduction. + * Returns: 16-bit integer congruent to a*b*R^-1 mod q. + **************************************************/ + public short fqmul(short a, short b) + { + return montgomery_reduce((int)a * b); + } + + /************************************************* + * Name: montgomery_reduce + * Description: Montgomery reduction; given a 32-bit integer a, computes + * a 16-bit integer congruent to a * R^-1 mod q, + * where R = 2^16. + **************************************************/ + public short montgomery_reduce(int a) + { + return (short)((a - (short)(a * QINV) * Q) >> 16); + } + + /************************************************* + * Name: barrett_reduce + * Description: Barrett reduction; given a 16-bit integer a, computes a + * centered representative congruent to a mod q. + **************************************************/ + public short barrett_reduce(short a) + { + return (short)(a - ((V * a + (1 << 25)) >> 26) * Q); + } + + /************************************************* + * Name: poly_baseinv + * Description: Inversion of polynomial in NTT domain + **************************************************/ + private int poly_baseinv(short[] r, short[] a) + { + if (n == 864) + { + // Special handling for N=864 with 3-coefficient blocks + for (int i = 0, pos = 0, zetaOff = zetaOffset; i < n / 6; ++i, pos += 6, zetaOff++) + { + // Use baseinv3 for 3-coefficient blocks + if (baseinv3(r, pos, a, pos, zetas[zetaOff]) == 1) + { + Arrays.fill(r, (short)0); + return 1; + } + + if (baseinv3(r, pos + 3, a, pos + 3, (short)-zetas[zetaOff]) == 1) + { + Arrays.fill(r, (short)0); + return 1; + } + } + } + else + { + // Use existing logic for N=768 and N=1152 + for (int i = 0, pos = 0, zetaOff = zetaOffset; i < eighthN; ++i, pos += 8, zetaOff++) + { + if (baseinv(r, pos, a, pos, zetas[zetaOff]) == 1) + { + Arrays.fill(r, (short)0); + return 1; + } + + if (baseinv(r, pos + 4, a, pos + 4, (short)-zetas[zetaOff]) == 1) + { + Arrays.fill(r, (short)0); + return 1; + } + } + } + + return 0; + } + + /** + * Inversion of a polynomial in Zq[X]/(X^3 - zeta), used as + * a building block for inversion of elements in R_q in the NTT domain. + * This version is specifically for N=864 with 3-coefficient blocks. + * + * @param r Output polynomial array (3 elements) + * @param rPos Starting position in r array + * @param a Input polynomial array (3 elements) + * @param aPos Starting position in a array + * @param zeta Parameter defining X^3 - zeta + * @return 0 if a is invertible, 1 otherwise + */ + private int baseinv3(short[] r, int rPos, short[] a, int aPos, short zeta) + { + short a0 = a[aPos], a1 = a[aPos + 1], a2 = a[aPos + 2]; + + short r0 = montgomery_reduce(a1 * a2); + short r1 = montgomery_reduce(a2 * a2); + short r2 = montgomery_reduce(a1 * a1 - a0 * a2); + + r0 = montgomery_reduce(a0 * a0 - r0 * zeta); + r1 = montgomery_reduce(r1 * zeta - a0 * a1); + + short t = montgomery_reduce(r2 * a1 + r1 * a2); + t = montgomery_reduce(t * zeta + r0 * a0); + + if (t == 0) + { + return 1; // Not invertible + } + + t = fqinv(t); + t = montgomery_reduce(t * RINV); + + r[rPos] = montgomery_reduce(r0 * t); + r[rPos + 1] = montgomery_reduce(r1 * t); + r[rPos + 2] = montgomery_reduce(r2 * t); + + return 0; // Success + } + + /************************************************* + * Name: baseinv + * Description: Inversion of a polynomial in Zq[X]/(X^4 - zeta) + * Returns: 0 if a is invertible, 1 otherwise. + **************************************************/ + public int baseinv(short[] r, int rOff, short[] a, int aOff, short zeta) + { + short a0 = a[aOff], a1 = a[aOff + 1], a2 = a[aOff + 2], a3 = a[aOff + 3]; + short t0, t1, t2, t3; + + t0 = montgomery_reduce(a2 * a2 - 2 * a1 * a3); + t1 = montgomery_reduce(a3 * a3); + t0 = montgomery_reduce(a0 * a0 + t0 * zeta); + t1 = montgomery_reduce(a1 * a1 + t1 * zeta - 2 * a0 * a2); + t2 = montgomery_reduce(t1 * zeta); + + t3 = montgomery_reduce(t0 * t0 - t1 * t2); + + if (t3 == 0) + { + return 1; + } + + short r0 = montgomery_reduce(a0 * t0 + a2 * t2); + short r1 = montgomery_reduce(a3 * t2 + a1 * t0); + short r2 = montgomery_reduce(a2 * t0 + a0 * t1); + short r3 = montgomery_reduce(a1 * t1 + a3 * t0); + + t3 = fqinv(t3); + t3 = montgomery_reduce(t3 * RINV); + + r[rOff] = montgomery_reduce(r0 * t3); + r[rOff + 1] = (short)-montgomery_reduce(r1 * t3); + r[rOff + 2] = montgomery_reduce(r2 * t3); + r[rOff + 3] = (short)-montgomery_reduce(r3 * t3); + + return 0; + } + + public void shake256(byte[] output, int outOff, int outLen, byte[] input, int inLen) + { + shakeDigest.update(input, 0, inLen); + shakeDigest.doFinal(output, outOff, outLen); + } + + /** + * Computes the multiplicative inverse of a value in the finite field Z_q, + * using Montgomery arithmetic. + *

    + * The input is an ordinary field element x (no scaling), and the function + * returns x^{-1} scaled by R^2 modulo q, where R = 2^16 is the Montgomery radix. + * + * @param a The input value a = x mod q, as a signed 16-bit integer. + * @return A 16-bit integer congruent to x^{-1} * R^2 mod q. + */ + public short fqinv(short a) + { + short t1, t2, t3; + + // Follow the exact exponentiation sequence from the original C code + // This efficiently computes a^(q-2) mod q using a fixed addition chain. + t1 = fqmul(a, a); // a^2 + t2 = fqmul(t1, t1); // a^4 + t2 = fqmul(t2, t2); // a^8 + t3 = fqmul(t2, t2); // a^16 + + t1 = fqmul(t1, t2); // a^10 + + t2 = fqmul(t1, t3); // a^26 + t2 = fqmul(t2, t2); // a^52 + t2 = fqmul(t2, a); // a^53 + + t1 = fqmul(t1, t2); // a^63 + + t2 = fqmul(t2, t2); // a^106 + t2 = fqmul(t2, t2); // a^212 + t2 = fqmul(t2, t2); // a^424 + t2 = fqmul(t2, t2); // a^848 + t2 = fqmul(t2, t2); // a^1696 + t2 = fqmul(t2, t2); // a^3392 + t2 = fqmul(t2, t1); // a^3455 + + return t2; + } + + /** + * Multiplication of two polynomials in NTT domain. + * This merged function supports all three parameter sets: + * - N=768: 8-coefficient blocks, zeta offset 96 + * - N=864: 6-coefficient blocks, zeta offset 144 + * - N=1152: 8-coefficient blocks, zeta offset 144 + *

    + * All cases perform: r = a * b (in NTT domain) + * + * @param r Output polynomial + * @param a First input polynomial + * @param b Second input polynomial + */ + private void poly_basemul(short[] r, short[] a, short[] b) + { + for (int i = 0; i < n / doubleBlockSize; ++i) + { + basemul(r, doubleBlockSize * i, a, doubleBlockSize * i, b, doubleBlockSize * i, zetas[zetaOffset + i]); + basemul(r, doubleBlockSize * i + blockSize, a, doubleBlockSize * i + blockSize, b, doubleBlockSize * i + blockSize, (short)-zetas[zetaOffset + i]); + } + } + + + /** + * Serialization of a polynomial + * + * @param r Output byte array (must have space for NTRUPLUS_POLYBYTES bytes) + * @param a Input polynomial + */ + public void poly_tobytes(byte[] r, int rOff, short[] a) + { + int t0, t1; + + for (int i = 0, inOff = 0, outOff = rOff; i < halfN; i++) + { + t0 = a[inOff++]; + t0 += (t0 >> 15) & Q; + + t1 = a[inOff++]; + t1 += (t1 >> 15) & Q; + + // Pack two 13-bit coefficients into three bytes + r[outOff++] = (byte)(t0); // Lower 8 bits of first coefficient + r[outOff++] = (byte)((t0 >> 8) | (t1 << 4)); // Upper 5 bits of t0, lower 4 bits of t1 + r[outOff++] = (byte)(t1 >> 4); // Upper 8 bits of t1 + } + } + + /** + * Deterministically generates a secret polynomial g and its + * multiplicative inverse ginv in the NTT domain. + * + * @param g Output polynomial g (in NTT domain) + * @param ginv Output multiplicative inverse of g in the NTT domain + * @param coins 32-byte deterministic seed + * @return 0 on success; non-zero if g is not invertible in the NTT domain + */ + public int geng_derand(short[] g, short[] ginv, byte[] coins) + { + byte[] buf = new byte[quarterN]; + shake256(buf, 0, buf.length, coins, 32); + poly_cbd1(g, buf, 0); + poly_triple(g, g); + poly_ntt(g); + return poly_baseinv(ginv, g); + } + + /** + * Computes the deterministic public and secret key pair from + * the secret polynomials f and g and their multiplicative + * inverses finv and ginv in the NTT domain. + * + * @param pk Output public key (must have length params.getPublicKeyBytes()) + * @param sk Output secret key (must have length params.getSecretKeyBytes()) + * @param f Secret polynomial f (in NTT domain) + * @param finv Multiplicative inverse of f (in NTT domain) + * @param g Secret polynomial g (in NTT domain) + * @param ginv Multiplicative inverse of g (in NTT domain) + */ + public void crypto_kem_keypair_derand(byte[] pk, byte[] sk, short[] f, short[] finv, short[] g, short[] ginv) + { + short[] h = new short[n]; + short[] hinv = new short[n]; + + // Compute h = g * finv (in NTT domain) + poly_basemul(h, g, finv); + + // Compute hinv = f * ginv (in NTT domain) + poly_basemul(hinv, f, ginv); + + // Serialize h to get the public key + poly_tobytes(pk, 0, h); + + // Serialize f to the first part of the secret key + poly_tobytes(sk, 0, f); + + // Serialize hinv to the second part of the secret key (offset by NTRUPLUS_POLYBYTES) + poly_tobytes(sk, polyBytes, hinv); + + // Compute hash of public key and store in the third part of secret key + shake256(sk, polyBytes << 1, 32, hash_f_domain, pk, 0, polyBytes); + } + + /** + * SOTP encoding + */ + private void poly_sotp_encode(short[] r, byte[] msg, byte[] buf) + { + Bytes.xorTo(eighthN, msg, buf); + poly_cbd1(r, buf, 0); + } + + /** + * Deserialization of a polynomial from bytes + */ + private void poly_frombytes(short[] r, byte[] a, int aPos) + { + for (int i = 0, inOff = aPos, outOff = 0; i < halfN; i++, inOff += 3) + { + r[outOff++] = (short)(((a[inOff] & 0xFF) | ((a[inOff + 1] & 0xFF) << 8)) & 0xFFF); + r[outOff++] = (short)(((a[inOff + 1] & 0xFF) >> 4 | ((a[inOff + 2] & 0xFF) << 4)) & 0xFFF); + } + } + + /** + * Multiplication then addition of three polynomials in NTT domain. + * This merged function supports all three parameter sets: + * - N=768: 8-coefficient blocks, zeta offset 96 + * - N=864: 6-coefficient blocks, zeta offset 144 + * - N=1152: 8-coefficient blocks, zeta offset 144 + *

    + * All cases perform: r = a * b + c (in NTT domain) + * + * @param r Output polynomial + * @param a First input polynomial + * @param b Second input polynomial + * @param c Third input polynomial to add + */ + private void poly_basemul_add(short[] r, short[] a, short[] b, short[] c) + { + for (int i = 0, pos = 0, zetaOff = zetaOffset; i < n / doubleBlockSize; ++i, zetaOff++) + { + basemul_add(r, pos, a, pos, b, pos, c, pos, zetas[zetaOff], blockSize); + pos += blockSize; + basemul_add(r, pos, a, pos, b, pos, c, pos, (short)-zetas[zetaOff], blockSize); + pos += blockSize; + } + } + + /** + * Multiplication then addition of polynomials in Zq[X]/(X^d - zeta), + * used for multiplication of elements in R_q in the NTT domain. + *

    + * Supports: + * - 4-coefficient blocks (d=4) for N=768, 1152 + * - 3-coefficient blocks (d=3) for N=864 + */ + private void basemul_add(short[] r, int rPos, short[] a, int aPos, + short[] b, int bPos, short[] c, int cPos, + short zeta, int blockSize) + { + // Common multiplication core + multiplyCore(r, rPos, a, aPos, b, bPos, zeta, blockSize); + + // Addition and final scaling + finalizeWithAddition(r, rPos, c, cPos, blockSize); + } + + /** + * Multiplication of polynomials in Zq[X]/(X^d - zeta) + */ + private void basemul(short[] r, int rPos, short[] a, int aPos, + short[] b, int bPos, short zeta) + { + // Common multiplication core + multiplyCore(r, rPos, a, aPos, b, bPos, zeta, blockSize); + + // Final scaling (multiplication only) + finalizeMultiplication(r, rPos, blockSize); + } + + /** + * Core multiplication logic shared by both basemul and basemul_add + */ + private void multiplyCore(short[] r, int rPos, short[] a, int aPos, + short[] b, int bPos, short zeta, int blockSize) + { + // Extract common coefficients (a0, a1, a2, b0, b1, b2) + short a0 = a[aPos], a1 = a[aPos + 1], a2 = a[aPos + 2]; + short b0 = b[bPos], b1 = b[bPos + 1], b2 = b[bPos + 2]; + int temp; + + if (blockSize == 4) + { + // 4-coefficient specific logic + short a3 = a[aPos + 3]; + short b3 = b[bPos + 3]; + + // High-degree terms + temp = (int)a1 * b3 + (int)a2 * b2 + (int)a3 * b1; + r[rPos] = montgomery_reduce(temp); + + temp = (int)a2 * b3 + (int)a3 * b2; + r[rPos + 1] = montgomery_reduce(temp); + + temp = (int)a3 * b3; + temp = montgomery_reduce(temp); + + // Apply zeta to middle terms + temp = temp * zeta + (int)a0 * b2 + (int)a1 * b1 + (int)a2 * b0; + r[rPos + 2] = montgomery_reduce(temp); + + // Compute r3 term + temp = (int)a0 * b3 + (int)a1 * b2 + (int)a2 * b1 + (int)a3 * b0; + r[rPos + 3] = montgomery_reduce(temp); + } + else + { + // 3-coefficient specific logic + // High-degree terms + temp = (int)a2 * b1 + (int)a1 * b2; + r[rPos] = montgomery_reduce(temp); + + temp = (int)a2 * b2; + r[rPos + 1] = montgomery_reduce(temp); + + // Compute r2 term + temp = (int)a2 * b0 + (int)a1 * b1 + (int)a0 * b2; + r[rPos + 2] = montgomery_reduce(temp); + } + + // Common low-degree terms (apply zeta to r0 and r1) + temp = (int)r[rPos] * zeta + (int)a0 * b0; + r[rPos] = montgomery_reduce(temp); + + temp = (int)r[rPos + 1] * zeta + (int)a0 * b1 + (int)a1 * b0; + r[rPos + 1] = montgomery_reduce(temp); + } + + /** + * Final scaling for multiplication with addition (basemul_add) + */ + private void finalizeWithAddition(short[] r, int rPos, short[] c, int cPos, int blockSize) + { + int rValue = 1 << 16; // NTRUPLUS_R = 2^16 = 65536 + + // Handle all coefficients + for (int i = 0; i < blockSize; i++) + { + int temp = c[cPos++] * rValue + (int)r[rPos] * RSQ; + r[rPos++] = montgomery_reduce(temp); + } + } + + /** + * Final scaling for multiplication only (basemul) + */ + private void finalizeMultiplication(short[] r, int rPos, int blockSize) + { + for (int i = 0; i < blockSize; i++) + { + r[rPos] = montgomery_reduce((int)r[rPos++] * RSQ); + } + } + + /** + * Deterministic KEM encapsulation + */ + public void crypto_kem_enc_derand(byte[] ct, int ctPos, byte[] ss, int ssPos, + byte[] pk, int pkPos, byte[] coins, int coinsPos) + { + byte[] msg = new byte[eighthN + SSBytes]; + byte[] buf1 = new byte[SSBytes + quarterN]; + byte[] buf2 = new byte[polyBytes]; + + short[] c = new short[n]; + short[] h = new short[n]; + short[] r = new short[n]; + short[] m = new short[n]; + + // Copy first n/8 bytes of coins to msg + System.arraycopy(coins, coinsPos, msg, 0, eighthN); + + // Compute hash_f of pk and store in remaining part of msg + shake256(msg, eighthN, 32, hash_f_domain, pk, pkPos, polyBytes); + + // Compute hash_h of msg, result in buf1 + shake256(buf1, 0, buf1.length, hash_h_domain, msg, 0, msg.length); + // Generate r from second part of buf1 + poly_cbd1(r, buf1, SSBytes); + poly_ntt(r); + + // Convert r to bytes and then hash_g + poly_tobytes(buf2, 0, r); + shake256(buf2, 0, quarterN, hash_g_domain, buf2, 0, polyBytes); + + // Generate m by encoding msg and buf2 + poly_sotp_encode(m, msg, buf2); + poly_ntt(m); + + // Convert pk to polynomial h + poly_frombytes(h, pk, pkPos); + + // Compute c = h*r + m in NTT domain + poly_basemul_add(c, h, r, m); + + // Convert c to ciphertext + poly_tobytes(ct, ctPos, c); + + // Copy first ssBytes of buf1 to ss + System.arraycopy(buf1, 0, ss, ssPos, SSBytes); + } + + /** + * Updated SHAKE256 with offsets + */ + private void shake256(byte[] output, int outOff, int outLen, byte domainSeperation, byte[] input, int inOff, int inLen) + { + shakeDigest.update(domainSeperation); + shakeDigest.update(input, inOff, inLen); + shakeDigest.doFinal(output, outOff, outLen); + } + + /** + * Inverse number-theoretic transform (NTT) in R_q. + * Transforms the NTT representation back to the coefficient representation in R_q. + *

    + * Supports: + * - N=768: 4-coefficient blocks, step 4-64, 384-block processing + * - N=864: 3-coefficient blocks, step 3-24, multiplication by 3 in second loop + * - N=1152: 4-coefficient blocks, step 4-32, multiplication by 3 in second loop + * + * @param r Output vector (coefficient representation) + */ + private void poly_invntt(short[] r) + { + short t1, t2, t3; + short zeta1, zeta2; + short a1, a2; + int k; + if (n == 768) + { + a1 = (short)-811; + a2 = (short)-1622; + k = 191; + } + else + { + a1 = (short)-1693; + a2 = (short)71; + k = 287; + } + + int minStep = params.getMinStep(); + int baseStep = params.getBaseStep(); + for (; minStep <= baseStep; minStep <<= 1) + { + for (int start = 0; start < n; start += (minStep << 1)) + { + zeta1 = zetas[k--]; + for (int i = start, pos = start + minStep; i < start + minStep; i++, pos++) + { + t1 = r[pos]; + r[pos] = fqmul(zeta1, (short)(t1 - r[i])); + r[i] = barrett_reduce((short)(r[i] + t1)); + } + } + } + for (int step = baseStep << 1; step <= n / 6; step *= 3) + { + int twoStep = step << 1; + for (int start = 0; start < n; start += 3 * step) + { + zeta2 = zetas[k--]; + zeta1 = zetas[k--]; + + for (int i = start, pos1 = start + step, pos2 = start + twoStep; i < start + step; i++, pos1++, pos2++) + { + t1 = fqmul(OMEGA, (short)(r[pos1] - r[i])); + t2 = fqmul(zeta1, (short)(r[pos2] - r[i] + t1)); + t3 = fqmul(zeta2, (short)(r[pos2] - r[pos1] - t1)); + + r[i] = barrett_reduce((short)(r[i] + r[pos1] + r[pos2])); + r[pos1] = t2; + r[pos2] = t3; + } + } + } + + for (int i = 0; i < halfN; i++) + { + t1 = (short)(r[i] + r[i + halfN]); + t2 = fqmul((short)-1665, (short)(r[i] - r[i + halfN])); + r[i] = fqmul(a1, (short)(t1 - t2)); + r[i + halfN] = fqmul(a2, t2); + } + } + + /** + * Compute modulus 3 operation to polynomial + */ + private void poly_crepmod3(short[] r, short[] a) + { + for (int i = 0; i < n; i++) + { + r[i] = crepmod3(a[i]); + } + } + + /** + * Compute modulus 3 operation + */ + private short crepmod3(short a) + { + short t; + final short v = (short)(((1 << 15) + 1) / 3); + + // Reduce a to range [0, q-1] + // Center around 0: subtract (q+1)/2 + a += (short)(((a >> 15) & Q) - QPlus1_Half); + // If negative, add q back + // Subtract (q-1)/2 to get centered around 0 + a += (short)(((a >> 15) & Q) - QMinus1_Half); + + // Barrett reduction for mod 3 + t = (short)((v * a + (1 << 14)) >> 15); + t *= 3; + return (short)(a - t); + } + + /** + * Subtract two polynomials; no modular reduction is performed + */ + private void poly_sub(short[] r, short[] a, short[] b) + { + for (int i = 0; i < n; ++i) + { + r[i] = (short)(a[i] - b[i]); + } + } + + /** + * Decode a message using SOTP_INV and a random + */ + private int poly_sotp_decode(byte[] msg, short[] a, byte[] buf) + { + int r = 0; + byte mask; + + for (int i = 0; i < eighthN; i++) + { + int t1 = buf[i] & 0xFF; // Convert to unsigned + int t2 = buf[i + eighthN] & 0xFF; + byte t3 = 0; + + for (int j = 0; j < 8; j++) + { + int t4 = t2 & 0x1; + t4 += a[8 * i + j]; + r |= t4; + t4 = (t4 ^ t1) & 0x1; + t3 ^= (byte)(t4 << j); + + t1 >>= 1; + t2 >>= 1; + } + + msg[i] = t3; + } + + r = r >> 1; + r = (-r) >> 31; // This is the C trick: -(uint32_t)r) >> 31 + + mask = (byte)(r - 1); + + for (int i = 0; i < eighthN; i++) + { + msg[i] &= mask; + } + + return r; + } + + /** + * Compares two byte arrays for equality in constant time + */ + private int verify(byte[] a, byte[] b, int len) + { + int acc = 0; + + for (int i = 0; i < len; i++) + { + acc |= (a[i] ^ b[i]) & 0xFF; + } + + // Return 0 if equal, 1 otherwise + // Equivalent to: (-(uint64_t)acc) >> 63 + return (acc != 0) ? 1 : 0; + } + + /** + * Performs NTRU+ KEM decapsulation + */ + public void crypto_kem_dec(byte[] ss, int ssPos, byte[] ct, int ctPos, byte[] sk, int skPos) + { + byte[] msg = new byte[eighthN + SSBytes]; + byte[] buf1 = new byte[polyBytes]; + byte[] buf2 = new byte[polyBytes]; + byte[] buf3 = new byte[polyBytes + SSBytes]; + + int fail; + + short[] c = new short[n]; + short[] f = new short[n]; + short[] hinv = new short[n]; + short[] r1 = new short[n]; + short[] r2 = new short[n]; + short[] m1 = new short[n]; + short[] m2 = new short[n]; + + // Load ciphertext and secret key components + poly_frombytes(c, ct, ctPos); + poly_frombytes(f, sk, skPos); + poly_frombytes(hinv, sk, skPos + polyBytes); + + // m1 = c * f + poly_basemul(m1, c, f); + poly_invntt(m1); // Convert from NTT domain + poly_crepmod3(m1, m1); // Reduce mod 3 + + // m2 = NTT(m1) + System.arraycopy(m1, 0, m2, 0, n); + poly_ntt(m2); + + // c = c - m2 + poly_sub(c, c, m2); + + // r2 = c * hinv + poly_basemul(r2, c, hinv); + + // Convert r2 to bytes and hash + poly_tobytes(buf1, 0, r2); + shake256(buf2, 0, quarterN, hash_g_domain, buf1, 0, polyBytes); + + // Decode message + fail = poly_sotp_decode(msg, m1, buf2); + + // Append hash of pk from secret key + System.arraycopy(sk, skPos + 2 * polyBytes, msg, eighthN, SSBytes); + + // Hash H + shake256(buf3, 0, buf3.length, hash_h_domain, msg, 0, msg.length); + + // Generate r1 from second part of buf3 + poly_cbd1(r1, buf3, SSBytes); + poly_ntt(r1); + poly_tobytes(buf2, 0, r1); + + // Verify that buf1 (from r2) equals buf2 (from r1) + fail |= verify(buf1, buf2, polyBytes); + + // Copy shared secret, zeroing on failure + if (fail != 0) + { + Arrays.fill(ss, (byte)0); + } + else + { + System.arraycopy(buf3, 0, ss, ssPos, SSBytes); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKEMExtractor.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKEMExtractor.java new file mode 100644 index 0000000000..fb8ff1971f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKEMExtractor.java @@ -0,0 +1,35 @@ +package org.bouncycastle.pqc.crypto.ntruplus; + +import org.bouncycastle.crypto.EncapsulatedSecretExtractor; + +public class NTRUPlusKEMExtractor + implements EncapsulatedSecretExtractor +{ + private final NTRUPlusPrivateKeyParameters privateKey; + private final NTRUPlusEngine engine; + + public NTRUPlusKEMExtractor(NTRUPlusPrivateKeyParameters privateKey) + { + if (privateKey == null) + { + throw new NullPointerException("'privateKey' cannot be null"); + } + + this.privateKey = privateKey; + this.engine = new NTRUPlusEngine(privateKey.getParameters()); + } + + @Override + public byte[] extractSecret(byte[] encapsulation) + { + byte[] ss = new byte[NTRUPlusEngine.SSBytes]; + engine.crypto_kem_dec(ss, 0, encapsulation, 0, privateKey.getEncoded(), 0); + return ss; + } + + @Override + public int getEncapsulationLength() + { + return privateKey.getParameters().getCiphertextBytes(); + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKEMGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKEMGenerator.java new file mode 100644 index 0000000000..2b4a9b0ce4 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKEMGenerator.java @@ -0,0 +1,33 @@ +package org.bouncycastle.pqc.crypto.ntruplus; + +import java.security.SecureRandom; + +import org.bouncycastle.crypto.EncapsulatedSecretGenerator; +import org.bouncycastle.crypto.SecretWithEncapsulation; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.pqc.crypto.util.SecretWithEncapsulationImpl; + +public class NTRUPlusKEMGenerator + implements EncapsulatedSecretGenerator +{ + private final SecureRandom sr; + + public NTRUPlusKEMGenerator(SecureRandom random) + { + this.sr = random; + } + + @Override + public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recipientKey) + { + NTRUPlusPublicKeyParameters key = (NTRUPlusPublicKeyParameters)recipientKey; + NTRUPlusParameters params = key.getParameters(); + byte[] ct = new byte[params.getCiphertextBytes()]; + byte[] ss = new byte[NTRUPlusEngine.SSBytes]; + NTRUPlusEngine engine = new NTRUPlusEngine(params); + byte[] coins = new byte[params.getN() >> 3]; + sr.nextBytes(coins); + engine.crypto_kem_enc_derand(ct, 0, ss,0, key.getEncoded(), 0, coins, 0); + return new SecretWithEncapsulationImpl(ss, ct); + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKeyGenerationParameters.java new file mode 100644 index 0000000000..2fdaf28694 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKeyGenerationParameters.java @@ -0,0 +1,24 @@ +package org.bouncycastle.pqc.crypto.ntruplus; + +import java.security.SecureRandom; + +import org.bouncycastle.crypto.KeyGenerationParameters; + +public class NTRUPlusKeyGenerationParameters + extends KeyGenerationParameters +{ + private final NTRUPlusParameters params; + + public NTRUPlusKeyGenerationParameters( + SecureRandom random, + NTRUPlusParameters mayoParameters) + { + super(random, 256); + this.params = mayoParameters; + } + + public NTRUPlusParameters getParameters() + { + return params; + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKeyPairGenerator.java new file mode 100644 index 0000000000..3ff44c27b1 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKeyPairGenerator.java @@ -0,0 +1,81 @@ +package org.bouncycastle.pqc.crypto.ntruplus; + +import java.security.SecureRandom; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import org.bouncycastle.crypto.KeyGenerationParameters; + +/** + * Implementation of the NTRU+ asymmetric key pair generator following the NTRU+ KEM specifications. + *

    + * This generator produces {@link NTRUPlusPublicKeyParameters} and {@link NTRUPlusPrivateKeyParameters} + * based on the chosen NTRU+ algorithm parameters. The implementation follows the specification + * defined in the official NTRU+ documentation and reference implementation. + *

    + *

    + * NTRU+ is a key encapsulation mechanism (KEM) and public key encryption (PKE) scheme based on + * structured lattices. It was selected as a final algorithm in the Korean Post-Quantum Cryptography + * Competition (KpqC). + *

    + * + *

    References:

    + * + */ +public class NTRUPlusKeyPairGenerator + implements AsymmetricCipherKeyPairGenerator +{ + private NTRUPlusParameters params; + private SecureRandom random; + + @Override + public void init(KeyGenerationParameters param) + { + this.params = ((NTRUPlusKeyGenerationParameters)param).getParameters(); + this.random = param.getRandom(); + } + + @Override + public AsymmetricCipherKeyPair generateKeyPair() + { + byte[] pk = new byte[params.getPublicKeyBytes()]; + byte[] sk = new byte[params.getSecretKeyBytes()]; + NTRUPlusEngine engine = new NTRUPlusEngine(params); + byte[] coins = new byte[NTRUPlusEngine.SSBytes]; // NTRUPLUS_SYMBYTES + + int n = params.getN(); + // Create polynomial objects + short[] f = new short[n]; + short[] finv = new short[n]; + short[] g = new short[n]; + short[] ginv = new short[n]; + + // Generate f and finv (retry if f is not invertible) + boolean fInvertible; + do + { + // Generate random bytes for the seed + random.nextBytes(coins); + fInvertible = (engine.genf_derand(f, finv, coins) == 0); + } + while (!fInvertible); + + // Generate g and ginv (retry if g is not invertible) + boolean gInvertible; + do + { + // Generate new random bytes for the seed + random.nextBytes(coins); + gInvertible = (engine.geng_derand(g, ginv, coins) == 0); + } + while (!gInvertible); + + // Generate the actual key pair using the derived polynomials + engine.crypto_kem_keypair_derand(pk, sk, f, finv, g, ginv); + return new AsymmetricCipherKeyPair(new NTRUPlusPublicKeyParameters(params, pk), new NTRUPlusPrivateKeyParameters(params, sk)); + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKeyParameters.java new file mode 100644 index 0000000000..2bb2dec810 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusKeyParameters.java @@ -0,0 +1,23 @@ +package org.bouncycastle.pqc.crypto.ntruplus; + +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; + +public class NTRUPlusKeyParameters + extends AsymmetricKeyParameter +{ + private final NTRUPlusParameters params; + + public NTRUPlusKeyParameters( + boolean isPrivate, + NTRUPlusParameters params) + { + super(isPrivate); + this.params = params; + } + + public NTRUPlusParameters getParameters() + { + return params; + } +} + diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusParameters.java new file mode 100644 index 0000000000..6ebdc14c03 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusParameters.java @@ -0,0 +1,175 @@ +package org.bouncycastle.pqc.crypto.ntruplus; + +public class NTRUPlusParameters +{ + private static final short[] zetas768 = new short[]{ + -147, -1033, -682, -248, -708, 682, 1, -722, + -723, -257, -1124, -867, -256, 1484, 1262, -1590, + 1611, 222, 1164, -1346, 1716, -1521, -357, 395, + -455, 639, 502, 655, -699, 541, 95, -1577, + -1241, 550, -44, 39, -820, -216, -121, -757, + -348, 937, 893, 387, -603, 1713, -1105, 1058, + 1449, 837, 901, 1637, -569, -1617, -1530, 1199, + 50, -830, -625, 4, 176, -156, 1257, -1507, + -380, -606, 1293, 661, 1428, -1580, -565, -992, + 548, -800, 64, -371, 961, 641, 87, 630, + 675, -834, 205, 54, -1081, 1351, 1413, -1331, + -1673, -1267, -1558, 281, -1464, -588, 1015, 436, + 223, 1138, -1059, -397, -183, 1655, 559, -1674, + 277, 933, 1723, 437, -1514, 242, 1640, 432, + -1583, 696, 774, 1671, 927, 514, 512, 489, + 297, 601, 1473, 1130, 1322, 871, 760, 1212, + -312, -352, 443, 943, 8, 1250, -100, 1660, + -31, 1206, -1341, -1247, 444, 235, 1364, -1209, + 361, 230, 673, 582, 1409, 1501, 1401, 251, + 1022, -1063, 1053, 1188, 417, -1391, -27, -1626, + 1685, -315, 1408, -1248, 400, 274, -1543, 32, + -1550, 1531, -1367, -124, 1458, 1379, -940, -1681, + 22, 1709, -275, 1108, 354, -1728, -968, 858, + 1221, -218, 294, -732, -1095, 892, 1588, -779 + }; + + private static final short[] zetas864_1152 = new short[]{ + -147, -1033, -1265, 708, 460, 1265, -467, 727, + 556, 1307, -773, -161, 1200, -1612, 570, 1529, + 1135, -556, 1120, 298, -822, -1556, -93, 1463, + 532, -377, -909, 58, -392, -450, 1722, 1236, + -486, -491, -1569, -1078, 36, 1289, -1443, 1628, + 1664, -725, -952, 99, -1020, 353, -599, 1119, + 592, 839, 1622, 652, 1244, -783, -1085, -726, + 566, -284, -1369, -1292, 268, -391, 781, -172, + 96, -1172, 211, 737, 473, -445, -234, 264, + -1536, 1467, -676, -1542, -170, 635, -705, -1332, + -658, 831, -1712, 1311, 1488, -881, 1087, -1315, + 1245, -75, 791, -6, -875, -697, -70, -1162, + 287, -767, -945, 1598, -882, 1261, 206, 654, + -1421, -81, 716, -1251, 838, -1300, 1035, -104, + 966, -558, -61, -1704, 404, -899, 862, -1593, + -1460, -37, 1266, 965, -1584, -1404, -265, -942, + 905, 1195, -619, 787, 118, 576, 286, -1475, + -194, 928, 1229, -1032, 1608, 1111, -1669, 642, + -1323, 163, 309, 981, -557, -258, 232, -1680, + -1657, -1233, 144, 1699, 311, -1060, 578, 1298, + -403, 1607, 1074, -148, 447, -1568, 1142, -402, + -1412, -623, 855, 365, -98, -244, 407, 1225, + 416, 683, -105, 1714, -1019, 1061, 1163, 638, + 798, 1493, -351, 396, -542, -9, 1616, -139, + -987, -482, 889, 238, -1513, 466, -1089, -101, + 849, -426, 1589, 1487, 671, 1459, -776, 255, + -1014, 1144, 472, -1153, -325, 1519, -26, -1123, + 324, 1230, 1547, -593, -428, 1192, 1072, -1564, + 688, -333, 1023, -1686, 841, 824, -71, 1587, + 522, -323, 1148, 389, 1231, 384, 1343, 169, + 628, -1329, -1056, -936, 24, -293, 1523, -300, + -1654, 891, -962, -67, 179, -1177, 844, -509, + -1677, -1565, -549, -1508, 1191, -280, -43, 669, + -746, 753, 770, -1046, 1711, 1438, 690, 1083, + 1062, 1727, -883, 553, 1670, 66, 825, -133, + -1586, 637, -680, -917, 644, -372, -1193, -1136 + }; + + // Parameter sets for different security levels + public static final NTRUPlusParameters ntruplus_kem_768 = new NTRUPlusParameters( + "NTRU+KEM768", // name + 768, // NTRUPLUS_N + 1152, // NTRUPLUS_PUBLICKEYBYTES + 4, + 64, + 96, + zetas768 + ); + + public static final NTRUPlusParameters ntruplus_kem_864 = new NTRUPlusParameters( + "NTRU+KEM864", // name + 864, // NTRUPLUS_N + 1296, // NTRUPLUS_PUBLICKEYBYTES + 3, + 24, + 144, + zetas864_1152 + ); + + public static final NTRUPlusParameters ntruplus_kem_1152 = new NTRUPlusParameters( + "NTRU+KEM1152", // name + 1152, // NTRUPLUS_N + 1728, // NTRUPLUS_PUBLICKEYBYTES + 4, + 32, + 144, + zetas864_1152 + ); + + // Instance fields + private final String name; + private final int n; // NTRUPLUS_N + private final int publicKeyBytes; // NTRUPLUS_PUBLICKEYBYTES + private final int secretKeyBytes; // NTRUPLUS_SECRETKEYBYTES + private final int minStep; + private final int baseStep; + private final int zetasOffset; + private final short[] zetas; + + + private NTRUPlusParameters(String name, int n, int publicKeyBytes, int minStep, int baseStep, int zetasOffset, short[] zetas) + { + this.name = name; + this.n = n; + this.publicKeyBytes = publicKeyBytes; + this.secretKeyBytes = (publicKeyBytes << 1) + 32; + this.minStep = minStep; + this.baseStep = baseStep; + this.zetasOffset = zetasOffset; + this.zetas = zetas; + } + + // Getters for all parameters + public String getName() + { + return name; + } + + public int getN() + { + return n; + } + + public int getSsBytes() + { + return 32; + } + + public int getPublicKeyBytes() + { + return publicKeyBytes; + } + + public int getSecretKeyBytes() + { + return secretKeyBytes; + } + + public int getCiphertextBytes() + { + return publicKeyBytes; + } + + public short[] getZetas() + { + return zetas; + } + + int getBaseStep() + { + return baseStep; + } + + int getMinStep() + { + return minStep; + } + + int getZetasOffset() + { + return zetasOffset; + } +} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusPrivateKeyParameters.java new file mode 100644 index 0000000000..fa2b3c0716 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusPrivateKeyParameters.java @@ -0,0 +1,20 @@ +package org.bouncycastle.pqc.crypto.ntruplus; + +import org.bouncycastle.util.Arrays; + +public class NTRUPlusPrivateKeyParameters + extends NTRUPlusKeyParameters +{ + private final byte[] sk; + + public NTRUPlusPrivateKeyParameters(NTRUPlusParameters params, byte[] sk) + { + super(true, params); + this.sk = Arrays.clone(sk); + } + + public byte[] getEncoded() + { + return Arrays.clone(sk); + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusPublicKeyParameters.java new file mode 100644 index 0000000000..4fdfab9907 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruplus/NTRUPlusPublicKeyParameters.java @@ -0,0 +1,20 @@ +package org.bouncycastle.pqc.crypto.ntruplus; + +import org.bouncycastle.util.Arrays; + +public class NTRUPlusPublicKeyParameters + extends NTRUPlusKeyParameters +{ + private final byte[] p; + + public NTRUPlusPublicKeyParameters(NTRUPlusParameters params, byte[] p) + { + super(false, params); + this.p = Arrays.clone(p); + } + + public byte[] getEncoded() + { + return Arrays.clone(p); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntruprime/SNTRUPrimeKEMExtractor.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruprime/SNTRUPrimeKEMExtractor.java index 319c4e65b2..7d82576c48 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntruprime/SNTRUPrimeKEMExtractor.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruprime/SNTRUPrimeKEMExtractor.java @@ -10,6 +10,11 @@ public class SNTRUPrimeKEMExtractor public SNTRUPrimeKEMExtractor(SNTRUPrimePrivateKeyParameters privateKey) { + if (privateKey == null) + { + throw new NullPointerException("'privateKey' cannot be null"); + } + this.privateKey = privateKey; } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntruprime/SNTRUPrimeKEMGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruprime/SNTRUPrimeKEMGenerator.java index 9f1923260e..ba97f204f0 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntruprime/SNTRUPrimeKEMGenerator.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntruprime/SNTRUPrimeKEMGenerator.java @@ -2,6 +2,7 @@ import java.security.SecureRandom; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.EncapsulatedSecretGenerator; import org.bouncycastle.crypto.SecretWithEncapsulation; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; @@ -15,7 +16,7 @@ public class SNTRUPrimeKEMGenerator public SNTRUPrimeKEMGenerator(SecureRandom random) { - this.random = random; + this.random = CryptoServicesRegistrar.getSecureRandom(random); } @Override diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/Fors.java b/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/Fors.java index 3123c56fba..e92d5c6aaa 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/Fors.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/Fors.java @@ -70,8 +70,8 @@ public SIG_FORS[] sign(byte[] md, byte[] skSeed, byte[] pkSeed, ADRS paramAdrs) // int[] idxs = message_to_idxs(md, engine.K, engine.A); int[] idxs = base2B(md, engine.A, engine.K); SIG_FORS[] sig_fors = new SIG_FORS[engine.K]; + // compute signature elements - int t = engine.T; for (int i = 0; i < engine.K; i++) { // get next index @@ -80,7 +80,7 @@ public SIG_FORS[] sign(byte[] md, byte[] skSeed, byte[] pkSeed, ADRS paramAdrs) adrs.setTypeAndClear(ADRS.FORS_PRF); adrs.setKeyPairAddress(paramAdrs.getKeyPairAddress()); adrs.setTreeHeight(0); - adrs.setTreeIndex(i * t + idx); + adrs.setTreeIndex((i << engine.A) + idx); byte[] sk = engine.PRF(pkSeed, skSeed, adrs); @@ -90,8 +90,8 @@ public SIG_FORS[] sign(byte[] md, byte[] skSeed, byte[] pkSeed, ADRS paramAdrs) // compute auth path for (int j = 0; j < engine.A; j++) { - int s = (idx / (1 << j)) ^ 1; - authPath[j] = treehash(skSeed, i * t + s * (1 << j), j, pkSeed, adrs); + int s = (idx >>> j) ^ 1; + authPath[j] = treehash(skSeed, (i << engine.A) + (s << j), j, pkSeed, adrs); } sig_fors[i] = new SIG_FORS(sk, authPath); } @@ -102,7 +102,6 @@ public byte[] pkFromSig(SIG_FORS[] sig_fors, byte[] message, byte[] pkSeed, ADRS { byte[][] node = new byte[2][]; byte[][] root = new byte[engine.K][]; - int t = engine.T; // int[] idxs = message_to_idxs(message, engine.K, engine.A); int[] idxs = base2B(message, engine.A, engine.K); @@ -114,16 +113,16 @@ public byte[] pkFromSig(SIG_FORS[] sig_fors, byte[] message, byte[] pkSeed, ADRS // compute leaf byte[] sk = sig_fors[i].getSK(); adrs.setTreeHeight(0); - adrs.setTreeIndex(i * t + idx); + adrs.setTreeIndex((i << engine.A) + idx); node[0] = engine.F(pkSeed, adrs, sk); // compute root from leaf and AUTH byte[][] authPath = sig_fors[i].getAuthPath(); - adrs.setTreeIndex(i * t + idx); + adrs.setTreeIndex((i << engine.A) + idx); for (int j = 0; j < engine.A; j++) { adrs.setTreeHeight(j + 1); - if (((idx / (1 << j)) % 2) == 0) + if ((idx & (1 << j)) == 0) { adrs.setTreeIndex(adrs.getTreeIndex() / 2); node[1] = engine.H(pkSeed, adrs, node[0], authPath[j]); diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/HT.java b/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/HT.java index 8bf4c0440c..698f53238d 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/HT.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/HT.java @@ -101,7 +101,7 @@ byte[] xmss_pkFromSig(int idx, SIG_XMSS sig_xmss, byte[] M, byte[] pkSeed, ADRS for (int k = 0; k < engine.H_PRIME; k++) { adrs.setTreeHeight(k + 1); - if (((idx / (1 << k)) % 2) == 0) + if ((idx & (1 << k)) == 0) { adrs.setTreeIndex(adrs.getTreeIndex() / 2); node1 = engine.H(pkSeed, adrs, node0, AUTH[k]); diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/HashSLHDSASigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/HashSLHDSASigner.java index 16a725bd93..7ae5c71e7b 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/HashSLHDSASigner.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/HashSLHDSASigner.java @@ -19,7 +19,7 @@ import org.bouncycastle.util.Arrays; /** - * SLH-DA signer. + * SLH-DSA signer. */ public class HashSLHDSASigner implements Signer diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/SLHDSAEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/SLHDSAEngine.java index 58c8d8b765..8f0cc44d45 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/SLHDSAEngine.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/SLHDSAEngine.java @@ -30,8 +30,6 @@ abstract class SLHDSAEngine final int H; // FULL_HEIGHT final int H_PRIME; // H / D - final int T; // T = 1 << A - public SLHDSAEngine(int n, int w, int d, int a, int k, int h) { this.N = n; @@ -87,7 +85,6 @@ else if (N <= 256) this.K = k; this.H = h; this.H_PRIME = h / d; - this.T = 1 << a; } abstract void init(byte[] pkSeed); diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/SLHDSASigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/SLHDSASigner.java index ff3ad48583..7b53fc311e 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/SLHDSASigner.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/slhdsa/SLHDSASigner.java @@ -9,7 +9,7 @@ import org.bouncycastle.util.Arrays; /** - * SLH-DA signer. + * SLH-DSA signer. *

    * This version is based on the 3rd submission with deference to the updated reference * implementation on github as at November 9th 2021. This version includes the changes diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java new file mode 100644 index 0000000000..2da96b17c2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/GF16Utils.java @@ -0,0 +1,209 @@ +package org.bouncycastle.pqc.crypto.snova; + +import org.bouncycastle.util.GF16; + +class GF16Utils +{ + static void encodeMergeInHalf(byte[] m, int mlen, byte[] menc) + { + int i, half = (mlen + 1) >>> 1; + // Process pairs of 4-bit values + for (i = 0; i < mlen / 2; i++, half++) + { + menc[i] = (byte)(m[i] | (m[half] << 4)); + } + // If there is an extra nibble (odd number of nibbles), store it directly in lower 4 bits. + if ((mlen & 1) == 1) + { + menc[i] = m[i]; + } + } + + static void decodeMergeInHalf(byte[] byteArray, byte[] gf16Array, int nGf16) + { + int i, half = (nGf16 + 1) >>> 1; + // Process pairs of 4-bit values + for (i = 0; i < half; i++) + { + gf16Array[i] = (byte)(byteArray[i] & 0x0F); + gf16Array[i + half] = (byte)((byteArray[i] >>> 4) & 0x0F); + } + } + + static void gf16mTranMulMul(byte[] sign, int signOff, byte[] a, byte[] b, byte[] q1, byte[] q2, byte[] tmp, + byte[] left, byte[] right, int rank) + { + for (int i = 0, leftOff = 0, dOff = 0; i < rank; i++, leftOff += rank) + { + for (int j = 0; j < rank; j++) + { + byte result = 0; + for (int k = 0, aOff = signOff + j, bOff = i; k < rank; ++k, aOff += rank, bOff += rank) + { + result ^= GF16.mul(sign[aOff], q1[bOff]); + } + tmp[j] = result; + } + + for (int j = 0, jxl = 0; j < rank; j++, jxl += rank) + { + byte result = 0; + for (int k = 0; k < rank; ++k) + { + result ^= GF16.mul(a[jxl + k], tmp[k]); + } + left[i + jxl] = result; + } + for (int j = 0; j < rank; j++) + { + tmp[j] = GF16.innerProduct(q2, leftOff, sign, signOff + j, rank); + } + + for (int j = 0; j < rank; j++) + { + right[dOff++] = GF16.innerProduct(tmp, 0, b, j, rank); + } + } + } + + // tmp = a * b, d = tmp * c -> d = (a * b) * c + static void gf16mMulMul(byte[] a, byte[] b, byte[] c, byte[] tmp, byte[] d, int rank) + { + for (int i = 0, leftOff = 0, dOff = 0; i < rank; i++, leftOff += rank) + { + for (int j = 0; j < rank; j++) + { + tmp[j] = GF16.innerProduct(a, leftOff, b, j, rank); + } + + for (int j = 0; j < rank; j++) + { + d[dOff++] = GF16.innerProduct(tmp, 0, c, j, rank); + } + } + } + + static void gf16mMul(byte[] a, byte[] b, byte[] c, int rank) + { + for (int i = 0, aOff = 0, cOff = 0; i < rank; i++, aOff += rank) + { + for (int j = 0; j < rank; j++) + { + c[cOff++] = GF16.innerProduct(a, aOff, b, j, rank); + } + } + } + + static void gf16mMulMulTo(byte[] a, byte[] b, byte[] c, byte[] tmp, byte[] d, int rank) + { + for (int i = 0, leftOff = 0, dOff = 0; i < rank; i++, leftOff += rank) + { + for (int j = 0; j < rank; j++) + { + tmp[j] = GF16.innerProduct(a, leftOff, b, j, rank); + } + + for (int j = 0; j < rank; j++) + { + d[dOff++] ^= GF16.innerProduct(tmp, 0, c, j, rank); + } + } + } + + static void gf16mMulTo(byte[] a, byte[] b, byte[] c, int rank) + { + for (int i = 0, aOff = 0, cOff = 0; i < rank; i++, aOff += rank) + { + for (int j = 0; j < rank; j++) + { + c[cOff++] ^= GF16.innerProduct(a, aOff, b, j, rank); + } + } + } + + // d = a * b, e = b * c + static void gf16mMulToTo(byte[] a, byte[] b, byte[] c, byte[] d, byte[] e, int rank) + { + for (int i = 0, leftOff = 0, outOff = 0; i < rank; i++, leftOff += rank) + { + for (int j = 0; j < rank; j++) + { + d[outOff] ^= GF16.innerProduct(a, leftOff, b, j, rank); + e[outOff++] ^= GF16.innerProduct(b, leftOff, c, j, rank); + } + } + } + + static void gf16mMulTo(byte[] a, byte[] b, byte[] c, int cOff, int rank) + { + for (int i = 0, aOff = 0; i < rank; i++, aOff += rank) + { + for (int j = 0; j < rank; j++) + { + c[cOff++] ^= GF16.innerProduct(a, aOff, b, j, rank); + } + } + } + + // d ^= a * b + c * d + static void gf16mMulTo(byte[] a, byte[] b, byte[] c, byte[] d, byte[] e, int eOff, int rank) + { + for (int i = 0, leftOff = 0; i < rank; i++, leftOff += rank) + { + for (int j = 0; j < rank; j++) + { + e[eOff++] ^= GF16.innerProduct(a, leftOff, b, j, rank) ^ GF16.innerProduct(c, leftOff, d, j, rank); + } + } + } + + static void gf16mMulTo(byte[] a, byte[] b, int bOff, byte[] c, int cOff, int rank) + { + for (int i = 0, aOff = 0; i < rank; i++, aOff += rank) + { + for (int j = 0; j < rank; j++) + { + c[cOff++] ^= GF16.innerProduct(a, aOff, b, bOff + j, rank); + } + } + } + + /** + * Conversion 4 bit -> 32 bit representation + */ + static int gf16FromNibble(int idx) + { + int middle = idx | (idx << 4); + return ((middle & 0x41) | ((middle << 2) & 0x208)); + } + + private static final int GF16_MASK = 0x249; // Mask for GF(2^4) reduction + + // Constant-time GF16 != 0 check + static int ctGF16IsNotZero(byte val) + { + int v = val & 0xFF; + return (v | (v >>> 1) | (v >>> 2) | (v >>> 3)) & 1; + } + + // GF16 reduction modulo x^4 + x + 1 + private static int gf16Reduce(int idx) + { + int res = idx & 0x49249249; + int upper = idx >>> 12; + res ^= upper ^ (upper << 3); + upper = res >>> 12; + res ^= upper ^ (upper << 3); + upper = res >>> 12; + res ^= upper ^ (upper << 3); + return res & GF16_MASK; + } + + // Convert 32-bit reduced value to 4-bit nibble + static byte gf16ToNibble(int val) + { + int res = gf16Reduce(val); + res |= res >>> 4; + return (byte)((res & 0x5) | ((res >>> 2) & 0xA)); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java new file mode 100644 index 0000000000..ff4e7531ee --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup1.java @@ -0,0 +1,118 @@ +package org.bouncycastle.pqc.crypto.snova; + +import org.bouncycastle.util.GF16; + +class MapGroup1 +{ + public final byte[][][][] p11; // [m][v][v] + public final byte[][][][] p12; // [m][v][o] + public final byte[][][][] p21; // [m][o][v] + public final byte[][][] aAlpha; // [m][alpha] + public final byte[][][] bAlpha; // [m][alpha] + public final byte[][][] qAlpha1;// [m][alpha] + public final byte[][][] qAlpha2;// [m][alpha] + + public MapGroup1(SnovaParameters params) + { + int m = params.getM(); + int v = params.getV(); + int o = params.getO(); + int alpha = params.getAlpha(); + int lsq = params.getLsq(); + p11 = new byte[m][v][v][lsq]; + p12 = new byte[m][v][o][lsq]; + p21 = new byte[m][o][v][lsq]; + aAlpha = new byte[m][alpha][lsq]; + bAlpha = new byte[m][alpha][lsq]; + qAlpha1 = new byte[m][alpha][lsq]; + qAlpha2 = new byte[m][alpha][lsq]; + } + + void decode(byte[] input, int len, boolean isl4or5) + { + //TODO: when (lsq & 1) == 1 + int inOff = decodeP(input, 0, p11, len); + inOff += decodeP(input, inOff, p12, len - inOff); + inOff += decodeP(input, inOff, p21, len - inOff); + if (isl4or5) + { + inOff += decodeAlpha(input, inOff, aAlpha, len - inOff); + inOff += decodeAlpha(input, inOff, bAlpha, len - inOff); + inOff += decodeAlpha(input, inOff, qAlpha1, len - inOff); + decodeAlpha(input, inOff, qAlpha2, len - inOff); + } + } + + static int decodeP(byte[] input, int inOff, byte[][][][] p, int len) + { + int rlt = 0; + for (int i = 0; i < p.length; ++i) + { + rlt += decodeAlpha(input, inOff + rlt, p[i], len); + } + return rlt; + } + + private static int decodeAlpha(byte[] input, int inOff, byte[][][] alpha, int len) + { + int rlt = 0; + for (int i = 0; i < alpha.length; ++i) + { + rlt += decodeArray(input, inOff + rlt, alpha[i], len - rlt); + } + return rlt; + } + + static int decodeArray(byte[] input, int inOff, byte[][] array, int len) + { + int rlt = 0; + for (int j = 0; j < array.length; ++j) + { + int tmp = Math.min(array[j].length, len << 1); + GF16.decode(input, inOff + rlt, array[j], 0, tmp); + tmp = (tmp + 1) >> 1; + rlt += tmp; + len -= tmp; + } + return rlt; + } + + void fill(byte[] input, boolean isl4or5) + { + int inOff = fillP(input, 0, p11, input.length); + inOff += fillP(input, inOff, p12, input.length - inOff); + inOff += fillP(input, inOff, p21, input.length - inOff); + if (isl4or5) + { + inOff += fillAlpha(input, inOff, aAlpha, input.length - inOff); + inOff += fillAlpha(input, inOff, bAlpha, input.length - inOff); + inOff += fillAlpha(input, inOff, qAlpha1, input.length - inOff); + fillAlpha(input, inOff, qAlpha2, input.length - inOff); + } + } + + static int fillP(byte[] input, int inOff, byte[][][][] p, int len) + { + int rlt = 0; + for (int i = 0; i < p.length; ++i) + { + rlt += fillAlpha(input, inOff + rlt, p[i], len - rlt); + } + return rlt; + } + + static int fillAlpha(byte[] input, int inOff, byte[][][] alpha, int len) + { + int rlt = 0; + for (int i = 0; i < alpha.length; ++i) + { + for (int j = 0; j < alpha[i].length; ++j) + { + int tmp = Math.min(alpha[i][j].length, len - rlt); + System.arraycopy(input, inOff + rlt, alpha[i][j], 0, tmp); + rlt += tmp; + } + } + return rlt; + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup2.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup2.java new file mode 100644 index 0000000000..946ad2ab99 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/MapGroup2.java @@ -0,0 +1,19 @@ +package org.bouncycastle.pqc.crypto.snova; + +class MapGroup2 +{ + public final byte[][][][] f11; // [m][v][v] + public final byte[][][][] f12; // [m][v][o] + public final byte[][][][] f21; // [m][o][v] + + public MapGroup2(SnovaParameters params) + { + int m = params.getM(); + int v = params.getV(); + int o = params.getO(); + int lsq = params.getLsq(); + f11 = new byte[m][v][v][lsq]; + f12 = new byte[m][v][o][lsq]; + f21 = new byte[m][o][v][lsq]; + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java new file mode 100644 index 0000000000..1651dab43d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaEngine.java @@ -0,0 +1,587 @@ +package org.bouncycastle.pqc.crypto.snova; + +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.crypto.digests.SHAKEDigest; +import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.modes.CTRModeCipher; +import org.bouncycastle.crypto.modes.SICBlockCipher; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.GF16; +import org.bouncycastle.util.Integers; +import org.bouncycastle.util.Pack; + +class SnovaEngine +{ + private final static Map fixedAbqSet = new HashMap();//key is o + private final static Map sSet = new HashMap(); //key is l + private final static Map xSSet = new HashMap(); //key is l + private final SnovaParameters params; + private final int l; + private final int lsq; + private final int m; + private final int v; + private final int o; + private final int alpha; + private final int n; + final byte[][] S; + final int[][] xS; + + public SnovaEngine(SnovaParameters params) + { + this.params = params; + this.l = params.getL(); + this.lsq = params.getLsq(); + this.m = params.getM(); + this.v = params.getV(); + this.o = params.getO(); + this.alpha = params.getAlpha(); + this.n = params.getN(); + if (!xSSet.containsKey(Integers.valueOf(l))) + { + byte[][] S = new byte[l][lsq]; + int[][] xS = new int[l][lsq]; + be_aI(S[0], 0, (byte)1); + beTheS(S[1]); + for (int index = 2; index < l; ++index) + { + GF16Utils.gf16mMul(S[index - 1], S[1], S[index], l); + } + + for (int index = 0; index < l; ++index) + { + for (int ij = 0; ij < lsq; ++ij) + { + xS[index][ij] = GF16Utils.gf16FromNibble(S[index][ij]); + } + } + sSet.put(Integers.valueOf(l), S); + xSSet.put(Integers.valueOf(l), xS); + } + S = (byte[][])sSet.get(Integers.valueOf(l)); + xS = (int[][])xSSet.get(Integers.valueOf(l)); + if (l < 4 && !fixedAbqSet.containsKey(Integers.valueOf(o))) + { + int alphaxl = alpha * l; + int alphaxlsq = alphaxl * l; + int oxalphaxl = o * alphaxl; + int oxalphaxlsq = o * alphaxlsq; + byte[] fixedAbq = new byte[oxalphaxlsq << 2]; + byte[] rngOut = new byte[oxalphaxlsq + oxalphaxl]; + byte[] q12 = new byte[oxalphaxl << 2]; + byte[] seed = "SNOVA_ABQ".getBytes(); + SHAKEDigest shake = new SHAKEDigest(256); + shake.update(seed, 0, seed.length); + shake.doFinal(rngOut, 0, rngOut.length); + GF16.decode(rngOut, fixedAbq, oxalphaxlsq << 1); + GF16.decode(rngOut, alphaxlsq, q12, 0, oxalphaxl << 1); + // Post-processing for invertible matrices + for (int pi = 0, pixAlphaxlsq = 0, pixalphaxl = 0; pi < o; ++pi, pixAlphaxlsq += alphaxlsq, pixalphaxl += alphaxl) + { + for (int a = 0, axl = pixalphaxl, axlsq = pixAlphaxlsq; a < alpha; ++a, axl += l, axlsq += lsq) + { + makeInvertibleByAddingAS(fixedAbq, axlsq); + makeInvertibleByAddingAS(fixedAbq, oxalphaxlsq + axlsq); + genAFqS(q12, axl, fixedAbq, (oxalphaxlsq << 1) + axlsq); + genAFqS(q12, oxalphaxl + axl, fixedAbq, (oxalphaxlsq << 1) + oxalphaxlsq + axlsq); + } + } + fixedAbqSet.put(Integers.valueOf(o), fixedAbq); + } + } + + private void beTheS(byte[] target) + { + // Set all elements to 8 - (i + j) in GF16 (4-bit values) + for (int i = 0, il = 0; i < l; ++i, il += l) + { + for (int j = 0; j < l; ++j) + { + int value = 8 - (i + j); + target[il + j] = (byte)(value & 0x0F); // Mask to 4 bits + } + } + + // Special case for rank 5 + if (l == 5) + { + target[24] = (byte)9; // Set (4,4) to 9 + } + } + + private void be_aI(byte[] target, int off, byte a) + { + // Ensure 'a' iss a valid 4-bit GF16 element + int l1 = l + 1; + for (int i = 0; i < l; ++i, off += l1) + { + target[off] = a; + } + } + + // Constant-time GF16 matrix generation + private void genAFqSCT(byte[] c, int cOff, byte[] ptMatrix) + { + int[] xTemp = new int[lsq]; + int l1 = l + 1; + // Initialize diagonal with c[0] + int cX = GF16Utils.gf16FromNibble(c[cOff]); + for (int ij = 0, ijl1 = 0; ij < l; ij++, ijl1 += l1) + { + xTemp[ijl1] = cX; + } + + // Process middle coefficients + for (int i1 = 1; i1 < l - 1; i1++) + { + cX = GF16Utils.gf16FromNibble(c[cOff + i1]); + for (int ij = 0; ij < lsq; ij++) + { + xTemp[ij] ^= cX * xS[i1][ij]; + } + } + + // Handle last coefficient with constant-time selection + int zero = GF16Utils.ctGF16IsNotZero(c[cOff + l - 1]); + int val = zero * c[cOff + l - 1] + (1 - zero) * (15 + GF16Utils.ctGF16IsNotZero(c[cOff]) - c[cOff]); + cX = GF16Utils.gf16FromNibble((byte)val); + + for (int ij = 0; ij < lsq; ij++) + { + xTemp[ij] ^= cX * xS[l - 1][ij]; + ptMatrix[ij] = GF16Utils.gf16ToNibble(xTemp[ij]); + } + Arrays.fill(xTemp, 0); // Secure clear + } + + private void makeInvertibleByAddingAS(byte[] source, int off) + { + if (gf16Determinant(source, off) != 0) + { + return; + } + + for (int a = 1; a < 16; a++) + { + generateASMatrixTo(source, off, (byte)a); + + if (gf16Determinant(source, off) != 0) + { + return; + } + } + } + + private byte gf16Determinant(byte[] matrix, int off) + { + switch (l) + { + case 2: + return determinant2x2(matrix, off); + case 3: + return determinant3x3(matrix, off); + case 4: + return determinant4x4(matrix, off); + case 5: + return determinant5x5(matrix, off); + default: + throw new IllegalStateException(); + } + } + + private byte determinant2x2(byte[] m, int off) + { + return (byte)(GF16.mul(m[off], m[off + 3]) ^ GF16.mul(m[off + 1], m[off + 2])); + } + + private byte determinant3x3(byte[] m, int off) + { + byte m00 = m[off++]; + byte m01 = m[off++]; + byte m02 = m[off++]; + byte m10 = m[off++]; + byte m11 = m[off++]; + byte m12 = m[off++]; + byte m20 = m[off++]; + byte m21 = m[off++]; + byte m22 = m[off]; + return (byte)(GF16.mul(m00, GF16.mul(m11, m22) ^ GF16.mul(m12, m21)) ^ + GF16.mul(m01, GF16.mul(m10, m22) ^ GF16.mul(m12, m20)) ^ + GF16.mul(m02, GF16.mul(m10, m21) ^ GF16.mul(m11, m20))); + } + + private byte determinant4x4(byte[] m, int off) + { + byte m00 = m[off++]; + byte m01 = m[off++]; + byte m02 = m[off++]; + byte m03 = m[off++]; + byte m10 = m[off++]; + byte m11 = m[off++]; + byte m12 = m[off++]; + byte m13 = m[off++]; + byte m20 = m[off++]; + byte m21 = m[off++]; + byte m22 = m[off++]; + byte m23 = m[off++]; + byte m30 = m[off++]; + byte m31 = m[off++]; + byte m32 = m[off++]; + byte m33 = m[off]; + + byte m22xm33_m23xm32 = (byte)(GF16.mul(m22, m33) ^ GF16.mul(m23, m32)); + byte m21xm33_m23xm31 = (byte)(GF16.mul(m21, m33) ^ GF16.mul(m23, m31)); + byte m21xm32_m22xm31 = (byte)(GF16.mul(m21, m32) ^ GF16.mul(m22, m31)); + byte m20xm33_m23xm30 = (byte)(GF16.mul(m20, m33) ^ GF16.mul(m23, m30)); + byte m20xm32_m32xm30 = (byte)(GF16.mul(m20, m32) ^ GF16.mul(m22, m30)); + byte m20xm31_m21xm30 = (byte)(GF16.mul(m20, m31) ^ GF16.mul(m21, m30)); + // POD -> entry[a][b] * (entry[c][d] * entry[e][f] + entry[g][h] * entry[i][j]) + return (byte)(GF16.mul(m00, GF16.mul(m11, m22xm33_m23xm32) ^ + GF16.mul(m12, m21xm33_m23xm31) ^ GF16.mul(m13, m21xm32_m22xm31)) ^ + GF16.mul(m01, GF16.mul(m10, m22xm33_m23xm32) ^ + GF16.mul(m12, m20xm33_m23xm30) ^ GF16.mul(m13, m20xm32_m32xm30)) ^ + GF16.mul(m02, GF16.mul(m10, m21xm33_m23xm31) ^ + GF16.mul(m11, m20xm33_m23xm30) ^ GF16.mul(m13, m20xm31_m21xm30)) ^ + GF16.mul(m03, GF16.mul(m10, m21xm32_m22xm31) ^ + GF16.mul(m11, m20xm32_m32xm30) ^ GF16.mul(m12, m20xm31_m21xm30))); + } + + private byte determinant5x5(byte[] m, int off) + { + byte m00 = m[off++]; + byte m01 = m[off++]; + byte m02 = m[off++]; + byte m03 = m[off++]; + byte m04 = m[off++]; + byte m10 = m[off++]; + byte m11 = m[off++]; + byte m12 = m[off++]; + byte m13 = m[off++]; + byte m14 = m[off++]; + byte m20 = m[off++]; + byte m21 = m[off++]; + byte m22 = m[off++]; + byte m23 = m[off++]; + byte m24 = m[off++]; + byte m30 = m[off++]; + byte m31 = m[off++]; + byte m32 = m[off++]; + byte m33 = m[off++]; + byte m34 = m[off++]; + byte m40 = m[off++]; + byte m41 = m[off++]; + byte m42 = m[off++]; + byte m43 = m[off++]; + byte m44 = m[off]; + + byte m10xm21_m11xm20 = (byte)(GF16.mul(m10, m21) ^ GF16.mul(m11, m20)); + byte m10xm22_m12xm20 = (byte)(GF16.mul(m10, m22) ^ GF16.mul(m12, m20)); + byte m10xm23_m13xm20 = (byte)(GF16.mul(m10, m23) ^ GF16.mul(m13, m20)); + byte m10xm24_m14xm20 = (byte)(GF16.mul(m10, m24) ^ GF16.mul(m14, m20)); + byte m11xm22_m12xm21 = (byte)(GF16.mul(m11, m22) ^ GF16.mul(m12, m21)); + byte m11xm23_m13xm21 = (byte)(GF16.mul(m11, m23) ^ GF16.mul(m13, m21)); + byte m11xm24_m14xm21 = (byte)(GF16.mul(m11, m24) ^ GF16.mul(m14, m21)); + byte m12xm23_m13xm22 = (byte)(GF16.mul(m12, m23) ^ GF16.mul(m13, m22)); + byte m12xm24_m14xm22 = (byte)(GF16.mul(m12, m24) ^ GF16.mul(m14, m22)); + byte m13xm24_m14xm23 = (byte)(GF16.mul(m13, m24) ^ GF16.mul(m14, m23)); + + byte result = (byte)GF16.mul(//determinant3x3(m, off, 0, 1, 2), + (GF16.mul(m00, m11xm22_m12xm21) ^ + GF16.mul(m01, m10xm22_m12xm20) ^ + GF16.mul(m02, m10xm21_m11xm20)), + (GF16.mul(m33, m44) ^ GF16.mul(m34, m43))); + result ^= GF16.mul(//determinant3x3(m, off, 0, 1, 3), + (GF16.mul(m00, m11xm23_m13xm21) ^ + GF16.mul(m01, m10xm23_m13xm20) ^ + GF16.mul(m03, m10xm21_m11xm20)), + (GF16.mul(m32, m44) ^ GF16.mul(m34, m42))); + result ^= GF16.mul(//determinant3x3(m, off, 0, 1, 4), + (GF16.mul(m00, m11xm24_m14xm21) ^ + GF16.mul(m01, m10xm24_m14xm20) ^ + GF16.mul(m04, m10xm21_m11xm20)), + (GF16.mul(m32, m43) ^ GF16.mul(m33, m42))); + result ^= GF16.mul(//determinant3x3(m, off, 0, 2, 3), + (GF16.mul(m00, m12xm23_m13xm22) ^ + GF16.mul(m02, m10xm23_m13xm20) ^ + GF16.mul(m03, m10xm22_m12xm20)), + (GF16.mul(m31, m44) ^ GF16.mul(m34, m41))); + result ^= GF16.mul(//determinant3x3(m, off, 0, 2, 4), + (GF16.mul(m00, m12xm24_m14xm22) ^ + GF16.mul(m02, m10xm24_m14xm20) ^ + GF16.mul(m04, m10xm22_m12xm20)), + (GF16.mul(m31, m43) ^ GF16.mul(m33, m41))); + result ^= GF16.mul(//determinant3x3(m, off, 0, 3, 4), + (GF16.mul(m00, m13xm24_m14xm23) ^ + GF16.mul(m03, m10xm24_m14xm20) ^ + GF16.mul(m04, m10xm23_m13xm20)), + (GF16.mul(m31, m42) ^ GF16.mul(m32, m41))); + result ^= GF16.mul(//determinant3x3(m, off, 1, 2, 3), + (GF16.mul(m01, m12xm23_m13xm22) ^ + GF16.mul(m02, m11xm23_m13xm21) ^ + GF16.mul(m03, m11xm22_m12xm21)), + (GF16.mul(m30, m44) ^ GF16.mul(m34, m40))); + result ^= GF16.mul(//determinant3x3(m, off, 1, 2, 4), + (GF16.mul(m01, m12xm24_m14xm22) ^ + GF16.mul(m02, m11xm24_m14xm21) ^ + GF16.mul(m04, m11xm22_m12xm21)), + (GF16.mul(m30, m43) ^ GF16.mul(m33, m40))); + result ^= GF16.mul(//determinant3x3(m, off, 1, 3, 4), + (GF16.mul(m01, m13xm24_m14xm23) ^ + GF16.mul(m03, m11xm24_m14xm21) ^ + GF16.mul(m04, m11xm23_m13xm21)), + (GF16.mul(m30, m42) ^ GF16.mul(m32, m40))); + result ^= GF16.mul(//determinant3x3(m, off, 2, 3, 4), + (GF16.mul(m02, m13xm24_m14xm23) ^ + GF16.mul(m03, m12xm24_m14xm22) ^ + GF16.mul(m04, m12xm23_m13xm22)), + (GF16.mul(m30, m41) ^ GF16.mul(m31, m40))); + return result; + } + + private void generateASMatrixTo(byte[] target, int off, byte a) + { + for (int i = 0, ixl = off; i < l; i++, ixl += l) + { + for (int j = 0; j < l; j++) + { + byte coefficient = (byte)(8 - (i + j)); + if (l == 5 && i == 4 && j == 4) + { + coefficient = 9; + } + target[ixl + j] ^= GF16.mul(coefficient, a); + } + } + } + + private void genAFqS(byte[] c, int cOff, byte[] ptMatrix, int off) + { + // Initialize with be_aI + be_aI(ptMatrix, off, c[cOff]); + + // Process middle terms + for (int i = 1; i < l - 1; ++i) + { + gf16mScaleTo(S[i], c[cOff + i], ptMatrix, off); + } + + // Handle last term with special case + byte lastScalar = (byte)((c[cOff + l - 1] != 0) ? c[cOff + l - 1] : 16 - (c[cOff] + (c[cOff] == 0 ? 1 : 0))); + gf16mScaleTo(S[l - 1], lastScalar, ptMatrix, off); + } + + private void gf16mScaleTo(byte[] a, byte k, byte[] c, int cOff) + { + for (int i = 0, il = 0; i < l; ++i, il += l) + { + for (int j = 0; j < l; ++j) + { + c[il + j + cOff] ^= GF16.mul(a[il + j], k); + } + } + } + + private void genF(MapGroup2 map2, MapGroup1 map1, byte[][][] T12) + { + // Copy initial matrices + copy4DMatrix(map1.p11, map2.f11, m, v, v, lsq); + copy4DMatrix(map1.p12, map2.f12, m, v, o, lsq); + copy4DMatrix(map1.p21, map2.f21, m, o, v, lsq); + + for (int i = 0; i < m; i++) + { + for (int j = 0; j < v; j++) + { + for (int k = 0; k < o; k++) + { + for (int index = 0; index < v; index++) + { + GF16Utils.gf16mMulToTo(map1.p11[i][j][index], T12[index][k], map1.p11[i][index][j], map2.f12[i][j][k], map2.f21[i][k][j], l); + } + } + } + } + } + + private static void copy4DMatrix(byte[][][][] src, byte[][][][] dest, int dim1, int dim2, int dim3, int lsq) + { + for (int i = 0; i < dim1; i++) + { + for (int j = 0; j < dim2; j++) + { + for (int k = 0; k < dim3; k++) + { + System.arraycopy(src[i][j][k], 0, dest[i][j][k], 0, lsq); + } + } + } + } + + public void genP22(byte[] outP22, int outOff, byte[][][] T12, byte[][][][] P21, byte[][][][] F12) + { + // Initialize P22 with zeros + int oxlsq = o * lsq; + int oxoxlsq = oxlsq * o; + byte[] P22 = new byte[m * oxoxlsq]; + + for (int i = 0, ixoxolsq = 0; i < m; i++, ixoxolsq += oxoxlsq) + { + for (int j = 0, jxoxlsq = ixoxolsq; j < o; j++, jxoxlsq += oxlsq) + { + for (int k = 0, kxlsq = jxoxlsq; k < o; k++, kxlsq += lsq) + { + for (int index = 0; index < v; index++) + { + // P22[i][j][k] ^= (T12[index][j] * F12[i][index][k]) ^ (P21[i][j][index] * T12[index][k]) + GF16Utils.gf16mMulTo(T12[index][j], F12[i][index][k], P21[i][j][index], T12[index][k], P22, kxlsq, l); + } + } + } + } + + // Convert GF16 elements to packed bytes + GF16.encode(P22, outP22, outOff, P22.length); + } + + private void genSeedsAndT12(byte[][][] T12, byte[] skSeed) + { + int gf16sPrngPrivate = v * o * l; + int bytesPrngPrivate = (gf16sPrngPrivate + 1) >>> 1; + byte[] prngOutput = new byte[bytesPrngPrivate]; + + // Generate PRNG output using SHAKE-256 + SHAKEDigest shake = new SHAKEDigest(256); + shake.update(skSeed, 0, skSeed.length); + shake.doFinal(prngOutput, 0, prngOutput.length); + + // Convert bytes to GF16 array + byte[] gf16PrngOutput = new byte[gf16sPrngPrivate]; + GF16.decode(prngOutput, gf16PrngOutput, gf16sPrngPrivate); + + // Generate T12 matrices + int ptArray = 0; + for (int j = 0; j < v; j++) + { + for (int k = 0; k < o; k++) + { + //gen_a_FqS_ct + genAFqSCT(gf16PrngOutput, ptArray, T12[j][k]); + ptArray += l; + } + } + } + + public void genABQP(MapGroup1 map1, byte[] pkSeed) + { + int gf16sPrngPublic = lsq * (2 * m * alpha + m * (n * n - m * m)) + l * 2 * m * alpha; + byte[] qTemp = new byte[(m * alpha * l) << 1]; + byte[] prngOutput = new byte[(gf16sPrngPublic + 1) >> 1]; + + if (params.isPkExpandShake()) + { + final int SHAKE128_RATE = 168; // 1344-bit rate = 168 bytes + long blockCounter = 0; + int offset = 0; + int remaining = prngOutput.length; + byte[] counterBytes = new byte[8]; + SHAKEDigest shake = new SHAKEDigest(128); + while (remaining > 0) + { + // Process seed + counter + shake.update(pkSeed, 0, pkSeed.length); + Pack.longToLittleEndian(blockCounter, counterBytes, 0); + shake.update(counterBytes, 0, 8); + + // Calculate bytes to generate in this iteration + int bytesToGenerate = Math.min(remaining, SHAKE128_RATE); + + // Generate output (XOF mode) + shake.doFinal(prngOutput, offset, bytesToGenerate); + + offset += bytesToGenerate; + remaining -= bytesToGenerate; + blockCounter++; + } + } + else + { + // Create a 16-byte IV (all zeros) + byte[] iv = new byte[16]; // automatically zero-initialized + // AES-CTR-based expansion + // Set up AES engine in CTR (SIC) mode. + // SICBlockCipher implements CTR mode for AES. + CTRModeCipher ctrCipher = SICBlockCipher.newInstance(AESEngine.newInstance()); + ctrCipher.init(true, new ParametersWithIV(new KeyParameter(pkSeed), iv)); + int blockSize = ctrCipher.getBlockSize(); // typically 16 bytes + byte[] zeroBlock = new byte[blockSize]; // block of zeros + + int offset = 0; + // Process full blocks + while (offset + blockSize <= prngOutput.length) + { + ctrCipher.processBlock(zeroBlock, 0, prngOutput, offset); + offset += blockSize; + } + // Process any remaining partial block. + if (offset < prngOutput.length) + { + ctrCipher.processBlock(zeroBlock, 0, zeroBlock, 0); + int remaining = prngOutput.length - offset; + System.arraycopy(zeroBlock, 0, prngOutput, offset, remaining); + } + } + if ((lsq & 1) == 0) + { + map1.decode(prngOutput, (gf16sPrngPublic - qTemp.length) >> 1, l >= 4); + } + else + { + byte[] temp = new byte[gf16sPrngPublic - qTemp.length]; + GF16.decode(prngOutput, temp, temp.length); + map1.fill(temp, l >= 4); + } + if (l >= 4) + { + GF16.decode(prngOutput, (gf16sPrngPublic - qTemp.length) >> 1, qTemp, 0, qTemp.length); + int ptArray = 0; + // Post-processing for invertible matrices + int offset = m * alpha * l; + for (int pi = 0; pi < m; ++pi) + { + for (int a = 0; a < alpha; ++a) + { + makeInvertibleByAddingAS(map1.aAlpha[pi][a], 0); + makeInvertibleByAddingAS(map1.bAlpha[pi][a], 0); + genAFqS(qTemp, ptArray, map1.qAlpha1[pi][a], 0); + genAFqS(qTemp, offset, map1.qAlpha2[pi][a], 0); + ptArray += l; + offset += l; + } + } + } + else + { + int oxalphaxlsq = o * alpha * lsq; + byte[] fixedAbq = (byte[])fixedAbqSet.get(Integers.valueOf(o)); + MapGroup1.fillAlpha(fixedAbq, 0, map1.aAlpha, m * oxalphaxlsq); + MapGroup1.fillAlpha(fixedAbq, oxalphaxlsq, map1.bAlpha, (m - 1) * oxalphaxlsq); + MapGroup1.fillAlpha(fixedAbq, oxalphaxlsq * 2, map1.qAlpha1, (m - 2) * oxalphaxlsq); + MapGroup1.fillAlpha(fixedAbq, oxalphaxlsq * 3, map1.qAlpha2, (m - 3) * oxalphaxlsq); + } + } + + public void genMap1T12Map2(SnovaKeyElements keyElements, byte[] pkSeed, byte[] skSeed) + { + // Generate T12 matrix + genSeedsAndT12(keyElements.T12, skSeed); + + // Generate map components + genABQP(keyElements.map1, pkSeed); + + // Generate F matrices + genF(keyElements.map2, keyElements.map1, keyElements.T12); + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java new file mode 100644 index 0000000000..0915e590e2 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyElements.java @@ -0,0 +1,69 @@ +package org.bouncycastle.pqc.crypto.snova; + +class SnovaKeyElements +{ + public final MapGroup1 map1; + public final byte[][][] T12; // [v][o] + public final MapGroup2 map2; + + public SnovaKeyElements(SnovaParameters params) + { + int o = params.getO(); + int v = params.getV(); + int lsq = params.getLsq(); + map1 = new MapGroup1(params); + T12 = new byte[v][o][lsq]; + map2 = new MapGroup2(params); + } + + static int copy3d(byte[][][] alpha, byte[] output, int outOff) + { + for (int i = 0; i < alpha.length; ++i) + { + for (int j = 0; j < alpha[i].length; ++j) + { + System.arraycopy(alpha[i][j], 0, output, outOff, alpha[i][j].length); + outOff += alpha[i][j].length; + } + } + return outOff; + } + + static int copy4d(byte[][][][] alpha, byte[] output, int outOff) + { + for (int i = 0; i < alpha.length; ++i) + { + outOff = copy3d(alpha[i], output, outOff); + } + return outOff; + } + + static int copy3d(byte[] input, int inOff, byte[][][] alpha) + { + for (int i = 0; i < alpha.length; ++i) + { + for (int j = 0; j < alpha[i].length; ++j) + { + System.arraycopy(input, inOff, alpha[i][j], 0, alpha[i][j].length); + inOff += alpha[i][j].length; + } + } + return inOff; + } + + static int copy4d(byte[] input, int inOff, byte[][][][] alpha) + { + for (int i = 0; i < alpha.length; ++i) + { + for (int j = 0; j < alpha[i].length; ++j) + { + for (int k = 0; k < alpha[i][j].length; ++k) + { + System.arraycopy(input, inOff, alpha[i][j][k], 0, alpha[i][j][k].length); + inOff += alpha[i][j][k].length; + } + } + } + return inOff; + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyGenerationParameters.java new file mode 100644 index 0000000000..ef25e9605d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyGenerationParameters.java @@ -0,0 +1,22 @@ +package org.bouncycastle.pqc.crypto.snova; + +import java.security.SecureRandom; + +import org.bouncycastle.crypto.KeyGenerationParameters; + +public class SnovaKeyGenerationParameters + extends KeyGenerationParameters +{ + private final SnovaParameters params; + + public SnovaKeyGenerationParameters(SecureRandom random, SnovaParameters params) + { + super(random, -1); // Security parameter not used directly + this.params = params; + } + + public SnovaParameters getParameters() + { + return params; + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java new file mode 100644 index 0000000000..5eb5c11c38 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaKeyPairGenerator.java @@ -0,0 +1,90 @@ +package org.bouncycastle.pqc.crypto.snova; + +import java.security.SecureRandom; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import org.bouncycastle.crypto.KeyGenerationParameters; +import org.bouncycastle.util.Arrays; + +public class SnovaKeyPairGenerator + implements AsymmetricCipherKeyPairGenerator +{ + private SnovaEngine engine; + private static final int seedLength = 48; + static final int publicSeedLength = 16; + static final int privateSeedLength = 32; + private SnovaParameters params; + private SecureRandom random; + private boolean initialized; + + @Override + public void init(KeyGenerationParameters param) + { + SnovaKeyGenerationParameters snovaParams = (SnovaKeyGenerationParameters)param; + this.params = snovaParams.getParameters(); + this.random = snovaParams.getRandom(); + this.initialized = true; + this.engine = new SnovaEngine(params); + } + + @Override + public AsymmetricCipherKeyPair generateKeyPair() + { + if (!initialized) + { + throw new IllegalStateException("SNOVA key pair generator not initialized"); + } + + // Generate seed pair according to SNOVA specifications + byte[] seedPair = new byte[seedLength]; + random.nextBytes(seedPair); + + byte[] pk = new byte[params.getPublicKeyLength()]; + byte[] sk = new byte[params.getPrivateKeyLength()]; + + byte[] ptPublicKeySeed = Arrays.copyOfRange(seedPair, 0, publicSeedLength); + byte[] ptPrivateKeySeed = Arrays.copyOfRange(seedPair, publicSeedLength, seedPair.length); + + SnovaKeyElements keyElements = new SnovaKeyElements(params); + System.arraycopy(ptPublicKeySeed, 0, pk, 0, ptPublicKeySeed.length); + engine.genMap1T12Map2(keyElements, ptPublicKeySeed, ptPrivateKeySeed); + + // Generate P22 matrix + engine.genP22(pk, ptPublicKeySeed.length, keyElements.T12, keyElements.map1.p21, keyElements.map2.f12); + + + // Pack public key components + System.arraycopy(ptPublicKeySeed, 0, pk, 0, ptPublicKeySeed.length); + + if (params.isSkIsSeed()) + { + sk = seedPair; + } + else + { + int o = params.getO(); + int lsq = params.getLsq(); + int v = params.getV(); + int length = o * params.getAlpha() * lsq * 4 + v * o * lsq + (o * v * v + o * v * o + o * o * v) * lsq; + + byte[] input = new byte[length]; + int inOff = 0; + inOff = SnovaKeyElements.copy3d(keyElements.map1.aAlpha, input, inOff); + inOff = SnovaKeyElements.copy3d(keyElements.map1.bAlpha, input, inOff); + inOff = SnovaKeyElements.copy3d(keyElements.map1.qAlpha1, input, inOff); + inOff = SnovaKeyElements.copy3d(keyElements.map1.qAlpha2, input, inOff); + inOff = SnovaKeyElements.copy3d(keyElements.T12, input, inOff); + inOff = SnovaKeyElements.copy4d(keyElements.map2.f11, input, inOff); + inOff = SnovaKeyElements.copy4d(keyElements.map2.f12, input, inOff); + SnovaKeyElements.copy4d(keyElements.map2.f21, input, inOff); + GF16Utils.encodeMergeInHalf(input, length, sk); + System.arraycopy(seedPair, 0, sk, sk.length - seedLength, seedLength); + } + + return new AsymmetricCipherKeyPair( + new SnovaPublicKeyParameters(params, pk), + new SnovaPrivateKeyParameters(params, sk) + ); + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaParameters.java new file mode 100644 index 0000000000..fcce21df1c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaParameters.java @@ -0,0 +1,198 @@ +package org.bouncycastle.pqc.crypto.snova; + +public class SnovaParameters +{ + + public static final SnovaParameters SNOVA_24_5_4_SSK = + new SnovaParameters("SNOVA_24_5_4_SSK", 24, 5, 4, true, false); + public static final SnovaParameters SNOVA_24_5_4_ESK = + new SnovaParameters("SNOVA_24_5_4_ESK", 24, 5, 4, false, false); + public static final SnovaParameters SNOVA_24_5_4_SHAKE_SSK = + new SnovaParameters("SNOVA_24_5_4_SHAKE_SSK", 24, 5, 4, true, true); + public static final SnovaParameters SNOVA_24_5_4_SHAKE_ESK = + new SnovaParameters("SNOVA_24_5_4_SHAKE_ESK", 24, 5, 4, false, true); + + public static final SnovaParameters SNOVA_24_5_5_SSK = + new SnovaParameters("SNOVA_24_5_5_SSK", 24, 5, 5, true, false); + public static final SnovaParameters SNOVA_24_5_5_ESK = + new SnovaParameters("SNOVA_24_5_5_ESK", 24, 5, 5, false, false); + public static final SnovaParameters SNOVA_24_5_5_SHAKE_SSK = + new SnovaParameters("SNOVA_24_5_5_SHAKE_SSK", 24, 5, 5, true, true); + public static final SnovaParameters SNOVA_24_5_5_SHAKE_ESK = + new SnovaParameters("SNOVA_24_5_5_SHAKE_ESK", 24, 5, 5, false, true); + + public static final SnovaParameters SNOVA_25_8_3_SSK = + new SnovaParameters("SNOVA_25_8_3_SSK", 25, 8, 3, true, false); + public static final SnovaParameters SNOVA_25_8_3_ESK = + new SnovaParameters("SNOVA_25_8_3_ESK", 25, 8, 3, false, false); + public static final SnovaParameters SNOVA_25_8_3_SHAKE_SSK = + new SnovaParameters("SNOVA_25_8_3_SHAKE_SSK", 25, 8, 3, true, true); + public static final SnovaParameters SNOVA_25_8_3_SHAKE_ESK = + new SnovaParameters("SNOVA_25_8_3_SHAKE_ESK", 25, 8, 3, false, true); + + public static final SnovaParameters SNOVA_29_6_5_SSK = + new SnovaParameters("SNOVA_29_6_5_SSK", 29, 6, 5, true, false); + public static final SnovaParameters SNOVA_29_6_5_ESK = + new SnovaParameters("SNOVA_29_6_5_ESK", 29, 6, 5, false, false); + public static final SnovaParameters SNOVA_29_6_5_SHAKE_SSK = + new SnovaParameters("SNOVA_29_6_5_SHAKE_SSK", 29, 6, 5, true, true); + public static final SnovaParameters SNOVA_29_6_5_SHAKE_ESK = + new SnovaParameters("SNOVA_29_6_5_SHAKE_ESK", 29, 6, 5, false, true); + + public static final SnovaParameters SNOVA_37_8_4_SSK = + new SnovaParameters("SNOVA_37_8_4_SSK", 37, 8, 4, true, false); + public static final SnovaParameters SNOVA_37_8_4_ESK = + new SnovaParameters("SNOVA_37_8_4_ESK", 37, 8, 4, false, false); + public static final SnovaParameters SNOVA_37_8_4_SHAKE_SSK = + new SnovaParameters("SNOVA_37_8_4_SHAKE_SSK", 37, 8, 4, true, true); + public static final SnovaParameters SNOVA_37_8_4_SHAKE_ESK = + new SnovaParameters("SNOVA_37_8_4_SHAKE_ESK", 37, 8, 4, false, true); + + // SNOVA_37_17_2 variants + public static final SnovaParameters SNOVA_37_17_2_SSK = + new SnovaParameters("SNOVA_37_17_2_SSK", 37, 17, 2, true, false); + public static final SnovaParameters SNOVA_37_17_2_ESK = + new SnovaParameters("SNOVA_37_17_2_ESK", 37, 17, 2, false, false); + public static final SnovaParameters SNOVA_37_17_2_SHAKE_SSK = + new SnovaParameters("SNOVA_37_17_2_SHAKE_SSK", 37, 17, 2, true, true); + public static final SnovaParameters SNOVA_37_17_2_SHAKE_ESK = + new SnovaParameters("SNOVA_37_17_2_SHAKE_ESK", 37, 17, 2, false, true); + + // SNOVA_49_11_3 variants + public static final SnovaParameters SNOVA_49_11_3_SSK = + new SnovaParameters("SNOVA_49_11_3_SSK", 49, 11, 3, true, false); + public static final SnovaParameters SNOVA_49_11_3_ESK = + new SnovaParameters("SNOVA_49_11_3_ESK", 49, 11, 3, false, false); + public static final SnovaParameters SNOVA_49_11_3_SHAKE_SSK = + new SnovaParameters("SNOVA_49_11_3_SHAKE_SSK", 49, 11, 3, true, true); + public static final SnovaParameters SNOVA_49_11_3_SHAKE_ESK = + new SnovaParameters("SNOVA_49_11_3_SHAKE_ESK", 49, 11, 3, false, true); + + // SNOVA_56_25_2 variants + public static final SnovaParameters SNOVA_56_25_2_SSK = + new SnovaParameters("SNOVA_56_25_2_SSK", 56, 25, 2, true, false); + public static final SnovaParameters SNOVA_56_25_2_ESK = + new SnovaParameters("SNOVA_56_25_2_ESK", 56, 25, 2, false, false); + public static final SnovaParameters SNOVA_56_25_2_SHAKE_SSK = + new SnovaParameters("SNOVA_56_25_2_SHAKE_SSK", 56, 25, 2, true, true); + public static final SnovaParameters SNOVA_56_25_2_SHAKE_ESK = + new SnovaParameters("SNOVA_56_25_2_SHAKE_ESK", 56, 25, 2, false, true); + + // SNOVA_60_10_4 variants + public static final SnovaParameters SNOVA_60_10_4_SSK = + new SnovaParameters("SNOVA_60_10_4_SSK", 60, 10, 4, true, false); + public static final SnovaParameters SNOVA_60_10_4_ESK = + new SnovaParameters("SNOVA_60_10_4_ESK", 60, 10, 4, false, false); + public static final SnovaParameters SNOVA_60_10_4_SHAKE_SSK = + new SnovaParameters("SNOVA_60_10_4_SHAKE_SSK", 60, 10, 4, true, true); + public static final SnovaParameters SNOVA_60_10_4_SHAKE_ESK = + new SnovaParameters("SNOVA_60_10_4_SHAKE_ESK", 60, 10, 4, false, true); + + // SNOVA_66_15_4 variants + public static final SnovaParameters SNOVA_66_15_3_SSK = + new SnovaParameters("SNOVA_66_15_3_SSK", 66, 15, 3, true, false); + public static final SnovaParameters SNOVA_66_15_3_ESK = + new SnovaParameters("SNOVA_66_15_3_ESK", 66, 15, 3, false, false); + public static final SnovaParameters SNOVA_66_15_3_SHAKE_SSK = + new SnovaParameters("SNOVA_66_15_3_SHAKE_SSK", 66, 15, 3, true, true); + public static final SnovaParameters SNOVA_66_15_3_SHAKE_ESK = + new SnovaParameters("SNOVA_66_15_3_SHAKE_ESK", 66, 15, 3, false, true); + + // SNOVA_75_33_2 variants + public static final SnovaParameters SNOVA_75_33_2_SSK = + new SnovaParameters("SNOVA_75_33_2_SSK", 75, 33, 2, true, false); + public static final SnovaParameters SNOVA_75_33_2_ESK = + new SnovaParameters("SNOVA_75_33_2_ESK", 75, 33, 2, false, false); + public static final SnovaParameters SNOVA_75_33_2_SHAKE_SSK = + new SnovaParameters("SNOVA_75_33_2_SHAKE_SSK", 75, 33, 2, true, true); + public static final SnovaParameters SNOVA_75_33_2_SHAKE_ESK = + new SnovaParameters("SNOVA_75_33_2_SHAKE_ESK", 75, 33, 2, false, true); + + private final String name; + private final int v; + private final int o; + private final int l; + private final int lsq; + private final int alpha; + private final boolean skIsSeed; + private final boolean pkExpandShake; + + private SnovaParameters(String name, int v, int o, int l, boolean skIsSeed, boolean pkExpandShake) + { + this.name = name; + this.v = v; + this.o = o; + this.l = l; + this.lsq = l * l; + this.alpha = lsq + l; + this.skIsSeed = skIsSeed; + this.pkExpandShake = pkExpandShake; + } + + // Getter methods + public String getName() + { + return name; + } + + public int getV() + { + return v; + } + + public int getO() + { + return o; + } + + public int getL() + { + return l; + } + + public boolean isSkIsSeed() + { + return skIsSeed; + } + + public boolean isPkExpandShake() + { + return pkExpandShake; + } + + public int getM() + { + return o; + } + + public int getAlpha() + { + return alpha; + } + + public int getPublicKeyLength() + { + return SnovaKeyPairGenerator.publicSeedLength + ((o * o * o * lsq + 1) >>> 1); + } + + public int getPrivateKeyLength() + { + return ((lsq * (4 * o * alpha + o * (v * v + v * o + o * v) + v * o) + 1) >> 1) + + SnovaKeyPairGenerator.privateSeedLength + SnovaKeyPairGenerator.publicSeedLength; + } + + public int getN() + { + return v + o; + } + + public int getLsq() + { + return lsq; + } + + public int getSaltLength() + { + return 16; + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaPrivateKeyParameters.java new file mode 100644 index 0000000000..a8643bcc98 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaPrivateKeyParameters.java @@ -0,0 +1,33 @@ +package org.bouncycastle.pqc.crypto.snova; + +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.util.Arrays; + +public class SnovaPrivateKeyParameters + extends AsymmetricKeyParameter +{ + private final byte[] privateKey; + private final SnovaParameters parameters; + + public SnovaPrivateKeyParameters(SnovaParameters parameters, byte[] privateKey) + { + super(true); + this.privateKey = Arrays.clone(privateKey); + this.parameters = parameters; + } + + public byte[] getPrivateKey() + { + return Arrays.clone(privateKey); + } + + public byte[] getEncoded() + { + return Arrays.clone(privateKey); + } + + public SnovaParameters getParameters() + { + return parameters; + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaPublicKeyParameters.java new file mode 100644 index 0000000000..40001e0269 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaPublicKeyParameters.java @@ -0,0 +1,33 @@ +package org.bouncycastle.pqc.crypto.snova; + +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.util.Arrays; + +public class SnovaPublicKeyParameters + extends AsymmetricKeyParameter +{ + private final byte[] publicKey; + private final SnovaParameters parameters; + + public SnovaPublicKeyParameters(SnovaParameters parameters, byte[] publicKey) + { + super(false); + this.publicKey = Arrays.clone(publicKey); + this.parameters = parameters; + } + + public byte[] getPublicKey() + { + return Arrays.clone(publicKey); + } + + public byte[] getEncoded() + { + return Arrays.clone(publicKey); + } + + public SnovaParameters getParameters() + { + return parameters; + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaSigner.java new file mode 100644 index 0000000000..764a289458 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/snova/SnovaSigner.java @@ -0,0 +1,512 @@ +package org.bouncycastle.pqc.crypto.snova; + +import java.security.SecureRandom; + +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.crypto.digests.SHAKEDigest; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.pqc.crypto.MessageSigner; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.GF16; + +public class SnovaSigner + implements MessageSigner +{ + private SnovaParameters params; + private SnovaEngine engine; + private SecureRandom random; + private final SHAKEDigest shake = new SHAKEDigest(256); + private SnovaPublicKeyParameters pubKey; + private SnovaPrivateKeyParameters privKey; + + @Override + public void init(boolean forSigning, CipherParameters param) + { + if (forSigning) + { + pubKey = null; + + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom withRandom = (ParametersWithRandom)param; + privKey = (SnovaPrivateKeyParameters)withRandom.getParameters(); + random = withRandom.getRandom(); + } + else + { + privKey = (SnovaPrivateKeyParameters)param; + random = CryptoServicesRegistrar.getSecureRandom(); + } + params = privKey.getParameters(); + } + else + { + pubKey = (SnovaPublicKeyParameters)param; + params = pubKey.getParameters(); + privKey = null; + random = null; + } + engine = new SnovaEngine(params); + } + + @Override + public byte[] generateSignature(byte[] message) + { + byte[] hash = getMessageHash(message); + byte[] salt = new byte[params.getSaltLength()]; + random.nextBytes(salt); + byte[] signature = new byte[((params.getN() * params.getLsq() + 1) >>> 1) + params.getSaltLength()]; + SnovaKeyElements keyElements = new SnovaKeyElements(params); + byte[] publicKeySeed; + byte[] ptPrivateKeySeed; + if (params.isSkIsSeed()) + { + byte[] seedPair = privKey.getPrivateKey(); + publicKeySeed = Arrays.copyOfRange(seedPair, 0, SnovaKeyPairGenerator.publicSeedLength); + ptPrivateKeySeed = Arrays.copyOfRange(seedPair, SnovaKeyPairGenerator.publicSeedLength, seedPair.length); + engine.genMap1T12Map2(keyElements, publicKeySeed, ptPrivateKeySeed); + } + else + { + byte[] privateKey = privKey.getPrivateKey(); + byte[] tmp = new byte[(privateKey.length - SnovaKeyPairGenerator.publicSeedLength - SnovaKeyPairGenerator.privateSeedLength) << 1]; + GF16Utils.decodeMergeInHalf(privateKey, tmp, tmp.length); + int inOff = 0; + inOff = SnovaKeyElements.copy3d(tmp, inOff, keyElements.map1.aAlpha); + inOff = SnovaKeyElements.copy3d(tmp, inOff, keyElements.map1.bAlpha); + inOff = SnovaKeyElements.copy3d(tmp, inOff, keyElements.map1.qAlpha1); + inOff = SnovaKeyElements.copy3d(tmp, inOff, keyElements.map1.qAlpha2); + inOff = SnovaKeyElements.copy3d(tmp, inOff, keyElements.T12); + inOff = SnovaKeyElements.copy4d(tmp, inOff, keyElements.map2.f11); + inOff = SnovaKeyElements.copy4d(tmp, inOff, keyElements.map2.f12); + SnovaKeyElements.copy4d(tmp, inOff, keyElements.map2.f21); + publicKeySeed = Arrays.copyOfRange(privateKey, privateKey.length - SnovaKeyPairGenerator.publicSeedLength - SnovaKeyPairGenerator.privateSeedLength, privateKey.length - SnovaKeyPairGenerator.privateSeedLength); + ptPrivateKeySeed = Arrays.copyOfRange(privateKey, privateKey.length - SnovaKeyPairGenerator.privateSeedLength, privateKey.length); + } + signDigestCore(signature, hash, salt, keyElements.map1.aAlpha, keyElements.map1.bAlpha, keyElements.map1.qAlpha1, keyElements.map1.qAlpha2, + keyElements.T12, keyElements.map2.f11, keyElements.map2.f12, keyElements.map2.f21, publicKeySeed, ptPrivateKeySeed); + return Arrays.concatenate(signature, message); + } + + @Override + public boolean verifySignature(byte[] message, byte[] signature) + { + byte[] hash = getMessageHash(message); + MapGroup1 map1 = new MapGroup1(params); + byte[] pk = pubKey.getEncoded(); + byte[] publicKeySeed = Arrays.copyOf(pk, SnovaKeyPairGenerator.publicSeedLength); + byte[] p22_source = Arrays.copyOfRange(pk, SnovaKeyPairGenerator.publicSeedLength, pk.length); + engine.genABQP(map1, publicKeySeed); + byte[][][][] p22 = new byte[params.getM()][params.getO()][params.getO()][params.getLsq()]; + if ((params.getLsq() & 1) == 0) + { + MapGroup1.decodeP(p22_source, 0, p22, p22_source.length << 1); + } + else + { + byte[] p22_gf16s = new byte[p22_source.length << 1]; + GF16.decode(p22_source, p22_gf16s, p22_gf16s.length); + MapGroup1.fillP(p22_gf16s, 0, p22, p22_gf16s.length); + } + + return verifySignatureCore(hash, signature, publicKeySeed, map1, p22); + } + + void createSignedHash( + byte[] ptPublicKeySeed, int seedLengthPublic, + byte[] digest, int bytesDigest, + byte[] arraySalt, int saltOff, int bytesSalt, + byte[] signedHashOut, int bytesHash) + { + // 1. Absorb public key seed + shake.update(ptPublicKeySeed, 0, seedLengthPublic); + + // 2. Absorb message digest + shake.update(digest, 0, bytesDigest); + + // 3. Absorb salt + shake.update(arraySalt, saltOff, bytesSalt); + + // 4. Finalize absorption and squeeze output + shake.doFinal(signedHashOut, 0, bytesHash); + } + + void signDigestCore(byte[] ptSignature, byte[] digest, byte[] arraySalt, + byte[][][] Aalpha, byte[][][] Balpha, + byte[][][] Qalpha1, byte[][][] Qalpha2, + byte[][][] T12, byte[][][][] F11, + byte[][][][] F12, byte[][][][] F21, + byte[] ptPublicKeySeed, byte[] ptPrivateKeySeed) + { + // Initialize constants from parameters + final int m = params.getM(); + final int l = params.getL(); + final int lsq = params.getLsq(); + final int alpha = params.getAlpha(); + final int v = params.getV(); + final int o = params.getO(); + final int n = params.getN(); + final int mxlsq = m * lsq; + final int oxlsq = o * lsq; + final int vxlsq = v * lsq; + final int bytesHash = (oxlsq + 1) >>> 1; + final int bytesSalt = 16; + + // Initialize matrices and arrays + byte[][] Gauss = new byte[mxlsq][mxlsq + 1]; + byte[][] Temp = new byte[lsq][lsq]; + byte[] solution = new byte[mxlsq]; + + byte[][][] Left = new byte[alpha][v][lsq]; + byte[][][] Right = new byte[alpha][v][lsq]; + byte[] leftXTmp = new byte[lsq]; + byte[] rightXtmp = new byte[lsq]; + byte[] FvvGF16Matrix = new byte[lsq]; + byte[] hashInGF16 = new byte[mxlsq]; + byte[] vinegarGf16 = new byte[n * lsq]; + byte[] signedHash = new byte[bytesHash]; + byte[] vinegarBytes = new byte[(vxlsq + 1) >>> 1]; + + // Temporary matrices + byte[] gf16mTemp0 = new byte[l]; + + int flagRedo; + byte numSign = 0; + byte valLeft, valB, valA, valRight; + // Step 1: Create signed hash + createSignedHash(ptPublicKeySeed, ptPublicKeySeed.length, digest, digest.length, + arraySalt, 0, arraySalt.length, signedHash, bytesHash); + GF16.decode(signedHash, 0, hashInGF16, 0, hashInGF16.length); + + do + { + // Initialize Gauss matrix + for (int i = 0; i < Gauss.length; ++i) + { + Arrays.fill(Gauss[i], (byte)0); + } + numSign++; + + // Fill last column of Gauss matrix + for (int i = 0; i < mxlsq; i++) + { + Gauss[i][mxlsq] = hashInGF16[i]; + } + + // Generate vinegar values + shake.update(ptPrivateKeySeed, 0, ptPrivateKeySeed.length); + shake.update(digest, 0, digest.length); + shake.update(arraySalt, 0, arraySalt.length); + shake.update(numSign); + shake.doFinal(vinegarBytes, 0, vinegarBytes.length); + + GF16.decode(vinegarBytes, vinegarGf16, vinegarBytes.length << 1); + + for (int i = 0, ixlsq = 0; i < m; i++, ixlsq += lsq) + { + Arrays.fill(FvvGF16Matrix, (byte)0); + // Evaluate vinegar part of central map + for (int a = 0, miPrime = i; a < alpha; a++, miPrime++) + { + if (miPrime >= o) + { + miPrime -= o; + } + for (int j = 0, jxlsq = 0; j < v; j++, jxlsq += lsq) + { + GF16Utils.gf16mTranMulMul(vinegarGf16, jxlsq, Aalpha[i][a], Balpha[i][a], Qalpha1[i][a], + Qalpha2[i][a], gf16mTemp0, Left[a][j], Right[a][j], l); + } + + for (int j = 0; j < v; j++) + { + // Gaussian elimination setup + for (int k = 0; k < v; k++) + { + GF16Utils.gf16mMulMulTo(Left[a][j], F11[miPrime][j][k], Right[a][k], gf16mTemp0, FvvGF16Matrix, l); + } + } + } + + for (int j = 0, off = 0; j < l; j++) + { + for (int k = 0; k < l; k++) + { + Gauss[ixlsq + off][mxlsq] ^= FvvGF16Matrix[off++]; + } + } +// } +// // TODO: think about why this two loops can merge together? +// // Compute the coefficients of Xo and put into Gauss matrix and compute the coefficients of Xo^t and add into Gauss matrix +// for (int i = 0, ixlsq = 0; i < m; ++i, ixlsq += lsq) +// { + for (int index = 0, idxlsq = 0; index < o; ++index, idxlsq += lsq) + { + for (int a = 0, mi_prime = i; a < alpha; ++a, ++mi_prime) + { + if (mi_prime >= o) + { + mi_prime -= o; + } + // Initialize Temp to zero + for (int ti = 0; ti < lsq; ++ti) + { + Arrays.fill(Temp[ti], (byte)0); + } + // Process each j for Left part + for (int j = 0; j < v; ++j) + { + GF16Utils.gf16mMulMul(Left[a][j], F12[mi_prime][j][index], Qalpha2[i][a], gf16mTemp0, leftXTmp, l); + GF16Utils.gf16mMulMul(Qalpha1[i][a], F21[mi_prime][index][j], Right[a][j], gf16mTemp0, rightXtmp, l); + // Accumulate into Temp from leftXTmp and Balpha[mi][a] + // rlra_l is short for "rowLeft_rowA times l" + for (int ti = 0, colB_colRight = 0, rlraxl = 0; ti < lsq; ++ti, ++colB_colRight) + { + if (colB_colRight == l) + { + colB_colRight = 0; + rlraxl += l; + } + valLeft = leftXTmp[rlraxl]; + valRight = rightXtmp[colB_colRight]; + // clrrxl is short for "rowLeft_rowA times l" + // rbcaxl is short for "rowB_colA times l" + for (int tj = 0, rowB_colA = 0, colLeft_rowRight = 0, clrrxl = 0, rbcaxl = 0; tj < lsq; + ++tj, ++rowB_colA, rbcaxl += l) + { + if (rowB_colA == l) + { + rowB_colA = 0; + rbcaxl = 0; + colLeft_rowRight++; + clrrxl += l; + valLeft = leftXTmp[rlraxl + colLeft_rowRight]; + valRight = rightXtmp[clrrxl + colB_colRight]; + } + valB = Balpha[i][a][rbcaxl + colB_colRight]; + valA = Aalpha[i][a][rlraxl + rowB_colA]; + Temp[ti][tj] ^= GF16.mul(valLeft, valB) ^ GF16.mul(valA, valRight); + } + } + } + // Add Temp to Gauss matrix + for (int ti = 0; ti < lsq; ++ti) + { + for (int tj = 0; tj < lsq; ++tj) + { + Gauss[ixlsq + ti][idxlsq + tj] ^= Temp[ti][tj]; + } + } + } + } + } + // Gaussian elimination implementation + flagRedo = performGaussianElimination(Gauss, solution, mxlsq); + } + while (flagRedo != 0); + + // Copy vinegar variables + for (int idx = 0, idxlsq = 0; idx < v; idx++, idxlsq += lsq) + { + for (int i = 0, ixlsq = 0; i < o; i++, ixlsq += lsq) + { + GF16Utils.gf16mMulTo(T12[idx][i], solution, ixlsq, vinegarGf16, idxlsq, l); + } + } + + // Copy remaining oil variables + System.arraycopy(solution, 0, vinegarGf16, vxlsq, oxlsq); + GF16.encode(vinegarGf16, ptSignature, vinegarGf16.length); + + System.arraycopy(arraySalt, 0, ptSignature, ptSignature.length - bytesSalt, bytesSalt); + } + + boolean verifySignatureCore(byte[] digest, byte[] signature, byte[] publicKeySeed, MapGroup1 map1, byte[][][][] p22) + { + final int lsq = params.getLsq(); + final int o = params.getO(); + final int oxlsq = o * lsq; + final int bytesHash = (oxlsq + 1) >>> 1; + final int bytesSalt = params.getSaltLength(); + final int m = params.getM(); + final int n = params.getN(); + final int nxlsq = n * lsq; + + int bytesSignature = ((nxlsq) + 1) >>> 1; + + // Step 1: Regenerate signed hash using public key seed, digest and salt + byte[] signedHash = new byte[bytesHash]; + createSignedHash(publicKeySeed, publicKeySeed.length, digest, digest.length, + signature, bytesSignature, bytesSalt, signedHash, bytesHash); + + // Handle odd-length adjustment (if needed) + if (((oxlsq) & 1) != 0) + { + signedHash[bytesHash - 1] &= 0x0F; + } + + // Step 2: Convert signature to GF16 matrices + byte[] decodedSig = new byte[nxlsq]; + GF16.decode(signature, 0, decodedSig, 0, decodedSig.length); + + // Step 3: Evaluate signature using public key + byte[] computedHashBytes = new byte[m * lsq]; + evaluation(computedHashBytes, map1, p22, decodedSig);//signatureGF16Matrix); + + // Convert computed hash matrix to bytes + byte[] encodedHash = new byte[bytesHash]; + GF16.encode(computedHashBytes, encodedHash, computedHashBytes.length); + + // Step 4: Compare hashes + return Arrays.areEqual(signedHash, encodedHash); + } + + private void evaluation(byte[] hashMatrix, MapGroup1 map1, byte[][][][] p22, byte[] signature) + { + final int m = params.getM(); + final int alpha = params.getAlpha(); + final int n = params.getN(); + final int l = params.getL(); + final int lsq = params.getLsq(); + final int o = params.getO(); + + byte[][][] Left = new byte[alpha][n][lsq]; + byte[][][] Right = new byte[alpha][n][lsq]; + byte[] temp = new byte[lsq]; + + // Evaluate Left and Right matrices + for (int mi = 0, mixlsq = 0; mi < m; mi++, mixlsq += lsq) + { + for (int si = 0, sixlsq = 0; si < n; si++, sixlsq += lsq) + { + for (int a = 0; a < alpha; a++) + { + // Left[mi][a][si] = Aalpha * (sig^T * Qalpha1) + // Right[mi][a][si] = (Qalpha2 * sig) * Balpha + GF16Utils.gf16mTranMulMul(signature, sixlsq, map1.aAlpha[mi][a], map1.bAlpha[mi][a], map1.qAlpha1[mi][a], + map1.qAlpha2[mi][a], temp, Left[a][si], Right[a][si], l); + } + } + + // Process P matrices and accumulate results + for (int a = 0, miPrime = mi; a < alpha; a++, miPrime++) + { + if (miPrime >= o) + { + miPrime -= o; + } + for (int ni = 0; ni < n; ni++) + { + // sum_t0 = sum(P[miPrime][ni][nj] * Right[mi][a][nj]) + byte[] p = getPMatrix(map1, p22, miPrime, ni, 0); + GF16Utils.gf16mMul(p, Right[a][0], temp, l); + for (int nj = 1; nj < n; nj++) + { + p = getPMatrix(map1, p22, miPrime, ni, nj); + GF16Utils.gf16mMulTo(p, Right[a][nj], temp, l); + } + + // hashMatrix += Left[mi][a][ni] * temp + GF16Utils.gf16mMulTo(Left[a][ni], temp, hashMatrix, mixlsq, l); + } + } + } + } + + private byte[] getPMatrix(MapGroup1 map1, byte[][][][] p22, int mi, int ni, int nj) + { + final int v = params.getV(); + if (ni < v) + { + if (nj < v) + { + return map1.p11[mi][ni][nj]; + } + else + { + return map1.p12[mi][ni][nj - v]; + } + } + else + { + if (nj < v) + { + return map1.p21[mi][ni - v][nj]; + } + else + { + return p22[mi][ni - v][nj - v]; + } + } + } + + private int performGaussianElimination(byte[][] Gauss, byte[] solution, int size) + { + final int cols = size + 1; + + for (int i = 0; i < size; i++) + { + // Find pivot + int pivot = i; + while (pivot < size && Gauss[pivot][i] == 0) + { + pivot++; + } + + // Check for singularity + if (pivot >= size) + { + return 1; // Flag for redo + } + + // Swap rows if needed + if (pivot != i) + { + byte[] tempRow = Gauss[i]; + Gauss[i] = Gauss[pivot]; + Gauss[pivot] = tempRow; + } + + // Normalize pivot row + byte invPivot = GF16.inv(Gauss[i][i]); + for (int j = i; j < cols; j++) + { + Gauss[i][j] = GF16.mul(Gauss[i][j], invPivot); + } + + // Eliminate below + for (int j = i + 1; j < size; j++) + { + byte factor = Gauss[j][i]; + if (factor != 0) + { + for (int k = i; k < cols; k++) + { + Gauss[j][k] ^= GF16.mul(Gauss[i][k], factor); + } + } + } + } + + // Back substitution + for (int i = size - 1; i >= 0; i--) + { + byte tmp = Gauss[i][size]; + for (int j = i + 1; j < size; j++) + { + tmp ^= GF16.mul(Gauss[i][j], solution[j]); + } + solution[i] = tmp; + } + return 0; + } + + private byte[] getMessageHash(byte[] message) + { + byte[] hash = new byte[shake.getDigestSize()]; + shake.update(message, 0, message.length); + shake.doFinal(hash, 0); + return hash; + } +} diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/sphincsplus/SPHINCSPlusParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/sphincsplus/SPHINCSPlusParameters.java index 35204ee8f1..ffbad0e989 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/sphincsplus/SPHINCSPlusParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/sphincsplus/SPHINCSPlusParameters.java @@ -193,6 +193,8 @@ public static SPHINCSPlusParameters getParams(Integer id) * @return the OID for the parameter set. * @deprecated Use {@link #getID()} instead */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public static Integer getID(SPHINCSPlusParameters params) { return params.getID(); diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java index 96a5dfcd7e..b009f1b66e 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java @@ -20,7 +20,6 @@ import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.pqc.asn1.CMCEPrivateKey; import org.bouncycastle.pqc.asn1.FalconPrivateKey; -import org.bouncycastle.pqc.asn1.McElieceCCA2PrivateKey; import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import org.bouncycastle.pqc.asn1.SPHINCSPLUSPrivateKey; @@ -43,14 +42,19 @@ import org.bouncycastle.pqc.crypto.hqc.HQCParameters; import org.bouncycastle.pqc.crypto.hqc.HQCPrivateKeyParameters; import org.bouncycastle.pqc.crypto.lms.HSSPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoPrivateKeyParameters; import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters; import org.bouncycastle.pqc.crypto.mldsa.MLDSAPrivateKeyParameters; import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mlkem.MLKEMPublicKeyParameters; import org.bouncycastle.pqc.crypto.newhope.NHPrivateKeyParameters; import org.bouncycastle.pqc.crypto.ntru.NTRUParameters; import org.bouncycastle.pqc.crypto.ntru.NTRUPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusParameters; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusPrivateKeyParameters; import org.bouncycastle.pqc.crypto.ntruprime.NTRULPRimeParameters; import org.bouncycastle.pqc.crypto.ntruprime.NTRULPRimePrivateKeyParameters; import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeParameters; @@ -63,6 +67,8 @@ import org.bouncycastle.pqc.crypto.saber.SABERPrivateKeyParameters; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAParameters; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaPrivateKeyParameters; import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPrivateKeyParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusPrivateKeyParameters; @@ -73,8 +79,6 @@ import org.bouncycastle.pqc.crypto.xmss.XMSSParameters; import org.bouncycastle.pqc.crypto.xmss.XMSSPrivateKeyParameters; import org.bouncycastle.pqc.crypto.xmss.XMSSUtil; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.qtesla.QTESLAPrivateKeyParameters; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; @@ -91,7 +95,7 @@ public class PrivateKeyFactory * @throws IOException on an error decoding the key */ public static AsymmetricKeyParameter createKey(byte[] privateKeyInfoData) - throws IOException + throws IOException { if (privateKeyInfoData == null) { @@ -113,7 +117,7 @@ public static AsymmetricKeyParameter createKey(byte[] privateKeyInfoData) * @throws IOException on an error decoding the key */ public static AsymmetricKeyParameter createKey(InputStream inStr) - throws IOException + throws IOException { return createKey(PrivateKeyInfo.getInstance(new ASN1InputStream(inStr).readObject())); } @@ -126,7 +130,7 @@ public static AsymmetricKeyParameter createKey(InputStream inStr) * @throws IOException on an error decoding the key */ public static AsymmetricKeyParameter createKey(PrivateKeyInfo keyInfo) - throws IOException + throws IOException { if (keyInfo == null) { @@ -136,16 +140,10 @@ public static AsymmetricKeyParameter createKey(PrivateKeyInfo keyInfo) AlgorithmIdentifier algId = keyInfo.getPrivateKeyAlgorithm(); ASN1ObjectIdentifier algOID = algId.getAlgorithm(); - if (algOID.on(PQCObjectIdentifiers.qTESLA)) - { - ASN1OctetString qTESLAPriv = ASN1OctetString.getInstance(keyInfo.parsePrivateKey()); - - return new QTESLAPrivateKeyParameters(Utils.qTeslaLookupSecurityCategory(algId), qTESLAPriv.getOctets()); - } - else if (algOID.equals(PQCObjectIdentifiers.sphincs256)) + if (algOID.equals(PQCObjectIdentifiers.sphincs256)) { return new SPHINCSPrivateKeyParameters(ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets(), - Utils.sphincs256LookupTreeAlgName(SPHINCS256KeyParams.getInstance(algId.getParameters()))); + Utils.sphincs256LookupTreeAlgName(SPHINCS256KeyParams.getInstance(algId.getParameters()))); } else if (algOID.equals(PQCObjectIdentifiers.newHope)) { @@ -175,14 +173,14 @@ else if (algOID.on(BCObjectIdentifiers.sphincsPlus) || algOID.on(BCObjectIdentif SPHINCSPLUSPrivateKey spKey = SPHINCSPLUSPrivateKey.getInstance(obj); SPHINCSPLUSPublicKey publicKey = spKey.getPublicKey(); return new SPHINCSPlusPrivateKeyParameters(spParams, spKey.getSkseed(), spKey.getSkprf(), - publicKey.getPkseed(), publicKey.getPkroot()); + publicKey.getPkseed(), publicKey.getPkroot()); } else { return new SPHINCSPlusPrivateKeyParameters(spParams, ASN1OctetString.getInstance(obj).getOctets()); } } - else if (Utils.shldsaParams.containsKey(algOID)) + else if (Utils.slhdsaParams.containsKey(algOID)) { SLHDSAParameters spParams = Utils.slhdsaParamsLookup(algOID); ASN1OctetString slhdsaKey = parseOctetString(keyInfo.getPrivateKey(), spParams.getN() * 4); @@ -225,13 +223,47 @@ else if (algOID.on(BCObjectIdentifiers.pqc_kem_ntru)) return new NTRUPrivateKeyParameters(spParams, keyEnc); } else if (algOID.equals(NISTObjectIdentifiers.id_alg_ml_kem_512) || - algOID.equals(NISTObjectIdentifiers.id_alg_ml_kem_768) || - algOID.equals(NISTObjectIdentifiers.id_alg_ml_kem_1024)) + algOID.equals(NISTObjectIdentifiers.id_alg_ml_kem_768) || + algOID.equals(NISTObjectIdentifiers.id_alg_ml_kem_1024)) { - ASN1OctetString mlkemKey = parseOctetString(keyInfo.getPrivateKey(), 64); + ASN1Primitive mlkemKey = parsePrimitiveString(keyInfo.getPrivateKey(), 64); MLKEMParameters mlkemParams = Utils.mlkemParamsLookup(algOID); - return new MLKEMPrivateKeyParameters(mlkemParams, mlkemKey.getOctets()); + MLKEMPublicKeyParameters pubParams = null; + if (keyInfo.getPublicKeyData() != null) + { + pubParams = PublicKeyFactory.MLKEMConverter.getPublicKeyParams(mlkemParams, keyInfo.getPublicKeyData()); + } + + if (mlkemKey instanceof ASN1OctetString) + { + // TODO This should be explicitly EXPANDED_KEY or SEED (tag already removed) but is length-flexible + return new MLKEMPrivateKeyParameters(mlkemParams, ((ASN1OctetString)mlkemKey).getOctets(), pubParams); + } + else if (mlkemKey instanceof ASN1Sequence) + { + ASN1Sequence keySeq = (ASN1Sequence)mlkemKey; + byte[] seed = ASN1OctetString.getInstance(keySeq.getObjectAt(0)).getOctets(); + byte[] encoding = ASN1OctetString.getInstance(keySeq.getObjectAt(1)).getOctets(); + + // TODO This should only allow seed but is length-flexible + MLKEMPrivateKeyParameters mlkemPriv = new MLKEMPrivateKeyParameters(mlkemParams, seed, pubParams); + + /* + * RFC 9881 8.2. When receiving a private key that contains both the seed and the expandedKey, the + * recipient SHOULD perform a seed consistency check to ensure that the sender properly generated + * the private key. [..] If the check is done and the seed and the expandedKey are not consistent, + * the recipient MUST reject the private key as malformed. + */ + if (!Arrays.constantTimeAreEqual(mlkemPriv.getEncoded(), encoding)) + { + throw new IllegalArgumentException("inconsistent " + mlkemParams.getName() + " private key"); + } + + return mlkemPriv; + } + + throw new IllegalArgumentException("invalid " + mlkemParams.getName() + " private key"); } else if (algOID.on(BCObjectIdentifiers.pqc_kem_ntrulprime)) { @@ -240,10 +272,10 @@ else if (algOID.on(BCObjectIdentifiers.pqc_kem_ntrulprime)) NTRULPRimeParameters spParams = Utils.ntrulprimeParamsLookup(algOID); return new NTRULPRimePrivateKeyParameters(spParams, - ASN1OctetString.getInstance(keyEnc.getObjectAt(0)).getOctets(), - ASN1OctetString.getInstance(keyEnc.getObjectAt(1)).getOctets(), - ASN1OctetString.getInstance(keyEnc.getObjectAt(2)).getOctets(), - ASN1OctetString.getInstance(keyEnc.getObjectAt(3)).getOctets()); + ASN1OctetString.getInstance(keyEnc.getObjectAt(0)).getOctets(), + ASN1OctetString.getInstance(keyEnc.getObjectAt(1)).getOctets(), + ASN1OctetString.getInstance(keyEnc.getObjectAt(2)).getOctets(), + ASN1OctetString.getInstance(keyEnc.getObjectAt(3)).getOctets()); } else if (algOID.on(BCObjectIdentifiers.pqc_kem_sntruprime)) { @@ -252,34 +284,48 @@ else if (algOID.on(BCObjectIdentifiers.pqc_kem_sntruprime)) SNTRUPrimeParameters spParams = Utils.sntruprimeParamsLookup(algOID); return new SNTRUPrimePrivateKeyParameters(spParams, - ASN1OctetString.getInstance(keyEnc.getObjectAt(0)).getOctets(), - ASN1OctetString.getInstance(keyEnc.getObjectAt(1)).getOctets(), - ASN1OctetString.getInstance(keyEnc.getObjectAt(2)).getOctets(), - ASN1OctetString.getInstance(keyEnc.getObjectAt(3)).getOctets(), - ASN1OctetString.getInstance(keyEnc.getObjectAt(4)).getOctets()); + ASN1OctetString.getInstance(keyEnc.getObjectAt(0)).getOctets(), + ASN1OctetString.getInstance(keyEnc.getObjectAt(1)).getOctets(), + ASN1OctetString.getInstance(keyEnc.getObjectAt(2)).getOctets(), + ASN1OctetString.getInstance(keyEnc.getObjectAt(3)).getOctets(), + ASN1OctetString.getInstance(keyEnc.getObjectAt(4)).getOctets()); } else if (Utils.mldsaParams.containsKey(algOID)) { - ASN1Encodable keyObj = parseOctetString(keyInfo.getPrivateKey(), 32); - MLDSAParameters spParams = Utils.mldsaParamsLookup(algOID); + ASN1Encodable mldsaKey = parsePrimitiveString(keyInfo.getPrivateKey(), 32); + MLDSAParameters mldsaParams = Utils.mldsaParamsLookup(algOID); - if (keyObj instanceof DEROctetString) + MLDSAPublicKeyParameters pubParams = null; + if (keyInfo.getPublicKeyData() != null) { - byte[] data = ASN1OctetString.getInstance(keyObj).getOctets(); - if (keyInfo.getPublicKeyData() != null) - { - MLDSAPublicKeyParameters pubParams = PublicKeyFactory.MLDSAConverter.getPublicKeyParams(spParams, keyInfo.getPublicKeyData()); - return new MLDSAPrivateKeyParameters(spParams, data, pubParams); - } - return new MLDSAPrivateKeyParameters(spParams, data); + pubParams = PublicKeyFactory.MLDSAConverter.getPublicKeyParams(mldsaParams, keyInfo.getPublicKeyData()); } - else + + if (mldsaKey instanceof ASN1OctetString) { - throw new IOException("not supported"); + // TODO This should be explicitly EXPANDED_KEY or SEED (tag already removed) but is length-flexible + return new MLDSAPrivateKeyParameters(mldsaParams, ((ASN1OctetString)mldsaKey).getOctets(), pubParams); + } + else if (mldsaKey instanceof ASN1Sequence) + { + ASN1Sequence keySeq = (ASN1Sequence)mldsaKey; + byte[] seed = ASN1OctetString.getInstance(keySeq.getObjectAt(0)).getOctets(); + byte[] encoding = ASN1OctetString.getInstance(keySeq.getObjectAt(1)).getOctets(); + + // TODO This should only allow seed but is length-flexible + MLDSAPrivateKeyParameters mldsaPriv = new MLDSAPrivateKeyParameters(mldsaParams, seed, pubParams); + if (!Arrays.constantTimeAreEqual(mldsaPriv.getEncoded(), encoding)) + { + throw new IllegalArgumentException("inconsistent " + mldsaParams.getName() + " private key"); + } + + return mldsaPriv; } + + throw new IllegalArgumentException("invalid " + mldsaParams.getName() + " private key"); } else if (algOID.equals(BCObjectIdentifiers.dilithium2) - || algOID.equals(BCObjectIdentifiers.dilithium3) || algOID.equals(BCObjectIdentifiers.dilithium5)) + || algOID.equals(BCObjectIdentifiers.dilithium3) || algOID.equals(BCObjectIdentifiers.dilithium5)) { ASN1Encodable keyObj = keyInfo.parsePrivateKey(); DilithiumParameters dilParams = Utils.dilithiumParamsLookup(algOID); @@ -299,24 +345,24 @@ else if (algOID.equals(BCObjectIdentifiers.dilithium2) DilithiumPublicKeyParameters pubParams = PublicKeyFactory.DilithiumConverter.getPublicKeyParams(dilParams, keyInfo.getPublicKeyData()); return new DilithiumPrivateKeyParameters(dilParams, - ASN1BitString.getInstance(keyEnc.getObjectAt(1)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(2)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(3)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(4)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(5)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(6)).getOctets(), - pubParams.getT1()); // encT1 + ASN1BitString.getInstance(keyEnc.getObjectAt(1)).getOctets(), + ASN1BitString.getInstance(keyEnc.getObjectAt(2)).getOctets(), + ASN1BitString.getInstance(keyEnc.getObjectAt(3)).getOctets(), + ASN1BitString.getInstance(keyEnc.getObjectAt(4)).getOctets(), + ASN1BitString.getInstance(keyEnc.getObjectAt(5)).getOctets(), + ASN1BitString.getInstance(keyEnc.getObjectAt(6)).getOctets(), + pubParams.getT1()); // encT1 } else { return new DilithiumPrivateKeyParameters(dilParams, - ASN1BitString.getInstance(keyEnc.getObjectAt(1)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(2)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(3)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(4)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(5)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(6)).getOctets(), - null); + ASN1BitString.getInstance(keyEnc.getObjectAt(1)).getOctets(), + ASN1BitString.getInstance(keyEnc.getObjectAt(2)).getOctets(), + ASN1BitString.getInstance(keyEnc.getObjectAt(3)).getOctets(), + ASN1BitString.getInstance(keyEnc.getObjectAt(4)).getOctets(), + ASN1BitString.getInstance(keyEnc.getObjectAt(5)).getOctets(), + ASN1BitString.getInstance(keyEnc.getObjectAt(6)).getOctets(), + null); } } else if (keyObj instanceof DEROctetString) @@ -341,6 +387,13 @@ else if (algOID.equals(BCObjectIdentifiers.falcon_512) || algOID.equals(BCObject return new FalconPrivateKeyParameters(falconParams, falconKey.getf(), falconKey.getG(), falconKey.getF(), falconKey.getPublicKey().getH()); } + else if (algOID.equals(BCObjectIdentifiers.old_falcon_512) || algOID.equals(BCObjectIdentifiers.old_falcon_1024)) + { + FalconPrivateKey falconKey = FalconPrivateKey.getInstance(keyInfo.parsePrivateKey()); + FalconParameters falconParams = Utils.falconParamsLookup(algOID); + + return new FalconPrivateKeyParameters(falconParams, falconKey.getf(), falconKey.getG(), falconKey.getF(), falconKey.getPublicKey().getH()); + } else if (algOID.on(BCObjectIdentifiers.pqc_kem_bike)) { byte[] keyEnc = ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets(); @@ -375,12 +428,12 @@ else if (algOID.equals(PQCObjectIdentifiers.xmss)) try { XMSSPrivateKeyParameters.Builder keyBuilder = new XMSSPrivateKeyParameters - .Builder(new XMSSParameters(keyParams.getHeight(), Utils.getDigest(treeDigest))) - .withIndex(xmssPrivateKey.getIndex()) - .withSecretKeySeed(xmssPrivateKey.getSecretKeySeed()) - .withSecretKeyPRF(xmssPrivateKey.getSecretKeyPRF()) - .withPublicSeed(xmssPrivateKey.getPublicSeed()) - .withRoot(xmssPrivateKey.getRoot()); + .Builder(new XMSSParameters(keyParams.getHeight(), Utils.getDigest(treeDigest))) + .withIndex(xmssPrivateKey.getIndex()) + .withSecretKeySeed(xmssPrivateKey.getSecretKeySeed()) + .withSecretKeyPRF(xmssPrivateKey.getSecretKeyPRF()) + .withPublicSeed(xmssPrivateKey.getPublicSeed()) + .withRoot(xmssPrivateKey.getRoot()); if (xmssPrivateKey.getVersion() != 0) { @@ -389,7 +442,7 @@ else if (algOID.equals(PQCObjectIdentifiers.xmss)) if (xmssPrivateKey.getBdsState() != null) { - BDS bds = (BDS) XMSSUtil.deserialize(xmssPrivateKey.getBdsState(), BDS.class); + BDS bds = (BDS)XMSSUtil.deserialize(xmssPrivateKey.getBdsState(), BDS.class); keyBuilder.withBDSState(bds.withWOTSDigest(treeDigest)); } @@ -410,12 +463,12 @@ else if (algOID.equals(PQCObjectIdentifiers.xmss_mt)) XMSSMTPrivateKey xmssMtPrivateKey = XMSSMTPrivateKey.getInstance(keyInfo.parsePrivateKey()); XMSSMTPrivateKeyParameters.Builder keyBuilder = new XMSSMTPrivateKeyParameters - .Builder(new XMSSMTParameters(keyParams.getHeight(), keyParams.getLayers(), Utils.getDigest(treeDigest))) - .withIndex(xmssMtPrivateKey.getIndex()) - .withSecretKeySeed(xmssMtPrivateKey.getSecretKeySeed()) - .withSecretKeyPRF(xmssMtPrivateKey.getSecretKeyPRF()) - .withPublicSeed(xmssMtPrivateKey.getPublicSeed()) - .withRoot(xmssMtPrivateKey.getRoot()); + .Builder(new XMSSMTParameters(keyParams.getHeight(), keyParams.getLayers(), Utils.getDigest(treeDigest))) + .withIndex(xmssMtPrivateKey.getIndex()) + .withSecretKeySeed(xmssMtPrivateKey.getSecretKeySeed()) + .withSecretKeyPRF(xmssMtPrivateKey.getSecretKeyPRF()) + .withPublicSeed(xmssMtPrivateKey.getPublicSeed()) + .withRoot(xmssMtPrivateKey.getRoot()); if (xmssMtPrivateKey.getVersion() != 0) { @@ -424,7 +477,7 @@ else if (algOID.equals(PQCObjectIdentifiers.xmss_mt)) if (xmssMtPrivateKey.getBdsState() != null) { - BDSStateMap bdsState = (BDSStateMap) XMSSUtil.deserialize(xmssMtPrivateKey.getBdsState(), BDSStateMap.class); + BDSStateMap bdsState = (BDSStateMap)XMSSUtil.deserialize(xmssMtPrivateKey.getBdsState(), BDSStateMap.class); keyBuilder.withBDSState(bdsState.withWOTSDigest(treeDigest)); } @@ -435,11 +488,23 @@ else if (algOID.equals(PQCObjectIdentifiers.xmss_mt)) throw new IOException("ClassNotFoundException processing BDS state: " + e.getMessage()); } } - else if (algOID.equals(PQCObjectIdentifiers.mcElieceCca2)) + else if (algOID.on(BCObjectIdentifiers.mayo)) { - McElieceCCA2PrivateKey mKey = McElieceCCA2PrivateKey.getInstance(keyInfo.parsePrivateKey()); - - return new McElieceCCA2PrivateKeyParameters(mKey.getN(), mKey.getK(), mKey.getField(), mKey.getGoppaPoly(), mKey.getP(), Utils.getDigestName(mKey.getDigest().getAlgorithm())); + byte[] keyEnc = ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets(); + MayoParameters mayoParams = Utils.mayoParamsLookup(algOID); + return new MayoPrivateKeyParameters(mayoParams, keyEnc); + } + else if (algOID.on(BCObjectIdentifiers.snova)) + { + byte[] keyEnc = ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets(); + SnovaParameters snovaParams = Utils.snovaParamsLookup(algOID); + return new SnovaPrivateKeyParameters(snovaParams, keyEnc); + } + else if (algOID.on(BCObjectIdentifiers.ntruPlus)) + { + byte[] keyEnc = ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets(); + NTRUPlusParameters ntruPlusParams = Utils.ntruPlusParamsLookup(algOID); + return new NTRUPlusPrivateKeyParameters(ntruPlusParams, keyEnc); } else { @@ -464,15 +529,49 @@ private static ASN1OctetString parseOctetString(ASN1OctetString octStr, int expe // // possible internal OCTET STRING, possibly long form with or without the internal OCTET STRING - data = Utils.readOctetString(data); - if (data != null) + ASN1OctetString obj = Utils.parseOctetData(data); + + if (obj != null) + { + return ASN1OctetString.getInstance(obj); + } + + return octStr; + } + + /** + * So it seems for the new PQC algorithms, there's a couple of approaches to what goes in the OCTET STRING + * and in this case there may also be SEQUENCE. + */ + private static ASN1Primitive parsePrimitiveString(ASN1OctetString octStr, int expectedLength) + throws IOException + { + byte[] data = octStr.getOctets(); + // + // it's the right length for a RAW encoding, just return it. + // + if (data.length == expectedLength) + { + return octStr; + } + + // + // possible internal OCTET STRING, possibly long form with or without the internal OCTET STRING + // or possible SEQUENCE + ASN1Encodable obj = Utils.parseData(data); + + if (obj instanceof ASN1OctetString) + { + return ASN1OctetString.getInstance(obj); + } + if (obj instanceof ASN1Sequence) { - return new DEROctetString(data); + return ASN1Sequence.getInstance(obj); } return octStr; } - + private static short[] convert(byte[] octets) { short[] rv = new short[octets.length / 2]; diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java index baf84f6262..101e127081 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java @@ -3,9 +3,11 @@ import java.io.IOException; import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; @@ -14,7 +16,6 @@ import org.bouncycastle.pqc.asn1.CMCEPublicKey; import org.bouncycastle.pqc.asn1.FalconPrivateKey; import org.bouncycastle.pqc.asn1.FalconPublicKey; -import org.bouncycastle.pqc.asn1.McElieceCCA2PrivateKey; import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import org.bouncycastle.pqc.asn1.XMSSKeyParams; @@ -31,17 +32,19 @@ import org.bouncycastle.pqc.crypto.lms.Composer; import org.bouncycastle.pqc.crypto.lms.HSSPrivateKeyParameters; import org.bouncycastle.pqc.crypto.lms.LMSPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoPrivateKeyParameters; import org.bouncycastle.pqc.crypto.mldsa.MLDSAPrivateKeyParameters; -import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMPrivateKeyParameters; import org.bouncycastle.pqc.crypto.newhope.NHPrivateKeyParameters; import org.bouncycastle.pqc.crypto.ntru.NTRUPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusPrivateKeyParameters; import org.bouncycastle.pqc.crypto.ntruprime.NTRULPRimePrivateKeyParameters; import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimePrivateKeyParameters; import org.bouncycastle.pqc.crypto.picnic.PicnicPrivateKeyParameters; import org.bouncycastle.pqc.crypto.rainbow.RainbowPrivateKeyParameters; import org.bouncycastle.pqc.crypto.saber.SABERPrivateKeyParameters; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaPrivateKeyParameters; import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPrivateKeyParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusPrivateKeyParameters; import org.bouncycastle.pqc.crypto.xmss.BDS; @@ -49,8 +52,6 @@ import org.bouncycastle.pqc.crypto.xmss.XMSSMTPrivateKeyParameters; import org.bouncycastle.pqc.crypto.xmss.XMSSPrivateKeyParameters; import org.bouncycastle.pqc.crypto.xmss.XMSSUtil; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.qtesla.QTESLAPrivateKeyParameters; import org.bouncycastle.util.Pack; /** @@ -84,15 +85,7 @@ public static PrivateKeyInfo createPrivateKeyInfo(AsymmetricKeyParameter private */ public static PrivateKeyInfo createPrivateKeyInfo(AsymmetricKeyParameter privateKey, ASN1Set attributes) throws IOException { - if (privateKey instanceof QTESLAPrivateKeyParameters) - { - QTESLAPrivateKeyParameters keyParams = (QTESLAPrivateKeyParameters)privateKey; - - AlgorithmIdentifier algorithmIdentifier = Utils.qTeslaLookupAlgID(keyParams.getSecurityCategory()); - - return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(keyParams.getSecret()), attributes); - } - else if (privateKey instanceof SPHINCSPrivateKeyParameters) + if (privateKey instanceof SPHINCSPrivateKeyParameters) { SPHINCSPrivateKeyParameters params = (SPHINCSPrivateKeyParameters)privateKey; AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.sphincs256, @@ -150,7 +143,7 @@ else if (privateKey instanceof SLHDSAPrivateKeyParameters) AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.slhdsaOidLookup(params.getParameters())); - return new PrivateKeyInfo(algorithmIdentifier, params.getEncoded(), attributes, params.getPublicKey()); + return new PrivateKeyInfo(algorithmIdentifier, params.getEncoded(), attributes); } else if (privateKey instanceof PicnicPrivateKeyParameters) { @@ -192,14 +185,6 @@ else if (privateKey instanceof XMSSMTPrivateKeyParameters) return new PrivateKeyInfo(algorithmIdentifier, xmssmtCreateKeyStructure(keyParams), attributes); } - else if (privateKey instanceof McElieceCCA2PrivateKeyParameters) - { - McElieceCCA2PrivateKeyParameters priv = (McElieceCCA2PrivateKeyParameters)privateKey; - McElieceCCA2PrivateKey mcEliecePriv = new McElieceCCA2PrivateKey(priv.getN(), priv.getK(), priv.getField(), priv.getGoppaPoly(), priv.getP(), Utils.getAlgorithmIdentifier(priv.getDigest())); - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.mcElieceCca2); - - return new PrivateKeyInfo(algorithmIdentifier, mcEliecePriv); - } else if (privateKey instanceof FrodoPrivateKeyParameters) { FrodoPrivateKeyParameters params = (FrodoPrivateKeyParameters)privateKey; @@ -247,15 +232,15 @@ else if (privateKey instanceof MLKEMPrivateKeyParameters) AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.mlkemOidLookup(params.getParameters())); - byte[] seed = params.getSeed(); - if (seed == null) + if (params.getPreferredFormat() == MLKEMPrivateKeyParameters.SEED_ONLY) { - return new PrivateKeyInfo(algorithmIdentifier, params.getEncoded(), attributes); + return new PrivateKeyInfo(algorithmIdentifier, new DERTaggedObject(false, 0, new DEROctetString(params.getSeed())), attributes); } - else + else if (params.getPreferredFormat() == MLKEMPrivateKeyParameters.EXPANDED_KEY) { - return new PrivateKeyInfo(algorithmIdentifier, seed, attributes); + return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getEncoded()), attributes); } + return new PrivateKeyInfo(algorithmIdentifier, getBasicPQCEncoding(params.getSeed(), params.getEncoded()), attributes); } else if (privateKey instanceof NTRULPRimePrivateKeyParameters) { @@ -294,19 +279,15 @@ else if (privateKey instanceof MLDSAPrivateKeyParameters) AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.mldsaOidLookup(params.getParameters())); - byte[] seed = params.getSeed(); - if (seed == null) + if (params.getPreferredFormat() == MLDSAPrivateKeyParameters.SEED_ONLY) { - MLDSAPublicKeyParameters pubParams = params.getPublicKeyParameters(); - - return new PrivateKeyInfo(algorithmIdentifier, params.getEncoded(), attributes, pubParams.getEncoded()); + return new PrivateKeyInfo(algorithmIdentifier, new DERTaggedObject(false, 0, new DEROctetString(params.getSeed())), attributes); } - else + else if (params.getPreferredFormat() == MLDSAPrivateKeyParameters.EXPANDED_KEY) { - MLDSAPublicKeyParameters pubParams = params.getPublicKeyParameters(); - - return new PrivateKeyInfo(algorithmIdentifier, params.getSeed(), attributes); + return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getEncoded()), attributes); } + return new PrivateKeyInfo(algorithmIdentifier, getBasicPQCEncoding(params.getSeed(), params.getEncoded()), attributes); } else if (privateKey instanceof DilithiumPrivateKeyParameters) { @@ -339,6 +320,27 @@ else if (privateKey instanceof RainbowPrivateKeyParameters) byte[] encoding = params.getEncoded(); return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(encoding), attributes); } + else if (privateKey instanceof MayoPrivateKeyParameters) + { + MayoPrivateKeyParameters params = (MayoPrivateKeyParameters)privateKey; + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.mayoOidLookup(params.getParameters())); + byte[] encoding = params.getEncoded(); + return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(encoding), attributes); + } + else if (privateKey instanceof SnovaPrivateKeyParameters) + { + SnovaPrivateKeyParameters params = (SnovaPrivateKeyParameters)privateKey; + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.snovaOidLookup(params.getParameters())); + byte[] encoding = params.getEncoded(); + return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(encoding), attributes); + } + else if (privateKey instanceof NTRUPlusPrivateKeyParameters) + { + NTRUPlusPrivateKeyParameters params = (NTRUPlusPrivateKeyParameters)privateKey; + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.ntruPlusOidLookup(params.getParameters())); + byte[] encoding = params.getEncoded(); + return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(encoding), attributes); + } else { throw new IOException("key parameters not recognized"); @@ -395,6 +397,11 @@ private static XMSSPrivateKey xmssCreateKeyStructure(XMSSPrivateKeyParameters ke } } + private static ASN1Sequence getBasicPQCEncoding(byte[] seed, byte[] expanded) + { + return new DERSequence(new DEROctetString(seed), new DEROctetString(expanded)); + } + private static XMSSMTPrivateKey xmssmtCreateKeyStructure(XMSSMTPrivateKeyParameters keyParams) throws IOException { diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java index 6f2fde3b0e..bbdbfd2cb1 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java @@ -19,8 +19,6 @@ import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers; import org.bouncycastle.pqc.asn1.CMCEPublicKey; -import org.bouncycastle.pqc.asn1.KyberPublicKey; -import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey; import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import org.bouncycastle.pqc.asn1.XMSSKeyParams; @@ -40,6 +38,8 @@ import org.bouncycastle.pqc.crypto.hqc.HQCPublicKeyParameters; import org.bouncycastle.pqc.crypto.lms.HSSPublicKeyParameters; import org.bouncycastle.pqc.crypto.lms.LMSKeyParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameters; import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters; import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters; @@ -47,6 +47,8 @@ import org.bouncycastle.pqc.crypto.newhope.NHPublicKeyParameters; import org.bouncycastle.pqc.crypto.ntru.NTRUParameters; import org.bouncycastle.pqc.crypto.ntru.NTRUPublicKeyParameters; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusParameters; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusPublicKeyParameters; import org.bouncycastle.pqc.crypto.ntruprime.NTRULPRimeParameters; import org.bouncycastle.pqc.crypto.ntruprime.NTRULPRimePublicKeyParameters; import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeParameters; @@ -59,6 +61,8 @@ import org.bouncycastle.pqc.crypto.saber.SABERPublicKeyParameters; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAParameters; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPublicKeyParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaPublicKeyParameters; import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPublicKeyParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusPublicKeyParameters; @@ -66,8 +70,6 @@ import org.bouncycastle.pqc.crypto.xmss.XMSSMTPublicKeyParameters; import org.bouncycastle.pqc.crypto.xmss.XMSSParameters; import org.bouncycastle.pqc.crypto.xmss.XMSSPublicKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PublicKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.qtesla.QTESLAPublicKeyParameters; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; @@ -81,8 +83,6 @@ public class PublicKeyFactory static { - converters.put(PQCObjectIdentifiers.qTESLA_p_I, new QTeslaConverter()); - converters.put(PQCObjectIdentifiers.qTESLA_p_III, new QTeslaConverter()); converters.put(PQCObjectIdentifiers.sphincs256, new SPHINCSConverter()); converters.put(PQCObjectIdentifiers.newHope, new NHConverter()); converters.put(PQCObjectIdentifiers.xmss, new XMSSConverter()); @@ -90,7 +90,6 @@ public class PublicKeyFactory converters.put(IsaraObjectIdentifiers.id_alg_xmss, new XMSSConverter()); converters.put(IsaraObjectIdentifiers.id_alg_xmssmt, new XMSSMTConverter()); converters.put(PKCSObjectIdentifiers.id_alg_hss_lms_hashsig, new LMSConverter()); - converters.put(PQCObjectIdentifiers.mcElieceCca2, new McElieceCCA2Converter()); converters.put(BCObjectIdentifiers.sphincsPlus, new SPHINCSPlusConverter()); converters.put(BCObjectIdentifiers.sphincsPlus_sha2_128s_r3, new SPHINCSPlusConverter()); @@ -186,12 +185,14 @@ public class PublicKeyFactory converters.put(BCObjectIdentifiers.ntruhrss1373, new NtruConverter()); converters.put(BCObjectIdentifiers.falcon_512, new FalconConverter()); converters.put(BCObjectIdentifiers.falcon_1024, new FalconConverter()); - converters.put(NISTObjectIdentifiers.id_alg_ml_kem_512, new KyberConverter()); - converters.put(NISTObjectIdentifiers.id_alg_ml_kem_768, new KyberConverter()); - converters.put(NISTObjectIdentifiers.id_alg_ml_kem_1024, new KyberConverter()); - converters.put(BCObjectIdentifiers.kyber512_aes, new KyberConverter()); - converters.put(BCObjectIdentifiers.kyber768_aes, new KyberConverter()); - converters.put(BCObjectIdentifiers.kyber1024_aes, new KyberConverter()); + converters.put(BCObjectIdentifiers.old_falcon_512, new FalconConverter()); + converters.put(BCObjectIdentifiers.old_falcon_1024, new FalconConverter()); + converters.put(NISTObjectIdentifiers.id_alg_ml_kem_512, new MLKEMConverter()); + converters.put(NISTObjectIdentifiers.id_alg_ml_kem_768, new MLKEMConverter()); + converters.put(NISTObjectIdentifiers.id_alg_ml_kem_1024, new MLKEMConverter()); + converters.put(BCObjectIdentifiers.kyber512_aes, new MLKEMConverter()); + converters.put(BCObjectIdentifiers.kyber768_aes, new MLKEMConverter()); + converters.put(BCObjectIdentifiers.kyber1024_aes, new MLKEMConverter()); converters.put(BCObjectIdentifiers.ntrulpr653, new NTRULPrimeConverter()); converters.put(BCObjectIdentifiers.ntrulpr761, new NTRULPrimeConverter()); converters.put(BCObjectIdentifiers.ntrulpr857, new NTRULPrimeConverter()); @@ -253,6 +254,60 @@ public class PublicKeyFactory converters.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256, new SLHDSAConverter()); converters.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256, new SLHDSAConverter()); converters.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256, new SLHDSAConverter()); + + converters.put(BCObjectIdentifiers.mayo1, new MayoConverter()); + converters.put(BCObjectIdentifiers.mayo2, new MayoConverter()); + converters.put(BCObjectIdentifiers.mayo3, new MayoConverter()); + converters.put(BCObjectIdentifiers.mayo5, new MayoConverter()); + + converters.put(BCObjectIdentifiers.snova_24_5_4_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_24_5_4_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_24_5_4_shake_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_24_5_4_shake_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_24_5_5_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_24_5_5_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_24_5_5_shake_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_24_5_5_shake_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_25_8_3_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_25_8_3_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_25_8_3_shake_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_25_8_3_shake_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_29_6_5_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_29_6_5_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_29_6_5_shake_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_29_6_5_shake_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_37_8_4_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_37_8_4_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_37_8_4_shake_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_37_8_4_shake_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_37_17_2_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_37_17_2_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_37_17_2_shake_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_37_17_2_shake_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_49_11_3_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_49_11_3_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_49_11_3_shake_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_49_11_3_shake_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_56_25_2_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_56_25_2_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_56_25_2_shake_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_56_25_2_shake_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_60_10_4_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_60_10_4_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_60_10_4_shake_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_60_10_4_shake_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_66_15_3_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_66_15_3_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_66_15_3_shake_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_66_15_3_shake_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_75_33_2_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_75_33_2_ssk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_75_33_2_shake_esk, new SnovaConverter()); + converters.put(BCObjectIdentifiers.snova_75_33_2_shake_ssk, new SnovaConverter()); + + converters.put(BCObjectIdentifiers.ntruPlus768, new NTRUPlusConverter()); + converters.put(BCObjectIdentifiers.ntruPlus864, new NTRUPlusConverter()); + converters.put(BCObjectIdentifiers.ntruPlus1152, new NTRUPlusConverter()); } /** @@ -340,17 +395,7 @@ private static abstract class SubjectPublicKeyInfoConverter abstract AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) throws IOException; } - - private static class QTeslaConverter - extends SubjectPublicKeyInfoConverter - { - AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) - throws IOException - { - return new QTESLAPublicKeyParameters(Utils.qTeslaLookupSecurityCategory(keyInfo.getAlgorithm()), keyInfo.getPublicKeyData().getOctets()); - } - } - + private static class SPHINCSConverter extends SubjectPublicKeyInfoConverter { @@ -438,11 +483,11 @@ AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Obje throws IOException { byte[] keyEnc = keyInfo.getPublicKeyData().getOctets(); - byte[] data = Utils.readOctetString(keyEnc); + ASN1OctetString data = (ASN1OctetString)Utils.parseData(keyEnc); if (data != null) { - return getLmsKeyParameters(data); + return getLmsKeyParameters(data.getOctets()); } return getLmsKeyParameters(keyEnc); @@ -520,18 +565,6 @@ AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Obje } } - private static class McElieceCCA2Converter - extends SubjectPublicKeyInfoConverter - { - AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) - throws IOException - { - McElieceCCA2PublicKey mKey = McElieceCCA2PublicKey.getInstance(keyInfo.parsePublicKey()); - - return new McElieceCCA2PublicKeyParameters(mKey.getN(), mKey.getT(), mKey.getG(), Utils.getDigestName(mKey.getDigest().getAlgorithm())); - } - } - private static class FrodoConverter extends SubjectPublicKeyInfoConverter { @@ -567,11 +600,11 @@ AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Obje throws IOException { byte[] keyEnc = keyInfo.getPublicKeyData().getOctets(); - byte[] data = Utils.readOctetString(keyEnc); + ASN1OctetString data = Utils.parseOctetData(keyEnc); if (data != null) { - return getNtruPublicKeyParameters(keyInfo, data); + return getNtruPublicKeyParameters(keyInfo, data.getOctets()); } return getNtruPublicKeyParameters(keyInfo, keyEnc); @@ -602,25 +635,42 @@ AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Obje } } - private static class KyberConverter + static class MLKEMConverter extends SubjectPublicKeyInfoConverter { AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) throws IOException { - MLKEMParameters kyberParameters = Utils.mlkemParamsLookup(keyInfo.getAlgorithm().getAlgorithm()); + MLKEMParameters parameters = Utils.mlkemParamsLookup(keyInfo.getAlgorithm().getAlgorithm()); + + // we're a raw encoding + return new MLKEMPublicKeyParameters(parameters, keyInfo.getPublicKeyData().getOctets()); + } + static MLKEMPublicKeyParameters getPublicKeyParams(MLKEMParameters parameters, ASN1BitString publicKeyData) + { try { - ASN1Primitive obj = keyInfo.parsePublicKey(); - KyberPublicKey kyberKey = KyberPublicKey.getInstance(obj); + ASN1Primitive obj = ASN1Primitive.fromByteArray(publicKeyData.getOctets()); + if (obj instanceof ASN1Sequence) + { + ASN1Sequence keySeq = ASN1Sequence.getInstance(obj); + + return new MLKEMPublicKeyParameters(parameters, + ASN1OctetString.getInstance(keySeq.getObjectAt(0)).getOctets(), + ASN1OctetString.getInstance(keySeq.getObjectAt(1)).getOctets()); + } + else + { + byte[] encKey = ASN1OctetString.getInstance(obj).getOctets(); - return new MLKEMPublicKeyParameters(kyberParameters, kyberKey.getT(), kyberKey.getRho()); + return new MLKEMPublicKeyParameters(parameters, encKey); + } } catch (Exception e) { // we're a raw encoding - return new MLKEMPublicKeyParameters(kyberParameters, keyInfo.getPublicKeyData().getOctets()); + return new MLKEMPublicKeyParameters(parameters, publicKeyData.getOctets()); } } } @@ -703,7 +753,7 @@ AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Obje return getPublicKeyParams(dilithiumParams, keyInfo.getPublicKeyData()); } - static MLDSAPublicKeyParameters getPublicKeyParams(MLDSAParameters dilithiumParams, ASN1BitString publicKeyData) + static MLDSAPublicKeyParameters getPublicKeyParams(MLDSAParameters mlDsaParams, ASN1BitString publicKeyData) { try { @@ -712,7 +762,7 @@ static MLDSAPublicKeyParameters getPublicKeyParams(MLDSAParameters dilithiumPara { ASN1Sequence keySeq = ASN1Sequence.getInstance(obj); - return new MLDSAPublicKeyParameters(dilithiumParams, + return new MLDSAPublicKeyParameters(mlDsaParams, ASN1OctetString.getInstance(keySeq.getObjectAt(0)).getOctets(), ASN1OctetString.getInstance(keySeq.getObjectAt(1)).getOctets()); } @@ -720,13 +770,13 @@ static MLDSAPublicKeyParameters getPublicKeyParams(MLDSAParameters dilithiumPara { byte[] encKey = ASN1OctetString.getInstance(obj).getOctets(); - return new MLDSAPublicKeyParameters(dilithiumParams, encKey); + return new MLDSAPublicKeyParameters(mlDsaParams, encKey); } } catch (Exception e) { // we're a raw encoding - return new MLDSAPublicKeyParameters(dilithiumParams, publicKeyData.getOctets()); + return new MLDSAPublicKeyParameters(mlDsaParams, publicKeyData.getOctets()); } } } @@ -820,4 +870,46 @@ AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Obje return new RainbowPublicKeyParameters(rainbowParams, keyEnc); } } + + private static class MayoConverter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + throws IOException + { + byte[] keyEnc = ASN1OctetString.getInstance(keyInfo.parsePublicKey()).getOctets(); + + MayoParameters mayoParams = Utils.mayoParamsLookup(keyInfo.getAlgorithm().getAlgorithm()); + + return new MayoPublicKeyParameters(mayoParams, keyEnc); + } + } + + private static class SnovaConverter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + throws IOException + { + byte[] keyEnc = ASN1OctetString.getInstance(keyInfo.parsePublicKey()).getOctets(); + + SnovaParameters snovaParams = Utils.snovaParamsLookup(keyInfo.getAlgorithm().getAlgorithm()); + + return new SnovaPublicKeyParameters(snovaParams, keyEnc); + } + } + + private static class NTRUPlusConverter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + throws IOException + { + byte[] keyEnc = ASN1OctetString.getInstance(keyInfo.parsePublicKey()).getOctets(); + + NTRUPlusParameters ntruPlusParams = Utils.ntruPlusParamsLookup(keyInfo.getAlgorithm().getAlgorithm()); + + return new NTRUPlusPublicKeyParameters(ntruPlusParams, keyEnc); + } + } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java index f46a283c5d..88ff88981b 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java @@ -9,7 +9,6 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers; -import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey; import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import org.bouncycastle.pqc.asn1.XMSSKeyParams; @@ -25,22 +24,23 @@ import org.bouncycastle.pqc.crypto.lms.Composer; import org.bouncycastle.pqc.crypto.lms.HSSPublicKeyParameters; import org.bouncycastle.pqc.crypto.lms.LMSPublicKeyParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameters; import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMPublicKeyParameters; import org.bouncycastle.pqc.crypto.newhope.NHPublicKeyParameters; import org.bouncycastle.pqc.crypto.ntru.NTRUPublicKeyParameters; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusPublicKeyParameters; import org.bouncycastle.pqc.crypto.ntruprime.NTRULPRimePublicKeyParameters; import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimePublicKeyParameters; import org.bouncycastle.pqc.crypto.picnic.PicnicPublicKeyParameters; import org.bouncycastle.pqc.crypto.rainbow.RainbowPublicKeyParameters; import org.bouncycastle.pqc.crypto.saber.SABERPublicKeyParameters; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPublicKeyParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaPublicKeyParameters; import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPublicKeyParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusPublicKeyParameters; import org.bouncycastle.pqc.crypto.xmss.XMSSMTPublicKeyParameters; import org.bouncycastle.pqc.crypto.xmss.XMSSPublicKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PublicKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.qtesla.QTESLAPublicKeyParameters; /** * Factory to create ASN.1 subject public key info objects from lightweight public keys. @@ -62,14 +62,7 @@ private SubjectPublicKeyInfoFactory() public static SubjectPublicKeyInfo createSubjectPublicKeyInfo(AsymmetricKeyParameter publicKey) throws IOException { - if (publicKey instanceof QTESLAPublicKeyParameters) - { - QTESLAPublicKeyParameters keyParams = (QTESLAPublicKeyParameters)publicKey; - AlgorithmIdentifier algorithmIdentifier = Utils.qTeslaLookupAlgID(keyParams.getSecurityCategory()); - - return new SubjectPublicKeyInfo(algorithmIdentifier, keyParams.getPublicData()); - } - else if (publicKey instanceof SPHINCSPublicKeyParameters) + if (publicKey instanceof SPHINCSPublicKeyParameters) { SPHINCSPublicKeyParameters params = (SPHINCSPublicKeyParameters)publicKey; @@ -171,14 +164,6 @@ else if (publicKey instanceof XMSSMTPublicKeyParameters) return new SubjectPublicKeyInfo(algorithmIdentifier, new XMSSMTPublicKey(keyParams.getPublicSeed(), keyParams.getRoot())); } } - else if (publicKey instanceof McElieceCCA2PublicKeyParameters) - { - McElieceCCA2PublicKeyParameters pub = (McElieceCCA2PublicKeyParameters)publicKey; - McElieceCCA2PublicKey mcEliecePub = new McElieceCCA2PublicKey(pub.getN(), pub.getT(), pub.getG(), Utils.getAlgorithmIdentifier(pub.getDigest())); - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.mcElieceCca2); - - return new SubjectPublicKeyInfo(algorithmIdentifier, mcEliecePub); - } else if (publicKey instanceof FrodoPublicKeyParameters) { FrodoPublicKeyParameters params = (FrodoPublicKeyParameters)publicKey; @@ -196,7 +181,7 @@ else if (publicKey instanceof SABERPublicKeyParameters) byte[] encoding = params.getEncoded(); AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.saberOidLookup(params.getParameters())); - + return new SubjectPublicKeyInfo(algorithmIdentifier, new DERSequence(new DEROctetString(encoding))); } else if (publicKey instanceof PicnicPublicKeyParameters) @@ -274,7 +259,7 @@ else if (publicKey instanceof MLDSAPublicKeyParameters) } else if (publicKey instanceof BIKEPublicKeyParameters) { - BIKEPublicKeyParameters params = (BIKEPublicKeyParameters) publicKey; + BIKEPublicKeyParameters params = (BIKEPublicKeyParameters)publicKey; byte[] encoding = params.getEncoded(); @@ -302,6 +287,27 @@ else if (publicKey instanceof RainbowPublicKeyParameters) return new SubjectPublicKeyInfo(algorithmIdentifier, new DEROctetString(encoding)); } + else if (publicKey instanceof MayoPublicKeyParameters) + { + MayoPublicKeyParameters params = (MayoPublicKeyParameters)publicKey; + byte[] encoding = params.getEncoded(); + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.mayoOidLookup(params.getParameters())); + return new SubjectPublicKeyInfo(algorithmIdentifier, new DEROctetString(encoding)); + } + else if (publicKey instanceof SnovaPublicKeyParameters) + { + SnovaPublicKeyParameters params = (SnovaPublicKeyParameters)publicKey; + byte[] encoding = params.getEncoded(); + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.snovaOidLookup(params.getParameters())); + return new SubjectPublicKeyInfo(algorithmIdentifier, new DEROctetString(encoding)); + } + else if (publicKey instanceof NTRUPlusPublicKeyParameters) + { + NTRUPlusPublicKeyParameters params = (NTRUPlusPublicKeyParameters)publicKey; + byte[] encoding = params.getEncoded(); + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.ntruPlusOidLookup(params.getParameters())); + return new SubjectPublicKeyInfo(algorithmIdentifier, new DEROctetString(encoding)); + } else { throw new IOException("key parameters not recognized"); diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java index 2b4b420e13..9e78a36277 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java @@ -1,11 +1,14 @@ package org.bouncycastle.pqc.crypto.util; import java.io.ByteArrayInputStream; -import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.bc.BCObjectIdentifiers; @@ -16,7 +19,6 @@ import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.digests.SHAKEDigest; import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers; -import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import org.bouncycastle.pqc.crypto.bike.BIKEParameters; import org.bouncycastle.pqc.crypto.cmce.CMCEParameters; @@ -24,27 +26,24 @@ import org.bouncycastle.pqc.crypto.falcon.FalconParameters; import org.bouncycastle.pqc.crypto.frodo.FrodoParameters; import org.bouncycastle.pqc.crypto.hqc.HQCParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoParameters; import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters; import org.bouncycastle.pqc.crypto.ntru.NTRUParameters; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusParameters; import org.bouncycastle.pqc.crypto.ntruprime.NTRULPRimeParameters; import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeParameters; import org.bouncycastle.pqc.crypto.picnic.PicnicParameters; import org.bouncycastle.pqc.crypto.rainbow.RainbowParameters; import org.bouncycastle.pqc.crypto.saber.SABERParameters; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaParameters; import org.bouncycastle.pqc.crypto.sphincs.SPHINCSKeyParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusParameters; import org.bouncycastle.pqc.crypto.xmss.XMSSKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.qtesla.QTESLASecurityCategory; -import org.bouncycastle.util.Integers; -import org.bouncycastle.util.io.Streams; class Utils { - static final AlgorithmIdentifier AlgID_qTESLA_p_I = new AlgorithmIdentifier(PQCObjectIdentifiers.qTESLA_p_I); - static final AlgorithmIdentifier AlgID_qTESLA_p_III = new AlgorithmIdentifier(PQCObjectIdentifiers.qTESLA_p_III); - static final AlgorithmIdentifier SPHINCS_SHA3_256 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha3_256); static final AlgorithmIdentifier SPHINCS_SHA512_256 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512_256); @@ -53,8 +52,6 @@ class Utils static final AlgorithmIdentifier XMSS_SHAKE128 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake128); static final AlgorithmIdentifier XMSS_SHAKE256 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256); - static final Map categories = new HashMap(); - static final Map picnicOids = new HashMap(); static final Map picnicParams = new HashMap(); @@ -103,15 +100,20 @@ class Utils static final Map mldsaOids = new HashMap(); static final Map mldsaParams = new HashMap(); - static final Map shldsaOids = new HashMap(); - static final Map shldsaParams = new HashMap(); + static final Map slhdsaOids = new HashMap(); + static final Map slhdsaParams = new HashMap(); - static - { - categories.put(PQCObjectIdentifiers.qTESLA_p_I, Integers.valueOf(QTESLASecurityCategory.PROVABLY_SECURE_I)); - categories.put(PQCObjectIdentifiers.qTESLA_p_III, Integers.valueOf(QTESLASecurityCategory.PROVABLY_SECURE_III)); + static final Map mayoOids = new HashMap(); + static final Map mayoParams = new HashMap(); + static final Map snovaOids = new HashMap(); + static final Map snovaParams = new HashMap(); + static final Map ntruPlusOids = new HashMap(); + static final Map ntruPlusParams = new HashMap(); + + static + { mcElieceOids.put(CMCEParameters.mceliece348864r3, BCObjectIdentifiers.mceliece348864_r3); mcElieceOids.put(CMCEParameters.mceliece348864fr3, BCObjectIdentifiers.mceliece348864f_r3); mcElieceOids.put(CMCEParameters.mceliece460896r3, BCObjectIdentifiers.mceliece460896_r3); @@ -231,6 +233,8 @@ class Utils falconParams.put(BCObjectIdentifiers.falcon_512, FalconParameters.falcon_512); falconParams.put(BCObjectIdentifiers.falcon_1024, FalconParameters.falcon_1024); + falconParams.put(BCObjectIdentifiers.old_falcon_512, FalconParameters.falcon_512); + falconParams.put(BCObjectIdentifiers.old_falcon_1024, FalconParameters.falcon_1024); mlkemOids.put(MLKEMParameters.ml_kem_512, NISTObjectIdentifiers.id_alg_ml_kem_512); mlkemOids.put(MLKEMParameters.ml_kem_768, NISTObjectIdentifiers.id_alg_ml_kem_768); @@ -320,57 +324,57 @@ class Utils rainbowOids.put(RainbowParameters.rainbowVcircumzenithal, BCObjectIdentifiers.rainbow_V_circumzenithal); rainbowOids.put(RainbowParameters.rainbowVcompressed, BCObjectIdentifiers.rainbow_V_compressed); - shldsaOids.put(SLHDSAParameters.sha2_128s, NISTObjectIdentifiers.id_slh_dsa_sha2_128s); - shldsaOids.put(SLHDSAParameters.sha2_128f, NISTObjectIdentifiers.id_slh_dsa_sha2_128f); - shldsaOids.put(SLHDSAParameters.sha2_192s, NISTObjectIdentifiers.id_slh_dsa_sha2_192s); - shldsaOids.put(SLHDSAParameters.sha2_192f, NISTObjectIdentifiers.id_slh_dsa_sha2_192f); - shldsaOids.put(SLHDSAParameters.sha2_256s, NISTObjectIdentifiers.id_slh_dsa_sha2_256s); - shldsaOids.put(SLHDSAParameters.sha2_256f, NISTObjectIdentifiers.id_slh_dsa_sha2_256f); - shldsaOids.put(SLHDSAParameters.shake_128s, NISTObjectIdentifiers.id_slh_dsa_shake_128s); - shldsaOids.put(SLHDSAParameters.shake_128f, NISTObjectIdentifiers.id_slh_dsa_shake_128f); - shldsaOids.put(SLHDSAParameters.shake_192s, NISTObjectIdentifiers.id_slh_dsa_shake_192s); - shldsaOids.put(SLHDSAParameters.shake_192f, NISTObjectIdentifiers.id_slh_dsa_shake_192f); - shldsaOids.put(SLHDSAParameters.shake_256s, NISTObjectIdentifiers.id_slh_dsa_shake_256s); - shldsaOids.put(SLHDSAParameters.shake_256f, NISTObjectIdentifiers.id_slh_dsa_shake_256f); - - shldsaOids.put(SLHDSAParameters.sha2_128s_with_sha256, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128s_with_sha256); - shldsaOids.put(SLHDSAParameters.sha2_128f_with_sha256, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128f_with_sha256); - shldsaOids.put(SLHDSAParameters.sha2_192s_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192s_with_sha512); - shldsaOids.put(SLHDSAParameters.sha2_192f_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192f_with_sha512); - shldsaOids.put(SLHDSAParameters.sha2_256s_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256s_with_sha512); - shldsaOids.put(SLHDSAParameters.sha2_256f_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256f_with_sha512); - shldsaOids.put(SLHDSAParameters.shake_128s_with_shake128, NISTObjectIdentifiers.id_hash_slh_dsa_shake_128s_with_shake128); - shldsaOids.put(SLHDSAParameters.shake_128f_with_shake128, NISTObjectIdentifiers.id_hash_slh_dsa_shake_128f_with_shake128); - shldsaOids.put(SLHDSAParameters.shake_192s_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_192s_with_shake256); - shldsaOids.put(SLHDSAParameters.shake_192f_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256); - shldsaOids.put(SLHDSAParameters.shake_256s_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256); - shldsaOids.put(SLHDSAParameters.shake_256f_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256); - - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_128s, SLHDSAParameters.sha2_128s); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_128f, SLHDSAParameters.sha2_128f); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_192s, SLHDSAParameters.sha2_192s); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_192f, SLHDSAParameters.sha2_192f); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_256s, SLHDSAParameters.sha2_256s); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_256f, SLHDSAParameters.sha2_256f); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_128s, SLHDSAParameters.shake_128s); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_128f, SLHDSAParameters.shake_128f); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_192s, SLHDSAParameters.shake_192s); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_192f, SLHDSAParameters.shake_192f); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_256s, SLHDSAParameters.shake_256s); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_256f, SLHDSAParameters.shake_256f); - - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128s_with_sha256, SLHDSAParameters.sha2_128s_with_sha256); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128f_with_sha256, SLHDSAParameters.sha2_128f_with_sha256); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192s_with_sha512, SLHDSAParameters.sha2_192s_with_sha512); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192f_with_sha512, SLHDSAParameters.sha2_192f_with_sha512); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256s_with_sha512, SLHDSAParameters.sha2_256s_with_sha512); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256f_with_sha512, SLHDSAParameters.sha2_256f_with_sha512); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_128s_with_shake128, SLHDSAParameters.shake_128s_with_shake128); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_128f_with_shake128, SLHDSAParameters.shake_128f_with_shake128); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_192s_with_shake256, SLHDSAParameters.shake_192s_with_shake256); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256, SLHDSAParameters.shake_192f_with_shake256); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256, SLHDSAParameters.shake_256s_with_shake256); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256, SLHDSAParameters.shake_256f_with_shake256); + slhdsaOids.put(SLHDSAParameters.sha2_128s, NISTObjectIdentifiers.id_slh_dsa_sha2_128s); + slhdsaOids.put(SLHDSAParameters.sha2_128f, NISTObjectIdentifiers.id_slh_dsa_sha2_128f); + slhdsaOids.put(SLHDSAParameters.sha2_192s, NISTObjectIdentifiers.id_slh_dsa_sha2_192s); + slhdsaOids.put(SLHDSAParameters.sha2_192f, NISTObjectIdentifiers.id_slh_dsa_sha2_192f); + slhdsaOids.put(SLHDSAParameters.sha2_256s, NISTObjectIdentifiers.id_slh_dsa_sha2_256s); + slhdsaOids.put(SLHDSAParameters.sha2_256f, NISTObjectIdentifiers.id_slh_dsa_sha2_256f); + slhdsaOids.put(SLHDSAParameters.shake_128s, NISTObjectIdentifiers.id_slh_dsa_shake_128s); + slhdsaOids.put(SLHDSAParameters.shake_128f, NISTObjectIdentifiers.id_slh_dsa_shake_128f); + slhdsaOids.put(SLHDSAParameters.shake_192s, NISTObjectIdentifiers.id_slh_dsa_shake_192s); + slhdsaOids.put(SLHDSAParameters.shake_192f, NISTObjectIdentifiers.id_slh_dsa_shake_192f); + slhdsaOids.put(SLHDSAParameters.shake_256s, NISTObjectIdentifiers.id_slh_dsa_shake_256s); + slhdsaOids.put(SLHDSAParameters.shake_256f, NISTObjectIdentifiers.id_slh_dsa_shake_256f); + + slhdsaOids.put(SLHDSAParameters.sha2_128s_with_sha256, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128s_with_sha256); + slhdsaOids.put(SLHDSAParameters.sha2_128f_with_sha256, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128f_with_sha256); + slhdsaOids.put(SLHDSAParameters.sha2_192s_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192s_with_sha512); + slhdsaOids.put(SLHDSAParameters.sha2_192f_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192f_with_sha512); + slhdsaOids.put(SLHDSAParameters.sha2_256s_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256s_with_sha512); + slhdsaOids.put(SLHDSAParameters.sha2_256f_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256f_with_sha512); + slhdsaOids.put(SLHDSAParameters.shake_128s_with_shake128, NISTObjectIdentifiers.id_hash_slh_dsa_shake_128s_with_shake128); + slhdsaOids.put(SLHDSAParameters.shake_128f_with_shake128, NISTObjectIdentifiers.id_hash_slh_dsa_shake_128f_with_shake128); + slhdsaOids.put(SLHDSAParameters.shake_192s_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_192s_with_shake256); + slhdsaOids.put(SLHDSAParameters.shake_192f_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256); + slhdsaOids.put(SLHDSAParameters.shake_256s_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256); + slhdsaOids.put(SLHDSAParameters.shake_256f_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256); + + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_128s, SLHDSAParameters.sha2_128s); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_128f, SLHDSAParameters.sha2_128f); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_192s, SLHDSAParameters.sha2_192s); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_192f, SLHDSAParameters.sha2_192f); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_256s, SLHDSAParameters.sha2_256s); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_256f, SLHDSAParameters.sha2_256f); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_128s, SLHDSAParameters.shake_128s); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_128f, SLHDSAParameters.shake_128f); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_192s, SLHDSAParameters.shake_192s); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_192f, SLHDSAParameters.shake_192f); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_256s, SLHDSAParameters.shake_256s); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_256f, SLHDSAParameters.shake_256f); + + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128s_with_sha256, SLHDSAParameters.sha2_128s_with_sha256); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128f_with_sha256, SLHDSAParameters.sha2_128f_with_sha256); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192s_with_sha512, SLHDSAParameters.sha2_192s_with_sha512); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192f_with_sha512, SLHDSAParameters.sha2_192f_with_sha512); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256s_with_sha512, SLHDSAParameters.sha2_256s_with_sha512); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256f_with_sha512, SLHDSAParameters.sha2_256f_with_sha512); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_128s_with_shake128, SLHDSAParameters.shake_128s_with_shake128); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_128f_with_shake128, SLHDSAParameters.shake_128f_with_shake128); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_192s_with_shake256, SLHDSAParameters.shake_192s_with_shake256); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256, SLHDSAParameters.shake_192f_with_shake256); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256, SLHDSAParameters.shake_256s_with_shake256); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256, SLHDSAParameters.shake_256f_with_shake256); sphincsPlusOids.put(SLHDSAParameters.sha2_128s, BCObjectIdentifiers.sphincsPlus_sha2_128s); sphincsPlusOids.put(SLHDSAParameters.sha2_128f, BCObjectIdentifiers.sphincsPlus_sha2_128f); @@ -471,34 +475,124 @@ class Utils sphincsPlusParams.put(BCObjectIdentifiers.sphincsPlus_shake_256f_r3_simple, SPHINCSPlusParameters.shake_256f); sphincsPlusParams.put(BCObjectIdentifiers.sphincsPlus_haraka_256s_r3_simple, SPHINCSPlusParameters.haraka_256s_simple); sphincsPlusParams.put(BCObjectIdentifiers.sphincsPlus_haraka_256f_r3_simple, SPHINCSPlusParameters.haraka_256f_simple); + + mayoOids.put(MayoParameters.mayo1, BCObjectIdentifiers.mayo1); + mayoOids.put(MayoParameters.mayo2, BCObjectIdentifiers.mayo2); + mayoOids.put(MayoParameters.mayo3, BCObjectIdentifiers.mayo3); + mayoOids.put(MayoParameters.mayo5, BCObjectIdentifiers.mayo5); + + mayoParams.put(BCObjectIdentifiers.mayo1, MayoParameters.mayo1); + mayoParams.put(BCObjectIdentifiers.mayo2, MayoParameters.mayo2); + mayoParams.put(BCObjectIdentifiers.mayo3, MayoParameters.mayo3); + mayoParams.put(BCObjectIdentifiers.mayo5, MayoParameters.mayo5); + + snovaOids.put(SnovaParameters.SNOVA_24_5_4_SSK, BCObjectIdentifiers.snova_24_5_4_ssk); + snovaOids.put(SnovaParameters.SNOVA_24_5_4_ESK, BCObjectIdentifiers.snova_24_5_4_esk); + snovaOids.put(SnovaParameters.SNOVA_24_5_4_SHAKE_SSK, BCObjectIdentifiers.snova_24_5_4_shake_ssk); + snovaOids.put(SnovaParameters.SNOVA_24_5_4_SHAKE_ESK, BCObjectIdentifiers.snova_24_5_4_shake_esk); + snovaOids.put(SnovaParameters.SNOVA_24_5_5_SSK, BCObjectIdentifiers.snova_24_5_5_ssk); + snovaOids.put(SnovaParameters.SNOVA_24_5_5_ESK, BCObjectIdentifiers.snova_24_5_5_esk); + snovaOids.put(SnovaParameters.SNOVA_24_5_5_SHAKE_SSK, BCObjectIdentifiers.snova_24_5_5_shake_ssk); + snovaOids.put(SnovaParameters.SNOVA_24_5_5_SHAKE_ESK, BCObjectIdentifiers.snova_24_5_5_shake_esk); + snovaOids.put(SnovaParameters.SNOVA_25_8_3_SSK, BCObjectIdentifiers.snova_25_8_3_ssk); + snovaOids.put(SnovaParameters.SNOVA_25_8_3_ESK, BCObjectIdentifiers.snova_25_8_3_esk); + snovaOids.put(SnovaParameters.SNOVA_25_8_3_SHAKE_SSK, BCObjectIdentifiers.snova_25_8_3_shake_ssk); + snovaOids.put(SnovaParameters.SNOVA_25_8_3_SHAKE_ESK, BCObjectIdentifiers.snova_25_8_3_shake_esk); + snovaOids.put(SnovaParameters.SNOVA_29_6_5_SSK, BCObjectIdentifiers.snova_29_6_5_ssk); + snovaOids.put(SnovaParameters.SNOVA_29_6_5_ESK, BCObjectIdentifiers.snova_29_6_5_esk); + snovaOids.put(SnovaParameters.SNOVA_29_6_5_SHAKE_SSK, BCObjectIdentifiers.snova_29_6_5_shake_ssk); + snovaOids.put(SnovaParameters.SNOVA_29_6_5_SHAKE_ESK, BCObjectIdentifiers.snova_29_6_5_shake_esk); + snovaOids.put(SnovaParameters.SNOVA_37_8_4_SSK, BCObjectIdentifiers.snova_37_8_4_ssk); + snovaOids.put(SnovaParameters.SNOVA_37_8_4_ESK, BCObjectIdentifiers.snova_37_8_4_esk); + snovaOids.put(SnovaParameters.SNOVA_37_8_4_SHAKE_SSK, BCObjectIdentifiers.snova_37_8_4_shake_ssk); + snovaOids.put(SnovaParameters.SNOVA_37_8_4_SHAKE_ESK, BCObjectIdentifiers.snova_37_8_4_shake_esk); + snovaOids.put(SnovaParameters.SNOVA_37_17_2_SSK, BCObjectIdentifiers.snova_37_17_2_ssk); + snovaOids.put(SnovaParameters.SNOVA_37_17_2_ESK, BCObjectIdentifiers.snova_37_17_2_esk); + snovaOids.put(SnovaParameters.SNOVA_37_17_2_SHAKE_SSK, BCObjectIdentifiers.snova_37_17_2_shake_ssk); + snovaOids.put(SnovaParameters.SNOVA_37_17_2_SHAKE_ESK, BCObjectIdentifiers.snova_37_17_2_shake_esk); + snovaOids.put(SnovaParameters.SNOVA_49_11_3_SSK, BCObjectIdentifiers.snova_49_11_3_ssk); + snovaOids.put(SnovaParameters.SNOVA_49_11_3_ESK, BCObjectIdentifiers.snova_49_11_3_esk); + snovaOids.put(SnovaParameters.SNOVA_49_11_3_SHAKE_SSK, BCObjectIdentifiers.snova_49_11_3_shake_ssk); + snovaOids.put(SnovaParameters.SNOVA_49_11_3_SHAKE_ESK, BCObjectIdentifiers.snova_49_11_3_shake_esk); + snovaOids.put(SnovaParameters.SNOVA_56_25_2_SSK, BCObjectIdentifiers.snova_56_25_2_ssk); + snovaOids.put(SnovaParameters.SNOVA_56_25_2_ESK, BCObjectIdentifiers.snova_56_25_2_esk); + snovaOids.put(SnovaParameters.SNOVA_56_25_2_SHAKE_SSK, BCObjectIdentifiers.snova_56_25_2_shake_ssk); + snovaOids.put(SnovaParameters.SNOVA_56_25_2_SHAKE_ESK, BCObjectIdentifiers.snova_56_25_2_shake_esk); + snovaOids.put(SnovaParameters.SNOVA_60_10_4_SSK, BCObjectIdentifiers.snova_60_10_4_ssk); + snovaOids.put(SnovaParameters.SNOVA_60_10_4_ESK, BCObjectIdentifiers.snova_60_10_4_esk); + snovaOids.put(SnovaParameters.SNOVA_60_10_4_SHAKE_SSK, BCObjectIdentifiers.snova_60_10_4_shake_ssk); + snovaOids.put(SnovaParameters.SNOVA_60_10_4_SHAKE_ESK, BCObjectIdentifiers.snova_60_10_4_shake_esk); + snovaOids.put(SnovaParameters.SNOVA_66_15_3_SSK, BCObjectIdentifiers.snova_66_15_3_ssk); + snovaOids.put(SnovaParameters.SNOVA_66_15_3_ESK, BCObjectIdentifiers.snova_66_15_3_esk); + snovaOids.put(SnovaParameters.SNOVA_66_15_3_SHAKE_SSK, BCObjectIdentifiers.snova_66_15_3_shake_ssk); + snovaOids.put(SnovaParameters.SNOVA_66_15_3_SHAKE_ESK, BCObjectIdentifiers.snova_66_15_3_shake_esk); + snovaOids.put(SnovaParameters.SNOVA_75_33_2_SSK, BCObjectIdentifiers.snova_75_33_2_ssk); + snovaOids.put(SnovaParameters.SNOVA_75_33_2_ESK, BCObjectIdentifiers.snova_75_33_2_esk); + snovaOids.put(SnovaParameters.SNOVA_75_33_2_SHAKE_SSK, BCObjectIdentifiers.snova_75_33_2_shake_ssk); + snovaOids.put(SnovaParameters.SNOVA_75_33_2_SHAKE_ESK, BCObjectIdentifiers.snova_75_33_2_shake_esk); + + snovaParams.put(BCObjectIdentifiers.snova_24_5_4_ssk, SnovaParameters.SNOVA_24_5_4_SSK); + snovaParams.put(BCObjectIdentifiers.snova_24_5_4_esk, SnovaParameters.SNOVA_24_5_4_ESK); + snovaParams.put(BCObjectIdentifiers.snova_24_5_4_shake_ssk, SnovaParameters.SNOVA_24_5_4_SHAKE_SSK); + snovaParams.put(BCObjectIdentifiers.snova_24_5_4_shake_esk, SnovaParameters.SNOVA_24_5_4_SHAKE_ESK); + snovaParams.put(BCObjectIdentifiers.snova_24_5_5_ssk, SnovaParameters.SNOVA_24_5_5_SSK); + snovaParams.put(BCObjectIdentifiers.snova_24_5_5_esk, SnovaParameters.SNOVA_24_5_5_ESK); + snovaParams.put(BCObjectIdentifiers.snova_24_5_5_shake_ssk, SnovaParameters.SNOVA_24_5_5_SHAKE_SSK); + snovaParams.put(BCObjectIdentifiers.snova_24_5_5_shake_esk, SnovaParameters.SNOVA_24_5_5_SHAKE_ESK); + snovaParams.put(BCObjectIdentifiers.snova_25_8_3_ssk, SnovaParameters.SNOVA_25_8_3_SSK); + snovaParams.put(BCObjectIdentifiers.snova_25_8_3_esk, SnovaParameters.SNOVA_25_8_3_ESK); + snovaParams.put(BCObjectIdentifiers.snova_25_8_3_shake_ssk, SnovaParameters.SNOVA_25_8_3_SHAKE_SSK); + snovaParams.put(BCObjectIdentifiers.snova_25_8_3_shake_esk, SnovaParameters.SNOVA_25_8_3_SHAKE_ESK); + snovaParams.put(BCObjectIdentifiers.snova_29_6_5_ssk, SnovaParameters.SNOVA_29_6_5_SSK); + snovaParams.put(BCObjectIdentifiers.snova_29_6_5_esk, SnovaParameters.SNOVA_29_6_5_ESK); + snovaParams.put(BCObjectIdentifiers.snova_29_6_5_shake_ssk, SnovaParameters.SNOVA_29_6_5_SHAKE_SSK); + snovaParams.put(BCObjectIdentifiers.snova_29_6_5_shake_esk, SnovaParameters.SNOVA_29_6_5_SHAKE_ESK); + snovaParams.put(BCObjectIdentifiers.snova_37_8_4_ssk, SnovaParameters.SNOVA_37_8_4_SSK); + snovaParams.put(BCObjectIdentifiers.snova_37_8_4_esk, SnovaParameters.SNOVA_37_8_4_ESK); + snovaParams.put(BCObjectIdentifiers.snova_37_8_4_shake_ssk, SnovaParameters.SNOVA_37_8_4_SHAKE_SSK); + snovaParams.put(BCObjectIdentifiers.snova_37_8_4_shake_esk, SnovaParameters.SNOVA_37_8_4_SHAKE_ESK); + snovaParams.put(BCObjectIdentifiers.snova_37_17_2_ssk, SnovaParameters.SNOVA_37_17_2_SSK); + snovaParams.put(BCObjectIdentifiers.snova_37_17_2_esk, SnovaParameters.SNOVA_37_17_2_ESK); + snovaParams.put(BCObjectIdentifiers.snova_37_17_2_shake_ssk, SnovaParameters.SNOVA_37_17_2_SHAKE_SSK); + snovaParams.put(BCObjectIdentifiers.snova_37_17_2_shake_esk, SnovaParameters.SNOVA_37_17_2_SHAKE_ESK); + snovaParams.put(BCObjectIdentifiers.snova_49_11_3_ssk, SnovaParameters.SNOVA_49_11_3_SSK); + snovaParams.put(BCObjectIdentifiers.snova_49_11_3_esk, SnovaParameters.SNOVA_49_11_3_ESK); + snovaParams.put(BCObjectIdentifiers.snova_49_11_3_shake_ssk, SnovaParameters.SNOVA_49_11_3_SHAKE_SSK); + snovaParams.put(BCObjectIdentifiers.snova_49_11_3_shake_esk, SnovaParameters.SNOVA_49_11_3_SHAKE_ESK); + snovaParams.put(BCObjectIdentifiers.snova_56_25_2_ssk, SnovaParameters.SNOVA_56_25_2_SSK); + snovaParams.put(BCObjectIdentifiers.snova_56_25_2_esk, SnovaParameters.SNOVA_56_25_2_ESK); + snovaParams.put(BCObjectIdentifiers.snova_56_25_2_shake_ssk, SnovaParameters.SNOVA_56_25_2_SHAKE_SSK); + snovaParams.put(BCObjectIdentifiers.snova_56_25_2_shake_esk, SnovaParameters.SNOVA_56_25_2_SHAKE_ESK); + snovaParams.put(BCObjectIdentifiers.snova_60_10_4_ssk, SnovaParameters.SNOVA_60_10_4_SSK); + snovaParams.put(BCObjectIdentifiers.snova_60_10_4_esk, SnovaParameters.SNOVA_60_10_4_ESK); + snovaParams.put(BCObjectIdentifiers.snova_60_10_4_shake_ssk, SnovaParameters.SNOVA_60_10_4_SHAKE_SSK); + snovaParams.put(BCObjectIdentifiers.snova_60_10_4_shake_esk, SnovaParameters.SNOVA_60_10_4_SHAKE_ESK); + snovaParams.put(BCObjectIdentifiers.snova_66_15_3_ssk, SnovaParameters.SNOVA_66_15_3_SSK); + snovaParams.put(BCObjectIdentifiers.snova_66_15_3_esk, SnovaParameters.SNOVA_66_15_3_ESK); + snovaParams.put(BCObjectIdentifiers.snova_66_15_3_shake_ssk, SnovaParameters.SNOVA_66_15_3_SHAKE_SSK); + snovaParams.put(BCObjectIdentifiers.snova_66_15_3_shake_esk, SnovaParameters.SNOVA_66_15_3_SHAKE_ESK); + snovaParams.put(BCObjectIdentifiers.snova_75_33_2_ssk, SnovaParameters.SNOVA_75_33_2_SSK); + snovaParams.put(BCObjectIdentifiers.snova_75_33_2_esk, SnovaParameters.SNOVA_75_33_2_ESK); + snovaParams.put(BCObjectIdentifiers.snova_75_33_2_shake_ssk, SnovaParameters.SNOVA_75_33_2_SHAKE_SSK); + snovaParams.put(BCObjectIdentifiers.snova_75_33_2_shake_esk, SnovaParameters.SNOVA_75_33_2_SHAKE_ESK); + + ntruPlusParams.put(BCObjectIdentifiers.ntruPlus768, NTRUPlusParameters.ntruplus_kem_768); + ntruPlusParams.put(BCObjectIdentifiers.ntruPlus864, NTRUPlusParameters.ntruplus_kem_864); + ntruPlusParams.put(BCObjectIdentifiers.ntruPlus1152, NTRUPlusParameters.ntruplus_kem_1152); + + ntruPlusOids.put(NTRUPlusParameters.ntruplus_kem_768, BCObjectIdentifiers.ntruPlus768); + ntruPlusOids.put(NTRUPlusParameters.ntruplus_kem_864, BCObjectIdentifiers.ntruPlus864); + ntruPlusOids.put(NTRUPlusParameters.ntruplus_kem_1152, BCObjectIdentifiers.ntruPlus1152); } static ASN1ObjectIdentifier slhdsaOidLookup(SLHDSAParameters params) { - return (ASN1ObjectIdentifier)shldsaOids.get(params); + return (ASN1ObjectIdentifier)slhdsaOids.get(params); } static SLHDSAParameters slhdsaParamsLookup(ASN1ObjectIdentifier oid) { - return (SLHDSAParameters)shldsaParams.get(oid); - } - - static int qTeslaLookupSecurityCategory(AlgorithmIdentifier algorithm) - { - return ((Integer)categories.get(algorithm.getAlgorithm())).intValue(); - } - - static AlgorithmIdentifier qTeslaLookupAlgID(int securityCategory) - { - switch (securityCategory) - { - case QTESLASecurityCategory.PROVABLY_SECURE_I: - return AlgID_qTESLA_p_I; - case QTESLASecurityCategory.PROVABLY_SECURE_III: - return AlgID_qTESLA_p_III; - default: - throw new IllegalArgumentException("unknown security category: " + securityCategory); - } + return (SLHDSAParameters)slhdsaParams.get(oid); } static AlgorithmIdentifier sphincs256LookupTreeAlgID(String treeDigest) @@ -783,18 +877,83 @@ static RainbowParameters rainbowParamsLookup(ASN1ObjectIdentifier oid) return (RainbowParameters)rainbowParams.get(oid); } - static byte[] readOctetString(byte[] data) - throws IOException + static ASN1ObjectIdentifier mayoOidLookup(MayoParameters params) + { + return (ASN1ObjectIdentifier)mayoOids.get(params); + } + + static MayoParameters mayoParamsLookup(ASN1ObjectIdentifier oid) + { + return (MayoParameters)mayoParams.get(oid); + } + + static ASN1ObjectIdentifier snovaOidLookup(SnovaParameters params) + { + return (ASN1ObjectIdentifier)snovaOids.get(params); + } + + static SnovaParameters snovaParamsLookup(ASN1ObjectIdentifier oid) + { + return (SnovaParameters)snovaParams.get(oid); + } + + static NTRUPlusParameters ntruPlusParamsLookup(ASN1ObjectIdentifier oid) { - if (data[0] == BERTags.OCTET_STRING) + return (NTRUPlusParameters)ntruPlusParams.get(oid); + } + + static ASN1ObjectIdentifier ntruPlusOidLookup(NTRUPlusParameters params) + { + return (ASN1ObjectIdentifier)ntruPlusOids.get(params); + } + + private static boolean isRaw(byte[] data) + { + // check well-formed first + ByteArrayInputStream bIn = new ByteArrayInputStream(data); + + int tag = bIn.read(); + int len = readLen(bIn); + if (len != bIn.available()) { - ByteArrayInputStream bIn = new ByteArrayInputStream(data); + return true; + } + + return false; + } + + static ASN1OctetString parseOctetData(byte[] data) + { + // check well-formed first + if (!isRaw(data)) + { + if (data[0] == BERTags.OCTET_STRING) + { + return ASN1OctetString.getInstance(data); + } + } + + return null; + } + + static ASN1Primitive parseData(byte[] data) + { + // check well-formed first + if (!isRaw(data)) + { + if (data[0] == (BERTags.SEQUENCE | BERTags.CONSTRUCTED)) + { + return ASN1Sequence.getInstance(data); + } + + if (data[0] == BERTags.OCTET_STRING) + { + return ASN1OctetString.getInstance(data); + } - int tag = bIn.read(); - int len = readLen(bIn); - if (len == bIn.available()) + if ((data[0] & 0xff) == BERTags.TAGGED) { - return Streams.readAll(bIn); + return ASN1OctetString.getInstance(ASN1TaggedObject.getInstance(data), false); } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSMTPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSMTPrivateKeyParameters.java index 3cdee493ab..9dcde26aa1 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSMTPrivateKeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSMTPrivateKeyParameters.java @@ -262,6 +262,7 @@ public XMSSMTPrivateKeyParameters build() /** * @deprecated use getEncoded() - this method will become private. */ + @Deprecated public byte[] toByteArray() { synchronized (this) diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSMTPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSMTPublicKeyParameters.java index 9b1e3d2e5d..bb43419e09 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSMTPublicKeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSMTPublicKeyParameters.java @@ -144,6 +144,7 @@ public XMSSMTPublicKeyParameters build() /** * @deprecated use getEncoded() - this method will become private. */ + @Deprecated public byte[] toByteArray() { /* oid || root || seed */ diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSPrivateKeyParameters.java index beea21ef47..5e37fdefb7 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSPrivateKeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSPrivateKeyParameters.java @@ -162,14 +162,7 @@ private XMSSPrivateKeyParameters(Builder builder) } else { - if (builder.index < ((1 << params.getHeight()) - 2) && tmpPublicSeed != null && tmpSecretKeySeed != null) - { - bdsState = new BDS(params, tmpPublicSeed, tmpSecretKeySeed, (OTSHashAddress)new OTSHashAddress.Builder().build(), builder.index); - } - else - { - bdsState = new BDS(params, (1 << params.getHeight()) - 1, builder.index); - } + bdsState = new BDS(params, tmpPublicSeed, tmpSecretKeySeed, (OTSHashAddress)new OTSHashAddress.Builder().build(), builder.index); } if (builder.maxIndex >= 0 && builder.maxIndex != bdsState.getMaxIndex()) { @@ -228,6 +221,7 @@ public XMSSPrivateKeyParameters getNextKey() *

    * Note: this will use the range [index...index + usageCount) for the current key. *

    + * * @param usageCount the number of usages the key should have. * @return a key based on the current key that can be used usageCount times. */ @@ -343,6 +337,10 @@ public Builder withPrivateKey(byte[] privateKeyVal) public XMSSPrivateKeyParameters build() { + if (!((privateKey != null) || (publicSeed != null && secretKeySeed != null))) + { + throw new IllegalStateException("publicSeed or secretKeySeed is null"); + } return new XMSSPrivateKeyParameters(this); } } @@ -350,6 +348,7 @@ public XMSSPrivateKeyParameters build() /** * @deprecated use getEncoded() - this method will become private. */ + @Deprecated public byte[] toByteArray() { synchronized (this) diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSPublicKeyParameters.java index be24df58d9..cb89612fd5 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSPublicKeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSPublicKeyParameters.java @@ -149,6 +149,7 @@ public XMSSPublicKeyParameters build() /** * @deprecated use getEncoded() - this method will become private. */ + @Deprecated public byte[] toByteArray() { /* oid || root || seed */ diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSStoreableObjectInterface.java b/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSStoreableObjectInterface.java index 1df76eca4a..f7c5fee430 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSStoreableObjectInterface.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/xmss/XMSSStoreableObjectInterface.java @@ -5,6 +5,7 @@ * * @deprecated use Encodable */ +@Deprecated public interface XMSSStoreableObjectInterface { @@ -13,5 +14,5 @@ public interface XMSSStoreableObjectInterface * * @return Byte representation of object. */ - public byte[] toByteArray(); + byte[] toByteArray(); } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingKEMExtractor.java b/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingKEMExtractor.java index cbc815f22d..657df1a12b 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingKEMExtractor.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingKEMExtractor.java @@ -1,62 +1,54 @@ package org.bouncycastle.pqc.crypto.xwing; import org.bouncycastle.crypto.EncapsulatedSecretExtractor; -import org.bouncycastle.crypto.agreement.X25519Agreement; -import org.bouncycastle.crypto.digests.SHA3Digest; -import org.bouncycastle.crypto.params.X25519PrivateKeyParameters; import org.bouncycastle.crypto.params.X25519PublicKeyParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMExtractor; -import org.bouncycastle.pqc.crypto.mlkem.MLKEMPrivateKeyParameters; import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Strings; +/** + * Implements the decapsulation process of the X-Wing hybrid Key Encapsulation Mechanism (KEM). + *

    + * This class allows the recipient to derive the shared secret from a given ciphertext using their private key, + * as defined in the X-Wing KEM specification. + *

    + * + * @see X-Wing KEM Draft + */ public class XWingKEMExtractor implements EncapsulatedSecretExtractor { + private static final int MLKEM_CIPHERTEXT_SIZE = 1088; private final XWingPrivateKeyParameters key; - private final MLKEMExtractor kemExtractor; + private final MLKEMExtractor mlkemExtractor; public XWingKEMExtractor(XWingPrivateKeyParameters privParams) { this.key = privParams; - this.kemExtractor = new MLKEMExtractor((MLKEMPrivateKeyParameters)key.getKyberPrivateKey()); + this.mlkemExtractor = new MLKEMExtractor(key.getKyberPrivateKey()); } @Override public byte[] extractSecret(byte[] encapsulation) { - // Decryption - byte[] kybSecret = kemExtractor.extractSecret(Arrays.copyOfRange(encapsulation, 0, encapsulation.length - X25519PublicKeyParameters.KEY_SIZE)); - X25519Agreement xdhAgree = new X25519Agreement(); + // 1. Split ciphertext into ML-KEM and X25519 parts + byte[] ctM = Arrays.copyOfRange(encapsulation, 0, MLKEM_CIPHERTEXT_SIZE); + byte[] ctX = Arrays.copyOfRange(encapsulation, MLKEM_CIPHERTEXT_SIZE, encapsulation.length); - byte[] k = new byte[kybSecret.length + xdhAgree.getAgreementSize()]; + // 2. Compute X25519 shared secret + byte[] ssX = XWingKEMGenerator.computeSSX(new X25519PublicKeyParameters(ctX, 0), key.getXDHPrivateKey()); - System.arraycopy(kybSecret, 0, k, 0, kybSecret.length); + // 3. Compute combiner: SHA3-256(ssM || ssX || ctX || pkX || XWING_LABEL) + byte[] kemSecret = XWingKEMGenerator.computeSharedSecret(key.getXDHPublicKey().getEncoded(), + mlkemExtractor.extractSecret(ctM), ctX, ssX); - Arrays.clear(kybSecret); - - xdhAgree.init(key.getXDHPrivateKey()); - - X25519PublicKeyParameters ephXdhPub = new X25519PublicKeyParameters(Arrays.copyOfRange(encapsulation, encapsulation.length - X25519PublicKeyParameters.KEY_SIZE, encapsulation.length)); - - xdhAgree.calculateAgreement(ephXdhPub, k, kybSecret.length); - - SHA3Digest sha3 = new SHA3Digest(256); - - sha3.update(Strings.toByteArray("\\.//^\\"), 0, 6); - sha3.update(k, 0, k.length); - sha3.update(ephXdhPub.getEncoded(), 0, X25519PublicKeyParameters.KEY_SIZE); - sha3.update(((X25519PrivateKeyParameters)key.getXDHPrivateKey()).generatePublicKey().getEncoded(), 0, X25519PublicKeyParameters.KEY_SIZE); - - byte[] kemSecret = new byte[32]; - - sha3.doFinal(kemSecret, 0); + // 4. Cleanup intermediate values + Arrays.clear(ssX); return kemSecret; } public int getEncapsulationLength() { - return kemExtractor.getEncapsulationLength() + X25519PublicKeyParameters.KEY_SIZE; + return mlkemExtractor.getEncapsulationLength() + X25519PublicKeyParameters.KEY_SIZE; } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingKEMGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingKEMGenerator.java index fe32917fb7..807ae7bfd3 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingKEMGenerator.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingKEMGenerator.java @@ -10,61 +10,88 @@ import org.bouncycastle.crypto.generators.X25519KeyPairGenerator; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.X25519KeyGenerationParameters; +import org.bouncycastle.crypto.params.X25519PrivateKeyParameters; import org.bouncycastle.crypto.params.X25519PublicKeyParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMGenerator; +import org.bouncycastle.pqc.crypto.mlkem.MLKEMPublicKeyParameters; import org.bouncycastle.pqc.crypto.util.SecretWithEncapsulationImpl; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; +/** + * Implements the encapsulation process of the X-Wing hybrid Key Encapsulation Mechanism (KEM). + *

    + * X-Wing is a general-purpose hybrid post-quantum/traditional KEM that combines X25519 and ML-KEM-768, + * as specified in the IETF draft: draft-connolly-cfrg-xwing-kem-07. + *

    + *

    + * This class facilitates the generation of ciphertexts and shared secrets using a recipient's public key. + *

    + * + * @see X-Wing KEM Draft + */ public class XWingKEMGenerator implements EncapsulatedSecretGenerator { - // the source of randomness - private final SecureRandom sr; + private final SecureRandom random; + private static final byte[] XWING_LABEL = Strings.toByteArray("\\.//^\\"); public XWingKEMGenerator(SecureRandom random) { - this.sr = random; + this.random = random; } public SecretWithEncapsulation generateEncapsulated(AsymmetricKeyParameter recipientKey) { XWingPublicKeyParameters key = (XWingPublicKeyParameters)recipientKey; + MLKEMPublicKeyParameters kyberPub = key.getKyberPublicKey(); + X25519PublicKeyParameters xdhPub = key.getXDHPublicKey(); + byte[] xdhPubBytes = xdhPub.getEncoded(); - MLKEMGenerator kybKem = new MLKEMGenerator(sr); - - SecretWithEncapsulation kybSecWithEnc = kybKem.generateEncapsulated(key.getKyberPublicKey()); - X25519Agreement xdhAgree = new X25519Agreement(); - byte[] kybSecret = kybSecWithEnc.getSecret(); - byte[] k = new byte[kybSecret.length + xdhAgree.getAgreementSize()]; - - System.arraycopy(kybSecret, 0, k, 0, kybSecret.length); - - Arrays.clear(kybSecret); + // 1. Perform ML-KEM encapsulation + MLKEMGenerator mlkemGen = new MLKEMGenerator(random); + SecretWithEncapsulation mlkemSec = mlkemGen.generateEncapsulated(kyberPub); + byte[] ctM = mlkemSec.getEncapsulation(); + // 2. Generate ephemeral X25519 key pair X25519KeyPairGenerator xdhGen = new X25519KeyPairGenerator(); + xdhGen.init(new X25519KeyGenerationParameters(random)); + AsymmetricCipherKeyPair ephXdhKp = xdhGen.generateKeyPair(); + byte[] ctX = ((X25519PublicKeyParameters)ephXdhKp.getPublic()).getEncoded(); - xdhGen.init(new X25519KeyGenerationParameters(sr)); + // 3. Perform X25519 agreement + byte[] ssX = computeSSX(xdhPub, (X25519PrivateKeyParameters)ephXdhKp.getPrivate()); - AsymmetricCipherKeyPair ephXdh = xdhGen.generateKeyPair(); + // 4. Compute shared secret: SHA3-256(ssM || ssX || ctX || pkX || label) + byte[] ss = computeSharedSecret(xdhPubBytes, mlkemSec.getSecret(), ctX, ssX); - xdhAgree.init(ephXdh.getPrivate()); + // 5. Cleanup intermediate values + Arrays.clear(ssX); - xdhAgree.calculateAgreement(key.getXDHPublicKey(), k, kybSecret.length); + // 6. Return shared secret and encapsulation (ctM || ctX) + return new SecretWithEncapsulationImpl(ss, Arrays.concatenate(ctM, ctX)); + } - X25519PublicKeyParameters ephXdhPub = (X25519PublicKeyParameters)ephXdh.getPublic(); + static byte[] computeSSX(X25519PublicKeyParameters xdhPub, X25519PrivateKeyParameters ephXdhPriv) + { + X25519Agreement xdhAgreement = new X25519Agreement(); + xdhAgreement.init(ephXdhPriv); + byte[] ssX = new byte[xdhAgreement.getAgreementSize()]; + xdhAgreement.calculateAgreement(xdhPub, ssX, 0); + return ssX; + } + static byte[] computeSharedSecret(byte[] xdhPubBytes, byte[] ssM, byte[] ctX, byte[] ssX) + { SHA3Digest sha3 = new SHA3Digest(256); - - sha3.update(Strings.toByteArray("\\.//^\\"), 0, 6); - sha3.update(k, 0, k.length); - sha3.update(ephXdhPub.getEncoded(), 0, X25519PublicKeyParameters.KEY_SIZE); - sha3.update(((X25519PublicKeyParameters)key.getXDHPublicKey()).getEncoded(), 0, X25519PublicKeyParameters.KEY_SIZE); - - byte[] kemSecret = new byte[32]; - - sha3.doFinal(kemSecret, 0); - - return new SecretWithEncapsulationImpl(kemSecret, Arrays.concatenate(kybSecWithEnc.getEncapsulation(), ephXdhPub.getEncoded())); + sha3.update(ssM, 0, ssM.length); + sha3.update(ssX, 0, ssX.length); + sha3.update(ctX, 0, ctX.length); + sha3.update(xdhPubBytes, 0, xdhPubBytes.length); + sha3.update(XWING_LABEL, 0, XWING_LABEL.length); + + byte[] ss = new byte[32]; + sha3.doFinal(ss, 0); + return ss; } } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingKeyPairGenerator.java index f7691d0125..694ac2dcfd 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingKeyPairGenerator.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingKeyPairGenerator.java @@ -5,12 +5,28 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; import org.bouncycastle.crypto.KeyGenerationParameters; +import org.bouncycastle.crypto.digests.SHAKEDigest; import org.bouncycastle.crypto.generators.X25519KeyPairGenerator; import org.bouncycastle.crypto.params.X25519KeyGenerationParameters; +import org.bouncycastle.crypto.params.X25519PrivateKeyParameters; +import org.bouncycastle.crypto.params.X25519PublicKeyParameters; +import org.bouncycastle.crypto.prng.FixedSecureRandom; import org.bouncycastle.pqc.crypto.mlkem.MLKEMKeyGenerationParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMKeyPairGenerator; import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters; +import org.bouncycastle.pqc.crypto.mlkem.MLKEMPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mlkem.MLKEMPublicKeyParameters; +import org.bouncycastle.util.Arrays; +/** + * Generates key pairs compatible with the X-Wing hybrid Key Encapsulation Mechanism (KEM). + *

    + * This class produces key pairs that include both X25519 and ML-KEM-768 components, + * suitable for use in the X-Wing KEM as specified in the IETF draft. + *

    + * + * @see X-Wing KEM Draft + */ public class XWingKeyPairGenerator implements AsymmetricCipherKeyPairGenerator { @@ -22,22 +38,39 @@ private void initialize( this.random = param.getRandom(); } - private AsymmetricCipherKeyPair genKeyPair() + static AsymmetricCipherKeyPair genKeyPair(byte[] seed) { - MLKEMKeyPairGenerator kyberKeyGen = new MLKEMKeyPairGenerator(); + // Step 2: Expand seed to 96 bytes using SHAKE256 + SHAKEDigest shake = new SHAKEDigest(256); + shake.update(seed, 0, seed.length); + byte[] expanded = new byte[96]; + shake.doOutput(expanded, 0, expanded.length); - kyberKeyGen.init(new MLKEMKeyGenerationParameters(random, MLKEMParameters.ml_kem_768)); + // Step 3: Split expanded bytes + byte[] mlkemSeed = Arrays.copyOfRange(expanded, 0, 64); + byte[] skX = Arrays.copyOfRange(expanded, 64, 96); - X25519KeyPairGenerator x25519KeyGen = new X25519KeyPairGenerator(); + // Step 4a: Generate ML-KEM key pair deterministically + SecureRandom mlkemRandom = new FixedSecureRandom(mlkemSeed); + MLKEMKeyPairGenerator mlkemKeyGen = new MLKEMKeyPairGenerator(); + mlkemKeyGen.init(new MLKEMKeyGenerationParameters(mlkemRandom, MLKEMParameters.ml_kem_768)); + AsymmetricCipherKeyPair mlkemKp = mlkemKeyGen.generateKeyPair(); + MLKEMPublicKeyParameters mlkemPub = (MLKEMPublicKeyParameters)mlkemKp.getPublic(); + MLKEMPrivateKeyParameters mlkemPriv = (MLKEMPrivateKeyParameters)mlkemKp.getPrivate(); - x25519KeyGen.init(new X25519KeyGenerationParameters(random)); - - AsymmetricCipherKeyPair kybKp = kyberKeyGen.generateKeyPair(); - AsymmetricCipherKeyPair xdhKp = x25519KeyGen.generateKeyPair(); + // Step 4b: Generate X25519 key pair deterministically + SecureRandom xdhRandom = new FixedSecureRandom(skX); + X25519KeyPairGenerator xdhKeyGen = new X25519KeyPairGenerator(); + xdhKeyGen.init(new X25519KeyGenerationParameters(xdhRandom)); + AsymmetricCipherKeyPair xdhKp = xdhKeyGen.generateKeyPair(); + X25519PublicKeyParameters xdhPub = (X25519PublicKeyParameters)xdhKp.getPublic(); + X25519PrivateKeyParameters xdhPriv = (X25519PrivateKeyParameters)xdhKp.getPrivate(); + // Step 5: Create X-Wing keys return new AsymmetricCipherKeyPair( - new XWingPublicKeyParameters(kybKp.getPublic(), xdhKp.getPublic()), - new XWingPrivateKeyParameters(kybKp.getPrivate(), xdhKp.getPrivate())); + new XWingPublicKeyParameters(mlkemPub, xdhPub), + new XWingPrivateKeyParameters(seed, mlkemPriv, xdhPriv, mlkemPub, xdhPub) + ); } public void init(KeyGenerationParameters param) @@ -47,7 +80,9 @@ public void init(KeyGenerationParameters param) public AsymmetricCipherKeyPair generateKeyPair() { - return genKeyPair(); + // Step 1: Generate 32-byte random seed + byte[] seed = new byte[32]; + random.nextBytes(seed); + return genKeyPair(seed); } - } diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingPrivateKeyParameters.java index 5558f76120..a26020e197 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingPrivateKeyParameters.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/xwing/XWingPrivateKeyParameters.java @@ -1,45 +1,72 @@ package org.bouncycastle.pqc.crypto.xwing; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.X25519PrivateKeyParameters; -import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters; +import org.bouncycastle.crypto.params.X25519PublicKeyParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mlkem.MLKEMPublicKeyParameters; import org.bouncycastle.util.Arrays; public class XWingPrivateKeyParameters extends XWingKeyParameters { - private final MLKEMPrivateKeyParameters kybPriv; - private final X25519PrivateKeyParameters xdhPriv; + private final transient byte[] seed; + private final transient MLKEMPrivateKeyParameters kyberPrivateKey; + private final transient X25519PrivateKeyParameters xdhPrivateKey; + private final transient MLKEMPublicKeyParameters kyberPublicKey; + private final transient X25519PublicKeyParameters xdhPublicKey; - XWingPrivateKeyParameters(AsymmetricKeyParameter kybPriv, AsymmetricKeyParameter xdhPriv) + public XWingPrivateKeyParameters(byte[] seed, + MLKEMPrivateKeyParameters kyberPrivateKey, + X25519PrivateKeyParameters xdhPrivateKey, + MLKEMPublicKeyParameters kyberPublicKey, + X25519PublicKeyParameters xdhPublicKey) { super(true); - - this.kybPriv = (MLKEMPrivateKeyParameters)kybPriv; - this.xdhPriv = (X25519PrivateKeyParameters)xdhPriv; + this.seed = Arrays.clone(seed); + this.kyberPrivateKey = kyberPrivateKey; + this.xdhPrivateKey = xdhPrivateKey; + this.kyberPublicKey = kyberPublicKey; + this.xdhPublicKey = xdhPublicKey; } - public XWingPrivateKeyParameters(byte[] encoding) + public XWingPrivateKeyParameters(byte[] seed) { - super(false); + super(true); + XWingPrivateKeyParameters key = (XWingPrivateKeyParameters)XWingKeyPairGenerator.genKeyPair(seed).getPrivate(); + this.seed = key.seed; + this.kyberPrivateKey = key.kyberPrivateKey; + this.xdhPrivateKey = key.xdhPrivateKey; + this.kyberPublicKey = key.kyberPublicKey; + this.xdhPublicKey = key.xdhPublicKey; + } - this.kybPriv = new MLKEMPrivateKeyParameters(MLKEMParameters.ml_kem_768, Arrays.copyOfRange(encoding, 0, encoding.length - X25519PrivateKeyParameters.KEY_SIZE)); - this.xdhPriv = new X25519PrivateKeyParameters(encoding, encoding.length - X25519PrivateKeyParameters.KEY_SIZE); + public byte[] getSeed() + { + return Arrays.clone(seed); } MLKEMPrivateKeyParameters getKyberPrivateKey() { - return kybPriv; + return kyberPrivateKey; + } + + MLKEMPublicKeyParameters getKyberPublicKey() + { + return kyberPublicKey; } X25519PrivateKeyParameters getXDHPrivateKey() { - return xdhPriv; + return xdhPrivateKey; + } + + X25519PublicKeyParameters getXDHPublicKey() + { + return xdhPublicKey; } public byte[] getEncoded() { - return Arrays.concatenate(kybPriv.getEncoded(), xdhPriv.getEncoded()); + return Arrays.clone(seed); } } diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSDigestProvider.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSDigestProvider.java deleted file mode 100644 index 569f4ee73c..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSDigestProvider.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss; - -import org.bouncycastle.crypto.Digest; - -public interface GMSSDigestProvider -{ - Digest get(); -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSKeyGenerationParameters.java deleted file mode 100644 index 3180867c91..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSKeyGenerationParameters.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.KeyGenerationParameters; - -public class GMSSKeyGenerationParameters - extends KeyGenerationParameters -{ - - private GMSSParameters params; - - public GMSSKeyGenerationParameters( - SecureRandom random, - GMSSParameters params) - { - // XXX key size? - super(random, 1); - this.params = params; - } - - public GMSSParameters getParameters() - { - return params; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSKeyPairGenerator.java deleted file mode 100644 index 24ffa4765e..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSKeyPairGenerator.java +++ /dev/null @@ -1,471 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss; - -import java.security.SecureRandom; -import java.util.Vector; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.pqc.legacy.crypto.gmss.util.GMSSRandom; -import org.bouncycastle.pqc.legacy.crypto.gmss.util.WinternitzOTSVerify; -import org.bouncycastle.pqc.legacy.crypto.gmss.util.WinternitzOTSignature; - - -/** - * This class implements key pair generation of the generalized Merkle signature - * scheme (GMSS). - * - * @see GMSSSigner - */ -public class GMSSKeyPairGenerator - implements AsymmetricCipherKeyPairGenerator -{ - /** - * The source of randomness for OTS private key generation - */ - private GMSSRandom gmssRandom; - - /** - * The hash function used for the construction of the authentication trees - */ - private Digest messDigestTree; - - /** - * An array of the seeds for the PRGN (for main tree, and all current - * subtrees) - */ - private byte[][] currentSeeds; - - /** - * An array of seeds for the PRGN (for all subtrees after next) - */ - private byte[][] nextNextSeeds; - - /** - * An array of the RootSignatures - */ - private byte[][] currentRootSigs; - - /** - * Class of hash function to use - */ - private GMSSDigestProvider digestProvider; - - /** - * The length of the seed for the PRNG - */ - private int mdLength; - - /** - * the number of Layers - */ - private int numLayer; - - - /** - * Flag indicating if the class already has been initialized - */ - private boolean initialized = false; - - /** - * Instance of GMSSParameterset - */ - private GMSSParameters gmssPS; - - /** - * An array of the heights of the authentication trees of each layer - */ - private int[] heightOfTrees; - - /** - * An array of the Winternitz parameter 'w' of each layer - */ - private int[] otsIndex; - - /** - * The parameter K needed for the authentication path computation - */ - private int[] K; - - private GMSSKeyGenerationParameters gmssParams; - - /** - * The GMSS OID. - */ - public static final String OID = "1.3.6.1.4.1.8301.3.1.3.3"; - - /** - * The standard constructor tries to generate the GMSS algorithm identifier - * with the corresponding OID. - * - * @param digestProvider provider for digest implementations. - */ - public GMSSKeyPairGenerator(GMSSDigestProvider digestProvider) - { - this.digestProvider = digestProvider; - messDigestTree = digestProvider.get(); - - // set mdLength - this.mdLength = messDigestTree.getDigestSize(); - // construct randomizer - this.gmssRandom = new GMSSRandom(messDigestTree); - - } - - /** - * Generates the GMSS key pair. The public key is an instance of - * JDKGMSSPublicKey, the private key is an instance of JDKGMSSPrivateKey. - * - * @return Key pair containing a JDKGMSSPublicKey and a JDKGMSSPrivateKey - */ - private AsymmetricCipherKeyPair genKeyPair() - { - if (!initialized) - { - initializeDefault(); - } - - // initialize authenticationPaths and treehash instances - byte[][][] currentAuthPaths = new byte[numLayer][][]; - byte[][][] nextAuthPaths = new byte[numLayer - 1][][]; - Treehash[][] currentTreehash = new Treehash[numLayer][]; - Treehash[][] nextTreehash = new Treehash[numLayer - 1][]; - - Vector[] currentStack = new Vector[numLayer]; - Vector[] nextStack = new Vector[numLayer - 1]; - - Vector[][] currentRetain = new Vector[numLayer][]; - Vector[][] nextRetain = new Vector[numLayer - 1][]; - - for (int i = 0; i < numLayer; i++) - { - currentAuthPaths[i] = new byte[heightOfTrees[i]][mdLength]; - currentTreehash[i] = new Treehash[heightOfTrees[i] - K[i]]; - - if (i > 0) - { - nextAuthPaths[i - 1] = new byte[heightOfTrees[i]][mdLength]; - nextTreehash[i - 1] = new Treehash[heightOfTrees[i] - K[i]]; - } - - currentStack[i] = new Vector(); - if (i > 0) - { - nextStack[i - 1] = new Vector(); - } - } - - // initialize roots - byte[][] currentRoots = new byte[numLayer][mdLength]; - byte[][] nextRoots = new byte[numLayer - 1][mdLength]; - // initialize seeds - byte[][] seeds = new byte[numLayer][mdLength]; - // initialize seeds[] by copying starting-seeds of first trees of each - // layer - for (int i = 0; i < numLayer; i++) - { - System.arraycopy(currentSeeds[i], 0, seeds[i], 0, mdLength); - } - - // initialize rootSigs - currentRootSigs = new byte[numLayer - 1][mdLength]; - - // ------------------------- - // ------------------------- - // --- calculation of current authpaths and current rootsigs (AUTHPATHS, - // SIG)------ - // from bottom up to the root - for (int h = numLayer - 1; h >= 0; h--) - { - GMSSRootCalc tree; - - // on lowest layer no lower root is available, so just call - // the method with null as first parameter - if (h == numLayer - 1) - { - tree = this.generateCurrentAuthpathAndRoot(null, currentStack[h], seeds[h], h); - } - else - // otherwise call the method with the former computed root - // value - { - tree = this.generateCurrentAuthpathAndRoot(currentRoots[h + 1], currentStack[h], seeds[h], h); - } - - // set initial values needed for the private key construction - for (int i = 0; i < heightOfTrees[h]; i++) - { - System.arraycopy(tree.getAuthPath()[i], 0, currentAuthPaths[h][i], 0, mdLength); - } - currentRetain[h] = tree.getRetain(); - currentTreehash[h] = tree.getTreehash(); - System.arraycopy(tree.getRoot(), 0, currentRoots[h], 0, mdLength); - } - - // --- calculation of next authpaths and next roots (AUTHPATHS+, ROOTS+) - // ------ - for (int h = numLayer - 2; h >= 0; h--) - { - GMSSRootCalc tree = this.generateNextAuthpathAndRoot(nextStack[h], seeds[h + 1], h + 1); - - // set initial values needed for the private key construction - for (int i = 0; i < heightOfTrees[h + 1]; i++) - { - System.arraycopy(tree.getAuthPath()[i], 0, nextAuthPaths[h][i], 0, mdLength); - } - nextRetain[h] = tree.getRetain(); - nextTreehash[h] = tree.getTreehash(); - System.arraycopy(tree.getRoot(), 0, nextRoots[h], 0, mdLength); - - // create seed for the Merkle tree after next (nextNextSeeds) - // SEEDs++ - System.arraycopy(seeds[h + 1], 0, this.nextNextSeeds[h], 0, mdLength); - } - // ------------ - - // generate JDKGMSSPublicKey - GMSSPublicKeyParameters publicKey = new GMSSPublicKeyParameters(currentRoots[0], gmssPS); - - // generate the JDKGMSSPrivateKey - GMSSPrivateKeyParameters privateKey = new GMSSPrivateKeyParameters(currentSeeds, nextNextSeeds, currentAuthPaths, - nextAuthPaths, currentTreehash, nextTreehash, currentStack, nextStack, currentRetain, nextRetain, nextRoots, currentRootSigs, gmssPS, digestProvider); - - // return the KeyPair - return (new AsymmetricCipherKeyPair(publicKey, privateKey)); - } - - /** - * calculates the authpath for tree in layer h which starts with seed[h] - * additionally computes the rootSignature of underlaying root - * - * @param currentStack stack used for the treehash instance created by this method - * @param lowerRoot stores the root of the lower tree - * @param seed starting seeds - * @param h actual layer - */ - private GMSSRootCalc generateCurrentAuthpathAndRoot(byte[] lowerRoot, Vector currentStack, byte[] seed, int h) - { - byte[] help = new byte[mdLength]; - - byte[] OTSseed = new byte[mdLength]; - OTSseed = gmssRandom.nextSeed(seed); - - WinternitzOTSignature ots; - - // data structure that constructs the whole tree and stores - // the initial values for treehash, Auth and retain - GMSSRootCalc treeToConstruct = new GMSSRootCalc(this.heightOfTrees[h], this.K[h], digestProvider); - - treeToConstruct.initialize(currentStack); - - // generate the first leaf - if (h == numLayer - 1) - { - ots = new WinternitzOTSignature(OTSseed, digestProvider.get(), otsIndex[h]); - help = ots.getPublicKey(); - } - else - { - // for all layers except the lowest, generate the signature of the - // underlying root - // and reuse this signature to compute the first leaf of acual layer - // more efficiently (by verifiing the signature) - ots = new WinternitzOTSignature(OTSseed, digestProvider.get(), otsIndex[h]); - currentRootSigs[h] = ots.getSignature(lowerRoot); - WinternitzOTSVerify otsver = new WinternitzOTSVerify(digestProvider.get(), otsIndex[h]); - help = otsver.Verify(lowerRoot, currentRootSigs[h]); - } - // update the tree with the first leaf - treeToConstruct.update(help); - - int seedForTreehashIndex = 3; - int count = 0; - - // update the tree 2^(H) - 1 times, from the second to the last leaf - for (int i = 1; i < (1 << this.heightOfTrees[h]); i++) - { - // initialize the seeds for the leaf generation with index 3 * 2^h - if (i == seedForTreehashIndex && count < this.heightOfTrees[h] - this.K[h]) - { - treeToConstruct.initializeTreehashSeed(seed, count); - seedForTreehashIndex *= 2; - count++; - } - - OTSseed = gmssRandom.nextSeed(seed); - ots = new WinternitzOTSignature(OTSseed, digestProvider.get(), otsIndex[h]); - treeToConstruct.update(ots.getPublicKey()); - } - - if (treeToConstruct.wasFinished()) - { - return treeToConstruct; - } - // -DM System.err.println - System.err.println("Baum noch nicht fertig konstruiert!!!"); - return null; - } - - /** - * calculates the authpath and root for tree in layer h which starts with - * seed[h] - * - * @param nextStack stack used for the treehash instance created by this method - * @param seed starting seeds - * @param h actual layer - */ - private GMSSRootCalc generateNextAuthpathAndRoot(Vector nextStack, byte[] seed, int h) - { - byte[] OTSseed = new byte[numLayer]; - WinternitzOTSignature ots; - - // data structure that constructs the whole tree and stores - // the initial values for treehash, Auth and retain - GMSSRootCalc treeToConstruct = new GMSSRootCalc(this.heightOfTrees[h], this.K[h], this.digestProvider); - treeToConstruct.initialize(nextStack); - - int seedForTreehashIndex = 3; - int count = 0; - - // update the tree 2^(H) times, from the first to the last leaf - for (int i = 0; i < (1 << this.heightOfTrees[h]); i++) - { - // initialize the seeds for the leaf generation with index 3 * 2^h - if (i == seedForTreehashIndex && count < this.heightOfTrees[h] - this.K[h]) - { - treeToConstruct.initializeTreehashSeed(seed, count); - seedForTreehashIndex *= 2; - count++; - } - - OTSseed = gmssRandom.nextSeed(seed); - ots = new WinternitzOTSignature(OTSseed, digestProvider.get(), otsIndex[h]); - treeToConstruct.update(ots.getPublicKey()); - } - - if (treeToConstruct.wasFinished()) - { - return treeToConstruct; - } - // -DM System.err.println - System.err.println("N�chster Baum noch nicht fertig konstruiert!!!"); - return null; - } - - /** - * This method initializes the GMSS KeyPairGenerator using an integer value - * keySize as input. It provides a simple use of the GMSS for - * testing demands. - *

    - * A given keysize of less than 10 creates an amount 2^10 - * signatures. A keySize between 10 and 20 creates 2^20 signatures. Given an - * integer greater than 20 the key pair generator creates 2^40 signatures. - * - * @param keySize Assigns the parameters used for the GMSS signatures. There are - * 3 choices:
    - * 1. keysize <= 10: creates 2^10 signatures using the - * parameterset
    - * P = (2, (5, 5), (3, 3), (3, 3))
    - * 2. keysize > 10 and <= 20: creates 2^20 signatures using the - * parameterset
    - * P = (2, (10, 10), (5, 4), (2, 2))
    - * 3. keysize > 20: creates 2^40 signatures using the - * parameterset
    - * P = (2, (10, 10, 10, 10), (9, 9, 9, 3), (2, 2, 2, 2)) - * @param secureRandom not used by GMSS, the SHA1PRNG of the SUN Provider is always - * used - */ - public void initialize(int keySize, SecureRandom secureRandom) - { - - KeyGenerationParameters kgp; - if (keySize <= 10) - { // create 2^10 keys - int[] defh = {10}; - int[] defw = {3}; - int[] defk = {2}; - // XXX sec random neede? - kgp = new GMSSKeyGenerationParameters(secureRandom, new GMSSParameters(defh.length, defh, defw, defk)); - } - else if (keySize <= 20) - { // create 2^20 keys - int[] defh = {10, 10}; - int[] defw = {5, 4}; - int[] defk = {2, 2}; - kgp = new GMSSKeyGenerationParameters(secureRandom, new GMSSParameters(defh.length, defh, defw, defk)); - } - else - { // create 2^40 keys, keygen lasts around 80 seconds - int[] defh = {10, 10, 10, 10}; - int[] defw = {9, 9, 9, 3}; - int[] defk = {2, 2, 2, 2}; - kgp = new GMSSKeyGenerationParameters(secureRandom, new GMSSParameters(defh.length, defh, defw, defk)); - } - - // call the initializer with the chosen parameters - this.initialize(kgp); - - } - - - /** - * Initalizes the key pair generator using a parameter set as input - */ - public void initialize(KeyGenerationParameters param) - { - - this.gmssParams = (GMSSKeyGenerationParameters)param; - - // generate GMSSParameterset - this.gmssPS = new GMSSParameters(gmssParams.getParameters().getNumOfLayers(), gmssParams.getParameters().getHeightOfTrees(), - gmssParams.getParameters().getWinternitzParameter(), gmssParams.getParameters().getK()); - - this.numLayer = gmssPS.getNumOfLayers(); - this.heightOfTrees = gmssPS.getHeightOfTrees(); - this.otsIndex = gmssPS.getWinternitzParameter(); - this.K = gmssPS.getK(); - - // seeds - this.currentSeeds = new byte[numLayer][mdLength]; - this.nextNextSeeds = new byte[numLayer - 1][mdLength]; - - // SecureRandom for initial seed generation - SecureRandom secRan = param.getRandom(); - - // generation of initial seeds - for (int i = 0; i < numLayer; i++) - { - secRan.nextBytes(currentSeeds[i]); - gmssRandom.nextSeed(currentSeeds[i]); - } - - this.initialized = true; - } - - /** - * This method is called by generateKeyPair() in case that no other - * initialization method has been called by the user - */ - private void initializeDefault() - { - int[] defh = {10, 10, 10, 10}; - int[] defw = {3, 3, 3, 3}; - int[] defk = {2, 2, 2, 2}; - - KeyGenerationParameters kgp = new GMSSKeyGenerationParameters(null, new GMSSParameters(defh.length, defh, defw, defk)); - this.initialize(kgp); - - } - - public void init(KeyGenerationParameters param) - { - this.initialize(param); - - } - - public AsymmetricCipherKeyPair generateKeyPair() - { - return genKeyPair(); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSKeyParameters.java deleted file mode 100644 index 44898997d9..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSKeyParameters.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; - -public class GMSSKeyParameters - extends AsymmetricKeyParameter -{ - private GMSSParameters params; - - public GMSSKeyParameters( - boolean isPrivate, - GMSSParameters params) - { - super(isPrivate); - this.params = params; - } - - public GMSSParameters getParameters() - { - return params; - } -} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSLeaf.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSLeaf.java deleted file mode 100644 index d988f6c32b..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSLeaf.java +++ /dev/null @@ -1,372 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.pqc.legacy.crypto.gmss.util.GMSSRandom; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.encoders.Hex; - - -/** - * This class implements the distributed computation of the public key of the - * Winternitz one-time signature scheme (OTSS). The class is used by the GMSS - * classes for calculation of upcoming leafs. - */ -public class GMSSLeaf -{ - - /** - * The hash function used by the OTS and the PRNG - */ - private Digest messDigestOTS; - - /** - * The length of the message digest and private key - */ - private int mdsize, keysize; - - /** - * The source of randomness for OTS private key generation - */ - private GMSSRandom gmssRandom; - - /** - * Byte array for distributed computation of the upcoming leaf - */ - private byte[] leaf; - - /** - * Byte array for storing the concatenated hashes of private key parts - */ - private byte[] concHashs; - - /** - * indices for distributed computation - */ - private int i, j; - - /** - * storing 2^w - */ - private int two_power_w; - - /** - * Winternitz parameter w - */ - private int w; - - /** - * the amount of distributed computation steps when updateLeaf is called - */ - private int steps; - - /** - * the internal seed - */ - private byte[] seed; - - /** - * the OTS privateKey parts - */ - byte[] privateKeyOTS; - - /** - * This constructor regenerates a prior GMSSLeaf object - * - * @param digest an array of strings, containing the name of the used hash - * function and PRNG and the name of the corresponding - * provider - * @param otsIndex status bytes - * @param numLeafs status ints - */ - public GMSSLeaf(Digest digest, byte[][] otsIndex, int[] numLeafs) - { - this.i = numLeafs[0]; - this.j = numLeafs[1]; - this.steps = numLeafs[2]; - this.w = numLeafs[3]; - - messDigestOTS = digest; - - gmssRandom = new GMSSRandom(messDigestOTS); - - // calulate keysize for private key and the help array - mdsize = messDigestOTS.getDigestSize(); - int mdsizeBit = mdsize << 3; - int messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w); - int checksumsize = getLog((messagesize << w) + 1); - this.keysize = messagesize - + (int)Math.ceil((double)checksumsize / (double)w); - this.two_power_w = 1 << w; - - // calculate steps - // ((2^w)-1)*keysize + keysize + 1 / (2^h -1) - - // initialize arrays - this.privateKeyOTS = otsIndex[0]; - this.seed = otsIndex[1]; - this.concHashs = otsIndex[2]; - this.leaf = otsIndex[3]; - } - - /** - * The constructor precomputes some needed variables for distributed leaf - * calculation - * - * @param digest an array of strings, containing the digest of the used hash - * function and PRNG and the digest of the corresponding - * provider - * @param w the winterniz parameter of that tree the leaf is computed - * for - * @param numLeafs the number of leafs of the tree from where the distributed - * computation is called - */ - GMSSLeaf(Digest digest, int w, int numLeafs) - { - this.w = w; - - messDigestOTS = digest; - - gmssRandom = new GMSSRandom(messDigestOTS); - - // calulate keysize for private key and the help array - mdsize = messDigestOTS.getDigestSize(); - int mdsizeBit = mdsize << 3; - int messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w); - int checksumsize = getLog((messagesize << w) + 1); - this.keysize = messagesize - + (int)Math.ceil((double)checksumsize / (double)w); - this.two_power_w = 1 << w; - - // calculate steps - // ((2^w)-1)*keysize + keysize + 1 / (2^h -1) - this.steps = (int)Math - .ceil((double)(((1 << w) - 1) * keysize + 1 + keysize) - / (double)(numLeafs)); - - // initialize arrays - this.seed = new byte[mdsize]; - this.leaf = new byte[mdsize]; - this.privateKeyOTS = new byte[mdsize]; - this.concHashs = new byte[mdsize * keysize]; - } - - public GMSSLeaf(Digest digest, int w, int numLeafs, byte[] seed0) - { - this.w = w; - - messDigestOTS = digest; - - gmssRandom = new GMSSRandom(messDigestOTS); - - // calulate keysize for private key and the help array - mdsize = messDigestOTS.getDigestSize(); - int mdsizeBit = mdsize << 3; - int messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w); - int checksumsize = getLog((messagesize << w) + 1); - this.keysize = messagesize - + (int)Math.ceil((double)checksumsize / (double)w); - this.two_power_w = 1 << w; - - // calculate steps - // ((2^w)-1)*keysize + keysize + 1 / (2^h -1) - this.steps = (int)Math - .ceil((double)(((1 << w) - 1) * keysize + 1 + keysize) - / (double)(numLeafs)); - - // initialize arrays - this.seed = new byte[mdsize]; - this.leaf = new byte[mdsize]; - this.privateKeyOTS = new byte[mdsize]; - this.concHashs = new byte[mdsize * keysize]; - - initLeafCalc(seed0); - } - - private GMSSLeaf(GMSSLeaf original) - { - this.messDigestOTS = original.messDigestOTS; - this.mdsize = original.mdsize; - this.keysize = original.keysize; - this.gmssRandom = original.gmssRandom; - this.leaf = Arrays.clone(original.leaf); - this.concHashs = Arrays.clone(original.concHashs); - this.i = original.i; - this.j = original.j; - this.two_power_w = original.two_power_w; - this.w = original.w; - this.steps = original.steps; - this.seed = Arrays.clone(original.seed); - this.privateKeyOTS = Arrays.clone(original.privateKeyOTS); - } - - /** - * initialize the distributed leaf calculation reset i,j and compute OTSseed - * with seed0 - * - * @param seed0 the starting seed - */ - // TODO: this really looks like it should be either always called from a constructor or nextLeaf. - void initLeafCalc(byte[] seed0) - { - this.i = 0; - this.j = 0; - byte[] dummy = new byte[mdsize]; - System.arraycopy(seed0, 0, dummy, 0, seed.length); - this.seed = gmssRandom.nextSeed(dummy); - } - - GMSSLeaf nextLeaf() - { - GMSSLeaf nextLeaf = new GMSSLeaf(this); - - nextLeaf.updateLeafCalc(); - - return nextLeaf; - } - - /** - * Processes steps steps of distributed leaf calculation - * - * @return true if leaf is completed, else false - */ - private void updateLeafCalc() - { - byte[] buf = new byte[messDigestOTS.getDigestSize()]; - - // steps times do - // TODO: this really needs to be looked at, the 10000 has been added as - // prior to this the leaf value always ended up as zeros. - for (int s = 0; s < steps + 10000; s++) - { - if (i == keysize && j == two_power_w - 1) - { // [3] at last hash the - // concatenation - messDigestOTS.update(concHashs, 0, concHashs.length); - leaf = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(leaf, 0); - return; - } - else if (i == 0 || j == two_power_w - 1) - { // [1] at the - // beginning and - // when [2] is - // finished: get the - // next private key - // part - i++; - j = 0; - // get next privKey part - this.privateKeyOTS = gmssRandom.nextSeed(seed); - } - else - { // [2] hash the privKey part - messDigestOTS.update(privateKeyOTS, 0, privateKeyOTS.length); - privateKeyOTS = buf; - messDigestOTS.doFinal(privateKeyOTS, 0); - j++; - if (j == two_power_w - 1) - { // after w hashes add to the - // concatenated array - System.arraycopy(privateKeyOTS, 0, concHashs, mdsize - * (i - 1), mdsize); - } - } - } - - throw new IllegalStateException("unable to updateLeaf in steps: " + steps + " " + i + " " + j); - } - - /** - * Returns the leaf value. - * - * @return the leaf value - */ - public byte[] getLeaf() - { - return Arrays.clone(leaf); - } - - /** - * This method returns the least integer that is greater or equal to the - * logarithm to the base 2 of an integer intValue. - * - * @param intValue an integer - * @return The least integer greater or equal to the logarithm to the base 2 - * of intValue - */ - private int getLog(int intValue) - { - int log = 1; - int i = 2; - while (i < intValue) - { - i <<= 1; - log++; - } - return log; - } - - /** - * Returns the status byte array used by the GMSSPrivateKeyASN.1 class - * - * @return The status bytes - */ - public byte[][] getStatByte() - { - - byte[][] statByte = new byte[4][]; - statByte[0] = privateKeyOTS; - statByte[1] = seed; - statByte[2] = concHashs; - statByte[3] = leaf; - - return statByte; - } - - /** - * Returns the status int array used by the GMSSPrivateKeyASN.1 class - * - * @return The status ints - */ - public int[] getStatInt() - { - - int[] statInt = new int[4]; - statInt[0] = i; - statInt[1] = j; - statInt[2] = steps; - statInt[3] = w; - return statInt; - } - - /** - * Returns a String representation of the main part of this element - * - * @return a String representation of the main part of this element - */ - public String toString() - { - String out = ""; - - for (int i = 0; i < 4; i++) - { - out = out + this.getStatInt()[i] + " "; - } - out = out + " " + this.mdsize + " " + this.keysize + " " - + this.two_power_w + " "; - - byte[][] temp = this.getStatByte(); - for (int i = 0; i < 4; i++) - { - if (temp[i] != null) - { - out = out + new String(Hex.encode(temp[i])) + " "; - } - else - { - out = out + "null "; - } - } - return out; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSParameters.java deleted file mode 100644 index e094017c03..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSParameters.java +++ /dev/null @@ -1,155 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss; - -import org.bouncycastle.util.Arrays; - -/** - * This class provides a specification for the GMSS parameters that are used by - * the GMSSKeyPairGenerator and GMSSSignature classes. - * - * @see org.bouncycastle.pqc.legacy.crypto.gmss.GMSSKeyPairGenerator - */ -public class GMSSParameters -{ - /** - * The number of authentication tree layers. - */ - private int numOfLayers; - - /** - * The height of the authentication trees of each layer. - */ - private int[] heightOfTrees; - - /** - * The Winternitz Parameter 'w' of each layer. - */ - private int[] winternitzParameter; - - /** - * The parameter K needed for the authentication path computation - */ - private int[] K; - - /** - * The constructor for the parameters of the GMSSKeyPairGenerator. - * - * @param layers the number of authentication tree layers - * @param heightOfTrees the height of the authentication trees - * @param winternitzParameter the Winternitz Parameter 'w' of each layer - * @param K parameter for authpath computation - */ - public GMSSParameters(int layers, int[] heightOfTrees, int[] winternitzParameter, int[] K) - throws IllegalArgumentException - { - init(layers, heightOfTrees, winternitzParameter, K); - } - - private void init(int layers, int[] heightOfTrees, - int[] winternitzParameter, int[] K) - throws IllegalArgumentException - { - boolean valid = true; - String errMsg = ""; - this.numOfLayers = layers; - if ((numOfLayers != winternitzParameter.length) - || (numOfLayers != heightOfTrees.length) - || (numOfLayers != K.length)) - { - valid = false; - errMsg = "Unexpected parameterset format"; - } - for (int i = 0; i < numOfLayers; i++) - { - if ((K[i] < 2) || ((heightOfTrees[i] - K[i]) % 2 != 0)) - { - valid = false; - errMsg = "Wrong parameter K (K >= 2 and H-K even required)!"; - } - - if ((heightOfTrees[i] < 4) || (winternitzParameter[i] < 2)) - { - valid = false; - errMsg = "Wrong parameter H or w (H > 3 and w > 1 required)!"; - } - } - - if (valid) - { - this.heightOfTrees = Arrays.clone(heightOfTrees); - this.winternitzParameter = Arrays.clone(winternitzParameter); - this.K = Arrays.clone(K); - } - else - { - throw new IllegalArgumentException(errMsg); - } - } - - public GMSSParameters(int keySize) - throws IllegalArgumentException - { - if (keySize <= 10) - { // create 2^10 keys - int[] defh = {10}; - int[] defw = {3}; - int[] defk = {2}; - this.init(defh.length, defh, defw, defk); - } - else if (keySize <= 20) - { // create 2^20 keys - int[] defh = {10, 10}; - int[] defw = {5, 4}; - int[] defk = {2, 2}; - this.init(defh.length, defh, defw, defk); - } - else - { // create 2^40 keys, keygen lasts around 80 seconds - int[] defh = {10, 10, 10, 10}; - int[] defw = {9, 9, 9, 3}; - int[] defk = {2, 2, 2, 2}; - this.init(defh.length, defh, defw, defk); - } - } - - /** - * Returns the number of levels of the authentication trees. - * - * @return The number of levels of the authentication trees. - */ - public int getNumOfLayers() - { - return numOfLayers; - } - - /** - * Returns the array of height (for each layer) of the authentication trees - * - * @return The array of height (for each layer) of the authentication trees - */ - public int[] getHeightOfTrees() - { - return Arrays.clone(heightOfTrees); - } - - /** - * Returns the array of WinternitzParameter (for each layer) of the - * authentication trees - * - * @return The array of WinternitzParameter (for each layer) of the - * authentication trees - */ - public int[] getWinternitzParameter() - { - return Arrays.clone(winternitzParameter); - } - - /** - * Returns the parameter K needed for authentication path computation - * - * @return The parameter K needed for authentication path computation - */ - public int[] getK() - { - return Arrays.clone(K); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSPrivateKeyParameters.java deleted file mode 100644 index 085f6f0980..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSPrivateKeyParameters.java +++ /dev/null @@ -1,1045 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss; - -import java.util.Vector; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.pqc.legacy.crypto.gmss.util.GMSSRandom; -import org.bouncycastle.pqc.legacy.crypto.gmss.util.WinternitzOTSignature; -import org.bouncycastle.util.Arrays; - - -/** - * This class provides a specification for a GMSS private key. - */ -public class GMSSPrivateKeyParameters - extends GMSSKeyParameters -{ - private int[] index; - - private byte[][] currentSeeds; - private byte[][] nextNextSeeds; - - private byte[][][] currentAuthPaths; - private byte[][][] nextAuthPaths; - - 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; - - private GMSSDigestProvider digestProvider; - - private boolean used = false; - - /** - * An array of the heights of the authentication trees of each layer - */ - private int[] heightOfTrees; - - /** - * An array of the Winternitz parameter 'w' of each layer - */ - private int[] otsIndex; - - /** - * The parameter K needed for the authentication path computation - */ - private int[] K; - - /** - * the number of Layers - */ - private int numLayer; - - /** - * The hash function used to construct the authentication trees - */ - private Digest messDigestTrees; - - /** - * The message digest length - */ - private int mdLength; - - /** - * The PRNG used for private key generation - */ - private GMSSRandom gmssRandom; - - - /** - * The number of leafs of one tree of each layer - */ - private int[] numLeafs; - - - /** - * Generates a new GMSS private key - * - * @param currentSeed seed for the generation of private OTS keys for the - * current subtrees - * @param nextNextSeed seed for the generation of private OTS keys for the next - * subtrees - * @param currentAuthPath array of current authentication paths - * @param nextAuthPath array of next authentication paths - * @param currentTreehash array of current treehash instances - * @param nextTreehash array of next treehash instances - * @param currentStack array of current shared stacks - * @param nextStack array of next shared stacks - * @param currentRetain array of current retain stacks - * @param nextRetain array of next retain stacks - * @param nextRoot the roots of the next subtree - * @param currentRootSig array of signatures of the roots of the current subtrees - * @param gmssParameterset the GMSS Parameterset - * @see org.bouncycastle.pqc.legacy.crypto.gmss.GMSSKeyPairGenerator - */ - - public GMSSPrivateKeyParameters(byte[][] currentSeed, byte[][] nextNextSeed, - byte[][][] currentAuthPath, byte[][][] nextAuthPath, - Treehash[][] currentTreehash, Treehash[][] nextTreehash, - Vector[] currentStack, Vector[] nextStack, - Vector[][] currentRetain, Vector[][] nextRetain, byte[][] nextRoot, - byte[][] currentRootSig, GMSSParameters gmssParameterset, - GMSSDigestProvider digestProvider) - { - this(null, currentSeed, nextNextSeed, currentAuthPath, nextAuthPath, - null, currentTreehash, nextTreehash, currentStack, nextStack, - currentRetain, nextRetain, null, null, null, null, nextRoot, - null, currentRootSig, null, gmssParameterset, digestProvider); - } - - /** - * /** - * - * @param index tree indices - * @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 GMSSPrivateKeyParameters(int[] index, byte[][] currentSeeds, - byte[][] nextNextSeeds, byte[][][] currentAuthPaths, - byte[][][] nextAuthPaths, byte[][][] keep, - Treehash[][] currentTreehash, Treehash[][] nextTreehash, - Vector[] currentStack, Vector[] nextStack, - Vector[][] currentRetain, Vector[][] nextRetain, - GMSSLeaf[] nextNextLeaf, GMSSLeaf[] upperLeaf, - GMSSLeaf[] upperTreehashLeaf, int[] minTreehash, byte[][] nextRoot, - GMSSRootCalc[] nextNextRoot, byte[][] currentRootSig, - GMSSRootSig[] nextRootSig, GMSSParameters gmssParameterset, - GMSSDigestProvider digestProvider) - { - - super(true, gmssParameterset); - - // construct message digest - - this.messDigestTrees = digestProvider.get(); - this.mdLength = messDigestTrees.getDigestSize(); - - - // Parameter - this.gmssPS = gmssParameterset; - this.otsIndex = gmssParameterset.getWinternitzParameter(); - this.K = gmssParameterset.getK(); - this.heightOfTrees = gmssParameterset.getHeightOfTrees(); - // initialize numLayer - this.numLayer = gmssPS.getNumOfLayers(); - - // initialize index if null - if (index == null) - { - this.index = new int[numLayer]; - for (int i = 0; i < numLayer; i++) - { - this.index[i] = 0; - } - } - else - { - this.index = index; - } - - this.currentSeeds = currentSeeds; - this.nextNextSeeds = nextNextSeeds; - - this.currentAuthPaths = Arrays.clone(currentAuthPaths); - this.nextAuthPaths = nextAuthPaths; - - // initialize keep if null - if (keep == null) - { - this.keep = new byte[numLayer][][]; - for (int i = 0; i < numLayer; i++) - { - this.keep[i] = new byte[(int)Math.floor(heightOfTrees[i] / 2)][mdLength]; - } - } - else - { - this.keep = keep; - } - - // initialize stack if null - if (currentStack == null) - { - this.currentStack = new Vector[numLayer]; - for (int i = 0; i < numLayer; i++) - { - this.currentStack[i] = new Vector(); - } - } - else - { - this.currentStack = currentStack; - } - - // initialize nextStack if null - if (nextStack == null) - { - this.nextStack = new Vector[numLayer - 1]; - for (int i = 0; i < numLayer - 1; i++) - { - this.nextStack[i] = new Vector(); - } - } - else - { - this.nextStack = nextStack; - } - - this.currentTreehash = currentTreehash; - this.nextTreehash = nextTreehash; - - this.currentRetain = currentRetain; - this.nextRetain = nextRetain; - - this.nextRoot = nextRoot; - - this.digestProvider = digestProvider; - - if (nextNextRoot == null) - { - this.nextNextRoot = new GMSSRootCalc[numLayer - 1]; - for (int i = 0; i < numLayer - 1; i++) - { - this.nextNextRoot[i] = new GMSSRootCalc( - this.heightOfTrees[i + 1], this.K[i + 1], this.digestProvider); - } - } - else - { - this.nextNextRoot = nextNextRoot; - } - this.currentRootSig = currentRootSig; - - // calculate numLeafs - numLeafs = new int[numLayer]; - for (int i = 0; i < numLayer; i++) - { - numLeafs[i] = 1 << heightOfTrees[i]; - } - // construct PRNG - this.gmssRandom = new GMSSRandom(messDigestTrees); - - if (numLayer > 1) - { - // construct the nextNextLeaf (LEAFs++) array for upcoming leafs in - // tree after next (TREE++) - if (nextNextLeaf == null) - { - this.nextNextLeaf = new GMSSLeaf[numLayer - 2]; - for (int i = 0; i < numLayer - 2; i++) - { - this.nextNextLeaf[i] = new GMSSLeaf(digestProvider.get(), otsIndex[i + 1], numLeafs[i + 2], this.nextNextSeeds[i]); - } - } - else - { - this.nextNextLeaf = nextNextLeaf; - } - } - else - { - this.nextNextLeaf = new GMSSLeaf[0]; - } - - // construct the upperLeaf array for upcoming leafs in tree over the - // actual - if (upperLeaf == null) - { - this.upperLeaf = new GMSSLeaf[numLayer - 1]; - for (int i = 0; i < numLayer - 1; i++) - { - this.upperLeaf[i] = new GMSSLeaf(digestProvider.get(), otsIndex[i], - numLeafs[i + 1], this.currentSeeds[i]); - } - } - else - { - this.upperLeaf = upperLeaf; - } - - // construct the leafs for upcoming leafs in treehashs in tree over the - // actual - if (upperTreehashLeaf == null) - { - this.upperTreehashLeaf = new GMSSLeaf[numLayer - 1]; - for (int i = 0; i < numLayer - 1; i++) - { - this.upperTreehashLeaf[i] = new GMSSLeaf(digestProvider.get(), otsIndex[i], numLeafs[i + 1]); - } - } - else - { - this.upperTreehashLeaf = upperTreehashLeaf; - } - - if (minTreehash == null) - { - this.minTreehash = new int[numLayer - 1]; - for (int i = 0; i < numLayer - 1; i++) - { - this.minTreehash[i] = -1; - } - } - else - { - this.minTreehash = minTreehash; - } - - // construct the nextRootSig (RootSig++) - byte[] dummy = new byte[mdLength]; - byte[] OTSseed = new byte[mdLength]; - if (nextRootSig == null) - { - this.nextRootSig = new GMSSRootSig[numLayer - 1]; - for (int i = 0; i < numLayer - 1; i++) - { - System.arraycopy(currentSeeds[i], 0, dummy, 0, mdLength); - gmssRandom.nextSeed(dummy); - OTSseed = gmssRandom.nextSeed(dummy); - this.nextRootSig[i] = new GMSSRootSig(digestProvider.get(), otsIndex[i], - heightOfTrees[i + 1]); - this.nextRootSig[i].initSign(OTSseed, nextRoot[i]); - } - } - else - { - this.nextRootSig = nextRootSig; - } - } - - // we assume this only gets called from nextKey so used is never copied. - private GMSSPrivateKeyParameters(GMSSPrivateKeyParameters original) - { - super(true, original.getParameters()); - - this.index = Arrays.clone(original.index); - this.currentSeeds = Arrays.clone(original.currentSeeds); - this.nextNextSeeds = Arrays.clone(original.nextNextSeeds); - this.currentAuthPaths = Arrays.clone(original.currentAuthPaths); - this.nextAuthPaths = Arrays.clone(original.nextAuthPaths); - this.currentTreehash = original.currentTreehash; - this.nextTreehash = original.nextTreehash; - this.currentStack = original.currentStack; - this.nextStack = original.nextStack; - this.currentRetain = original.currentRetain; - this.nextRetain = original.nextRetain; - this.keep = Arrays.clone(original.keep); - this.nextNextLeaf = original.nextNextLeaf; - this.upperLeaf = original.upperLeaf; - this.upperTreehashLeaf = original.upperTreehashLeaf; - this.minTreehash = original.minTreehash; - this.gmssPS = original.gmssPS; - this.nextRoot = Arrays.clone(original.nextRoot); - this.nextNextRoot = original.nextNextRoot; - this.currentRootSig = original.currentRootSig; - this.nextRootSig = original.nextRootSig; - this.digestProvider = original.digestProvider; - this.heightOfTrees = original.heightOfTrees; - this.otsIndex = original.otsIndex; - this.K = original.K; - this.numLayer = original.numLayer; - this.messDigestTrees = original.messDigestTrees; - this.mdLength = original.mdLength; - this.gmssRandom = original.gmssRandom; - this.numLeafs = original.numLeafs; - } - - public boolean isUsed() - { - return this.used; - } - - public void markUsed() - { - this.used = true; - } - - public GMSSPrivateKeyParameters nextKey() - { - GMSSPrivateKeyParameters nKey = new GMSSPrivateKeyParameters(this); - - nKey.nextKey(gmssPS.getNumOfLayers() - 1); - - return nKey; - } - - /** - * This method updates the GMSS private key for the next signature - * - * @param layer the layer where the next key is processed - */ - private void nextKey(int layer) - { - // only for lowest layer ( other layers indices are raised in nextTree() - // method ) - if (layer == numLayer - 1) - { - index[layer]++; - } // else System.out.println(" --- nextKey on layer " + layer + " - // index is now : " + index[layer]); - - // if tree of this layer is depleted - if (index[layer] == numLeafs[layer]) - { - if (numLayer != 1) - { - nextTree(layer); - index[layer] = 0; - } - } - else - { - updateKey(layer); - } - } - - /** - * Switch to next subtree if the current one is depleted - * - * @param layer the layer where the next tree is processed - */ - private void nextTree(int layer) - { - // System.out.println("NextTree method called on layer " + layer); - // dont create next tree for the top layer - if (layer > 0) - { - // raise index for upper layer - index[layer - 1]++; - - // test if it is already the last tree - boolean lastTree = true; - int z = layer; - do - { - z--; - if (index[z] < numLeafs[z]) - { - lastTree = false; - } - } - while (lastTree && (z > 0)); - - // only construct next subtree if last one is not already in use - if (!lastTree) - { - gmssRandom.nextSeed(currentSeeds[layer]); - - // last step of distributed signature calculation - nextRootSig[layer - 1].updateSign(); - - // last step of distributed leaf calculation for nextNextLeaf - if (layer > 1) - { - nextNextLeaf[layer - 1 - 1] = nextNextLeaf[layer - 1 - 1].nextLeaf(); - } - - // last step of distributed leaf calculation for upper leaf - upperLeaf[layer - 1] = upperLeaf[layer - 1].nextLeaf(); - - // last step of distributed leaf calculation for all treehashs - - if (minTreehash[layer - 1] >= 0) - { - upperTreehashLeaf[layer - 1] = upperTreehashLeaf[layer - 1].nextLeaf(); - byte[] leaf = this.upperTreehashLeaf[layer - 1].getLeaf(); - // if update is required use the precomputed leaf to update - // treehash - try - { - currentTreehash[layer - 1][minTreehash[layer - 1]] - .update(this.gmssRandom, leaf); - // System.out.println("UUUpdated TH " + - // minTreehash[layer - 1]); - if (currentTreehash[layer - 1][minTreehash[layer - 1]] - .wasFinished()) - { - // System.out.println("FFFinished TH " + - // minTreehash[layer - 1]); - } - } - catch (Exception e) - { - // -DM System.out.println - System.out.println(e); - } - } - - // last step of nextNextAuthRoot calculation - this.updateNextNextAuthRoot(layer); - - // ******************************************************** / - - // NOW: advance to next tree on layer 'layer' - - // NextRootSig --> currentRootSigs - this.currentRootSig[layer - 1] = nextRootSig[layer - 1] - .getSig(); - - // ----------------------- - - // nextTreehash --> currentTreehash - // nextNextTreehash --> nextTreehash - for (int i = 0; i < heightOfTrees[layer] - K[layer]; i++) - { - this.currentTreehash[layer][i] = this.nextTreehash[layer - 1][i]; - this.nextTreehash[layer - 1][i] = this.nextNextRoot[layer - 1] - .getTreehash()[i]; - } - - // NextAuthPath --> currentAuthPath - // nextNextAuthPath --> nextAuthPath - for (int i = 0; i < heightOfTrees[layer]; i++) - { - System.arraycopy(nextAuthPaths[layer - 1][i], 0, - currentAuthPaths[layer][i], 0, mdLength); - System.arraycopy(nextNextRoot[layer - 1].getAuthPath()[i], - 0, nextAuthPaths[layer - 1][i], 0, mdLength); - } - - // nextRetain --> currentRetain - // nextNextRetain --> nextRetain - for (int i = 0; i < K[layer] - 1; i++) - { - this.currentRetain[layer][i] = this.nextRetain[layer - 1][i]; - this.nextRetain[layer - 1][i] = this.nextNextRoot[layer - 1] - .getRetain()[i]; - } - - // nextStack --> currentStack - this.currentStack[layer] = this.nextStack[layer - 1]; - // nextNextStack --> nextStack - this.nextStack[layer - 1] = this.nextNextRoot[layer - 1] - .getStack(); - - // nextNextRoot --> nextRoot - this.nextRoot[layer - 1] = this.nextNextRoot[layer - 1] - .getRoot(); - // ----------------------- - - // ----------------- - byte[] OTSseed = new byte[mdLength]; - byte[] dummy = new byte[mdLength]; - // gmssRandom.setSeed(currentSeeds[layer]); - System - .arraycopy(currentSeeds[layer - 1], 0, dummy, 0, - mdLength); - OTSseed = gmssRandom.nextSeed(dummy); // only need OTSSeed - OTSseed = gmssRandom.nextSeed(dummy); - OTSseed = gmssRandom.nextSeed(dummy); - // nextWinSig[layer-1]=new - // GMSSWinSig(OTSseed,algNames,otsIndex[layer-1],heightOfTrees[layer],nextRoot[layer-1]); - nextRootSig[layer - 1].initSign(OTSseed, nextRoot[layer - 1]); - - // nextKey for upper layer - nextKey(layer - 1); - } - } - } - - /** - * This method computes the authpath (AUTH) for the current tree, - * Additionally the root signature for the next tree (SIG+), the authpath - * (AUTH++) and root (ROOT++) for the tree after next in layer - * layer, and the LEAF++^1 for the next next tree in the - * layer above are updated This method is used by nextKey() - * - * @param layer - */ - private void updateKey(int layer) - { - // ----------current tree processing of actual layer--------- - // compute upcoming authpath for current Tree (AUTH) - computeAuthPaths(layer); - - // -----------distributed calculations part------------ - // not for highest tree layer - if (layer > 0) - { - - // compute (partial) next leaf on TREE++ (not on layer 1 and 0) - if (layer > 1) - { - nextNextLeaf[layer - 1 - 1] = nextNextLeaf[layer - 1 - 1].nextLeaf(); - } - - // compute (partial) next leaf on tree above (not on layer 0) - upperLeaf[layer - 1] = upperLeaf[layer - 1].nextLeaf(); - - // compute (partial) next leaf for all treehashs on tree above (not - // on layer 0) - - int t = (int)Math - .floor((double)(this.getNumLeafs(layer) * 2) - / (double)(this.heightOfTrees[layer - 1] - this.K[layer - 1])); - - if (index[layer] % t == 1) - { - // System.out.println(" layer: " + layer + " index: " + - // index[layer] + " t : " + t); - - // take precomputed node for treehash update - // ------------------------------------------------ - if (index[layer] > 1 && minTreehash[layer - 1] >= 0) - { - byte[] leaf = this.upperTreehashLeaf[layer - 1].getLeaf(); - // if update is required use the precomputed leaf to update - // treehash - try - { - currentTreehash[layer - 1][minTreehash[layer - 1]] - .update(this.gmssRandom, leaf); - // System.out.println("Updated TH " + minTreehash[layer - // - 1]); - if (currentTreehash[layer - 1][minTreehash[layer - 1]] - .wasFinished()) - { - // System.out.println("Finished TH " + - // minTreehash[layer - 1]); - } - } - catch (Exception e) - { - // -DM System.out.println - System.out.println(e); - } - // ------------------------------------------------ - } - - // initialize next leaf precomputation - // ------------------------------------------------ - - // get lowest index of treehashs - this.minTreehash[layer - 1] = getMinTreehashIndex(layer - 1); - - if (this.minTreehash[layer - 1] >= 0) - { - // initialize leaf - byte[] seed = this.currentTreehash[layer - 1][this.minTreehash[layer - 1]] - .getSeedActive(); - this.upperTreehashLeaf[layer - 1] = new GMSSLeaf( - this.digestProvider.get(), this.otsIndex[layer - 1], t, seed); - this.upperTreehashLeaf[layer - 1] = this.upperTreehashLeaf[layer - 1].nextLeaf(); - // System.out.println("restarted treehashleaf (" + (layer - - // 1) + "," + this.minTreehash[layer - 1] + ")"); - } - // ------------------------------------------------ - - } - else - { - // update the upper leaf for the treehash one step - if (this.minTreehash[layer - 1] >= 0) - { - this.upperTreehashLeaf[layer - 1] = this.upperTreehashLeaf[layer - 1].nextLeaf(); - // if (minTreehash[layer - 1] > 3) - // System.out.print("#"); - } - } - - // compute (partial) the signature of ROOT+ (RootSig+) (not on top - // layer) - nextRootSig[layer - 1].updateSign(); - - // compute (partial) AUTHPATH++ & ROOT++ (not on top layer) - if (index[layer] == 1) - { - // init root and authpath calculation for tree after next - // (AUTH++, ROOT++) - this.nextNextRoot[layer - 1].initialize(new Vector()); - } - - // update root and authpath calculation for tree after next (AUTH++, - // ROOT++) - this.updateNextNextAuthRoot(layer); - } - // ----------- end distributed calculations part----------------- - } - - /** - * This method returns the index of the next Treehash instance that should - * receive an update - * - * @param layer the layer of the GMSS tree - * @return index of the treehash instance that should get the update - */ - private int getMinTreehashIndex(int layer) - { - int minTreehash = -1; - for (int h = 0; h < heightOfTrees[layer] - K[layer]; h++) - { - if (currentTreehash[layer][h].wasInitialized() - && !currentTreehash[layer][h].wasFinished()) - { - if (minTreehash == -1) - { - minTreehash = h; - } - else if (currentTreehash[layer][h].getLowestNodeHeight() < currentTreehash[layer][minTreehash] - .getLowestNodeHeight()) - { - minTreehash = h; - } - } - } - return minTreehash; - } - - /** - * Computes the upcoming currentAuthpath of layer layer using - * the revisited authentication path computation of Dahmen/Schneider 2008 - * - * @param layer the actual layer - */ - private void computeAuthPaths(int layer) - { - - int Phi = index[layer]; - int H = heightOfTrees[layer]; - int K = this.K[layer]; - - // update all nextSeeds for seed scheduling - for (int i = 0; i < H - K; i++) - { - currentTreehash[layer][i].updateNextSeed(gmssRandom); - } - - // STEP 1 of Algorithm - int Tau = heightOfPhi(Phi); - - byte[] OTSseed = new byte[mdLength]; - OTSseed = gmssRandom.nextSeed(currentSeeds[layer]); - - // STEP 2 of Algorithm - // if phi's parent on height tau + 1 if left node, store auth_tau - // in keep_tau. - // TODO check it, formerly was - // int L = Phi / (int) Math.floor(Math.pow(2, Tau + 1)); - // L %= 2; - int L = (Phi >>> (Tau + 1)) & 1; - - byte[] tempKeep = new byte[mdLength]; - // store the keep node not in keep[layer][tau/2] because it might be in - // use - // wait until the space is freed in step 4a - if (Tau < H - 1 && L == 0) - { - System.arraycopy(currentAuthPaths[layer][Tau], 0, tempKeep, 0, - mdLength); - } - - byte[] help = new byte[mdLength]; - // STEP 3 of Algorithm - // if phi is left child, compute and store leaf for next currentAuthPath - // path, - // (obtained by veriying current signature) - if (Tau == 0) - { - // LEAFCALC !!! - if (layer == numLayer - 1) - { // lowest layer computes the - // necessary leaf completely at this - // time - WinternitzOTSignature ots = new WinternitzOTSignature(OTSseed, - digestProvider.get(), otsIndex[layer]); - help = ots.getPublicKey(); - } - else - { // other layers use the precomputed leafs in - // nextNextLeaf - byte[] dummy = new byte[mdLength]; - System.arraycopy(currentSeeds[layer], 0, dummy, 0, mdLength); - gmssRandom.nextSeed(dummy); - help = upperLeaf[layer].getLeaf(); - this.upperLeaf[layer].initLeafCalc(dummy); - - // WinternitzOTSVerify otsver = new - // WinternitzOTSVerify(algNames, otsIndex[layer]); - // byte[] help2 = otsver.Verify(currentRoot[layer], - // currentRootSig[layer]); - // System.out.println(" --- " + layer + " " + - // ByteUtils.toHexString(help) + " " + - // ByteUtils.toHexString(help2)); - } - System.arraycopy(help, 0, currentAuthPaths[layer][0], 0, mdLength); - } - else - { - // STEP 4a of Algorithm - // get new left currentAuthPath node on height tau - byte[] toBeHashed = new byte[mdLength << 1]; - System.arraycopy(currentAuthPaths[layer][Tau - 1], 0, toBeHashed, - 0, mdLength); - // free the shared keep[layer][tau/2] - System.arraycopy(keep[layer][(int)Math.floor((Tau - 1) / 2)], 0, - toBeHashed, mdLength, mdLength); - messDigestTrees.update(toBeHashed, 0, toBeHashed.length); - currentAuthPaths[layer][Tau] = new byte[messDigestTrees.getDigestSize()]; - messDigestTrees.doFinal(currentAuthPaths[layer][Tau], 0); - - // STEP 4b and 4c of Algorithm - // copy right nodes to currentAuthPath on height 0..Tau-1 - for (int i = 0; i < Tau; i++) - { - - // STEP 4b of Algorithm - // 1st: copy from treehashs - if (i < H - K) - { - if (currentTreehash[layer][i].wasFinished()) - { - System.arraycopy(currentTreehash[layer][i] - .getFirstNode(), 0, currentAuthPaths[layer][i], - 0, mdLength); - currentTreehash[layer][i].destroy(); - } - else - { - // -DM System.err.println - System.err - .println("Treehash (" - + layer - + "," - + i - + ") not finished when needed in AuthPathComputation"); - } - } - - // 2nd: copy precomputed values from Retain - if (i < H - 1 && i >= H - K) - { - if (currentRetain[layer][i - (H - K)].size() > 0) - { - // pop element from retain - System.arraycopy(currentRetain[layer][i - (H - K)] - .lastElement(), 0, currentAuthPaths[layer][i], - 0, mdLength); - currentRetain[layer][i - (H - K)] - .removeElementAt(currentRetain[layer][i - - (H - K)].size() - 1); - } - } - - // STEP 4c of Algorithm - // initialize new stack at heights 0..Tau-1 - if (i < H - K) - { - // create stacks anew - int startPoint = Phi + 3 * (1 << i); - if (startPoint < numLeafs[layer]) - { - // if (layer < 2) { - // System.out.println("initialized TH " + i + " on layer - // " + layer); - // } - currentTreehash[layer][i].initialize(); - } - } - } - } - - // now keep space is free to use - if (Tau < H - 1 && L == 0) - { - System.arraycopy(tempKeep, 0, - keep[layer][(int)Math.floor(Tau / 2)], 0, mdLength); - } - - // only update empty stack at height h if all other stacks have - // tailnodes with height >h - // finds active stack with lowest node height, choses lower index in - // case of tie - - // on the lowest layer leafs must be computed at once, no precomputation - // is possible. So all treehash updates are done at once here - if (layer == numLayer - 1) - { - for (int tmp = 1; tmp <= (H - K) / 2; tmp++) - { - // index of the treehash instance that receives the next update - int minTreehash = getMinTreehashIndex(layer); - - // if active treehash is found update with a leaf - if (minTreehash >= 0) - { - try - { - byte[] seed = new byte[mdLength]; - System.arraycopy( - this.currentTreehash[layer][minTreehash] - .getSeedActive(), 0, seed, 0, mdLength); - byte[] seed2 = gmssRandom.nextSeed(seed); - WinternitzOTSignature ots = new WinternitzOTSignature( - seed2, this.digestProvider.get(), this.otsIndex[layer]); - byte[] leaf = ots.getPublicKey(); - currentTreehash[layer][minTreehash].update( - this.gmssRandom, leaf); - } - catch (Exception e) - { - // -DM System.out.println - System.out.println(e); - } - } - } - } - else - { // on higher layers the updates are done later - this.minTreehash[layer] = getMinTreehashIndex(layer); - } - } - - /** - * Returns the largest h such that 2^h | Phi - * - * @param Phi the leaf index - * @return The largest h with 2^h | Phi if - * Phi!=0 else return -1 - */ - private int heightOfPhi(int Phi) - { - if (Phi == 0) - { - return -1; - } - int Tau = 0; - int modul = 1; - while (Phi % modul == 0) - { - modul *= 2; - Tau += 1; - } - return Tau - 1; - } - - /** - * Updates the authentication path and root calculation for the tree after - * next (AUTH++, ROOT++) in layer layer - * - * @param layer - */ - private void updateNextNextAuthRoot(int layer) - { - - byte[] OTSseed = new byte[mdLength]; - OTSseed = gmssRandom.nextSeed(nextNextSeeds[layer - 1]); - - // get the necessary leaf - if (layer == numLayer - 1) - { // lowest layer computes the necessary - // leaf completely at this time - WinternitzOTSignature ots = new WinternitzOTSignature(OTSseed, - digestProvider.get(), otsIndex[layer]); - this.nextNextRoot[layer - 1].update(nextNextSeeds[layer - 1], ots - .getPublicKey()); - } - else - { // other layers use the precomputed leafs in nextNextLeaf - this.nextNextRoot[layer - 1].update(nextNextSeeds[layer - 1], nextNextLeaf[layer - 1].getLeaf()); - this.nextNextLeaf[layer - 1].initLeafCalc(nextNextSeeds[layer - 1]); - } - } - - public int[] getIndex() - { - return index; - } - - /** - * @return The current index of layer i - */ - public int getIndex(int i) - { - return index[i]; - } - - public byte[][] getCurrentSeeds() - { - return Arrays.clone(currentSeeds); - } - - public byte[][][] getCurrentAuthPaths() - { - return Arrays.clone(currentAuthPaths); - } - - /** - * @return The one-time signature of the root of the current subtree - */ - public byte[] getSubtreeRootSig(int i) - { - return currentRootSig[i]; - } - - - public GMSSDigestProvider getName() - { - return digestProvider; - } - - /** - * @return The number of leafs of each tree of layer i - */ - public int getNumLeafs(int i) - { - return numLeafs[i]; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSPublicKeyParameters.java deleted file mode 100644 index 34c89c59bf..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSPublicKeyParameters.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss; - - -public class GMSSPublicKeyParameters - extends GMSSKeyParameters -{ - /** - * The GMSS public key - */ - private byte[] gmssPublicKey; - - /** - * The constructor. - * - * @param key a raw GMSS public key - * @param gmssParameterSet an instance of GMSSParameterset - */ - public GMSSPublicKeyParameters(byte[] key, GMSSParameters gmssParameterSet) - { - super(false, gmssParameterSet); - this.gmssPublicKey = key; - } - - /** - * Returns the GMSS public key - * - * @return The GMSS public key - */ - public byte[] getPublicKey() - { - return gmssPublicKey; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSRootCalc.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSRootCalc.java deleted file mode 100644 index 8e99722af2..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSRootCalc.java +++ /dev/null @@ -1,525 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss; - -import java.util.Enumeration; -import java.util.Vector; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Integers; -import org.bouncycastle.util.encoders.Hex; - - -/** - * This class computes a whole Merkle tree and saves the needed values for - * AuthPath computation. It is used for precomputation of the root of a - * following tree. After initialization, 2^H updates are required to complete - * the root. Every update requires one leaf value as parameter. While computing - * the root all initial values for the authentication path algorithm (treehash, - * auth, retain) are stored for later use. - */ -public class GMSSRootCalc -{ - - /** - * max height of the tree - */ - private int heightOfTree; - - /** - * length of the messageDigest - */ - private int mdLength; - - /** - * the treehash instances of the tree - */ - private Treehash[] treehash; - - /** - * stores the retain nodes for authPath computation - */ - private Vector[] retain; - - /** - * finally stores the root of the tree when finished - */ - private byte[] root; - - /** - * stores the authentication path y_1(i), i = 0..H-1 - */ - private byte[][] AuthPath; - - /** - * the value K for the authentication path computation - */ - private int K; - - /** - * Vector element that stores the nodes on the stack - */ - private Vector tailStack; - - /** - * stores the height of all nodes laying on the tailStack - */ - private Vector heightOfNodes; - /** - * The hash function used for the construction of the authentication trees - */ - private Digest messDigestTree; - - /** - * An array of strings containing the name of the hash function used to - * construct the authentication trees and used by the OTS. - */ - private GMSSDigestProvider digestProvider; - - /** - * stores the index of the current node on each height of the tree - */ - private int[] index; - - /** - * true if instance was already initialized, false otherwise - */ - private boolean isInitialized; - - /** - * true it instance was finished - */ - private boolean isFinished; - - /** - * Integer that stores the index of the next seed that has to be omitted to - * the treehashs - */ - private int indexForNextSeed; - - /** - * temporary integer that stores the height of the next treehash instance - * that gets initialized with a seed - */ - private int heightOfNextSeed; - - /** - * Constructor - * - * @param heightOfTree maximal height of the tree - * @param digestProvider an array of strings, containing the name of the used hash - * function and PRNG and the name of the corresponding - * provider - */ - public GMSSRootCalc(int heightOfTree, int K, GMSSDigestProvider digestProvider) - { - this.heightOfTree = heightOfTree; - this.digestProvider = digestProvider; - this.messDigestTree = digestProvider.get(); - this.mdLength = messDigestTree.getDigestSize(); - this.K = K; - this.index = new int[heightOfTree]; - this.AuthPath = new byte[heightOfTree][mdLength]; - this.root = new byte[mdLength]; - // this.treehash = new Treehash[this.heightOfTree - this.K]; - this.retain = new Vector[this.K - 1]; - for (int i = 0; i < K - 1; i++) - { - this.retain[i] = new Vector(); - } - - } - - /** - * Initializes the calculation of a new root - * - * @param sharedStack the stack shared by all treehash instances of this tree - */ - public void initialize(Vector sharedStack) - { - this.treehash = new Treehash[this.heightOfTree - this.K]; - for (int i = 0; i < this.heightOfTree - this.K; i++) - { - this.treehash[i] = new Treehash(sharedStack, i, this.digestProvider.get()); - } - - this.index = new int[heightOfTree]; - this.AuthPath = new byte[heightOfTree][mdLength]; - this.root = new byte[mdLength]; - - this.tailStack = new Vector(); - this.heightOfNodes = new Vector(); - this.isInitialized = true; - this.isFinished = false; - - for (int i = 0; i < heightOfTree; i++) - { - this.index[i] = -1; - } - - this.retain = new Vector[this.K - 1]; - for (int i = 0; i < K - 1; i++) - { - this.retain[i] = new Vector(); - } - - this.indexForNextSeed = 3; - this.heightOfNextSeed = 0; - } - - /** - * updates the root with one leaf and stores needed values in retain, - * treehash or authpath. Additionally counts the seeds used. This method is - * used when performing the updates for TREE++. - * - * @param seed the initial seed for treehash: seedNext - * @param leaf the height of the treehash - */ - public void update(byte[] seed, byte[] leaf) - { - if (this.heightOfNextSeed < (this.heightOfTree - this.K) - && this.indexForNextSeed - 2 == index[0]) - { - this.initializeTreehashSeed(seed, this.heightOfNextSeed); - this.heightOfNextSeed++; - this.indexForNextSeed *= 2; - } - // now call the simple update - this.update(leaf); - } - - /** - * Updates the root with one leaf and stores the needed values in retain, - * treehash or authpath - */ - public void update(byte[] leaf) - { - - if (isFinished) - { - // -DM System.out.print - System.out.print("Too much updates for Tree!!"); - return; - } - if (!isInitialized) - { - // -DM System.err.print - System.err.println("GMSSRootCalc not initialized!"); - return; - } - - // a new leaf was omitted, so raise index on lowest layer - index[0]++; - - // store the nodes on the lowest layer in treehash or authpath - if (index[0] == 1) - { - System.arraycopy(leaf, 0, AuthPath[0], 0, mdLength); - } - else if (index[0] == 3) - { - // store in treehash only if K < H - if (heightOfTree > K) - { - treehash[0].setFirstNode(leaf); - } - } - - if ((index[0] - 3) % 2 == 0 && index[0] >= 3) - { - // store in retain if K = H - if (heightOfTree == K) - // TODO: check it - { - retain[0].insertElementAt(leaf, 0); - } - } - - // if first update to this tree is made - if (index[0] == 0) - { - tailStack.addElement(leaf); - heightOfNodes.addElement(Integers.valueOf(0)); - } - else - { - - byte[] help = new byte[mdLength]; - byte[] toBeHashed = new byte[mdLength << 1]; - - // store the new leaf in help - System.arraycopy(leaf, 0, help, 0, mdLength); - int helpHeight = 0; - // while top to nodes have same height - while (tailStack.size() > 0 - && helpHeight == ((Integer)heightOfNodes.lastElement()) - .intValue()) - { - - // help <-- hash(stack top element || help) - System.arraycopy(tailStack.lastElement(), 0, toBeHashed, 0, - mdLength); - tailStack.removeElementAt(tailStack.size() - 1); - heightOfNodes.removeElementAt(heightOfNodes.size() - 1); - System.arraycopy(help, 0, toBeHashed, mdLength, mdLength); - - messDigestTree.update(toBeHashed, 0, toBeHashed.length); - help = new byte[messDigestTree.getDigestSize()]; - messDigestTree.doFinal(help, 0); - - // the new help node is one step higher - helpHeight++; - if (helpHeight < heightOfTree) - { - index[helpHeight]++; - - // add index 1 element to initial authpath - if (index[helpHeight] == 1) - { - System.arraycopy(help, 0, AuthPath[helpHeight], 0, - mdLength); - } - - if (helpHeight >= heightOfTree - K) - { - if (helpHeight == 0) - { - // -DM System.out.println - System.out.println("M���P"); - } - // add help element to retain stack if it is a right - // node - // and not stored in treehash - if ((index[helpHeight] - 3) % 2 == 0 - && index[helpHeight] >= 3) - // TODO: check it - { - retain[helpHeight - (heightOfTree - K)] - .insertElementAt(help, 0); - } - } - else - { - // if element is third in his line add it to treehash - if (index[helpHeight] == 3) - { - treehash[helpHeight].setFirstNode(help); - } - } - } - } - // push help element to the stack - tailStack.addElement(help); - heightOfNodes.addElement(Integers.valueOf(helpHeight)); - - // is the root calculation finished? - if (helpHeight == heightOfTree) - { - isFinished = true; - isInitialized = false; - root = (byte[])tailStack.lastElement(); - } - } - - } - - /** - * initializes the seeds for the treehashs of the tree precomputed by this - * class - * - * @param seed the initial seed for treehash: seedNext - * @param index the height of the treehash - */ - public void initializeTreehashSeed(byte[] seed, int index) - { - treehash[index].initializeSeed(seed); - } - - /** - * Method to check whether the instance has been initialized or not - * - * @return true if treehash was already initialized - */ - public boolean wasInitialized() - { - return isInitialized; - } - - /** - * Method to check whether the instance has been finished or not - * - * @return true if tree has reached its maximum height - */ - public boolean wasFinished() - { - return isFinished; - } - - /** - * returns the authentication path of the first leaf of the tree - * - * @return the authentication path of the first leaf of the tree - */ - public byte[][] getAuthPath() - { - return GMSSUtils.clone(AuthPath); - } - - /** - * returns the initial treehash instances, storing value y_3(i) - * - * @return the initial treehash instances, storing value y_3(i) - */ - public Treehash[] getTreehash() - { - return GMSSUtils.clone(treehash); - } - - /** - * returns the retain stacks storing all right nodes near to the root - * - * @return the retain stacks storing all right nodes near to the root - */ - public Vector[] getRetain() - { - return GMSSUtils.clone(retain); - } - - /** - * returns the finished root value - * - * @return the finished root value - */ - public byte[] getRoot() - { - return Arrays.clone(root); - } - - /** - * returns the shared stack - * - * @return the shared stack - */ - public Vector getStack() - { - Vector copy = new Vector(); - for (Enumeration en = tailStack.elements(); en.hasMoreElements();) - { - copy.addElement(en.nextElement()); - } - return copy; - } - - /** - * Returns the status byte array used by the GMSSPrivateKeyASN.1 class - * - * @return The status bytes - */ - public byte[][] getStatByte() - { - - int tailLength; - if (tailStack == null) - { - tailLength = 0; - } - else - { - tailLength = tailStack.size(); - } - byte[][] statByte = new byte[1 + heightOfTree + tailLength][64]; //FIXME: messDigestTree.getByteLength() - statByte[0] = root; - - for (int i = 0; i < heightOfTree; i++) - { - statByte[1 + i] = AuthPath[i]; - } - for (int i = 0; i < tailLength; i++) - { - statByte[1 + heightOfTree + i] = (byte[])tailStack.elementAt(i); - } - - return statByte; - } - - /** - * Returns the status int array used by the GMSSPrivateKeyASN.1 class - * - * @return The status ints - */ - public int[] getStatInt() - { - - int tailLength; - if (tailStack == null) - { - tailLength = 0; - } - else - { - tailLength = tailStack.size(); - } - int[] statInt = new int[8 + heightOfTree + tailLength]; - statInt[0] = heightOfTree; - statInt[1] = mdLength; - statInt[2] = K; - statInt[3] = indexForNextSeed; - statInt[4] = heightOfNextSeed; - if (isFinished) - { - statInt[5] = 1; - } - else - { - statInt[5] = 0; - } - if (isInitialized) - { - statInt[6] = 1; - } - else - { - statInt[6] = 0; - } - statInt[7] = tailLength; - - for (int i = 0; i < heightOfTree; i++) - { - statInt[8 + i] = index[i]; - } - for (int i = 0; i < tailLength; i++) - { - statInt[8 + heightOfTree + i] = ((Integer)heightOfNodes - .elementAt(i)).intValue(); - } - - return statInt; - } - - /** - * @return a human readable version of the structure - */ - public String toString() - { - String out = ""; - int tailLength; - if (tailStack == null) - { - tailLength = 0; - } - else - { - tailLength = tailStack.size(); - } - - for (int i = 0; i < 8 + heightOfTree + tailLength; i++) - { - out = out + getStatInt()[i] + " "; - } - for (int i = 0; i < 1 + heightOfTree + tailLength; i++) - { - out = out + new String(Hex.encode(getStatByte()[i])) + " "; - } - out = out + " " + digestProvider.get().getDigestSize(); - return out; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSRootSig.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSRootSig.java deleted file mode 100644 index 10eee9f453..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSRootSig.java +++ /dev/null @@ -1,666 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.pqc.legacy.crypto.gmss.util.GMSSRandom; -import org.bouncycastle.util.encoders.Hex; - - -/** - * This class implements the distributed signature generation of the Winternitz - * one-time signature scheme (OTSS), described in C.Dods, N.P. Smart, and M. - * Stam, "Hash Based Digital Signature Schemes", LNCS 3796, pages 96–115, - * 2005. The class is used by the GMSS classes. - */ -public class GMSSRootSig -{ - - /** - * The hash function used by the OTS - */ - private Digest messDigestOTS; - - /** - * The length of the message digest and private key - */ - private int mdsize, keysize; - - /** - * The private key - */ - private byte[] privateKeyOTS; - - /** - * The message bytes - */ - private byte[] hash; - - /** - * The signature bytes - */ - private byte[] sign; - - /** - * The Winternitz parameter - */ - private int w; - - /** - * The source of randomness for OTS private key generation - */ - private GMSSRandom gmssRandom; - - /** - * Sizes of the message - */ - private int messagesize; - - /** - * Some precalculated values - */ - private int k; - - /** - * Some variables for storing the actual status of distributed signing - */ - private int r, test, counter, ii; - - /** - * variables for storing big numbers for the actual status of distributed - * signing - */ - private long test8, big8; - - /** - * The necessary steps of each updateSign() call - */ - private int steps; - - /** - * The checksum part - */ - private int checksum; - - /** - * The height of the tree - */ - private int height; - - /** - * The current intern OTSseed - */ - private byte[] seed; - - /** - * This constructor regenerates a prior GMSSRootSig object used by the - * GMSSPrivateKeyASN.1 class - * - * @param digest an array of strings, containing the digest of the used hash - * function, the digest of the PRGN and the names of the - * corresponding providers - * @param statByte status byte array - * @param statInt status int array - */ - public GMSSRootSig(Digest digest, byte[][] statByte, int[] statInt) - { - messDigestOTS = digest; - gmssRandom = new GMSSRandom(messDigestOTS); - - this.counter = statInt[0]; - this.test = statInt[1]; - this.ii = statInt[2]; - this.r = statInt[3]; - this.steps = statInt[4]; - this.keysize = statInt[5]; - this.height = statInt[6]; - this.w = statInt[7]; - this.checksum = statInt[8]; - - this.mdsize = messDigestOTS.getDigestSize(); - - this.k = (1 << w) - 1; - - int mdsizeBit = mdsize << 3; - this.messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w); - - this.privateKeyOTS = statByte[0]; - this.seed = statByte[1]; - this.hash = statByte[2]; - - this.sign = statByte[3]; - - this.test8 = ((statByte[4][0] & 0xff)) - | ((long)(statByte[4][1] & 0xff) << 8) - | ((long)(statByte[4][2] & 0xff) << 16) - | ((long)(statByte[4][3] & 0xff)) << 24 - | ((long)(statByte[4][4] & 0xff)) << 32 - | ((long)(statByte[4][5] & 0xff)) << 40 - | ((long)(statByte[4][6] & 0xff)) << 48 - | ((long)(statByte[4][7] & 0xff)) << 56; - - this.big8 = ((statByte[4][8] & 0xff)) - | ((long)(statByte[4][9] & 0xff) << 8) - | ((long)(statByte[4][10] & 0xff) << 16) - | ((long)(statByte[4][11] & 0xff)) << 24 - | ((long)(statByte[4][12] & 0xff)) << 32 - | ((long)(statByte[4][13] & 0xff)) << 40 - | ((long)(statByte[4][14] & 0xff)) << 48 - | ((long)(statByte[4][15] & 0xff)) << 56; - } - - /** - * The constructor generates the PRNG and initializes some variables - * - * @param digest an array of strings, containing the digest of the used hash - * function, the digest of the PRGN and the names of the - * corresponding providers - * @param w the winternitz parameter - * @param height the heigth of the tree - */ - public GMSSRootSig(Digest digest, int w, int height) - { - messDigestOTS = digest; - gmssRandom = new GMSSRandom(messDigestOTS); - - this.mdsize = messDigestOTS.getDigestSize(); - this.w = w; - this.height = height; - - this.k = (1 << w) - 1; - - int mdsizeBit = mdsize << 3; - this.messagesize = (int)Math.ceil((double)(mdsizeBit) / (double)w); - } - - /** - * This method initializes the distributed sigature calculation. Variables - * are reseted and necessary steps are calculated - * - * @param seed0 the initial OTSseed - * @param message the massage which will be signed - */ - public void initSign(byte[] seed0, byte[] message) - { - - // create hash of message m - this.hash = new byte[mdsize]; - messDigestOTS.update(message, 0, message.length); - this.hash = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(this.hash, 0); - - // variables for calculation of steps - byte[] messPart = new byte[mdsize]; - System.arraycopy(hash, 0, messPart, 0, mdsize); - int checkPart = 0; - int sumH = 0; - int checksumsize = getLog((messagesize << w) + 1); - - // ------- calculation of necessary steps ------ - if (8 % w == 0) - { - int dt = 8 / w; - // message part - for (int a = 0; a < mdsize; a++) - { - // count necessary hashs in 'sumH' - for (int b = 0; b < dt; b++) - { - sumH += messPart[a] & k; - messPart[a] = (byte)(messPart[a] >>> w); - } - } - // checksum part - this.checksum = (messagesize << w) - sumH; - checkPart = checksum; - // count necessary hashs in 'sumH' - for (int b = 0; b < checksumsize; b += w) - { - sumH += checkPart & k; - checkPart >>>= w; - } - } // end if ( 8 % w == 0 ) - else if (w < 8) - { - long big8; - int ii = 0; - int dt = mdsize / w; - - // first d*w bytes of hash (main message part) - for (int i = 0; i < dt; i++) - { - big8 = 0; - for (int j = 0; j < w; j++) - { - big8 ^= (messPart[ii] & 0xff) << (j << 3); - ii++; - } - // count necessary hashs in 'sumH' - for (int j = 0; j < 8; j++) - { - sumH += (int)(big8 & k); - big8 >>>= w; - } - } - // rest of message part - dt = mdsize % w; - big8 = 0; - for (int j = 0; j < dt; j++) - { - big8 ^= (messPart[ii] & 0xff) << (j << 3); - ii++; - } - dt <<= 3; - // count necessary hashs in 'sumH' - for (int j = 0; j < dt; j += w) - { - sumH += (int)(big8 & k); - big8 >>>= w; - } - // checksum part - this.checksum = (messagesize << w) - sumH; - checkPart = checksum; - // count necessary hashs in 'sumH' - for (int i = 0; i < checksumsize; i += w) - { - sumH += checkPart & k; - checkPart >>>= w; - } - }// end if(w<8) - else if (w < 57) - { - long big8; - int r = 0; - int s, f, rest, ii; - - // first a*w bits of hash where a*w <= 8*mdsize < (a+1)*w (main - // message part) - while (r <= ((mdsize << 3) - w)) - { - s = r >>> 3; - rest = r % 8; - r += w; - f = (r + 7) >>> 3; - big8 = 0; - ii = 0; - for (int j = s; j < f; j++) - { - big8 ^= (messPart[j] & 0xff) << (ii << 3); - ii++; - } - big8 >>>= rest; - // count necessary hashs in 'sumH' - sumH += (big8 & k); - - } - // rest of message part - s = r >>> 3; - if (s < mdsize) - { - rest = r % 8; - big8 = 0; - ii = 0; - for (int j = s; j < mdsize; j++) - { - big8 ^= (messPart[j] & 0xff) << (ii << 3); - ii++; - } - - big8 >>>= rest; - // count necessary hashs in 'sumH' - sumH += (big8 & k); - } - // checksum part - this.checksum = (messagesize << w) - sumH; - checkPart = checksum; - // count necessary hashs in 'sumH' - for (int i = 0; i < checksumsize; i += w) - { - sumH += (checkPart & k); - checkPart >>>= w; - } - }// end if(w<57) - - // calculate keysize - this.keysize = messagesize - + (int)Math.ceil((double)checksumsize / (double)w); - - // calculate steps: 'keysize' times PRNG, 'sumH' times hashing, - // (1<steps steps of distributed signature - * calculaion - * - * @return true if signature is generated completly, else false - */ - public boolean updateSign() - { - // steps times do - - for (int s = 0; s < steps; s++) - { // do 'step' times - - if (counter < keysize) - { // generate the private key or perform - // the next hash - oneStep(); - } - if (counter == keysize) - {// finish - return true; - } - } - - return false; // leaf not finished yet - } - - /** - * @return The private OTS key - */ - public byte[] getSig() - { - - return sign; - } - - /** - * @return The one-time signature of the message, generated step by step - */ - private void oneStep() - { - // -------- if (8 % w == 0) ---------- - if (8 % w == 0) - { - if (test == 0) - { - // get current OTSprivateKey - this.privateKeyOTS = gmssRandom.nextSeed(seed); - // System.arraycopy(privateKeyOTS, 0, hlp, 0, mdsize); - - if (ii < mdsize) - { // for main message part - test = hash[ii] & k; - hash[ii] = (byte)(hash[ii] >>> w); - } - else - { // for checksum part - test = checksum & k; - checksum >>>= w; - } - } - else if (test > 0) - { // hash the private Key 'test' times (on - // time each step) - messDigestOTS.update(privateKeyOTS, 0, privateKeyOTS.length); - privateKeyOTS = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(privateKeyOTS, 0); - test--; - } - if (test == 0) - { // if all hashes done copy result to siganture - // array - System.arraycopy(privateKeyOTS, 0, sign, counter * mdsize, - mdsize); - counter++; - - if (counter % (8 / w) == 0) - { // raise array index for main - // massage part - ii++; - } - } - - }// ----- end if (8 % w == 0) ----- - // ---------- if ( w < 8 ) ---------------- - else if (w < 8) - { - - if (test == 0) - { - if (counter % 8 == 0 && ii < mdsize) - { // after every 8th "add - // to signature"-step - big8 = 0; - if (counter < ((mdsize / w) << 3)) - {// main massage - // (generate w*8 Bits - // every time) part - for (int j = 0; j < w; j++) - { - big8 ^= (hash[ii] & 0xff) << (j << 3); - ii++; - } - } - else - { // rest of massage part (once) - for (int j = 0; j < mdsize % w; j++) - { - big8 ^= (hash[ii] & 0xff) << (j << 3); - ii++; - } - } - } - if (counter == messagesize) - { // checksum part (once) - big8 = checksum; - } - - test = (int)(big8 & k); - // generate current OTSprivateKey - this.privateKeyOTS = gmssRandom.nextSeed(seed); - // System.arraycopy(privateKeyOTS, 0, hlp, 0, mdsize); - - } - else if (test > 0) - { // hash the private Key 'test' times (on - // time each step) - messDigestOTS.update(privateKeyOTS, 0, privateKeyOTS.length); - privateKeyOTS = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(privateKeyOTS, 0); - test--; - } - if (test == 0) - { // if all hashes done copy result to siganture - // array - System.arraycopy(privateKeyOTS, 0, sign, counter * mdsize, - mdsize); - big8 >>>= w; - counter++; - } - - }// ------- end if(w<8)-------------------------------- - // --------- if w < 57 ----------------------------- - else if (w < 57) - { - - if (test8 == 0) - { - int s, f, rest; - big8 = 0; - ii = 0; - rest = r % 8; - s = r >>> 3; - // --- message part--- - if (s < mdsize) - { - if (r <= ((mdsize << 3) - w)) - { // first message part - r += w; - f = (r + 7) >>> 3; - } - else - { // rest of message part (once) - f = mdsize; - r += w; - } - // generate long 'big8' with minimum w next bits of the - // message array - for (int i = s; i < f; i++) - { - big8 ^= (hash[i] & 0xff) << (ii << 3); - ii++; - } - // delete bits on the right side, which were used already by - // the last loop - big8 >>>= rest; - test8 = (big8 & k); - } - // --- checksum part - else - { - test8 = (checksum & k); - checksum >>>= w; - } - // generate current OTSprivateKey - this.privateKeyOTS = gmssRandom.nextSeed(seed); - // System.arraycopy(privateKeyOTS, 0, hlp, 0, mdsize); - - } - else if (test8 > 0) - { // hash the private Key 'test' times (on - // time each step) - messDigestOTS.update(privateKeyOTS, 0, privateKeyOTS.length); - privateKeyOTS = new byte[messDigestOTS.getDigestSize()]; - messDigestOTS.doFinal(privateKeyOTS, 0); - test8--; - } - if (test8 == 0) - { // if all hashes done copy result to siganture - // array - System.arraycopy(privateKeyOTS, 0, sign, counter * mdsize, - mdsize); - counter++; - } - - } - } - - /** - * This method returns the least integer that is greater or equal to the - * logarithm to the base 2 of an integer intValue. - * - * @param intValue an integer - * @return The least integer greater or equal to the logarithm to the base 2 - * of intValue - */ - public int getLog(int intValue) - { - int log = 1; - int i = 2; - while (i < intValue) - { - i <<= 1; - log++; - } - return log; - } - - /** - * This method returns the status byte array - * - * @return statBytes - */ - public byte[][] getStatByte() - { - - byte[][] statByte = new byte[5][mdsize]; - statByte[0] = privateKeyOTS; - statByte[1] = seed; - statByte[2] = hash; - statByte[3] = sign; - statByte[4] = this.getStatLong(); - - return statByte; - } - - /** - * This method returns the status int array - * - * @return statInt - */ - public int[] getStatInt() - { - int[] statInt = new int[9]; - statInt[0] = counter; - statInt[1] = test; - statInt[2] = ii; - statInt[3] = r; - statInt[4] = steps; - statInt[5] = keysize; - statInt[6] = height; - statInt[7] = w; - statInt[8] = checksum; - return statInt; - } - - /** - * Converts the long parameters into byte arrays to store it in - * statByte-Array - */ - public byte[] getStatLong() - { - byte[] bytes = new byte[16]; - - bytes[0] = (byte)((test8) & 0xff); - bytes[1] = (byte)((test8 >> 8) & 0xff); - bytes[2] = (byte)((test8 >> 16) & 0xff); - bytes[3] = (byte)((test8 >> 24) & 0xff); - bytes[4] = (byte)((test8) >> 32 & 0xff); - bytes[5] = (byte)((test8 >> 40) & 0xff); - bytes[6] = (byte)((test8 >> 48) & 0xff); - bytes[7] = (byte)((test8 >> 56) & 0xff); - - bytes[8] = (byte)((big8) & 0xff); - bytes[9] = (byte)((big8 >> 8) & 0xff); - bytes[10] = (byte)((big8 >> 16) & 0xff); - bytes[11] = (byte)((big8 >> 24) & 0xff); - bytes[12] = (byte)((big8) >> 32 & 0xff); - bytes[13] = (byte)((big8 >> 40) & 0xff); - bytes[14] = (byte)((big8 >> 48) & 0xff); - bytes[15] = (byte)((big8 >> 56) & 0xff); - - return bytes; - } - - /** - * returns a string representation of the instance - * - * @return a string representation of the instance - */ - public String toString() - { - String out = "" + this.big8 + " "; - int[] statInt = new int[9]; - statInt = this.getStatInt(); - byte[][] statByte = new byte[5][mdsize]; - statByte = this.getStatByte(); - for (int i = 0; i < 9; i++) - { - out = out + statInt[i] + " "; - } - for (int i = 0; i < 5; i++) - { - out = out + new String(Hex.encode(statByte[i])) + " "; - } - - return out; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSSigner.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSSigner.java deleted file mode 100644 index 164b95e762..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSSigner.java +++ /dev/null @@ -1,405 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.CryptoServicesRegistrar; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.MessageSigner; -import org.bouncycastle.pqc.legacy.crypto.gmss.util.GMSSRandom; -import org.bouncycastle.pqc.legacy.crypto.gmss.util.GMSSUtil; -import org.bouncycastle.pqc.legacy.crypto.gmss.util.WinternitzOTSVerify; -import org.bouncycastle.pqc.legacy.crypto.gmss.util.WinternitzOTSignature; -import org.bouncycastle.util.Arrays; - -/** - * This class implements the GMSS signature scheme. - */ -public class GMSSSigner - implements MessageSigner -{ - - /** - * Instance of GMSSParameterSpec - */ - //private GMSSParameterSpec gmssParameterSpec; - - /** - * Instance of GMSSUtilities - */ - private GMSSUtil gmssUtil = new GMSSUtil(); - - - /** - * The raw GMSS public key - */ - private byte[] pubKeyBytes; - - /** - * Hash function for the construction of the authentication trees - */ - private Digest messDigestTrees; - - /** - * The length of the hash function output - */ - private int mdLength; - - /** - * The number of tree layers - */ - private int numLayer; - - /** - * The hash function used by the OTS - */ - private Digest messDigestOTS; - - /** - * An instance of the Winternitz one-time signature - */ - private WinternitzOTSignature ots; - - /** - * Array of strings containing the name of the hash function used by the OTS - * and the corresponding provider name - */ - private GMSSDigestProvider digestProvider; - - /** - * The current main tree and subtree indices - */ - private int[] index; - - /** - * Array of the authentication paths for the current trees of all layers - */ - private byte[][][] currentAuthPaths; - - /** - * The one-time signature of the roots of the current subtrees - */ - private byte[][] subtreeRootSig; - - - /** - * The GMSSParameterset - */ - private GMSSParameters gmssPS; - - /** - * The PRNG - */ - private GMSSRandom gmssRandom; - - GMSSKeyParameters key; - - // XXX needed? Source of randomness - private SecureRandom random; - - - /** - * The standard constructor tries to generate the MerkleTree Algorithm - * identifier with the corresponding OID. - * - * @param digest the digest to use - */ - // TODO - public GMSSSigner(GMSSDigestProvider digest) - { - digestProvider = digest; - messDigestTrees = digest.get(); - messDigestOTS = messDigestTrees; - mdLength = messDigestTrees.getDigestSize(); - gmssRandom = new GMSSRandom(messDigestTrees); - } - - public void init(boolean forSigning, - CipherParameters param) - { - - if (forSigning) - { - if (param instanceof ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - // XXX random needed? - this.random = rParam.getRandom(); - this.key = (GMSSPrivateKeyParameters)rParam.getParameters(); - initSign(); - - } - else - { - - this.random = CryptoServicesRegistrar.getSecureRandom(); - this.key = (GMSSPrivateKeyParameters)param; - initSign(); - } - } - else - { - this.key = (GMSSPublicKeyParameters)param; - initVerify(); - - } - - } - - - /** - * Initializes the signature algorithm for signing a message. - */ - private void initSign() - { - messDigestTrees.reset(); - // set private key and take from it ots key, auth, tree and key - // counter, rootSign - GMSSPrivateKeyParameters gmssPrivateKey = (GMSSPrivateKeyParameters)key; - - if (gmssPrivateKey.isUsed()) - { - throw new IllegalStateException("Private key already used"); - } - - // check if last signature has been generated - if (gmssPrivateKey.getIndex(0) >= gmssPrivateKey.getNumLeafs(0)) - { - throw new IllegalStateException("No more signatures can be generated"); - } - - // get Parameterset - this.gmssPS = gmssPrivateKey.getParameters(); - // get numLayer - this.numLayer = gmssPS.getNumOfLayers(); - - // get OTS Instance of lowest layer - byte[] seed = gmssPrivateKey.getCurrentSeeds()[numLayer - 1]; - byte[] OTSSeed = new byte[mdLength]; - byte[] dummy = new byte[mdLength]; - System.arraycopy(seed, 0, dummy, 0, mdLength); - OTSSeed = gmssRandom.nextSeed(dummy); // secureRandom.nextBytes(currentSeeds[currentSeeds.length-1]);secureRandom.nextBytes(OTSseed); - this.ots = new WinternitzOTSignature(OTSSeed, digestProvider.get(), gmssPS.getWinternitzParameter()[numLayer - 1]); - - byte[][][] helpCurrentAuthPaths = gmssPrivateKey.getCurrentAuthPaths(); - currentAuthPaths = new byte[numLayer][][]; - - // copy the main tree authentication path - for (int j = 0; j < numLayer; j++) - { - currentAuthPaths[j] = new byte[helpCurrentAuthPaths[j].length][mdLength]; - for (int i = 0; i < helpCurrentAuthPaths[j].length; i++) - { - System.arraycopy(helpCurrentAuthPaths[j][i], 0, currentAuthPaths[j][i], 0, mdLength); - } - } - - // copy index - index = new int[numLayer]; - System.arraycopy(gmssPrivateKey.getIndex(), 0, index, 0, numLayer); - - // copy subtreeRootSig - byte[] helpSubtreeRootSig; - subtreeRootSig = new byte[numLayer - 1][]; - for (int i = 0; i < numLayer - 1; i++) - { - helpSubtreeRootSig = gmssPrivateKey.getSubtreeRootSig(i); - subtreeRootSig[i] = new byte[helpSubtreeRootSig.length]; - System.arraycopy(helpSubtreeRootSig, 0, subtreeRootSig[i], 0, helpSubtreeRootSig.length); - } - - gmssPrivateKey.markUsed(); - } - - /** - * Signs a message. - * - * @return the signature. - */ - public byte[] generateSignature(byte[] message) - { - - byte[] otsSig = new byte[mdLength]; - byte[] authPathBytes; - byte[] indexBytes; - - otsSig = ots.getSignature(message); - - // get concatenated lowest layer tree authentication path - authPathBytes = gmssUtil.concatenateArray(currentAuthPaths[numLayer - 1]); - - // put lowest layer index into a byte array - indexBytes = gmssUtil.intToBytesLittleEndian(index[numLayer - 1]); - - // create first part of GMSS signature - byte[] gmssSigFirstPart = new byte[indexBytes.length + otsSig.length + authPathBytes.length]; - System.arraycopy(indexBytes, 0, gmssSigFirstPart, 0, indexBytes.length); - System.arraycopy(otsSig, 0, gmssSigFirstPart, indexBytes.length, otsSig.length); - System.arraycopy(authPathBytes, 0, gmssSigFirstPart, (indexBytes.length + otsSig.length), authPathBytes.length); - // --- end first part - - // --- next parts of the signature - // create initial array with length 0 for iteration - byte[] gmssSigNextPart = new byte[0]; - - for (int i = numLayer - 1 - 1; i >= 0; i--) - { - - // get concatenated next tree authentication path - authPathBytes = gmssUtil.concatenateArray(currentAuthPaths[i]); - - // put next tree index into a byte array - indexBytes = gmssUtil.intToBytesLittleEndian(index[i]); - - // create next part of GMSS signature - - // create help array and copy actual gmssSig into it - byte[] helpGmssSig = new byte[gmssSigNextPart.length]; - System.arraycopy(gmssSigNextPart, 0, helpGmssSig, 0, gmssSigNextPart.length); - // adjust length of gmssSigNextPart for adding next part - gmssSigNextPart = new byte[helpGmssSig.length + indexBytes.length + subtreeRootSig[i].length + authPathBytes.length]; - - // copy old data (help array) and new data in gmssSigNextPart - System.arraycopy(helpGmssSig, 0, gmssSigNextPart, 0, helpGmssSig.length); - System.arraycopy(indexBytes, 0, gmssSigNextPart, helpGmssSig.length, indexBytes.length); - System.arraycopy(subtreeRootSig[i], 0, gmssSigNextPart, (helpGmssSig.length + indexBytes.length), subtreeRootSig[i].length); - System.arraycopy(authPathBytes, 0, gmssSigNextPart, (helpGmssSig.length + indexBytes.length + subtreeRootSig[i].length), authPathBytes.length); - - } - // --- end next parts - - // concatenate the two parts of the GMSS signature - byte[] gmssSig = new byte[gmssSigFirstPart.length + gmssSigNextPart.length]; - System.arraycopy(gmssSigFirstPart, 0, gmssSig, 0, gmssSigFirstPart.length); - System.arraycopy(gmssSigNextPart, 0, gmssSig, gmssSigFirstPart.length, gmssSigNextPart.length); - - // return the GMSS signature - return gmssSig; - } - - /** - * Initializes the signature algorithm for verifying a signature. - */ - private void initVerify() - { - messDigestTrees.reset(); - - GMSSPublicKeyParameters gmssPublicKey = (GMSSPublicKeyParameters)key; - pubKeyBytes = gmssPublicKey.getPublicKey(); - gmssPS = gmssPublicKey.getParameters(); - // get numLayer - this.numLayer = gmssPS.getNumOfLayers(); - - - } - - /** - * This function verifies the signature of the message that has been - * updated, with the aid of the public key. - * - * @param message the message - * @param signature the signature associated with the message - * @return true if the signature has been verified, false otherwise. - */ - public boolean verifySignature(byte[] message, byte[] signature) - { - - boolean success = false; - // int halfSigLength = signature.length >>> 1; - messDigestOTS.reset(); - WinternitzOTSVerify otsVerify; - int otsSigLength; - - byte[] help = message; - - byte[] otsSig; - byte[] otsPublicKey; - byte[][] authPath; - byte[] dest; - int nextEntry = 0; - int index; - // Verify signature - - // --- begin with message = 'message that was signed' - // and then in each step message = subtree root - for (int j = numLayer - 1; j >= 0; j--) - { - otsVerify = new WinternitzOTSVerify(digestProvider.get(), gmssPS.getWinternitzParameter()[j]); - otsSigLength = otsVerify.getSignatureLength(); - - message = help; - // get the subtree index - index = gmssUtil.bytesToIntLittleEndian(signature, nextEntry); - - // 4 is the number of bytes in integer - nextEntry += 4; - - // get one-time signature - otsSig = new byte[otsSigLength]; - System.arraycopy(signature, nextEntry, otsSig, 0, otsSigLength); - nextEntry += otsSigLength; - - // compute public OTS key from the one-time signature - otsPublicKey = otsVerify.Verify(message, otsSig); - - // test if OTSsignature is correct - if (otsPublicKey == null) - { - // -DM System.err.println - System.err.println("OTS Public Key is null in GMSSSignature.verify"); - return false; - } - - // get authentication path from the signature - authPath = new byte[gmssPS.getHeightOfTrees()[j]][mdLength]; - for (int i = 0; i < authPath.length; i++) - { - System.arraycopy(signature, nextEntry, authPath[i], 0, mdLength); - nextEntry = nextEntry + mdLength; - } - - // compute the root of the subtree from the authentication path - help = new byte[mdLength]; - - help = otsPublicKey; - - int count = 1 << authPath.length; - count = count + index; - - for (int i = 0; i < authPath.length; i++) - { - dest = new byte[mdLength << 1]; - - if ((count % 2) == 0) - { - System.arraycopy(help, 0, dest, 0, mdLength); - System.arraycopy(authPath[i], 0, dest, mdLength, mdLength); - count = count / 2; - } - else - { - System.arraycopy(authPath[i], 0, dest, 0, mdLength); - System.arraycopy(help, 0, dest, mdLength, help.length); - count = (count - 1) / 2; - } - messDigestTrees.update(dest, 0, dest.length); - help = new byte[messDigestTrees.getDigestSize()]; - messDigestTrees.doFinal(help, 0); - } - } - - // now help contains the root of the maintree - - // test if help is equal to the GMSS public key - if (Arrays.areEqual(pubKeyBytes, help)) - { - success = true; - } - - return success; - } - - -} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSStateAwareSigner.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSStateAwareSigner.java deleted file mode 100644 index fc56581283..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSStateAwareSigner.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss; - -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.StateAwareMessageSigner; -import org.bouncycastle.util.Memoable; - -/** - * This class implements the GMSS signature scheme, but allows multiple signatures to be generated. - *

    - * Note: getUpdatedPrivateKey() needs to be called to fetch the current value of the usable private key. - *

    - */ -public class GMSSStateAwareSigner - implements StateAwareMessageSigner -{ - private final GMSSSigner gmssSigner; - - private GMSSPrivateKeyParameters key; - - public GMSSStateAwareSigner(final Digest digest) - { - if (!(digest instanceof Memoable)) - { - throw new IllegalArgumentException("digest must implement Memoable"); - } - - final Memoable dig = ((Memoable)digest).copy(); - gmssSigner = new GMSSSigner(new GMSSDigestProvider() - { - public Digest get() - { - return (Digest)dig.copy(); - } - }); - } - - public void init(boolean forSigning, CipherParameters param) - { - if (forSigning) - { - if (param instanceof ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.key = (GMSSPrivateKeyParameters)rParam.getParameters(); - } - else - { - this.key = (GMSSPrivateKeyParameters)param; - } - } - - gmssSigner.init(forSigning, param); - } - - public byte[] generateSignature(byte[] message) - { - if (key == null) - { - throw new IllegalStateException("signing key no longer usable"); - } - - byte[] sig = gmssSigner.generateSignature(message); - - key = key.nextKey(); - - return sig; - } - - public boolean verifySignature(byte[] message, byte[] signature) - { - return gmssSigner.verifySignature(message, signature); - } - - public AsymmetricKeyParameter getUpdatedPrivateKey() - { - AsymmetricKeyParameter k = key; - - key = null; - - return k; - } -} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSUtils.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSUtils.java deleted file mode 100644 index 1a29b54b09..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/GMSSUtils.java +++ /dev/null @@ -1,145 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss; - -import java.util.Enumeration; -import java.util.Vector; - -import org.bouncycastle.util.Arrays; - -class GMSSUtils -{ - 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; - } - - 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; - } - - 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; - } - - 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; - } - - 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; - } - - 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; - } - - 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; - } - - 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(); - for (Enumeration en = data[i].elements(); en.hasMoreElements();) - { - copy[i].addElement(en.nextElement()); - } - } - - return copy; - } - - 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; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/Treehash.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/Treehash.java deleted file mode 100644 index b9be9008c0..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/Treehash.java +++ /dev/null @@ -1,526 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss; - -import java.util.Vector; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.pqc.legacy.crypto.gmss.util.GMSSRandom; -import org.bouncycastle.util.Integers; -import org.bouncycastle.util.encoders.Hex; - - -/** - * This class implements a treehash instance for the Merkle tree traversal - * algorithm. The first node of the stack is stored in this instance itself, - * additional tail nodes are stored on a tailstack. - */ -public class Treehash -{ - - /** - * max height of current treehash instance. - */ - private int maxHeight; - - /** - * Vector element that stores the nodes on the stack - */ - private Vector tailStack; - - /** - * Vector element that stores the height of the nodes on the stack - */ - private Vector heightOfNodes; - - /** - * the first node is stored in the treehash instance itself, not on stack - */ - private byte[] firstNode; - - /** - * seedActive needed for the actual node - */ - private byte[] seedActive; - - /** - * the seed needed for the next re-initialization of the treehash instance - */ - private byte[] seedNext; - - /** - * number of nodes stored on the stack and belonging to this treehash - * instance - */ - private int tailLength; - - /** - * the height in the tree of the first node stored in treehash - */ - private int firstNodeHeight; - - /** - * true if treehash instance was already initialized, false otherwise - */ - private boolean isInitialized; - - /** - * true if the first node's height equals the maxHeight of the treehash - */ - private boolean isFinished; - - /** - * true if the nextSeed has been initialized with index 3*2^h needed for the - * seed scheduling - */ - private boolean seedInitialized; - - /** - * denotes the Message Digest used by the tree to create nodes - */ - private Digest messDigestTree; - - /** - * This constructor regenerates a prior treehash object - * - * @param name an array of strings, containing the name of the used hash - * function and PRNG and the name of the corresponding provider - * @param statByte status bytes - * @param statInt status ints - */ - public Treehash(Digest name, byte[][] statByte, int[] statInt) - { - this.messDigestTree = name; - - // decode statInt - this.maxHeight = statInt[0]; - this.tailLength = statInt[1]; - this.firstNodeHeight = statInt[2]; - - if (statInt[3] == 1) - { - this.isFinished = true; - } - else - { - this.isFinished = false; - } - if (statInt[4] == 1) - { - this.isInitialized = true; - } - else - { - this.isInitialized = false; - } - if (statInt[5] == 1) - { - this.seedInitialized = true; - } - else - { - this.seedInitialized = false; - } - - this.heightOfNodes = new Vector(); - for (int i = 0; i < tailLength; i++) - { - this.heightOfNodes.addElement(Integers.valueOf(statInt[6 + i])); - } - - // decode statByte - this.firstNode = statByte[0]; - this.seedActive = statByte[1]; - this.seedNext = statByte[2]; - - this.tailStack = new Vector(); - for (int i = 0; i < tailLength; i++) - { - this.tailStack.addElement(statByte[3 + i]); - } - } - - /** - * Constructor - * - * @param tailStack a vector element where the stack nodes are stored - * @param maxHeight maximal height of the treehash instance - * @param digest an array of strings, containing the name of the used hash - * function and PRNG and the name of the corresponding provider - */ - public Treehash(Vector tailStack, int maxHeight, Digest digest) - { - this.tailStack = tailStack; - this.maxHeight = maxHeight; - this.firstNode = null; - this.isInitialized = false; - this.isFinished = false; - this.seedInitialized = false; - this.messDigestTree = digest; - - this.seedNext = new byte[messDigestTree.getDigestSize()]; - this.seedActive = new byte[messDigestTree.getDigestSize()]; - } - - /** - * Method to initialize the seeds needed for the precomputation of right - * nodes. Should be initialized with index 3*2^i for treehash_i - * - * @param seedIn - */ - public void initializeSeed(byte[] seedIn) - { - System.arraycopy(seedIn, 0, this.seedNext, 0, this.messDigestTree - .getDigestSize()); - this.seedInitialized = true; - } - - /** - * initializes the treehash instance. The seeds must already have been - * initialized to work correctly. - */ - public void initialize() - { - if (!this.seedInitialized) - { - throw new IllegalStateException("Seed " + this.maxHeight + " not initialized"); - } - - this.heightOfNodes = new Vector(); - this.tailLength = 0; - this.firstNode = null; - this.firstNodeHeight = -1; - this.isInitialized = true; - System.arraycopy(this.seedNext, 0, this.seedActive, 0, messDigestTree - .getDigestSize()); - } - - /** - * Calculates one update of the treehash instance, i.e. creates a new leaf - * and hashes if possible - * - * @param gmssRandom an instance of the PRNG - * @param leaf The byte value of the leaf needed for the update - */ - public void update(GMSSRandom gmssRandom, byte[] leaf) - { - - if (this.isFinished) - { - // -DM System.err.println - System.err - .println("No more update possible for treehash instance!"); - return; - } - if (!this.isInitialized) - { - // -DM System.err.println - System.err - .println("Treehash instance not initialized before update"); - return; - } - - byte[] help = new byte[this.messDigestTree.getDigestSize()]; - int helpHeight = -1; - - gmssRandom.nextSeed(this.seedActive); - - // if treehash gets first update - if (this.firstNode == null) - { - this.firstNode = leaf; - this.firstNodeHeight = 0; - } - else - { - // store the new node in help array, do not push it on the stack - help = leaf; - helpHeight = 0; - - // hash the nodes on the stack if possible - while (this.tailLength > 0 - && helpHeight == ((Integer)heightOfNodes.lastElement()) - .intValue()) - { - // put top element of the stack and help node in array - // 'tobehashed' - // and hash them together, put result again in help array - byte[] toBeHashed = new byte[this.messDigestTree - .getDigestSize() << 1]; - - // pop element from stack - System.arraycopy(this.tailStack.lastElement(), 0, toBeHashed, - 0, this.messDigestTree.getDigestSize()); - this.tailStack.removeElementAt(this.tailStack.size() - 1); - this.heightOfNodes - .removeElementAt(this.heightOfNodes.size() - 1); - - System.arraycopy(help, 0, toBeHashed, this.messDigestTree - .getDigestSize(), this.messDigestTree - .getDigestSize()); - messDigestTree.update(toBeHashed, 0, toBeHashed.length); - help = new byte[messDigestTree.getDigestSize()]; - messDigestTree.doFinal(help, 0); - - // increase help height, stack was reduced by one element - helpHeight++; - this.tailLength--; - } - - // push the new node on the stack - this.tailStack.addElement(help); - this.heightOfNodes.addElement(Integers.valueOf(helpHeight)); - this.tailLength++; - - // finally check whether the top node on stack and the first node - // in treehash have same height. If so hash them together - // and store them in treehash - if (((Integer)heightOfNodes.lastElement()).intValue() == this.firstNodeHeight) - { - byte[] toBeHashed = new byte[this.messDigestTree - .getDigestSize() << 1]; - System.arraycopy(this.firstNode, 0, toBeHashed, 0, - this.messDigestTree.getDigestSize()); - - // pop element from tailStack and copy it into help2 array - System.arraycopy(this.tailStack.lastElement(), 0, toBeHashed, - this.messDigestTree.getDigestSize(), - this.messDigestTree.getDigestSize()); - this.tailStack.removeElementAt(this.tailStack.size() - 1); - this.heightOfNodes - .removeElementAt(this.heightOfNodes.size() - 1); - - // store new element in firstNode, stack is then empty - messDigestTree.update(toBeHashed, 0, toBeHashed.length); - this.firstNode = new byte[messDigestTree.getDigestSize()]; - messDigestTree.doFinal(this.firstNode, 0); - this.firstNodeHeight++; - - // empty the stack - this.tailLength = 0; - } - } - - // check if treehash instance is completed - if (this.firstNodeHeight == this.maxHeight) - { - this.isFinished = true; - } - } - - /** - * Destroys a treehash instance after the top node was taken for - * authentication path. - */ - public void destroy() - { - this.isInitialized = false; - this.isFinished = false; - this.firstNode = null; - this.tailLength = 0; - this.firstNodeHeight = -1; - } - - /** - * Returns the height of the lowest node stored either in treehash or on the - * stack. It must not be set to infinity (as mentioned in the paper) because - * this cases are considered in the computeAuthPaths method of - * JDKGMSSPrivateKey - * - * @return Height of the lowest node - */ - public int getLowestNodeHeight() - { - if (this.firstNode == null) - { - return this.maxHeight; - } - else if (this.tailLength == 0) - { - return this.firstNodeHeight; - } - else - { - return Math.min(this.firstNodeHeight, ((Integer)heightOfNodes - .lastElement()).intValue()); - } - } - - /** - * Returns the top node height - * - * @return Height of the first node, the top node - */ - public int getFirstNodeHeight() - { - if (firstNode == null) - { - return maxHeight; - } - return firstNodeHeight; - } - - /** - * Method to check whether the instance has been initialized or not - * - * @return true if treehash was already initialized - */ - public boolean wasInitialized() - { - return this.isInitialized; - } - - /** - * Method to check whether the instance has been finished or not - * - * @return true if treehash has reached its maximum height - */ - public boolean wasFinished() - { - return this.isFinished; - } - - /** - * returns the first node stored in treehash instance itself - * - * @return the first node stored in treehash instance itself - */ - public byte[] getFirstNode() - { - return this.firstNode; - } - - /** - * returns the active seed - * - * @return the active seed - */ - public byte[] getSeedActive() - { - return this.seedActive; - } - - /** - * This method sets the first node stored in the treehash instance itself - * - * @param hash - */ - public void setFirstNode(byte[] hash) - { - if (!this.isInitialized) - { - this.initialize(); - } - this.firstNode = hash; - this.firstNodeHeight = this.maxHeight; - this.isFinished = true; - } - - /** - * updates the nextSeed of this treehash instance one step needed for the - * schedulng of the seeds - * - * @param gmssRandom the prng used for the seeds - */ - public void updateNextSeed(GMSSRandom gmssRandom) - { - gmssRandom.nextSeed(seedNext); - } - - /** - * Returns the tailstack - * - * @return the tailstack - */ - public Vector getTailStack() - { - return this.tailStack; - } - - /** - * Returns the status byte array used by the GMSSPrivateKeyASN.1 class - * - * @return The status bytes - */ - public byte[][] getStatByte() - { - - byte[][] statByte = new byte[3 + tailLength][this.messDigestTree - .getDigestSize()]; - statByte[0] = firstNode; - statByte[1] = seedActive; - statByte[2] = seedNext; - for (int i = 0; i < tailLength; i++) - { - statByte[3 + i] = (byte[])tailStack.elementAt(i); - } - return statByte; - } - - /** - * Returns the status int array used by the GMSSPrivateKeyASN.1 class - * - * @return The status ints - */ - public int[] getStatInt() - { - - int[] statInt = new int[6 + tailLength]; - statInt[0] = maxHeight; - statInt[1] = tailLength; - statInt[2] = firstNodeHeight; - if (this.isFinished) - { - statInt[3] = 1; - } - else - { - statInt[3] = 0; - } - if (this.isInitialized) - { - statInt[4] = 1; - } - else - { - statInt[4] = 0; - } - if (this.seedInitialized) - { - statInt[5] = 1; - } - else - { - statInt[5] = 0; - } - for (int i = 0; i < tailLength; i++) - { - statInt[6 + i] = ((Integer)heightOfNodes.elementAt(i)).intValue(); - } - return statInt; - } - - /** - * returns a String representation of the treehash instance - */ - public String toString() - { - String out = "Treehash : "; - for (int i = 0; i < 6 + tailLength; i++) - { - out = out + this.getStatInt()[i] + " "; - } - for (int i = 0; i < 3 + tailLength; i++) - { - if (this.getStatByte()[i] != null) - { - out = out + new String(Hex.encode((this.getStatByte()[i]))) + " "; - } - else - { - out = out + "null "; - } - } - out = out + " " + this.messDigestTree.getDigestSize(); - return out; - } - -} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/util/GMSSRandom.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/util/GMSSRandom.java deleted file mode 100644 index 0ebcd741d1..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/util/GMSSRandom.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss.util; - -import org.bouncycastle.crypto.Digest; - -/** - * This class provides a PRNG for GMSS - */ -public class GMSSRandom -{ - /** - * Hash function for the construction of the authentication trees - */ - private Digest messDigestTree; - - /** - * Constructor - * - * @param messDigestTree2 - */ - public GMSSRandom(Digest messDigestTree2) - { - - this.messDigestTree = messDigestTree2; - } - - /** - * computes the next seed value, returns a random byte array and sets - * outseed to the next value - * - * @param outseed byte array in which ((1 + SEEDin +RAND) mod 2^n) will be - * stored - * @return byte array of H(SEEDin) - */ - public byte[] nextSeed(byte[] outseed) - { - // RAND <-- H(SEEDin) - byte[] rand = new byte[outseed.length]; - messDigestTree.update(outseed, 0, outseed.length); - rand = new byte[messDigestTree.getDigestSize()]; - messDigestTree.doFinal(rand, 0); - - // SEEDout <-- (1 + SEEDin +RAND) mod 2^n - addByteArrays(outseed, rand); - addOne(outseed); - - // System.arraycopy(outseed, 0, outseed, 0, outseed.length); - - return rand; - } - - private void addByteArrays(byte[] a, byte[] b) - { - - byte overflow = 0; - int temp; - - for (int i = 0; i < a.length; i++) - { - temp = (0xFF & a[i]) + (0xFF & b[i]) + overflow; - a[i] = (byte)temp; - overflow = (byte)(temp >> 8); - } - } - - private void addOne(byte[] a) - { - - byte overflow = 1; - int temp; - - for (int i = 0; i < a.length; i++) - { - temp = (0xFF & a[i]) + overflow; - a[i] = (byte)temp; - overflow = (byte)(temp >> 8); - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/util/GMSSUtil.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/util/GMSSUtil.java deleted file mode 100644 index d8c01c8e86..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/util/GMSSUtil.java +++ /dev/null @@ -1,155 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss.util; - -/** - * This class provides several methods that are required by the GMSS classes. - */ -public class GMSSUtil -{ - /** - * Converts a 32 bit integer into a byte array beginning at - * offset (little-endian representation) - * - * @param value the integer to convert - */ - public byte[] intToBytesLittleEndian(int value) - { - byte[] bytes = new byte[4]; - - bytes[0] = (byte)((value) & 0xff); - bytes[1] = (byte)((value >> 8) & 0xff); - bytes[2] = (byte)((value >> 16) & 0xff); - bytes[3] = (byte)((value >> 24) & 0xff); - return bytes; - } - - /** - * Converts a byte array beginning at offset into a 32 bit - * integer (little-endian representation) - * - * @param bytes the byte array - * @return The resulting integer - */ - public int bytesToIntLittleEndian(byte[] bytes) - { - - return ((bytes[0] & 0xff)) | ((bytes[1] & 0xff) << 8) - | ((bytes[2] & 0xff) << 16) | ((bytes[3] & 0xff)) << 24; - } - - /** - * Converts a byte array beginning at offset into a 32 bit - * integer (little-endian representation) - * - * @param bytes the byte array - * @param offset the integer offset into the byte array - * @return The resulting integer - */ - public int bytesToIntLittleEndian(byte[] bytes, int offset) - { - return ((bytes[offset++] & 0xff)) | ((bytes[offset++] & 0xff) << 8) - | ((bytes[offset++] & 0xff) << 16) - | ((bytes[offset] & 0xff)) << 24; - } - - /** - * This method concatenates a 2-dimensional byte array into a 1-dimensional - * byte array - * - * @param arraycp a 2-dimensional byte array. - * @return 1-dimensional byte array with concatenated input array - */ - public byte[] concatenateArray(byte[][] arraycp) - { - byte[] dest = new byte[arraycp.length * arraycp[0].length]; - int indx = 0; - for (int i = 0; i < arraycp.length; i++) - { - System.arraycopy(arraycp[i], 0, dest, indx, arraycp[i].length); - indx = indx + arraycp[i].length; - } - return dest; - } - - /** - * This method prints the values of a 2-dimensional byte array - * - * @param text a String - * @param array a 2-dimensional byte array - */ - public void printArray(String text, byte[][] array) - { - // -DM System.out.println - System.out.println(text); - int counter = 0; - for (int i = 0; i < array.length; i++) - { - for (int j = 0; j < array[0].length; j++) - { - // -DM System.out.println - System.out.println(counter + "; " + array[i][j]); - counter++; - } - } - } - - /** - * This method prints the values of a 1-dimensional byte array - * - * @param text a String - * @param array a 1-dimensional byte array. - */ - public void printArray(String text, byte[] array) - { - // -DM System.out.println - System.out.println(text); - int counter = 0; - for (int i = 0; i < array.length; i++) - { - // -DM System.out.println - System.out.println(counter + "; " + array[i]); - counter++; - } - } - - /** - * This method tests if an integer is a power of 2. - * - * @param testValue an integer - * @return TRUE if testValue is a power of 2, - * FALSE otherwise - */ - public boolean testPowerOfTwo(int testValue) - { - int a = 1; - while (a < testValue) - { - a <<= 1; - } - if (testValue == a) - { - return true; - } - - return false; - } - - /** - * This method returns the least integer that is greater or equal to the - * logarithm to the base 2 of an integer intValue. - * - * @param intValue an integer - * @return The least integer greater or equal to the logarithm to the base 2 - * of intValue - */ - public int getLog(int intValue) - { - int log = 1; - int i = 2; - while (i < intValue) - { - i <<= 1; - log++; - } - return log; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/util/WinternitzOTSVerify.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/util/WinternitzOTSVerify.java deleted file mode 100644 index fcc466aeef..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/util/WinternitzOTSVerify.java +++ /dev/null @@ -1,300 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss.util; - -import org.bouncycastle.crypto.Digest; - -/** - * This class implements signature verification of the Winternitz one-time - * signature scheme (OTSS), described in C.Dods, N.P. Smart, and M. Stam, "Hash - * Based Digital Signature Schemes", LNCS 3796, pages 96–115, 2005. The - * class is used by the GMSS classes. - */ -public class WinternitzOTSVerify -{ - private Digest messDigestOTS; - - private int mdsize; - - /** - * The Winternitz parameter - */ - private int w; - - /** - * The constructor - * - * @param digest the name of the hash function used by the OTS and the provider - * name of the hash function - * @param w the Winternitz parameter - */ - public WinternitzOTSVerify(Digest digest, int w) - { - this.w = w; - - messDigestOTS = digest; - mdsize = messDigestOTS.getDigestSize(); - } - - /** - * @return The length of the one-time signature - */ - public int getSignatureLength() - { - int mdsize = messDigestOTS.getDigestSize(); - int size = ((mdsize << 3) + (w - 1)) / w; - int logs = getLog((size << w) + 1); - size += (logs + w - 1) / w; - - return mdsize * size; - } - - /** - * This method computes the public OTS key from the one-time signature of a - * message. This is *NOT* a complete OTS signature verification, but it - * suffices for usage with CMSS. - * - * @param message the message - * @param signature the one-time signature - * @return The public OTS key - */ - public byte[] Verify(byte[] message, byte[] signature) - { - byte[] hash = new byte[mdsize]; // hash of message m - - // create hash of message m - messDigestOTS.update(message, 0, message.length); - messDigestOTS.doFinal(hash, 0); - - int size = ((mdsize << 3) + (w - 1)) / w; - int logs = getLog((size << w) + 1); - int keysize = size + (logs + w - 1) / w; - - int testKeySize = mdsize * keysize; - - if (testKeySize != signature.length) - { - return null; - } - - byte[] testKey = new byte[testKeySize]; - - int c = 0; - int counter = 0; - int test; - - if (8 % w == 0) - { - int d = 8 / w; - int k = (1 << w) - 1; - - // verify signature - for (int i = 0; i < hash.length; i++) - { - for (int j = 0; j < d; j++) - { - test = hash[i] & k; - c += test; - hashSignatureBlock(signature, counter * mdsize, k - test, testKey, counter * mdsize); - hash[i] = (byte)(hash[i] >>> w); - counter++; - } - } - - c = (size << w) - c; - for (int i = 0; i < logs; i += w) - { - test = c & k; - hashSignatureBlock(signature, counter * mdsize, k - test, testKey, counter * mdsize); - c >>>= w; - counter++; - } - } - else if (w < 8) - { - int d = mdsize / w; - int k = (1 << w) - 1; - long big8; - int ii = 0; - // create signature - // first d*w bytes of hash - for (int i = 0; i < d; i++) - { - big8 = 0; - for (int j = 0; j < w; j++) - { - big8 ^= (hash[ii] & 0xff) << (j << 3); - ii++; - } - for (int j = 0; j < 8; j++) - { - test = (int)(big8 & k); - c += test; - hashSignatureBlock(signature, counter * mdsize, k - test, testKey, counter * mdsize); - big8 >>>= w; - counter++; - } - } - // rest of hash - d = mdsize % w; - big8 = 0; - for (int j = 0; j < d; j++) - { - big8 ^= (hash[ii] & 0xff) << (j << 3); - ii++; - } - d <<= 3; - for (int j = 0; j < d; j += w) - { - test = (int)(big8 & k); - c += test; - hashSignatureBlock(signature, counter * mdsize, k - test, testKey, counter * mdsize); - big8 >>>= w; - counter++; - } - - // check bytes - c = (size << w) - c; - for (int i = 0; i < logs; i += w) - { - test = c & k; - hashSignatureBlock(signature, counter * mdsize, k - test, testKey, counter * mdsize); - c >>>= w; - counter++; - } - }// end if(w<8) - else if (w < 57) - { - int d = (mdsize << 3) - w; - int k = (1 << w) - 1; - byte[] hlp = new byte[mdsize]; - long big8, test8; - int r = 0; - int s, f, rest, ii; - // create signature - // first a*w bits of hash where a*w <= 8*mdsize < (a+1)*w - while (r <= d) - { - s = r >>> 3; - rest = r % 8; - r += w; - f = (r + 7) >>> 3; - big8 = 0; - ii = 0; - for (int j = s; j < f; j++) - { - big8 ^= (hash[j] & 0xff) << (ii << 3); - ii++; - } - - big8 >>>= rest; - test8 = (big8 & k); - c += test8; - - System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize); - - while (test8 < k) - { - messDigestOTS.update(hlp, 0, hlp.length); - messDigestOTS.doFinal(hlp, 0); - test8++; - } - - System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize); - counter++; - - } - // rest of hash - s = r >>> 3; - if (s < mdsize) - { - rest = r % 8; - big8 = 0; - ii = 0; - for (int j = s; j < mdsize; j++) - { - big8 ^= (hash[j] & 0xff) << (ii << 3); - ii++; - } - - big8 >>>= rest; - test8 = (big8 & k); - c += test8; - - System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize); - - while (test8 < k) - { - messDigestOTS.update(hlp, 0, hlp.length); - messDigestOTS.doFinal(hlp, 0); - test8++; - } - - System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize); - counter++; - } - // check bytes - c = (size << w) - c; - for (int i = 0; i < logs; i += w) - { - test8 = (c & k); - - System.arraycopy(signature, counter * mdsize, hlp, 0, mdsize); - - while (test8 < k) - { - messDigestOTS.update(hlp, 0, hlp.length); - messDigestOTS.doFinal(hlp, 0); - test8++; - } - - System.arraycopy(hlp, 0, testKey, counter * mdsize, mdsize); - c >>>= w; - counter++; - } - }// end if(w<57) - - messDigestOTS.update(testKey, 0, testKey.length); - - byte[] TKey = new byte[mdsize]; - messDigestOTS.doFinal(TKey, 0); - return TKey; - } - - /** - * This method returns the least integer that is greater or equal to the - * logarithm to the base 2 of an integer intValue. - * - * @param intValue an integer - * @return The least integer greater or equal to the logarithm to the base - * 256 of intValue - */ - public int getLog(int intValue) - { - int log = 1; - int i = 2; - while (i < intValue) - { - i <<= 1; - log++; - } - return log; - } - - private void hashSignatureBlock(byte[] sig, int sigOff, int rounds, byte[] buf, int bufOff) - { - if (rounds < 1) - { - System.arraycopy(sig, sigOff, buf, bufOff, mdsize); - } - else - { - messDigestOTS.update(sig, sigOff, mdsize); - messDigestOTS.doFinal(buf, bufOff); - - while (--rounds > 0) - { - messDigestOTS.update(buf, bufOff, mdsize); - messDigestOTS.doFinal(buf, bufOff); - } - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/util/WinternitzOTSignature.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/util/WinternitzOTSignature.java deleted file mode 100644 index 49933d520e..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/gmss/util/WinternitzOTSignature.java +++ /dev/null @@ -1,347 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.gmss.util; - -import org.bouncycastle.crypto.Digest; - -/** - * This class implements key pair generation and signature generation of the - * Winternitz one-time signature scheme (OTSS), described in C.Dods, N.P. Smart, - * and M. Stam, "Hash Based Digital Signature Schemes", LNCS 3796, pages - * 96–115, 2005. The class is used by the GMSS classes. - */ - -public class WinternitzOTSignature -{ - - /** - * The hash function used by the OTS - */ - private Digest messDigestOTS; - - /** - * The length of the message digest and private key - */ - private int mdsize, keysize; - - /** - * An array of strings, containing the name of the used hash function, the - * name of the PRGN and the names of the corresponding providers - */ - // private String[] name = new String[2]; - /** - * The private key - */ - private byte[][] privateKeyOTS; - - /** - * The Winternitz parameter - */ - private int w; - - /** - * The source of randomness for OTS private key generation - */ - private GMSSRandom gmssRandom; - - /** - * Sizes of the message and the checksum, both - */ - private int messagesize, checksumsize; - - /** - * The constructor generates an OTS key pair, using seed0 and - * the PRNG - * - * @param seed0 the seed for the PRGN - * @param digest an array of strings, containing the name of the used hash - * function, the name of the PRGN and the names of the - * corresponding providers - * @param w the Winternitz parameter - */ - public WinternitzOTSignature(byte[] seed0, Digest digest, int w) - { - this.w = w; - - messDigestOTS = digest; - - gmssRandom = new GMSSRandom(messDigestOTS); - - // calulate keysize for private and public key and also the help - // array - - mdsize = messDigestOTS.getDigestSize(); - messagesize = ((mdsize << 3) + w - 1) / w; - - checksumsize = getLog((messagesize << w) + 1); - keysize = messagesize + (checksumsize + w - 1) / w; - - // define the private key messagesize - privateKeyOTS = new byte[keysize][]; - - // gmssRandom.setSeed(seed0); - byte[] dummy = new byte[mdsize]; - System.arraycopy(seed0, 0, dummy, 0, dummy.length); - - // generate random bytes and - // assign them to the private key - for (int i = 0; i < keysize; i++) - { - privateKeyOTS[i] = gmssRandom.nextSeed(dummy); - } - } - - /** - * @return The private OTS key - */ - public byte[][] getPrivateKey() - { - return privateKeyOTS; - } - - /** - * @return The public OTS key - */ - public byte[] getPublicKey() - { - byte[] buf = new byte[keysize * mdsize]; - - int pos = 0; - int rounds = (1 << w) - 1; - - for (int i = 0; i < keysize; i++) - { - // hash w-1 time the private key and assign it to the public key - hashPrivateKeyBlock(i, rounds, buf, pos); - pos += mdsize; - } - - messDigestOTS.update(buf, 0, buf.length); - - byte[] tmp = new byte[mdsize]; - messDigestOTS.doFinal(tmp, 0); - return tmp; - } - - /** - * @return The one-time signature of the message, generated with the private - * key - */ - public byte[] getSignature(byte[] message) - { - byte[] sign = new byte[keysize * mdsize]; - // byte [] message; // message m as input - byte[] hash = new byte[mdsize]; // hash of message m - int counter = 0; - int c = 0; - int test = 0; - // create hash of message m - messDigestOTS.update(message, 0, message.length); - messDigestOTS.doFinal(hash, 0); - - if (8 % w == 0) - { - int d = 8 / w; - int k = (1 << w) - 1; - - // create signature - for (int i = 0; i < hash.length; i++) - { - for (int j = 0; j < d; j++) - { - test = hash[i] & k; - c += test; - hashPrivateKeyBlock(counter, test, sign, counter * mdsize); - hash[i] = (byte)(hash[i] >>> w); - counter++; - } - } - - c = (messagesize << w) - c; - for (int i = 0; i < checksumsize; i += w) - { - test = c & k; - hashPrivateKeyBlock(counter, test, sign, counter * mdsize); - c >>>= w; - counter++; - } - } - else if (w < 8) - { - int d = mdsize / w; - int k = (1 << w) - 1; - long big8; - int ii = 0; - // create signature - // first d*w bytes of hash - for (int i = 0; i < d; i++) - { - big8 = 0; - for (int j = 0; j < w; j++) - { - big8 ^= (hash[ii] & 0xff) << (j << 3); - ii++; - } - for (int j = 0; j < 8; j++) - { - test = (int)big8 & k; - c += test; - hashPrivateKeyBlock(counter, test, sign, counter * mdsize); - big8 >>>= w; - counter++; - } - } - // rest of hash - d = mdsize % w; - big8 = 0; - for (int j = 0; j < d; j++) - { - big8 ^= (hash[ii] & 0xff) << (j << 3); - ii++; - } - d <<= 3; - for (int j = 0; j < d; j += w) - { - test = (int)big8 & k; - c += test; - hashPrivateKeyBlock(counter, test, sign, counter * mdsize); - big8 >>>= w; - counter++; - } - - // check bytes - c = (messagesize << w) - c; - for (int i = 0; i < checksumsize; i += w) - { - test = c & k; - hashPrivateKeyBlock(counter, test, sign, counter * mdsize); - c >>>= w; - counter++; - } - }// end if(w<8) - else if (w < 57) - { - int d = (mdsize << 3) - w; - int k = (1 << w) - 1; - byte[] hlp = new byte[mdsize]; - long big8, test8; - int r = 0; - int s, f, rest, ii; - // create signature - // first a*w bits of hash where a*w <= 8*mdsize < (a+1)*w - while (r <= d) - { - s = r >>> 3; - rest = r % 8; - r += w; - f = (r + 7) >>> 3; - big8 = 0; - ii = 0; - for (int j = s; j < f; j++) - { - big8 ^= (hash[j] & 0xff) << (ii << 3); - ii++; - } - - big8 >>>= rest; - test8 = (big8 & k); - c += test8; - - System.arraycopy(privateKeyOTS[counter], 0, hlp, 0, mdsize); - while (test8 > 0) - { - messDigestOTS.update(hlp, 0, hlp.length); - messDigestOTS.doFinal(hlp, 0); - test8--; - } - System.arraycopy(hlp, 0, sign, counter * mdsize, mdsize); - counter++; - - } - // rest of hash - s = r >>> 3; - if (s < mdsize) - { - rest = r % 8; - big8 = 0; - ii = 0; - for (int j = s; j < mdsize; j++) - { - big8 ^= (hash[j] & 0xff) << (ii << 3); - ii++; - } - - big8 >>>= rest; - test8 = (big8 & k); - c += test8; - - System.arraycopy(privateKeyOTS[counter], 0, hlp, 0, mdsize); - while (test8 > 0) - { - messDigestOTS.update(hlp, 0, hlp.length); - messDigestOTS.doFinal(hlp, 0); - test8--; - } - System.arraycopy(hlp, 0, sign, counter * mdsize, mdsize); - counter++; - } - // check bytes - c = (messagesize << w) - c; - for (int i = 0; i < checksumsize; i += w) - { - test8 = (c & k); - - System.arraycopy(privateKeyOTS[counter], 0, hlp, 0, mdsize); - - while (test8 > 0) - { - messDigestOTS.update(hlp, 0, hlp.length); - messDigestOTS.doFinal(hlp, 0); - test8--; - } - System.arraycopy(hlp, 0, sign, counter * mdsize, mdsize); - c >>>= w; - counter++; - } - }// end if(w<57) - - return sign; - } - - /** - * This method returns the least integer that is greater or equal to the - * logarithm to the base 2 of an integer intValue. - * - * @param intValue an integer - * @return The least integer greater or equal to the logarithm to the base 2 - * of intValue - */ - public int getLog(int intValue) - { - int log = 1; - int i = 2; - while (i < intValue) - { - i <<= 1; - log++; - } - return log; - } - - private void hashPrivateKeyBlock(int index, int rounds, byte[] buf, int off) - { - if (rounds < 1) - { - System.arraycopy(privateKeyOTS[index], 0, buf, off, mdsize); - } - else - { - messDigestOTS.update(privateKeyOTS[index], 0, mdsize); - messDigestOTS.doFinal(buf, off); - - while (--rounds > 0) - { - messDigestOTS.update(buf, off, mdsize); - messDigestOTS.doFinal(buf, off); - } - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/Conversions.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/Conversions.java deleted file mode 100644 index d67600cb6e..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/Conversions.java +++ /dev/null @@ -1,236 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -import java.math.BigInteger; - -import org.bouncycastle.pqc.legacy.math.linearalgebra.BigIntUtils; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Vector; -import org.bouncycastle.pqc.legacy.math.linearalgebra.IntegerFunctions; - - -/** - * Provides methods for CCA2-Secure Conversions of McEliece PKCS - */ -final class Conversions -{ - private static final BigInteger ZERO = BigInteger.valueOf(0); - private static final BigInteger ONE = BigInteger.valueOf(1); - - /** - * Default constructor (private). - */ - private Conversions() - { - } - - /** - * Encode a number between 0 and (n|t) (binomial coefficient) into a binary - * vector of length n with weight t. The number is given as a byte array. - * Only the first s bits are used, where s = floor[log(n|t)]. - * - * @param n integer - * @param t integer - * @param m the message as a byte array - * @return the encoded message as {@link GF2Vector} - */ - public static GF2Vector encode(final int n, final int t, final byte[] m) - { - if (n < t) - { - throw new IllegalArgumentException("n < t"); - } - - // compute the binomial c = (n|t) - BigInteger c = IntegerFunctions.binomial(n, t); - // get the number encoded in m - BigInteger i = new BigInteger(1, m); - // compare - if (i.compareTo(c) >= 0) - { - throw new IllegalArgumentException("Encoded number too large."); - } - - GF2Vector result = new GF2Vector(n); - - int nn = n; - int tt = t; - for (int j = 0; j < n; j++) - { - c = c.multiply(BigInteger.valueOf(nn - tt)).divide( - BigInteger.valueOf(nn)); - nn--; - if (c.compareTo(i) <= 0) - { - result.setBit(j); - i = i.subtract(c); - tt--; - if (nn == tt) - { - c = ONE; - } - else - { - c = (c.multiply(BigInteger.valueOf(tt + 1))) - .divide(BigInteger.valueOf(nn - tt)); - } - } - } - - return result; - } - - /** - * Decode a binary vector of length n and weight t into a number between 0 - * and (n|t) (binomial coefficient). The result is given as a byte array of - * length floor[(s+7)/8], where s = floor[log(n|t)]. - * - * @param n integer - * @param t integer - * @param vec the binary vector - * @return the decoded vector as a byte array - */ - public static byte[] decode(int n, int t, GF2Vector vec) - { - if ((vec.getLength() != n) || (vec.getHammingWeight() != t)) - { - throw new IllegalArgumentException( - "vector has wrong length or hamming weight"); - } - int[] vecArray = vec.getVecArray(); - - BigInteger bc = IntegerFunctions.binomial(n, t); - BigInteger d = ZERO; - int nn = n; - int tt = t; - for (int i = 0; i < n; i++) - { - bc = bc.multiply(BigInteger.valueOf(nn - tt)).divide( - BigInteger.valueOf(nn)); - nn--; - - int q = i >> 5; - int e = vecArray[q] & (1 << (i & 0x1f)); - if (e != 0) - { - d = d.add(bc); - tt--; - if (nn == tt) - { - bc = ONE; - } - else - { - bc = bc.multiply(BigInteger.valueOf(tt + 1)).divide( - BigInteger.valueOf(nn - tt)); - } - - } - } - - return BigIntUtils.toMinimalByteArray(d); - } - - /** - * Compute a message representative of a message given as a vector of length - * n bit and of hamming weight t. The result is a - * byte array of length (s+7)/8, where - * s = floor[log(n|t)]. - * - * @param n integer - * @param t integer - * @param m the message vector as a byte array - * @return a message representative for m - */ - public static byte[] signConversion(int n, int t, byte[] m) - { - if (n < t) - { - throw new IllegalArgumentException("n < t"); - } - - BigInteger bc = IntegerFunctions.binomial(n, t); - // finds s = floor[log(binomial(n,t))] - int s = bc.bitLength() - 1; - // s = sq*8 + sr; - int sq = s >> 3; - int sr = s & 7; - if (sr == 0) - { - sq--; - sr = 8; - } - - // n = nq*8+nr; - int nq = n >> 3; - int nr = n & 7; - if (nr == 0) - { - nq--; - nr = 8; - } - // take s bit from m - byte[] data = new byte[nq + 1]; - if (m.length < data.length) - { - System.arraycopy(m, 0, data, 0, m.length); - for (int i = m.length; i < data.length; i++) - { - data[i] = 0; - } - } - else - { - System.arraycopy(m, 0, data, 0, nq); - int h = (1 << nr) - 1; - data[nq] = (byte)(h & m[nq]); - } - - BigInteger d = ZERO; - int nn = n; - int tt = t; - for (int i = 0; i < n; i++) - { - bc = (bc.multiply(new BigInteger(Integer.toString(nn - tt)))) - .divide(new BigInteger(Integer.toString(nn))); - nn--; - - int q = i >>> 3; - int r = i & 7; - r = 1 << r; - byte e = (byte)(r & data[q]); - if (e != 0) - { - d = d.add(bc); - tt--; - if (nn == tt) - { - bc = ONE; - } - else - { - bc = (bc - .multiply(new BigInteger(Integer.toString(tt + 1)))) - .divide(new BigInteger(Integer.toString(nn - tt))); - } - } - } - - byte[] result = new byte[sq + 1]; - byte[] help = d.toByteArray(); - if (help.length < result.length) - { - System.arraycopy(help, 0, result, 0, help.length); - for (int i = help.length; i < result.length; i++) - { - result[i] = 0; - } - } - else - { - System.arraycopy(help, 0, result, 0, sq); - result[sq] = (byte)(((1 << sr) - 1) & help[sq]); - } - - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2KeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2KeyGenerationParameters.java deleted file mode 100644 index e5d6738d63..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2KeyGenerationParameters.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.KeyGenerationParameters; - -public class McElieceCCA2KeyGenerationParameters - extends KeyGenerationParameters -{ - private McElieceCCA2Parameters params; - - public McElieceCCA2KeyGenerationParameters( - SecureRandom random, - McElieceCCA2Parameters params) - { - // XXX key size? - super(random, 128); - this.params = params; - } - - public McElieceCCA2Parameters getParameters() - { - return params; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2KeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2KeyPairGenerator.java deleted file mode 100644 index d3c960537e..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2KeyPairGenerator.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GoppaCode; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GoppaCode.MaMaPe; -import org.bouncycastle.pqc.legacy.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialGF2mSmallM; - - -/** - * This class implements key pair generation of the McEliece Public Key - * Cryptosystem (McEliecePKC). - */ -public class McElieceCCA2KeyPairGenerator - implements AsymmetricCipherKeyPairGenerator -{ - - - /** - * The OID of the algorithm. - */ - public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2"; - - private McElieceCCA2KeyGenerationParameters mcElieceCCA2Params; - - // the extension degree of the finite field GF(2^m) - private int m; - - // the length of the code - private int n; - - // the error correction capability - private int t; - - // the field polynomial - private int fieldPoly; - - // the source of randomness - private SecureRandom random; - - // flag indicating whether the key pair generator has been initialized - private boolean initialized = false; - - /** - * Default initialization of the key pair generator. - */ - private void initializeDefault() - { - McElieceCCA2KeyGenerationParameters mcCCA2Params = new McElieceCCA2KeyGenerationParameters(null, new McElieceCCA2Parameters()); - init(mcCCA2Params); - } - - // TODO - public void init( - KeyGenerationParameters param) - { - this.mcElieceCCA2Params = (McElieceCCA2KeyGenerationParameters)param; - - // set source of randomness - this.random = param.getRandom(); - - this.m = this.mcElieceCCA2Params.getParameters().getM(); - this.n = this.mcElieceCCA2Params.getParameters().getN(); - this.t = this.mcElieceCCA2Params.getParameters().getT(); - this.fieldPoly = this.mcElieceCCA2Params.getParameters().getFieldPoly(); - this.initialized = true; - } - - - public AsymmetricCipherKeyPair generateKeyPair() - { - - if (!initialized) - { - initializeDefault(); - } - - // finite field GF(2^m) - GF2mField field = new GF2mField(m, fieldPoly); - - // irreducible Goppa polynomial - PolynomialGF2mSmallM gp = new PolynomialGF2mSmallM(field, t, - PolynomialGF2mSmallM.RANDOM_IRREDUCIBLE_POLYNOMIAL, random); - - // generate canonical check matrix - GF2Matrix h = GoppaCode.createCanonicalCheckMatrix(field, gp); - - // compute short systematic form of check matrix - MaMaPe mmp = GoppaCode.computeSystematicForm(h, random); - GF2Matrix shortH = mmp.getSecondMatrix(); - Permutation p = mmp.getPermutation(); - - // compute short systematic form of generator matrix - GF2Matrix shortG = (GF2Matrix)shortH.computeTranspose(); - - // obtain number of rows of G (= dimension of the code) - int k = shortG.getNumRows(); - - // generate keys - 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/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2Parameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2Parameters.java deleted file mode 100644 index e0fb8c6573..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2Parameters.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -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 McElieceCCA2Parameters(String digest) - { - this(DEFAULT_M, DEFAULT_T, digest); - } - - /** - * Constructor. - * - * @param keysize the length of a Goppa code - * @throws IllegalArgumentException if keysize < 1. - */ - public McElieceCCA2Parameters(int keysize) - { - this(keysize, "SHA-256"); - } - - /** - * Constructor. - * - * @param keysize the length of a Goppa code - * @param digest CCA2 mode digest - * @throws IllegalArgumentException if keysize < 1. - */ - public McElieceCCA2Parameters(int keysize, String digest) - { - 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 m < 1 or m > 32 or - * t < 0 or t > n. - */ - public McElieceCCA2Parameters(int m, int t) - { - this(m, t, "SHA-256"); - } - - /** - * Constructor. - * - * @param m degree of the finite field GF(2^m) - * @param t error correction capability of the code - * @throws IllegalArgumentException if m < 1 or m > 32 or - * t < 0 or t > n. - */ - public McElieceCCA2Parameters(int m, int t, String digest) - { - super(m, t); - 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 m < 1 or m > 32 or - * t < 0 or t > n or - * poly is not an irreducible field polynomial. - */ - public McElieceCCA2Parameters(int m, int t, int poly) - { - 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 m < 1 or m > 32 or - * t < 0 or t > n or - * poly 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/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2Primitives.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2Primitives.java deleted file mode 100644 index 2096f992ed..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2Primitives.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Vector; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GoppaCode; -import org.bouncycastle.pqc.legacy.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialGF2mSmallM; -import org.bouncycastle.pqc.legacy.math.linearalgebra.Vector; - -/** - * Core operations for the CCA-secure variants of McEliece. - */ -final class McElieceCCA2Primitives -{ - - /** - * Default constructor (private). - */ - private McElieceCCA2Primitives() - { - } - - /** - * The McEliece encryption primitive. - * - * @param pubKey the public key - * @param m the message vector - * @param z the error vector - * @return m*G + z - */ - - - public static GF2Vector encryptionPrimitive(McElieceCCA2PublicKeyParameters pubKey, - GF2Vector m, GF2Vector z) - { - - GF2Matrix matrixG = pubKey.getG(); - Vector mG = matrixG.leftMultiplyLeftCompactForm(m); - return (GF2Vector)mG.add(z); - } - - /** - * The McEliece decryption primitive. - * - * @param privKey the private key - * @param c the ciphertext vector c = m*G + z - * @return the message vector m and the error vector z - */ - public static GF2Vector[] decryptionPrimitive( - McElieceCCA2PrivateKeyParameters privKey, GF2Vector c) - { - - // obtain values from private key - int k = privKey.getK(); - Permutation p = privKey.getP(); - GF2mField field = privKey.getField(); - PolynomialGF2mSmallM gp = privKey.getGoppaPoly(); - GF2Matrix h = privKey.getH(); - PolynomialGF2mSmallM[] q = privKey.getQInv(); - - // compute inverse permutation P^-1 - Permutation pInv = p.computeInverse(); - - // multiply c with permutation P^-1 - GF2Vector cPInv = (GF2Vector)c.multiply(pInv); - - // compute syndrome of cP^-1 - GF2Vector syndVec = (GF2Vector)h.rightMultiply(cPInv); - - // decode syndrome - GF2Vector errors = GoppaCode.syndromeDecode(syndVec, field, gp, q); - GF2Vector mG = (GF2Vector)cPInv.add(errors); - - // multiply codeword and error vector with P - mG = (GF2Vector)mG.multiply(p); - errors = (GF2Vector)errors.multiply(p); - - // extract plaintext vector (last k columns of mG) - GF2Vector m = mG.extractRightVector(k); - - // return vectors - return new GF2Vector[]{m, errors}; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2PrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2PrivateKeyParameters.java deleted file mode 100644 index 8d2c18874b..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2PrivateKeyParameters.java +++ /dev/null @@ -1,148 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - - -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GoppaCode; -import org.bouncycastle.pqc.legacy.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialGF2mSmallM; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialRingGF2m; - -/** - * - * - * - */ -public class McElieceCCA2PrivateKeyParameters - extends McElieceCCA2KeyParameters -{ - // 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 GF(2m) - * @param gp the irreducible Goppa polynomial - * @param p the permutation - * @param digest name of digest algorithm - */ - public McElieceCCA2PrivateKeyParameters(int n, int k, GF2mField field, - PolynomialGF2mSmallM gp, Permutation p, String digest) - { - this(n, k, field, gp, GoppaCode.createCanonicalCheckMatrix(field, gp), p, digest); - } - - /** - * Constructor. - * - * @param n the length of the code - * @param k the dimension of the code - * @param field the finite field GF(2m) - * @param gp the irreducible Goppa polynomial - * @param canonicalCheckMatrix the canonical check matrix - * @param p the permutation - * @param digest name of digest algorithm - */ - public McElieceCCA2PrivateKeyParameters(int n, int k, GF2mField field, PolynomialGF2mSmallM gp, - GF2Matrix canonicalCheckMatrix, Permutation p, String digest) - { - super(true, digest); - - this.n = n; - this.k = k; - this.field = field; - this.goppaPoly = gp; - this.h = canonicalCheckMatrix; - this.p = p; - - PolynomialRingGF2m ring = new PolynomialRingGF2m(field, gp); - - // matrix for computing square roots in (GF(2^m))^t - this.qInv = ring.getSquareRootMatrix(); - } - - /** - * @return the length of the code - */ - public int getN() - { - return n; - } - - /** - * @return the dimension of the code - */ - public int getK() - { - return k; - } - - /** - * @return the degree of the Goppa polynomial (error correcting capability) - */ - public int getT() - { - return goppaPoly.getDegree(); - } - - /** - * @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 (GF(2^m))^t - */ - public PolynomialGF2mSmallM[] getQInv() - { - return qInv; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2PublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2PublicKeyParameters.java deleted file mode 100644 index 21b3bd1a46..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCCA2PublicKeyParameters.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; - -/** - * - * - * - */ -public class McElieceCCA2PublicKeyParameters - extends McElieceCCA2KeyParameters -{ - // 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 - * @param digest McElieceCCA2Parameters - */ - public McElieceCCA2PublicKeyParameters(int n, int t, GF2Matrix matrix, String digest) - { - super(false, digest); - - this.n = n; - this.t = t; - this.matrixG = new GF2Matrix(matrix); - } - - /** - * @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 matrixG; - } - - /** - * @return the dimension of the code - */ - public int getK() - { - return matrixG.getNumRows(); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCipher.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCipher.java deleted file mode 100644 index 7e29d1a2bf..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceCipher.java +++ /dev/null @@ -1,234 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.CryptoServicesRegistrar; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.MessageEncryptor; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Vector; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GoppaCode; -import org.bouncycastle.pqc.legacy.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialGF2mSmallM; -import org.bouncycastle.pqc.legacy.math.linearalgebra.Vector; - -/** - * This class implements the McEliece Public Key cryptosystem (McEliecePKCS). It - * was first described in R.J. McEliece, "A public key cryptosystem based on - * algebraic coding theory", DSN progress report, 42-44:114-116, 1978. The - * McEliecePKCS is the first cryptosystem which is based on error correcting - * codes. The trapdoor for the McEliece cryptosystem using Goppa codes is the - * knowledge of the Goppa polynomial used to generate the code. - */ -public class McElieceCipher - implements MessageEncryptor -{ - - /** - * The OID of the algorithm. - */ - public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.1"; - - - // the source of randomness - private SecureRandom sr; - - // the McEliece main parameters - private int n, k, t; - - // The maximum number of bytes the cipher can decrypt - public int maxPlainTextSize; - - // The maximum number of bytes the cipher can encrypt - public int cipherTextSize; - - private McElieceKeyParameters key; - private boolean forEncryption; - - - public void init(boolean forEncryption, - CipherParameters param) - { - this.forEncryption = forEncryption; - if (forEncryption) - { - if (param instanceof ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.sr = rParam.getRandom(); - this.key = (McEliecePublicKeyParameters)rParam.getParameters(); - this.initCipherEncrypt((McEliecePublicKeyParameters)key); - - } - else - { - this.sr = CryptoServicesRegistrar.getSecureRandom(); - this.key = (McEliecePublicKeyParameters)param; - this.initCipherEncrypt((McEliecePublicKeyParameters)key); - } - } - else - { - this.key = (McEliecePrivateKeyParameters)param; - this.initCipherDecrypt((McEliecePrivateKeyParameters)key); - } - - } - - /** - * Return the key size of the given key object. - * - * @param key the McElieceKeyParameters object - * @return the keysize of the given key object - */ - - public int getKeySize(McElieceKeyParameters key) - { - - if (key instanceof McEliecePublicKeyParameters) - { - return ((McEliecePublicKeyParameters)key).getN(); - - } - if (key instanceof McEliecePrivateKeyParameters) - { - return ((McEliecePrivateKeyParameters)key).getN(); - } - throw new IllegalArgumentException("unsupported type"); - - } - - - private void initCipherEncrypt(McEliecePublicKeyParameters pubKey) - { - n = pubKey.getN(); - k = pubKey.getK(); - t = pubKey.getT(); - cipherTextSize = n >> 3; - maxPlainTextSize = (k >> 3); - } - - - private void initCipherDecrypt(McEliecePrivateKeyParameters privKey) - { - n = privKey.getN(); - k = privKey.getK(); - - maxPlainTextSize = (k >> 3); - cipherTextSize = n >> 3; - } - - /** - * Encrypt a plain text. - * - * @param input the plain text - * @return the cipher text - */ - 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); - - GF2Matrix g = ((McEliecePublicKeyParameters)key).getG(); - Vector mG = g.leftMultiply(m); - GF2Vector mGZ = (GF2Vector)mG.add(z); - - return mGZ.getEncoded(); - } - - private GF2Vector computeMessageRepresentative(byte[] input) - { - byte[] data = new byte[maxPlainTextSize + ((k & 0x07) != 0 ? 1 : 0)]; - System.arraycopy(input, 0, data, 0, input.length); - data[input.length] = 0x01; - return GF2Vector.OS2VP(k, data); - } - - /** - * Decrypt a cipher text. - * - * @param input the cipher text - * @return the plain text - * @throws InvalidCipherTextException if the cipher text is invalid. - */ - public byte[] messageDecrypt(byte[] input) - 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(); - PolynomialGF2mSmallM gp = privKey.getGoppaPoly(); - GF2Matrix sInv = privKey.getSInv(); - Permutation p1 = privKey.getP1(); - Permutation p2 = privKey.getP2(); - GF2Matrix h = privKey.getH(); - PolynomialGF2mSmallM[] qInv = privKey.getQInv(); - - // compute permutation P = P1 * P2 - Permutation p = p1.rightMultiply(p2); - - // compute P^-1 - Permutation pInv = p.computeInverse(); - - // compute c P^-1 - GF2Vector cPInv = (GF2Vector)vec.multiply(pInv); - - // compute syndrome of c P^-1 - GF2Vector syndrome = (GF2Vector)h.rightMultiply(cPInv); - - // decode syndrome - GF2Vector z = GoppaCode.syndromeDecode(syndrome, field, gp, qInv); - GF2Vector mSG = (GF2Vector)cPInv.add(z); - - // multiply codeword with P1 and error vector with P - mSG = (GF2Vector)mSG.multiply(p1); - z = (GF2Vector)z.multiply(p); - - // extract mS (last k columns of mSG) - GF2Vector mS = mSG.extractRightVector(k); - - // compute plaintext vector - GF2Vector mVec = (GF2Vector)sInv.leftMultiply(mS); - - // compute and return plaintext - return computeMessage(mVec); - } - - private byte[] computeMessage(GF2Vector mr) - throws InvalidCipherTextException - { - byte[] mrBytes = mr.getEncoded(); - // find first non-zero byte - int index; - for (index = mrBytes.length - 1; index >= 0 && mrBytes[index] == 0; index--) - { - ; - } - - // check if padding byte is valid - if (index<0 || mrBytes[index] != 0x01) - { - throw new InvalidCipherTextException("Bad Padding: invalid ciphertext"); - } - - // extract and return message - byte[] mBytes = new byte[index]; - System.arraycopy(mrBytes, 0, mBytes, 0, index); - return mBytes; - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceFujisakiCipher.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceFujisakiCipher.java deleted file mode 100644 index 8309055ad3..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceFujisakiCipher.java +++ /dev/null @@ -1,218 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.CryptoServicesRegistrar; -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; -import org.bouncycastle.pqc.crypto.MessageEncryptor; -import org.bouncycastle.pqc.legacy.math.linearalgebra.ByteUtils; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Vector; - -/** - * This class implements the Fujisaki/Okamoto conversion of the McEliecePKCS. - * Fujisaki and Okamoto propose hybrid encryption that merges a symmetric - * encryption scheme which is secure in the find-guess model with an asymmetric - * one-way encryption scheme which is sufficiently probabilistic to obtain a - * public key cryptosystem which is CCA2-secure. For details, see D. Engelbert, - * R. Overbeck, A. Schmidt, "A Summary of McEliece-Type Cryptosystems and their Security", technical report. - * https://www.degruyter.com/document/doi/10.1515/JMC.2007.009/html - */ -public class McElieceFujisakiCipher - implements MessageEncryptor -{ - /** - * The OID of the algorithm. - */ - public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2.1"; - - private static final String DEFAULT_PRNG_NAME = "SHA1PRNG"; - - private Digest messDigest; - - private SecureRandom sr; - - /** - * The McEliece main parameters - */ - private int n, k, t; - - McElieceCCA2KeyParameters key; - private boolean forEncryption; - - - public void init(boolean forEncryption, - CipherParameters param) - { - this.forEncryption = forEncryption; - if (forEncryption) - { - if (param instanceof ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.sr = rParam.getRandom(); - this.key = (McElieceCCA2PublicKeyParameters)rParam.getParameters(); - this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key); - - } - else - { - this.sr = CryptoServicesRegistrar.getSecureRandom(); - this.key = (McElieceCCA2PublicKeyParameters)param; - this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key); - } - } - else - { - this.key = (McElieceCCA2PrivateKeyParameters)param; - this.initCipherDecrypt((McElieceCCA2PrivateKeyParameters)key); - } - } - - - public int getKeySize(McElieceCCA2KeyParameters key) - throws IllegalArgumentException - { - - if (key instanceof McElieceCCA2PublicKeyParameters) - { - return ((McElieceCCA2PublicKeyParameters)key).getN(); - } - if (key instanceof McElieceCCA2PrivateKeyParameters) - { - return ((McElieceCCA2PrivateKeyParameters)key).getN(); - } - throw new IllegalArgumentException("unsupported type"); - - } - - - private void initCipherEncrypt(McElieceCCA2PublicKeyParameters pubKey) - { - this.messDigest = Utils.getDigest(pubKey.getDigest()); - n = pubKey.getN(); - k = pubKey.getK(); - t = pubKey.getT(); - } - - - private void initCipherDecrypt(McElieceCCA2PrivateKeyParameters privKey) - { - this.messDigest = Utils.getDigest(privKey.getDigest()); - n = privKey.getN(); - t = privKey.getT(); - } - - - public byte[] messageEncrypt(byte[] input) - { - if (!forEncryption) - { - throw new IllegalStateException("cipher initialised for decryption"); - } - - // generate random vector r of length k bits - GF2Vector r = new GF2Vector(k, sr); - - // convert r to byte array - byte[] rBytes = r.getEncoded(); - - // compute (r||input) - byte[] rm = ByteUtils.concatenate(rBytes, input); - - // compute H(r||input) - messDigest.update(rm, 0, rm.length); - byte[] hrm = new byte[messDigest.getDigestSize()]; - messDigest.doFinal(hrm, 0); - - // convert H(r||input) to error vector z - GF2Vector z = Conversions.encode(n, t, hrm); - - // compute c1 = E(r, z) - byte[] c1 = McElieceCCA2Primitives.encryptionPrimitive((McElieceCCA2PublicKeyParameters)key, r, z) - .getEncoded(); - - // get PRNG object - DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); - - // seed PRNG with r' - sr0.addSeedMaterial(rBytes); - - // generate random c2 - byte[] c2 = new byte[input.length]; - sr0.nextBytes(c2); - - // XOR with input - for (int i = 0; i < input.length; i++) - { - c2[i] ^= input[i]; - } - - // return (c1||c2) - return ByteUtils.concatenate(c1, c2); - } - - public byte[] messageDecrypt(byte[] input) - throws InvalidCipherTextException - { - if (forEncryption) - { - throw new IllegalStateException("cipher initialised for decryption"); - } - - int c1Len = (n + 7) >> 3; - int c2Len = input.length - c1Len; - - // split ciphertext (c1||c2) - byte[][] c1c2 = ByteUtils.split(input, c1Len); - byte[] c1 = c1c2[0]; - byte[] c2 = c1c2[1]; - - // decrypt c1 ... - GF2Vector hrmVec = GF2Vector.OS2VP(n, c1); - GF2Vector[] decC1 = McElieceCCA2Primitives.decryptionPrimitive((McElieceCCA2PrivateKeyParameters)key, hrmVec); - byte[] rBytes = decC1[0].getEncoded(); - // ... and obtain error vector z - GF2Vector z = decC1[1]; - - // get PRNG object - DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); - - // seed PRNG with r' - sr0.addSeedMaterial(rBytes); - - // generate random sequence - byte[] mBytes = new byte[c2Len]; - sr0.nextBytes(mBytes); - - // XOR with c2 to obtain m - for (int i = 0; i < c2Len; i++) - { - mBytes[i] ^= c2[i]; - } - - // compute H(r||m) - byte[] rmBytes = ByteUtils.concatenate(rBytes, mBytes); - byte[] hrm = new byte[messDigest.getDigestSize()]; - messDigest.update(rmBytes, 0, rmBytes.length); - messDigest.doFinal(hrm, 0); - - - // compute Conv(H(r||m)) - hrmVec = Conversions.encode(n, t, hrm); - - // check that Conv(H(m||r)) = z - if (!hrmVec.equals(z)) - { - throw new InvalidCipherTextException("Bad Padding: invalid ciphertext"); - } - - // return plaintext m - return mBytes; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceKeyGenerationParameters.java deleted file mode 100644 index 7a43e39979..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceKeyGenerationParameters.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.KeyGenerationParameters; - -public class McElieceKeyGenerationParameters - extends KeyGenerationParameters -{ - private McElieceParameters params; - - public McElieceKeyGenerationParameters( - SecureRandom random, - McElieceParameters params) - { - // XXX key size? - super(random, 256); - this.params = params; - } - - public McElieceParameters getParameters() - { - return params; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceKeyPairGenerator.java deleted file mode 100644 index 81750c1e5b..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceKeyPairGenerator.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GoppaCode; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GoppaCode.MaMaPe; -import org.bouncycastle.pqc.legacy.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialGF2mSmallM; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialRingGF2m; - - -/** - * This class implements key pair generation of the McEliece Public Key - * Cryptosystem (McEliecePKC). - */ -public class McElieceKeyPairGenerator - implements AsymmetricCipherKeyPairGenerator -{ - - - public McElieceKeyPairGenerator() - { - - } - - - /** - * The OID of the algorithm. - */ - private static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.1"; - - private McElieceKeyGenerationParameters mcElieceParams; - - // the extension degree of the finite field GF(2^m) - private int m; - - // the length of the code - private int n; - - // the error correction capability - private int t; - - // the field polynomial - private int fieldPoly; - - // the source of randomness - private SecureRandom random; - - // flag indicating whether the key pair generator has been initialized - private boolean initialized = false; - - - /** - * Default initialization of the key pair generator. - */ - private void initializeDefault() - { - McElieceKeyGenerationParameters mcParams = new McElieceKeyGenerationParameters(null, new McElieceParameters()); - initialize(mcParams); - } - - private void initialize( - KeyGenerationParameters param) - { - this.mcElieceParams = (McElieceKeyGenerationParameters)param; - this.random = param.getRandom(); - - this.m = this.mcElieceParams.getParameters().getM(); - this.n = this.mcElieceParams.getParameters().getN(); - this.t = this.mcElieceParams.getParameters().getT(); - this.fieldPoly = this.mcElieceParams.getParameters().getFieldPoly(); - this.initialized = true; - } - - - private AsymmetricCipherKeyPair genKeyPair() - { - - if (!initialized) - { - initializeDefault(); - } - - // finite field GF(2^m) - GF2mField field = new GF2mField(m, fieldPoly); - - // irreducible Goppa polynomial - PolynomialGF2mSmallM gp = new PolynomialGF2mSmallM(field, t, - PolynomialGF2mSmallM.RANDOM_IRREDUCIBLE_POLYNOMIAL, random); - PolynomialRingGF2m ring = new PolynomialRingGF2m(field, gp); - - // matrix used to compute square roots in (GF(2^m))^t - PolynomialGF2mSmallM[] sqRootMatrix = ring.getSquareRootMatrix(); - - // generate canonical check matrix - GF2Matrix h = GoppaCode.createCanonicalCheckMatrix(field, gp); - - // compute short systematic form of check matrix - MaMaPe mmp = GoppaCode.computeSystematicForm(h, random); - GF2Matrix shortH = mmp.getSecondMatrix(); - Permutation p1 = mmp.getPermutation(); - - // compute short systematic form of generator matrix - GF2Matrix shortG = (GF2Matrix)shortH.computeTranspose(); - - // extend to full systematic form - GF2Matrix gPrime = shortG.extendLeftCompactForm(); - - // obtain number of rows of G (= dimension of the code) - int k = shortG.getNumRows(); - - // generate random invertible (k x k)-matrix S and its inverse S^-1 - GF2Matrix[] matrixSandInverse = GF2Matrix - .createRandomRegularMatrixAndItsInverse(k, random); - - // generate random permutation P2 - Permutation p2 = new Permutation(n, random); - - // compute public matrix G=S*G'*P2 - GF2Matrix g = (GF2Matrix)matrixSandInverse[0].rightMultiply(gPrime); - g = (GF2Matrix)g.rightMultiply(p2); - - - // generate keys - 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); - } - - public void init(KeyGenerationParameters param) - { - this.initialize(param); - } - - public AsymmetricCipherKeyPair generateKeyPair() - { - return genKeyPair(); - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceKeyParameters.java deleted file mode 100644 index 84cc513434..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceKeyParameters.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; - - -public class McElieceKeyParameters - extends AsymmetricKeyParameter -{ - private McElieceParameters params; - - public McElieceKeyParameters( - boolean isPrivate, - McElieceParameters params) - { - super(isPrivate); - this.params = params; - } - - - public McElieceParameters getParameters() - { - return params; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceKobaraImaiCipher.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceKobaraImaiCipher.java deleted file mode 100644 index 6555410479..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceKobaraImaiCipher.java +++ /dev/null @@ -1,336 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.CryptoServicesRegistrar; -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; -import org.bouncycastle.pqc.crypto.MessageEncryptor; -import org.bouncycastle.pqc.legacy.math.linearalgebra.ByteUtils; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Vector; -import org.bouncycastle.pqc.legacy.math.linearalgebra.IntegerFunctions; - -/** - * This class implements the Kobara/Imai conversion of the McEliecePKCS. This is - * a conversion of the McEliecePKCS which is CCA2-secure. For details, see D. - * Engelbert, R. Overbeck, A. Schmidt, "A Summary of McEliece-Type Cryptosystems and their Security", technical report. - * https://www.degruyter.com/document/doi/10.1515/JMC.2007.009/html - */ -public class McElieceKobaraImaiCipher - implements MessageEncryptor -{ - - /** - * The OID of the algorithm. - */ - public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2.3"; - - private static final String DEFAULT_PRNG_NAME = "SHA1PRNG"; - - /** - * A predetermined public constant. - */ - public static final byte[] PUBLIC_CONSTANT = "a predetermined public constant" - .getBytes(); - - - private Digest messDigest; - - private SecureRandom sr; - - McElieceCCA2KeyParameters key; - - /** - * The McEliece main parameters - */ - private int n, k, t; - private boolean forEncryption; - - - public void init(boolean forEncryption, - CipherParameters param) - { - this.forEncryption = forEncryption; - if (forEncryption) - { - if (param instanceof ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.sr = rParam.getRandom(); - this.key = (McElieceCCA2PublicKeyParameters)rParam.getParameters(); - this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key); - - } - else - { - this.sr = CryptoServicesRegistrar.getSecureRandom(); - this.key = (McElieceCCA2PublicKeyParameters)param; - this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key); - } - } - else - { - this.key = (McElieceCCA2PrivateKeyParameters)param; - this.initCipherDecrypt((McElieceCCA2PrivateKeyParameters)key); - } - - } - - /** - * Return the key size of the given key object. - * - * @param key the McElieceCCA2KeyParameters object - * @return the key size of the given key object - */ - public int getKeySize(McElieceCCA2KeyParameters key) - { - if (key instanceof McElieceCCA2PublicKeyParameters) - { - return ((McElieceCCA2PublicKeyParameters)key).getN(); - - } - if (key instanceof McElieceCCA2PrivateKeyParameters) - { - return ((McElieceCCA2PrivateKeyParameters)key).getN(); - } - throw new IllegalArgumentException("unsupported type"); - } - - private void initCipherEncrypt(McElieceCCA2PublicKeyParameters pubKey) - { - this.messDigest = Utils.getDigest(pubKey.getDigest()); - n = pubKey.getN(); - k = pubKey.getK(); - t = pubKey.getT(); - - } - - private void initCipherDecrypt(McElieceCCA2PrivateKeyParameters privKey) - { - this.messDigest = Utils.getDigest(privKey.getDigest()); - n = privKey.getN(); - k = privKey.getK(); - t = privKey.getT(); - } - - public byte[] messageEncrypt(byte[] input) - { - if (!forEncryption) - { - throw new IllegalStateException("cipher initialised for decryption"); - } - - int c2Len = messDigest.getDigestSize(); - int c4Len = k >> 3; - int c5Len = (IntegerFunctions.binomial(n, t).bitLength() - 1) >> 3; - - - int mLen = c4Len + c5Len - c2Len - PUBLIC_CONSTANT.length; - if (input.length > mLen) - { - mLen = input.length; - } - - int c1Len = mLen + PUBLIC_CONSTANT.length; - int c6Len = c1Len + c2Len - c4Len - c5Len; - - // compute (m||const) - byte[] mConst = new byte[c1Len]; - System.arraycopy(input, 0, mConst, 0, input.length); - System.arraycopy(PUBLIC_CONSTANT, 0, mConst, mLen, - PUBLIC_CONSTANT.length); - - // generate random r of length c2Len bytes - byte[] r = new byte[c2Len]; - sr.nextBytes(r); - - // get PRNG object - // get PRNG object - DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); - - // seed PRNG with r' - sr0.addSeedMaterial(r); - - // generate random sequence ... - byte[] c1 = new byte[c1Len]; - sr0.nextBytes(c1); - - // ... and XOR with (m||const) to obtain c1 - for (int i = c1Len - 1; i >= 0; i--) - { - c1[i] ^= mConst[i]; - } - - // compute H(c1) ... - byte[] c2 = new byte[messDigest.getDigestSize()]; - messDigest.update(c1, 0, c1.length); - messDigest.doFinal(c2, 0); - - // ... and XOR with r - for (int i = c2Len - 1; i >= 0; i--) - { - c2[i] ^= r[i]; - } - - // compute (c2||c1) - byte[] c2c1 = ByteUtils.concatenate(c2, c1); - - // split (c2||c1) into (c6||c5||c4), where c4Len is k/8 bytes, c5Len is - // floor[log(n|t)]/8 bytes, and c6Len is c1Len+c2Len-c4Len-c5Len (may be - // 0). - byte[] c6 = new byte[0]; - if (c6Len > 0) - { - c6 = new byte[c6Len]; - System.arraycopy(c2c1, 0, c6, 0, c6Len); - } - - byte[] c5 = new byte[c5Len]; - System.arraycopy(c2c1, c6Len, c5, 0, c5Len); - - byte[] c4 = new byte[c4Len]; - System.arraycopy(c2c1, c6Len + c5Len, c4, 0, c4Len); - - // convert c4 to vector over GF(2) - GF2Vector c4Vec = GF2Vector.OS2VP(k, c4); - - // convert c5 to error vector z - GF2Vector z = Conversions.encode(n, t, c5); - - // compute encC4 = E(c4, z) - byte[] encC4 = McElieceCCA2Primitives.encryptionPrimitive((McElieceCCA2PublicKeyParameters)key, - c4Vec, z).getEncoded(); - - // if c6Len > 0 - if (c6Len > 0) - { - // return (c6||encC4) - return ByteUtils.concatenate(c6, encC4); - } - // else, return encC4 - return encC4; - } - - - public byte[] messageDecrypt(byte[] input) - throws InvalidCipherTextException - { - if (forEncryption) - { - throw new IllegalStateException("cipher initialised for decryption"); - } - - int nDiv8 = n >> 3; - - if (input.length < nDiv8) - { - throw new InvalidCipherTextException("Bad Padding: Ciphertext too short."); - } - - int c2Len = messDigest.getDigestSize(); - int c4Len = k >> 3; - int c5Len = (IntegerFunctions.binomial(n, t).bitLength() - 1) >> 3; - int c6Len = input.length - nDiv8; - - // split cipher text (c6||encC4), where c6 may be empty - byte[] c6, encC4; - if (c6Len > 0) - { - byte[][] c6EncC4 = ByteUtils.split(input, c6Len); - c6 = c6EncC4[0]; - encC4 = c6EncC4[1]; - } - else - { - c6 = new byte[0]; - encC4 = input; - } - - // convert encC4 into vector over GF(2) - GF2Vector encC4Vec = GF2Vector.OS2VP(n, encC4); - - // decrypt encC4Vec to obtain c4 and error vector z - GF2Vector[] c4z = McElieceCCA2Primitives.decryptionPrimitive((McElieceCCA2PrivateKeyParameters)key, - encC4Vec); - byte[] c4 = c4z[0].getEncoded(); - GF2Vector z = c4z[1]; - - // if length of c4 is greater than c4Len (because of padding) ... - if (c4.length > c4Len) - { - // ... truncate the padding bytes - c4 = ByteUtils.subArray(c4, 0, c4Len); - } - - // compute c5 = Conv^-1(z) - byte[] c5 = Conversions.decode(n, t, z); - - // if c5 is shorter than expected, pad with leading zeroes - if (c5.length < c5Len) - { - byte[] paddedC5 = new byte[c5Len]; - System.arraycopy(c5, 0, paddedC5, c5Len - c5.length, c5.length); - c5 = paddedC5; - } - - // compute (c6||c5||c4) - byte[] c6c5c4 = ByteUtils.concatenate(c6, c5); - c6c5c4 = ByteUtils.concatenate(c6c5c4, c4); - - // split (c6||c5||c4) into (c2||c1), where c2Len = mdLen and c1Len = - // input.length-c2Len bytes. - int c1Len = c6c5c4.length - c2Len; - byte[][] c2c1 = ByteUtils.split(c6c5c4, c2Len); - byte[] c2 = c2c1[0]; - byte[] c1 = c2c1[1]; - - // compute H(c1) ... - byte[] rPrime = new byte[messDigest.getDigestSize()]; - messDigest.update(c1, 0, c1.length); - messDigest.doFinal(rPrime, 0); - - // ... and XOR with c2 to obtain r' - for (int i = c2Len - 1; i >= 0; i--) - { - rPrime[i] ^= c2[i]; - } - - // get PRNG object - DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); - - // seed PRNG with r' - sr0.addSeedMaterial(rPrime); - - // generate random sequence R(r') ... - byte[] mConstPrime = new byte[c1Len]; - sr0.nextBytes(mConstPrime); - - // ... and XOR with c1 to obtain (m||const') - for (int i = c1Len - 1; i >= 0; i--) - { - mConstPrime[i] ^= c1[i]; - } - - if (mConstPrime.length < c1Len) - { - throw new InvalidCipherTextException("Bad Padding: invalid ciphertext"); - } - - byte[][] temp = ByteUtils.split(mConstPrime, c1Len - - PUBLIC_CONSTANT.length); - byte[] mr = temp[0]; - byte[] constPrime = temp[1]; - - if (!ByteUtils.equals(constPrime, PUBLIC_CONSTANT)) - { - throw new InvalidCipherTextException("Bad Padding: invalid ciphertext"); - } - - return mr; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceParameters.java deleted file mode 100644 index 2c36ea3875..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McElieceParameters.java +++ /dev/null @@ -1,230 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialRingGF2; - -public class McElieceParameters - implements CipherParameters -{ - - /** - * 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 int m; - - /** - * error correction capability of the code - */ - private int t; - - /** - * length of the code - */ - private int n; - - /** - * the field polynomial - */ - private int fieldPoly; - - private Digest digest; - - /** - * Constructor. Set the default parameters: extension degree. - */ - public McElieceParameters() - { - this(DEFAULT_M, DEFAULT_T); - } - - public McElieceParameters(Digest digest) - { - this(DEFAULT_M, DEFAULT_T, digest); - } - - /** - * Constructor. - * - * @param keysize the length of a Goppa code - * @throws IllegalArgumentException if keysize < 1. - */ - public McElieceParameters(int keysize) - { - this(keysize, null); - } - - /** - * Constructor. - * - * @param keysize the length of a Goppa code - * @param digest CCA2 mode digest - * @throws IllegalArgumentException if keysize < 1. - */ - public McElieceParameters(int keysize, Digest digest) - { - if (keysize < 1) - { - throw new IllegalArgumentException("key size must be positive"); - } - m = 0; - n = 1; - while (n < keysize) - { - n <<= 1; - m++; - } - t = n >>> 1; - t /= m; - 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 IllegalArgumentException if m < 1 or m > 32 or - * t < 0 or t > n. - */ - public McElieceParameters(int m, int t) - { - 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 m < 1 or m > 32 or - * t < 0 or t > n. - */ - public McElieceParameters(int m, int t, Digest 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 m < 1 or m > 32 or - * t < 0 or t > n or - * poly is not an irreducible field polynomial. - */ - public McElieceParameters(int m, int t, int poly) - { - 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 m < 1 or m > 32 or - * t < 0 or t > n or - * poly is not an irreducible field polynomial. - */ - public McElieceParameters(int m, int t, int poly, Digest 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; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McEliecePointchevalCipher.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McEliecePointchevalCipher.java deleted file mode 100644 index 5e3570ca0c..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McEliecePointchevalCipher.java +++ /dev/null @@ -1,251 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.CryptoServicesRegistrar; -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; -import org.bouncycastle.pqc.crypto.MessageEncryptor; -import org.bouncycastle.pqc.legacy.math.linearalgebra.ByteUtils; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Vector; - -/** - * This class implements the Pointcheval conversion of the McEliecePKCS. - * Pointcheval presents a generic technique to make a CCA2-secure cryptosystem - * from any partially trapdoor one-way function in the random oracle model. For - * details, see D. Engelbert, R. Overbeck, A. Schmidt, "A Summary of McEliece-Type Cryptosystems and their Security", technical report. - * https://www.degruyter.com/document/doi/10.1515/JMC.2007.009/html - */ -public class McEliecePointchevalCipher - implements MessageEncryptor -{ - - - /** - * The OID of the algorithm. - */ - public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2.2"; - - private Digest messDigest; - - private SecureRandom sr; - - /** - * The McEliece main parameters - */ - private int n, k, t; - - McElieceCCA2KeyParameters key; - private boolean forEncryption; - - public void init(boolean forEncryption, - CipherParameters param) - { - this.forEncryption = forEncryption; - - if (forEncryption) - { - if (param instanceof ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.sr = rParam.getRandom(); - this.key = (McElieceCCA2PublicKeyParameters)rParam.getParameters(); - this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key); - - } - else - { - this.sr = CryptoServicesRegistrar.getSecureRandom(); - this.key = (McElieceCCA2PublicKeyParameters)param; - this.initCipherEncrypt((McElieceCCA2PublicKeyParameters)key); - } - } - else - { - this.key = (McElieceCCA2PrivateKeyParameters)param; - this.initCipherDecrypt((McElieceCCA2PrivateKeyParameters)key); - } - - } - - /** - * Return the key size of the given key object. - * - * @param key the McElieceCCA2KeyParameters object - * @return the key size of the given key object - * @throws IllegalArgumentException if the key is invalid - */ - public int getKeySize(McElieceCCA2KeyParameters key) - throws IllegalArgumentException - { - - if (key instanceof McElieceCCA2PublicKeyParameters) - { - return ((McElieceCCA2PublicKeyParameters)key).getN(); - - } - if (key instanceof McElieceCCA2PrivateKeyParameters) - { - return ((McElieceCCA2PrivateKeyParameters)key).getN(); - } - throw new IllegalArgumentException("unsupported type"); - - } - - - protected int decryptOutputSize(int inLen) - { - return 0; - } - - protected int encryptOutputSize(int inLen) - { - return 0; - } - - - private void initCipherEncrypt(McElieceCCA2PublicKeyParameters pubKey) - { - this.messDigest = Utils.getDigest(pubKey.getDigest()); - n = pubKey.getN(); - k = pubKey.getK(); - t = pubKey.getT(); - } - - private void initCipherDecrypt(McElieceCCA2PrivateKeyParameters privKey) - { - this.messDigest = Utils.getDigest(privKey.getDigest()); - n = privKey.getN(); - k = privKey.getK(); - t = privKey.getT(); - } - - public byte[] messageEncrypt(byte[] input) - { - if (!forEncryption) - { - throw new IllegalStateException("cipher initialised for decryption"); - } - - int kDiv8 = k >> 3; - - // generate random r of length k div 8 bytes - byte[] r = new byte[kDiv8]; - sr.nextBytes(r); - - // generate random vector r' of length k bits - GF2Vector rPrime = new GF2Vector(k, sr); - - // convert r' to byte array - byte[] rPrimeBytes = rPrime.getEncoded(); - - // compute (input||r) - byte[] mr = ByteUtils.concatenate(input, r); - - // compute H(input||r) - messDigest.update(mr, 0, mr.length); - byte[] hmr = new byte[messDigest.getDigestSize()]; - messDigest.doFinal(hmr, 0); - - - // convert H(input||r) to error vector z - GF2Vector z = Conversions.encode(n, t, hmr); - - // compute c1 = E(rPrime, z) - byte[] c1 = McElieceCCA2Primitives.encryptionPrimitive((McElieceCCA2PublicKeyParameters)key, rPrime, - z).getEncoded(); - - // get PRNG object - DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); - - // seed PRNG with r' - sr0.addSeedMaterial(rPrimeBytes); - - // generate random c2 - byte[] c2 = new byte[input.length + kDiv8]; - sr0.nextBytes(c2); - - // XOR with input - for (int i = 0; i < input.length; i++) - { - c2[i] ^= input[i]; - } - // XOR with r - for (int i = 0; i < kDiv8; i++) - { - c2[input.length + i] ^= r[i]; - } - - // return (c1||c2) - return ByteUtils.concatenate(c1, c2); - } - - public byte[] messageDecrypt(byte[] input) - throws InvalidCipherTextException - { - if (forEncryption) - { - throw new IllegalStateException("cipher initialised for decryption"); - } - - int c1Len = (n + 7) >> 3; - int c2Len = input.length - c1Len; - - // split cipher text (c1||c2) - byte[][] c1c2 = ByteUtils.split(input, c1Len); - byte[] c1 = c1c2[0]; - byte[] c2 = c1c2[1]; - - // decrypt c1 ... - GF2Vector c1Vec = GF2Vector.OS2VP(n, c1); - GF2Vector[] c1Dec = McElieceCCA2Primitives.decryptionPrimitive((McElieceCCA2PrivateKeyParameters)key, - c1Vec); - byte[] rPrimeBytes = c1Dec[0].getEncoded(); - // ... and obtain error vector z - GF2Vector z = c1Dec[1]; - - // get PRNG object - DigestRandomGenerator sr0 = new DigestRandomGenerator(new SHA1Digest()); - - // seed PRNG with r' - sr0.addSeedMaterial(rPrimeBytes); - - // generate random sequence - byte[] mrBytes = new byte[c2Len]; - sr0.nextBytes(mrBytes); - - // XOR with c2 to obtain (m||r) - for (int i = 0; i < c2Len; i++) - { - mrBytes[i] ^= c2[i]; - } - - // compute H(m||r) - messDigest.update(mrBytes, 0, mrBytes.length); - byte[] hmr = new byte[messDigest.getDigestSize()]; - messDigest.doFinal(hmr, 0); - - // compute Conv(H(m||r)) - c1Vec = Conversions.encode(n, t, hmr); - - // check that Conv(H(m||r)) = z - if (!c1Vec.equals(z)) - { - throw new InvalidCipherTextException("Bad Padding: Invalid ciphertext."); - } - - // split (m||r) to obtain m - int kDiv8 = k >> 3; - byte[][] mr = ByteUtils.split(mrBytes, c2Len - kDiv8); - - // return plain text m - return mr[0]; - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McEliecePrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McEliecePrivateKeyParameters.java deleted file mode 100644 index 93a2a7b300..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McEliecePrivateKeyParameters.java +++ /dev/null @@ -1,189 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GoppaCode; -import org.bouncycastle.pqc.legacy.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialGF2mSmallM; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialRingGF2m; - - -public class McEliecePrivateKeyParameters - extends McElieceKeyParameters -{ - - // the OID of the algorithm - private String oid; - - // the length of the code - private int n; - - // the dimension of the code, where k >= n - mt - 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 (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 field polynomial defining the finite field -* GF(2m) - * @param gp the irreducible Goppa polynomial - * @param p1 the permutation used to generate the systematic check -* matrix - * @param p2 the permutation used to compute the public generator -* matrix - * @param sInv the matrix S-1 - */ - public McEliecePrivateKeyParameters(int n, int k, GF2mField field, - PolynomialGF2mSmallM gp, Permutation p1, Permutation p2, GF2Matrix sInv) - { - super(true, null); - this.k = k; - this.n = n; - this.field = field; - this.goppaPoly = gp; - this.sInv = sInv; - this.p1 = p1; - this.p2 = p2; - 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 n the length of the code - * @param k the dimension of the code - * @param encField the encoded field polynomial defining the finite field - * GF(2m) - * @param encGoppaPoly the encoded irreducible Goppa polynomial - * @param encSInv the encoded matrix S-1 - * @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 - * (GF(2m))t - */ - public McEliecePrivateKeyParameters(int n, int k, byte[] encField, - byte[] encGoppaPoly, byte[] encSInv, byte[] encP1, byte[] encP2, - byte[] encH, byte[][] encQInv) - { - super(true, null); - 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 GF(2m) - */ - 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 - * (GF(2m))t - */ - public PolynomialGF2mSmallM[] getQInv() - { - return qInv; - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McEliecePublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McEliecePublicKeyParameters.java deleted file mode 100644 index 0dcd730945..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/McEliecePublicKeyParameters.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.mceliece; - -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; - - -public class McEliecePublicKeyParameters - extends McElieceKeyParameters -{ - // 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. - * - * @param n the length of the code - * @param t the error correction capability of the code - * @param g the generator matrix - */ - public McEliecePublicKeyParameters(int n, int t, GF2Matrix g) - { - super(false, null); - this.n = n; - this.t = t; - this.g = new GF2Matrix(g); - } - - /** - * @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; - } - - /** - * @return the dimension of the code - */ - public int getK() - { - return g.getNumRows(); - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/Utils.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/Utils.java deleted file mode 100644 index e62fd33f36..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/mceliece/Utils.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.bouncycastle.pqc.legacy.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/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/IndexGenerator.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/IndexGenerator.java deleted file mode 100644 index ef140f3e2f..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/IndexGenerator.java +++ /dev/null @@ -1,237 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.util.Arrays; - -/** - * An implementation of the Index Generation Function in IEEE P1363.1. - */ -public class IndexGenerator -{ - private byte[] seed; - private int N; - private int c; - private int minCallsR; - private int totLen; - private int remLen; - private BitString buf; - private int counter; - private boolean initialized; - private Digest hashAlg; - private int hLen; - - /** - * Constructs a new index generator. - * - * @param seed a seed of arbitrary length to initialize the index generator with - * @param params NtruEncrypt parameters - */ - IndexGenerator(byte[] seed, NTRUEncryptionParameters params) - { - this.seed = seed; - N = params.N; - c = params.c; - minCallsR = params.minCallsR; - - totLen = 0; - remLen = 0; - counter = 0; - hashAlg = params.hashAlg; - - hLen = hashAlg.getDigestSize(); // hash length - initialized = false; - } - - /* - * Returns a number i such that 0 <= i < N. - */ - int nextIndex() - { - if (!initialized) - { - buf = new BitString(); - byte[] hash = new byte[hashAlg.getDigestSize()]; - while (counter < minCallsR) - { - appendHash(buf, hash); - counter++; - } - totLen = minCallsR * 8 * hLen; - remLen = totLen; - initialized = true; - } - - while (true) - { - totLen += c; - BitString M = buf.getTrailing(remLen); - if (remLen < c) - { - int tmpLen = c - remLen; - int cThreshold = counter + (tmpLen + hLen - 1) / hLen; - byte[] hash = new byte[hashAlg.getDigestSize()]; - while (counter < cThreshold) - { - appendHash(M, hash); - counter++; - if (tmpLen > 8 * hLen) - { - tmpLen -= 8 * hLen; - } - } - remLen = 8 * hLen - tmpLen; - buf = new BitString(); - buf.appendBits(hash); - } - else - { - remLen -= c; - } - - int i = M.getLeadingAsInt(c); // assume c<32 - if (i < (1 << c) - ((1 << c) % N)) - { - return i % N; - } - } - } - - private void appendHash(BitString m, byte[] hash) - { - hashAlg.update(seed, 0, seed.length); - - putInt(hashAlg, counter); - - hashAlg.doFinal(hash, 0); - - m.appendBits(hash); - } - - private void putInt(Digest hashAlg, int counter) - { - hashAlg.update((byte)(counter >> 24)); - hashAlg.update((byte)(counter >> 16)); - hashAlg.update((byte)(counter >> 8)); - hashAlg.update((byte)counter); - } - - /** - * Represents a string of bits and supports appending, reading the head, and reading the tail. - */ - public static class BitString - { - byte[] bytes = new byte[4]; - int numBytes; // includes the last byte even if only some of its bits are used - int lastByteBits; // lastByteBits <= 8 - - /** - * Appends all bits in a byte array to the end of the bit string. - * - * @param bytes a byte array - */ - void appendBits(byte[] bytes) - { - for (int i = 0; i != bytes.length; i++) - { - appendBits(bytes[i]); - } - } - - /** - * Appends all bits in a byte to the end of the bit string. - * - * @param b a byte - */ - public void appendBits(byte b) - { - if (numBytes == bytes.length) - { - bytes = copyOf(bytes, 2 * bytes.length); - } - - if (numBytes == 0) - { - numBytes = 1; - bytes[0] = b; - lastByteBits = 8; - } - else if (lastByteBits == 8) - { - bytes[numBytes++] = b; - } - else - { - int s = 8 - lastByteBits; - bytes[numBytes - 1] |= (b & 0xFF) << lastByteBits; - bytes[numBytes++] = (byte)((b & 0xFF) >> s); - } - } - - /** - * Returns the last numBits bits from the end of the bit string. - * - * @param numBits number of bits - * @return a new BitString of length numBits - */ - public BitString getTrailing(int numBits) - { - BitString newStr = new BitString(); - newStr.numBytes = (numBits + 7) / 8; - newStr.bytes = new byte[newStr.numBytes]; - for (int i = 0; i < newStr.numBytes; i++) - { - newStr.bytes[i] = bytes[i]; - } - - newStr.lastByteBits = numBits % 8; - if (newStr.lastByteBits == 0) - { - newStr.lastByteBits = 8; - } - else - { - int s = 32 - newStr.lastByteBits; - newStr.bytes[newStr.numBytes - 1] = (byte)(newStr.bytes[newStr.numBytes - 1] << s >>> s); - } - - return newStr; - } - - /** - * Returns up to 32 bits from the beginning of the bit string. - * - * @param numBits number of bits - * @return an int whose lower numBits bits are the beginning of the bit string - */ - public int getLeadingAsInt(int numBits) - { - int startBit = (numBytes - 1) * 8 + lastByteBits - numBits; - int startByte = startBit / 8; - - int startBitInStartByte = startBit % 8; - int sum = (bytes[startByte] & 0xFF) >>> startBitInStartByte; - int shift = 8 - startBitInStartByte; - for (int i = startByte + 1; i < numBytes; i++) - { - sum |= (bytes[i] & 0xFF) << shift; - shift += 8; - } - - return sum; - } - - public byte[] getBytes() - { - return Arrays.clone(bytes); - } - } - - private static byte[] copyOf(byte[] src, int len) - { - byte[] tmp = new byte[len]; - - System.arraycopy(src, 0, tmp, 0, len < src.length ? len : src.length); - - return tmp; - } -} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionKeyGenerationParameters.java deleted file mode 100644 index 07348286e6..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionKeyGenerationParameters.java +++ /dev/null @@ -1,519 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.SecureRandom; -import java.util.Arrays; - -import org.bouncycastle.crypto.CryptoServicesRegistrar; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; -import org.bouncycastle.crypto.util.DigestFactory; - -/** - * A set of parameters for NtruEncrypt. Several predefined parameter sets are available and new ones can be created as well. - */ -public class NTRUEncryptionKeyGenerationParameters - extends KeyGenerationParameters - implements Cloneable -{ - /** - * A conservative (in terms of security) parameter set that gives 256 bits of security and is optimized for key size. - * Uses {@link CryptoServicesRegistrar#getSecureRandom()} as an entropy source (but the value present at class load time). - */ - public static final NTRUEncryptionKeyGenerationParameters EES1087EP2 = new NTRUEncryptionKeyGenerationParameters(1087, 2048, 120, 120, 256, 13, 25, 14, true, new byte[]{0, 6, 3}, true, false, new SHA512Digest()); - - /** - * A conservative (in terms of security) parameter set that gives 256 bits of security and is a tradeoff between key size and encryption/decryption speed. - * Uses {@link CryptoServicesRegistrar#getSecureRandom()} as an entropy source (but the value present at class load time). - */ - public static final NTRUEncryptionKeyGenerationParameters EES1171EP1 = new NTRUEncryptionKeyGenerationParameters(1171, 2048, 106, 106, 256, 13, 20, 15, true, new byte[]{0, 6, 4}, true, false, new SHA512Digest()); - - /** - * A conservative (in terms of security) parameter set that gives 256 bits of security and is optimized for encryption/decryption speed. - * Uses {@link CryptoServicesRegistrar#getSecureRandom()} as an entropy source (but the value present at class load time). - */ - public static final NTRUEncryptionKeyGenerationParameters EES1499EP1 = new NTRUEncryptionKeyGenerationParameters(1499, 2048, 79, 79, 256, 13, 17, 19, true, new byte[]{0, 6, 5}, true, false, new SHA512Digest()); - - /** - * A parameter set that gives 128 bits of security and uses simple ternary polynomials. - * Uses {@link CryptoServicesRegistrar#getSecureRandom()} as an entropy source (but the value present at class load time). - */ - public static final NTRUEncryptionKeyGenerationParameters APR2011_439 = new NTRUEncryptionKeyGenerationParameters(439, 2048, 146, 130, 128, 9, 32, 9, true, new byte[]{0, 7, 101}, true, false, new SHA256Digest()); - - /** - * Like APR2011_439, this parameter set gives 128 bits of security but uses product-form polynomials and f=1+pF. - * Uses {@link CryptoServicesRegistrar#getSecureRandom()} as an entropy source (but the value present at class load time). - */ - public static final NTRUEncryptionKeyGenerationParameters APR2011_439_FAST = new NTRUEncryptionKeyGenerationParameters(439, 2048, 9, 8, 5, 130, 128, 9, 32, 9, true, new byte[]{0, 7, 101}, true, true, new SHA256Digest()); - - /** - * A parameter set that gives 256 bits of security and uses simple ternary polynomials. - * Uses {@link CryptoServicesRegistrar#getSecureRandom()} as an entropy source (but the value present at class load time). - */ - public static final NTRUEncryptionKeyGenerationParameters APR2011_743 = new NTRUEncryptionKeyGenerationParameters(743, 2048, 248, 220, 256, 10, 27, 14, true, new byte[]{0, 7, 105}, false, false, new SHA512Digest()); - - /** - * Like APR2011_743, this parameter set gives 256 bits of security but uses product-form polynomials and f=1+pF. - * Uses {@link CryptoServicesRegistrar#getSecureRandom()} as an entropy source (but the value present at class load time). - */ - public static final NTRUEncryptionKeyGenerationParameters APR2011_743_FAST = new NTRUEncryptionKeyGenerationParameters(743, 2048, 11, 11, 15, 220, 256, 10, 27, 14, true, new byte[]{0, 7, 105}, false, true, new SHA512Digest()); - - public int N, q, df, df1, df2, df3; - public int dr; - public int dr1; - public int dr2; - public int dr3; - public int dg; - int llen; - public int maxMsgLenBytes; - public int db; - public int bufferLenBits; - int bufferLenTrits; - public int dm0; - public int pkLen; - public int c; - public int minCallsR; - public int minCallsMask; - public boolean hashSeed; - public byte[] oid; - public boolean sparse; - public boolean fastFp; - public int polyType; - public Digest hashAlg; - - /** - * Constructs a parameter set that uses ternary private keys (i.e. polyType=SIMPLE). - * @param N number of polynomial coefficients - * @param q modulus - * @param df number of ones in the private polynomial f - * @param dm0 minimum acceptable number of -1's, 0's, and 1's in the polynomial m' in the last encryption step - * @param db number of random bits to prepend to the message - * @param c a parameter for the Index Generation Function ({@link IndexGenerator}) - * @param minCallsR minimum number of hash calls for the IGF to make - * @param minCallsMask minimum number of calls to generate the masking polynomial - * @param hashSeed whether to hash the seed in the MGF first (true) or use the seed directly (false) - * @param oid three bytes that uniquely identify the parameter set - * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial}) - * @param fastFp whether f=1+p*F for a ternary F (true) or f is ternary (false) - * @param hashAlg a valid identifier for a java.security.MessageDigest instance such as SHA-256. The MessageDigest must support the getDigestLength() method. - * @param random entropy source, if null uses {@link CryptoServicesRegistrar#getSecureRandom()} - */ - public NTRUEncryptionKeyGenerationParameters(int N, int q, int df, int dm0, int db, int c, int minCallsR, int minCallsMask, boolean hashSeed, byte[] oid, boolean sparse, boolean fastFp, Digest hashAlg, SecureRandom random) - { - super(null != random ? random : CryptoServicesRegistrar.getSecureRandom(), db); - this.N = N; - this.q = q; - this.df = df; - this.db = db; - this.dm0 = dm0; - this.c = c; - this.minCallsR = minCallsR; - this.minCallsMask = minCallsMask; - this.hashSeed = hashSeed; - this.oid = oid; - this.sparse = sparse; - this.fastFp = fastFp; - this.polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE; - this.hashAlg = hashAlg; - init(); - } - - /** - * Constructs a parameter set that uses ternary private keys (i.e. polyType=SIMPLE). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param df number of ones in the private polynomial f - * @param dm0 minimum acceptable number of -1's, 0's, and 1's in the polynomial m' in the last encryption step - * @param db number of random bits to prepend to the message - * @param c a parameter for the Index Generation Function ({@link org.bouncycastle.pqc.legacy.crypto.ntru.IndexGenerator}) - * @param minCallsR minimum number of hash calls for the IGF to make - * @param minCallsMask minimum number of calls to generate the masking polynomial - * @param hashSeed whether to hash the seed in the MGF first (true) or use the seed directly (false) - * @param oid three bytes that uniquely identify the parameter set - * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial}) - * @param fastFp whether f=1+p*F for a ternary F (true) or f is ternary (false) - * @param hashAlg a valid identifier for a java.security.MessageDigest instance such as SHA-256. The MessageDigest must support the getDigestLength() method. - */ - public NTRUEncryptionKeyGenerationParameters(int N, int q, int df, int dm0, int db, int c, int minCallsR, int minCallsMask, boolean hashSeed, byte[] oid, boolean sparse, boolean fastFp, Digest hashAlg) - { - this(N, q, df, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, hashAlg, null); - } - - /** - * Constructs a parameter set that uses product-form private keys (i.e. polyType=PRODUCT). - * @param N number of polynomial coefficients - * @param q modulus - * @param df1 number of ones in the private polynomial f1 - * @param df2 number of ones in the private polynomial f2 - * @param df3 number of ones in the private polynomial f3 - * @param dm0 minimum acceptable number of -1's, 0's, and 1's in the polynomial m' in the last encryption step - * @param db number of random bits to prepend to the message - * @param c a parameter for the Index Generation Function ({@link IndexGenerator}) - * @param minCallsR minimum number of hash calls for the IGF to make - * @param minCallsMask minimum number of calls to generate the masking polynomial - * @param hashSeed whether to hash the seed in the MGF first (true) or use the seed directly (false) - * @param oid three bytes that uniquely identify the parameter set - * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial}) - * @param fastFp whether f=1+p*F for a ternary F (true) or f is ternary (false) - * @param hashAlg a valid identifier for a java.security.MessageDigest instance such as SHA-256 - * @param random entropy source, if null uses {@link CryptoServicesRegistrar#getSecureRandom()} - */ - public NTRUEncryptionKeyGenerationParameters(int N, int q, int df1, int df2, int df3, int dm0, int db, int c, int minCallsR, int minCallsMask, boolean hashSeed, byte[] oid, boolean sparse, boolean fastFp, Digest hashAlg, SecureRandom random) - { - super(null != random ? random : CryptoServicesRegistrar.getSecureRandom(), db); - - this.N = N; - this.q = q; - this.df1 = df1; - this.df2 = df2; - this.df3 = df3; - this.db = db; - this.dm0 = dm0; - this.c = c; - this.minCallsR = minCallsR; - this.minCallsMask = minCallsMask; - this.hashSeed = hashSeed; - this.oid = oid; - this.sparse = sparse; - this.fastFp = fastFp; - this.polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT; - this.hashAlg = hashAlg; - init(); - } - - /** - * Constructs a parameter set that uses product-form private keys (i.e. polyType=PRODUCT). - * Uses {@link CryptoServicesRegistrar#getSecureRandom()} as an entropy source. - * - * @param N number of polynomial coefficients - * @param q modulus - * @param df1 number of ones in the private polynomial f1 - * @param df2 number of ones in the private polynomial f2 - * @param df3 number of ones in the private polynomial f3 - * @param dm0 minimum acceptable number of -1's, 0's, and 1's in the polynomial m' in the last encryption step - * @param db number of random bits to prepend to the message - * @param c a parameter for the Index Generation Function ({@link org.bouncycastle.pqc.legacy.crypto.ntru.IndexGenerator}) - * @param minCallsR minimum number of hash calls for the IGF to make - * @param minCallsMask minimum number of calls to generate the masking polynomial - * @param hashSeed whether to hash the seed in the MGF first (true) or use the seed directly (false) - * @param oid three bytes that uniquely identify the parameter set - * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial}) - * @param fastFp whether f=1+p*F for a ternary F (true) or f is ternary (false) - * @param hashAlg a valid identifier for a java.security.MessageDigest instance such as SHA-256 - */ - public NTRUEncryptionKeyGenerationParameters(int N, int q, int df1, int df2, int df3, int dm0, int db, int c, int minCallsR, int minCallsMask, boolean hashSeed, byte[] oid, boolean sparse, boolean fastFp, Digest hashAlg) - { - this(N, q, df1, df2, df3, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, hashAlg, null); - } - - private void init() - { - dr = df; - dr1 = df1; - dr2 = df2; - dr3 = df3; - dg = N / 3; - llen = 1; // ceil(log2(maxMsgLenBytes)) - maxMsgLenBytes = N * 3 / 2 / 8 - llen - db / 8 - 1; - bufferLenBits = (N * 3 / 2 + 7) / 8 * 8 + 1; - bufferLenTrits = N - 1; - pkLen = db; - } - - /** - * Reads a parameter set from an input stream. - * - * @param is an input stream - * @throws java.io.IOException - */ - public NTRUEncryptionKeyGenerationParameters(InputStream is) - throws IOException - { - super(CryptoServicesRegistrar.getSecureRandom(), -1); - DataInputStream dis = new DataInputStream(is); - N = dis.readInt(); - q = dis.readInt(); - df = dis.readInt(); - df1 = dis.readInt(); - df2 = dis.readInt(); - df3 = dis.readInt(); - db = dis.readInt(); - dm0 = dis.readInt(); - c = dis.readInt(); - minCallsR = dis.readInt(); - minCallsMask = dis.readInt(); - hashSeed = dis.readBoolean(); - oid = new byte[3]; - dis.readFully(oid); - sparse = dis.readBoolean(); - fastFp = dis.readBoolean(); - polyType = dis.read(); - - String alg = dis.readUTF(); - - if ("SHA-512".equals(alg)) - { - hashAlg = new SHA512Digest(); - } - else if ("SHA-256".equals(alg)) - { - hashAlg = new SHA256Digest(); - } - - init(); - } - - public NTRUEncryptionParameters getEncryptionParameters() - { - if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE) - { - return new NTRUEncryptionParameters(N, q, df, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, DigestFactory.cloneDigest(hashAlg)); - } - else - { - return new NTRUEncryptionParameters(N, q, df1, df2, df3, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, DigestFactory.cloneDigest(hashAlg)); - } - } - - public NTRUEncryptionKeyGenerationParameters clone() - { - if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE) - { - return new NTRUEncryptionKeyGenerationParameters(N, q, df, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, DigestFactory.cloneDigest(hashAlg)); - } - else - { - return new NTRUEncryptionKeyGenerationParameters(N, q, df1, df2, df3, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, DigestFactory.cloneDigest(hashAlg)); - } - } - - /** - * Returns the maximum length a plaintext message can be with this parameter set. - * - * @return the maximum length in bytes - */ - public int getMaxMessageLength() - { - return maxMsgLenBytes; - } - - /** - * Writes the parameter set to an output stream - * - * @param os an output stream - * @throws java.io.IOException - */ - public void writeTo(OutputStream os) - throws IOException - { - DataOutputStream dos = new DataOutputStream(os); - dos.writeInt(N); - dos.writeInt(q); - dos.writeInt(df); - dos.writeInt(df1); - dos.writeInt(df2); - dos.writeInt(df3); - dos.writeInt(db); - dos.writeInt(dm0); - dos.writeInt(c); - dos.writeInt(minCallsR); - dos.writeInt(minCallsMask); - dos.writeBoolean(hashSeed); - dos.write(oid); - dos.writeBoolean(sparse); - dos.writeBoolean(fastFp); - dos.write(polyType); - dos.writeUTF(hashAlg.getAlgorithmName()); - } - - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + N; - result = prime * result + bufferLenBits; - result = prime * result + bufferLenTrits; - result = prime * result + c; - result = prime * result + db; - result = prime * result + df; - result = prime * result + df1; - result = prime * result + df2; - result = prime * result + df3; - result = prime * result + dg; - result = prime * result + dm0; - result = prime * result + dr; - result = prime * result + dr1; - result = prime * result + dr2; - result = prime * result + dr3; - result = prime * result + (fastFp ? 1231 : 1237); - result = prime * result + ((hashAlg == null) ? 0 : hashAlg.getAlgorithmName().hashCode()); - result = prime * result + (hashSeed ? 1231 : 1237); - result = prime * result + llen; - result = prime * result + maxMsgLenBytes; - result = prime * result + minCallsMask; - result = prime * result + minCallsR; - result = prime * result + Arrays.hashCode(oid); - result = prime * result + pkLen; - result = prime * result + polyType; - result = prime * result + q; - result = prime * result + (sparse ? 1231 : 1237); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - NTRUEncryptionKeyGenerationParameters other = (NTRUEncryptionKeyGenerationParameters)obj; - if (N != other.N) - { - return false; - } - if (bufferLenBits != other.bufferLenBits) - { - return false; - } - if (bufferLenTrits != other.bufferLenTrits) - { - return false; - } - if (c != other.c) - { - return false; - } - if (db != other.db) - { - return false; - } - if (df != other.df) - { - return false; - } - if (df1 != other.df1) - { - return false; - } - if (df2 != other.df2) - { - return false; - } - if (df3 != other.df3) - { - return false; - } - if (dg != other.dg) - { - return false; - } - if (dm0 != other.dm0) - { - return false; - } - if (dr != other.dr) - { - return false; - } - if (dr1 != other.dr1) - { - return false; - } - if (dr2 != other.dr2) - { - return false; - } - if (dr3 != other.dr3) - { - return false; - } - if (fastFp != other.fastFp) - { - return false; - } - if (hashAlg == null) - { - if (other.hashAlg != null) - { - return false; - } - } - else if (!hashAlg.getAlgorithmName().equals(other.hashAlg.getAlgorithmName())) - { - return false; - } - if (hashSeed != other.hashSeed) - { - return false; - } - if (llen != other.llen) - { - return false; - } - if (maxMsgLenBytes != other.maxMsgLenBytes) - { - return false; - } - if (minCallsMask != other.minCallsMask) - { - return false; - } - if (minCallsR != other.minCallsR) - { - return false; - } - if (!Arrays.equals(oid, other.oid)) - { - return false; - } - if (pkLen != other.pkLen) - { - return false; - } - if (polyType != other.polyType) - { - return false; - } - if (q != other.q) - { - return false; - } - if (sparse != other.sparse) - { - return false; - } - return true; - } - - public String toString() - { - StringBuilder output = new StringBuilder("EncryptionParameters(N=" + N + " q=" + q); - if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE) - { - output.append(" polyType=SIMPLE df=" + df); - } - else - { - output.append(" polyType=PRODUCT df1=" + df1 + " df2=" + df2 + " df3=" + df3); - } - output.append(" dm0=" + dm0 + " db=" + db + " c=" + c + " minCallsR=" + minCallsR + " minCallsMask=" + minCallsMask + - " hashSeed=" + hashSeed + " hashAlg=" + hashAlg + " oid=" + Arrays.toString(oid) + " sparse=" + sparse + ")"); - return output.toString(); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionKeyPairGenerator.java deleted file mode 100644 index 308134f4a7..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionKeyPairGenerator.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.Polynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.ProductFormPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.util.Util; - -/** - * Generates key pairs.
    - * The parameter p is hardcoded to 3. - */ -public class NTRUEncryptionKeyPairGenerator - implements AsymmetricCipherKeyPairGenerator -{ - private NTRUEncryptionKeyGenerationParameters params; - - /** - * Constructs a new instance with a set of encryption parameters. - * - * @param param encryption parameters - */ - public void init(KeyGenerationParameters param) - { - this.params = (NTRUEncryptionKeyGenerationParameters)param; - } - - /** - * Generates a new encryption key pair. - * - * @return a key pair - */ - public AsymmetricCipherKeyPair generateKeyPair() - { - int N = params.N; - int q = params.q; - int df = params.df; - int df1 = params.df1; - int df2 = params.df2; - int df3 = params.df3; - int dg = params.dg; - boolean fastFp = params.fastFp; - boolean sparse = params.sparse; - - Polynomial t; - IntegerPolynomial fq; - IntegerPolynomial fp = null; - - // choose a random f that is invertible mod 3 and q - while (true) - { - IntegerPolynomial f; - - // choose random t, calculate f and fp - if (fastFp) - { - // if fastFp=true, f is always invertible mod 3 - t = params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? Util.generateRandomTernary(N, df, df, sparse, params.getRandom()) : ProductFormPolynomial.generateRandom(N, df1, df2, df3, df3, params.getRandom()); - f = t.toIntegerPolynomial(); - f.mult(3); - f.coeffs[0] += 1; - } - else - { - t = params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? Util.generateRandomTernary(N, df, df - 1, sparse, params.getRandom()) : ProductFormPolynomial.generateRandom(N, df1, df2, df3, df3 - 1, params.getRandom()); - f = t.toIntegerPolynomial(); - fp = f.invertF3(); - if (fp == null) - { - continue; - } - } - - fq = f.invertFq(q); - if (fq == null) - { - continue; - } - break; - } - - // if fastFp=true, fp=1 - if (fastFp) - { - fp = new IntegerPolynomial(N); - fp.coeffs[0] = 1; - } - - // choose a random g that is invertible mod q - DenseTernaryPolynomial g; - while (true) - { - g = DenseTernaryPolynomial.generateRandom(N, dg, dg - 1, params.getRandom()); - if (g.invertFq(q) != null) - { - break; - } - } - - IntegerPolynomial h = g.mult(fq, q); - h.mult3(q); - h.ensurePositive(q); - g.clear(); - fq.clear(); - - NTRUEncryptionPrivateKeyParameters priv = new NTRUEncryptionPrivateKeyParameters(h, t, fp, params.getEncryptionParameters()); - NTRUEncryptionPublicKeyParameters pub = new NTRUEncryptionPublicKeyParameters(h, params.getEncryptionParameters()); - return new AsymmetricCipherKeyPair(pub, priv); - } -} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionKeyParameters.java deleted file mode 100644 index 3b2a82c91c..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionKeyParameters.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; - -public class NTRUEncryptionKeyParameters - extends AsymmetricKeyParameter -{ - final protected NTRUEncryptionParameters params; - - public NTRUEncryptionKeyParameters(boolean privateKey, NTRUEncryptionParameters params) - { - super(privateKey); - this.params = params; - } - - public NTRUEncryptionParameters getParameters() - { - return params; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionParameters.java deleted file mode 100644 index babf38decd..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionParameters.java +++ /dev/null @@ -1,411 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Arrays; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; -import org.bouncycastle.crypto.util.DigestFactory; - -/** - * A set of parameters for NtruEncrypt. Several predefined parameter sets are available and new ones can be created as well. - */ -public class NTRUEncryptionParameters - implements Cloneable -{ - - public int N, q, df, df1, df2, df3; - public int dr; - public int dr1; - public int dr2; - public int dr3; - public int dg; - int llen; - public int maxMsgLenBytes; - public int db; - public int bufferLenBits; - int bufferLenTrits; - public int dm0; - public int pkLen; - public int c; - public int minCallsR; - public int minCallsMask; - public boolean hashSeed; - public byte[] oid; - public boolean sparse; - public boolean fastFp; - public int polyType; - public Digest hashAlg; - - /** - * Constructs a parameter set that uses ternary private keys (i.e. polyType=SIMPLE). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param df number of ones in the private polynomial f - * @param dm0 minimum acceptable number of -1's, 0's, and 1's in the polynomial m' in the last encryption step - * @param db number of random bits to prepend to the message - * @param c a parameter for the Index Generation Function ({@link org.bouncycastle.pqc.legacy.crypto.ntru.IndexGenerator}) - * @param minCallsR minimum number of hash calls for the IGF to make - * @param minCallsMask minimum number of calls to generate the masking polynomial - * @param hashSeed whether to hash the seed in the MGF first (true) or use the seed directly (false) - * @param oid three bytes that uniquely identify the parameter set - * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial}) - * @param fastFp whether f=1+p*F for a ternary F (true) or f is ternary (false) - * @param hashAlg a valid identifier for a java.security.MessageDigest instance such as SHA-256. The MessageDigest must support the getDigestLength() method. - */ - public NTRUEncryptionParameters(int N, int q, int df, int dm0, int db, int c, int minCallsR, int minCallsMask, boolean hashSeed, byte[] oid, boolean sparse, boolean fastFp, Digest hashAlg) - { - this.N = N; - this.q = q; - this.df = df; - this.db = db; - this.dm0 = dm0; - this.c = c; - this.minCallsR = minCallsR; - this.minCallsMask = minCallsMask; - this.hashSeed = hashSeed; - this.oid = oid; - this.sparse = sparse; - this.fastFp = fastFp; - this.polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE; - this.hashAlg = hashAlg; - init(); - } - - /** - * Constructs a parameter set that uses product-form private keys (i.e. polyType=PRODUCT). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param df1 number of ones in the private polynomial f1 - * @param df2 number of ones in the private polynomial f2 - * @param df3 number of ones in the private polynomial f3 - * @param dm0 minimum acceptable number of -1's, 0's, and 1's in the polynomial m' in the last encryption step - * @param db number of random bits to prepend to the message - * @param c a parameter for the Index Generation Function ({@link org.bouncycastle.pqc.legacy.crypto.ntru.IndexGenerator}) - * @param minCallsR minimum number of hash calls for the IGF to make - * @param minCallsMask minimum number of calls to generate the masking polynomial - * @param hashSeed whether to hash the seed in the MGF first (true) or use the seed directly (false) - * @param oid three bytes that uniquely identify the parameter set - * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial}) - * @param fastFp whether f=1+p*F for a ternary F (true) or f is ternary (false) - * @param hashAlg a valid identifier for a java.security.MessageDigest instance such as SHA-256 - */ - public NTRUEncryptionParameters(int N, int q, int df1, int df2, int df3, int dm0, int db, int c, int minCallsR, int minCallsMask, boolean hashSeed, byte[] oid, boolean sparse, boolean fastFp, Digest hashAlg) - { - this.N = N; - this.q = q; - this.df1 = df1; - this.df2 = df2; - this.df3 = df3; - this.db = db; - this.dm0 = dm0; - this.c = c; - this.minCallsR = minCallsR; - this.minCallsMask = minCallsMask; - this.hashSeed = hashSeed; - this.oid = oid; - this.sparse = sparse; - this.fastFp = fastFp; - this.polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT; - this.hashAlg = hashAlg; - init(); - } - - private void init() - { - dr = df; - dr1 = df1; - dr2 = df2; - dr3 = df3; - dg = N / 3; - llen = 1; // ceil(log2(maxMsgLenBytes)) - maxMsgLenBytes = N * 3 / 2 / 8 - llen - db / 8 - 1; - bufferLenBits = (N * 3 / 2 + 7) / 8 * 8 + 1; - bufferLenTrits = N - 1; - pkLen = db; - } - - /** - * Reads a parameter set from an input stream. - * - * @param is an input stream - * @throws IOException - */ - public NTRUEncryptionParameters(InputStream is) - throws IOException - { - DataInputStream dis = new DataInputStream(is); - N = dis.readInt(); - q = dis.readInt(); - df = dis.readInt(); - df1 = dis.readInt(); - df2 = dis.readInt(); - df3 = dis.readInt(); - db = dis.readInt(); - dm0 = dis.readInt(); - c = dis.readInt(); - minCallsR = dis.readInt(); - minCallsMask = dis.readInt(); - hashSeed = dis.readBoolean(); - oid = new byte[3]; - dis.read(oid); - sparse = dis.readBoolean(); - fastFp = dis.readBoolean(); - polyType = dis.read(); - - String alg = dis.readUTF(); - - if ("SHA-512".equals(alg)) - { - hashAlg = new SHA512Digest(); - } - else if ("SHA-256".equals(alg)) - { - hashAlg = new SHA256Digest(); - } - - init(); - } - - public NTRUEncryptionParameters clone() - { - if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE) - { - return new NTRUEncryptionParameters(N, q, df, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, DigestFactory.cloneDigest(hashAlg)); - } - else - { - return new NTRUEncryptionParameters(N, q, df1, df2, df3, dm0, db, c, minCallsR, minCallsMask, hashSeed, oid, sparse, fastFp, DigestFactory.cloneDigest(hashAlg)); - } - } - - /** - * Returns the maximum length a plaintext message can be with this parameter set. - * - * @return the maximum length in bytes - */ - public int getMaxMessageLength() - { - return maxMsgLenBytes; - } - - /** - * Writes the parameter set to an output stream - * - * @param os an output stream - * @throws IOException - */ - public void writeTo(OutputStream os) - throws IOException - { - DataOutputStream dos = new DataOutputStream(os); - dos.writeInt(N); - dos.writeInt(q); - dos.writeInt(df); - dos.writeInt(df1); - dos.writeInt(df2); - dos.writeInt(df3); - dos.writeInt(db); - dos.writeInt(dm0); - dos.writeInt(c); - dos.writeInt(minCallsR); - dos.writeInt(minCallsMask); - dos.writeBoolean(hashSeed); - dos.write(oid); - dos.writeBoolean(sparse); - dos.writeBoolean(fastFp); - dos.write(polyType); - dos.writeUTF(hashAlg.getAlgorithmName()); - } - - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + N; - result = prime * result + bufferLenBits; - result = prime * result + bufferLenTrits; - result = prime * result + c; - result = prime * result + db; - result = prime * result + df; - result = prime * result + df1; - result = prime * result + df2; - result = prime * result + df3; - result = prime * result + dg; - result = prime * result + dm0; - result = prime * result + dr; - result = prime * result + dr1; - result = prime * result + dr2; - result = prime * result + dr3; - result = prime * result + (fastFp ? 1231 : 1237); - result = prime * result + ((hashAlg == null) ? 0 : hashAlg.getAlgorithmName().hashCode()); - result = prime * result + (hashSeed ? 1231 : 1237); - result = prime * result + llen; - result = prime * result + maxMsgLenBytes; - result = prime * result + minCallsMask; - result = prime * result + minCallsR; - result = prime * result + Arrays.hashCode(oid); - result = prime * result + pkLen; - result = prime * result + polyType; - result = prime * result + q; - result = prime * result + (sparse ? 1231 : 1237); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - NTRUEncryptionParameters other = (NTRUEncryptionParameters)obj; - if (N != other.N) - { - return false; - } - if (bufferLenBits != other.bufferLenBits) - { - return false; - } - if (bufferLenTrits != other.bufferLenTrits) - { - return false; - } - if (c != other.c) - { - return false; - } - if (db != other.db) - { - return false; - } - if (df != other.df) - { - return false; - } - if (df1 != other.df1) - { - return false; - } - if (df2 != other.df2) - { - return false; - } - if (df3 != other.df3) - { - return false; - } - if (dg != other.dg) - { - return false; - } - if (dm0 != other.dm0) - { - return false; - } - if (dr != other.dr) - { - return false; - } - if (dr1 != other.dr1) - { - return false; - } - if (dr2 != other.dr2) - { - return false; - } - if (dr3 != other.dr3) - { - return false; - } - if (fastFp != other.fastFp) - { - return false; - } - if (hashAlg == null) - { - if (other.hashAlg != null) - { - return false; - } - } - else if (!hashAlg.getAlgorithmName().equals(other.hashAlg.getAlgorithmName())) - { - return false; - } - if (hashSeed != other.hashSeed) - { - return false; - } - if (llen != other.llen) - { - return false; - } - if (maxMsgLenBytes != other.maxMsgLenBytes) - { - return false; - } - if (minCallsMask != other.minCallsMask) - { - return false; - } - if (minCallsR != other.minCallsR) - { - return false; - } - if (!Arrays.equals(oid, other.oid)) - { - return false; - } - if (pkLen != other.pkLen) - { - return false; - } - if (polyType != other.polyType) - { - return false; - } - if (q != other.q) - { - return false; - } - if (sparse != other.sparse) - { - return false; - } - return true; - } - - public String toString() - { - StringBuilder output = new StringBuilder("EncryptionParameters(N=" + N + " q=" + q); - if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE) - { - output.append(" polyType=SIMPLE df=" + df); - } - else - { - output.append(" polyType=PRODUCT df1=" + df1 + " df2=" + df2 + " df3=" + df3); - } - output.append(" dm0=" + dm0 + " db=" + db + " c=" + c + " minCallsR=" + minCallsR + " minCallsMask=" + minCallsMask + - " hashSeed=" + hashSeed + " hashAlg=" + hashAlg + " oid=" + Arrays.toString(oid) + " sparse=" + sparse + ")"); - return output.toString(); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionPrivateKeyParameters.java deleted file mode 100644 index d36dbe7c12..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionPrivateKeyParameters.java +++ /dev/null @@ -1,199 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.Polynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.ProductFormPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.SparseTernaryPolynomial; - -/** - * A NtruEncrypt private key is essentially a polynomial named f - * which takes different forms depending on whether product-form polynomials are used, - * and on fastP
    - * The inverse of f modulo p is precomputed on initialization. - */ -public class NTRUEncryptionPrivateKeyParameters - extends NTRUEncryptionKeyParameters -{ - public Polynomial t; - public IntegerPolynomial fp; - public IntegerPolynomial h; - - /** - * Constructs a new private key from a polynomial - * - * @param h the public polynomial for the key. - * @param t the polynomial which determines the key: if fastFp=true, f=1+3t; otherwise, f=t - * @param fp the inverse of f - * @param params the NtruEncrypt parameters to use - */ - public NTRUEncryptionPrivateKeyParameters(IntegerPolynomial h, Polynomial t, IntegerPolynomial fp, NTRUEncryptionParameters params) - { - super(true, params); - - this.h = h; - this.t = t; - this.fp = fp; - } - - /** - * Converts a byte array to a polynomial f and constructs a new private key - * - * @param b an encoded polynomial - * @param params the NtruEncrypt parameters to use - * @see #getEncoded() - */ - public NTRUEncryptionPrivateKeyParameters(byte[] b, NTRUEncryptionParameters params) - throws IOException - { - this(new ByteArrayInputStream(b), params); - } - - /** - * Reads a polynomial f from an input stream and constructs a new private key - * - * @param is an input stream - * @param params the NtruEncrypt parameters to use - * @see #writeTo(OutputStream) - */ - public NTRUEncryptionPrivateKeyParameters(InputStream is, NTRUEncryptionParameters params) - throws IOException - { - super(true, params); - - if (params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT) - { - int N = params.N; - int df1 = params.df1; - int df2 = params.df2; - int df3Ones = params.df3; - int df3NegOnes = params.fastFp ? params.df3 : params.df3 - 1; - h = IntegerPolynomial.fromBinary(is, params.N, params.q); - t = ProductFormPolynomial.fromBinary(is, N, df1, df2, df3Ones, df3NegOnes); - } - else - { - h = IntegerPolynomial.fromBinary(is, params.N, params.q); - IntegerPolynomial fInt = IntegerPolynomial.fromBinary3Tight(is, params.N); - t = params.sparse ? new SparseTernaryPolynomial(fInt) : new DenseTernaryPolynomial(fInt); - } - - init(); - } - - /** - * Initializes fp from t. - */ - private void init() - { - if (params.fastFp) - { - fp = new IntegerPolynomial(params.N); - fp.coeffs[0] = 1; - } - else - { - fp = t.toIntegerPolynomial().invertF3(); - } - } - - /** - * Converts the key to a byte array - * - * @return the encoded key - * @see #NTRUEncryptionPrivateKeyParameters(byte[], NTRUEncryptionParameters) - */ - public byte[] getEncoded() - { - byte[] hBytes = h.toBinary(params.q); - byte[] tBytes; - - if (t instanceof ProductFormPolynomial) - { - tBytes = ((ProductFormPolynomial)t).toBinary(); - } - else - { - tBytes = t.toIntegerPolynomial().toBinary3Tight(); - } - - byte[] res = new byte[hBytes.length + tBytes.length]; - - System.arraycopy(hBytes, 0, res, 0, hBytes.length); - System.arraycopy(tBytes, 0, res, hBytes.length, tBytes.length); - - return res; - } - - /** - * Writes the key to an output stream - * - * @param os an output stream - * @throws IOException - * @see #NTRUEncryptionPrivateKeyParameters(InputStream, NTRUEncryptionParameters) - */ - public void writeTo(OutputStream os) - throws IOException - { - os.write(getEncoded()); - } - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((params == null) ? 0 : params.hashCode()); - result = prime * result + ((t == null) ? 0 : t.hashCode()); - result = prime * result + ((h == null) ? 0 : h.hashCode()); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (!(obj instanceof NTRUEncryptionPrivateKeyParameters)) - { - return false; - } - NTRUEncryptionPrivateKeyParameters other = (NTRUEncryptionPrivateKeyParameters)obj; - if (params == null) - { - if (other.params != null) - { - return false; - } - } - else if (!params.equals(other.params)) - { - return false; - } - if (t == null) - { - if (other.t != null) - { - return false; - } - } - else if (!t.equals(other.t)) - { - return false; - } - if (!h.equals(other.h)) - { - return false; - } - return true; - } -} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionPublicKeyParameters.java deleted file mode 100644 index 91380f36f5..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEncryptionPublicKeyParameters.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; - -/** - * A NtruEncrypt public key is essentially a polynomial named h. - */ -public class NTRUEncryptionPublicKeyParameters - extends NTRUEncryptionKeyParameters -{ - public IntegerPolynomial h; - - /** - * Constructs a new public key from a polynomial - * - * @param h the polynomial h which determines the key - * @param params the NtruEncrypt parameters to use - */ - public NTRUEncryptionPublicKeyParameters(IntegerPolynomial h, NTRUEncryptionParameters params) - { - super(false, params); - - this.h = h; - } - - /** - * Converts a byte array to a polynomial h and constructs a new public key - * - * @param b an encoded polynomial - * @param params the NtruEncrypt parameters to use - * @see #getEncoded() - */ - public NTRUEncryptionPublicKeyParameters(byte[] b, NTRUEncryptionParameters params) - { - super(false, params); - - h = IntegerPolynomial.fromBinary(b, params.N, params.q); - } - - /** - * Reads a polynomial h from an input stream and constructs a new public key - * - * @param is an input stream - * @param params the NtruEncrypt parameters to use - * @see #writeTo(OutputStream) - */ - public NTRUEncryptionPublicKeyParameters(InputStream is, NTRUEncryptionParameters params) - throws IOException - { - super(false, params); - - h = IntegerPolynomial.fromBinary(is, params.N, params.q); - } - - /** - * Converts the key to a byte array - * - * @return the encoded key - * @see #NTRUEncryptionPublicKeyParameters(byte[], NTRUEncryptionParameters) - */ - public byte[] getEncoded() - { - return h.toBinary(params.q); - } - - /** - * Writes the key to an output stream - * - * @param os an output stream - * @throws IOException - * @see #NTRUEncryptionPublicKeyParameters(InputStream, NTRUEncryptionParameters) - */ - public void writeTo(OutputStream os) - throws IOException - { - os.write(getEncoded()); - } - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((h == null) ? 0 : h.hashCode()); - result = prime * result + ((params == null) ? 0 : params.hashCode()); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (!(obj instanceof NTRUEncryptionPublicKeyParameters)) - { - return false; - } - NTRUEncryptionPublicKeyParameters other = (NTRUEncryptionPublicKeyParameters)obj; - if (h == null) - { - if (other.h != null) - { - return false; - } - } - else if (!h.equals(other.h)) - { - return false; - } - if (params == null) - { - if (other.params != null) - { - return false; - } - } - else if (!params.equals(other.params)) - { - return false; - } - return true; - } -} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEngine.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEngine.java deleted file mode 100644 index 79f6769c93..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUEngine.java +++ /dev/null @@ -1,496 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.AsymmetricBlockCipher; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.CryptoServicesRegistrar; -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.Polynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.ProductFormPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.SparseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.TernaryPolynomial; -import org.bouncycastle.util.Arrays; - -/** - * Encrypts, decrypts data and generates key pairs.
    - * The parameter p is hardcoded to 3. - */ -public class NTRUEngine - implements AsymmetricBlockCipher -{ - private boolean forEncryption; - private NTRUEncryptionParameters params; - private NTRUEncryptionPublicKeyParameters pubKey; - private NTRUEncryptionPrivateKeyParameters privKey; - private SecureRandom random; - - /** - * Constructs a new instance with a set of encryption parameters. - * - */ - public NTRUEngine() - { - } - - public void init(boolean forEncryption, CipherParameters parameters) - { - this.forEncryption = forEncryption; - - SecureRandom providedRandom = null; - if (parameters instanceof ParametersWithRandom) - { - ParametersWithRandom withRandom = (ParametersWithRandom)parameters; - providedRandom = withRandom.getRandom(); - parameters = withRandom.getParameters(); - } - - if (forEncryption) - { - this.pubKey = (NTRUEncryptionPublicKeyParameters)parameters; - this.privKey = null; - this.params = pubKey.getParameters(); - this.random = CryptoServicesRegistrar.getSecureRandom(providedRandom); - } - else - { - this.pubKey = null; - this.privKey = (NTRUEncryptionPrivateKeyParameters)parameters; - this.params = privKey.getParameters(); - this.random = null; - } - } - - public int getInputBlockSize() - { - return params.maxMsgLenBytes; - } - - public int getOutputBlockSize() - { - return ((params.N * log2(params.q)) + 7) / 8; - } - - public byte[] processBlock(byte[] in, int inOff, int len) - throws InvalidCipherTextException - { - byte[] tmp = new byte[len]; - - System.arraycopy(in, inOff, tmp, 0, len); - - if (forEncryption) - { - return encrypt(tmp, pubKey); - } - else - { - return decrypt(tmp, privKey); - } - } - - /** - * Encrypts a message.
    - * See P1363.1 section 9.2.2. - * - * @param m The message to encrypt - * @param pubKey the public key to encrypt the message with - * @return the encrypted message - */ - private byte[] encrypt(byte[] m, NTRUEncryptionPublicKeyParameters pubKey) - { - IntegerPolynomial pub = pubKey.h; - int N = params.N; - int q = params.q; - - int maxLenBytes = params.maxMsgLenBytes; - int db = params.db; - int bufferLenBits = params.bufferLenBits; - int dm0 = params.dm0; - int pkLen = params.pkLen; - int minCallsMask = params.minCallsMask; - boolean hashSeed = params.hashSeed; - byte[] oid = params.oid; - - int l = m.length; - if (maxLenBytes > 255) - { - throw new IllegalArgumentException("llen values bigger than 1 are not supported"); - } - if (l > maxLenBytes) - { - throw new DataLengthException("Message too long: " + l + ">" + maxLenBytes); - } - - while (true) - { - // M = b|octL|m|p0 - byte[] b = new byte[db / 8]; - random.nextBytes(b); - byte[] p0 = new byte[maxLenBytes + 1 - l]; - byte[] M = new byte[bufferLenBits / 8]; - - System.arraycopy(b, 0, M, 0, b.length); - M[b.length] = (byte)l; - System.arraycopy(m, 0, M, b.length + 1, m.length); - System.arraycopy(p0, 0, M, b.length + 1 + m.length, p0.length); - - IntegerPolynomial mTrin = IntegerPolynomial.fromBinary3Sves(M, N); - - // sData = OID|m|b|hTrunc - byte[] bh = pub.toBinary(q); - byte[] hTrunc = copyOf(bh, pkLen / 8); - byte[] sData = buildSData(oid, m, l, b, hTrunc); - - Polynomial r = generateBlindingPoly(sData, M); - IntegerPolynomial R = r.mult(pub, q); - IntegerPolynomial R4 = (IntegerPolynomial)R.clone(); - R4.modPositive(4); - byte[] oR4 = R4.toBinary(4); - IntegerPolynomial mask = MGF(oR4, N, minCallsMask, hashSeed); - mTrin.add(mask); - mTrin.mod3(); - - if (mTrin.count(-1) < dm0) - { - continue; - } - if (mTrin.count(0) < dm0) - { - continue; - } - if (mTrin.count(1) < dm0) - { - continue; - } - - R.add(mTrin, q); - R.ensurePositive(q); - return R.toBinary(q); - } - } - - private byte[] buildSData(byte[] oid, byte[] m, int l, byte[] b, byte[] hTrunc) - { - byte[] sData = new byte[oid.length + l + b.length + hTrunc.length]; - - System.arraycopy(oid, 0, sData, 0, oid.length); - System.arraycopy(m, 0, sData, oid.length, m.length); - System.arraycopy(b, 0, sData, oid.length + m.length, b.length); - System.arraycopy(hTrunc, 0, sData, oid.length + m.length + b.length, hTrunc.length); - return sData; - } - - protected IntegerPolynomial encrypt(IntegerPolynomial m, TernaryPolynomial r, IntegerPolynomial pubKey) - { - IntegerPolynomial e = r.mult(pubKey, params.q); - e.add(m, params.q); - e.ensurePositive(params.q); - return e; - } - - /** - * Deterministically generates a blinding polynomial from a seed and a message representative. - * - * @param seed - * @param M message representative - * @return a blinding polynomial - */ - private Polynomial generateBlindingPoly(byte[] seed, byte[] M) - { - IndexGenerator ig = new IndexGenerator(seed, params); - - if (params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT) - { - SparseTernaryPolynomial r1 = new SparseTernaryPolynomial(generateBlindingCoeffs(ig, params.dr1)); - SparseTernaryPolynomial r2 = new SparseTernaryPolynomial(generateBlindingCoeffs(ig, params.dr2)); - SparseTernaryPolynomial r3 = new SparseTernaryPolynomial(generateBlindingCoeffs(ig, params.dr3)); - return new ProductFormPolynomial(r1, r2, r3); - } - else - { - int dr = params.dr; - boolean sparse = params.sparse; - int[] r = generateBlindingCoeffs(ig, dr); - if (sparse) - { - return new SparseTernaryPolynomial(r); - } - else - { - return new DenseTernaryPolynomial(r); - } - } - } - - /** - * Generates an int array containing dr elements equal to 1 - * and dr elements equal to -1 using an index generator. - * - * @param ig an index generator - * @param dr number of ones / negative ones - * @return an array containing numbers between -1 and 1 - */ - private int[] generateBlindingCoeffs(IndexGenerator ig, int dr) - { - int N = params.N; - - int[] r = new int[N]; - for (int coeff = -1; coeff <= 1; coeff += 2) - { - int t = 0; - while (t < dr) - { - int i = ig.nextIndex(); - if (r[i] == 0) - { - r[i] = coeff; - t++; - } - } - } - - return r; - } - - /** - * An implementation of MGF-TP-1 from P1363.1 section 8.4.1.1. - * - * @param seed - * @param N - * @param minCallsR - * @param hashSeed whether to hash the seed - */ - private IntegerPolynomial MGF(byte[] seed, int N, int minCallsR, boolean hashSeed) - { - Digest hashAlg = params.hashAlg; - int hashLen = hashAlg.getDigestSize(); - byte[] buf = new byte[minCallsR * hashLen]; - byte[] Z = hashSeed ? calcHash(hashAlg, seed) : seed; - int counter = 0; - while (counter < minCallsR) - { - hashAlg.update(Z, 0, Z.length); - putInt(hashAlg, counter); - - byte[] hash = calcHash(hashAlg); - System.arraycopy(hash, 0, buf, counter * hashLen, hashLen); - counter++; - } - - IntegerPolynomial i = new IntegerPolynomial(N); - while (true) - { - int cur = 0; - for (int index = 0; index != buf.length; index++) - { - int O = (int)buf[index] & 0xFF; - if (O >= 243) // 243 = 3^5 - { - continue; - } - - for (int terIdx = 0; terIdx < 4; terIdx++) - { - int rem3 = O % 3; - i.coeffs[cur] = rem3 - 1; - cur++; - if (cur == N) - { - return i; - } - O = (O - rem3) / 3; - } - - i.coeffs[cur] = O - 1; - cur++; - if (cur == N) - { - return i; - } - } - - if (cur >= N) - { - return i; - } - - hashAlg.update(Z, 0, Z.length); - putInt(hashAlg, counter); - - byte[] hash = calcHash(hashAlg); - - buf = hash; - - counter++; - } - } - - private void putInt(Digest hashAlg, int counter) - { - hashAlg.update((byte)(counter >> 24)); - hashAlg.update((byte)(counter >> 16)); - hashAlg.update((byte)(counter >> 8)); - hashAlg.update((byte)counter); - } - - private byte[] calcHash(Digest hashAlg) - { - byte[] tmp = new byte[hashAlg.getDigestSize()]; - - hashAlg.doFinal(tmp, 0); - - return tmp; - } - - private byte[] calcHash(Digest hashAlg, byte[] input) - { - byte[] tmp = new byte[hashAlg.getDigestSize()]; - - hashAlg.update(input, 0, input.length); - hashAlg.doFinal(tmp, 0); - - return tmp; - } - /** - * Decrypts a message.
    - * See P1363.1 section 9.2.3. - * - * @param data The message to decrypt - * @param privKey the corresponding private key - * @return the decrypted message - * @throws InvalidCipherTextException if the encrypted data is invalid, or maxLenBytes is greater than 255 - */ - private byte[] decrypt(byte[] data, NTRUEncryptionPrivateKeyParameters privKey) - throws InvalidCipherTextException - { - Polynomial priv_t = privKey.t; - IntegerPolynomial priv_fp = privKey.fp; - IntegerPolynomial pub = privKey.h; - int N = params.N; - int q = params.q; - int db = params.db; - int maxMsgLenBytes = params.maxMsgLenBytes; - int dm0 = params.dm0; - int pkLen = params.pkLen; - int minCallsMask = params.minCallsMask; - boolean hashSeed = params.hashSeed; - byte[] oid = params.oid; - - if (maxMsgLenBytes > 255) - { - throw new DataLengthException("maxMsgLenBytes values bigger than 255 are not supported"); - } - - int bLen = db / 8; - - IntegerPolynomial e = IntegerPolynomial.fromBinary(data, N, q); - IntegerPolynomial ci = decrypt(e, priv_t, priv_fp); - - if (ci.count(-1) < dm0) - { - throw new InvalidCipherTextException("Less than dm0 coefficients equal -1"); - } - if (ci.count(0) < dm0) - { - throw new InvalidCipherTextException("Less than dm0 coefficients equal 0"); - } - if (ci.count(1) < dm0) - { - throw new InvalidCipherTextException("Less than dm0 coefficients equal 1"); - } - - IntegerPolynomial cR = (IntegerPolynomial)e.clone(); - cR.sub(ci); - cR.modPositive(q); - IntegerPolynomial cR4 = (IntegerPolynomial)cR.clone(); - cR4.modPositive(4); - byte[] coR4 = cR4.toBinary(4); - IntegerPolynomial mask = MGF(coR4, N, minCallsMask, hashSeed); - IntegerPolynomial cMTrin = ci; - cMTrin.sub(mask); - cMTrin.mod3(); - byte[] cM = cMTrin.toBinary3Sves(); - - byte[] cb = new byte[bLen]; - System.arraycopy(cM, 0, cb, 0, bLen); - int cl = cM[bLen] & 0xFF; // llen=1, so read one byte - if (cl > maxMsgLenBytes) - { - throw new InvalidCipherTextException("Message too long: " + cl + ">" + maxMsgLenBytes); - } - byte[] cm = new byte[cl]; - System.arraycopy(cM, bLen + 1, cm, 0, cl); - byte[] p0 = new byte[cM.length - (bLen + 1 + cl)]; - System.arraycopy(cM, bLen + 1 + cl, p0, 0, p0.length); - if (!Arrays.constantTimeAreEqual(p0, new byte[p0.length])) - { - throw new InvalidCipherTextException("The message is not followed by zeroes"); - } - - // sData = OID|m|b|hTrunc - byte[] bh = pub.toBinary(q); - byte[] hTrunc = copyOf(bh, pkLen / 8); - byte[] sData = buildSData(oid, cm, cl, cb, hTrunc); - - Polynomial cr = generateBlindingPoly(sData, cm); - IntegerPolynomial cRPrime = cr.mult(pub); - cRPrime.modPositive(q); - if (!cRPrime.equals(cR)) - { - throw new InvalidCipherTextException("Invalid message encoding"); - } - - return cm; - } - - /** - * @param e - * @param priv_t a polynomial such that if fastFp=true, f=1+3*priv_t; otherwise, f=priv_t - * @param priv_fp - * @return an IntegerPolynomial representing the output. - */ - protected IntegerPolynomial decrypt(IntegerPolynomial e, Polynomial priv_t, IntegerPolynomial priv_fp) - { - IntegerPolynomial a; - if (params.fastFp) - { - a = priv_t.mult(e, params.q); - a.mult(3); - a.add(e); - } - else - { - a = priv_t.mult(e, params.q); - } - a.center0(params.q); - a.mod3(); - - IntegerPolynomial c = params.fastFp ? a : new DenseTernaryPolynomial(a).mult(priv_fp, 3); - c.center0(3); - return c; - } - - private byte[] copyOf(byte[] src, int len) - { - byte[] tmp = new byte[len]; - - System.arraycopy(src, 0, tmp, 0, len < src.length ? len : src.length); - - return tmp; - } - - private int log2(int value) - { - if (value == 2048) - { - return 11; - } - - throw new IllegalStateException("log2 not fully implemented"); - } -} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUParameters.java deleted file mode 100644 index bc98348519..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUParameters.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -public class NTRUParameters -{ - public static final int TERNARY_POLYNOMIAL_TYPE_SIMPLE = 0; - public static final int TERNARY_POLYNOMIAL_TYPE_PRODUCT = 1; -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigner.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigner.java deleted file mode 100644 index 43733af6c4..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigner.java +++ /dev/null @@ -1,263 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import java.nio.ByteBuffer; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.Polynomial; - -/** -* Signs, verifies data and generates key pairs. -* @deprecated the NTRUSigner algorithm was broken in 2012 by Ducas and Nguyen. See -* -* https://www.di.ens.fr/~ducas/NTRUSign_Cryptanalysis/DucasNguyen_Learning.pdf -* for details. -*/ -public class NTRUSigner -{ - private NTRUSigningParameters params; - private Digest hashAlg; - private NTRUSigningPrivateKeyParameters signingKeyPair; - private NTRUSigningPublicKeyParameters verificationKey; - - /** - * Constructs a new instance with a set of signature parameters. - * - * @param params signature parameters - */ - public NTRUSigner(NTRUSigningParameters params) - { - this.params = params; - } - - /** - * Resets the engine for signing a message. - * - * @param forSigning - * @param params - */ - public void init(boolean forSigning, CipherParameters params) - { - if (forSigning) - { - this.signingKeyPair = (NTRUSigningPrivateKeyParameters)params; - } - else - { - this.verificationKey = (NTRUSigningPublicKeyParameters)params; - } - hashAlg = this.params.hashAlg; - hashAlg.reset(); - } - - /** - * Adds data to sign or verify. - * - * @param b data - */ - public void update(byte b) - { - if (hashAlg == null) - { - throw new IllegalStateException("Call initSign or initVerify first!"); - } - - hashAlg.update(b); - } - - /** - * Adds data to sign or verify. - * - * @param m data - * @param off offset - * @param length number of bytes - */ - public void update(byte[] m, int off, int length) - { - if (hashAlg == null) - { - throw new IllegalStateException("Call initSign or initVerify first!"); - } - - hashAlg.update(m, off, length); - } - - /** - * Adds data to sign and computes a signature over this data and any data previously added via {@link #update(byte[], int, int)}. - * - * @return a signature - * @throws IllegalStateException if initSign was not called - */ - public byte[] generateSignature() - { - if (hashAlg == null || signingKeyPair == null) - { - throw new IllegalStateException("Call initSign first!"); - } - - byte[] msgHash = new byte[hashAlg.getDigestSize()]; - - hashAlg.doFinal(msgHash, 0); - return signHash(msgHash, signingKeyPair); - } - - private byte[] signHash(byte[] msgHash, NTRUSigningPrivateKeyParameters kp) - { - int r = 0; - IntegerPolynomial s; - IntegerPolynomial i; - - NTRUSigningPublicKeyParameters kPub = kp.getPublicKey(); - do - { - r++; - if (r > params.signFailTolerance) - { - throw new IllegalStateException("Signing failed: too many retries (max=" + params.signFailTolerance + ")"); - } - i = createMsgRep(msgHash, r); - s = sign(i, kp); - } - while (!verify(i, s, kPub.h)); - - byte[] rawSig = s.toBinary(params.q); - ByteBuffer sbuf = ByteBuffer.allocate(rawSig.length + 4); - sbuf.put(rawSig); - sbuf.putInt(r); - return sbuf.array(); - } - - private IntegerPolynomial sign(IntegerPolynomial i, NTRUSigningPrivateKeyParameters kp) - { - int N = params.N; - int q = params.q; - int perturbationBases = params.B; - - NTRUSigningPrivateKeyParameters kPriv = kp; - NTRUSigningPublicKeyParameters kPub = kp.getPublicKey(); - - IntegerPolynomial s = new IntegerPolynomial(N); - int iLoop = perturbationBases; - while (iLoop >= 1) - { - Polynomial f = kPriv.getBasis(iLoop).f; - Polynomial fPrime = kPriv.getBasis(iLoop).fPrime; - - IntegerPolynomial y = f.mult(i); - y.div(q); - y = fPrime.mult(y); - - IntegerPolynomial x = fPrime.mult(i); - x.div(q); - x = f.mult(x); - - IntegerPolynomial si = y; - si.sub(x); - s.add(si); - - IntegerPolynomial hi = (IntegerPolynomial)kPriv.getBasis(iLoop).h.clone(); - if (iLoop > 1) - { - hi.sub(kPriv.getBasis(iLoop - 1).h); - } - else - { - hi.sub(kPub.h); - } - i = si.mult(hi, q); - - iLoop--; - } - - Polynomial f = kPriv.getBasis(0).f; - Polynomial fPrime = kPriv.getBasis(0).fPrime; - - IntegerPolynomial y = f.mult(i); - y.div(q); - y = fPrime.mult(y); - - IntegerPolynomial x = fPrime.mult(i); - x.div(q); - x = f.mult(x); - - y.sub(x); - s.add(y); - s.modPositive(q); - return s; - } - - /** - * Verifies a signature for any data previously added via {@link #update(byte[], int, int)}. - * - * @param sig a signature - * @return whether the signature is valid - * @throws IllegalStateException if initVerify was not called - */ - public boolean verifySignature(byte[] sig) - { - if (hashAlg == null || verificationKey == null) - { - throw new IllegalStateException("Call initVerify first!"); - } - - byte[] msgHash = new byte[hashAlg.getDigestSize()]; - - hashAlg.doFinal(msgHash, 0); - - return verifyHash(msgHash, sig, verificationKey); - } - - private boolean verifyHash(byte[] msgHash, byte[] sig, NTRUSigningPublicKeyParameters pub) - { - ByteBuffer sbuf = ByteBuffer.wrap(sig); - byte[] rawSig = new byte[sig.length - 4]; - sbuf.get(rawSig); - IntegerPolynomial s = IntegerPolynomial.fromBinary(rawSig, params.N, params.q); - int r = sbuf.getInt(); - return verify(createMsgRep(msgHash, r), s, pub.h); - } - - private boolean verify(IntegerPolynomial i, IntegerPolynomial s, IntegerPolynomial h) - { - int q = params.q; - double normBoundSq = params.normBoundSq; - double betaSq = params.betaSq; - - IntegerPolynomial t = h.mult(s, q); - t.sub(i); - long centeredNormSq = (long)(s.centeredNormSq(q) + betaSq * t.centeredNormSq(q)); - return centeredNormSq <= normBoundSq; - } - - protected IntegerPolynomial createMsgRep(byte[] msgHash, int r) - { - int N = params.N; - int q = params.q; - - int c = 31 - Integer.numberOfLeadingZeros(q); - int B = (c + 7) / 8; - IntegerPolynomial i = new IntegerPolynomial(N); - - ByteBuffer cbuf = ByteBuffer.allocate(msgHash.length + 4); - cbuf.put(msgHash); - cbuf.putInt(r); - NTRUSignerPrng prng = new NTRUSignerPrng(cbuf.array(), params.hashAlg); - - for (int t = 0; t < N; t++) - { - byte[] o = prng.nextBytes(B); - int hi = o[o.length - 1]; - hi >>= 8 * B - c; - hi <<= 8 * B - c; - o[o.length - 1] = (byte)hi; - - ByteBuffer obuf = ByteBuffer.allocate(4); - obuf.put(o); - obuf.rewind(); - // reverse byte order so it matches the endianness of java ints - i.coeffs[t] = Integer.reverseBytes(obuf.getInt()); - } - return i; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSignerPrng.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSignerPrng.java deleted file mode 100644 index 89ff217bff..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSignerPrng.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import java.nio.ByteBuffer; - -import org.bouncycastle.crypto.Digest; - -/** - * An implementation of the deterministic pseudo-random generator in EESS section 3.7.3.1 - */ -public class NTRUSignerPrng -{ - private int counter; - private byte[] seed; - private Digest hashAlg; - - /** - * Constructs a new PRNG and seeds it with a byte array. - * - * @param seed a seed - * @param hashAlg the hash algorithm to use - */ - NTRUSignerPrng(byte[] seed, Digest hashAlg) - { - counter = 0; - this.seed = seed; - this.hashAlg = hashAlg; - } - - /** - * Returns n random bytes - * - * @param n number of bytes to return - * @return the next n random bytes - */ - byte[] nextBytes(int n) - { - ByteBuffer buf = ByteBuffer.allocate(n); - - while (buf.hasRemaining()) - { - ByteBuffer cbuf = ByteBuffer.allocate(seed.length + 4); - cbuf.put(seed); - cbuf.putInt(counter); - byte[] array = cbuf.array(); - byte[] hash = new byte[hashAlg.getDigestSize()]; - - hashAlg.update(array, 0, array.length); - - hashAlg.doFinal(hash, 0); - - if (buf.remaining() < hash.length) - { - buf.put(hash, 0, buf.remaining()); - } - else - { - buf.put(hash); - } - counter++; - } - - return buf.array(); - } -} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningKeyGenerationParameters.java deleted file mode 100644 index 8d72277a9b..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningKeyGenerationParameters.java +++ /dev/null @@ -1,407 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.text.DecimalFormat; - -import org.bouncycastle.crypto.CryptoServicesRegistrar; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; - -/** - * A set of parameters for NtruSign. Several predefined parameter sets are available and new ones can be created as well. - */ -public class NTRUSigningKeyGenerationParameters - extends KeyGenerationParameters - implements Cloneable -{ - public static final int BASIS_TYPE_STANDARD = 0; - public static final int BASIS_TYPE_TRANSPOSE = 1; - - public static final int KEY_GEN_ALG_RESULTANT = 0; - public static final int KEY_GEN_ALG_FLOAT = 1; - - /** - * Gives 128 bits of security - */ - public static final NTRUSigningKeyGenerationParameters APR2011_439 = new NTRUSigningKeyGenerationParameters(439, 2048, 146, 1, BASIS_TYPE_TRANSPOSE, 0.165, 490, 280, false, true, KEY_GEN_ALG_RESULTANT, new SHA256Digest()); - - /** - * Like APR2011_439, this parameter set gives 128 bits of security but uses product-form polynomials - */ - public static final NTRUSigningKeyGenerationParameters APR2011_439_PROD = new NTRUSigningKeyGenerationParameters(439, 2048, 9, 8, 5, 1, BASIS_TYPE_TRANSPOSE, 0.165, 490, 280, false, true, KEY_GEN_ALG_RESULTANT, new SHA256Digest()); - - /** - * Gives 256 bits of security - */ - public static final NTRUSigningKeyGenerationParameters APR2011_743 = new NTRUSigningKeyGenerationParameters(743, 2048, 248, 1, BASIS_TYPE_TRANSPOSE, 0.127, 560, 360, true, false, KEY_GEN_ALG_RESULTANT, new SHA512Digest()); - - /** - * Like APR2011_439, this parameter set gives 256 bits of security but uses product-form polynomials - */ - public static final NTRUSigningKeyGenerationParameters APR2011_743_PROD = new NTRUSigningKeyGenerationParameters(743, 2048, 11, 11, 15, 1, BASIS_TYPE_TRANSPOSE, 0.127, 560, 360, true, false, KEY_GEN_ALG_RESULTANT, new SHA512Digest()); - - /** - * Generates key pairs quickly. Use for testing only. - */ - public static final NTRUSigningKeyGenerationParameters TEST157 = new NTRUSigningKeyGenerationParameters(157, 256, 29, 1, BASIS_TYPE_TRANSPOSE, 0.38, 200, 80, false, false, KEY_GEN_ALG_RESULTANT, new SHA256Digest()); - /** - * Generates key pairs quickly. Use for testing only. - */ - public static final NTRUSigningKeyGenerationParameters TEST157_PROD = new NTRUSigningKeyGenerationParameters(157, 256, 5, 5, 8, 1, BASIS_TYPE_TRANSPOSE, 0.38, 200, 80, false, false, KEY_GEN_ALG_RESULTANT, new SHA256Digest()); - - - public int N; - public int q; - public int d, d1, d2, d3, B; - double beta; - public double betaSq; - double normBound; - public double normBoundSq; - public int signFailTolerance = 100; - double keyNormBound; - public double keyNormBoundSq; - public boolean primeCheck; // true if N and 2N+1 are prime - public int basisType; - int bitsF = 6; // max #bits needed to encode one coefficient of the polynomial F - public boolean sparse; // whether to treat ternary polynomials as sparsely populated - public int keyGenAlg; - public Digest hashAlg; - public int polyType; - - /** - * Constructs a parameter set that uses ternary private keys (i.e. polyType=SIMPLE). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param d number of -1's in the private polynomials f and g - * @param B number of perturbations - * @param basisType whether to use the standard or transpose lattice - * @param beta balancing factor for the transpose lattice - * @param normBound maximum norm for valid signatures - * @param keyNormBound maximum norm for the ploynomials F and G - * @param primeCheck whether 2N+1 is prime - * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial}) - * @param keyGenAlg RESULTANT produces better bases, FLOAT is slightly faster. RESULTANT follows the EESS standard while FLOAT is described in Hoffstein et al: An Introduction to Mathematical Cryptography. - * @param hashAlg a valid identifier for a java.security.MessageDigest instance such as SHA-256. The MessageDigest must support the getDigestLength() method. - */ - public NTRUSigningKeyGenerationParameters(int N, int q, int d, int B, int basisType, double beta, double normBound, double keyNormBound, boolean primeCheck, boolean sparse, int keyGenAlg, Digest hashAlg) - { - super(CryptoServicesRegistrar.getSecureRandom(), N); - this.N = N; - this.q = q; - this.d = d; - this.B = B; - this.basisType = basisType; - this.beta = beta; - this.normBound = normBound; - this.keyNormBound = keyNormBound; - this.primeCheck = primeCheck; - this.sparse = sparse; - this.keyGenAlg = keyGenAlg; - this.hashAlg = hashAlg; - polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE; - init(); - } - - /** - * Constructs a parameter set that uses product-form private keys (i.e. polyType=PRODUCT). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param d1 number of -1's in the private polynomials f and g - * @param d2 number of -1's in the private polynomials f and g - * @param d3 number of -1's in the private polynomials f and g - * @param B number of perturbations - * @param basisType whether to use the standard or transpose lattice - * @param beta balancing factor for the transpose lattice - * @param normBound maximum norm for valid signatures - * @param keyNormBound maximum norm for the ploynomials F and G - * @param primeCheck whether 2N+1 is prime - * @param sparse whether to treat ternary polynomials as sparsely populated ({@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.SparseTernaryPolynomial} vs {@link org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial}) - * @param keyGenAlg RESULTANT produces better bases, FLOAT is slightly faster. RESULTANT follows the EESS standard while FLOAT is described in Hoffstein et al: An Introduction to Mathematical Cryptography. - * @param hashAlg a valid identifier for a java.security.MessageDigest instance such as SHA-256. The MessageDigest must support the getDigestLength() method. - */ - public NTRUSigningKeyGenerationParameters(int N, int q, int d1, int d2, int d3, int B, int basisType, double beta, double normBound, double keyNormBound, boolean primeCheck, boolean sparse, int keyGenAlg, Digest hashAlg) - { - super(CryptoServicesRegistrar.getSecureRandom(), N); - this.N = N; - this.q = q; - this.d1 = d1; - this.d2 = d2; - this.d3 = d3; - this.B = B; - this.basisType = basisType; - this.beta = beta; - this.normBound = normBound; - this.keyNormBound = keyNormBound; - this.primeCheck = primeCheck; - this.sparse = sparse; - this.keyGenAlg = keyGenAlg; - this.hashAlg = hashAlg; - polyType = NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT; - init(); - } - - private void init() - { - betaSq = beta * beta; - normBoundSq = normBound * normBound; - keyNormBoundSq = keyNormBound * keyNormBound; - } - - /** - * Reads a parameter set from an input stream. - * - * @param is an input stream - * @throws java.io.IOException - */ - public NTRUSigningKeyGenerationParameters(InputStream is) - throws IOException - { - super(CryptoServicesRegistrar.getSecureRandom(), 0); // TODO: - DataInputStream dis = new DataInputStream(is); - N = dis.readInt(); - q = dis.readInt(); - d = dis.readInt(); - d1 = dis.readInt(); - d2 = dis.readInt(); - d3 = dis.readInt(); - B = dis.readInt(); - basisType = dis.readInt(); - beta = dis.readDouble(); - normBound = dis.readDouble(); - keyNormBound = dis.readDouble(); - signFailTolerance = dis.readInt(); - primeCheck = dis.readBoolean(); - sparse = dis.readBoolean(); - bitsF = dis.readInt(); - keyGenAlg = dis.read(); - String alg = dis.readUTF(); - if ("SHA-512".equals(alg)) - { - hashAlg = new SHA512Digest(); - } - else if ("SHA-256".equals(alg)) - { - hashAlg = new SHA256Digest(); - } - polyType = dis.read(); - init(); - } - - /** - * Writes the parameter set to an output stream - * - * @param os an output stream - * @throws java.io.IOException - */ - public void writeTo(OutputStream os) - throws IOException - { - DataOutputStream dos = new DataOutputStream(os); - dos.writeInt(N); - dos.writeInt(q); - dos.writeInt(d); - dos.writeInt(d1); - dos.writeInt(d2); - dos.writeInt(d3); - dos.writeInt(B); - dos.writeInt(basisType); - dos.writeDouble(beta); - dos.writeDouble(normBound); - dos.writeDouble(keyNormBound); - dos.writeInt(signFailTolerance); - dos.writeBoolean(primeCheck); - dos.writeBoolean(sparse); - dos.writeInt(bitsF); - dos.write(keyGenAlg); - dos.writeUTF(hashAlg.getAlgorithmName()); - dos.write(polyType); - } - - public NTRUSigningParameters getSigningParameters() - { - return new NTRUSigningParameters(N, q, d, B, beta, normBound, hashAlg); - } - - public NTRUSigningKeyGenerationParameters clone() - { - if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE) - { - return new NTRUSigningKeyGenerationParameters(N, q, d, B, basisType, beta, normBound, keyNormBound, primeCheck, sparse, keyGenAlg, hashAlg); - } - else - { - return new NTRUSigningKeyGenerationParameters(N, q, d1, d2, d3, B, basisType, beta, normBound, keyNormBound, primeCheck, sparse, keyGenAlg, hashAlg); - } - } - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + B; - result = prime * result + N; - result = prime * result + basisType; - long temp; - temp = Double.doubleToLongBits(beta); - result = prime * result + (int)(temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(betaSq); - result = prime * result + (int)(temp ^ (temp >>> 32)); - result = prime * result + bitsF; - result = prime * result + d; - result = prime * result + d1; - result = prime * result + d2; - result = prime * result + d3; - result = prime * result + ((hashAlg == null) ? 0 : hashAlg.getAlgorithmName().hashCode()); - result = prime * result + keyGenAlg; - temp = Double.doubleToLongBits(keyNormBound); - result = prime * result + (int)(temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(keyNormBoundSq); - result = prime * result + (int)(temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(normBound); - result = prime * result + (int)(temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(normBoundSq); - result = prime * result + (int)(temp ^ (temp >>> 32)); - result = prime * result + polyType; - result = prime * result + (primeCheck ? 1231 : 1237); - result = prime * result + q; - result = prime * result + signFailTolerance; - result = prime * result + (sparse ? 1231 : 1237); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (!(obj instanceof NTRUSigningKeyGenerationParameters)) - { - return false; - } - NTRUSigningKeyGenerationParameters other = (NTRUSigningKeyGenerationParameters)obj; - if (B != other.B) - { - return false; - } - if (N != other.N) - { - return false; - } - if (basisType != other.basisType) - { - return false; - } - if (Double.doubleToLongBits(beta) != Double.doubleToLongBits(other.beta)) - { - return false; - } - if (Double.doubleToLongBits(betaSq) != Double.doubleToLongBits(other.betaSq)) - { - return false; - } - if (bitsF != other.bitsF) - { - return false; - } - if (d != other.d) - { - return false; - } - if (d1 != other.d1) - { - return false; - } - if (d2 != other.d2) - { - return false; - } - if (d3 != other.d3) - { - return false; - } - if (hashAlg == null) - { - if (other.hashAlg != null) - { - return false; - } - } - else if (!hashAlg.getAlgorithmName().equals(other.hashAlg.getAlgorithmName())) - { - return false; - } - if (keyGenAlg != other.keyGenAlg) - { - return false; - } - if (Double.doubleToLongBits(keyNormBound) != Double.doubleToLongBits(other.keyNormBound)) - { - return false; - } - if (Double.doubleToLongBits(keyNormBoundSq) != Double.doubleToLongBits(other.keyNormBoundSq)) - { - return false; - } - if (Double.doubleToLongBits(normBound) != Double.doubleToLongBits(other.normBound)) - { - return false; - } - if (Double.doubleToLongBits(normBoundSq) != Double.doubleToLongBits(other.normBoundSq)) - { - return false; - } - if (polyType != other.polyType) - { - return false; - } - if (primeCheck != other.primeCheck) - { - return false; - } - if (q != other.q) - { - return false; - } - if (signFailTolerance != other.signFailTolerance) - { - return false; - } - if (sparse != other.sparse) - { - return false; - } - return true; - } - - public String toString() - { - DecimalFormat format = new DecimalFormat("0.00"); - - StringBuilder output = new StringBuilder("SignatureParameters(N=" + N + " q=" + q); - if (polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE) - { - output.append(" polyType=SIMPLE d=" + d); - } - else - { - output.append(" polyType=PRODUCT d1=" + d1 + " d2=" + d2 + " d3=" + d3); - } - output.append(" B=" + B + " basisType=" + basisType + " beta=" + format.format(beta) + - " normBound=" + format.format(normBound) + " keyNormBound=" + format.format(keyNormBound) + - " prime=" + primeCheck + " sparse=" + sparse + " keyGenAlg=" + keyGenAlg + " hashAlg=" + hashAlg + ")"); - return output.toString(); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningKeyPairGenerator.java deleted file mode 100644 index 0f9fdc12b4..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningKeyPairGenerator.java +++ /dev/null @@ -1,349 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.CryptoServicesRegistrar; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.pqc.legacy.math.ntru.euclid.BigIntEuclidean; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.BigDecimalPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.BigIntPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.Polynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.ProductFormPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.Resultant; - -import static java.math.BigInteger.ONE; -import static java.math.BigInteger.ZERO; - -public class NTRUSigningKeyPairGenerator - implements AsymmetricCipherKeyPairGenerator -{ - private NTRUSigningKeyGenerationParameters params; - - public void init(KeyGenerationParameters param) - { - this.params = (NTRUSigningKeyGenerationParameters)param; - } - - /** - * Generates a new signature key pair. Starts B+1 threads. - * - * @return a key pair - */ - public AsymmetricCipherKeyPair generateKeyPair() - { - NTRUSigningPublicKeyParameters pub = null; - ExecutorService executor = Executors.newCachedThreadPool(); - List> bases = new ArrayList>(); - for (int k = params.B; k >= 0; k--) - { - bases.add(executor.submit(new BasisGenerationTask())); - } - executor.shutdown(); - - List basises = new ArrayList(); - - for (int k = params.B; k >= 0; k--) - { - Future basis = bases.get(k); - try - { - basises.add(basis.get()); - if (k == params.B) - { - pub = new NTRUSigningPublicKeyParameters(basis.get().h, params.getSigningParameters()); - } - } - catch (Exception e) - { - throw new IllegalStateException(e); - } - } - NTRUSigningPrivateKeyParameters priv = new NTRUSigningPrivateKeyParameters(basises, pub); - AsymmetricCipherKeyPair kp = new AsymmetricCipherKeyPair(pub, priv); - return kp; - } - - /** - * Generates a new signature key pair. Runs in a single thread. - * - * @return a key pair - */ - public AsymmetricCipherKeyPair generateKeyPairSingleThread() - { - List basises = new ArrayList(); - NTRUSigningPublicKeyParameters pub = null; - for (int k = params.B; k >= 0; k--) - { - NTRUSigningPrivateKeyParameters.Basis basis = generateBoundedBasis(); - basises.add(basis); - if (k == 0) - { - pub = new NTRUSigningPublicKeyParameters(basis.h, params.getSigningParameters()); - } - } - NTRUSigningPrivateKeyParameters priv = new NTRUSigningPrivateKeyParameters(basises, pub); - return new AsymmetricCipherKeyPair(pub, priv); - } - - - /* - * Implementation of the optional steps 20 through 26 in EESS1v2.pdf, section 3.5.1.1. - * This doesn't seem to have much of an effect and sometimes actually increases the - * norm of F, but on average it slightly reduces the norm.
    - * This method changes F and g but leaves f and - * g unchanged. - */ - private void minimizeFG(IntegerPolynomial f, IntegerPolynomial g, IntegerPolynomial F, IntegerPolynomial G, int N) - { - int E = 0; - for (int j = 0; j < N; j++) - { - E += 2 * N * (f.coeffs[j] * f.coeffs[j] + g.coeffs[j] * g.coeffs[j]); - } - - // [f(1)+g(1)]^2 = 4 - E -= 4; - - IntegerPolynomial u = (IntegerPolynomial)f.clone(); - IntegerPolynomial v = (IntegerPolynomial)g.clone(); - int j = 0; - int k = 0; - int maxAdjustment = N; - while (k < maxAdjustment && j < N) - { - int D = 0; - int i = 0; - while (i < N) - { - int D1 = F.coeffs[i] * f.coeffs[i]; - int D2 = G.coeffs[i] * g.coeffs[i]; - int D3 = 4 * N * (D1 + D2); - D += D3; - i++; - } - // f(1)+g(1) = 2 - int D1 = 4 * (F.sumCoeffs() + G.sumCoeffs()); - D -= D1; - - if (D > E) - { - F.sub(u); - G.sub(v); - k++; - j = 0; - } - else if (D < -E) - { - F.add(u); - G.add(v); - k++; - j = 0; - } - j++; - u.rotate1(); - v.rotate1(); - } - } - - /** - * Creates a NTRUSigner basis consisting of polynomials f, g, F, G, h.
    - * If KeyGenAlg=FLOAT, the basis may not be valid and this method must be rerun if that is the case.
    - * - * @see #generateBoundedBasis() - */ - private FGBasis generateBasis() - { - int N = params.N; - int q = params.q; - int d = params.d; - int d1 = params.d1; - int d2 = params.d2; - int d3 = params.d3; - int basisType = params.basisType; - - Polynomial f; - IntegerPolynomial fInt; - Polynomial g; - IntegerPolynomial gInt; - IntegerPolynomial fq; - Resultant rf; - Resultant rg; - BigIntEuclidean r; - - int _2n1 = 2 * N + 1; - boolean primeCheck = params.primeCheck; - - do - { - do - { - f = params.polyType== NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? DenseTernaryPolynomial.generateRandom(N, d + 1, d, CryptoServicesRegistrar.getSecureRandom()) : ProductFormPolynomial.generateRandom(N, d1, d2, d3 + 1, d3, CryptoServicesRegistrar.getSecureRandom()); - fInt = f.toIntegerPolynomial(); - } - while (primeCheck && fInt.resultant(_2n1).res.equals(ZERO)); - fq = fInt.invertFq(q); - } - while (fq == null); - rf = fInt.resultant(); - - do - { - do - { - do - { - g = params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE ? DenseTernaryPolynomial.generateRandom(N, d + 1, d, CryptoServicesRegistrar.getSecureRandom()) : ProductFormPolynomial.generateRandom(N, d1, d2, d3 + 1, d3, CryptoServicesRegistrar.getSecureRandom()); - gInt = g.toIntegerPolynomial(); - } - while (primeCheck && gInt.resultant(_2n1).res.equals(ZERO)); - } - while (gInt.invertFq(q) == null); - rg = gInt.resultant(); - r = BigIntEuclidean.calculate(rf.res, rg.res); - } - while (!r.gcd.equals(ONE)); - - BigIntPolynomial A = (BigIntPolynomial)rf.rho.clone(); - A.mult(r.x.multiply(BigInteger.valueOf(q))); - BigIntPolynomial B = (BigIntPolynomial)rg.rho.clone(); - B.mult(r.y.multiply(BigInteger.valueOf(-q))); - - BigIntPolynomial C; - if (params.keyGenAlg == NTRUSigningKeyGenerationParameters.KEY_GEN_ALG_RESULTANT) - { - int[] fRevCoeffs = new int[N]; - int[] gRevCoeffs = new int[N]; - fRevCoeffs[0] = fInt.coeffs[0]; - gRevCoeffs[0] = gInt.coeffs[0]; - for (int i = 1; i < N; i++) - { - fRevCoeffs[i] = fInt.coeffs[N - i]; - gRevCoeffs[i] = gInt.coeffs[N - i]; - } - IntegerPolynomial fRev = new IntegerPolynomial(fRevCoeffs); - IntegerPolynomial gRev = new IntegerPolynomial(gRevCoeffs); - - IntegerPolynomial t = f.mult(fRev); - t.add(g.mult(gRev)); - Resultant rt = t.resultant(); - C = fRev.mult(B); // fRev.mult(B) is actually faster than new SparseTernaryPolynomial(fRev).mult(B), possibly due to cache locality? - C.add(gRev.mult(A)); - C = C.mult(rt.rho); - C.div(rt.res); - } - else - { // KeyGenAlg.FLOAT - // calculate ceil(log10(N)) - int log10N = 0; - for (int i = 1; i < N; i *= 10) - { - log10N++; - } - - // * Cdec needs to be accurate to 1 decimal place so it can be correctly rounded; - // * fInv loses up to (#digits of longest coeff of B) places in fInv.mult(B); - // * multiplying fInv by B also multiplies the rounding error by a factor of N; - // so make #decimal places of fInv the sum of the above. - BigDecimalPolynomial fInv = rf.rho.div(new BigDecimal(rf.res), B.getMaxCoeffLength() + 1 + log10N); - BigDecimalPolynomial gInv = rg.rho.div(new BigDecimal(rg.res), A.getMaxCoeffLength() + 1 + log10N); - - BigDecimalPolynomial Cdec = fInv.mult(B); - Cdec.add(gInv.mult(A)); - Cdec.halve(); - C = Cdec.round(); - } - - BigIntPolynomial F = (BigIntPolynomial)B.clone(); - F.sub(f.mult(C)); - BigIntPolynomial G = (BigIntPolynomial)A.clone(); - G.sub(g.mult(C)); - - IntegerPolynomial FInt = new IntegerPolynomial(F); - IntegerPolynomial GInt = new IntegerPolynomial(G); - minimizeFG(fInt, gInt, FInt, GInt, N); - - Polynomial fPrime; - IntegerPolynomial h; - if (basisType == NTRUSigningKeyGenerationParameters.BASIS_TYPE_STANDARD) - { - fPrime = FInt; - h = g.mult(fq, q); - } - else - { - fPrime = g; - h = FInt.mult(fq, q); - } - h.modPositive(q); - - return new FGBasis(f, fPrime, h, FInt, GInt, params); - } - - /** - * Creates a basis such that |F| < keyNormBound and |G| < keyNormBound - * - * @return a NTRUSigner basis - */ - public NTRUSigningPrivateKeyParameters.Basis generateBoundedBasis() - { - while (true) - { - FGBasis basis = generateBasis(); - if (basis.isNormOk()) - { - return basis; - } - } - } - - private class BasisGenerationTask - implements Callable - { - - - public NTRUSigningPrivateKeyParameters.Basis call() - throws Exception - { - return generateBoundedBasis(); - } - } - - /** - * A subclass of Basis that additionally contains the polynomials F and G. - */ - public static class FGBasis - extends NTRUSigningPrivateKeyParameters.Basis - { - public IntegerPolynomial F; - public IntegerPolynomial G; - - FGBasis(Polynomial f, Polynomial fPrime, IntegerPolynomial h, IntegerPolynomial F, IntegerPolynomial G, NTRUSigningKeyGenerationParameters params) - { - super(f, fPrime, h, params); - this.F = F; - this.G = G; - } - - /* - * Returns true if the norms of the polynomials F and G - * are within {@link NTRUSigningKeyGenerationParameters#keyNormBound}. - */ - boolean isNormOk() - { - double keyNormBoundSq = params.keyNormBoundSq; - int q = params.q; - return (F.centeredNormSq(q) < keyNormBoundSq && G.centeredNormSq(q) < keyNormBoundSq); - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningParameters.java deleted file mode 100644 index 5df537a503..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningParameters.java +++ /dev/null @@ -1,269 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.text.DecimalFormat; - -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.digests.SHA512Digest; - -/** - * A set of parameters for NtruSign. Several predefined parameter sets are available and new ones can be created as well. - */ -public class NTRUSigningParameters - implements Cloneable -{ - public int N; - public int q; - public int d, d1, d2, d3, B; - double beta; - public double betaSq; - double normBound; - public double normBoundSq; - public int signFailTolerance = 100; - int bitsF = 6; // max #bits needed to encode one coefficient of the polynomial F - public Digest hashAlg; - - /** - * Constructs a parameter set that uses ternary private keys (i.e. polyType=SIMPLE). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param d number of -1's in the private polynomials f and g - * @param B number of perturbations - * @param beta balancing factor for the transpose lattice - * @param normBound maximum norm for valid signatures - * @param hashAlg a valid identifier for a java.security.MessageDigest instance such as SHA-256. The MessageDigest must support the getDigestLength() method. - */ - public NTRUSigningParameters(int N, int q, int d, int B, double beta, double normBound, Digest hashAlg) - { - this.N = N; - this.q = q; - this.d = d; - this.B = B; - this.beta = beta; - this.normBound = normBound; - this.hashAlg = hashAlg; - init(); - } - - /** - * Constructs a parameter set that uses product-form private keys (i.e. polyType=PRODUCT). - * - * @param N number of polynomial coefficients - * @param q modulus - * @param d1 number of -1's in the private polynomials f and g - * @param d2 number of -1's in the private polynomials f and g - * @param d3 number of -1's in the private polynomials f and g - * @param B number of perturbations - * @param beta balancing factor for the transpose lattice - * @param normBound maximum norm for valid signatures - * @param keyNormBound maximum norm for the ploynomials F and G - * @param hashAlg a valid identifier for a java.security.MessageDigest instance such as SHA-256. The MessageDigest must support the getDigestLength() method. - */ - public NTRUSigningParameters(int N, int q, int d1, int d2, int d3, int B, double beta, double normBound, double keyNormBound, Digest hashAlg) - { - this.N = N; - this.q = q; - this.d1 = d1; - this.d2 = d2; - this.d3 = d3; - this.B = B; - this.beta = beta; - this.normBound = normBound; - this.hashAlg = hashAlg; - init(); - } - - private void init() - { - betaSq = beta * beta; - normBoundSq = normBound * normBound; - } - - /** - * Reads a parameter set from an input stream. - * - * @param is an input stream - * @throws IOException - */ - public NTRUSigningParameters(InputStream is) - throws IOException - { - DataInputStream dis = new DataInputStream(is); - N = dis.readInt(); - q = dis.readInt(); - d = dis.readInt(); - d1 = dis.readInt(); - d2 = dis.readInt(); - d3 = dis.readInt(); - B = dis.readInt(); - beta = dis.readDouble(); - normBound = dis.readDouble(); - signFailTolerance = dis.readInt(); - bitsF = dis.readInt(); - String alg = dis.readUTF(); - if ("SHA-512".equals(alg)) - { - hashAlg = new SHA512Digest(); - } - else if ("SHA-256".equals(alg)) - { - hashAlg = new SHA256Digest(); - } - init(); - } - - /** - * Writes the parameter set to an output stream - * - * @param os an output stream - * @throws IOException - */ - public void writeTo(OutputStream os) - throws IOException - { - DataOutputStream dos = new DataOutputStream(os); - dos.writeInt(N); - dos.writeInt(q); - dos.writeInt(d); - dos.writeInt(d1); - dos.writeInt(d2); - dos.writeInt(d3); - dos.writeInt(B); - dos.writeDouble(beta); - dos.writeDouble(normBound); - dos.writeInt(signFailTolerance); - dos.writeInt(bitsF); - dos.writeUTF(hashAlg.getAlgorithmName()); - } - - public NTRUSigningParameters clone() - { - return new NTRUSigningParameters(N, q, d, B, beta, normBound, hashAlg); - } - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + B; - result = prime * result + N; - long temp; - temp = Double.doubleToLongBits(beta); - result = prime * result + (int)(temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(betaSq); - result = prime * result + (int)(temp ^ (temp >>> 32)); - result = prime * result + bitsF; - result = prime * result + d; - result = prime * result + d1; - result = prime * result + d2; - result = prime * result + d3; - result = prime * result + ((hashAlg == null) ? 0 : hashAlg.getAlgorithmName().hashCode()); - temp = Double.doubleToLongBits(normBound); - result = prime * result + (int)(temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(normBoundSq); - result = prime * result + (int)(temp ^ (temp >>> 32)); - result = prime * result + q; - result = prime * result + signFailTolerance; - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (!(obj instanceof NTRUSigningParameters)) - { - return false; - } - NTRUSigningParameters other = (NTRUSigningParameters)obj; - if (B != other.B) - { - return false; - } - if (N != other.N) - { - return false; - } - if (Double.doubleToLongBits(beta) != Double.doubleToLongBits(other.beta)) - { - return false; - } - if (Double.doubleToLongBits(betaSq) != Double.doubleToLongBits(other.betaSq)) - { - return false; - } - if (bitsF != other.bitsF) - { - return false; - } - if (d != other.d) - { - return false; - } - if (d1 != other.d1) - { - return false; - } - if (d2 != other.d2) - { - return false; - } - if (d3 != other.d3) - { - return false; - } - if (hashAlg == null) - { - if (other.hashAlg != null) - { - return false; - } - } - else if (!hashAlg.getAlgorithmName().equals(other.hashAlg.getAlgorithmName())) - { - return false; - } - if (Double.doubleToLongBits(normBound) != Double.doubleToLongBits(other.normBound)) - { - return false; - } - if (Double.doubleToLongBits(normBoundSq) != Double.doubleToLongBits(other.normBoundSq)) - { - return false; - } - if (q != other.q) - { - return false; - } - if (signFailTolerance != other.signFailTolerance) - { - return false; - } - - return true; - } - - public String toString() - { - DecimalFormat format = new DecimalFormat("0.00"); - - StringBuilder output = new StringBuilder("SignatureParameters(N=" + N + " q=" + q); - - output.append(" B=" + B + " beta=" + format.format(beta) + - " normBound=" + format.format(normBound) + - " hashAlg=" + hashAlg + ")"); - return output.toString(); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningPrivateKeyParameters.java deleted file mode 100644 index b3d1efa313..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningPrivateKeyParameters.java +++ /dev/null @@ -1,388 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.Polynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.ProductFormPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.SparseTernaryPolynomial; - -/** - * A NtruSign private key comprises one or more {@link NTRUSigningPrivateKeyParameters.Basis} of three polynomials each, - * except the zeroth basis for which h is undefined. - */ -public class NTRUSigningPrivateKeyParameters - extends AsymmetricKeyParameter -{ - private List bases; - private NTRUSigningPublicKeyParameters publicKey; - - /** - * Constructs a new private key from a byte array - * - * @param b an encoded private key - * @param params the NtruSign parameters to use - */ - public NTRUSigningPrivateKeyParameters(byte[] b, NTRUSigningKeyGenerationParameters params) - throws IOException - { - this(new ByteArrayInputStream(b), params); - } - - /** - * Constructs a new private key from an input stream - * - * @param is an input stream - * @param params the NtruSign parameters to use - */ - public NTRUSigningPrivateKeyParameters(InputStream is, NTRUSigningKeyGenerationParameters params) - throws IOException - { - super(true); - bases = new ArrayList(); - for (int i = 0; i <= params.B; i++) - // include a public key h[i] in all bases except for the first one - { - add(new Basis(is, params, i != 0)); - } - publicKey = new NTRUSigningPublicKeyParameters(is, params.getSigningParameters()); - } - - public NTRUSigningPrivateKeyParameters(List bases, NTRUSigningPublicKeyParameters publicKey) - { - super(true); - this.bases = new ArrayList(bases); - this.publicKey = publicKey; - } - - /** - * Adds a basis to the key. - * - * @param b a NtruSign basis - */ - private void add(Basis b) - { - bases.add(b); - } - - /** - * Returns the i-th basis - * - * @param i the index - * @return the basis at index i - */ - public Basis getBasis(int i) - { - return bases.get(i); - } - - public NTRUSigningPublicKeyParameters getPublicKey() - { - return publicKey; - } - - /** - * Converts the key to a byte array - * - * @return the encoded key - */ - public byte[] getEncoded() - throws IOException - { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - for (int i = 0; i < bases.size(); i++) - { - // all bases except for the first one contain a public key - bases.get(i).encode(os, i != 0); - } - - os.write(publicKey.getEncoded()); - - return os.toByteArray(); - } - - /** - * Writes the key to an output stream - * - * @param os an output stream - * @throws IOException - */ - public void writeTo(OutputStream os) - throws IOException - { - os.write(getEncoded()); - } - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result; - if (bases==null) return result; - result += bases.hashCode(); - for (Basis basis : bases) - { - result += basis.hashCode(); - } - return result; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - NTRUSigningPrivateKeyParameters other = (NTRUSigningPrivateKeyParameters)obj; - if ((bases == null) != (other.bases == null)) - { - return false; - } - if (bases == null) - { - return true; - } - if (bases.size() != other.bases.size()) - { - return false; - } - for (int i = 0; i < bases.size(); i++) - { - Basis basis1 = bases.get(i); - Basis basis2 = other.bases.get(i); - if (!basis1.f.equals(basis2.f)) - { - return false; - } - if (!basis1.fPrime.equals(basis2.fPrime)) - { - return false; - } - if (i != 0 && !basis1.h.equals(basis2.h)) // don't compare h for the 0th basis - { - return false; - } - if (!basis1.params.equals(basis2.params)) - { - return false; - } - } - return true; - } - - /** - * A NtruSign basis. Contains three polynomials f, f', h. - */ - public static class Basis - { - public Polynomial f; - public Polynomial fPrime; - public IntegerPolynomial h; - NTRUSigningKeyGenerationParameters params; - - /** - * Constructs a new basis from polynomials f, f', h. - * - * @param f - * @param fPrime - * @param h - * @param params NtruSign parameters - */ - protected Basis(Polynomial f, Polynomial fPrime, IntegerPolynomial h, NTRUSigningKeyGenerationParameters params) - { - this.f = f; - this.fPrime = fPrime; - this.h = h; - this.params = params; - } - - /** - * Reads a basis from an input stream and constructs a new basis. - * - * @param is an input stream - * @param params NtruSign parameters - * @param include_h whether to read the polynomial h (true) or only f and f' (false) - */ - Basis(InputStream is, NTRUSigningKeyGenerationParameters params, boolean include_h) - throws IOException - { - int N = params.N; - int q = params.q; - int d1 = params.d1; - int d2 = params.d2; - int d3 = params.d3; - boolean sparse = params.sparse; - this.params = params; - - if (params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT) - { - f = ProductFormPolynomial.fromBinary(is, N, d1, d2, d3 + 1, d3); - } - else - { - IntegerPolynomial fInt = IntegerPolynomial.fromBinary3Tight(is, N); - f = sparse ? new SparseTernaryPolynomial(fInt) : new DenseTernaryPolynomial(fInt); - } - - if (params.basisType == NTRUSigningKeyGenerationParameters.BASIS_TYPE_STANDARD) - { - IntegerPolynomial fPrimeInt = IntegerPolynomial.fromBinary(is, N, q); - for (int i = 0; i < fPrimeInt.coeffs.length; i++) - { - fPrimeInt.coeffs[i] -= q / 2; - } - fPrime = fPrimeInt; - } - else if (params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT) - { - fPrime = ProductFormPolynomial.fromBinary(is, N, d1, d2, d3 + 1, d3); - } - else - { - fPrime = IntegerPolynomial.fromBinary3Tight(is, N); - } - - if (include_h) - { - h = IntegerPolynomial.fromBinary(is, N, q); - } - } - - /** - * Writes the basis to an output stream - * - * @param os an output stream - * @param include_h whether to write the polynomial h (true) or only f and f' (false) - * @throws IOException - */ - void encode(OutputStream os, boolean include_h) - throws IOException - { - int q = params.q; - - os.write(getEncoded(f)); - if (params.basisType == NTRUSigningKeyGenerationParameters.BASIS_TYPE_STANDARD) - { - IntegerPolynomial fPrimeInt = fPrime.toIntegerPolynomial(); - for (int i = 0; i < fPrimeInt.coeffs.length; i++) - { - fPrimeInt.coeffs[i] += q / 2; - } - os.write(fPrimeInt.toBinary(q)); - } - else - { - os.write(getEncoded(fPrime)); - } - if (include_h) - { - os.write(h.toBinary(q)); - } - } - - private byte[] getEncoded(Polynomial p) - { - if (p instanceof ProductFormPolynomial) - { - return ((ProductFormPolynomial)p).toBinary(); - } - else - { - return p.toIntegerPolynomial().toBinary3Tight(); - } - } - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((f == null) ? 0 : f.hashCode()); - result = prime * result + ((fPrime == null) ? 0 : fPrime.hashCode()); - result = prime * result + ((h == null) ? 0 : h.hashCode()); - result = prime * result + ((params == null) ? 0 : params.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (!(obj instanceof Basis)) - { - return false; - } - Basis other = (Basis)obj; - if (f == null) - { - if (other.f != null) - { - return false; - } - } - else if (!f.equals(other.f)) - { - return false; - } - if (fPrime == null) - { - if (other.fPrime != null) - { - return false; - } - } - else if (!fPrime.equals(other.fPrime)) - { - return false; - } - if (h == null) - { - if (other.h != null) - { - return false; - } - } - else if (!h.equals(other.h)) - { - return false; - } - if (params == null) - { - if (other.params != null) - { - return false; - } - } - else if (!params.equals(other.params)) - { - return false; - } - return true; - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningPublicKeyParameters.java deleted file mode 100644 index 61f45be4dc..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/ntru/NTRUSigningPublicKeyParameters.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.ntru; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; - -/** - * A NtruSign public key is essentially a polynomial named h. - */ -public class NTRUSigningPublicKeyParameters - extends AsymmetricKeyParameter -{ - private NTRUSigningParameters params; - public IntegerPolynomial h; - - /** - * Constructs a new public key from a polynomial - * - * @param h the polynomial h which determines the key - * @param params the NtruSign parameters to use - */ - public NTRUSigningPublicKeyParameters(IntegerPolynomial h, NTRUSigningParameters params) - { - super(false); - this.h = h; - this.params = params; - } - - /** - * Converts a byte array to a polynomial h and constructs a new public key - * - * @param b an encoded polynomial - * @param params the NtruSign parameters to use - */ - public NTRUSigningPublicKeyParameters(byte[] b, NTRUSigningParameters params) - { - super(false); - h = IntegerPolynomial.fromBinary(b, params.N, params.q); - this.params = params; - } - - /** - * Reads a polynomial h from an input stream and constructs a new public key - * - * @param is an input stream - * @param params the NtruSign parameters to use - */ - public NTRUSigningPublicKeyParameters(InputStream is, NTRUSigningParameters params) - throws IOException - { - super(false); - h = IntegerPolynomial.fromBinary(is, params.N, params.q); - this.params = params; - } - - - /** - * Converts the key to a byte array - * - * @return the encoded key - */ - public byte[] getEncoded() - { - return h.toBinary(params.q); - } - - /** - * Writes the key to an output stream - * - * @param os an output stream - * @throws IOException - */ - public void writeTo(OutputStream os) - throws IOException - { - os.write(getEncoded()); - } - - @Override - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((h == null) ? 0 : h.hashCode()); - result = prime * result + ((params == null) ? 0 : params.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - NTRUSigningPublicKeyParameters other = (NTRUSigningPublicKeyParameters)obj; - if (h == null) - { - if (other.h != null) - { - return false; - } - } - else if (!h.equals(other.h)) - { - return false; - } - if (params == null) - { - if (other.params != null) - { - return false; - } - } - else if (!params.equals(other.params)) - { - return false; - } - return true; - } -} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/HashUtils.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/HashUtils.java deleted file mode 100644 index 0b8be12d9d..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/HashUtils.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.qtesla; - -import org.bouncycastle.crypto.digests.CSHAKEDigest; -import org.bouncycastle.crypto.digests.SHAKEDigest; - -class HashUtils -{ - - static final int SECURE_HASH_ALGORITHM_KECCAK_128_RATE = 168; - static final int SECURE_HASH_ALGORITHM_KECCAK_256_RATE = 136; - - /*************************************************************************************************************************************************************** - * Description: The Secure-Hash-Algorithm-3 Extendable-Output Function That Generally Supports 128 Bits of Security Strength, If the Output is Sufficiently Long - ***************************************************************************************************************************************************************/ - static void secureHashAlgorithmKECCAK128(byte[] output, int outputOffset, int outputLength, byte[] input, int inputOffset, int inputLength) - { - SHAKEDigest dig = new SHAKEDigest(128); - dig.update(input, inputOffset, inputLength); - - dig.doFinal(output, outputOffset, outputLength); - } - - /*************************************************************************************************************************************************************** - * Description: The Secure-Hash-Algorithm-3 Extendable-Output Function That Generally Supports 256 Bits of Security Strength, If the Output is Sufficiently Long - ***************************************************************************************************************************************************************/ - static void secureHashAlgorithmKECCAK256(byte[] output, int outputOffset, int outputLength, byte[] input, int inputOffset, int inputLength) - { - SHAKEDigest dig = new SHAKEDigest(256); - dig.update(input, inputOffset, inputLength); - - dig.doFinal(output, outputOffset, outputLength); - } - - /* Customizable Secure Hash Algorithm KECCAK 128 / Customizable Secure Hash Algorithm KECCAK 256 */ - - - static void customizableSecureHashAlgorithmKECCAK128Simple(byte[] output, int outputOffset, int outputLength, short continuousTimeStochasticModelling, byte[] input, int inputOffset, int inputLength) - { - CSHAKEDigest dig = new CSHAKEDigest(128, null, new byte[]{(byte)continuousTimeStochasticModelling, (byte)(continuousTimeStochasticModelling >> 8)}); - dig.update(input, inputOffset, inputLength); - - dig.doFinal(output, outputOffset, outputLength); - } - - static void customizableSecureHashAlgorithmKECCAK256Simple(byte[] output, int outputOffset, int outputLength, short continuousTimeStochasticModelling, byte[] input, int inputOffset, int inputLength) - { - CSHAKEDigest dig = new CSHAKEDigest(256, null, new byte[]{(byte)continuousTimeStochasticModelling, (byte)(continuousTimeStochasticModelling >> 8)}); - dig.update(input, inputOffset, inputLength); - - dig.doFinal(output, outputOffset, outputLength); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/IntSlicer.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/IntSlicer.java deleted file mode 100644 index f11b04ab0b..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/IntSlicer.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.qtesla; - -/** - * Simulates pointer arithmetic. - * A utility for porting C to Java where C code makes heavy use of pointer arithmetic. - * - * @Deprecated Remove when Post-Quantum Standardization project has finished and standard is published. - */ -final class IntSlicer -{ - private final int[] values; - private int base; - - IntSlicer(int[] values, int base) - { - this.values = values; - this.base = base; - } - - final int at(int index) - { - return values[base + index]; - } - - final int at(int index, int value) - { - return values[base + index] = value; - } - - - final int at(int index, long value) - { - return values[base + index] = (int)value; - } - - final IntSlicer from(int o) - { - return new IntSlicer(values, base + o); - } - - final void incBase(int paramM) - { - base += paramM; - - } - - final IntSlicer copy() - { - return new IntSlicer(values, base); - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLAKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLAKeyGenerationParameters.java deleted file mode 100644 index 48aafa4bc3..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLAKeyGenerationParameters.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.qtesla; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.KeyGenerationParameters; - -/** - * qTESLA key-pair generation parameters. - */ -public class QTESLAKeyGenerationParameters - extends KeyGenerationParameters -{ - private final int securityCategory; - - /** - * Base constructor - provide the qTESLA security category and a source of randomness. - * - * @param securityCategory the security category to generate the parameters for. - * @param random the random byte source. - */ - public QTESLAKeyGenerationParameters(int securityCategory, SecureRandom random) - { - super(random, -1); - - QTESLASecurityCategory.getPrivateSize(securityCategory); // check the category is valid - - this.securityCategory = securityCategory; - } - - /** - * Return the security category for these parameters. - * - * @return the security category for keys generated using these parameters. - */ - public int getSecurityCategory() - { - return securityCategory; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLAKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLAKeyPairGenerator.java deleted file mode 100644 index 879fa89ee9..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLAKeyPairGenerator.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.qtesla; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.KeyGenerationParameters; - -/** - * Key-pair generator for qTESLA keys. - */ -public final class QTESLAKeyPairGenerator - implements AsymmetricCipherKeyPairGenerator -{ - /** - * qTESLA Security Category - */ - private int securityCategory; - private SecureRandom secureRandom; - - /** - * Initialize the generator with a security category and a source of randomness. - * - * @param param a {@link QTESLAKeyGenerationParameters} object. - */ - public void init( - KeyGenerationParameters param) - { - QTESLAKeyGenerationParameters parameters = (QTESLAKeyGenerationParameters)param; - - this.secureRandom = parameters.getRandom(); - this.securityCategory = parameters.getSecurityCategory(); - } - - /** - * Generate a key-pair. - * - * @return a matching key-pair consisting of (QTESLAPublicKeyParameters, QTESLAPrivateKeyParameters). - */ - public AsymmetricCipherKeyPair generateKeyPair() - { - byte[] privateKey = allocatePrivate(securityCategory); - byte[] publicKey = allocatePublic(securityCategory); - - switch (securityCategory) - { - case QTESLASecurityCategory.PROVABLY_SECURE_I: - QTesla1p.generateKeyPair(publicKey, privateKey, secureRandom); - break; - - case QTESLASecurityCategory.PROVABLY_SECURE_III: - QTesla3p.generateKeyPair(publicKey, privateKey, secureRandom); - break; - - default: - throw new IllegalArgumentException("unknown security category: " + securityCategory); - } - - return new AsymmetricCipherKeyPair(new QTESLAPublicKeyParameters(securityCategory, publicKey), new QTESLAPrivateKeyParameters(securityCategory, privateKey)); - } - - private byte[] allocatePrivate(int securityCategory) - { - return new byte[QTESLASecurityCategory.getPrivateSize(securityCategory)]; - } - - private byte[] allocatePublic(int securityCategory) - { - return new byte[QTESLASecurityCategory.getPublicSize(securityCategory)]; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLAPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLAPrivateKeyParameters.java deleted file mode 100644 index 56e1bf3ddc..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLAPrivateKeyParameters.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.qtesla; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.util.Arrays; - -/** - * qTESLA private key - */ -public final class QTESLAPrivateKeyParameters - extends AsymmetricKeyParameter -{ - /** - * qTESLA Security Category (From 4 To 8) - */ - private int securityCategory; - - /** - * Text of the qTESLA Private Key - */ - private byte[] privateKey; - - /** - * Base constructor. - * - * @param securityCategory the security category for the passed in public key data. - * @param privateKey the private key data. - */ - public QTESLAPrivateKeyParameters(int securityCategory, byte[] privateKey) - { - super(true); - - if (privateKey.length != QTESLASecurityCategory.getPrivateSize(securityCategory)) - { - throw new IllegalArgumentException("invalid key size for security category"); - } - - this.securityCategory = securityCategory; - this.privateKey = Arrays.clone(privateKey); - } - - /** - * Return the security category for this key. - * - * @return the key's security category. - */ - public int getSecurityCategory() - { - return this.securityCategory; - } - - /** - * Return the key's secret value. - * - * @return key private data. - */ - public byte[] getSecret() - { - return Arrays.clone(privateKey); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLAPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLAPublicKeyParameters.java deleted file mode 100644 index 8e1260f7d0..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLAPublicKeyParameters.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.qtesla; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.util.Arrays; - -/** - * qTESLA public key - */ -public final class QTESLAPublicKeyParameters - extends AsymmetricKeyParameter -{ - /** - * qTESLA Security Category - */ - private int securityCategory; - - /** - * Text of the qTESLA Public Key - */ - private byte[] publicKey; - - /** - * Base constructor. - * - * @param securityCategory the security category for the passed in public key data. - * @param publicKey the public key data. - */ - public QTESLAPublicKeyParameters(int securityCategory, byte[] publicKey) - { - super(false); - - if (publicKey.length != QTESLASecurityCategory.getPublicSize(securityCategory)) - { - throw new IllegalArgumentException("invalid key size for security category"); - } - - this.securityCategory = securityCategory; - this.publicKey = Arrays.clone(publicKey); - - } - - /** - * Return the security category for this key. - * - * @return the key's security category. - */ - public int getSecurityCategory() - { - return this.securityCategory; - } - - /** - * Return the key's public value. - * - * @return key public data. - */ - public byte[] getPublicData() - { - return Arrays.clone(publicKey); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLASecurityCategory.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLASecurityCategory.java deleted file mode 100644 index f22fe2fca2..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLASecurityCategory.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.qtesla; - -/** - * The qTESLA security categories. - */ -public class QTESLASecurityCategory -{ - public static final int PROVABLY_SECURE_I = 5; - public static final int PROVABLY_SECURE_III = 6; - - private QTESLASecurityCategory() - { - } - - static void validate(int securityCategory) - { - switch (securityCategory) - { - case PROVABLY_SECURE_I: - case PROVABLY_SECURE_III: - break; - default: - throw new IllegalArgumentException("unknown security category: " + securityCategory); - } - } - - static int getPrivateSize(int securityCategory) - { - switch (securityCategory) - { - case PROVABLY_SECURE_I: - return QTesla1p.CRYPTO_SECRETKEYBYTES; - case PROVABLY_SECURE_III: - return QTesla3p.CRYPTO_SECRETKEYBYTES; - - default: - throw new IllegalArgumentException("unknown security category: " + securityCategory); - } - } - - static int getPublicSize(int securityCategory) - { - switch (securityCategory) - { - case PROVABLY_SECURE_I: - return QTesla1p.CRYPTO_PUBLICKEYBYTES; - case PROVABLY_SECURE_III: - return QTesla3p.CRYPTO_PUBLICKEYBYTES; - - default: - throw new IllegalArgumentException("unknown security category: " + securityCategory); - } - } - - static int getSignatureSize(int securityCategory) - { - switch (securityCategory) - { - - case PROVABLY_SECURE_I: - return QTesla1p.CRYPTO_BYTES; - case PROVABLY_SECURE_III: - return QTesla3p.CRYPTO_BYTES; - default: - throw new IllegalArgumentException("unknown security category: " + securityCategory); - } - } - - /** - * Return a standard name for the security category. - * - * @param securityCategory the category of interest. - * @return the name for the category. - */ - public static String getName(int securityCategory) - { - switch (securityCategory) - { - case PROVABLY_SECURE_I: - return "qTESLA-p-I"; - case PROVABLY_SECURE_III: - return "qTESLA-p-III"; - default: - throw new IllegalArgumentException("unknown security category: " + securityCategory); - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLASigner.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLASigner.java deleted file mode 100644 index a43f15aa83..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTESLASigner.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.qtesla; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.CryptoServicesRegistrar; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.MessageSigner; - -/** - * Signer for the qTESLA algorithm (https://qtesla.org/) - */ -public class QTESLASigner - implements MessageSigner -{ - /** - * The Public Key of the Identity Whose Signature Will be Generated - */ - private QTESLAPublicKeyParameters publicKey; - - /** - * The Private Key of the Identity Whose Signature Will be Generated - */ - private QTESLAPrivateKeyParameters privateKey; - - /** - * The Source of Randomness for private key operations - */ - private SecureRandom secureRandom; - - public QTESLASigner() - { - } - - /** - * Initialise the signer. - * - * @param forSigning true if we are generating a signature, false - * otherwise. - * @param param ParametersWithRandom containing a private key for signature generation, public key otherwise. - */ - public void init(boolean forSigning, CipherParameters param) - { - if (forSigning) - { - if (param instanceof ParametersWithRandom) - { - this.secureRandom = ((ParametersWithRandom)param).getRandom(); - privateKey = (QTESLAPrivateKeyParameters)((ParametersWithRandom)param).getParameters(); - } - else - { - this.secureRandom = CryptoServicesRegistrar.getSecureRandom(); - privateKey = (QTESLAPrivateKeyParameters)param; - } - publicKey = null; - QTESLASecurityCategory.validate(privateKey.getSecurityCategory()); - } - else - { - privateKey = null; - publicKey = (QTESLAPublicKeyParameters)param; - QTESLASecurityCategory.validate(publicKey.getSecurityCategory()); - } - } - - /** - * Generate a signature directly for the passed in message. - * - * @param message the message to be signed. - * @return the signature generated. - */ - public byte[] generateSignature(byte[] message) - { - byte[] sig = new byte[QTESLASecurityCategory.getSignatureSize(privateKey.getSecurityCategory())]; - - switch (privateKey.getSecurityCategory()) - { - case QTESLASecurityCategory.PROVABLY_SECURE_I: - QTesla1p.generateSignature(sig, message, 0, message.length, privateKey.getSecret(), secureRandom); - break; - case QTESLASecurityCategory.PROVABLY_SECURE_III: - QTesla3p.generateSignature(sig, message, 0, message.length, privateKey.getSecret(), secureRandom); - break; - default: - throw new IllegalArgumentException("unknown security category: " + privateKey.getSecurityCategory()); - } - - return sig; - } - - /** - * Verify the signature against the passed in message. - * - * @param message the message that was supposed to have been signed. - * @param signature the signature of the message - * @return true if the signature passes, false otherwise. - */ - public boolean verifySignature(byte[] message, byte[] signature) - { - int status; - - switch (publicKey.getSecurityCategory()) - { - - case QTESLASecurityCategory.PROVABLY_SECURE_I: - status = QTesla1p.verifying(message, signature, 0, signature.length, publicKey.getPublicData()); - break; - - case QTESLASecurityCategory.PROVABLY_SECURE_III: - status = QTesla3p.verifying(message, signature, 0, signature.length, publicKey.getPublicData()); - break; - - default: - throw new IllegalArgumentException("unknown security category: " + publicKey.getSecurityCategory()); - } - - return 0 == status; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTesla1p.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTesla1p.java deleted file mode 100644 index 1ce8cc3130..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTesla1p.java +++ /dev/null @@ -1,1214 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.qtesla; - -import java.security.SecureRandom; - -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Pack; - -class QTesla1p -{ - private static final int PARAM_N = 1024; - // private static final int PARAM_N_LOG = 10; -// private static final double PARAM_SIGMA = 8.5; - private static final int PARAM_Q = 343576577; - private static final int PARAM_Q_LOG = 29; - private static final long PARAM_QINV = 2205847551L; - private static final int PARAM_BARR_MULT = 3; - private static final int PARAM_BARR_DIV = 30; - private static final int PARAM_B = 524287; - private static final int PARAM_B_BITS = 19; - private static final int PARAM_S_BITS = 8; - private static final int PARAM_K = 4; - // private static final double PARAM_SIGMA_E = PARAM_SIGMA; - private static final int PARAM_H = 25; - private static final int PARAM_D = 22; - private static final int PARAM_GEN_A = 108; - private static final int PARAM_KEYGEN_BOUND_E = 554; - private static final int PARAM_E = PARAM_KEYGEN_BOUND_E; - private static final int PARAM_KEYGEN_BOUND_S = 554; - private static final int PARAM_S = PARAM_KEYGEN_BOUND_S; - private static final int PARAM_R2_INVN = 13632409; -// private static final int PARAM_R = 172048372; - - private static final int CRYPTO_RANDOMBYTES = 32; - private static final int CRYPTO_SEEDBYTES = 32; - private static final int CRYPTO_C_BYTES = 32; - private static final int HM_BYTES = 40; - - // private static final int RADIX = 32; - private static final int RADIX32 = 32; - - - // Contains signature (z,c). z is a polynomial bounded by B, c is the output of a hashed string - static final int CRYPTO_BYTES = (PARAM_N * (PARAM_B_BITS + 1) + 7) / 8 + CRYPTO_C_BYTES; - // Contains polynomial s and e, and seeds seed_a and seed_y - static final int CRYPTO_SECRETKEYBYTES = (PARAM_K + 1) * PARAM_S_BITS * PARAM_N / 8 + 2 * CRYPTO_SEEDBYTES + HM_BYTES; - // Contains seed_a and polynomials t - static final int CRYPTO_PUBLICKEYBYTES = (PARAM_K * PARAM_Q_LOG * PARAM_N + 7) / 8 + CRYPTO_SEEDBYTES; - - - static int generateKeyPair(byte[] publicKey, byte[] privateKey, SecureRandom secureRandom) - { - /* Initialize Domain Separator for Error Polynomial and Secret Polynomial */ - int nonce = 0; - - byte[] randomness = new byte[CRYPTO_RANDOMBYTES]; - - /* Extend Random Bytes to Seed Generation of Error Polynomial and Secret Polynomial */ - byte[] randomnessExtended = new byte[(PARAM_K + 3) * CRYPTO_SEEDBYTES]; - - int[] secretPolynomial = new int[PARAM_N]; - int[] errorPolynomial = new int[PARAM_N * PARAM_K]; - int[] A = new int[PARAM_N * PARAM_K]; - int[] T = new int[PARAM_N * PARAM_K]; - - int[] s_ntt = new int[PARAM_N]; - - /* Get randomnessExtended <- seedErrorPolynomial, seedSecretPolynomial, seedA, seedY */ - // this.rng.randomByte (randomness, (short) 0, Polynomial.RANDOM); - secureRandom.nextBytes(randomness); - - HashUtils.secureHashAlgorithmKECCAK128( - randomnessExtended, 0, (PARAM_K + 3) * CRYPTO_SEEDBYTES, - randomness, 0, CRYPTO_RANDOMBYTES); - - /* - * Sample the Error Polynomial Fulfilling the Criteria - * Choose All Error Polynomial in R with Entries from D_SIGMA - * Repeat Step at Iteration if the h Largest Entries of Error Polynomial Summation to L_E - */ - for (int k = 0; k < PARAM_K; k++) - { - do - { - Gaussian.sample_gauss_poly(++nonce, randomnessExtended, k * CRYPTO_SEEDBYTES, errorPolynomial, k * PARAM_N); - } - while (checkPolynomial(errorPolynomial, k * PARAM_N, PARAM_KEYGEN_BOUND_E)); - } - - /* - * Sample the Secret Polynomial Fulfilling the Criteria - * Choose Secret Polynomial in R with Entries from D_SIGMA - * Repeat Step if the h Largest Entries of Secret Polynomial Summation to L_S - */ - do - { - Gaussian.sample_gauss_poly(++nonce, randomnessExtended, PARAM_K * CRYPTO_SEEDBYTES, secretPolynomial, 0); - } - while (checkPolynomial(secretPolynomial, 0, PARAM_KEYGEN_BOUND_S)); - - QTesla1PPolynomial.poly_uniform(A, randomnessExtended, (PARAM_K + 1) * CRYPTO_SEEDBYTES); - QTesla1PPolynomial.poly_ntt(s_ntt, secretPolynomial); - - for (int k = 0; k < PARAM_K; k++) - { - QTesla1PPolynomial.poly_mul(T, k * PARAM_N, A, k * PARAM_N, s_ntt); - QTesla1PPolynomial.poly_add_correct(T, k * PARAM_N, T, k * PARAM_N, errorPolynomial, k * PARAM_N); - } - - /* Pack Public and Private Keys */ - encodePublicKey(publicKey, T, randomnessExtended, (PARAM_K + 1) * CRYPTO_SEEDBYTES); - encodePrivateKey(privateKey, secretPolynomial, errorPolynomial, randomnessExtended, (PARAM_K + 1) * CRYPTO_SEEDBYTES, publicKey); - - return 0; - } - - static int generateSignature(byte[] signature, byte[] message, int messageOffset, int messageLength, - byte[] privateKey, SecureRandom secureRandom) - { - byte[] c = new byte[CRYPTO_C_BYTES]; - byte[] randomness = new byte[CRYPTO_SEEDBYTES]; - byte[] randomness_input = new byte[CRYPTO_SEEDBYTES + CRYPTO_RANDOMBYTES + 2 * HM_BYTES]; - int[] pos_list = new int[PARAM_H]; - short[] sign_list = new short[PARAM_H]; - int[] y = new int[PARAM_N]; - - int[] y_ntt = new int[PARAM_N]; - int[] Sc = new int[PARAM_N]; - int[] z = new int[PARAM_N]; - - int[] v = new int[PARAM_N * PARAM_K]; - int[] Ec = new int[PARAM_N * PARAM_K]; - int[] a = new int[PARAM_N * PARAM_K]; - - int k; - int nonce = 0; // Initialize domain separator for sampling y - boolean rsp = false; - - System.arraycopy(privateKey, CRYPTO_SECRETKEYBYTES - HM_BYTES - CRYPTO_SEEDBYTES, randomness_input, 0, CRYPTO_SEEDBYTES); - - { - byte[] tmp = new byte[CRYPTO_RANDOMBYTES]; - secureRandom.nextBytes(tmp); - System.arraycopy(tmp, 0, randomness_input, CRYPTO_SEEDBYTES, CRYPTO_RANDOMBYTES); - } - - HashUtils.secureHashAlgorithmKECCAK128( - randomness_input, CRYPTO_SEEDBYTES + CRYPTO_RANDOMBYTES, HM_BYTES, - message, 0, messageLength); - - HashUtils.secureHashAlgorithmKECCAK128( - randomness, 0, CRYPTO_SEEDBYTES, - randomness_input, 0, randomness_input.length - HM_BYTES); - - System.arraycopy(privateKey, CRYPTO_SECRETKEYBYTES - HM_BYTES, randomness_input, randomness_input.length - HM_BYTES, HM_BYTES); - - QTesla1PPolynomial.poly_uniform(a, privateKey, CRYPTO_SECRETKEYBYTES - HM_BYTES - 2 * CRYPTO_SEEDBYTES); - - while (true) - { - sample_y(y, randomness, 0, ++nonce); - - QTesla1PPolynomial.poly_ntt(y_ntt, y); - for (k = 0; k < PARAM_K; k++) - { - QTesla1PPolynomial.poly_mul(v, k * PARAM_N, a, k * PARAM_N, y_ntt); - } - - hashFunction(c, 0, v, randomness_input, CRYPTO_SEEDBYTES + CRYPTO_RANDOMBYTES); - encodeC(pos_list, sign_list, c, 0); - - QTesla1PPolynomial.sparse_mul8(Sc, 0, privateKey, 0, pos_list, sign_list); - - QTesla1PPolynomial.poly_add(z, y, Sc); - - if (testRejection(z)) - { - continue; - } - - for (k = 0; k < PARAM_K; k++) - { - QTesla1PPolynomial.sparse_mul8(Ec, k * PARAM_N, privateKey, (PARAM_N * (k + 1)), pos_list, sign_list); - QTesla1PPolynomial.poly_sub(v, k * PARAM_N, v, k * PARAM_N, Ec, k * PARAM_N); - rsp = test_correctness(v, k * PARAM_N); - if (rsp) - { - break; - } // TODO replace with contine outer - } - if (rsp) - { - continue; - } - - encodeSignature(signature, 0, c, 0, z); - return 0; - } - } - - static int verifying(byte[] message, final byte[] signature, int signatureOffset, int signatureLength, - final byte[] publicKey) - { - byte c[] = new byte[CRYPTO_C_BYTES]; - byte c_sig[] = new byte[CRYPTO_C_BYTES]; - byte seed[] = new byte[CRYPTO_SEEDBYTES]; - byte hm[] = new byte[2 * HM_BYTES]; - int pos_list[] = new int[PARAM_H]; - short sign_list[] = new short[PARAM_H]; - int pk_t[] = new int[PARAM_N * PARAM_K]; - int[] w = new int[PARAM_N * PARAM_K]; - int[] a = new int[PARAM_N * PARAM_K]; - int[] Tc = new int[PARAM_N * PARAM_K]; - - int[] z = new int[PARAM_N]; - int[] z_ntt = new int[PARAM_N]; - - int k = 0; - - if (signatureLength != CRYPTO_BYTES) - { - return -1; - } - - decodeSignature(c, z, signature, signatureOffset); - if (testZ(z)) - { - return -2; - } - decodePublicKey(pk_t, seed, 0, publicKey); - - // Get H(m) and hash_pk - HashUtils.secureHashAlgorithmKECCAK128( - hm, 0, HM_BYTES, - message, 0, message.length); - HashUtils.secureHashAlgorithmKECCAK128( - hm, HM_BYTES, HM_BYTES, - publicKey, 0, CRYPTO_PUBLICKEYBYTES - CRYPTO_SEEDBYTES); - - QTesla1PPolynomial.poly_uniform(a, seed, 0); - encodeC(pos_list, sign_list, c, 0); - QTesla1PPolynomial.poly_ntt(z_ntt, z); - - for (k = 0; k < PARAM_K; k++) - { // Compute w = az - tc - QTesla1PPolynomial.sparse_mul32(Tc, k * PARAM_N, pk_t, (k * PARAM_N), pos_list, sign_list); - QTesla1PPolynomial.poly_mul(w, k * PARAM_N, a, k * PARAM_N, z_ntt); - QTesla1PPolynomial.poly_sub_reduce(w, k * PARAM_N, w, k * PARAM_N, Tc, k * PARAM_N); - } - hashFunction(c_sig, 0, w, hm, 0); - - if (!memoryEqual(c, 0, c_sig, 0, CRYPTO_C_BYTES)) - { - return -3; - } - - return 0; - } - - static void encodePrivateKey(byte[] privateKey, int[] secretPolynomial, int[] errorPolynomial, - byte[] seed, int seedOffset, byte[] publicKey) - { - int i, k = 0; - int skPtr = 0; - - for (i = 0; i < PARAM_N; i++) - { - privateKey[skPtr + i] = (byte)secretPolynomial[i]; - } - skPtr += PARAM_N; - - for (k = 0; k < PARAM_K; k++) - { - for (i = 0; i < PARAM_N; i++) - { - privateKey[skPtr + (k * PARAM_N + i)] = (byte)errorPolynomial[k * PARAM_N + i]; - } - } - skPtr += PARAM_K * PARAM_N; - - System.arraycopy(seed, seedOffset, privateKey, skPtr, CRYPTO_SEEDBYTES * 2); - skPtr += CRYPTO_SEEDBYTES * 2; - - /* Hash of the public key */ - HashUtils.secureHashAlgorithmKECCAK128( - privateKey, skPtr, HM_BYTES, - publicKey, 0, CRYPTO_PUBLICKEYBYTES - CRYPTO_SEEDBYTES); - skPtr += HM_BYTES; - -// assert CRYPTO_SECRETKEYBYTES == skPtr; - } - - static void encodePublicKey(byte[] publicKey, final int[] T, final byte[] seedA, int seedAOffset) - { - int j = 0; - - for (int i = 0; i < (PARAM_N * PARAM_K * PARAM_Q_LOG / 32); i += PARAM_Q_LOG) - { - at(publicKey, i, 0, T[j] | (T[j + 1] << 29)); - at(publicKey, i, 1, (T[j + 1] >> 3) | (T[j + 2] << 26)); - at(publicKey, i, 2, (T[j + 2] >> 6) | (T[j + 3] << 23)); - at(publicKey, i, 3, (T[j + 3] >> 9) | (T[j + 4] << 20)); - at(publicKey, i, 4, (T[j + 4] >> 12) | (T[j + 5] << 17)); - at(publicKey, i, 5, (T[j + 5] >> 15) | (T[j + 6] << 14)); - at(publicKey, i, 6, (T[j + 6] >> 18) | (T[j + 7] << 11)); - at(publicKey, i, 7, (T[j + 7] >> 21) | (T[j + 8] << 8)); - at(publicKey, i, 8, (T[j + 8] >> 24) | (T[j + 9] << 5)); - at(publicKey, i, 9, (T[j + 9] >> 27) | (T[j + 10] << 2) | (T[j + 11] << 31)); - at(publicKey, i, 10, (T[j + 11] >> 1) | (T[j + 12] << 28)); - at(publicKey, i, 11, (T[j + 12] >> 4) | (T[j + 13] << 25)); - at(publicKey, i, 12, (T[j + 13] >> 7) | (T[j + 14] << 22)); - at(publicKey, i, 13, (T[j + 14] >> 10) | (T[j + 15] << 19)); - at(publicKey, i, 14, (T[j + 15] >> 13) | (T[j + 16] << 16)); - at(publicKey, i, 15, (T[j + 16] >> 16) | (T[j + 17] << 13)); - at(publicKey, i, 16, (T[j + 17] >> 19) | (T[j + 18] << 10)); - at(publicKey, i, 17, (T[j + 18] >> 22) | (T[j + 19] << 7)); - at(publicKey, i, 18, (T[j + 19] >> 25) | (T[j + 20] << 4)); - at(publicKey, i, 19, (T[j + 20] >> 28) | (T[j + 21] << 1) | (T[j + 22] << 30)); - at(publicKey, i, 20, (T[j + 22] >> 2) | (T[j + 23] << 27)); - at(publicKey, i, 21, (T[j + 23] >> 5) | (T[j + 24] << 24)); - at(publicKey, i, 22, (T[j + 24] >> 8) | (T[j + 25] << 21)); - at(publicKey, i, 23, (T[j + 25] >> 11) | (T[j + 26] << 18)); - at(publicKey, i, 24, (T[j + 26] >> 14) | (T[j + 27] << 15)); - at(publicKey, i, 25, (T[j + 27] >> 17) | (T[j + 28] << 12)); - at(publicKey, i, 26, (T[j + 28] >> 20) | (T[j + 29] << 9)); - at(publicKey, i, 27, (T[j + 29] >> 23) | (T[j + 30] << 6)); - at(publicKey, i, 28, (T[j + 30] >> 26) | (T[j + 31] << 3)); - j += 32; - } - - System.arraycopy(seedA, seedAOffset, publicKey, PARAM_N * PARAM_K * PARAM_Q_LOG / 8, CRYPTO_SEEDBYTES); - } - - static void decodePublicKey(int[] publicKey, byte[] seedA, int seedAOffset, final byte[] publicKeyInput) - { - - int j = 0; - byte[] pt = publicKeyInput; - int mask29 = (1 << PARAM_Q_LOG) - 1; - - - for (int i = 0; i < PARAM_N * PARAM_K; i += 32) - { - publicKey[i] = at(pt, j, 0) & mask29; - publicKey[i + 1] = ((at(pt, j, 0) >>> 29) | (at(pt, j, 1) << 3)) & mask29; - publicKey[i + 2] = ((at(pt, j, 1) >>> 26) | (at(pt, j, 2) << 6)) & mask29; - publicKey[i + 3] = ((at(pt, j, 2) >>> 23) | (at(pt, j, 3) << 9)) & mask29; - publicKey[i + 4] = ((at(pt, j, 3) >>> 20) | (at(pt, j, 4) << 12)) & mask29; - publicKey[i + 5] = ((at(pt, j, 4) >>> 17) | (at(pt, j, 5) << 15)) & mask29; - publicKey[i + 6] = ((at(pt, j, 5) >>> 14) | (at(pt, j, 6) << 18)) & mask29; - publicKey[i + 7] = ((at(pt, j, 6) >>> 11) | (at(pt, j, 7) << 21)) & mask29; - publicKey[i + 8] = ((at(pt, j, 7) >>> 8) | (at(pt, j, 8) << 24)) & mask29; - publicKey[i + 9] = ((at(pt, j, 8) >>> 5) | (at(pt, j, 9) << 27)) & mask29; - publicKey[i + 10] = (at(pt, j, 9) >>> 2) & mask29; - publicKey[i + 11] = ((at(pt, j, 9) >>> 31) | (at(pt, j, 10) << 1)) & mask29; - publicKey[i + 12] = ((at(pt, j, 10) >>> 28) | (at(pt, j, 11) << 4)) & mask29; - publicKey[i + 13] = ((at(pt, j, 11) >>> 25) | (at(pt, j, 12) << 7)) & mask29; - publicKey[i + 14] = ((at(pt, j, 12) >>> 22) | (at(pt, j, 13) << 10)) & mask29; - publicKey[i + 15] = ((at(pt, j, 13) >>> 19) | (at(pt, j, 14) << 13)) & mask29; - publicKey[i + 16] = ((at(pt, j, 14) >>> 16) | (at(pt, j, 15) << 16)) & mask29; - publicKey[i + 17] = ((at(pt, j, 15) >>> 13) | (at(pt, j, 16) << 19)) & mask29; - publicKey[i + 18] = ((at(pt, j, 16) >>> 10) | (at(pt, j, 17) << 22)) & mask29; - publicKey[i + 19] = ((at(pt, j, 17) >>> 7) | (at(pt, j, 18) << 25)) & mask29; - publicKey[i + 20] = ((at(pt, j, 18) >>> 4) | (at(pt, j, 19) << 28)) & mask29; - publicKey[i + 21] = (at(pt, j, 19) >>> 1) & mask29; - publicKey[i + 22] = ((at(pt, j, 19) >>> 30) | (at(pt, j, 20) << 2)) & mask29; - publicKey[i + 23] = ((at(pt, j, 20) >>> 27) | (at(pt, j, 21) << 5)) & mask29; - publicKey[i + 24] = ((at(pt, j, 21) >>> 24) | (at(pt, j, 22) << 8)) & mask29; - publicKey[i + 25] = ((at(pt, j, 22) >>> 21) | (at(pt, j, 23) << 11)) & mask29; - publicKey[i + 26] = ((at(pt, j, 23) >>> 18) | (at(pt, j, 24) << 14)) & mask29; - publicKey[i + 27] = ((at(pt, j, 24) >>> 15) | (at(pt, j, 25) << 17)) & mask29; - publicKey[i + 28] = ((at(pt, j, 25) >>> 12) | (at(pt, j, 26) << 20)) & mask29; - publicKey[i + 29] = ((at(pt, j, 26) >>> 9) | (at(pt, j, 27) << 23)) & mask29; - publicKey[i + 30] = ((at(pt, j, 27) >>> 6) | (at(pt, j, 28) << 26)) & mask29; - publicKey[i + 31] = at(pt, j, 28) >>> 3; - j += 29; - } - - - System.arraycopy(publicKeyInput, PARAM_N * PARAM_K * PARAM_Q_LOG / 8, seedA, seedAOffset, CRYPTO_SEEDBYTES); - - } - - private static boolean testZ(int[] Z) - { - // Returns false if valid, otherwise outputs 1 if invalid (rejected) - - for (int i = 0; i < PARAM_N; i++) - { - if ((Z[i] < -(PARAM_B - PARAM_S)) || (Z[i] > PARAM_B - PARAM_S)) - { - return true; - } - } - return false; - } - - private static final int maskb1 = ((1 << (PARAM_B_BITS + 1)) - 1); - - static void encodeSignature(byte[] signature, int signatureOffset, byte[] C, int cOffset, int[] Z) - { - int j = 0; - - for (int i = 0; i < (PARAM_N * (PARAM_B_BITS + 1) / 32); i += 10) - { - at(signature, i, 0, (Z[j] & ((1 << 20) - 1)) | (Z[j + 1] << 20)); - at(signature, i, 1, ((Z[j + 1] >>> 12) & ((1 << 8) - 1)) | ((Z[j + 2] & maskb1) << 8) | (Z[j + 3] << 28)); - at(signature, i, 2, ((Z[j + 3] >>> 4) & ((1 << 16) - 1)) | (Z[j + 4] << 16)); - at(signature, i, 3, ((Z[j + 4] >>> 16) & ((1 << 4) - 1)) | ((Z[j + 5] & maskb1) << 4) | (Z[j + 6] << 24)); - at(signature, i, 4, ((Z[j + 6] >>> 8) & ((1 << 12) - 1)) | (Z[j + 7] << 12)); - at(signature, i, 5, (Z[j + 8] & ((1 << 20) - 1)) | (Z[j + 9] << 20)); - at(signature, i, 6, ((Z[j + 9] >>> 12) & ((1 << 8) - 1)) | ((Z[j + 10] & maskb1) << 8) | (Z[j + 11] << 28)); - at(signature, i, 7, ((Z[j + 11] >>> 4) & ((1 << 16) - 1)) | (Z[j + 12] << 16)); - at(signature, i, 8, ((Z[j + 12] >>> 16) & ((1 << 4) - 1)) | ((Z[j + 13] & maskb1) << 4) | (Z[j + 14] << 24)); - at(signature, i, 9, ((Z[j + 14] >>> 8) & ((1 << 12) - 1)) | (Z[j + 15] << 12)); - j += 16; - } - - System.arraycopy(C, cOffset, signature, signatureOffset + PARAM_N * (PARAM_B_BITS + 1) / 8, CRYPTO_C_BYTES); - } - - static void decodeSignature(byte[] C, int[] Z, final byte[] signature, int signatureOffset) - { - int j = 0; - for (int i = 0; i < PARAM_N; i += 16) - { - int s0 = at(signature, j, 0); - int s1 = at(signature, j, 1); - int s2 = at(signature, j, 2); - int s3 = at(signature, j, 3); - int s4 = at(signature, j, 4); - int s5 = at(signature, j, 5); - int s6 = at(signature, j, 6); - int s7 = at(signature, j, 7); - int s8 = at(signature, j, 8); - int s9 = at(signature, j, 9); - - Z[i] = (s0 << 12) >> 12; - Z[i + 1] = (s0 >>> 20) | ((s1 << 24) >> 12); - Z[i + 2] = ((s1 << 4) >> 12); - Z[i + 3] = (s1 >>> 28) | ((s2 << 16) >> 12); - Z[i + 4] = (s2 >>> 16) | ((s3 << 28) >> 12); - Z[i + 5] = (s3 << 8) >> 12; - Z[i + 6] = (s3 >>> 24) | ((s4 << 20) >> 12); - Z[i + 7] = s4 >> 12; - Z[i + 8] = (s5 << 12) >> 12; - Z[i + 9] = (s5 >>> 20) | ((s6 << 24) >> 12); - Z[i + 10] = (s6 << 4) >> 12; - Z[i + 11] = (s6 >>> 28) | ((s7 << 16) >> 12); - Z[i + 12] = (s7 >>> 16) | ((s8 << 28) >> 12); - Z[i + 13] = (s8 << 8) >> 12; - Z[i + 14] = (s8 >>> 24) | ((s9 << 20) >> 12); - Z[i + 15] = (s9 >> 12); - j += 10; - } - System.arraycopy(signature, signatureOffset + PARAM_N * (PARAM_B_BITS + 1) / 8, C, 0, CRYPTO_C_BYTES); - } - - static void encodeC(int[] positionList, short[] signList, byte[] output, int outputOffset) - { - int count = 0; - int position; - short domainSeparator = 0; - short[] C = new short[PARAM_N]; - byte[] randomness = new byte[HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE]; - - // Enc: the XOF is instantiated with cSHAKE128 (see Algorithm 14). - HashUtils.customizableSecureHashAlgorithmKECCAK128Simple( - randomness, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE, - domainSeparator++, - output, outputOffset, CRYPTO_RANDOMBYTES - ); - - /* Use Rejection Sampling to Determine Positions to be Set in the New Vector */ - Arrays.fill(C, (short)0); - - /* Sample A Unique Position k times. - * Use Two Bytes - */ - for (int i = 0; i < PARAM_H; ) - { - if (count > HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE - 3) - { - // Enc: the XOF is instantiated with cSHAKE128 (see Algorithm 14). - HashUtils.customizableSecureHashAlgorithmKECCAK128Simple( - randomness, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE, - domainSeparator++, - output, outputOffset, CRYPTO_RANDOMBYTES - ); - - count = 0; - } - - position = (randomness[count] << 8) | (randomness[count + 1] & 0xFF); - position &= (PARAM_N - 1); - - /* Position is between [0, n - 1] and Has not Been Set Yet - * Determine Signature - */ - if (C[position] == 0) - { - - if ((randomness[count + 2] & 1) == 1) - { - - C[position] = -1; - - } - else - { - - C[position] = 1; - - } - - positionList[i] = position; - signList[i] = C[position]; - i++; - - } - - count += 3; - } - } - - private static void hashFunction(byte[] output, int outputOffset, int[] v, byte[] message, int messageOffset) - { - int mask; - int cL; - - byte[] T = new byte[PARAM_K * PARAM_N + 2 * HM_BYTES]; - - for (int k = 0; k < PARAM_K; k++) - { - int index = k * PARAM_N; - for (int i = 0; i < PARAM_N; i++) - { - int temp = v[index]; - // If v[i] > PARAM_Q/2 then v[i] -= PARAM_Q - mask = (PARAM_Q / 2 - temp) >> (RADIX32 - 1); - temp = ((temp - PARAM_Q) & mask) | (temp & ~mask); - - cL = temp & ((1 << PARAM_D) - 1); - // If cL > 2^(d-1) then cL -= 2^d - mask = ((1 << (PARAM_D - 1)) - cL) >> (RADIX32 - 1); - cL = ((cL - (1 << PARAM_D)) & mask) | (cL & ~mask); - T[index++] = (byte)((temp - cL) >> PARAM_D); - } - } - System.arraycopy(message, messageOffset, T, PARAM_N * PARAM_K, 2 * HM_BYTES); - - HashUtils.secureHashAlgorithmKECCAK128( - output, outputOffset, CRYPTO_C_BYTES, - T, 0, T.length); - } - - static int littleEndianToInt24(byte[] bs, int off) - { - int n = bs[off] & 0xff; - n |= (bs[++off] & 0xff) << 8; - n |= (bs[++off] & 0xff) << 16; - return n; - } - - private static int NBLOCKS_SHAKE = HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE / (((PARAM_B_BITS + 1) + 7) / 8); - private static int BPLUS1BYTES = ((PARAM_B_BITS + 1) + 7) / 8; - - static void sample_y(int[] y, byte[] seed, int seedOffset, int nonce) - { // Sample polynomial y, such that each coefficient is in the range [-B,B] - int i = 0, pos = 0, nblocks = PARAM_N; - byte buf[] = new byte[PARAM_N * BPLUS1BYTES + 1]; - int nbytes = BPLUS1BYTES; - short dmsp = (short)(nonce << 8); - - HashUtils.customizableSecureHashAlgorithmKECCAK128Simple( - buf, 0, PARAM_N * nbytes, dmsp++, seed, seedOffset, CRYPTO_RANDOMBYTES - ); - - while (i < PARAM_N) - { - if (pos >= nblocks * nbytes) - { - nblocks = NBLOCKS_SHAKE; - HashUtils.customizableSecureHashAlgorithmKECCAK128Simple( - buf, 0, PARAM_N * nbytes, dmsp++, seed, seedOffset, CRYPTO_RANDOMBYTES - ); - pos = 0; - } - y[i] = littleEndianToInt24(buf, pos) & ((1 << (PARAM_B_BITS + 1)) - 1); - y[i] -= PARAM_B; - if (y[i] != (1 << PARAM_B_BITS)) - { - i++; - } - pos += nbytes; - } - } - - private static void at(byte[] bs, int base, int index, int value) - { - Pack.intToLittleEndian(value, bs, (base + index) << 2); - } - - private static int at(byte[] bs, int base, int index) - { - return Pack.littleEndianToInt(bs, (base + index) << 2); - } - - static boolean test_correctness(int[] v, int vpos) - { // Check bounds for w = v - ec during signature verification. Returns 0 if valid, otherwise outputs 1 if invalid (rejected). - // This function leaks the position of the coefficient that fails the test (but this is independent of the secret data). - // It does not leak the sign of the coefficients. - int mask, left, val; - int t0, t1; - - for (int i = 0; i < PARAM_N; i++) - { - // If v[i] > PARAM_Q/2 then v[i] -= PARAM_Q - int a = v[vpos + i]; - mask = (PARAM_Q / 2 - a) >> (RADIX32 - 1); - val = ((a - PARAM_Q) & mask) | (a & ~mask); - // If (Abs(val) < PARAM_Q/2 - PARAM_E) then t0 = 0, else t0 = 1 - t0 = (~(absolute(val) - (PARAM_Q / 2 - PARAM_E))) >>> (RADIX32 - 1); - - left = val; - val = (val + (1 << (PARAM_D - 1)) - 1) >> PARAM_D; - val = left - (val << PARAM_D); - // If (Abs(val) < (1<<(PARAM_D-1))-PARAM_E) then t1 = 0, else t1 = 1 - t1 = (~(absolute(val) - ((1 << (PARAM_D - 1)) - PARAM_E))) >>> (RADIX32 - 1); - - if ((t0 | t1) == 1) // Returns 1 if any of the two tests failed - { - return true; - } - } - return false; - } - - private static boolean testRejection(int[] Z) - { - int valid = 0; - - for (int i = 0; i < PARAM_N; i++) - { - valid |= (PARAM_B - PARAM_S) - absolute(Z[i]); - } - - return (valid >>> 31) != 0; - } - - private static int absolute(int value) - { - int sign = value >> (RADIX32 - 1); - return (sign ^ value) - sign; - } - - private static boolean checkPolynomial(int[] polynomial, int polyOffset, int bound) - { - int i, j, sum = 0, limit = PARAM_N; - int temp, mask; - int[] list = new int[PARAM_N]; - - for (j = 0; j < PARAM_N; j++) - { - list[j] = absolute(polynomial[polyOffset + j]); - } - - for (j = 0; j < PARAM_H; j++) - { - for (i = 0; i < limit - 1; i++) - { - int a = list[i], b = list[i + 1]; - // If list[i+1] > list[i] then exchange contents - mask = (b - a) >> (RADIX32 - 1); - temp = (b & mask) | (a & ~mask); - list[i + 1] = (a & mask) | (b & ~mask); - list[i] = temp; - } - sum += list[limit - 1]; - limit -= 1; - } - - return sum > bound; - } - - static boolean memoryEqual(byte[] left, int leftOffset, byte[] right, int rightOffset, int length) - { - - if ((leftOffset + length <= left.length) && (rightOffset + length <= right.length)) - { - - for (int i = 0; i < length; i++) - { - - if (left[leftOffset + i] != right[rightOffset + i]) - { - - return false; - - } - - } - - return true; - - } - else - { - - return false; - - } - - } - - // End of outer. - - static class Gaussian - { - private static final int CDT_ROWS = 78; - private static final int CDT_COLS = 2; - private static final int CHUNK_SIZE = 512; - - private static final int[] cdt_v = new int[]{ - 0x00000000, 0x00000000, // 0 - 0x0601F22A, 0x280663D4, // 1 - 0x11F09FFA, 0x162FE23D, // 2 - 0x1DA089E9, 0x437226E8, // 3 - 0x28EAB25D, 0x04C51FE2, // 4 - 0x33AC2F26, 0x14FDBA70, // 5 - 0x3DC767DC, 0x4565C960, // 6 - 0x4724FC62, 0x3342C78A, // 7 - 0x4FB448F4, 0x5229D06D, // 8 - 0x576B8599, 0x7423407F, // 9 - 0x5E4786DA, 0x3210BAF7, // 10 - 0x644B2C92, 0x431B3947, // 11 - 0x697E90CE, 0x77C362C4, // 12 - 0x6DEE0B96, 0x2798C9CE, // 13 - 0x71A92144, 0x5765FCE4, // 14 - 0x74C16FD5, 0x1E2A0990, // 15 - 0x7749AC92, 0x0DF36EEB, // 16 - 0x7954BFA4, 0x28079289, // 17 - 0x7AF5067A, 0x2EDC2050, // 18 - 0x7C3BC17C, 0x123D5E7B, // 19 - 0x7D38AD76, 0x2A9381D9, // 20 - 0x7DF9C5DF, 0x0E868CA7, // 21 - 0x7E8B2ABA, 0x18E5C811, // 22 - 0x7EF7237C, 0x00908272, // 23 - 0x7F4637C5, 0x6DBA5126, // 24 - 0x7F7F5707, 0x4A52EDEB, // 25 - 0x7FA808CC, 0x23290599, // 26 - 0x7FC4A083, 0x69BDF2D5, // 27 - 0x7FD870CA, 0x42275558, // 28 - 0x7FE5FB5D, 0x3EF82C1B, // 29 - 0x7FEF1BFA, 0x6C03A362, // 30 - 0x7FF52D4E, 0x316C2C8C, // 31 - 0x7FF927BA, 0x12AE54AF, // 32 - 0x7FFBBA43, 0x749CC0E2, // 33 - 0x7FFD5E3D, 0x4524AD91, // 34 - 0x7FFE6664, 0x535785B5, // 35 - 0x7FFF0A41, 0x0B291681, // 36 - 0x7FFF6E81, 0x132C3D6F, // 37 - 0x7FFFAAFE, 0x4DBC6BED, // 38 - 0x7FFFCEFD, 0x7A1E2D14, // 39 - 0x7FFFE41E, 0x4C6EC115, // 40 - 0x7FFFF059, 0x319503C8, // 41 - 0x7FFFF754, 0x5DDD0D40, // 42 - 0x7FFFFB43, 0x0B9E9823, // 43 - 0x7FFFFD71, 0x76B81AE1, // 44 - 0x7FFFFEA3, 0x7E66A1EC, // 45 - 0x7FFFFF49, 0x26F6E191, // 46 - 0x7FFFFFA1, 0x2FA31694, // 47 - 0x7FFFFFCF, 0x5247BEC9, // 48 - 0x7FFFFFE7, 0x4F4127C7, // 49 - 0x7FFFFFF3, 0x6FAA69FD, // 50 - 0x7FFFFFFA, 0x0630D073, // 51 - 0x7FFFFFFD, 0x0F2957BB, // 52 - 0x7FFFFFFE, 0x4FD29432, // 53 - 0x7FFFFFFF, 0x2CFAD60D, // 54 - 0x7FFFFFFF, 0x5967A930, // 55 - 0x7FFFFFFF, 0x6E4C9DFF, // 56 - 0x7FFFFFFF, 0x77FDCCC8, // 57 - 0x7FFFFFFF, 0x7C6CE89E, // 58 - 0x7FFFFFFF, 0x7E6D116F, // 59 - 0x7FFFFFFF, 0x7F50FA31, // 60 - 0x7FFFFFFF, 0x7FB50089, // 61 - 0x7FFFFFFF, 0x7FE04C2D, // 62 - 0x7FFFFFFF, 0x7FF2C7C1, // 63 - 0x7FFFFFFF, 0x7FFA8FE3, // 64 - 0x7FFFFFFF, 0x7FFDCB1B, // 65 - 0x7FFFFFFF, 0x7FFF1DE2, // 66 - 0x7FFFFFFF, 0x7FFFA6B7, // 67 - 0x7FFFFFFF, 0x7FFFDD39, // 68 - 0x7FFFFFFF, 0x7FFFF2A3, // 69 - 0x7FFFFFFF, 0x7FFFFAEF, // 70 - 0x7FFFFFFF, 0x7FFFFE1B, // 71 - 0x7FFFFFFF, 0x7FFFFF4D, // 72 - 0x7FFFFFFF, 0x7FFFFFBF, // 73 - 0x7FFFFFFF, 0x7FFFFFE9, // 74 - 0x7FFFFFFF, 0x7FFFFFF8, // 75 - 0x7FFFFFFF, 0x7FFFFFFD, // 76 - 0x7FFFFFFF, 0x7FFFFFFF, // 77 - }; - - static void sample_gauss_poly(int nonce, byte[] seed, int seedOffset, int[] poly, int polyOffset) - { - int dmsp = nonce << 8; - - byte samp[] = new byte[CHUNK_SIZE * CDT_COLS * 4]; // This is int32_t in C, we will treat it as byte[] in java - int c[] = new int[CDT_COLS]; - int borrow, sign; - int mask = (-1) >>> 1; - - for (int chunk = 0; chunk < PARAM_N; chunk += CHUNK_SIZE) - { - HashUtils.customizableSecureHashAlgorithmKECCAK128Simple( - samp, 0, CHUNK_SIZE * CDT_COLS * 4, (short)dmsp++, seed, seedOffset, CRYPTO_SEEDBYTES); - - for (int i = 0; i < CHUNK_SIZE; i++) - { - poly[polyOffset + chunk + i] = 0; - for (int j = 1; j < CDT_ROWS; j++) - { - borrow = 0; - for (int k = CDT_COLS - 1; k >= 0; k--) - { - c[k] = (at(samp, i * CDT_COLS, k) & mask) - (cdt_v[j * CDT_COLS + k] + borrow); - borrow = c[k] >> (RADIX32 - 1); - } - poly[polyOffset + chunk + i] += ~borrow & 1; - } - -// sign = at(samp,i*CDT_COLS, 0) >> (RADIX32-1); - sign = (int)samp[((i * CDT_COLS) << 2) + 3] >> (RADIX32 - 1); - - poly[polyOffset + chunk + i] = (sign & -poly[polyOffset + chunk + i]) | (~sign & poly[polyOffset + chunk + i]); - } - } - } - } - - static class QTesla1PPolynomial - { - private static final int[] zeta = new int[]{ - 184007114, 341297933, 172127038, 306069179, 260374244, 269720605, 20436325, 2157599, 36206659, 61987110, 112759694, 92762708, 278504038, 139026960, 183642748, 298230187, - 37043356, 230730845, 107820937, 97015745, 156688276, 38891102, 170244636, 259345227, 170077366, 141586883, 100118513, 328793523, 289946488, 263574185, 132014089, 14516260, - 87424978, 192691578, 190961717, 262687761, 333967048, 12957952, 326574509, 273585413, 151922543, 195893203, 261889302, 120488377, 169571794, 44896463, 128576039, 68257019, - 20594664, 44164717, 36060712, 256009818, 172063915, 211967562, 135533785, 104908181, 203788155, 52968398, 123297488, 44711423, 329131026, 245797804, 220629853, 200431766, - 92905498, 215466666, 227373088, 120513729, 274875394, 236766448, 84216704, 97363940, 224003799, 167341181, 333540791, 225846253, 290150331, 137934911, 101127339, 95054535, - 7072757, 58600117, 264117725, 207480694, 268253444, 292044590, 166300682, 256585624, 133577520, 119707476, 58169614, 188489502, 184778640, 156039906, 286669262, 112658784, - 89254003, 266568758, 290599527, 80715937, 180664712, 225980378, 103512701, 304604206, 327443646, 92082345, 296093912, 144843084, 309484036, 329737605, 141656867, 264967053, - 227847682, 328674715, 208663554, 309005608, 315790590, 182996330, 333212133, 203436199, 13052895, 23858345, 173478900, 97132319, 57066271, 70747422, 202106993, 309870606, - 56390934, 336126437, 189147643, 219236223, 293351741, 305570320, 18378834, 336914091, 59506067, 277923611, 217306643, 129369847, 308113789, 56954705, 190254906, 199465001, - 119331054, 143640880, 17590914, 309468163, 172483421, 153376031, 58864560, 70957183, 237697179, 116097341, 62196815, 80692520, 310642530, 328595292, 12121494, 71200620, - 200016287, 235006678, 21821056, 102505389, 183332133, 59734849, 283127491, 313646880, 30359439, 163176989, 50717815, 100183661, 322975554, 92821217, 283119421, 34453836, - 303758926, 89460722, 147514506, 175603941, 76494101, 220775631, 304963431, 38821441, 217317485, 301302769, 328727631, 101476595, 270750726, 253708871, 176201368, 324059659, - 114780906, 304156831, 273708648, 144095014, 263545324, 179240984, 187811389, 244886526, 202581571, 209325648, 117231636, 182195945, 217965216, 252295904, 332003328, 46153749, - 334740528, 62618402, 301165510, 283016648, 212224416, 234984074, 107363471, 125430881, 172821269, 270409387, 156316970, 311644197, 50537885, 248376507, 154072039, 331539029, - 48454192, 267029920, 225963915, 16753350, 76840946, 226444843, 108106635, 154887261, 326283837, 101291223, 204194230, 54014060, 104099734, 104245071, 260949411, 333985274, - 291682234, 328313139, 29607387, 106291750, 162553334, 275058303, 64179189, 263147140, 15599810, 325103190, 137254480, 66787068, 4755224, 308520011, 181897417, 325162685, - 221099032, 131741505, 147534370, 131533267, 144073688, 166398146, 155829711, 252509898, 251605008, 323547097, 216038649, 232629333, 95137254, 287931575, 235583527, 32386598, - 76722491, 60825791, 138354268, 400761, 51907675, 197369064, 319840588, 98618414, 84343982, 108113946, 314679670, 134518178, 64988900, 4333172, 295712261, 200707216, - 147647414, 318013383, 77682006, 92518996, 42154619, 87464521, 285037574, 332936592, 62635246, 5534097, 308862707, 91097989, 269726589, 273280832, 251670430, 95492698, - 21676891, 182964692, 177187742, 294825274, 85128609, 273594538, 93115857, 116308166, 312212122, 18665807, 32192823, 313249299, 98777368, 273984239, 312125377, 205655336, - 264861277, 178920022, 341054719, 232663249, 173564046, 176591124, 157537342, 305058098, 277279130, 170028356, 228573747, 31628995, 175280663, 37304323, 122111670, 210658936, - 175704183, 314649282, 325535066, 266783938, 301319742, 327923297, 279787306, 304633001, 304153402, 292839078, 147442886, 94150133, 40461238, 221384781, 269671052, 265445273, - 208370149, 160863546, 287765159, 339146643, 129600429, 96192870, 113146118, 95879915, 216708053, 285201955, 67756451, 79028039, 309141895, 138447809, 212246614, 12641916, - 243544995, 33459809, 76979779, 71155723, 152521243, 200750888, 36425947, 339074467, 319204591, 188312744, 266105966, 280016981, 183723313, 238915015, 23277613, 160934729, - 200611286, 163282810, 297928823, 226921588, 86839172, 145317111, 202226936, 51887320, 318474782, 282270658, 221219795, 207597867, 132089009, 334627662, 163952597, 67529059, - 173759630, 234865017, 255217646, 277806158, 61964704, 216678166, 96126463, 39218331, 70028373, 4899005, 238135514, 242700690, 284680271, 81041980, 332906491, 463527, - 299280916, 204600651, 149654879, 222229829, 26825157, 81825189, 127990873, 200962599, 16149163, 108812393, 217708971, 152638110, 28735779, 5272794, 19720409, 231726324, - 49854178, 118319174, 185669526, 223407181, 243138094, 259020958, 308825615, 164156486, 341391280, 192526841, 97036052, 279986894, 20263748, 32228956, 43816679, 343421811, - 124320208, 3484106, 31711063, 147679160, 195369505, 54243678, 279088595, 149119313, 301997352, 244557309, 19700779, 138872683, 230523717, 113507709, 135291486, 313025300, - 254384479, 219815764, 253574481, 220646316, 124744817, 123915741, 325760383, 123516396, 138140410, 154060994, 314730104, 57286356, 222353426, 76630003, 145380041, 52039855, - 229881219, 332902036, 152308429, 95071889, 124799350, 270141530, 47897266, 119620601, 133269057, 138561303, 341820265, 66049665, 273409631, 304306012, 212490958, 210388603, - 277413768, 280793261, 223131872, 162407285, 44911970, 316685837, 298709373, 252812339, 230786851, 230319350, 56863422, 341141914, 177295413, 248222411, 215148650, 97970603, - 291678055, 161911155, 339645428, 206445182, 31895080, 279676698, 78257775, 268845232, 92545841, 336725589, 47384597, 62216335, 82290365, 89893410, 266117967, 791867, - 28042243, 110563426, 183316855, 281174508, 166338432, 86326996, 261473803, 164647535, 84749290, 157518777, 214336587, 72257047, 13358702, 229010735, 204196474, 179927635, - 21786785, 330554989, 164559635, 144505300, 280425045, 324057501, 268227440, 323362437, 26891539, 228523003, 166709094, 61174973, 13532911, 42168701, 133044957, 158219357, - 220115616, 15174468, 281706353, 283813987, 263212325, 289818392, 247170937, 276072317, 197581495, 33713097, 181695825, 96829354, 32991226, 228583784, 4040287, 65188717, - 258204083, 96366799, 176298395, 341574369, 306098123, 218746932, 29191888, 311810435, 305844323, 31614267, 28130094, 72716426, 38568041, 197579396, 14876445, 228525674, - 294569685, 2451649, 165929882, 112195415, 204786047, 138216235, 3438132, 126150615, 59754608, 158965324, 268160978, 266231264, 244422459, 306155336, 218178824, 301806695, - 208837335, 212153467, 209725081, 269355286, 295716530, 13980580, 264284060, 301901789, 275319045, 107139083, 4006959, 143908623, 139848274, 25357089, 21607040, 340818603, - 91260932, 198869267, 45119941, 224113252, 269556513, 42857483, 268925602, 188501450, 235382337, 324688793, 113056679, 177232352, 98280013, 117743899, 87369665, 330110286, - 310895756, 268425063, 27568325, 266303142, 181405304, 65876631, 246283438, 127636847, 16153922, 210256884, 9257227, 147272724, 235571791, 340876897, 31558760, 224463520, - 229909008, 40943950, 263351999, 14865952, 27279162, 51980445, 99553161, 108121152, 145230283, 217402431, 84060866, 190168688, 46894008, 205718237, 296935065, 331646198, - 59709076, 265829428, 214503586, 310273189, 86051634, 247210969, 275872780, 55395653, 302717617, 155583500, 207999042, 293597246, 305796948, 139332832, 198434142, 104197059, - 320317582, 101819543, 70813687, 43594385, 241913829, 210308279, 298735610, 151599086, 92093482, 24654121, 52528801, 134711941, 324580593, 293101038, 121757877, 323940193, - 276114751, 33522997, 218880483, 46953248, 33126382, 294367143, 161595040, 208968904, 129221110, 323693686, 234366848, 50155901, 123936119, 72127416, 34243899, 171824126, - 26019236, 93997235, 28452989, 24219933, 188331672, 181161011, 146526219, 186502916, 258266311, 207146754, 206589869, 189836867, 107762500, 129011227, 222324073, 331319091, - 36618753, 141615400, 273319528, 246222615, 156139193, 290104141, 154851520, 310226922, 60187406, 73704819, 225899604, 87931539, 142487643, 152682959, 45891249, 212048348, - 148547910, 207745063, 4405848, 179269204, 216233362, 230307487, 303352796, 41616117, 47140231, 13452075, 94626849, 48892822, 78453712, 214721933, 300785835, 1512599, - 173577933, 163255132, 239883248, 205714288, 306118903, 106953300, 150085654, 77068348, 246390345, 199698311, 280165539, 256497526, 194381508, 78125966, 168327358, 180735395, - 145983352, 243342736, 198463602, 83165996, 286431792, 22885329, 271516106, 66137359, 243561376, 324886778, 149497212, 24531379, 32857894, 62778029, 56960216, 224996784, - 129315394, 81068505, 277744916, 215817366, 117205172, 195090165, 287841567, 57750901, 162987791, 259309908, 135370005, 194853269, 236792732, 219249166, 42349628, 27805769, - 186263338, 310699018, 6491000, 228545163, 315890485, 22219119, 144392189, 15505150, 87848372, 155973124, 20446561, 177725890, 226669021, 205315635, 269580641, 133696452, - 189388357, 314652032, 317225560, 304194584, 157633737, 298144493, 185785271, 337434647, 559796, 4438732, 249110619, 184824722, 221490126, 205632858, 172362641, 176702767, - 276712118, 296075254, 111221225, 259809961, 15438443, 198021462, 134378223, 162261445, 170746654, 256890644, 125206341, 307078324, 279553989, 170124925, 296845387, 188226544, - 295437875, 315053523, 172025817, 279046062, 189967278, 158662482, 192989875, 326540363, 135446089, 98631439, 257379933, 325004289, 26554274, 62190249, 228828648, 274361329, - 18518762, 184854759, 210189061, 186836398, 230859454, 206912014, 201250021, 276332768, 119984643, 91358832, 325377399, 69085488, 307352479, 308876137, 208756649, 32865966, - 152976045, 207821125, 66426662, 67585526, 118828370, 3107192, 322037257, 146029104, 106553806, 266958791, 89567376, 153815988, 90786397, 271042585, 203781777, 169087756, - 315867500, 306916544, 7528726, 327732739, 227901532, 2263402, 14357894, 269740764, 322090105, 59838559, 298337502, 292797139, 337635349, 66476915, 75612762, 328089387, - 155232910, 87069405, 36163560, 273715413, 321325749, 218096743, 308178877, 21861281, 180676741, 135208372, 119891712, 122406065, 267537516, 341350322, 87789083, 196340943, - 217070591, 83564209, 159382818, 253921239, 184673854, 213569600, 194031064, 35973794, 18071215, 250854127, 115090766, 147707843, 330337973, 266187164, 27853295, 296801215, - 254949704, 43331190, 73930201, 35703461, 119780800, 216998106, 12687572, 250863345, 243908221, 330555990, 296216993, 202100577, 111307303, 151049872, 103451600, 237710099, - 78658022, 121490075, 134292528, 88277916, 177315676, 186629690, 77848818, 211822377, 145696683, 289190386, 274721999, 328391282, 218772820, 91324151, 321725584, 277577004, - 65732866, 275538085, 144429136, 204062923, 177280727, 214204692, 264758257, 169151951, 335535576, 334002493, 281131703, 305997258, 310527888, 136973519, 216764406, 235954329, - 254049694, 285174861, 264316834, 11792643, 149333889, 214699018, 261331547, 317320791, 24527858, 118790777, 264146824, 174296812, 332779737, 94199786, 288227027, 172048372, - }; - - private static final int[] zetainv = new int[]{ - 55349550, 249376791, 10796840, 169279765, 79429753, 224785800, 319048719, 26255786, 82245030, 128877559, 194242688, 331783934, 79259743, 58401716, 89526883, 107622248, - 126812171, 206603058, 33048689, 37579319, 62444874, 9574084, 8041001, 174424626, 78818320, 129371885, 166295850, 139513654, 199147441, 68038492, 277843711, 65999573, - 21850993, 252252426, 124803757, 15185295, 68854578, 54386191, 197879894, 131754200, 265727759, 156946887, 166260901, 255298661, 209284049, 222086502, 264918555, 105866478, - 240124977, 192526705, 232269274, 141476000, 47359584, 13020587, 99668356, 92713232, 330889005, 126578471, 223795777, 307873116, 269646376, 300245387, 88626873, 46775362, - 315723282, 77389413, 13238604, 195868734, 228485811, 92722450, 325505362, 307602783, 149545513, 130006977, 158902723, 89655338, 184193759, 260012368, 126505986, 147235634, - 255787494, 2226255, 76039061, 221170512, 223684865, 208368205, 162899836, 321715296, 35397700, 125479834, 22250828, 69861164, 307413017, 256507172, 188343667, 15487190, - 267963815, 277099662, 5941228, 50779438, 45239075, 283738018, 21486472, 73835813, 329218683, 341313175, 115675045, 15843838, 336047851, 36660033, 27709077, 174488821, - 139794800, 72533992, 252790180, 189760589, 254009201, 76617786, 237022771, 197547473, 21539320, 340469385, 224748207, 275991051, 277149915, 135755452, 190600532, 310710611, - 134819928, 34700440, 36224098, 274491089, 18199178, 252217745, 223591934, 67243809, 142326556, 136664563, 112717123, 156740179, 133387516, 158721818, 325057815, 69215248, - 114747929, 281386328, 317022303, 18572288, 86196644, 244945138, 208130488, 17036214, 150586702, 184914095, 153609299, 64530515, 171550760, 28523054, 48138702, 155350033, - 46731190, 173451652, 64022588, 36498253, 218370236, 86685933, 172829923, 181315132, 209198354, 145555115, 328138134, 83766616, 232355352, 47501323, 66864459, 166873810, - 171213936, 137943719, 122086451, 158751855, 94465958, 339137845, 343016781, 6141930, 157791306, 45432084, 185942840, 39381993, 26351017, 28924545, 154188220, 209880125, - 73995936, 138260942, 116907556, 165850687, 323130016, 187603453, 255728205, 328071427, 199184388, 321357458, 27686092, 115031414, 337085577, 32877559, 157313239, 315770808, - 301226949, 124327411, 106783845, 148723308, 208206572, 84266669, 180588786, 285825676, 55735010, 148486412, 226371405, 127759211, 65831661, 262508072, 214261183, 118579793, - 286616361, 280798548, 310718683, 319045198, 194079365, 18689799, 100015201, 277439218, 72060471, 320691248, 57144785, 260410581, 145112975, 100233841, 197593225, 162841182, - 175249219, 265450611, 149195069, 87079051, 63411038, 143878266, 97186232, 266508229, 193490923, 236623277, 37457674, 137862289, 103693329, 180321445, 169998644, 342063978, - 42790742, 128854644, 265122865, 294683755, 248949728, 330124502, 296436346, 301960460, 40223781, 113269090, 127343215, 164307373, 339170729, 135831514, 195028667, 131528229, - 297685328, 190893618, 201088934, 255645038, 117676973, 269871758, 283389171, 33349655, 188725057, 53472436, 187437384, 97353962, 70257049, 201961177, 306957824, 12257486, - 121252504, 214565350, 235814077, 153739710, 136986708, 136429823, 85310266, 157073661, 197050358, 162415566, 155244905, 319356644, 315123588, 249579342, 317557341, 171752451, - 309332678, 271449161, 219640458, 293420676, 109209729, 19882891, 214355467, 134607673, 181981537, 49209434, 310450195, 296623329, 124696094, 310053580, 67461826, 19636384, - 221818700, 50475539, 18995984, 208864636, 291047776, 318922456, 251483095, 191977491, 44840967, 133268298, 101662748, 299982192, 272762890, 241757034, 23258995, 239379518, - 145142435, 204243745, 37779629, 49979331, 135577535, 187993077, 40858960, 288180924, 67703797, 96365608, 257524943, 33303388, 129072991, 77747149, 283867501, 11930379, - 46641512, 137858340, 296682569, 153407889, 259515711, 126174146, 198346294, 235455425, 244023416, 291596132, 316297415, 328710625, 80224578, 302632627, 113667569, 119113057, - 312017817, 2699680, 108004786, 196303853, 334319350, 133319693, 327422655, 215939730, 97293139, 277699946, 162171273, 77273435, 316008252, 75151514, 32680821, 13466291, - 256206912, 225832678, 245296564, 166344225, 230519898, 18887784, 108194240, 155075127, 74650975, 300719094, 74020064, 119463325, 298456636, 144707310, 252315645, 2757974, - 321969537, 318219488, 203728303, 199667954, 339569618, 236437494, 68257532, 41674788, 79292517, 329595997, 47860047, 74221291, 133851496, 131423110, 134739242, 41769882, - 125397753, 37421241, 99154118, 77345313, 75415599, 184611253, 283821969, 217425962, 340138445, 205360342, 138790530, 231381162, 177646695, 341124928, 49006892, 115050903, - 328700132, 145997181, 305008536, 270860151, 315446483, 311962310, 37732254, 31766142, 314384689, 124829645, 37478454, 2002208, 167278182, 247209778, 85372494, 278387860, - 339536290, 114992793, 310585351, 246747223, 161880752, 309863480, 145995082, 67504260, 96405640, 53758185, 80364252, 59762590, 61870224, 328402109, 123460961, 185357220, - 210531620, 301407876, 330043666, 282401604, 176867483, 115053574, 316685038, 20214140, 75349137, 19519076, 63151532, 199071277, 179016942, 13021588, 321789792, 163648942, - 139380103, 114565842, 330217875, 271319530, 129239990, 186057800, 258827287, 178929042, 82102774, 257249581, 177238145, 62402069, 160259722, 233013151, 315534334, 342784710, - 77458610, 253683167, 261286212, 281360242, 296191980, 6850988, 251030736, 74731345, 265318802, 63899879, 311681497, 137131395, 3931149, 181665422, 51898522, 245605974, - 128427927, 95354166, 166281164, 2434663, 286713155, 113257227, 112789726, 90764238, 44867204, 26890740, 298664607, 181169292, 120444705, 62783316, 66162809, 133187974, - 131085619, 39270565, 70166946, 277526912, 1756312, 205015274, 210307520, 223955976, 295679311, 73435047, 218777227, 248504688, 191268148, 10674541, 113695358, 291536722, - 198196536, 266946574, 121223151, 286290221, 28846473, 189515583, 205436167, 220060181, 17816194, 219660836, 218831760, 122930261, 90002096, 123760813, 89192098, 30551277, - 208285091, 230068868, 113052860, 204703894, 323875798, 99019268, 41579225, 194457264, 64487982, 289332899, 148207072, 195897417, 311865514, 340092471, 219256369, 154766, - 299759898, 311347621, 323312829, 63589683, 246540525, 151049736, 2185297, 179420091, 34750962, 84555619, 100438483, 120169396, 157907051, 225257403, 293722399, 111850253, - 323856168, 338303783, 314840798, 190938467, 125867606, 234764184, 327427414, 142613978, 215585704, 261751388, 316751420, 121346748, 193921698, 138975926, 44295661, 343113050, - 10670086, 262534597, 58896306, 100875887, 105441063, 338677572, 273548204, 304358246, 247450114, 126898411, 281611873, 65770419, 88358931, 108711560, 169816947, 276047518, - 179623980, 8948915, 211487568, 135978710, 122356782, 61305919, 25101795, 291689257, 141349641, 198259466, 256737405, 116654989, 45647754, 180293767, 142965291, 182641848, - 320298964, 104661562, 159853264, 63559596, 77470611, 155263833, 24371986, 4502110, 307150630, 142825689, 191055334, 272420854, 266596798, 310116768, 100031582, 330934661, - 131329963, 205128768, 34434682, 264548538, 275820126, 58374622, 126868524, 247696662, 230430459, 247383707, 213976148, 4429934, 55811418, 182713031, 135206428, 78131304, - 73905525, 122191796, 303115339, 249426444, 196133691, 50737499, 39423175, 38943576, 63789271, 15653280, 42256835, 76792639, 18041511, 28927295, 167872394, 132917641, - 221464907, 306272254, 168295914, 311947582, 115002830, 173548221, 66297447, 38518479, 186039235, 166985453, 170012531, 110913328, 2521858, 164656555, 78715300, 137921241, - 31451200, 69592338, 244799209, 30327278, 311383754, 324910770, 31364455, 227268411, 250460720, 69982039, 258447968, 48751303, 166388835, 160611885, 321899686, 248083879, - 91906147, 70295745, 73849988, 252478588, 34713870, 338042480, 280941331, 10639985, 58539003, 256112056, 301421958, 251057581, 265894571, 25563194, 195929163, 142869361, - 47864316, 339243405, 278587677, 209058399, 28896907, 235462631, 259232595, 244958163, 23735989, 146207513, 291668902, 343175816, 205222309, 282750786, 266854086, 311189979, - 107993050, 55645002, 248439323, 110947244, 127537928, 20029480, 91971569, 91066679, 187746866, 177178431, 199502889, 212043310, 196042207, 211835072, 122477545, 18413892, - 161679160, 35056566, 338821353, 276789509, 206322097, 18473387, 327976767, 80429437, 279397388, 68518274, 181023243, 237284827, 313969190, 15263438, 51894343, 9591303, - 82627166, 239331506, 239476843, 289562517, 139382347, 242285354, 17292740, 188689316, 235469942, 117131734, 266735631, 326823227, 117612662, 76546657, 295122385, 12037548, - 189504538, 95200070, 293038692, 31932380, 187259607, 73167190, 170755308, 218145696, 236213106, 108592503, 131352161, 60559929, 42411067, 280958175, 8836049, 297422828, - 11573249, 91280673, 125611361, 161380632, 226344941, 134250929, 140995006, 98690051, 155765188, 164335593, 80031253, 199481563, 69867929, 39419746, 228795671, 19516918, - 167375209, 89867706, 72825851, 242099982, 14848946, 42273808, 126259092, 304755136, 38613146, 122800946, 267082476, 167972636, 196062071, 254115855, 39817651, 309122741, - 60457156, 250755360, 20601023, 243392916, 292858762, 180399588, 313217138, 29929697, 60449086, 283841728, 160244444, 241071188, 321755521, 108569899, 143560290, 272375957, - 331455083, 14981285, 32934047, 262884057, 281379762, 227479236, 105879398, 272619394, 284712017, 190200546, 171093156, 34108414, 325985663, 199935697, 224245523, 144111576, - 153321671, 286621872, 35462788, 214206730, 126269934, 65652966, 284070510, 6662486, 325197743, 38006257, 50224836, 124340354, 154428934, 7450140, 287185643, 33705971, - 141469584, 272829155, 286510306, 246444258, 170097677, 319718232, 330523682, 140140378, 10364444, 160580247, 27785987, 34570969, 134913023, 14901862, 115728895, 78609524, - 201919710, 13838972, 34092541, 198733493, 47482665, 251494232, 16132931, 38972371, 240063876, 117596199, 162911865, 262860640, 52977050, 77007819, 254322574, 230917793, - 56907315, 187536671, 158797937, 155087075, 285406963, 223869101, 209999057, 86990953, 177275895, 51531987, 75323133, 136095883, 79458852, 284976460, 336503820, 248522042, - 242449238, 205641666, 53426246, 117730324, 10035786, 176235396, 119572778, 246212637, 259359873, 106810129, 68701183, 223062848, 116203489, 128109911, 250671079, 143144811, - 122946724, 97778773, 14445551, 298865154, 220279089, 290608179, 139788422, 238668396, 208042792, 131609015, 171512662, 87566759, 307515865, 299411860, 322981913, 275319558, - 215000538, 298680114, 174004783, 223088200, 81687275, 147683374, 191654034, 69991164, 17002068, 330618625, 9609529, 80888816, 152614860, 150884999, 256151599, 329060317, - 211562488, 80002392, 53630089, 14783054, 243458064, 201989694, 173499211, 84231350, 173331941, 304685475, 186888301, 246560832, 235755640, 112845732, 306533221, 45346390, - 159933829, 204549617, 65072539, 250813869, 230816883, 281589467, 307369918, 341418978, 323140252, 73855972, 83202333, 37507398, 171449539, 2278644, 159569463, 171528205, - }; - - static void poly_uniform(int[] a, byte[] seed, int seedOffset) - { - int pos = 0, i = 0, nbytes = (PARAM_Q_LOG + 7) / 8; - int nblocks = PARAM_GEN_A; - int val1, val2, val3, val4, mask = (1 << PARAM_Q_LOG) - 1; - byte[] buf = new byte[HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * PARAM_GEN_A]; - short dmsp = 0; - - // GenA: the XOF is instantiated with cSHAKE128 (see Algorithm 10). - HashUtils.customizableSecureHashAlgorithmKECCAK128Simple( - buf, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * PARAM_GEN_A, - dmsp++, - seed, seedOffset, CRYPTO_RANDOMBYTES - ); - - while (i < PARAM_K * PARAM_N) - { - if (pos > HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * nblocks - 4 * nbytes) - { - nblocks = 1; - - // GenA: the XOF is instantiated with cSHAKE128 (see Algorithm 10). - HashUtils.customizableSecureHashAlgorithmKECCAK128Simple( - buf, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * PARAM_GEN_A, - dmsp++, - seed, seedOffset, CRYPTO_RANDOMBYTES - ); - - pos = 0; - } - - val1 = Pack.littleEndianToInt(buf, pos) & mask; - pos += nbytes; - val2 = Pack.littleEndianToInt(buf, pos) & mask; - pos += nbytes; - val3 = Pack.littleEndianToInt(buf, pos) & mask; - pos += nbytes; - val4 = Pack.littleEndianToInt(buf, pos) & mask; - pos += nbytes; - - if (val1 < PARAM_Q && i < PARAM_K * PARAM_N) - { - a[i++] = reduce((long)val1 * PARAM_R2_INVN); - } - if (val2 < PARAM_Q && i < PARAM_K * PARAM_N) - { - a[i++] = reduce((long)val2 * PARAM_R2_INVN); - } - if (val3 < PARAM_Q && i < PARAM_K * PARAM_N) - { - a[i++] = reduce((long)val3 * PARAM_R2_INVN); - } - if (val4 < PARAM_Q && i < PARAM_K * PARAM_N) - { - a[i++] = reduce((long)val4 * PARAM_R2_INVN); - } - } - } - - static int reduce(long a) - { // Montgomery reduction - long u; - - u = (a * (long)PARAM_QINV) & 0xFFFFFFFFL; - u *= PARAM_Q; - a += u; - return (int)(a >> 32); - } - - static void ntt(int[] a, int[] w) - { // Forward NTT transform - int NumoProblems = PARAM_N >> 1, jTwiddle = 0; - - for (; NumoProblems > 0; NumoProblems >>= 1) - { - int jFirst, j = 0; - for (jFirst = 0; jFirst < PARAM_N; jFirst = j + NumoProblems) - { - int W = w[jTwiddle++]; - for (j = jFirst; j < jFirst + NumoProblems; j++) - { - int a_j = a[j], a_n = a[j + NumoProblems]; - int temp = reduce((long)W * a_n); - a[j] = correct(a_j + temp - PARAM_Q); - a[j + NumoProblems] = correct(a_j - temp); - } - } - } - } - - private static int barr_reduce(int a) - { // Barrett reduction - int u = (int)(((long)a * PARAM_BARR_MULT) >> PARAM_BARR_DIV); - return a - u * PARAM_Q; - } - - private static int barr_reduce64(long a) - { // Barrett reduction - long u = (a * PARAM_BARR_MULT) >> PARAM_BARR_DIV; - return (int)(a - u * PARAM_Q); - } - - private static int correct(int x) - { - return x + ((x >> (RADIX32 - 1)) & PARAM_Q); - } - - static void nttinv(int[] a, int aPos, int[] w) - { // Inverse NTT transform - int NumoProblems = 1, jTwiddle = 0; - for (NumoProblems = 1; NumoProblems < PARAM_N; NumoProblems *= 2) - { - int jFirst, j = 0; - for (jFirst = 0; jFirst < PARAM_N; jFirst = j + NumoProblems) - { - int W = w[jTwiddle++]; - for (j = jFirst; j < jFirst + NumoProblems; j++) - { - int temp = a[aPos + j]; - a[aPos + j] = barr_reduce(temp + a[aPos + j + NumoProblems]); - a[aPos + j + NumoProblems] = reduce((long)W * (temp - a[aPos + j + NumoProblems])); - } - } - } - } - - static void poly_ntt(int[] x_ntt, int[] x) - { // Call to NTT function. Avoids input destruction - - for (int i = 0; i < PARAM_N; i++) - { - x_ntt[i] = x[i]; - } - ntt(x_ntt, zeta); - } - - static void poly_pointwise(int[] result, int rpos, int[] x, int xpos, int[] y) - { // Pointwise polynomial multiplication result = x.y - - for (int i = 0; i < PARAM_N; i++) - { - result[i + rpos] = reduce((long)x[i + xpos] * y[i]); - } - } - - static void poly_mul(int[] result, int rpos, int[] x, int xpos, int[] y) - { // Polynomial multiplication result = x*y, with in place reduction for (X^N+1) - - poly_pointwise(result, rpos, x, xpos, y); - nttinv(result, rpos, zetainv); - } - - static void poly_add(int[] result, int[] x, int[] y) - { // Polynomial addition result = x+y - - for (int i = 0; i < PARAM_N; i++) - { - result[i] = x[i] + y[i]; - } - } - - static void poly_add_correct(int[] result, int rpos, int[] x, int xpos, int[] y, int ypos) - { // Polynomial addition result = x+y with correction - - for (int i = 0; i < PARAM_N; i++) - { - int ri = correct(x[xpos + i] + y[ypos + i]); - result[rpos + i] = correct(ri - PARAM_Q); - } - } - - static void poly_sub(int[] result, int rpos, int[] x, int xpos, int[] y, int ypos) - { // Polynomial subtraction result = x-y - - for (int i = 0; i < PARAM_N; i++) - { - result[rpos + i] = x[xpos + i] - y[ypos + i]; - } - } - - static void poly_sub_reduce(int[] result, int rpos, int[] x, int xpos, int[] y, int ypos) - { // Polynomial subtraction result = x-y - - for (int i = 0; i < PARAM_N; i++) - { - result[rpos + i] = barr_reduce(x[xpos + i] - y[ypos + i]); - } - } - - static void sparse_mul8(int[] prod, int ppos, byte[] s, int spos, int[] pos_list, short[] sign_list) - { - // TODO Review multiplications involving elements of s (an unsigned char* in reference implementation) - int i, j, pos; - - for (i = 0; i < PARAM_N; i++) - { - prod[ppos + i] = 0; - } - - for (i = 0; i < PARAM_H; i++) - { - pos = pos_list[i]; - for (j = 0; j < pos; j++) - { - prod[ppos + j] = prod[ppos + j] - sign_list[i] * s[spos + j + PARAM_N - pos]; - } - for (j = pos; j < PARAM_N; j++) - { - prod[ppos + j] = prod[ppos + j] + sign_list[i] * s[spos + j - pos]; - } - } - } - - static void sparse_mul32(int[] prod, int ppos, int[] pk, int pkPos, int[] pos_list, short[] sign_list) - { - int i, j, pos; - long[] temp = new long[PARAM_N]; - - for (i = 0; i < PARAM_H; i++) - { - pos = pos_list[i]; - for (j = 0; j < pos; j++) - { - temp[j] = temp[j] - sign_list[i] * pk[pkPos + j + PARAM_N - pos]; - } - for (j = pos; j < PARAM_N; j++) - { - temp[j] = temp[j] + sign_list[i] * pk[pkPos + j - pos]; - } - } - - for (i = 0; i < PARAM_N; i++) - { - prod[ppos + i] = barr_reduce64(temp[i]); - } - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTesla3p.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTesla3p.java deleted file mode 100644 index 19013c53b7..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTesla3p.java +++ /dev/null @@ -1,1504 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.qtesla; - -import java.security.SecureRandom; - -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Pack; - -class QTesla3p -{ - private static final int PARAM_N = 2048; -// private static final double PARAM_SIGMA = 8.5; - private static final int PARAM_Q = 856145921; - private static final int PARAM_Q_LOG = 30; - private static final long PARAM_QINV = 587710463; - private static final long PARAM_BARR_MULT = 5; - private static final int PARAM_BARR_DIV = 32; - private static final int PARAM_B = 2097151; - private static final int PARAM_B_BITS = 21; -// private static final int PARAM_S_BITS = 8; - private static final int PARAM_K = 5; -// private static final double PARAM_SIGMA_E = PARAM_SIGMA; - private static final int PARAM_H = 40; - private static final int PARAM_D = 24; - private static final int PARAM_GEN_A = 180; - private static final int PARAM_KEYGEN_BOUND_E = 901; - private static final int PARAM_E = PARAM_KEYGEN_BOUND_E; - private static final int PARAM_KEYGEN_BOUND_S = 901; - private static final int PARAM_S = PARAM_KEYGEN_BOUND_S; - private static final int PARAM_R2_INVN = 513161157; -// private static final int PARAM_R = 14237691; - - private static final int CRYPTO_RANDOMBYTES = 32; - private static final int CRYPTO_SEEDBYTES = 32; - private static final int CRYPTO_C_BYTES = 32; - private static final int HM_BYTES = 40; - -// private static final int RADIX = 32; - private static final int RADIX32 = 32; - - - static final int CRYPTO_BYTES = ((PARAM_N * (PARAM_B_BITS + 1) + 7) / 8 + CRYPTO_C_BYTES); - // Contains polynomial s and e, and seeds seed_a and seed_y - static final int CRYPTO_SECRETKEYBYTES = (1 * PARAM_N + 1 * PARAM_N * PARAM_K + 2 * CRYPTO_SEEDBYTES + HM_BYTES); - - // Contains seed_a and polynomials t - static final int CRYPTO_PUBLICKEYBYTES = ((PARAM_Q_LOG * PARAM_N * PARAM_K + 7) / 8 + CRYPTO_SEEDBYTES); - - static int generateKeyPair(byte[] publicKey, byte[] privateKey, SecureRandom secureRandom) - { - /* Initialize Domain Separator for Error Polynomial and Secret Polynomial */ - int nonce = 0; - - byte[] randomness = new byte[CRYPTO_RANDOMBYTES]; - - /* Extend Random Bytes to Seed Generation of Error Polynomial and Secret Polynomial */ - byte[] randomnessExtended = new byte[(PARAM_K + 3) * CRYPTO_SEEDBYTES]; - - long[] secretPolynomial = new long[PARAM_N]; - long[] errorPolynomial = new long[PARAM_N * PARAM_K]; - long[] A = new long[PARAM_N * PARAM_K]; - long[] T = new long[PARAM_N * PARAM_K]; - - long[] s_ntt = new long[PARAM_N]; - - /* Get randomnessExtended <- seedErrorPolynomial, seedSecretPolynomial, seedA, seedY */ - secureRandom.nextBytes(randomness); - - HashUtils.secureHashAlgorithmKECCAK256( - randomnessExtended, 0, (PARAM_K + 3) * CRYPTO_SEEDBYTES, - randomness, 0, CRYPTO_RANDOMBYTES); - - /* - * Sample the Error Polynomial Fulfilling the Criteria - * Choose All Error Polynomial in R with Entries from D_SIGMA - * Repeat Step at Iteration if the h Largest Entries of Error Polynomial Summation to L_E - */ - - for (int k = 0; k < PARAM_K; k++) - { - do - { - Gaussian.sample_gauss_poly(++nonce, randomnessExtended, k * CRYPTO_SEEDBYTES, errorPolynomial, k * PARAM_N); - } - while (checkPolynomial(errorPolynomial, k * PARAM_N, PARAM_KEYGEN_BOUND_E)); - } - - /* - * Sample the Secret Polynomial Fulfilling the Criteria - * Choose Secret Polynomial in R with Entries from D_SIGMA - * Repeat Step if the h Largest Entries of Secret Polynomial Summation to L_S - */ - do - { - Gaussian.sample_gauss_poly(++nonce, randomnessExtended, PARAM_K * CRYPTO_SEEDBYTES, secretPolynomial, 0); - } - while (checkPolynomial(secretPolynomial, 0, PARAM_KEYGEN_BOUND_S)); - - QTesla3PPolynomial.poly_uniform(A, randomnessExtended, (PARAM_K + 1) * CRYPTO_SEEDBYTES); - QTesla3PPolynomial.poly_ntt(s_ntt, secretPolynomial); - - for (int k = 0; k < PARAM_K; k++) - { - QTesla3PPolynomial.poly_mul(T, k * PARAM_N, A, k * PARAM_N, s_ntt); - QTesla3PPolynomial.poly_add_correct(T, k * PARAM_N, T, k * PARAM_N, errorPolynomial, k * PARAM_N); - } - - /* Pack Public and Private Keys */ - encodePublicKey(publicKey, T, randomnessExtended, (PARAM_K + 1) * CRYPTO_SEEDBYTES); - encodePrivateKey(privateKey, secretPolynomial, errorPolynomial, randomnessExtended, (PARAM_K + 1) * CRYPTO_SEEDBYTES, publicKey); - - return 0; - } - - static int generateSignature( - byte[] signature, - final byte[] message, int messageOffset, int messageLength, - final byte[] privateKey, SecureRandom secureRandom) - { - byte[] c = new byte[CRYPTO_C_BYTES]; - byte[] randomness = new byte[CRYPTO_SEEDBYTES]; - byte[] randomness_input = new byte[CRYPTO_SEEDBYTES + CRYPTO_RANDOMBYTES + 2 * HM_BYTES]; - int[] pos_list = new int[PARAM_H]; - short[] sign_list = new short[PARAM_H]; - long[] y = new long[PARAM_N]; - - long[] y_ntt = new long[PARAM_N]; - long[] Sc = new long[PARAM_N]; - long[] z = new long[PARAM_N]; - - long[] v = new long[PARAM_N * PARAM_K]; - long[] Ec = new long[PARAM_N * PARAM_K]; - long[] a = new long[PARAM_N * PARAM_K]; - - int k; - int nonce = 0; // Initialize domain separator for sampling y - boolean rsp = false; - - System.arraycopy(privateKey, CRYPTO_SECRETKEYBYTES - HM_BYTES - CRYPTO_SEEDBYTES, randomness_input, 0, CRYPTO_SEEDBYTES); - - { - byte[] tmp = new byte[CRYPTO_RANDOMBYTES]; - secureRandom.nextBytes(tmp); - System.arraycopy(tmp, 0, randomness_input, CRYPTO_SEEDBYTES, CRYPTO_RANDOMBYTES); - } - - HashUtils.secureHashAlgorithmKECCAK256( - randomness_input, CRYPTO_SEEDBYTES + CRYPTO_RANDOMBYTES, HM_BYTES, - message, 0, messageLength); - - HashUtils.secureHashAlgorithmKECCAK256( - randomness, 0, CRYPTO_SEEDBYTES, - randomness_input, 0, randomness_input.length - HM_BYTES); - - System.arraycopy(privateKey, CRYPTO_SECRETKEYBYTES - HM_BYTES, randomness_input, randomness_input.length - HM_BYTES, HM_BYTES); - - QTesla3PPolynomial.poly_uniform(a, privateKey, CRYPTO_SECRETKEYBYTES - HM_BYTES - 2 * CRYPTO_SEEDBYTES); - - while (true) - { - sample_y(y, randomness, 0, ++nonce); - - QTesla3PPolynomial.poly_ntt(y_ntt, y); - for (k = 0; k < PARAM_K; k++) - { - QTesla3PPolynomial.poly_mul(v, k * PARAM_N, a, k * PARAM_N, y_ntt); - } - - hashFunction(c, 0, v, randomness_input, CRYPTO_SEEDBYTES + CRYPTO_RANDOMBYTES); - encodeC(pos_list, sign_list, c, 0); - - QTesla3PPolynomial.sparse_mul8(Sc, privateKey, pos_list, sign_list); - - QTesla3PPolynomial.poly_add(z, y, Sc); - - if (testRejection(z)) - { - continue; - } - - for (k = 0; k < PARAM_K; k++) - { - QTesla3PPolynomial.sparse_mul8(Ec, k * PARAM_N, privateKey, (PARAM_N * (k + 1)), pos_list, sign_list); - QTesla3PPolynomial.poly_sub(v, k * PARAM_N, v, k * PARAM_N, Ec, k * PARAM_N); - rsp = test_correctness(v, k * PARAM_N); - if (rsp) - { - break; - } // TODO replace with contine outer - } - if (rsp) - { - continue; - } - - encodeSignature(signature, 0, c, 0, z); - return 0; - } - - // return 0; - } - - static int verifying( - byte[] message, - final byte[] signature, int signatureOffset, int signatureLength, - final byte[] publicKey) - { - byte[] c = new byte[CRYPTO_C_BYTES]; - byte[] c_sig = new byte[CRYPTO_C_BYTES]; - byte[] seed = new byte[CRYPTO_SEEDBYTES]; - byte[] hm = new byte[2 * HM_BYTES]; - int[] pos_list = new int[PARAM_H]; - short[] sign_list = new short[PARAM_H]; - int[] pk_t = new int[PARAM_N * PARAM_K]; - long[] w = new long[PARAM_N * PARAM_K]; - long[] a = new long[PARAM_N * PARAM_K]; - long[] Tc = new long[PARAM_N * PARAM_K]; - - long[] z = new long[PARAM_N]; - long[] z_ntt = new long[PARAM_N]; - - int k = 0; - - if (signatureLength != CRYPTO_BYTES) - { - return -1; - } - - decodeSignature(c, z, signature, signatureOffset); - if (testZ(z)) - { - return -2; - } - decodePublicKey(pk_t, seed, 0, publicKey); - - // Get H(m) and hash_pk^M - HashUtils.secureHashAlgorithmKECCAK256( - hm, 0, HM_BYTES, - message, 0, message.length); - HashUtils.secureHashAlgorithmKECCAK256( - hm, HM_BYTES, HM_BYTES, - publicKey, 0, CRYPTO_PUBLICKEYBYTES - CRYPTO_SEEDBYTES); - - QTesla3PPolynomial.poly_uniform(a, seed, 0); - encodeC(pos_list, sign_list, c, 0); - QTesla3PPolynomial.poly_ntt(z_ntt, z); - - for (k = 0; k < PARAM_K; k++) - { // Compute w = az - tc - QTesla3PPolynomial.sparse_mul32(Tc, k * PARAM_N, pk_t, (k * PARAM_N), pos_list, sign_list); - QTesla3PPolynomial.poly_mul(w, k * PARAM_N, a, k * PARAM_N, z_ntt); - QTesla3PPolynomial.poly_sub(w, k * PARAM_N, w, k * PARAM_N, Tc, k * PARAM_N); - } - - hashFunction(c_sig, 0, w, hm, 0); - - if (!memoryEqual(c, 0, c_sig, 0, CRYPTO_C_BYTES)) - { - return -3; - } - - return 0; - } - - static void encodePrivateKey(byte[] privateKey, final long[] secretPolynomial, final long[] errorPolynomial, - final byte[] seed, int seedOffset, byte[] publicKey) - { - int i, k = 0; - int skPtr = 0; - - for (i = 0; i < PARAM_N; i++) - { - privateKey[skPtr + i] = (byte)secretPolynomial[i]; - } - skPtr += PARAM_N; - - for (k = 0; k < PARAM_K; k++) - { - for (i = 0; i < PARAM_N; i++) - { - privateKey[skPtr + (k * PARAM_N + i)] = (byte)errorPolynomial[k * PARAM_N + i]; - } - } - skPtr += PARAM_K * PARAM_N; - - System.arraycopy(seed, seedOffset, privateKey, skPtr, CRYPTO_SEEDBYTES * 2); - skPtr += CRYPTO_SEEDBYTES * 2; - - /* Hash of the public key */ - HashUtils.secureHashAlgorithmKECCAK256( - privateKey, skPtr, HM_BYTES, - publicKey, 0, CRYPTO_PUBLICKEYBYTES - CRYPTO_SEEDBYTES); - skPtr += HM_BYTES; - -// assert CRYPTO_SECRETKEYBYTES == skPtr; - } - - static void encodePublicKey(byte[] publicKey, final long[] T, final byte[] seedA, int seedAOffset) - { - int j = 0; - - for (int i = 0; i < (PARAM_N * PARAM_K * PARAM_Q_LOG / 32); i += 15) - { - at(publicKey, i, 0, (int)(T[j] | (T[j + 1] << 30))); - at(publicKey, i, 1, (int)((T[j + 1] >> 2) | (T[j + 2] << 28))); - at(publicKey, i, 2, (int)((T[j + 2] >> 4) | (T[j + 3] << 26))); - at(publicKey, i, 3, (int)((T[j + 3] >> 6) | (T[j + 4] << 24))); - at(publicKey, i, 4, (int)((T[j + 4] >> 8) | (T[j + 5] << 22))); - at(publicKey, i, 5, (int)((T[j + 5] >> 10) | (T[j + 6] << 20))); - at(publicKey, i, 6, (int)((T[j + 6] >> 12) | (T[j + 7] << 18))); - at(publicKey, i, 7, (int)((T[j + 7] >> 14) | (T[j + 8] << 16))); - at(publicKey, i, 8, (int)((T[j + 8] >> 16) | (T[j + 9] << 14))); - at(publicKey, i, 9, (int)((T[j + 9] >> 18) | (T[j + 10] << 12))); - at(publicKey, i, 10, (int)((T[j + 10] >> 20) | (T[j + 11] << 10))); - at(publicKey, i, 11, (int)((T[j + 11] >> 22) | (T[j + 12] << 8))); - at(publicKey, i, 12, (int)((T[j + 12] >> 24) | (T[j + 13] << 6))); - at(publicKey, i, 13, (int)((T[j + 13] >> 26) | (T[j + 14] << 4))); - at(publicKey, i, 14, (int)((T[j + 14] >> 28) | (T[j + 15] << 2))); - j += 16; - } - - System.arraycopy(seedA, seedAOffset, publicKey, PARAM_N * PARAM_K * PARAM_Q_LOG / 8, CRYPTO_SEEDBYTES); - - } - - - static void decodePublicKey(int[] publicKey, byte[] seedA, int seedAOffset, final byte[] publicKeyInput) - { - - int j = 0; - byte[] pt = publicKeyInput; - int maskq = (1 << PARAM_Q_LOG) - 1; - - - for (int i = 0; i < PARAM_N * PARAM_K; i += 16) - { - publicKey[i] = at(pt, j, 0) & maskq; - publicKey[i + 1] = ((at(pt, j, 0) >>> 30) | (at(pt, j, 1) << 2)) & maskq; - publicKey[i + 2] = ((at(pt, j, 1) >>> 28) | (at(pt, j, 2) << 4)) & maskq; - publicKey[i + 3] = ((at(pt, j, 2) >>> 26) | (at(pt, j, 3) << 6)) & maskq; - publicKey[i + 4] = ((at(pt, j, 3) >>> 24) | (at(pt, j, 4) << 8)) & maskq; - publicKey[i + 5] = ((at(pt, j, 4) >>> 22) | (at(pt, j, 5) << 10)) & maskq; - publicKey[i + 6] = ((at(pt, j, 5) >>> 20) | (at(pt, j, 6) << 12)) & maskq; - publicKey[i + 7] = ((at(pt, j, 6) >>> 18) | (at(pt, j, 7) << 14)) & maskq; - publicKey[i + 8] = ((at(pt, j, 7) >>> 16) | (at(pt, j, 8) << 16)) & maskq; - publicKey[i + 9] = ((at(pt, j, 8) >>> 14) | (at(pt, j, 9) << 18)) & maskq; - publicKey[i + 10] = ((at(pt, j, 9) >>> 12) | (at(pt, j, 10) << 20)) & maskq; - publicKey[i + 11] = ((at(pt, j, 10) >>> 10) | (at(pt, j, 11) << 22)) & maskq; - publicKey[i + 12] = ((at(pt, j, 11) >>> 8) | (at(pt, j, 12) << 24)) & maskq; - publicKey[i + 13] = ((at(pt, j, 12) >>> 6) | (at(pt, j, 13) << 26)) & maskq; - publicKey[i + 14] = ((at(pt, j, 13) >>> 4) | (at(pt, j, 14) << 28)) & maskq; - publicKey[i + 15] = (at(pt, j, 14) >>> 2) & maskq; - j += 15; - } - - - System.arraycopy(publicKeyInput, PARAM_N * PARAM_K * PARAM_Q_LOG / 8, seedA, seedAOffset, CRYPTO_SEEDBYTES); - - } - - private static boolean testZ(long[] Z) - { - // Returns false if valid, otherwise outputs 1 if invalid (rejected) - - for (int i = 0; i < PARAM_N; i++) - { - - if ((Z[i] < -(PARAM_B - PARAM_S)) || (Z[i] > PARAM_B - PARAM_S)) - { - - return true; - - } - - } - - return false; - - } - - private static final int maskb1 = ((1 << (PARAM_B_BITS + 1)) - 1); - - static void encodeSignature(byte[] signature, int signatureOffset, byte[] C, int cOffset, long[] Z) - { - int j = 0; - - for (int i = 0; i < (PARAM_N * (PARAM_B_BITS + 1) / 32); i += 11) - { - at(signature, i, 0, (int)((Z[j + 0] & ((1 << 22) - 1)) | (Z[j + 1] << 22))); - at(signature, i, 1, (int)(((Z[j + 1] >>> 10) & ((1 << 12) - 1)) | (Z[j + 2] << 12))); - at(signature, i, 2, (int)(((Z[j + 2] >>> 20) & ((1 << 2) - 1)) | ((Z[j + 3] & maskb1) << 2) | (Z[j + 4] << 24))); - at(signature, i, 3, (int)(((Z[j + 4] >>> 8) & ((1 << 14) - 1)) | (Z[j + 5] << 14))); - at(signature, i, 4, (int)(((Z[j + 5] >>> 18) & ((1 << 4) - 1)) | ((Z[j + 6] & maskb1) << 4) | (Z[j + 7] << 26))); - at(signature, i, 5, (int)(((Z[j + 7] >>> 6) & ((1 << 16) - 1)) | (Z[j + 8] << 16))); - at(signature, i, 6, (int)(((Z[j + 8] >>> 16) & ((1 << 6) - 1)) | ((Z[j + 9] & maskb1) << 6) | (Z[j + 10] << 28))); - at(signature, i, 7, (int)(((Z[j + 10] >>> 4) & ((1 << 18) - 1)) | (Z[j + 11] << 18))); - at(signature, i, 8, (int)(((Z[j + 11] >>> 14) & ((1 << 8) - 1)) | ((Z[j + 12] & maskb1) << 8) | (Z[j + 13] << 30))); - at(signature, i, 9, (int)(((Z[j + 13] >>> 2) & ((1 << 20) - 1)) | (Z[j + 14] << 20))); - at(signature, i, 10, (int)(((Z[j + 14] >>> 12) & ((1 << 10) - 1)) | (Z[j + 15] << 10))); - j += 16; - } - - System.arraycopy(C, cOffset, signature, signatureOffset + PARAM_N * (PARAM_B_BITS + 1) / 8, CRYPTO_C_BYTES); - } - - static void decodeSignature(byte[] C, long[] Z, final byte[] signature, int signatureOffset) - { - int j = 0; - for (int i = 0; i < PARAM_N; i += 16) - { - int s0 = at(signature, j, 0); - int s1 = at(signature, j, 1); - int s2 = at(signature, j, 2); - int s3 = at(signature, j, 3); - int s4 = at(signature, j, 4); - int s5 = at(signature, j, 5); - int s6 = at(signature, j, 6); - int s7 = at(signature, j, 7); - int s8 = at(signature, j, 8); - int s9 = at(signature, j, 9); - int s10 = at(signature, j, 10); - - Z[i] = (s0 << 10) >> 10; - Z[i + 1] = (s0 >>> 22) | ((s1 << 20) >> 10); - Z[i + 2] = (s1 >>> 12) | ((s2 << 30) >> 10); - Z[i + 3] = ((s2 << 8) >> 10); - Z[i + 4] = (s2 >>> 24) | ((s3 << 18) >> 10); - Z[i + 5] = (s3 >>> 14) | ((s4 << 28) >> 10); - Z[i + 6] = ((s4 << 6) >> 10); - Z[i + 7] = (s4 >>> 26) | ((s5 << 16) >> 10); - Z[i + 8] = (s5 >>> 16) | ((s6 << 26) >> 10); - Z[i + 9] = ((s6 << 4) >> 10); - Z[i + 10] = (s6 >>> 28) | ((s7 << 14) >> 10); - Z[i + 11] = (s7 >>> 18) | ((s8 << 24) >> 10); - Z[i + 12] = ((s8 << 2) >> 10); - Z[i + 13] = (s8 >>> 30) | ((s9 << 12) >> 10); - Z[i + 14] = (s9 >>> 20) | ((s10 << 22) >> 10); - Z[i + 15] = (s10 >> 10); - j += 11; - } - System.arraycopy(signature, signatureOffset + PARAM_N * (PARAM_B_BITS + 1) / 8, C, 0, CRYPTO_C_BYTES); - } - - static void encodeC(int[] positionList, short[] signList, byte[] output, int outputOffset) - { - int count = 0; - int position; - short domainSeparator = 0; - short[] C = new short[PARAM_N]; - byte[] randomness = new byte[HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE]; - - // Enc: the XOF is instantiated with cSHAKE128 (see Algorithm 14). - HashUtils.customizableSecureHashAlgorithmKECCAK128Simple( - randomness, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE, - domainSeparator++, - output, outputOffset, CRYPTO_RANDOMBYTES - ); - - /* Use Rejection Sampling to Determine Positions to be Set in the New Vector */ - Arrays.fill(C, (short)0); - - /* Sample A Unique Position k times. - * Use Two Bytes - */ - for (int i = 0; i < PARAM_H; ) - { - if (count > HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE - 3) - { - // Enc: the XOF is instantiated with cSHAKE128 (see Algorithm 14). - HashUtils.customizableSecureHashAlgorithmKECCAK128Simple( - randomness, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE, - domainSeparator++, - output, outputOffset, CRYPTO_RANDOMBYTES - ); - - count = 0; - } - - position = (randomness[count] << 8) | (randomness[count + 1] & 0xFF); - position &= (PARAM_N - 1); - - /* Position is between [0, n - 1] and Has not Been Set Yet - * Determine Signature - */ - if (C[position] == 0) - { - if ((randomness[count + 2] & 1) == 1) - { - C[position] = -1; - } - else - { - C[position] = 1; - } - - positionList[i] = position; - signList[i] = C[position]; - i++; - } - - count += 3; - } - } - - private static void hashFunction(byte[] output, int outputOff, long[] v, byte[] hm, int hmOff) - { - int mask, cL; - - byte[] T = new byte[PARAM_K * PARAM_N + 2 * HM_BYTES]; - - for (int k = 0; k < PARAM_K; k++) - { - int index = k * PARAM_N; - for (int i = 0; i < PARAM_N; i++) - { - int temp = (int)v[index]; - // If v[i] > PARAM_Q/2 then v[i] -= PARAM_Q - mask = (PARAM_Q / 2 - temp) >> (RADIX32 - 1); - temp = ((temp - PARAM_Q) & mask) | (temp & ~mask); - - cL = temp & ((1 << PARAM_D) - 1); - // If cL > 2^(d-1) then cL -= 2^d - mask = ((1 << (PARAM_D - 1)) - cL) >> (RADIX32 - 1); - cL = ((cL - (1 << PARAM_D)) & mask) | (cL & ~mask); - T[index++] = (byte)((temp - cL) >> PARAM_D); - } - } - System.arraycopy(hm, hmOff, T, PARAM_K * PARAM_N, 2 * HM_BYTES); - - HashUtils.secureHashAlgorithmKECCAK256( - output, outputOff, CRYPTO_C_BYTES, - T, 0, T.length); - } - - static int lE24BitToInt(byte[] bs, int off) - { - int n = bs[off] & 0xff; - n |= (bs[++off] & 0xff) << 8; - n |= (bs[++off] & 0xff) << 16; - return n; - } - - - private static int NBLOCKS_SHAKE = HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE / (((PARAM_B_BITS + 1) + 7) / 8); - private static int BPLUS1BYTES = ((PARAM_B_BITS + 1) + 7) / 8; - - - static void sample_y(long[] y, byte[] seed, int seedOffset, int nonce) - { // Sample polynomial y, such that each coefficient is in the range [-B,B] - int i = 0, pos = 0, nblocks = PARAM_N; - byte buf[] = new byte[PARAM_N * BPLUS1BYTES + 1]; - int nbytes = BPLUS1BYTES; - short dmsp = (short)(nonce << 8); - - HashUtils.customizableSecureHashAlgorithmKECCAK256Simple( - buf, 0, PARAM_N * nbytes, dmsp++, seed, seedOffset, CRYPTO_RANDOMBYTES - ); - - - while (i < PARAM_N) - { - if (pos >= nblocks * nbytes) - { - nblocks = NBLOCKS_SHAKE; - HashUtils.customizableSecureHashAlgorithmKECCAK256Simple( - buf, 0, PARAM_N * nbytes, dmsp++, seed, seedOffset, CRYPTO_RANDOMBYTES - ); - pos = 0; - } - y[i] = lE24BitToInt(buf, pos) & ((1 << (PARAM_B_BITS + 1)) - 1); - y[i] -= PARAM_B; - if (y[i] != (1 << PARAM_B_BITS)) - { - i++; - } - pos += nbytes; - } - } - - - private static void at(byte[] bs, int base, int index, int value) - { - Pack.intToLittleEndian(value, bs, (base * 4) + (index * 4)); - } - - private static int at(byte[] bs, int base, int index) - { - int off = (base * 4) + (index * 4); - - int n = bs[off] & 0xff; - n |= (bs[++off] & 0xff) << 8; - n |= (bs[++off] & 0xff) << 16; - n |= bs[++off] << 24; - return n; - } - - - static boolean test_correctness(long[] v, int vpos) - { // Check bounds for w = v - ec during signature verification. Returns 0 if valid, otherwise outputs 1 if invalid (rejected). - // This function leaks the position of the coefficient that fails the test (but this is independent of the secret data). - // It does not leak the sign of the coefficients. - int mask, left, val; - int t0, t1; - - for (int i = 0; i < PARAM_N; i++) - { - // If v[i] > PARAM_Q/2 then v[i] -= PARAM_Q - mask = (int)(PARAM_Q / 2 - v[vpos + i]) >> (RADIX32 - 1); - val = (int)(((v[vpos + i] - PARAM_Q) & mask) | (v[vpos + i] & ~mask)); - // If (Abs(val) < PARAM_Q/2 - PARAM_E) then t0 = 0, else t0 = 1 - t0 = (int)(~(absolute(val) - (PARAM_Q / 2 - PARAM_E))) >>> (RADIX32 - 1); - - left = val; - val = (val + (1 << (PARAM_D - 1)) - 1) >> PARAM_D; - val = left - (val << PARAM_D); - // If (Abs(val) < (1<<(PARAM_D-1))-PARAM_E) then t1 = 0, else t1 = 1 - t1 = (int)(~(absolute(val) - ((1 << (PARAM_D - 1)) - PARAM_E))) >>> (RADIX32 - 1); - - if ((t0 | t1) == 1) // Returns 1 if any of the two tests failed - { - return true; - } - } - return false; - } - - - private static boolean testRejection(long[] Z) //, int n, int b, int u) - { - - int valid = 0; - - for (int i = 0; i < PARAM_N; i++) - { - valid |= (PARAM_B - PARAM_S) - absolute(Z[i]); - - } - - return (valid >>> 31) > 0; - - } - - private static int absolute(int value) - { - - return ((value >> 31) ^ value) - (value >> 31); - - } - - private static long absolute(long value) - { - - return ((value >> 63) ^ value) - (value >> 63); - - } - - - private static boolean checkPolynomial(long[] polynomial, int polyOffset, int bound) - { - - int i, j, sum = 0, limit = PARAM_N; - long temp, mask; - long[] list = new long[PARAM_N]; - - for (j = 0; j < PARAM_N; j++) - { - list[j] = absolute((int)polynomial[polyOffset + j]); - } - - for (j = 0; j < PARAM_H; j++) - { - for (i = 0; i < limit - 1; i++) - { - // If list[i+1] > list[i] then exchange contents - mask = (list[i + 1] - list[i]) >> (RADIX32 - 1); - temp = (list[i + 1] & mask) | (list[i] & ~mask); - list[i + 1] = (list[i] & mask) | (list[i + 1] & ~mask); - list[i] = temp; - } - sum += (int)list[limit - 1]; - limit -= 1; - } - - return (sum > bound); - } - - - // End of outer. - - static class Gaussian - { - - private static final int CDT_ROWS = 111; - private static final int CDT_COLS = 4; - private static final int CHUNK_SIZE = 512; - - private static final long[] cdt_v = new long[]{ - 0x00000000L, 0x00000000L, 0x00000000L, 0x00000000L, // 0 - 0x0601F22AL, 0x280663D4L, 0x2E1B038CL, 0x1E75FCA7L, // 1 - 0x11F09FFAL, 0x162FE23DL, 0x403739B4L, 0x3F2AA531L, // 2 - 0x1DA089E9L, 0x437226E8L, 0x115E99C8L, 0x68C472A6L, // 3 - 0x28EAB25DL, 0x04C51FE2L, 0x13F63FD0L, 0x1E56BF40L, // 4 - 0x33AC2F26L, 0x14FDBA70L, 0x6618880FL, 0x792CE93EL, // 5 - 0x3DC767DCL, 0x4565C95FL, 0x7EAC4790L, 0x163F4D99L, // 6 - 0x4724FC62L, 0x3342C78AL, 0x390873B2L, 0x13A12ACEL, // 7 - 0x4FB448F4L, 0x5229D06DL, 0x09A6C84BL, 0x1D13CB0DL, // 8 - 0x576B8599L, 0x7423407FL, 0x1287EE2FL, 0x7B908556L, // 9 - 0x5E4786DAL, 0x3210BAF6L, 0x6881795CL, 0x13DF4F59L, // 10 - 0x644B2C92L, 0x431B3946L, 0x63F188D9L, 0x22AFB6DEL, // 11 - 0x697E90CEL, 0x77C362C3L, 0x600A627EL, 0x66AEDF96L, // 12 - 0x6DEE0B96L, 0x2798C9CEL, 0x147A98F9L, 0x27427F24L, // 13 - 0x71A92144L, 0x5765FCE4L, 0x0FF04C94L, 0x74183C18L, // 14 - 0x74C16FD5L, 0x1E2A0990L, 0x13EB545FL, 0x1CD9A2ADL, // 15 - 0x7749AC92L, 0x0DF36EEBL, 0x414629E5L, 0x66610A51L, // 16 - 0x7954BFA4L, 0x28079289L, 0x29D5B127L, 0x29B69601L, // 17 - 0x7AF5067AL, 0x2EDC2050L, 0x2B486556L, 0x43BF4664L, // 18 - 0x7C3BC17CL, 0x123D5E7AL, 0x63D4DD26L, 0x3B1E3755L, // 19 - 0x7D38AD76L, 0x2A9381D9L, 0x1D20D034L, 0x77C09C55L, // 20 - 0x7DF9C5DFL, 0x0E868CA7L, 0x23627687L, 0x78864423L, // 21 - 0x7E8B2ABAL, 0x18E5C810L, 0x7C85B42CL, 0x7AC98BCCL, // 22 - 0x7EF7237CL, 0x00908272L, 0x3D4B170EL, 0x3CD572E3L, // 23 - 0x7F4637C5L, 0x6DBA5125L, 0x5B0285ECL, 0x46661EB9L, // 24 - 0x7F7F5707L, 0x4A52EDEBL, 0x50ECECB1L, 0x7384DC42L, // 25 - 0x7FA808CCL, 0x23290598L, 0x704F7A4DL, 0x08532154L, // 26 - 0x7FC4A083L, 0x69BDF2D4L, 0x73B67B27L, 0x3AE237ADL, // 27 - 0x7FD870CAL, 0x42275557L, 0x6F2AE034L, 0x4E4B0395L, // 28 - 0x7FE5FB5DL, 0x3EF82C1BL, 0x256E2EB0L, 0x09E42B11L, // 29 - 0x7FEF1BFAL, 0x6C03A362L, 0x07334BD4L, 0x22B6B15FL, // 30 - 0x7FF52D4EL, 0x316C2C8CL, 0x1C77A4C3L, 0x1C3A974EL, // 31 - 0x7FF927BAL, 0x12AE54AEL, 0x6CC24956L, 0x3BA9A3E4L, // 32 - 0x7FFBBA43L, 0x749CC0E2L, 0x044B3068L, 0x620F14DAL, // 33 - 0x7FFD5E3DL, 0x4524AD91L, 0x31F84A1FL, 0x4D23AF51L, // 34 - 0x7FFE6664L, 0x535785B4L, 0x683C9E5EL, 0x2BD857DFL, // 35 - 0x7FFF0A41L, 0x0B291681L, 0x1CB4CE6FL, 0x32B314B9L, // 36 - 0x7FFF6E81L, 0x132C3D6FL, 0x4C8771CCL, 0x67421A75L, // 37 - 0x7FFFAAFEL, 0x4DBC6BEDL, 0x4E8644D2L, 0x5158A208L, // 38 - 0x7FFFCEFDL, 0x7A1E2D14L, 0x2CF905AAL, 0x79BFABD9L, // 39 - 0x7FFFE41EL, 0x4C6EC115L, 0x2D648F1AL, 0x4B01BA3EL, // 40 - 0x7FFFF059L, 0x319503C8L, 0x2CBEB96AL, 0x52FF656EL, // 41 - 0x7FFFF754L, 0x5DDD0D40L, 0x09D07206L, 0x6BF97EB5L, // 42 - 0x7FFFFB43L, 0x0B9E9822L, 0x5B584BE0L, 0x4974ED83L, // 43 - 0x7FFFFD71L, 0x76B81AE1L, 0x3C93755CL, 0x375F857BL, // 44 - 0x7FFFFEA3L, 0x7E66A1ECL, 0x3E342087L, 0x44ED1696L, // 45 - 0x7FFFFF49L, 0x26F6E190L, 0x7E3625F9L, 0x2F4F5849L, // 46 - 0x7FFFFFA1L, 0x2FA31694L, 0x0D53F684L, 0x59931C0DL, // 47 - 0x7FFFFFCFL, 0x5247BEC8L, 0x5CC20735L, 0x397CE966L, // 48 - 0x7FFFFFE7L, 0x4F4127C6L, 0x64926788L, 0x01CFEF66L, // 49 - 0x7FFFFFF3L, 0x6FAA69FDL, 0x26A67DC3L, 0x1FFA2528L, // 50 - 0x7FFFFFFAL, 0x0630D072L, 0x7AA0C1B7L, 0x7E90AAE6L, // 51 - 0x7FFFFFFDL, 0x0F2957BBL, 0x3ADCE1E6L, 0x5A311C28L, // 52 - 0x7FFFFFFEL, 0x4FD29431L, 0x6429F9EDL, 0x04653965L, // 53 - 0x7FFFFFFFL, 0x2CFAD60DL, 0x52ED82D1L, 0x26455881L, // 54 - 0x7FFFFFFFL, 0x5967A92FL, 0x5C85AB2DL, 0x188033BEL, // 55 - 0x7FFFFFFFL, 0x6E4C9DFEL, 0x76798EAFL, 0x0DC0BA65L, // 56 - 0x7FFFFFFFL, 0x77FDCCC8L, 0x194FF9ACL, 0x2C3FA855L, // 57 - 0x7FFFFFFFL, 0x7C6CE89EL, 0x01FA1A72L, 0x6C3DC40BL, // 58 - 0x7FFFFFFFL, 0x7E6D116EL, 0x5F82B352L, 0x57B67FCEL, // 59 - 0x7FFFFFFFL, 0x7F50FA31L, 0x31856599L, 0x579DC24BL, // 60 - 0x7FFFFFFFL, 0x7FB50089L, 0x43E64BB5L, 0x7F498E42L, // 61 - 0x7FFFFFFFL, 0x7FE04C2CL, 0x56CBFAEFL, 0x7FC9C15FL, // 62 - 0x7FFFFFFFL, 0x7FF2C7C0L, 0x5D509634L, 0x41DCA82BL, // 63 - 0x7FFFFFFFL, 0x7FFA8FE3L, 0x24F6020DL, 0x7B594401L, // 64 - 0x7FFFFFFFL, 0x7FFDCB1BL, 0x2D294BB3L, 0x1D1631BFL, // 65 - 0x7FFFFFFFL, 0x7FFF1DE1L, 0x5D75B704L, 0x323B12FEL, // 66 - 0x7FFFFFFFL, 0x7FFFA6B6L, 0x7E983E86L, 0x23392636L, // 67 - 0x7FFFFFFFL, 0x7FFFDD39L, 0x029CCA2CL, 0x035F7017L, // 68 - 0x7FFFFFFFL, 0x7FFFF2A3L, 0x205DBF7BL, 0x173D7F90L, // 69 - 0x7FFFFFFFL, 0x7FFFFAEFL, 0x3F79145BL, 0x642F005DL, // 70 - 0x7FFFFFFFL, 0x7FFFFE1BL, 0x23B2C7E4L, 0x6CA216CFL, // 71 - 0x7FFFFFFFL, 0x7FFFFF4DL, 0x1E959E3FL, 0x4A29BB03L, // 72 - 0x7FFFFFFFL, 0x7FFFFFBEL, 0x7C23D3D9L, 0x71DC92E4L, // 73 - 0x7FFFFFFFL, 0x7FFFFFE8L, 0x55110485L, 0x0E1813E2L, // 74 - 0x7FFFFFFFL, 0x7FFFFFF7L, 0x5EBC7B7BL, 0x2DFEE922L, // 75 - 0x7FFFFFFFL, 0x7FFFFFFDL, 0x0EDB0975L, 0x0C9F1639L, // 76 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x00DDA1A1L, 0x6DE86AA0L, // 77 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x54CF6D87L, 0x023F1F47L, // 78 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7186FF6AL, 0x5B71BF8CL, // 79 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7B375EBCL, 0x767A89DCL, // 80 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7E70BA89L, 0x44EBCEAAL, // 81 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7F7F98B5L, 0x44C8E44AL, // 82 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FD744C2L, 0x448EE5A4L, // 83 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FF34165L, 0x008855D0L, // 84 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFC1110L, 0x754A60B6L, // 85 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFECD77L, 0x44BE6D4AL, // 86 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFA3F4L, 0x7400A73EL, // 87 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFE4BDL, 0x1143830BL, // 88 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFF809L, 0x1A385059L, // 89 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFDB4L, 0x41CA0794L, // 90 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFF59L, 0x02FFB605L, // 91 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFD1L, 0x18360E8DL, // 92 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFF3L, 0x072A0E9AL, // 93 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFCL, 0x3C1BFEB0L, // 94 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x066EBCDDL, // 95 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x5FBE171AL, // 96 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x778EB81FL, // 97 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7DD211FEL, // 98 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7F71F071L, // 99 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FDC528FL, // 100 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FF7298CL, // 101 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFDD739L, // 102 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFF7ACAL, // 103 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFE056L, // 104 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFF893L, // 105 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFE48L, // 106 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFF9CL, // 107 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFE9L, // 108 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFBL, // 109 - 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, // 110 - }; - - - static void sample_gauss_poly(int nonce, byte[] seed, int seedOffset, long[] poly, int polyOffset) - { - int dmsp = nonce << 8; - - byte samp[] = new byte[CHUNK_SIZE * CDT_COLS * 4]; // This is int32_t in C, we will treat it as byte[] in java - int c[] = new int[CDT_COLS]; - int borrow, sign; - int mask = (-1) >>> 1; - - for (int chunk = 0; chunk < PARAM_N; chunk += CHUNK_SIZE) - { - - HashUtils.customizableSecureHashAlgorithmKECCAK256Simple( - samp, 0, CHUNK_SIZE * CDT_COLS * 4, (short)dmsp++, seed, seedOffset, CRYPTO_SEEDBYTES); - - for (int i = 0; i < CHUNK_SIZE; i++) - { - poly[polyOffset + chunk + i] = 0; - for (int j = 1; j < CDT_ROWS; j++) - { - borrow = 0; - for (int k = CDT_COLS - 1; k >= 0; k--) - { - c[k] = (int)((at(samp, 0, i * CDT_COLS + k) & mask) - (cdt_v[j * CDT_COLS + k] + borrow)); - borrow = c[k] >> (RADIX32 - 1); - } - poly[polyOffset + chunk + i] += ~borrow & 1; - } - sign = at(samp, 0, i * CDT_COLS) >> (RADIX32 - 1); - poly[polyOffset + chunk + i] = (sign & -poly[polyOffset + chunk + i]) | (~sign & poly[polyOffset + chunk + i]); - } - - } - - } - } - - static boolean memoryEqual(byte[] left, int leftOffset, byte[] right, int rightOffset, int length) - { - - if ((leftOffset + length <= left.length) && (rightOffset + length <= right.length)) - { - - for (int i = 0; i < length; i++) - { - - if (left[leftOffset + i] != right[rightOffset + i]) - { - - return false; - - } - - } - - return true; - - } - else - { - - return false; - - } - - } - - - static class QTesla3PPolynomial - { - - - private static final long[] zeta = new long[]{ - 147314272, 762289503, 284789571, 461457674, 723990704, 123382358, 685457283, 458774590, 644795450, 723622678, 441493948, 676062368, 648739792, 214990524, 261899220, 138474554, - 205277234, 788000393, 541334956, 769530525, 786231394, 812002793, 251385069, 152717354, 674883688, 458756880, 323745289, 823881240, 686340396, 716163820, 107735873, 144028791, - 586327243, 71257244, 739303131, 487030542, 313626215, 396596783, 664640087, 728258996, 854656117, 567834989, 2315110, 210792230, 795895843, 433034260, 432732757, 480454055, - 750130006, 47628047, 2271301, 98590211, 729637734, 683553815, 476917424, 121851414, 296210757, 820475433, 403416438, 605633242, 804828963, 435181077, 781182803, 276684653, - 329135201, 697859430, 248472020, 396579594, 109340098, 97605675, 755271019, 565755143, 534799496, 378374148, 85686225, 298978496, 650100484, 712463562, 818417023, 283716467, - 269132585, 153024538, 223768950, 331863760, 761523727, 586019306, 805044248, 810909760, 77905343, 401203343, 162625701, 616243024, 659789238, 385270982, 720521140, 545633566, - 688663167, 740046782, 257189758, 115795491, 101106443, 409863172, 622399622, 405606434, 498832246, 730567206, 350755879, 41236295, 561547732, 525723591, 18655497, 3396399, - 289694332, 221478904, 738940554, 769726362, 32128402, 693016435, 275431006, 65292213, 601823865, 469363520, 480544944, 607230206, 473150754, 267072604, 463615065, 412972775, - 197544577, 770873783, 189036815, 407973558, 110878446, 442760341, 667560342, 756992079, 663708407, 585601880, 763637579, 660019224, 424935088, 249313490, 844593983, 664952705, - 274981537, 40233161, 655530034, 742724096, 8926394, 67709207, 616610795, 539664358, 306118645, 741629065, 283521858, 621397947, 369041534, 162477412, 258256937, 269480966, - 75469364, 815614830, 724060729, 510819743, 489239410, 265607303, 103024793, 434961090, 474838542, 234701483, 505818866, 450427360, 188113529, 650423376, 599263141, 720479782, - 755079140, 469798456, 745591660, 432033717, 530128582, 94480771, 722477467, 169342233, 35413255, 89769525, 424389771, 240236288, 360665614, 66702784, 76128663, 565345206, - 605031892, 393503210, 249841967, 485930917, 45880284, 746120091, 684031522, 537926896, 408749937, 608644803, 692593939, 515424474, 748771159, 155377700, 347101257, 393516280, - 708186062, 809233270, 562547654, 768251664, 651110951, 574473323, 588028067, 352359235, 646902518, 410726541, 134129459, 460099853, 829152883, 819102028, 7270760, 562515302, - 419641762, 347973450, 161011009, 401974733, 619807719, 559105457, 276126568, 165473862, 380215069, 356617900, 347744328, 615885981, 824819772, 811367929, 6451967, 515345658, - 648239021, 56427040, 709160497, 71545092, 390921213, 17177139, 194174898, 825533429, 497469884, 88988508, 64227614, 641021859, 159258883, 529265733, 823190295, 567280997, - 414094239, 238392498, 695610059, 416342151, 90807038, 206865379, 568337348, 168011486, 844375038, 777332780, 147582038, 199025846, 396231915, 151630666, 466807217, 12672521, - 570774644, 764098787, 283719496, 779154504, 383628791, 851035387, 395488461, 291115871, 52707730, 776449280, 479801706, 73403989, 402014636, 255214342, 56904698, 446531030, - 639487570, 848061696, 202732901, 739018922, 653983847, 453022791, 391722680, 584290855, 270911670, 390838431, 653070075, 535876472, 83207555, 131151682, 505677504, 778583044, - 472363568, 734419459, 768500943, 321131696, 371745445, 751887879, 51797676, 157604159, 838805925, 358099697, 763440819, 776721566, 719570904, 304610785, 656838485, 239522278, - 796234199, 659506535, 825373307, 674901303, 250484891, 54612517, 410236408, 111976920, 728940855, 720463104, 559960962, 514189554, 637176165, 436151981, 485801800, 802811374, - 549456481, 808832355, 112672706, 199163132, 807410080, 645955491, 365378122, 222316474, 381896744, 693909930, 402130292, 199856804, 277639257, 6848838, 648262319, 601521139, - 108516632, 392382841, 563420106, 475932203, 249861415, 99274558, 152886431, 744977783, 269184267, 562674804, 760959275, 733098096, 771348891, 674288361, 631521272, 513632066, - 476339117, 621937967, 206834230, 507101607, 420341698, 528715580, 853092790, 580174958, 278044321, 432350205, 603769437, 144426940, 733518338, 365468467, 848983278, 385382826, - 846062026, 593903051, 216589699, 219997638, 350708517, 733669279, 624754239, 499821820, 772548008, 199677439, 287505007, 144199205, 215073292, 825467700, 101591831, 571728784, - 841898341, 420897808, 61323616, 823475752, 72494861, 89946011, 236594097, 379582577, 539401967, 221244669, 479250487, 100726882, 263096036, 647161225, 491060387, 419890898, - 816149055, 546441322, 690509770, 215789647, 5870948, 821456387, 294091098, 783700004, 278643020, 520754327, 813718894, 123610053, 157045201, 265331664, 807174256, 258134244, - 703519669, 300265991, 41892125, 662173055, 439638698, 494124024, 700655120, 535348417, 37146186, 379568907, 644973451, 554904963, 594757858, 477812802, 266085643, 46337543, - 454847754, 496027901, 701947604, 5722633, 790588605, 233501932, 728956461, 462020148, 214013660, 155806979, 159935426, 423504958, 638889309, 602641304, 277759403, 71654804, - 710920410, 108337831, 641924564, 252946326, 463082282, 23277660, 142056200, 263317553, 9044238, 367816044, 349695658, 291597086, 230031083, 385106216, 281069679, 644033142, - 134221740, 212497862, 686686078, 787489098, 781698667, 748299513, 774414792, 380836293, 114027649, 766161763, 10536612, 707355910, 100516219, 637517297, 21478533, 769067854, - 668364559, 410803198, 64949715, 643421522, 525590993, 585289785, 423839840, 554109325, 450599860, 295350132, 435789550, 306634115, 611298620, 777817576, 553655202, 804525538, - 794474290, 138542076, 780958763, 62228371, 738032107, 684994110, 661486955, 67099069, 68865906, 32413094, 358393763, 205008770, 849715545, 289798348, 384767209, 787328590, - 823677120, 47455925, 706001331, 612392717, 487804928, 731804935, 520572665, 442307581, 351275150, 726042356, 667657829, 254929787, 459520026, 625393223, 319307882, 77267096, - 815224795, 335964550, 408353208, 604252110, 574953308, 563501897, 515015302, 313600371, 178773384, 417549087, 510834475, 167049599, 488791556, 664276219, 82933775, 822541833, - 17111190, 409659978, 96304098, 500484311, 269766378, 327037310, 584926256, 538611363, 404132255, 170931824, 744460626, 154011192, 322194096, 215888234, 258344560, 702851111, - 192046250, 738511820, 530780560, 57197515, 335425579, 410968369, 830078545, 448351649, 208921555, 356653676, 718038774, 424362596, 158929491, 420096666, 387056270, 797383293, - 381201911, 466480709, 373815662, 84912008, 4969808, 524614597, 93448903, 559481007, 400813998, 665223025, 601707338, 466022707, 192709574, 615503265, 822863744, 639854175, - 158713505, 12757666, 389196370, 823105438, 682974863, 468401586, 93508626, 402414043, 806357152, 180544963, 27876186, 321527031, 329857607, 669501423, 829809824, 333202822, - 106923493, 368991112, 282317903, 790323774, 517381333, 548329656, 236147848, 700119793, 404187488, 343578810, 798813301, 497964535, 656188346, 678161787, 736817175, 518031339, - 716647183, 674797219, 308643560, 714308544, 516103468, 605229646, 564549717, 47650358, 706404486, 494887760, 152496104, 54954356, 271435602, 76951527, 136123931, 601823638, - 329273401, 252710411, 754980731, 351648254, 49239731, 837833233, 88830509, 598216539, 155534490, 669603727, 418388693, 79322074, 636251444, 703683994, 796989459, 126497707, - 644863316, 730359063, 265213001, 64483814, 552208981, 8135537, 782474322, 780853310, 733976806, 395661138, 128188419, 266691358, 407092046, 447349747, 526245954, 119272088, - 359659635, 812410956, 669835517, 565139408, 248981831, 139910745, 685462294, 406991131, 709944045, 589819925, 714299787, 72923680, 648836181, 145321778, 392775383, 243093077, - 412955839, 174619485, 310936394, 699727061, 421087619, 745421519, 539546394, 29471558, 116471631, 852650639, 443777703, 773131303, 81618669, 756719012, 702785073, 847088653, - 851830586, 300908692, 430974543, 463215976, 668971423, 414271988, 108350516, 345933325, 716417649, 174980945, 679092437, 384030489, 814050910, 506580116, 249434097, 178438885, - 146797119, 10369463, 296359082, 215645133, 149545847, 483689845, 322009569, 308978588, 38531178, 328571637, 815396967, 709744233, 765487128, 645413104, 564779557, 213794315, - 280607549, 124792697, 423470554, 631348430, 21223627, 220718413, 598791979, 47797633, 734556299, 590321944, 168292920, 484802055, 340999812, 769601438, 42675060, 116026587, - 227462622, 543574607, 444066479, 467277895, 278798674, 597413704, 350168725, 301936652, 82885511, 656047519, 765110538, 52228202, 533005731, 621989298, 148235931, 317833915, - 118463894, 522391939, 451332724, 548031654, 73854149, 527786213, 583308898, 840663438, 275278054, 362931963, 587861579, 830807449, 431695707, 178004048, 75513216, 60681147, - 638603143, 470791469, 490903319, 527370962, 102981857, 224220555, 756514239, 293859807, 797926303, 620196520, 466126507, 646136763, 265504163, 213257337, 92270416, 398713724, - 91810366, 724247342, 855386762, 631553083, 376095634, 833728623, 636218061, 510719408, 378530670, 737821436, 127781731, 3443282, 770116208, 769633348, 430675947, 40370755, - 52361322, 844601468, 442556599, 128290354, 494328514, 405616679, 651440882, 421541290, 171560170, 386143493, 284277254, 450756213, 248305939, 526718005, 300780198, 714218239, - 68021827, 527353904, 236472015, 309320156, 683815803, 527980097, 598849444, 779607597, 339852811, 845420163, 96001931, 326760873, 609319751, 520803868, 140143851, 766988701, - 844896794, 532008178, 388459130, 574799295, 760406065, 773758517, 453271555, 134636434, 155747417, 105505251, 796987277, 399016325, 71156680, 709579308, 274279004, 96962867, - 476741915, 585319990, 709143538, 721328791, 293159344, 640577897, 138404614, 572892015, 394460832, 465897068, 325895331, 413861636, 447337182, 376950267, 721061932, 181671909, - 272138750, 247768905, 634973622, 280653872, 165108426, 134241779, 15142090, 153256717, 783424845, 773227607, 172477802, 504458250, 349868083, 461422806, 487725644, 586146740, - 561546455, 815406759, 468110471, 126476456, 285774551, 522013234, 801943660, 79684345, 654558548, 188038414, 249923934, 551812615, 562560206, 407120348, 384535446, 176837117, - 433155458, 82591339, 459412819, 435604627, 312211805, 98158590, 752137480, 446017293, 666480139, 60261988, 275386848, 642778031, 8582401, 677484160, 819506256, 333441964, - 25465219, 190315429, 91529631, 754681170, 563660271, 167135649, 20270015, 115773732, 658954441, 132923202, 844102455, 453432758, 250487209, 423813160, 632223296, 537494486, - 158265753, 327949044, 494109748, 659672289, 67984726, 422358258, 345141182, 164372996, 338500924, 41400311, 207638305, 832074651, 50853458, 228267776, 621895888, 635834787, - 484972544, 181125024, 558134871, 282159878, 788157855, 145576343, 194837894, 501440949, 63641414, 252098681, 835930645, 662856247, 456140980, 206147937, 565198503, 449503819, - 684013129, 494002381, 793836418, 649296754, 444313288, 136544068, 540002286, 355912945, 613175147, 134541429, 843111781, 672612536, 541098995, 734996181, 211869705, 620777828, - 756152791, 242128346, 795442420, 73925532, 735232214, 738668090, 530800757, 266183732, 97165934, 803231879, 10057267, 175942047, 181460965, 320684297, 637472526, 213840116, - 182671953, 152704513, 388004388, 597349323, 473851493, 445333546, 679315863, 267078568, 46538491, 530171754, 698082287, 75308587, 266467406, 96440883, 759196579, 470119952, - 381731475, 428392158, 10628712, 173921356, 116809433, 323843928, 812172630, 403459283, 655501128, 261944441, 774418023, 790520709, 589149480, 264133112, 806274256, 752372117, - 66236193, 713859568, 90804933, 551864345, 843839891, 600244073, 719230074, 803646506, 254956426, 138935723, 738829647, 109576220, 105819621, 249706947, 110623114, 10002331, - 795710911, 547062229, 721440199, 820747461, 397666160, 685179945, 463869301, 470338753, 641244231, 652990696, 698429485, 41147155, 638072709, 515832968, 241130026, 314161759, - 526815813, 529167244, 53391331, 782008115, 822962086, 337706389, 648197286, 209496506, 760818531, 781900302, 717270807, 709143641, 740503641, 734328409, 514061476, 844010670, - 67993787, 712083588, 319801387, 338260400, 48758556, 304195768, 478833380, 841413917, 710197685, 196321647, 777595184, 775983866, 147506314, 620961439, 399972264, 398715644, - 684489092, 659918078, 664075287, 723890579, 643103903, 508525962, 375409248, 501237729, 740609783, 639854810, 510797913, 521151016, 421045341, 193698327, 800266392, 93518128, - 443879633, 699245445, 194001794, 123905867, 75572337, 242620749, 463111940, 755239011, 31718790, 162155292, 386689240, 381413538, 745322913, 367897558, 343088005, 31706107, - 10842029, 404961623, 537521191, 281624684, 372852160, 55286017, 534907560, 264398082, 667644310, 486871690, 716964533, 734731419, 143593638, 293949413, 760014789, 594443755, - 147804127, 537704286, 460110740, 596458323, 577775570, 333025386, 260094086, 711487611, 359384182, 323339045, 716675075, 248179763, 525311626, 76326208, 559009987, 548139736, - 541721430, 31450329, 653923741, 676193285, 295171241, 558845563, 387079118, 403184480, 807941436, 501042343, 284608894, 705710380, 82388415, 763336555, 126077422, 438548854, - 606252517, 144569238, 126964439, 809559381, 263253751, 547929033, 236704198, 377978058, 59501955, 749500335, 254242336, 605755194, 408388953, 116242711, 116340056, 691021496, - 48100285, 371076069, 638156108, 211570763, 185945242, 653505761, 667569173, 335131755, 736662207, 572078378, 755939949, 840393623, 322934679, 520522390, 252068808, 491370519, - 200565770, 552637112, 182345569, 394747039, 822229467, 817698102, 644484388, 156591766, 729600982, 695826242, 509682463, 785132583, 746139100, 188369785, 628995003, 406654440, - 650660075, 676485042, 540766742, 493428142, 753346328, 82608613, 670846442, 145894970, 770907988, 621807160, 14676199, 793865193, 36579515, 619741404, 303691972, 794920577, - 134684826, 190038753, 538889970, 836657477, 643017556, 316870164, 464572481, 305395359, 446406992, 587814221, 423552502, 122802120, 146043780, 173756097, 130720237, 445515559, - 109884833, 133119099, 804139234, 834841519, 458514524, 74213698, 490363622, 119287122, 165016718, 351506713, 433750226, 439149867, 348281119, 319795826, 320785867, 446561207, - 705678831, 714536161, 172299381, 552925586, 635421942, 851853231, 208071525, 142303096, 93164236, 207534795, 655906672, 558127940, 98870558, 388322132, 87475979, 835970665, - 61996500, 298060757, 256194194, 563529863, 249184704, 451295997, 73892211, 559049908, 44006160, 832886345, 720732161, 255948582, 827295342, 629663637, 323103159, 155698755, - 598913314, 586685341, 761273875, 135225209, 324099714, 391112815, 493469140, 796490769, 667498514, 148390126, 721802249, 781884558, 309264043, 603401759, 503111668, 563611748, - 363342598, 383209405, 108340736, 758017880, 145907493, 312330194, 608895549, 45540348, 143092704, 772401556, 806068040, 853177536, 662120004, 463347842, 495085709, 560431884, - 274002454, 76985308, 519320299, 253092838, 727478114, 593752634, 490277266, 206283832, 701277908, 504787112, 816832531, 730997507, 27807749, 58254704, 584933136, 515463756, - 241104222, 251881934, 566567573, 592887586, 528932268, 88111104, 523103099, 448331392, 351083975, 157811347, 758866581, 802151021, 843579185, 481417280, 507414106, 462708367, - 461501222, 790988186, 462220673, 727683888, 159759683, 59757110, 310746434, 326369241, 305829588, 457718309, 529317279, 503631310, 661769334, 343160359, 472216278, 740498212, - 11312284, 760170115, 513391009, 538224236, 710934956, 491998229, 539829044, 610387964, 86624968, 72542777, 493966272, 132327984, 371526334, 182549152, 51622114, 173997077, - 550633787, 205437301, 435219235, 406409162, 414751325, 33371226, 40899348, 77245052, 763383124, 817701136, 598256078, 357440859, 468418959, 353612800, 721601331, 262567156, - 521577430, 232027892, 75986872, 443113391, 107360999, 482079354, 563502258, 782475535, 402866161, 515580626, 742688144, 677398836, 425899303, 42066550, 537192943, 430672016, - 115368023, 64053241, 92008456, 74327791, 572607165, 681138002, 378104858, 695786430, 844827190, 436817825, 751393351, 142965259, 81300919, 688342617, 433082724, 221191094, - 712003270, 301076404, 747091407, 514191589, 814985450, 260951422, 187161058, 22316970, 806106670, 759397054, 158423624, 419813636, 462241316, 438231460, 108466764, 212745115, - 386264342, 176072326, 767127195, 399981627, 762991681, 173125691, 464627163, 770046798, 179369718, 829917528, 693004603, 178596003, 422852852, 182684967, 662425026, 713404098, - 766206683, 130088738, 321282752, 134898541, 86701214, 120555423, 464987852, 82865891, 758340585, 138256323, 308997895, 659614345, 510091933, 822699180, 464631718, 819896232, - 120792059, 160708255, 462868879, 72974246, 260451492, 120601343, 228097712, 369436704, 155304088, 74380537, 732305166, 203294189, 307421597, 96510570, 634243454, 486539430, - 16204477, 241987531, 317824421, 510180366, 794475492, 262770124, 441034891, 741864347, 205569410, 684844547, 340863522, 440616421, 454438375, 26285496, 141886125, 648947081, - 3791510, 529746935, 317826713, 411458050, 661690316, 45696331, 679684665, 184597094, 829228068, 375683582, 591739456, 855242340, 628594662, 30968619, 363932244, 103091463, - 614269714, 465960778, 791477766, 332731888, 853151007, 266045534, 132189407, 435008168, 65667470, 669304246, 760035868, 481409581, 36650645, 523634336, 702968013, 351902214, - 284360680, 34261165, 593134528, 337534074, 239112910, 710342799, 163287447, 20209506, 780785984, 480727309, 125776519, 691236193, 603228570, 48261672, 183120677, 73638683, - 3430616, 568026489, 808739797, 298585898, 64471573, 724550960, 568093636, 187449517, 655699449, 672689645, 829049456, 263525899, 612969883, 621652807, 186362075, 731851539, - 377104257, 39335761, 210768226, 253965025, 201921517, 715681274, 369453531, 18897741, 612559390, 660723864, 476963596, 585483298, 318614839, 227626072, 298891387, 110505944, - 814885802, 177563961, 443724544, 374856237, 577963338, 617516835, 475669105, 633353115, 12579943, 796644307, 569746680, 22381253, 343603333, 724567543, 845363898, 4023795, - 801359177, 347489967, 214644600, 78674056, 131782857, 284041623, 660502381, 161470286, 668158595, 765738294, 715872268, 678418089, 280458288, 758715787, 9311288, 490771912, - 757112000, 253990619, 698573830, 390611635, 52593584, 421202448, 494394112, 386893540, 29349323, 533111491, 774401558, 108660117, 405990553, 143728136, 852741683, 354532633, - 440222591, 663461253, 593338391, 298882952, 758170600, 660294062, 332348846, 541714172, 77716403, 169377728, 71932929, 110210904, 776771173, 645222398, 162195941, 792388932, - 502165627, 146897021, 243625970, 139123400, 462352793, 409369440, 247509680, 270865496, 539140627, 16949766, 245869282, 637926655, 37386603, 383033875, 316560876, 707909555, - 367315004, 173821041, 529529257, 227507318, 831716891, 830055847, 228911074, 205127100, 178872273, 819938491, 129875615, 764680417, 97028082, 560682982, 433649390, 727508847, - 494848582, 81279272, 435186566, 174468080, 69172161, 241860102, 692179355, 333985572, 788895276, 469576414, 594155471, 157828532, 182105752, 310394758, 673085082, 695719789, - 39004854, 251000641, 98748282, 744318650, 815050298, 622456803, 240419561, 403871914, 202214044, 627433637, 649505808, 668918393, 334630440, 386856024, 352649543, 135139523, - 216499252, 736376783, 269223150, 468318208, 801808348, 180378366, 640086372, 672618369, 291378195, 732195369, 805632553, 518515631, 603280165, 629836417, 59712833, 531020081, - 708771168, 539819295, 179149444, 552251927, 458994127, 584987693, 238644928, 640603619, 46728500, 843989005, 688747457, 236924093, 261539965, 705411056, 765907765, 38095657, - 382461698, 146650814, 351462947, 749417520, 628887925, 800857475, 790554154, 695483946, 160495923, 40896482, 471385785, 535516195, 197056285, 622795937, 368016917, 696525353, - 377315918, 58087122, 246518254, 431338589, 795949654, 611141265, 406307405, 365750089, 396243561, 843849531, 33802729, 573076974, 557841126, 411725124, 109489622, 370935707, - 372610558, 769825999, 367932152, 231499145, 240819898, 22648665, 418344529, 142438794, 552806180, 669450690, 614608056, 784369586, 258710636, 474742428, 166021530, 805595815, - 603578176, 686703780, 412868426, 26588048, 379895115, 77550061, 751188758, 294447541, 433574579, 234362222, 821492181, 23912038, 681093196, 483584545, 404339808, 396405029, - 744756742, 702481685, 413127074, 204115019, 187381271, 633523978, 433629465, 628184183, 783160918, 268799033, 646479372, 160458176, 602612912, 644506365, 391554011, 676966578, - 386430153, 98736426, 412745127, 296141927, 685909285, 355152260, 361415843, 127323093, 586337666, 1734791, 368678692, 155431915, 597290023, 109507713, 291804866, 135016081, - 144077689, 35054937, 16808265, 431962815, 534195521, 629326143, 309352001, 319948849, 443083246, 336744161, 100845182, 314804947, 476736581, 468528479, 416978018, 35141019, - 43314058, 384847955, 665126798, 295857628, 768013680, 741182796, 157855570, 695547618, 145251639, 818473396, 708640763, 87460130, 736400748, 465173936, 376720282, 437268868, - 137236663, 693860377, 247960644, 402124416, 656418852, 231401654, 248187016, 628418583, 224261112, 120581342, 49749199, 588812480, 309599954, 111357387, 14507354, 754564049, - 513444423, 816496110, 509193085, 361635970, 190608265, 697367838, 230953561, 140447357, 27745100, 163340427, 607823059, 325305463, 383028479, 269707244, 475022415, 708990989, - 738971809, 797646021, 126610937, 589310701, 191123172, 819715815, 337443183, 432224976, 337343783, 257301390, 172631141, 560659319, 646332329, 55110483, 467212803, 442977895, - 311159578, 569890333, 669396086, 536323022, 542648615, 366162176, 88951009, 408335586, 276237497, 384733042, 525960156, 74199534, 338209206, 676233089, 264342641, 241682204, - 226505461, 165013960, 129858819, 664852498, 432090291, 165700308, 382150900, 537002255, 368893910, 61006155, 238726881, 92317627, 632392147, 404715651, 802622348, 126100061, - 306024238, 397891265, 214661020, 211132870, 783722518, 149847645, 665379914, 624725195, 85864665, 496272723, 304811252, 29995710, 410500887, 756406394, 31206753, 647154006, - 596539568, 783214792, 286381882, 24560691, 681500270, 774933112, 506538708, 850347997, 611696036, 512607061, 251719669, 367108021, 456442965, 636694730, 399940257, 73870039, - 85190759, 264953709, 238854238, 395048514, 612738126, 27417876, 652695826, 188238483, 324168828, 736238139, 789061724, 529275445, 382304068, 176318391, 709989466, 14237691, - }; - - private static final long[] zetainv = new long[]{ - 146156455, 679827530, 473841853, 326870476, 67084197, 119907782, 531977093, 667907438, 203450095, 828728045, 243407795, 461097407, 617291683, 591192212, 770955162, 782275882, - 456205664, 219451191, 399702956, 489037900, 604426252, 343538860, 244449885, 5797924, 349607213, 81212809, 174645651, 831585230, 569764039, 72931129, 259606353, 208991915, - 824939168, 99739527, 445645034, 826150211, 551334669, 359873198, 770281256, 231420726, 190766007, 706298276, 72423403, 645013051, 641484901, 458254656, 550121683, 730045860, - 53523573, 451430270, 223753774, 763828294, 617419040, 795139766, 487252011, 319143666, 473995021, 690445613, 424055630, 191293423, 726287102, 691131961, 629640460, 614463717, - 591803280, 179912832, 517936715, 781946387, 330185765, 471412879, 579908424, 447810335, 767194912, 489983745, 313497306, 319822899, 186749835, 286255588, 544986343, 413168026, - 388933118, 801035438, 209813592, 295486602, 683514780, 598844531, 518802138, 423920945, 518702738, 36430106, 665022749, 266835220, 729534984, 58499900, 117174112, 147154932, - 381123506, 586438677, 473117442, 530840458, 248322862, 692805494, 828400821, 715698564, 625192360, 158778083, 665537656, 494509951, 346952836, 39649811, 342701498, 101581872, - 841638567, 744788534, 546545967, 267333441, 806396722, 735564579, 631884809, 227727338, 607958905, 624744267, 199727069, 454021505, 608185277, 162285544, 718909258, 418877053, - 479425639, 390971985, 119745173, 768685791, 147505158, 37672525, 710894282, 160598303, 698290351, 114963125, 88132241, 560288293, 191019123, 471297966, 812831863, 821004902, - 439167903, 387617442, 379409340, 541340974, 755300739, 519401760, 413062675, 536197072, 546793920, 226819778, 321950400, 424183106, 839337656, 821090984, 712068232, 721129840, - 564341055, 746638208, 258855898, 700714006, 487467229, 854411130, 269808255, 728822828, 494730078, 500993661, 170236636, 560003994, 443400794, 757409495, 469715768, 179179343, - 464591910, 211639556, 253533009, 695687745, 209666549, 587346888, 72985003, 227961738, 422516456, 222621943, 668764650, 652030902, 443018847, 153664236, 111389179, 459740892, - 451806113, 372561376, 175052725, 832233883, 34653740, 621783699, 422571342, 561698380, 104957163, 778595860, 476250806, 829557873, 443277495, 169442141, 252567745, 50550106, - 690124391, 381403493, 597435285, 71776335, 241537865, 186695231, 303339741, 713707127, 437801392, 833497256, 615326023, 624646776, 488213769, 86319922, 483535363, 485210214, - 746656299, 444420797, 298304795, 283068947, 822343192, 12296390, 459902360, 490395832, 449838516, 245004656, 60196267, 424807332, 609627667, 798058799, 478830003, 159620568, - 488129004, 233349984, 659089636, 320629726, 384760136, 815249439, 695649998, 160661975, 65591767, 55288446, 227257996, 106728401, 504682974, 709495107, 473684223, 818050264, - 90238156, 150734865, 594605956, 619221828, 167398464, 12156916, 809417421, 215542302, 617500993, 271158228, 397151794, 303893994, 676996477, 316326626, 147374753, 325125840, - 796433088, 226309504, 252865756, 337630290, 50513368, 123950552, 564767726, 183527552, 216059549, 675767555, 54337573, 387827713, 586922771, 119769138, 639646669, 721006398, - 503496378, 469289897, 521515481, 187227528, 206640113, 228712284, 653931877, 452274007, 615726360, 233689118, 41095623, 111827271, 757397639, 605145280, 817141067, 160426132, - 183060839, 545751163, 674040169, 698317389, 261990450, 386569507, 67250645, 522160349, 163966566, 614285819, 786973760, 681677841, 420959355, 774866649, 361297339, 128637074, - 422496531, 295462939, 759117839, 91465504, 726270306, 36207430, 677273648, 651018821, 627234847, 26090074, 24429030, 628638603, 326616664, 682324880, 488830917, 148236366, - 539585045, 473112046, 818759318, 218219266, 610276639, 839196155, 317005294, 585280425, 608636241, 446776481, 393793128, 717022521, 612519951, 709248900, 353980294, 63756989, - 693949980, 210923523, 79374748, 745935017, 784212992, 686768193, 778429518, 314431749, 523797075, 195851859, 97975321, 557262969, 262807530, 192684668, 415923330, 501613288, - 3404238, 712417785, 450155368, 747485804, 81744363, 323034430, 826796598, 469252381, 361751809, 434943473, 803552337, 465534286, 157572091, 602155302, 99033921, 365374009, - 846834633, 97430134, 575687633, 177727832, 140273653, 90407627, 187987326, 694675635, 195643540, 572104298, 724363064, 777471865, 641501321, 508655954, 54786744, 852122126, - 10782023, 131578378, 512542588, 833764668, 286399241, 59501614, 843565978, 222792806, 380476816, 238629086, 278182583, 481289684, 412421377, 678581960, 41260119, 745639977, - 557254534, 628519849, 537531082, 270662623, 379182325, 195422057, 243586531, 837248180, 486692390, 140464647, 654224404, 602180896, 645377695, 816810160, 479041664, 124294382, - 669783846, 234493114, 243176038, 592620022, 27096465, 183456276, 200446472, 668696404, 288052285, 131594961, 791674348, 557560023, 47406124, 288119432, 852715305, 782507238, - 673025244, 807884249, 252917351, 164909728, 730369402, 375418612, 75359937, 835936415, 692858474, 145803122, 617033011, 518611847, 263011393, 821884756, 571785241, 504243707, - 153177908, 332511585, 819495276, 374736340, 96110053, 186841675, 790478451, 421137753, 723956514, 590100387, 2994914, 523414033, 64668155, 390185143, 241876207, 753054458, - 492213677, 825177302, 227551259, 903581, 264406465, 480462339, 26917853, 671548827, 176461256, 810449590, 194455605, 444687871, 538319208, 326398986, 852354411, 207198840, - 714259796, 829860425, 401707546, 415529500, 515282399, 171301374, 650576511, 114281574, 415111030, 593375797, 61670429, 345965555, 538321500, 614158390, 839941444, 369606491, - 221902467, 759635351, 548724324, 652851732, 123840755, 781765384, 700841833, 486709217, 628048209, 735544578, 595694429, 783171675, 393277042, 695437666, 735353862, 36249689, - 391514203, 33446741, 346053988, 196531576, 547148026, 717889598, 97805336, 773280030, 391158069, 735590498, 769444707, 721247380, 534863169, 726057183, 89939238, 142741823, - 193720895, 673460954, 433293069, 677549918, 163141318, 26228393, 676776203, 86099123, 391518758, 683020230, 93154240, 456164294, 89018726, 680073595, 469881579, 643400806, - 747679157, 417914461, 393904605, 436332285, 697722297, 96748867, 50039251, 833828951, 668984863, 595194499, 41160471, 341954332, 109054514, 555069517, 144142651, 634954827, - 423063197, 167803304, 774845002, 713180662, 104752570, 419328096, 11318731, 160359491, 478041063, 175007919, 283538756, 781818130, 764137465, 792092680, 740777898, 425473905, - 318952978, 814079371, 430246618, 178747085, 113457777, 340565295, 453279760, 73670386, 292643663, 374066567, 748784922, 413032530, 780159049, 624118029, 334568491, 593578765, - 134544590, 502533121, 387726962, 498705062, 257889843, 38444785, 92762797, 778900869, 815246573, 822774695, 441394596, 449736759, 420926686, 650708620, 305512134, 682148844, - 804523807, 673596769, 484619587, 723817937, 362179649, 783603144, 769520953, 245757957, 316316877, 364147692, 145210965, 317921685, 342754912, 95975806, 844833637, 115647709, - 383929643, 512985562, 194376587, 352514611, 326828642, 398427612, 550316333, 529776680, 545399487, 796388811, 696386238, 128462033, 393925248, 65157735, 394644699, 393437554, - 348731815, 374728641, 12566736, 53994900, 97279340, 698334574, 505061946, 407814529, 333042822, 768034817, 327213653, 263258335, 289578348, 604263987, 615041699, 340682165, - 271212785, 797891217, 828338172, 125148414, 39313390, 351358809, 154868013, 649862089, 365868655, 262393287, 128667807, 603053083, 336825622, 779160613, 582143467, 295714037, - 361060212, 392798079, 194025917, 2968385, 50077881, 83744365, 713053217, 810605573, 247250372, 543815727, 710238428, 98128041, 747805185, 472936516, 492803323, 292534173, - 353034253, 252744162, 546881878, 74261363, 134343672, 707755795, 188647407, 59655152, 362676781, 465033106, 532046207, 720920712, 94872046, 269460580, 257232607, 700447166, - 533042762, 226482284, 28850579, 600197339, 135413760, 23259576, 812139761, 297096013, 782253710, 404849924, 606961217, 292616058, 599951727, 558085164, 794149421, 20175256, - 768669942, 467823789, 757275363, 298017981, 200239249, 648611126, 762981685, 713842825, 648074396, 4292690, 220723979, 303220335, 683846540, 141609760, 150467090, 409584714, - 535360054, 536350095, 507864802, 416996054, 422395695, 504639208, 691129203, 736858799, 365782299, 781932223, 397631397, 21304402, 52006687, 723026822, 746261088, 410630362, - 725425684, 682389824, 710102141, 733343801, 432593419, 268331700, 409738929, 550750562, 391573440, 539275757, 213128365, 19488444, 317255951, 666107168, 721461095, 61225344, - 552453949, 236404517, 819566406, 62280728, 841469722, 234338761, 85237933, 710250951, 185299479, 773537308, 102799593, 362717779, 315379179, 179660879, 205485846, 449491481, - 227150918, 667776136, 110006821, 71013338, 346463458, 160319679, 126544939, 699554155, 211661533, 38447819, 33916454, 461398882, 673800352, 303508809, 655580151, 364775402, - 604077113, 335623531, 533211242, 15752298, 100205972, 284067543, 119483714, 521014166, 188576748, 202640160, 670200679, 644575158, 217989813, 485069852, 808045636, 165124425, - 739805865, 739903210, 447756968, 250390727, 601903585, 106645586, 796643966, 478167863, 619441723, 308216888, 592892170, 46586540, 729181482, 711576683, 249893404, 417597067, - 730068499, 92809366, 773757506, 150435541, 571537027, 355103578, 48204485, 452961441, 469066803, 297300358, 560974680, 179952636, 202222180, 824695592, 314424491, 308006185, - 297135934, 779819713, 330834295, 607966158, 139470846, 532806876, 496761739, 144658310, 596051835, 523120535, 278370351, 259687598, 396035181, 318441635, 708341794, 261702166, - 96131132, 562196508, 712552283, 121414502, 139181388, 369274231, 188501611, 591747839, 321238361, 800859904, 483293761, 574521237, 318624730, 451184298, 845303892, 824439814, - 513057916, 488248363, 110823008, 474732383, 469456681, 693990629, 824427131, 100906910, 393033981, 613525172, 780573584, 732240054, 662144127, 156900476, 412266288, 762627793, - 55879529, 662447594, 435100580, 334994905, 345348008, 216291111, 115536138, 354908192, 480736673, 347619959, 213042018, 132255342, 192070634, 196227843, 171656829, 457430277, - 456173657, 235184482, 708639607, 80162055, 78550737, 659824274, 145948236, 14732004, 377312541, 551950153, 807387365, 517885521, 536344534, 144062333, 788152134, 12135251, - 342084445, 121817512, 115642280, 147002280, 138875114, 74245619, 95327390, 646649415, 207948635, 518439532, 33183835, 74137806, 802754590, 326978677, 329330108, 541984162, - 615015895, 340312953, 218073212, 814998766, 157716436, 203155225, 214901690, 385807168, 392276620, 170965976, 458479761, 35398460, 134705722, 309083692, 60435010, 846143590, - 745522807, 606438974, 750326300, 746569701, 117316274, 717210198, 601189495, 52499415, 136915847, 255901848, 12306030, 304281576, 765340988, 142286353, 789909728, 103773804, - 49871665, 592012809, 266996441, 65625212, 81727898, 594201480, 200644793, 452686638, 43973291, 532301993, 739336488, 682224565, 845517209, 427753763, 474414446, 386025969, - 96949342, 759705038, 589678515, 780837334, 158063634, 325974167, 809607430, 589067353, 176830058, 410812375, 382294428, 258796598, 468141533, 703441408, 673473968, 642305805, - 218673395, 535461624, 674684956, 680203874, 846088654, 52914042, 758979987, 589962189, 325345164, 117477831, 120913707, 782220389, 60703501, 614017575, 99993130, 235368093, - 644276216, 121149740, 315046926, 183533385, 13034140, 721604492, 242970774, 500232976, 316143635, 719601853, 411832633, 206849167, 62309503, 362143540, 172132792, 406642102, - 290947418, 649997984, 400004941, 193289674, 20215276, 604047240, 792504507, 354704972, 661308027, 710569578, 67988066, 573986043, 298011050, 675020897, 371173377, 220311134, - 234250033, 627878145, 805292463, 24071270, 648507616, 814745610, 517644997, 691772925, 511004739, 433787663, 788161195, 196473632, 362036173, 528196877, 697880168, 318651435, - 223922625, 432332761, 605658712, 402713163, 12043466, 723222719, 197191480, 740372189, 835875906, 689010272, 292485650, 101464751, 764616290, 665830492, 830680702, 522703957, - 36639665, 178661761, 847563520, 213367890, 580759073, 795883933, 189665782, 410128628, 104008441, 757987331, 543934116, 420541294, 396733102, 773554582, 422990463, 679308804, - 471610475, 449025573, 293585715, 304333306, 606221987, 668107507, 201587373, 776461576, 54202261, 334132687, 570371370, 729669465, 388035450, 40739162, 294599466, 269999181, - 368420277, 394723115, 506277838, 351687671, 683668119, 82918314, 72721076, 702889204, 841003831, 721904142, 691037495, 575492049, 221172299, 608377016, 584007171, 674474012, - 135083989, 479195654, 408808739, 442284285, 530250590, 390248853, 461685089, 283253906, 717741307, 215568024, 562986577, 134817130, 147002383, 270825931, 379404006, 759183054, - 581866917, 146566613, 784989241, 457129596, 59158644, 750640670, 700398504, 721509487, 402874366, 82387404, 95739856, 281346626, 467686791, 324137743, 11249127, 89157220, - 716002070, 335342053, 246826170, 529385048, 760143990, 10725758, 516293110, 76538324, 257296477, 328165824, 172330118, 546825765, 619673906, 328792017, 788124094, 141927682, - 555365723, 329427916, 607839982, 405389708, 571868667, 470002428, 684585751, 434604631, 204705039, 450529242, 361817407, 727855567, 413589322, 11544453, 803784599, 815775166, - 425469974, 86512573, 86029713, 852702639, 728364190, 118324485, 477615251, 345426513, 219927860, 22417298, 480050287, 224592838, 759159, 131898579, 764335555, 457432197, - 763875505, 642888584, 590641758, 210009158, 390019414, 235949401, 58219618, 562286114, 99631682, 631925366, 753164064, 328774959, 365242602, 385354452, 217542778, 795464774, - 780632705, 678141873, 424450214, 25338472, 268284342, 493213958, 580867867, 15482483, 272837023, 328359708, 782291772, 308114267, 404813197, 333753982, 737682027, 538312006, - 707909990, 234156623, 323140190, 803917719, 91035383, 200098402, 773260410, 554209269, 505977196, 258732217, 577347247, 388868026, 412079442, 312571314, 628683299, 740119334, - 813470861, 86544483, 515146109, 371343866, 687853001, 265823977, 121589622, 808348288, 257353942, 635427508, 834922294, 224797491, 432675367, 731353224, 575538372, 642351606, - 291366364, 210732817, 90658793, 146401688, 40748954, 527574284, 817614743, 547167333, 534136352, 372456076, 706600074, 640500788, 559786839, 845776458, 709348802, 677707036, - 606711824, 349565805, 42095011, 472115432, 177053484, 681164976, 139728272, 510212596, 747795405, 441873933, 187174498, 392929945, 425171378, 555237229, 4315335, 9057268, - 153360848, 99426909, 774527252, 83014618, 412368218, 3495282, 739674290, 826674363, 316599527, 110724402, 435058302, 156418860, 545209527, 681526436, 443190082, 613052844, - 463370538, 710824143, 207309740, 783222241, 141846134, 266325996, 146201876, 449154790, 170683627, 716235176, 607164090, 291006513, 186310404, 43734965, 496486286, 736873833, - 329899967, 408796174, 449053875, 589454563, 727957502, 460484783, 122169115, 75292611, 73671599, 848010384, 303936940, 791662107, 590932920, 125786858, 211282605, 729648214, - 59156462, 152461927, 219894477, 776823847, 437757228, 186542194, 700611431, 257929382, 767315412, 18312688, 806906190, 504497667, 101165190, 603435510, 526872520, 254322283, - 720021990, 779194394, 584710319, 801191565, 703649817, 361258161, 149741435, 808495563, 291596204, 250916275, 340042453, 141837377, 547502361, 181348702, 139498738, 338114582, - 119328746, 177984134, 199957575, 358181386, 57332620, 512567111, 451958433, 156026128, 619998073, 307816265, 338764588, 65822147, 573828018, 487154809, 749222428, 522943099, - 26336097, 186644498, 526288314, 534618890, 828269735, 675600958, 49788769, 453731878, 762637295, 387744335, 173171058, 33040483, 466949551, 843388255, 697432416, 216291746, - 33282177, 240642656, 663436347, 390123214, 254438583, 190922896, 455331923, 296664914, 762697018, 331531324, 851176113, 771233913, 482330259, 389665212, 474944010, 58762628, - 469089651, 436049255, 697216430, 431783325, 138107147, 499492245, 647224366, 407794272, 26067376, 445177552, 520720342, 798948406, 325365361, 117634101, 664099671, 153294810, - 597801361, 640257687, 533951825, 702134729, 111685295, 685214097, 452013666, 317534558, 271219665, 529108611, 586379543, 355661610, 759841823, 446485943, 839034731, 33604088, - 773212146, 191869702, 367354365, 689096322, 345311446, 438596834, 677372537, 542545550, 341130619, 292644024, 281192613, 251893811, 447792713, 520181371, 40921126, 778878825, - 536838039, 230752698, 396625895, 601216134, 188488092, 130103565, 504870771, 413838340, 335573256, 124340986, 368340993, 243753204, 150144590, 808689996, 32468801, 68817331, - 471378712, 566347573, 6430376, 651137151, 497752158, 823732827, 787280015, 789046852, 194658966, 171151811, 118113814, 793917550, 75187158, 717603845, 61671631, 51620383, - 302490719, 78328345, 244847301, 549511806, 420356371, 560795789, 405546061, 302036596, 432306081, 270856136, 330554928, 212724399, 791196206, 445342723, 187781362, 87078067, - 834667388, 218628624, 755629702, 148790011, 845609309, 89984158, 742118272, 475309628, 81731129, 107846408, 74447254, 68656823, 169459843, 643648059, 721924181, 212112779, - 575076242, 471039705, 626114838, 564548835, 506450263, 488329877, 847101683, 592828368, 714089721, 832868261, 393063639, 603199595, 214221357, 747808090, 145225511, 784491117, - 578386518, 253504617, 217256612, 432640963, 696210495, 700338942, 642132261, 394125773, 127189460, 622643989, 65557316, 850423288, 154198317, 360118020, 401298167, 809808378, - 590060278, 378333119, 261388063, 301240958, 211172470, 476577014, 818999735, 320797504, 155490801, 362021897, 416507223, 193972866, 814253796, 555879930, 152626252, 598011677, - 48971665, 590814257, 699100720, 732535868, 42427027, 335391594, 577502901, 72445917, 562054823, 34689534, 850274973, 640356274, 165636151, 309704599, 39996866, 436255023, - 365085534, 208984696, 593049885, 755419039, 376895434, 634901252, 316743954, 476563344, 619551824, 766199910, 783651060, 32670169, 794822305, 435248113, 14247580, 284417137, - 754554090, 30678221, 641072629, 711946716, 568640914, 656468482, 83597913, 356324101, 231391682, 122476642, 505437404, 636148283, 639556222, 262242870, 10083895, 470763095, - 7162643, 490677454, 122627583, 711718981, 252376484, 423795716, 578101600, 275970963, 3053131, 327430341, 435804223, 349044314, 649311691, 234207954, 379806804, 342513855, - 224624649, 181857560, 84797030, 123047825, 95186646, 293471117, 586961654, 111168138, 703259490, 756871363, 606284506, 380213718, 292725815, 463763080, 747629289, 254624782, - 207883602, 849297083, 578506664, 656289117, 454015629, 162235991, 474249177, 633829447, 490767799, 210190430, 48735841, 656982789, 743473215, 47313566, 306689440, 53334547, - 370344121, 419993940, 218969756, 341956367, 296184959, 135682817, 127205066, 744169001, 445909513, 801533404, 605661030, 181244618, 30772614, 196639386, 59911722, 616623643, - 199307436, 551535136, 136575017, 79424355, 92705102, 498046224, 17339996, 698541762, 804348245, 104258042, 484400476, 535014225, 87644978, 121726462, 383782353, 77562877, - 350468417, 724994239, 772938366, 320269449, 203075846, 465307490, 585234251, 271855066, 464423241, 403123130, 202162074, 117126999, 653413020, 8084225, 216658351, 409614891, - 799241223, 600931579, 454131285, 782741932, 376344215, 79696641, 803438191, 565030050, 460657460, 5110534, 472517130, 76991417, 572426425, 92047134, 285371277, 843473400, - 389338704, 704515255, 459914006, 657120075, 708563883, 78813141, 11770883, 688134435, 287808573, 649280542, 765338883, 439803770, 160535862, 617753423, 442051682, 288864924, - 32955626, 326880188, 696887038, 215124062, 791918307, 767157413, 358676037, 30612492, 661971023, 838968782, 465224708, 784600829, 146985424, 799718881, 207906900, 340800263, - 849693954, 44777992, 31326149, 240259940, 508401593, 499528021, 475930852, 690672059, 580019353, 297040464, 236338202, 454171188, 695134912, 508172471, 436504159, 293630619, - 848875161, 37043893, 26993038, 396046068, 722016462, 445419380, 209243403, 503786686, 268117854, 281672598, 205034970, 87894257, 293598267, 46912651, 147959859, 462629641, - 509044664, 700768221, 107374762, 340721447, 163551982, 247501118, 447395984, 318219025, 172114399, 110025830, 810265637, 370215004, 606303954, 462642711, 251114029, 290800715, - 780017258, 789443137, 495480307, 615909633, 431756150, 766376396, 820732666, 686803688, 133668454, 761665150, 326017339, 424112204, 110554261, 386347465, 101066781, 135666139, - 256882780, 205722545, 668032392, 405718561, 350327055, 621444438, 381307379, 421184831, 753121128, 590538618, 366906511, 345326178, 132085192, 40531091, 780676557, 586664955, - 597888984, 693668509, 487104387, 234747974, 572624063, 114516856, 550027276, 316481563, 239535126, 788436714, 847219527, 113421825, 200615887, 815912760, 581164384, 191193216, - 11551938, 606832431, 431210833, 196126697, 92508342, 270544041, 192437514, 99153842, 188585579, 413385580, 745267475, 448172363, 667109106, 85272138, 658601344, 443173146, - 392530856, 589073317, 382995167, 248915715, 375600977, 386782401, 254322056, 790853708, 580714915, 163129486, 824017519, 86419559, 117205367, 634667017, 566451589, 852749522, - 837490424, 330422330, 294598189, 814909626, 505390042, 125578715, 357313675, 450539487, 233746299, 446282749, 755039478, 740350430, 598956163, 116099139, 167482754, 310512355, - 135624781, 470874939, 196356683, 239902897, 693520220, 454942578, 778240578, 45236161, 51101673, 270126615, 94622194, 524282161, 632376971, 703121383, 587013336, 572429454, - 37728898, 143682359, 206045437, 557167425, 770459696, 477771773, 321346425, 290390778, 100874902, 758540246, 746805823, 459566327, 607673901, 158286491, 527010720, 579461268, - 74963118, 420964844, 51316958, 250512679, 452729483, 35670488, 559935164, 734294507, 379228497, 172592106, 126508187, 757555710, 853874620, 808517874, 106015915, 375691866, - 423413164, 423111661, 60250078, 645353691, 853830811, 288310932, 1489804, 127886925, 191505834, 459549138, 542519706, 369115379, 116842790, 784888677, 269818678, 712117130, - 748410048, 139982101, 169805525, 32264681, 532400632, 397389041, 181262233, 703428567, 604760852, 44143128, 69914527, 86615396, 314810965, 68145528, 650868687, 717671367, - 594246701, 641155397, 207406129, 180083553, 414651973, 132523243, 211350471, 397371331, 170688638, 732763563, 132155217, 394688247, 571356350, 93856418, 708831649, 841908230, - }; - - - static void poly_uniform(long[] a, byte[] seed, int seedOffset) - { - int pos = 0, i = 0, nbytes = (PARAM_Q_LOG + 7) / 8; - int nblocks = PARAM_GEN_A; - int val1, val2, val3, val4, mask = (1 << PARAM_Q_LOG) - 1; - byte[] buf = new byte[HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * PARAM_GEN_A]; - short dmsp = 0; - - // GenA: the XOF is instantiated with cSHAKE128 (see Algorithm 10). - HashUtils.customizableSecureHashAlgorithmKECCAK128Simple( - buf, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * PARAM_GEN_A, - dmsp++, - seed, seedOffset, CRYPTO_RANDOMBYTES - ); - - - while (i < PARAM_K * PARAM_N) - { - if (pos > HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * nblocks - 4 * nbytes) - { - nblocks = 1; - - // GenA: the XOF is instantiated with cSHAKE128 (see Algorithm 10). - HashUtils.customizableSecureHashAlgorithmKECCAK128Simple( - buf, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * PARAM_GEN_A, - dmsp++, - seed, seedOffset, CRYPTO_RANDOMBYTES - ); - - pos = 0; - } - val1 = Pack.littleEndianToInt(buf, pos) & mask; - pos += nbytes; - val2 = Pack.littleEndianToInt(buf, pos) & mask; - pos += nbytes; - val3 = Pack.littleEndianToInt(buf, pos) & mask; - pos += nbytes; - val4 = Pack.littleEndianToInt(buf, pos) & mask; - pos += nbytes; - if (val1 < PARAM_Q && i < PARAM_K * PARAM_N) - { - a[i++] = reduce((long)val1 * PARAM_R2_INVN); - } - if (val2 < PARAM_Q && i < PARAM_K * PARAM_N) - { - a[i++] = reduce((long)val2 * PARAM_R2_INVN); - } - if (val3 < PARAM_Q && i < PARAM_K * PARAM_N) - { - a[i++] = reduce((long)val3 * PARAM_R2_INVN); - } - if (val4 < PARAM_Q && i < PARAM_K * PARAM_N) - { - a[i++] = reduce((long)val4 * PARAM_R2_INVN); - } - } - } - - - static long reduce(long a) - { // Montgomery reduction - long u; - - u = (a * (long)PARAM_QINV) & 0xFFFFFFFFL; - u *= PARAM_Q; - a += u; - return a >> 32; - } - - - static void ntt(long[] a, long[] w) - { // Forward NTT transform - int NumoProblems = PARAM_N >> 1, jTwiddle = 0; - - for (; NumoProblems > 0; NumoProblems >>= 1) - { - int jFirst, j = 0; - for (jFirst = 0; jFirst < PARAM_N; jFirst = j + NumoProblems) - { - int W = (int)w[jTwiddle++]; - for (j = jFirst; j < jFirst + NumoProblems; j++) - { - long temp = barr_reduce(reduce(W * a[j + NumoProblems])); - a[j + NumoProblems] = barr_reduce(a[j] + (2L * PARAM_Q - temp)); - a[j] = barr_reduce(temp + a[j]); - } - } - } - } - - - static long barr_reduce(long a) - { // Barrett reduction - long u = (((long)a * PARAM_BARR_MULT) >> PARAM_BARR_DIV); // TODO u may need to be cast back to int. - return a - u * PARAM_Q; - } - - - static void nttinv(long[] a, long[] w) - { // Inverse NTT transform - int NumoProblems = 1, jTwiddle = 0; - for (NumoProblems = 1; NumoProblems < PARAM_N; NumoProblems *= 2) - { - int jFirst, j = 0; - for (jFirst = 0; jFirst < PARAM_N; jFirst = j + NumoProblems) - { - int W = (int)w[jTwiddle++]; - for (j = jFirst; j < jFirst + NumoProblems; j++) - { - long temp = a[j]; - - a[j] = barr_reduce((temp + a[j + NumoProblems])); - a[j + NumoProblems] = barr_reduce(reduce(W * (temp + (2L * PARAM_Q - a[j + NumoProblems])))); - } - } - } - } - - static void nttinv(long[] a, int aPos, long[] w) - { // Inverse NTT transform - int NumoProblems = 1, jTwiddle = 0; - for (NumoProblems = 1; NumoProblems < PARAM_N; NumoProblems *= 2) - { - int jFirst, j = 0; - for (jFirst = 0; jFirst < PARAM_N; jFirst = j + NumoProblems) - { - int W = (int)w[jTwiddle++]; - for (j = jFirst; j < jFirst + NumoProblems; j++) - { - long temp = a[aPos + j]; - a[aPos + j] = barr_reduce((temp + a[aPos + j + NumoProblems])); - a[aPos + j + NumoProblems] = barr_reduce(reduce((long)W * (temp + (2L * PARAM_Q - a[aPos + j + NumoProblems])))); - } - } - - } - } - - - static void poly_ntt(long[] x_ntt, long[] x) - { // Call to NTT function. Avoids input destruction - - for (int i = 0; i < PARAM_N; i++) - { - x_ntt[i] = x[i]; - } - ntt(x_ntt, zeta); - } - - - static void poly_pointwise(long[] result, long[] x, long[] y) - { // Pointwise polynomial multiplication result = x.y - - for (int i = 0; i < PARAM_N; i++) - { - result[i] = reduce((long)x[i] * y[i]); - } - } - - static void poly_pointwise(long[] result, int rpos, long[] x, int xpos, long[] y) - { // Pointwise polynomial multiplication result = x.y - - for (int i = 0; i < PARAM_N; i++) - { - result[i + rpos] = reduce((long)x[i + xpos] * y[i]); - } - } - - - static void poly_mul(long[] result, long[] x, long[] y) - { // Polynomial multiplication result = x*y, with in place reduction for (X^N+1) - // The input x is assumed to be in NTT form -// long[] y_ntt = new long[PARAM_N]; -// -// for (int i = 0; i < PARAM_N; i++) -// { -// y_ntt[i] = y[i]; -// } -// -// ntt(y_ntt, zeta); - poly_pointwise(result, x, y); - nttinv(result, zetainv); - } - - - static void poly_mul(long[] result, int rpos, long[] x, int xpos, long[] y) - { // Polynomial multiplication result = x*y, with in place reduction for (X^N+1) - - poly_pointwise(result, rpos, x, xpos, y); - nttinv(result, rpos, zetainv); - } - - - static void poly_add(long[] result, long[] x, long[] y) - { // Polynomial addition result = x+y - - for (int i = 0; i < PARAM_N; i++) - { - result[i] = x[i] + y[i]; - } - } - - static void poly_sub(long[] result, int rpos, long[] x, int xpos, long[] y, int ypos) - { // Polynomial subtraction result = x-y - - for (int i = 0; i < PARAM_N; i++) - { - result[rpos + i] = barr_reduce(x[xpos + i] - y[ypos + i]); - } - } - - - static void poly_add_correct(long[] result, int rpos, long[] x, int xpos, long[] y, int ypos) - { // Polynomial addition result = x+y with correction - - for (int i = 0; i < PARAM_N; i++) - { - result[rpos + i] = x[xpos + i] + y[ypos + i]; - result[rpos + i] -= PARAM_Q; - result[rpos + i] += (result[rpos + i] >> (RADIX32 - 1)) & PARAM_Q; // If result[i] >= q then subtract q - } - } - - - static void poly_sub_correct(int[] result, int[] x, int[] y) - { // Polynomial subtraction result = x-y with correction - - for (int i = 0; i < PARAM_N; i++) - { - result[i] = x[i] - y[i]; - result[i] += (result[i] >> (RADIX32 - 1)) & PARAM_Q; // If result[i] < 0 then add q - } - } - - - static void sparse_mul8(long[] prod, int ppos, byte[] s, int spos, int[] pos_list, short[] sign_list) - { - int i, j, pos; - - for (i = 0; i < PARAM_N; i++) - { - prod[ppos + i] = 0; - } - - for (i = 0; i < PARAM_H; i++) - { - pos = pos_list[i]; - for (j = 0; j < pos; j++) - { - prod[ppos + j] = prod[ppos + j] - sign_list[i] * s[spos + j + PARAM_N - pos]; - } - for (j = pos; j < PARAM_N; j++) - { - prod[ppos + j] = prod[ppos + j] + sign_list[i] * s[spos + j - pos]; - } - } - } - - - static void sparse_mul8(long[] prod, byte[] s, int[] pos_list, short[] sign_list) - { - int i, j, pos; - byte t[] = s; - - for (i = 0; i < PARAM_N; i++) - { - prod[i] = 0; - } - - for (i = 0; i < PARAM_H; i++) - { - pos = pos_list[i]; - for (j = 0; j < pos; j++) - { - prod[j] = prod[j] - sign_list[i] * t[j + PARAM_N - pos]; - } - for (j = pos; j < PARAM_N; j++) - { - prod[j] = prod[j] + sign_list[i] * t[j - pos]; - } - } - } - - - static void sparse_mul16(int[] prod, int s[], int pos_list[], short sign_list[]) - { - int i, j, pos; -// short[] t = s; - - for (i = 0; i < PARAM_N; i++) - { - prod[i] = 0; - } - - for (i = 0; i < PARAM_H; i++) - { - pos = pos_list[i]; - for (j = 0; j < pos; j++) - { - prod[j] = prod[j] - sign_list[i] * s[j + PARAM_N - pos]; - } - for (j = pos; j < PARAM_N; j++) - { - prod[j] = prod[j] + sign_list[i] * s[j - pos]; - } - } - } - - - static void sparse_mul32(int[] prod, int[] pk, int[] pos_list, short[] sign_list) - { - int i, j, pos; - - for (i = 0; i < PARAM_N; i++) - { - prod[i] = 0; - } - - for (i = 0; i < PARAM_H; i++) - { - pos = pos_list[i]; - for (j = 0; j < pos; j++) - { - prod[j] = prod[j] - sign_list[i] * pk[j + PARAM_N - pos]; - } - for (j = pos; j < PARAM_N; j++) - { - prod[j] = prod[j] + sign_list[i] * pk[j - pos]; - } - } - } - - static void sparse_mul32(long[] prod, int ppos, int[] pk, int pkPos, int[] pos_list, short[] sign_list) - { - int i, j, pos; - - for (i = 0; i < PARAM_N; i++) - { - prod[ppos + i] = 0; - } - - for (i = 0; i < PARAM_H; i++) - { - pos = pos_list[i]; - for (j = 0; j < pos; j++) - { - prod[ppos + j] = prod[ppos + j] - sign_list[i] * pk[pkPos + j + PARAM_N - pos]; - } - for (j = pos; j < PARAM_N; j++) - { - prod[ppos + j] = prod[ppos + j] + sign_list[i] * pk[pkPos + j - pos]; - } - } - } - - - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/Layer.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/Layer.java deleted file mode 100644 index 4cc2aed6de..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/Layer.java +++ /dev/null @@ -1,322 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.rainbow; - -import java.security.SecureRandom; - -import org.bouncycastle.pqc.legacy.crypto.rainbow.util.GF2Field; -import org.bouncycastle.pqc.legacy.crypto.rainbow.util.RainbowUtil; -import org.bouncycastle.util.Arrays; - - -/** - * This class represents a layer of the Rainbow Oil- and Vinegar Map. Each Layer - * consists of oi polynomials with their coefficients, generated at random. - *

    - * To sign a document, we solve a LES (linear equation system) for each layer in - * order to find the oil variables of that layer and to be able to use the - * variables to compute the signature. This functionality is implemented in the - * RainbowSignature-class, by the aid of the private key. - *

    - * Each layer is a part of the private key. - *

    - * More information about the layer can be found in the paper of Jintai Ding, - * Dieter Schmidt: Rainbow, a New Multivariable Polynomial Signature Scheme. - * ACNS 2005: 164-175 (https://dx.doi.org/10.1007/11496137_12) - */ -public class Layer -{ - private int vi; // number of vinegars in this layer - private int viNext; // number of vinegars in next layer - private int oi; // number of oils in this layer - - /* - * k : index of polynomial - * - * i,j : indices of oil and vinegar variables - */ - private short[/* k */][/* i */][/* j */] coeff_alpha; - private short[/* k */][/* i */][/* j */] coeff_beta; - private short[/* k */][/* i */] coeff_gamma; - private short[/* k */] coeff_eta; - - /** - * Constructor - * - * @param vi number of vinegar variables of this layer - * @param viNext number of vinegar variables of next layer. It's the same as - * (num of oils) + (num of vinegars) of this layer. - * @param coeffAlpha alpha-coefficients in the polynomials of this layer - * @param coeffBeta beta-coefficients in the polynomials of this layer - * @param coeffGamma gamma-coefficients in the polynomials of this layer - * @param coeffEta eta-coefficients in the polynomials of this layer - */ - public Layer(byte vi, byte viNext, short[][][] coeffAlpha, - short[][][] coeffBeta, short[][] coeffGamma, short[] coeffEta) - { - this.vi = vi & 0xff; - this.viNext = viNext & 0xff; - this.oi = this.viNext - this.vi; - - // the secret coefficients of all polynomials in this layer - this.coeff_alpha = coeffAlpha; - this.coeff_beta = coeffBeta; - this.coeff_gamma = coeffGamma; - this.coeff_eta = coeffEta; - } - - /** - * This function generates the coefficients of all polynomials in this layer - * at random using random generator. - * - * @param sr the random generator which is to be used - */ - public Layer(int vi, int viNext, SecureRandom sr) - { - this.vi = vi; - this.viNext = viNext; - this.oi = viNext - vi; - - // the coefficients of all polynomials in this layer - this.coeff_alpha = new short[this.oi][this.oi][this.vi]; - this.coeff_beta = new short[this.oi][this.vi][this.vi]; - this.coeff_gamma = new short[this.oi][this.viNext]; - this.coeff_eta = new short[this.oi]; - - int numOfPoly = this.oi; // number of polynomials per layer - - // Alpha coeffs - for (int k = 0; k < numOfPoly; k++) - { - for (int i = 0; i < this.oi; i++) - { - for (int j = 0; j < this.vi; j++) - { - coeff_alpha[k][i][j] = (short)(sr.nextInt() & GF2Field.MASK); - } - } - } - // Beta coeffs - for (int k = 0; k < numOfPoly; k++) - { - for (int i = 0; i < this.vi; i++) - { - for (int j = 0; j < this.vi; j++) - { - coeff_beta[k][i][j] = (short)(sr.nextInt() & GF2Field.MASK); - } - } - } - // Gamma coeffs - for (int k = 0; k < numOfPoly; k++) - { - for (int i = 0; i < this.viNext; i++) - { - coeff_gamma[k][i] = (short)(sr.nextInt() & GF2Field.MASK); - } - } - // Eta - for (int k = 0; k < numOfPoly; k++) - { - coeff_eta[k] = (short)(sr.nextInt() & GF2Field.MASK); - } - } - - /** - * This method plugs in the vinegar variables into the polynomials of this - * layer and computes the coefficients of the Oil-variables as well as the - * free coefficient in each polynomial. - *

    - * It is needed for computing the Oil variables while signing. - * - * @param x vinegar variables of this layer that should be plugged into - * the polynomials. - * @return coeff the coefficients of Oil variables and the free coeff in the - * polynomials of this layer. - */ - public short[][] plugInVinegars(short[] x) - { - // temporary variable needed for the multiplication - short tmpMult = 0; - // coeff: 1st index = which polynomial, 2nd index=which variable - short[][] coeff = new short[oi][oi + 1]; // gets returned - // free coefficient per polynomial - short[] sum = new short[oi]; - - /* - * evaluate the beta-part of the polynomials (it contains no oil - * variables) - */ - for (int k = 0; k < oi; k++) - { - for (int i = 0; i < vi; i++) - { - for (int j = 0; j < vi; j++) - { - // tmp = beta * xi (plug in) - tmpMult = GF2Field.multElem(coeff_beta[k][i][j], x[i]); - // tmp = tmp * xj - tmpMult = GF2Field.multElem(tmpMult, x[j]); - // accumulate into the array for the free coefficients. - sum[k] = GF2Field.addElem(sum[k], tmpMult); - } - } - } - - /* evaluate the alpha-part (it contains oils) */ - for (int k = 0; k < oi; k++) - { - for (int i = 0; i < oi; i++) - { - for (int j = 0; j < vi; j++) - { - // alpha * xj (plug in) - tmpMult = GF2Field.multElem(coeff_alpha[k][i][j], x[j]); - // accumulate - coeff[k][i] = GF2Field.addElem(coeff[k][i], tmpMult); - } - } - } - /* evaluate the gama-part of the polynomial (containing no oils) */ - for (int k = 0; k < oi; k++) - { - for (int i = 0; i < vi; i++) - { - // gamma * xi (plug in) - tmpMult = GF2Field.multElem(coeff_gamma[k][i], x[i]); - // accumulate in the array for the free coefficients (per - // polynomial). - sum[k] = GF2Field.addElem(sum[k], tmpMult); - } - } - /* evaluate the gama-part of the polynomial (but containing oils) */ - for (int k = 0; k < oi; k++) - { - for (int i = vi; i < viNext; i++) - { // oils - // accumulate the coefficients of the oil variables (per - // polynomial). - coeff[k][i - vi] = GF2Field.addElem(coeff_gamma[k][i], - coeff[k][i - vi]); - } - } - /* evaluate the eta-part of the polynomial */ - for (int k = 0; k < oi; k++) - { - // accumulate in the array for the free coefficients per polynomial. - sum[k] = GF2Field.addElem(sum[k], coeff_eta[k]); - } - - /* put the free coefficients (sum) into the coeff-array as last column */ - for (int k = 0; k < oi; k++) - { - coeff[k][oi] = sum[k]; - } - return coeff; - } - - /** - * Getter for the number of vinegar variables of this layer. - * - * @return the number of vinegar variables of this layer. - */ - public int getVi() - { - return vi; - } - - /** - * Getter for the number of vinegar variables of the next layer. - * - * @return the number of vinegar variables of the next layer. - */ - public int getViNext() - { - return viNext; - } - - /** - * Getter for the number of Oil variables of this layer. - * - * @return the number of oil variables of this layer. - */ - public int getOi() - { - return oi; - } - - /** - * Getter for the alpha-coefficients of the polynomials in this layer. - * - * @return the coefficients of alpha-terms of this layer. - */ - public short[][][] getCoeffAlpha() - { - return coeff_alpha; - } - - /** - * Getter for the beta-coefficients of the polynomials in this layer. - * - * @return the coefficients of beta-terms of this layer. - */ - - public short[][][] getCoeffBeta() - { - return coeff_beta; - } - - /** - * Getter for the gamma-coefficients of the polynomials in this layer. - * - * @return the coefficients of gamma-terms of this layer - */ - public short[][] getCoeffGamma() - { - return coeff_gamma; - } - - /** - * Getter for the eta-coefficients of the polynomials in this layer. - * - * @return the coefficients eta of this layer - */ - public short[] getCoeffEta() - { - return coeff_eta; - } - - /** - * This function compares this Layer with another object. - * - * @param other the other object - * @return the result of the comparison - */ - public boolean equals(Object other) - { - if (other == null || !(other instanceof Layer)) - { - return false; - } - Layer otherLayer = (Layer)other; - - return vi == otherLayer.getVi() - && viNext == otherLayer.getViNext() - && oi == otherLayer.getOi() - && RainbowUtil.equals(coeff_alpha, otherLayer.getCoeffAlpha()) - && RainbowUtil.equals(coeff_beta, otherLayer.getCoeffBeta()) - && RainbowUtil.equals(coeff_gamma, otherLayer.getCoeffGamma()) - && RainbowUtil.equals(coeff_eta, otherLayer.getCoeffEta()); - } - - public int hashCode() - { - int hash = vi; - hash = hash * 37 + viNext; - hash = hash * 37 + oi; - hash = hash * 37 + Arrays.hashCode(coeff_alpha); - hash = hash * 37 + Arrays.hashCode(coeff_beta); - hash = hash * 37 + Arrays.hashCode(coeff_gamma); - hash = hash * 37 + Arrays.hashCode(coeff_eta); - - return hash; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowKeyGenerationParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowKeyGenerationParameters.java deleted file mode 100644 index 6fac377c1f..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowKeyGenerationParameters.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.rainbow; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.KeyGenerationParameters; - -public class RainbowKeyGenerationParameters - extends KeyGenerationParameters -{ - private RainbowParameters params; - - public RainbowKeyGenerationParameters( - SecureRandom random, - RainbowParameters params) - { - // TODO: key size? - super(random, params.getVi()[params.getVi().length - 1] - params.getVi()[0]); - this.params = params; - } - - public RainbowParameters getParameters() - { - return params; - } -} - diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowKeyPairGenerator.java deleted file mode 100644 index b936c4b528..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowKeyPairGenerator.java +++ /dev/null @@ -1,418 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.rainbow; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; -import org.bouncycastle.crypto.CryptoServicesRegistrar; -import org.bouncycastle.crypto.KeyGenerationParameters; -import org.bouncycastle.pqc.legacy.crypto.rainbow.util.ComputeInField; -import org.bouncycastle.pqc.legacy.crypto.rainbow.util.GF2Field; - -/** - * This class implements AsymmetricCipherKeyPairGenerator. It is used - * as a generator for the private and public key of the Rainbow Signature - * Scheme. - *

    - * Detailed information about the key generation is to be found in the paper of - * Jintai Ding, Dieter Schmidt: Rainbow, a New Multivariable Polynomial - * Signature Scheme. ACNS 2005: 164-175 (https://dx.doi.org/10.1007/11496137_12) - */ -public class RainbowKeyPairGenerator - implements AsymmetricCipherKeyPairGenerator -{ - private boolean initialized = false; - private SecureRandom sr; - private RainbowKeyGenerationParameters rainbowParams; - - /* linear affine map L1: */ - private short[][] A1; // matrix of the lin. affine map L1(n-v1 x n-v1 matrix) - private short[][] A1inv; // inverted A1 - private short[] b1; // translation element of the lin.affine map L1 - - /* linear affine map L2: */ - private short[][] A2; // matrix of the lin. affine map (n x n matrix) - private short[][] A2inv; // inverted A2 - private short[] b2; // translation elemt of the lin.affine map L2 - - /* components of F: */ - private int numOfLayers; // u (number of sets S) - private Layer layers[]; // layers of polynomials of F - private int[] vi; // set of vinegar vars per layer. - - /* components of Public Key */ - private short[][] pub_quadratic; // quadratic(mixed) coefficients - private short[][] pub_singular; // singular coefficients - private short[] pub_scalar; // scalars - - // TODO - - /** - * The standard constructor tries to generate the Rainbow algorithm identifier - * with the corresponding OID. - */ - public RainbowKeyPairGenerator() - { - } - - - /** - * This function generates a Rainbow key pair. - * - * @return the generated key pair - */ - public AsymmetricCipherKeyPair genKeyPair() - { - RainbowPrivateKeyParameters privKey; - RainbowPublicKeyParameters pubKey; - - if (!initialized) - { - initializeDefault(); - } - - /* choose all coefficients at random */ - keygen(); - - /* now marshall them to PrivateKey */ - privKey = new RainbowPrivateKeyParameters(A1inv, b1, A2inv, b2, vi, layers); - - - /* marshall to PublicKey */ - pubKey = new RainbowPublicKeyParameters(vi[vi.length - 1] - vi[0], pub_quadratic, pub_singular, pub_scalar); - - return new AsymmetricCipherKeyPair(pubKey, privKey); - } - - // TODO - public void initialize( - KeyGenerationParameters param) - { - this.rainbowParams = (RainbowKeyGenerationParameters)param; - - // set source of randomness - this.sr = rainbowParams.getRandom(); - - // unmarshalling: - this.vi = this.rainbowParams.getParameters().getVi(); - this.numOfLayers = this.rainbowParams.getParameters().getNumOfLayers(); - - this.initialized = true; - } - - private void initializeDefault() - { - RainbowKeyGenerationParameters rbKGParams = new RainbowKeyGenerationParameters(CryptoServicesRegistrar.getSecureRandom(), new RainbowParameters()); - initialize(rbKGParams); - } - - /** - * This function calls the functions for the random generation of the coefficients - * and the matrices needed for the private key and the method for computing the public key. - */ - private void keygen() - { - generateL1(); - generateL2(); - generateF(); - computePublicKey(); - } - - /** - * This function generates the invertible affine linear map L1 = A1*x + b1 - *

    - * The translation part b1, is stored in a separate array. The inverse of - * the matrix-part of L1 A1inv is also computed here. - *

    - * This linear map hides the output of the map F. It is on k^(n-v1). - *

    - */ - private void generateL1() - { - - // dimension = n-v1 = vi[last] - vi[first] - int dim = vi[vi.length - 1] - vi[0]; - this.A1 = new short[dim][dim]; - this.A1inv = null; - ComputeInField c = new ComputeInField(); - - /* generation of A1 at random */ - while (A1inv == null) - { - for (int i = 0; i < dim; i++) - { - for (int j = 0; j < dim; j++) - { - A1[i][j] = (short)(sr.nextInt() & GF2Field.MASK); - } - } - A1inv = c.inverse(A1); - } - - /* generation of the translation vector at random */ - b1 = new short[dim]; - for (int i = 0; i < dim; i++) - { - b1[i] = (short)(sr.nextInt() & GF2Field.MASK); - } - } - - /** - * This function generates the invertible affine linear map L2 = A2*x + b2 - *

    - * The translation part b2, is stored in a separate array. The inverse of - * the matrix-part of L2 A2inv is also computed here. - *

    - * This linear map hides the output of the map F. It is on k^(n). - *

    - */ - private void generateL2() - { - - // dimension = n = vi[last] - int dim = vi[vi.length - 1]; - this.A2 = new short[dim][dim]; - this.A2inv = null; - ComputeInField c = new ComputeInField(); - - /* generation of A2 at random */ - while (this.A2inv == null) - { - for (int i = 0; i < dim; i++) - { - for (int j = 0; j < dim; j++) - { // one col extra for b - A2[i][j] = (short)(sr.nextInt() & GF2Field.MASK); - } - } - this.A2inv = c.inverse(A2); - } - /* generation of the translation vector at random */ - b2 = new short[dim]; - for (int i = 0; i < dim; i++) - { - b2[i] = (short)(sr.nextInt() & GF2Field.MASK); - } - - } - - /** - * This function generates the private map F, which consists of u-1 layers. - * Each layer consists of oi polynomials where oi = vi[i+1]-vi[i]. - *

    - * The methods for the generation of the coefficients of these polynomials - * are called here. - *

    - */ - private void generateF() - { - - this.layers = new Layer[this.numOfLayers]; - for (int i = 0; i < this.numOfLayers; i++) - { - layers[i] = new Layer(this.vi[i], this.vi[i + 1], sr); - } - } - - /** - * This function computes the public key from the private key. - *

    - * The composition of F with L2 is computed, followed by applying L1 to the - * composition's result. The singular and scalar values constitute to the - * public key as is, the quadratic terms are compacted in - * compactPublicKey() - *

    - */ - private void computePublicKey() - { - - ComputeInField c = new ComputeInField(); - int rows = this.vi[this.vi.length - 1] - this.vi[0]; - int vars = this.vi[this.vi.length - 1]; - // Fpub - short[][][] coeff_quadratic_3dim = new short[rows][vars][vars]; - this.pub_singular = new short[rows][vars]; - this.pub_scalar = new short[rows]; - - // Coefficients of layers of Private Key F - short[][][] coeff_alpha; - short[][][] coeff_beta; - short[][] coeff_gamma; - short[] coeff_eta; - - // Needed for counters; - int oils = 0; - int vins = 0; - int crnt_row = 0; // current row (polynomial) - - short vect_tmp[] = new short[vars]; // vector tmp; - short sclr_tmp = 0; - - // Composition of F and L2: Insert L2 = A2*x+b2 in F - for (int l = 0; l < this.layers.length; l++) - { - // get coefficients of current layer - coeff_alpha = this.layers[l].getCoeffAlpha(); - coeff_beta = this.layers[l].getCoeffBeta(); - coeff_gamma = this.layers[l].getCoeffGamma(); - coeff_eta = this.layers[l].getCoeffEta(); - oils = coeff_alpha[0].length;// this.layers[l].getOi(); - vins = coeff_beta[0].length;// this.layers[l].getVi(); - // compute polynomials of layer - for (int p = 0; p < oils; p++) - { - // multiply alphas - for (int x1 = 0; x1 < oils; x1++) - { - for (int x2 = 0; x2 < vins; x2++) - { - // multiply polynomial1 with polynomial2 - vect_tmp = c.multVect(coeff_alpha[p][x1][x2], - this.A2[x1 + vins]); - coeff_quadratic_3dim[crnt_row + p] = c.addSquareMatrix( - coeff_quadratic_3dim[crnt_row + p], c - .multVects(vect_tmp, this.A2[x2])); - // mul poly1 with scalar2 - vect_tmp = c.multVect(this.b2[x2], vect_tmp); - this.pub_singular[crnt_row + p] = c.addVect(vect_tmp, - this.pub_singular[crnt_row + p]); - // mul scalar1 with poly2 - vect_tmp = c.multVect(coeff_alpha[p][x1][x2], - this.A2[x2]); - vect_tmp = c.multVect(b2[x1 + vins], vect_tmp); - this.pub_singular[crnt_row + p] = c.addVect(vect_tmp, - this.pub_singular[crnt_row + p]); - // mul scalar1 with scalar2 - sclr_tmp = GF2Field.multElem(coeff_alpha[p][x1][x2], - this.b2[x1 + vins]); - this.pub_scalar[crnt_row + p] = GF2Field.addElem( - this.pub_scalar[crnt_row + p], GF2Field - .multElem(sclr_tmp, this.b2[x2])); - } - } - // multiply betas - for (int x1 = 0; x1 < vins; x1++) - { - for (int x2 = 0; x2 < vins; x2++) - { - // multiply polynomial1 with polynomial2 - vect_tmp = c.multVect(coeff_beta[p][x1][x2], - this.A2[x1]); - coeff_quadratic_3dim[crnt_row + p] = c.addSquareMatrix( - coeff_quadratic_3dim[crnt_row + p], c - .multVects(vect_tmp, this.A2[x2])); - // mul poly1 with scalar2 - vect_tmp = c.multVect(this.b2[x2], vect_tmp); - this.pub_singular[crnt_row + p] = c.addVect(vect_tmp, - this.pub_singular[crnt_row + p]); - // mul scalar1 with poly2 - vect_tmp = c.multVect(coeff_beta[p][x1][x2], - this.A2[x2]); - vect_tmp = c.multVect(this.b2[x1], vect_tmp); - this.pub_singular[crnt_row + p] = c.addVect(vect_tmp, - this.pub_singular[crnt_row + p]); - // mul scalar1 with scalar2 - sclr_tmp = GF2Field.multElem(coeff_beta[p][x1][x2], - this.b2[x1]); - this.pub_scalar[crnt_row + p] = GF2Field.addElem( - this.pub_scalar[crnt_row + p], GF2Field - .multElem(sclr_tmp, this.b2[x2])); - } - } - // multiply gammas - for (int n = 0; n < vins + oils; n++) - { - // mul poly with scalar - vect_tmp = c.multVect(coeff_gamma[p][n], this.A2[n]); - this.pub_singular[crnt_row + p] = c.addVect(vect_tmp, - this.pub_singular[crnt_row + p]); - // mul scalar with scalar - this.pub_scalar[crnt_row + p] = GF2Field.addElem( - this.pub_scalar[crnt_row + p], GF2Field.multElem( - coeff_gamma[p][n], this.b2[n])); - } - // add eta - this.pub_scalar[crnt_row + p] = GF2Field.addElem( - this.pub_scalar[crnt_row + p], coeff_eta[p]); - } - crnt_row = crnt_row + oils; - } - - // Apply L1 = A1*x+b1 to composition of F and L2 - { - // temporary coefficient arrays - short[][][] tmp_c_quad = new short[rows][vars][vars]; - short[][] tmp_c_sing = new short[rows][vars]; - short[] tmp_c_scal = new short[rows]; - for (int r = 0; r < rows; r++) - { - for (int q = 0; q < A1.length; q++) - { - tmp_c_quad[r] = c.addSquareMatrix(tmp_c_quad[r], c - .multMatrix(A1[r][q], coeff_quadratic_3dim[q])); - tmp_c_sing[r] = c.addVect(tmp_c_sing[r], c.multVect( - A1[r][q], this.pub_singular[q])); - tmp_c_scal[r] = GF2Field.addElem(tmp_c_scal[r], GF2Field - .multElem(A1[r][q], this.pub_scalar[q])); - } - tmp_c_scal[r] = GF2Field.addElem(tmp_c_scal[r], b1[r]); - } - // set public key - coeff_quadratic_3dim = tmp_c_quad; - this.pub_singular = tmp_c_sing; - this.pub_scalar = tmp_c_scal; - } - compactPublicKey(coeff_quadratic_3dim); - } - - /** - * The quadratic (or mixed) terms of the public key are compacted from a n x - * n matrix per polynomial to an upper diagonal matrix stored in one integer - * array of n (n + 1) / 2 elements per polynomial. The ordering of elements - * is lexicographic and the result is updating this.pub_quadratic, - * which stores the quadratic elements of the public key. - * - * @param coeff_quadratic_to_compact 3-dimensional array containing a n x n Matrix for each of the - * n - v1 polynomials - */ - private void compactPublicKey(short[][][] coeff_quadratic_to_compact) - { - int polynomials = coeff_quadratic_to_compact.length; - int n = coeff_quadratic_to_compact[0].length; - int entries = n * (n + 1) / 2;// the small gauss - this.pub_quadratic = new short[polynomials][entries]; - int offset = 0; - - for (int p = 0; p < polynomials; p++) - { - offset = 0; - for (int x = 0; x < n; x++) - { - for (int y = x; y < n; y++) - { - if (y == x) - { - this.pub_quadratic[p][offset] = coeff_quadratic_to_compact[p][x][y]; - } - else - { - this.pub_quadratic[p][offset] = GF2Field.addElem( - coeff_quadratic_to_compact[p][x][y], - coeff_quadratic_to_compact[p][y][x]); - } - offset++; - } - } - } - } - - public void init(KeyGenerationParameters param) - { - this.initialize(param); - } - - public AsymmetricCipherKeyPair generateKeyPair() - { - return genKeyPair(); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowKeyParameters.java deleted file mode 100644 index 5e164fa41b..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowKeyParameters.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.rainbow; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; - -public class RainbowKeyParameters - extends AsymmetricKeyParameter -{ - private int docLength; - - public RainbowKeyParameters( - boolean isPrivate, - int docLength) - { - super(isPrivate); - this.docLength = docLength; - } - - /** - * @return the docLength - */ - public int getDocLength() - { - return this.docLength; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowParameters.java deleted file mode 100644 index 3872ded350..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowParameters.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.rainbow; - -import org.bouncycastle.crypto.CipherParameters; - -public class RainbowParameters - implements CipherParameters -{ - - /** - * DEFAULT PARAMS - */ - /* - * Vi = vinegars per layer whereas n is vu (vu = 33 = n) such that - * - * v1 = 6; o1 = 12-6 = 6 - * - * v2 = 12; o2 = 17-12 = 5 - * - * v3 = 17; o3 = 22-17 = 5 - * - * v4 = 22; o4 = 33-22 = 11 - * - * v5 = 33; (o5 = 0) - */ - private final int[] DEFAULT_VI = {6, 12, 17, 22, 33}; - - private int[] vi;// set of vinegar vars per layer. - - /** - * Default Constructor The elements of the array containing the number of - * Vinegar variables in each layer are set to the default values here. - */ - public RainbowParameters() - { - this.vi = this.DEFAULT_VI; - } - - /** - * Constructor with parameters - * - * @param vi The elements of the array containing the number of Vinegar - * variables per layer are set to the values of the input array. - */ - public RainbowParameters(int[] vi) - { - this.vi = vi; - - checkParams(); - } - - private void checkParams() - { - if (vi == null) - { - throw new IllegalArgumentException("no layers defined."); - } - if (vi.length > 1) - { - for (int i = 0; i < vi.length - 1; i++) - { - if (vi[i] >= vi[i + 1]) - { - throw new IllegalArgumentException( - "v[i] has to be smaller than v[i+1]"); - } - } - } - else - { - throw new IllegalArgumentException( - "Rainbow needs at least 1 layer, such that v1 < v2."); - } - } - - /** - * Getter for the number of layers - * - * @return the number of layers - */ - public int getNumOfLayers() - { - return this.vi.length - 1; - } - - /** - * Getter for the number of all the polynomials in Rainbow - * - * @return the number of the polynomials - */ - public int getDocLength() - { - return vi[vi.length - 1] - vi[0]; - } - - /** - * Getter for the array containing the number of Vinegar-variables per layer - * - * @return the numbers of vinegars per layer - */ - public int[] getVi() - { - return this.vi; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowPrivateKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowPrivateKeyParameters.java deleted file mode 100644 index 90d4b3459f..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowPrivateKeyParameters.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.rainbow; - -public class RainbowPrivateKeyParameters - extends RainbowKeyParameters -{ - /** - * Constructor - * - * @param A1inv the inverse of A1(the matrix part of the affine linear map L1) - * (n-v1 x n-v1 matrix) - * @param b1 translation vector, part of the linear affine map L1 - * @param A2inv the inverse of A2(the matrix part of the affine linear map L2) - * (n x n matrix) - * @param b2 translation vector, part of the linear affine map L2 - * @param vi the number of Vinegar-variables per layer - * @param layers the polynomials with their coefficients of private map F - */ - public RainbowPrivateKeyParameters(short[][] A1inv, short[] b1, - short[][] A2inv, short[] b2, int[] vi, Layer[] layers) - { - super(true, vi[vi.length - 1] - vi[0]); - - this.A1inv = A1inv; - this.b1 = b1; - this.A2inv = A2inv; - this.b2 = b2; - this.vi = vi; - this.layers = layers; - } - - /* - * invertible affine linear map L1 - */ - // the inverse of A1, (n-v1 x n-v1 matrix) - private short[][] A1inv; - - // translation vector of L1 - private short[] b1; - - /* - * invertible affine linear map L2 - */ - // the inverse of A2, (n x n matrix) - private short[][] A2inv; - - // translation vector of L2 - private short[] b2; - - /* - * components of F - */ - // the number of Vinegar-variables per layer. - private int[] vi; - - // contains the polynomials with their coefficients of private map F - private Layer[] layers; - - /** - * Getter for the translation part of the private quadratic map L1. - * - * @return b1 the translation part of L1 - */ - public short[] getB1() - { - return this.b1; - } - - /** - * Getter for the inverse matrix of A1. - * - * @return the A1inv inverse - */ - public short[][] getInvA1() - { - return this.A1inv; - } - - /** - * Getter for the translation part of the private quadratic map L2. - * - * @return b2 the translation part of L2 - */ - public short[] getB2() - { - return this.b2; - } - - /** - * Getter for the inverse matrix of A2 - * - * @return the A2inv - */ - public short[][] getInvA2() - { - return this.A2inv; - } - - /** - * Returns the layers contained in the private key - * - * @return layers - */ - public Layer[] getLayers() - { - return this.layers; - } - - /** - * /** Returns the array of vi-s - * - * @return the vi - */ - public int[] getVi() - { - return vi; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowPublicKeyParameters.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowPublicKeyParameters.java deleted file mode 100644 index baff2225f7..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowPublicKeyParameters.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.rainbow; - -public class RainbowPublicKeyParameters - extends RainbowKeyParameters -{ - private short[][] coeffquadratic; - private short[][] coeffsingular; - private short[] coeffscalar; - - /** - * Constructor - * - * @param docLength - * @param coeffQuadratic - * @param coeffSingular - * @param coeffScalar - */ - public RainbowPublicKeyParameters(int docLength, - short[][] coeffQuadratic, short[][] coeffSingular, - short[] coeffScalar) - { - super(false, docLength); - - this.coeffquadratic = coeffQuadratic; - this.coeffsingular = coeffSingular; - this.coeffscalar = coeffScalar; - - } - - /** - * @return the coeffquadratic - */ - public short[][] getCoeffQuadratic() - { - return coeffquadratic; - } - - /** - * @return the coeffsingular - */ - public short[][] getCoeffSingular() - { - return coeffsingular; - } - - /** - * @return the coeffscalar - */ - public short[] getCoeffScalar() - { - return coeffscalar; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowSigner.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowSigner.java deleted file mode 100644 index 05e522503b..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/RainbowSigner.java +++ /dev/null @@ -1,311 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.rainbow; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.crypto.CryptoServicesRegistrar; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.MessageSigner; -import org.bouncycastle.pqc.legacy.crypto.rainbow.util.ComputeInField; -import org.bouncycastle.pqc.legacy.crypto.rainbow.util.GF2Field; - -/** - * It implements the sign and verify functions for the Rainbow Signature Scheme. - * Here the message, which has to be signed, is updated. The use of - * different hash functions is possible. - *

    - * Detailed information about the signature and the verify-method is to be found - * in the paper of Jintai Ding, Dieter Schmidt: Rainbow, a New Multivariable - * Polynomial Signature Scheme. ACNS 2005: 164-175 - * (https://dx.doi.org/10.1007/11496137_12) - */ -public class RainbowSigner - implements MessageSigner -{ - private static final int MAXITS = 65536; - - // Source of randomness - private SecureRandom random; - - // The length of a document that can be signed with the privKey - int signableDocumentLength; - - // Container for the oil and vinegar variables of all the layers - private short[] x; - - private ComputeInField cf = new ComputeInField(); - - RainbowKeyParameters key; - - public void init(boolean forSigning, - CipherParameters param) - { - if (forSigning) - { - if (param instanceof ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; - - this.random = rParam.getRandom(); - this.key = (RainbowPrivateKeyParameters)rParam.getParameters(); - - } - else - { - - this.random = CryptoServicesRegistrar.getSecureRandom(); - this.key = (RainbowPrivateKeyParameters)param; - } - } - else - { - this.key = (RainbowPublicKeyParameters)param; - } - - this.signableDocumentLength = this.key.getDocLength(); - } - - - /** - * initial operations before solving the Linear equation system. - * - * @param layer the current layer for which a LES is to be solved. - * @param msg the message that should be signed. - * @return Y_ the modified document needed for solving LES, (Y_ = - * A1^{-1}*(Y-b1)) linear map L1 = A1 x + b1. - */ - private short[] initSign(Layer[] layer, short[] msg) - { - - /* preparation: Modifies the document with the inverse of L1 */ - // tmp = Y - b1: - short[] tmpVec = new short[msg.length]; - - tmpVec = cf.addVect(((RainbowPrivateKeyParameters)this.key).getB1(), msg); - - // Y_ = A1^{-1} * (Y - b1) : - short[] Y_ = cf.multiplyMatrix(((RainbowPrivateKeyParameters)this.key).getInvA1(), tmpVec); - - /* generates the vinegar vars of the first layer at random */ - for (int i = 0; i < layer[0].getVi(); i++) - { - x[i] = (short)random.nextInt(); - x[i] = (short)(x[i] & GF2Field.MASK); - } - - return Y_; - } - - /** - * This function signs the message that has been updated, making use of the - * private key. - *

    - * For computing the signature, L1 and L2 are needed, as well as LES should - * be solved for each layer in order to find the Oil-variables in the layer. - *

    - * The Vinegar-variables of the first layer are random generated. - * - * @param message the message - * @return the signature of the message. - */ - public byte[] generateSignature(byte[] message) - { - Layer[] layer = ((RainbowPrivateKeyParameters)this.key).getLayers(); - int numberOfLayers = layer.length; - - x = new short[((RainbowPrivateKeyParameters)this.key).getInvA2().length]; // all variables - - short[] Y_; // modified document - short[] y_i; // part of Y_ each polynomial - int counter; // index of the current part of the doc - - short[] solVec; // the solution of LES pro layer - short[] tmpVec; - - // the signature as an array of shorts: - short[] signature; - // the signature as a byte-array: - byte[] S = new byte[layer[numberOfLayers - 1].getViNext()]; - - short[] msgHashVals = makeMessageRepresentative(message); - int itCount = 0; - - // shows if an exception is caught - boolean ok; - do - { - ok = true; - counter = 0; - try - { - Y_ = initSign(layer, msgHashVals); - - for (int i = 0; i < numberOfLayers; i++) - { - - y_i = new short[layer[i].getOi()]; - solVec = new short[layer[i].getOi()]; // solution of LES - - /* copy oi elements of Y_ into y_i */ - for (int k = 0; k < layer[i].getOi(); k++) - { - y_i[k] = Y_[counter]; - counter++; // current index of Y_ - } - - /* - * plug in the vars of the previous layer in order to get - * the vars of the current layer - */ - solVec = cf.solveEquation(layer[i].plugInVinegars(x), y_i); - - if (solVec == null) - { // LES is not solveable - throw new Exception("LES is not solveable!"); - } - - /* copy the new vars into the x-array */ - for (int j = 0; j < solVec.length; j++) - { - x[layer[i].getVi() + j] = solVec[j]; - } - } - - /* apply the inverse of L2: (signature = A2^{-1}*(b2+x)) */ - tmpVec = cf.addVect(((RainbowPrivateKeyParameters)this.key).getB2(), x); - signature = cf.multiplyMatrix(((RainbowPrivateKeyParameters)this.key).getInvA2(), tmpVec); - - /* cast signature from short[] to byte[] */ - for (int i = 0; i < S.length; i++) - { - S[i] = ((byte)signature[i]); - } - } - catch (Exception se) - { - // if one of the LESs was not solveable - sign again - ok = false; - } - } - while (!ok && ++itCount < MAXITS); - /* return the signature in bytes */ - - if (itCount == MAXITS) - { - throw new IllegalStateException("unable to generate signature - LES not solvable"); - } - - return S; - } - - /** - * This function verifies the signature of the message that has been - * updated, with the aid of the public key. - * - * @param message the message - * @param signature the signature of the message - * @return true if the signature has been verified, false otherwise. - */ - public boolean verifySignature(byte[] message, byte[] signature) - { - short[] sigInt = new short[signature.length]; - short tmp; - - for (int i = 0; i < signature.length; i++) - { - tmp = (short)signature[i]; - tmp &= (short)0xff; - sigInt[i] = tmp; - } - - short[] msgHashVal = makeMessageRepresentative(message); - - // verify - short[] verificationResult = verifySignatureIntern(sigInt); - - // compare - boolean verified = true; - if (msgHashVal.length != verificationResult.length) - { - return false; - } - for (int i = 0; i < msgHashVal.length; i++) - { - verified = verified && msgHashVal[i] == verificationResult[i]; - } - - return verified; - } - - /** - * Signature verification using public key - * - * @param signature vector of dimension n - * @return document hash of length n - v1 - */ - private short[] verifySignatureIntern(short[] signature) - { - - short[][] coeff_quadratic = ((RainbowPublicKeyParameters)this.key).getCoeffQuadratic(); - short[][] coeff_singular = ((RainbowPublicKeyParameters)this.key).getCoeffSingular(); - short[] coeff_scalar = ((RainbowPublicKeyParameters)this.key).getCoeffScalar(); - - short[] rslt = new short[coeff_quadratic.length];// n - v1 - int n = coeff_singular[0].length; - int offset = 0; // array position - short tmp = 0; // for scalar - - for (int p = 0; p < coeff_quadratic.length; p++) - { // no of polynomials - offset = 0; - for (int x = 0; x < n; x++) - { - // calculate quadratic terms - for (int y = x; y < n; y++) - { - tmp = GF2Field.multElem(coeff_quadratic[p][offset], - GF2Field.multElem(signature[x], signature[y])); - rslt[p] = GF2Field.addElem(rslt[p], tmp); - offset++; - } - // calculate singular terms - tmp = GF2Field.multElem(coeff_singular[p][x], signature[x]); - rslt[p] = GF2Field.addElem(rslt[p], tmp); - } - // add scalar - rslt[p] = GF2Field.addElem(rslt[p], coeff_scalar[p]); - } - - return rslt; - } - - /** - * This function creates the representative of the message which gets signed - * or verified. - * - * @param message the message - * @return message representative - */ - private short[] makeMessageRepresentative(byte[] message) - { - // the message representative - short[] output = new short[this.signableDocumentLength]; - - int h = 0; - int i = 0; - do - { - if (i >= message.length) - { - break; - } - output[i] = (short)message[h]; - output[i] &= (short)0xff; - h++; - i++; - } - while (i < output.length); - - return output; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/util/ComputeInField.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/util/ComputeInField.java deleted file mode 100644 index 181a6c4967..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/util/ComputeInField.java +++ /dev/null @@ -1,493 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.rainbow.util; - -/** - * This class offers different operations on matrices in field GF2^8. - *

    - * Implemented are functions: - * - finding inverse of a matrix - * - solving linear equation systems using the Gauss-Elimination method - * - basic operations like matrix multiplication, addition and so on. - */ - -public class ComputeInField -{ - - private short[][] A; // used by solveEquation and inverse - short[] x; - - /** - * Constructor with no parameters - */ - public ComputeInField() - { - } - - - /** - * This function finds a solution of the equation Bx = b. - * Exception is thrown if the linear equation system has no solution - * - * @param B this matrix is the left part of the - * equation (B in the equation above) - * @param b the right part of the equation - * (b in the equation above) - * @return x the solution of the equation if it is solvable - * null otherwise - * @throws RuntimeException if LES is not solvable - */ - public short[] solveEquation(short[][] B, short[] b) - { - if (B.length != b.length) - { - return null; // not solvable in this form - } - - try - { - - - // initialize - // this matrix stores B and b from the equation B*x = b - // b is stored as the last column. - // B contains one column more than rows. - // In this column we store a free coefficient that should be later subtracted from b - A = new short[B.length][B.length + 1]; - // stores the solution of the LES - x = new short[B.length]; - - // copy B into the global matrix A - for (int i = 0; i < B.length; i++) - { // rows - for (int j = 0; j < B[0].length; j++) - { // cols - A[i][j] = B[i][j]; - } - } - - // copy the vector b into the global A - //the free coefficient, stored in the last column of A( A[i][b.length] - // is to be subtracted from b - for (int i = 0; i < b.length; i++) - { - A[i][b.length] = GF2Field.addElem(b[i], A[i][b.length]); - } - - // call the methods for gauss elimination and backward substitution - computeZerosUnder(false); // obtain zeros under the diagonal - substitute(); - - return x; - - } - catch (RuntimeException rte) - { - return null; // the LES is not solvable! - } - } - - /** - * This function computes the inverse of a given matrix using the Gauss- - * Elimination method. - *

    - * An exception is thrown if the matrix has no inverse - * - * @param coef the matrix which inverse matrix is needed - * @return inverse matrix of the input matrix. - * If the matrix is singular, null is returned. - * @throws RuntimeException if the given matrix is not invertible - */ - public short[][] inverse(short[][] coef) - { - try - { - // Initialization: - short factor; - short[][] inverse; - A = new short[coef.length][2 * coef.length]; - if (coef.length != coef[0].length) - { - throw new RuntimeException( - "The matrix is not invertible. Please choose another one!"); - } - - // prepare: Copy coef and the identity matrix into the global A. - for (int i = 0; i < coef.length; i++) - { - for (int j = 0; j < coef.length; j++) - { - //copy the input matrix coef into A - A[i][j] = coef[i][j]; - } - // copy the identity matrix into A. - for (int j = coef.length; j < 2 * coef.length; j++) - { - A[i][j] = 0; - } - A[i][i + A.length] = 1; - } - - // Elimination operations to get the identity matrix from the left side of A. - // modify A to get 0s under the diagonal. - computeZerosUnder(true); - - // modify A to get only 1s on the diagonal: A[i][j] =A[i][j]/A[i][i]. - for (int i = 0; i < A.length; i++) - { - factor = GF2Field.invElem(A[i][i]); - for (int j = i; j < 2 * A.length; j++) - { - A[i][j] = GF2Field.multElem(A[i][j], factor); - } - } - - //modify A to get only 0s above the diagonal. - computeZerosAbove(); - - // copy the result (the second half of A) in the matrix inverse. - inverse = new short[A.length][A.length]; - for (int i = 0; i < A.length; i++) - { - for (int j = A.length; j < 2 * A.length; j++) - { - inverse[i][j - A.length] = A[i][j]; - } - } - return inverse; - - } - catch (RuntimeException rte) - { - // The matrix is not invertible! A new one should be generated! - return null; - } - } - - /** - * Elimination under the diagonal. - * This function changes a matrix so that it contains only zeros under the - * diagonal(Ai,i) using only Gauss-Elimination operations. - *

    - * It is used in solveEquaton as well as in the function for - * finding an inverse of a matrix: {@link}inverse. Both of them use the - * Gauss-Elimination Method. - *

    - * The result is stored in the global matrix A - *

    - * - * @param usedForInverse This parameter shows if the function is used by the - * solveEquation-function or by the inverse-function and according - * to this creates matrices of different sizes. - * @throws RuntimeException in case a multiplicative inverse of 0 is needed - */ - private void computeZerosUnder(boolean usedForInverse) - throws RuntimeException - { - - //the number of columns in the global A where the tmp results are stored - int length; - short tmp = 0; - - //the function is used in inverse() - A should have 2 times more columns than rows - if (usedForInverse) - { - length = 2 * A.length; - } - //the function is used in solveEquation - A has 1 column more than rows - else - { - length = A.length + 1; - } - - //elimination operations to modify A so that that it contains only 0s under the diagonal - for (int k = 0; k < A.length - 1; k++) - { // the fixed row - for (int i = k + 1; i < A.length; i++) - { // rows - short factor1 = A[i][k]; - short factor2 = GF2Field.invElem(A[k][k]); - - //The element which multiplicative inverse is needed, is 0 - //in this case is the input matrix not invertible - if (factor2 == 0) - { - throw new IllegalStateException("Matrix not invertible! We have to choose another one!"); - } - - for (int j = k; j < length; j++) - {// columns - // tmp=A[k,j] / A[k,k] - tmp = GF2Field.multElem(A[k][j], factor2); - // tmp = A[i,k] * A[k,j] / A[k,k] - tmp = GF2Field.multElem(factor1, tmp); - // A[i,j]=A[i,j]-A[i,k]/A[k,k]*A[k,j]; - A[i][j] = GF2Field.addElem(A[i][j], tmp); - } - } - } - } - - /** - * Elimination above the diagonal. - * This function changes a matrix so that it contains only zeros above the - * diagonal(Ai,i) using only Gauss-Elimination operations. - *

    - * It is used in the inverse-function - * The result is stored in the global matrix A - *

    - * - * @throws RuntimeException in case a multiplicative inverse of 0 is needed - */ - private void computeZerosAbove() - throws RuntimeException - { - short tmp = 0; - for (int k = A.length - 1; k > 0; k--) - { // the fixed row - for (int i = k - 1; i >= 0; i--) - { // rows - short factor1 = A[i][k]; - short factor2 = GF2Field.invElem(A[k][k]); - if (factor2 == 0) - { - throw new RuntimeException("The matrix is not invertible"); - } - for (int j = k; j < 2 * A.length; j++) - { // columns - // tmp = A[k,j] / A[k,k] - tmp = GF2Field.multElem(A[k][j], factor2); - // tmp = A[i,k] * A[k,j] / A[k,k] - tmp = GF2Field.multElem(factor1, tmp); - // A[i,j] = A[i,j] - A[i,k] / A[k,k] * A[k,j]; - A[i][j] = GF2Field.addElem(A[i][j], tmp); - } - } - } - } - - - /** - * This function uses backward substitution to find x - * of the linear equation system (LES) B*x = b, - * where A a triangle-matrix is (contains only zeros under the diagonal) - * and b is a vector - *

    - * If the multiplicative inverse of 0 is needed, an exception is thrown. - * In this case is the LES not solvable - *

    - * - * @throws RuntimeException in case a multiplicative inverse of 0 is needed - */ - private void substitute() - throws IllegalStateException - { - - // for the temporary results of the operations in field - short tmp, temp; - - temp = GF2Field.invElem(A[A.length - 1][A.length - 1]); - if (temp == 0) - { - throw new IllegalStateException("The equation system is not solvable"); - } - - // backward substitution - x[A.length - 1] = GF2Field.multElem(A[A.length - 1][A.length], temp); - for (int i = A.length - 2; i >= 0; i--) - { - tmp = A[i][A.length]; - for (int j = A.length - 1; j > i; j--) - { - temp = GF2Field.multElem(A[i][j], x[j]); - tmp = GF2Field.addElem(tmp, temp); - } - - temp = GF2Field.invElem(A[i][i]); - if (temp == 0) - { - throw new IllegalStateException("Not solvable equation system"); - } - x[i] = GF2Field.multElem(tmp, temp); - } - } - - - /** - * This function multiplies two given matrices. - * If the given matrices cannot be multiplied due - * to different sizes, an exception is thrown. - * - * @param M1 -the 1st matrix - * @param M2 -the 2nd matrix - * @return A = M1*M2 - * @throws RuntimeException in case the given matrices cannot be multiplied - * due to different dimensions. - */ - public short[][] multiplyMatrix(short[][] M1, short[][] M2) - throws RuntimeException - { - - if (M1[0].length != M2.length) - { - throw new RuntimeException("Multiplication is not possible!"); - } - short tmp = 0; - A = new short[M1.length][M2[0].length]; - for (int i = 0; i < M1.length; i++) - { - for (int j = 0; j < M2.length; j++) - { - for (int k = 0; k < M2[0].length; k++) - { - tmp = GF2Field.multElem(M1[i][j], M2[j][k]); - A[i][k] = GF2Field.addElem(A[i][k], tmp); - } - } - } - return A; - } - - /** - * This function multiplies a given matrix with a one-dimensional array. - *

    - * An exception is thrown, if the number of columns in the matrix and - * the number of rows in the one-dim. array differ. - * - * @param M1 the matrix to be multiplied - * @param m the one-dimensional array to be multiplied - * @return M1*m - * @throws RuntimeException in case of dimension inconsistency - */ - public short[] multiplyMatrix(short[][] M1, short[] m) - throws RuntimeException - { - if (M1[0].length != m.length) - { - throw new RuntimeException("Multiplication is not possible!"); - } - short tmp = 0; - short[] B = new short[M1.length]; - for (int i = 0; i < M1.length; i++) - { - for (int j = 0; j < m.length; j++) - { - tmp = GF2Field.multElem(M1[i][j], m[j]); - B[i] = GF2Field.addElem(B[i], tmp); - } - } - return B; - } - - /** - * Addition of two vectors - * - * @param vector1 first summand, always of dim n - * @param vector2 second summand, always of dim n - * @return addition of vector1 and vector2 - * @throws RuntimeException in case the addition is impossible - * due to inconsistency in the dimensions - */ - public short[] addVect(short[] vector1, short[] vector2) - { - if (vector1.length != vector2.length) - { - throw new RuntimeException("Multiplication is not possible!"); - } - short rslt[] = new short[vector1.length]; - for (int n = 0; n < rslt.length; n++) - { - rslt[n] = GF2Field.addElem(vector1[n], vector2[n]); - } - return rslt; - } - - /** - * Multiplication of column vector with row vector - * - * @param vector1 column vector, always n x 1 - * @param vector2 row vector, always 1 x n - * @return resulting n x n matrix of multiplication - * @throws RuntimeException in case the multiplication is impossible due to - * inconsistency in the dimensions - */ - public short[][] multVects(short[] vector1, short[] vector2) - { - if (vector1.length != vector2.length) - { - throw new RuntimeException("Multiplication is not possible!"); - } - short rslt[][] = new short[vector1.length][vector2.length]; - for (int i = 0; i < vector1.length; i++) - { - for (int j = 0; j < vector2.length; j++) - { - rslt[i][j] = GF2Field.multElem(vector1[i], vector2[j]); - } - } - return rslt; - } - - /** - * Multiplies vector with scalar - * - * @param scalar galois element to multiply vector with - * @param vector vector to be multiplied - * @return vector multiplied with scalar - */ - public short[] multVect(short scalar, short[] vector) - { - short rslt[] = new short[vector.length]; - for (int n = 0; n < rslt.length; n++) - { - rslt[n] = GF2Field.multElem(scalar, vector[n]); - } - return rslt; - } - - /** - * Multiplies matrix with scalar - * - * @param scalar galois element to multiply matrix with - * @param matrix 2-dim n x n matrix to be multiplied - * @return matrix multiplied with scalar - */ - public short[][] multMatrix(short scalar, short[][] matrix) - { - short[][] rslt = new short[matrix.length][matrix[0].length]; - for (int i = 0; i < matrix.length; i++) - { - for (int j = 0; j < matrix[0].length; j++) - { - rslt[i][j] = GF2Field.multElem(scalar, matrix[i][j]); - } - } - return rslt; - } - - /** - * Adds the n x n matrices matrix1 and matrix2 - * - * @param matrix1 first summand - * @param matrix2 second summand - * @return addition of matrix1 and matrix2; both having the dimensions n x n - * @throws RuntimeException in case the addition is not possible because of - * different dimensions of the matrices - */ - public short[][] addSquareMatrix(short[][] matrix1, short[][] matrix2) - { - if (matrix1.length != matrix2.length || matrix1[0].length != matrix2[0].length) - { - throw new RuntimeException("Addition is not possible!"); - } - - short[][] rslt = new short[matrix1.length][matrix1.length];// - for (int i = 0; i < matrix1.length; i++) - { - for (int j = 0; j < matrix2.length; j++) - { - rslt[i][j] = GF2Field.addElem(matrix1[i][j], matrix2[i][j]); - } - } - return rslt; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/util/GF2Field.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/util/GF2Field.java deleted file mode 100644 index 2016cb7fc6..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/util/GF2Field.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.rainbow.util; - -/** - * This class provides the basic operations like addition, multiplication and - * finding the multiplicative inverse of an element in GF2^8. - *

    - * The operations are implemented using the irreducible polynomial - * 1+x^2+x^3+x^6+x^8 ( 1 0100 1101 = 0x14d ) - *

    - * This class makes use of lookup tables(exps and logs) for implementing the - * operations in order to increase the efficiency of Rainbow. - */ -public class GF2Field -{ - - public static final int MASK = 0xff; - - /* - * this lookup table is needed for multiplication and computing the - * multiplicative inverse - */ - static final short exps[] = {1, 2, 4, 8, 16, 32, 64, 128, 77, 154, 121, 242, - 169, 31, 62, 124, 248, 189, 55, 110, 220, 245, 167, 3, 6, 12, 24, - 48, 96, 192, 205, 215, 227, 139, 91, 182, 33, 66, 132, 69, 138, 89, - 178, 41, 82, 164, 5, 10, 20, 40, 80, 160, 13, 26, 52, 104, 208, - 237, 151, 99, 198, 193, 207, 211, 235, 155, 123, 246, 161, 15, 30, - 60, 120, 240, 173, 23, 46, 92, 184, 61, 122, 244, 165, 7, 14, 28, - 56, 112, 224, 141, 87, 174, 17, 34, 68, 136, 93, 186, 57, 114, 228, - 133, 71, 142, 81, 162, 9, 18, 36, 72, 144, 109, 218, 249, 191, 51, - 102, 204, 213, 231, 131, 75, 150, 97, 194, 201, 223, 243, 171, 27, - 54, 108, 216, 253, 183, 35, 70, 140, 85, 170, 25, 50, 100, 200, - 221, 247, 163, 11, 22, 44, 88, 176, 45, 90, 180, 37, 74, 148, 101, - 202, 217, 255, 179, 43, 86, 172, 21, 42, 84, 168, 29, 58, 116, 232, - 157, 119, 238, 145, 111, 222, 241, 175, 19, 38, 76, 152, 125, 250, - 185, 63, 126, 252, 181, 39, 78, 156, 117, 234, 153, 127, 254, 177, - 47, 94, 188, 53, 106, 212, 229, 135, 67, 134, 65, 130, 73, 146, - 105, 210, 233, 159, 115, 230, 129, 79, 158, 113, 226, 137, 95, 190, - 49, 98, 196, 197, 199, 195, 203, 219, 251, 187, 59, 118, 236, 149, - 103, 206, 209, 239, 147, 107, 214, 225, 143, 83, 166, 1}; - - /* - * this lookup table is needed for multiplication and computing the - * multiplicative inverse - */ - static final short logs[] = {0, 0, 1, 23, 2, 46, 24, 83, 3, 106, 47, 147, - 25, 52, 84, 69, 4, 92, 107, 182, 48, 166, 148, 75, 26, 140, 53, - 129, 85, 170, 70, 13, 5, 36, 93, 135, 108, 155, 183, 193, 49, 43, - 167, 163, 149, 152, 76, 202, 27, 230, 141, 115, 54, 205, 130, 18, - 86, 98, 171, 240, 71, 79, 14, 189, 6, 212, 37, 210, 94, 39, 136, - 102, 109, 214, 156, 121, 184, 8, 194, 223, 50, 104, 44, 253, 168, - 138, 164, 90, 150, 41, 153, 34, 77, 96, 203, 228, 28, 123, 231, 59, - 142, 158, 116, 244, 55, 216, 206, 249, 131, 111, 19, 178, 87, 225, - 99, 220, 172, 196, 241, 175, 72, 10, 80, 66, 15, 186, 190, 199, 7, - 222, 213, 120, 38, 101, 211, 209, 95, 227, 40, 33, 137, 89, 103, - 252, 110, 177, 215, 248, 157, 243, 122, 58, 185, 198, 9, 65, 195, - 174, 224, 219, 51, 68, 105, 146, 45, 82, 254, 22, 169, 12, 139, - 128, 165, 74, 91, 181, 151, 201, 42, 162, 154, 192, 35, 134, 78, - 188, 97, 239, 204, 17, 229, 114, 29, 61, 124, 235, 232, 233, 60, - 234, 143, 125, 159, 236, 117, 30, 245, 62, 56, 246, 217, 63, 207, - 118, 250, 31, 132, 160, 112, 237, 20, 144, 179, 126, 88, 251, 226, - 32, 100, 208, 221, 119, 173, 218, 197, 64, 242, 57, 176, 247, 73, - 180, 11, 127, 81, 21, 67, 145, 16, 113, 187, 238, 191, 133, 200, - 161}; - - /** - * This function calculates the sum of two elements as an operation in GF2^8 - * - * @param x the first element that is to be added - * @param y the second element that should be add - * @return the sum of the two elements x and y in GF2^8 - */ - public static short addElem(short x, short y) - { - return (short)(x ^ y); - } - - /** - * This function computes the multiplicative inverse of a given element in - * GF2^8 The 0 has no multiplicative inverse and in this case 0 is returned. - * - * @param x the element which multiplicative inverse is to be computed - * @return the multiplicative inverse of the given element, in case it - * exists or 0, otherwise - */ - public static short invElem(short x) - { - if (x == 0) - { - return 0; - } - return (exps[255 - logs[x]]); - } - - /** - * This function multiplies two elements in GF2^8. If one of the two - * elements is 0, 0 is returned. - * - * @param x the first element to be multiplied. - * @param y the second element to be multiplied. - * @return the product of the two input elements in GF2^8. - */ - public static short multElem(short x, short y) - { - if (x == 0 || y == 0) - { - return 0; - } - else - { - return (exps[(logs[x] + logs[y]) % 255]); - } - } - - /** - * This function returns the values of exps-lookup table which correspond to - * the input - * - * @param x the index in the lookup table exps - * @return exps-value, corresponding to the input - */ - public static short getExp(short x) - { - return exps[x]; - } - - /** - * This function returns the values of logs-lookup table which correspond to - * the input - * - * @param x the index in the lookup table logs - * @return logs-value, corresponding to the input - */ - public static short getLog(short x) - { - return logs[x]; - } - - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/util/RainbowUtil.java b/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/util/RainbowUtil.java deleted file mode 100644 index da65aa6301..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/crypto/rainbow/util/RainbowUtil.java +++ /dev/null @@ -1,230 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.rainbow.util; - -/** - * This class is needed for the conversions while encoding and decoding, as well as for - * comparison between arrays of some dimensions - */ -public class RainbowUtil -{ - - /** - * This function converts an one-dimensional array of bytes into a - * one-dimensional array of int - * - * @param in the array to be converted - * @return out - * the one-dimensional int-array that corresponds the input - */ - public static int[] convertArraytoInt(byte[] in) - { - int[] out = new int[in.length]; - for (int i = 0; i < in.length; i++) - { - out[i] = in[i] & GF2Field.MASK; - } - return out; - } - - /** - * This function converts an one-dimensional array of bytes into a - * one-dimensional array of type short - * - * @param in the array to be converted - * @return out - * one-dimensional short-array that corresponds the input - */ - public static short[] convertArray(byte[] in) - { - short[] out = new short[in.length]; - for (int i = 0; i < in.length; i++) - { - out[i] = (short)(in[i] & GF2Field.MASK); - } - return out; - } - - /** - * This function converts a matrix of bytes into a matrix of type short - * - * @param in the matrix to be converted - * @return out - * short-matrix that corresponds the input - */ - public static short[][] convertArray(byte[][] in) - { - short[][] out = new short[in.length][in[0].length]; - for (int i = 0; i < in.length; i++) - { - for (int j = 0; j < in[0].length; j++) - { - out[i][j] = (short)(in[i][j] & GF2Field.MASK); - } - } - return out; - } - - /** - * This function converts a 3-dimensional array of bytes into a 3-dimensional array of type short - * - * @param in the array to be converted - * @return out - * short-array that corresponds the input - */ - public static short[][][] convertArray(byte[][][] in) - { - short[][][] out = new short[in.length][in[0].length][in[0][0].length]; - for (int i = 0; i < in.length; i++) - { - for (int j = 0; j < in[0].length; j++) - { - for (int k = 0; k < in[0][0].length; k++) - { - out[i][j][k] = (short)(in[i][j][k] & GF2Field.MASK); - } - } - } - return out; - } - - /** - * This function converts an array of type int into an array of type byte - * - * @param in the array to be converted - * @return out - * the byte-array that corresponds the input - */ - public static byte[] convertIntArray(int[] in) - { - byte[] out = new byte[in.length]; - for (int i = 0; i < in.length; i++) - { - out[i] = (byte)in[i]; - } - return out; - } - - - /** - * This function converts an array of type short into an array of type byte - * - * @param in the array to be converted - * @return out - * the byte-array that corresponds the input - */ - public static byte[] convertArray(short[] in) - { - byte[] out = new byte[in.length]; - for (int i = 0; i < in.length; i++) - { - out[i] = (byte)in[i]; - } - return out; - } - - /** - * This function converts a matrix of type short into a matrix of type byte - * - * @param in the matrix to be converted - * @return out - * the byte-matrix that corresponds the input - */ - public static byte[][] convertArray(short[][] in) - { - byte[][] out = new byte[in.length][in[0].length]; - for (int i = 0; i < in.length; i++) - { - for (int j = 0; j < in[0].length; j++) - { - out[i][j] = (byte)in[i][j]; - } - } - return out; - } - - /** - * This function converts a 3-dimensional array of type short into a 3-dimensional array of type byte - * - * @param in the array to be converted - * @return out - * the byte-array that corresponds the input - */ - public static byte[][][] convertArray(short[][][] in) - { - byte[][][] out = new byte[in.length][in[0].length][in[0][0].length]; - for (int i = 0; i < in.length; i++) - { - for (int j = 0; j < in[0].length; j++) - { - for (int k = 0; k < in[0][0].length; k++) - { - out[i][j][k] = (byte)in[i][j][k]; - } - } - } - return out; - } - - /** - * Compare two short arrays. No null checks are performed. - * - * @param left the first short array - * @param right the second short array - * @return the result of the comparison - */ - public static boolean equals(short[] left, short[] right) - { - if (left.length != right.length) - { - return false; - } - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - result &= left[i] == right[i]; - } - return result; - } - - /** - * Compare two two-dimensional short arrays. No null checks are performed. - * - * @param left the first short array - * @param right the second short array - * @return the result of the comparison - */ - public static boolean equals(short[][] left, short[][] right) - { - if (left.length != right.length) - { - return false; - } - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - result &= equals(left[i], right[i]); - } - return result; - } - - /** - * Compare two three-dimensional short arrays. No null checks are performed. - * - * @param left the first short array - * @param right the second short array - * @return the result of the comparison - */ - public static boolean equals(short[][][] left, short[][][] right) - { - if (left.length != right.length) - { - return false; - } - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - result &= equals(left[i], right[i]); - } - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/BigEndianConversions.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/BigEndianConversions.java deleted file mode 100644 index 251deec6a1..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/BigEndianConversions.java +++ /dev/null @@ -1,306 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - - -/** - * This is a utility class containing data type conversions using big-endian - * byte order. - * - * @see LittleEndianConversions - */ -public final class BigEndianConversions -{ - - /** - * Default constructor (private). - */ - private BigEndianConversions() - { - // empty - } - - /** - * Convert an integer to an octet string of length 4 according to IEEE 1363, - * Section 5.5.3. - * - * @param x the integer to convert - * @return the converted integer - */ - public static byte[] I2OSP(int x) - { - byte[] result = new byte[4]; - result[0] = (byte)(x >>> 24); - result[1] = (byte)(x >>> 16); - result[2] = (byte)(x >>> 8); - result[3] = (byte)x; - return result; - } - - /** - * Convert an integer to an octet string according to IEEE 1363, Section - * 5.5.3. Length checking is performed. - * - * @param x the integer to convert - * @param oLen the desired length of the octet string - * @return an octet string of length oLen representing the - * integer x, or null if the integer is - * negative - * @throws ArithmeticException if x can't be encoded into oLen - * octets. - */ - public static byte[] I2OSP(int x, int oLen) - throws ArithmeticException - { - if (x < 0) - { - return null; - } - int octL = IntegerFunctions.ceilLog256(x); - if (octL > oLen) - { - throw new ArithmeticException( - "Cannot encode given integer into specified number of octets."); - } - byte[] result = new byte[oLen]; - for (int i = oLen - 1; i >= oLen - octL; i--) - { - result[i] = (byte)(x >>> (8 * (oLen - 1 - i))); - } - return result; - } - - /** - * Convert an integer to an octet string of length 4 according to IEEE 1363, - * Section 5.5.3. - * - * @param input the integer to convert - * @param output byte array holding the output - * @param outOff offset in output array where the result is stored - */ - public static void I2OSP(int input, byte[] output, int outOff) - { - output[outOff++] = (byte)(input >>> 24); - output[outOff++] = (byte)(input >>> 16); - output[outOff++] = (byte)(input >>> 8); - output[outOff] = (byte)input; - } - - /** - * Convert an integer to an octet string of length 8 according to IEEE 1363, - * Section 5.5.3. - * - * @param input the integer to convert - * @return the converted integer - */ - public static byte[] I2OSP(long input) - { - byte[] output = new byte[8]; - output[0] = (byte)(input >>> 56); - output[1] = (byte)(input >>> 48); - output[2] = (byte)(input >>> 40); - output[3] = (byte)(input >>> 32); - output[4] = (byte)(input >>> 24); - output[5] = (byte)(input >>> 16); - output[6] = (byte)(input >>> 8); - output[7] = (byte)input; - return output; - } - - /** - * Convert an integer to an octet string of length 8 according to IEEE 1363, - * Section 5.5.3. - * - * @param input the integer to convert - * @param output byte array holding the output - * @param outOff offset in output array where the result is stored - */ - public static void I2OSP(long input, byte[] output, int outOff) - { - output[outOff++] = (byte)(input >>> 56); - output[outOff++] = (byte)(input >>> 48); - output[outOff++] = (byte)(input >>> 40); - output[outOff++] = (byte)(input >>> 32); - output[outOff++] = (byte)(input >>> 24); - output[outOff++] = (byte)(input >>> 16); - output[outOff++] = (byte)(input >>> 8); - output[outOff] = (byte)input; - } - - /** - * Convert an integer to an octet string of the specified length according - * to IEEE 1363, Section 5.5.3. No length checking is performed (i.e., if - * the integer cannot be encoded into length octets, it is - * truncated). - * - * @param input the integer to convert - * @param output byte array holding the output - * @param outOff offset in output array where the result is stored - * @param length the length of the encoding - */ - public static void I2OSP(int input, byte[] output, int outOff, int length) - { - for (int i = length - 1; i >= 0; i--) - { - output[outOff + i] = (byte)(input >>> (8 * (length - 1 - i))); - } - } - - /** - * Convert an octet string to an integer according to IEEE 1363, Section - * 5.5.3. - * - * @param input the byte array holding the octet string - * @return an integer representing the octet string input, or - * 0 if the represented integer is negative or too large - * or the byte array is empty - * @throws ArithmeticException if the length of the given octet string is larger than 4. - */ - public static int OS2IP(byte[] input) - { - if (input.length > 4) - { - throw new ArithmeticException("invalid input length"); - } - if (input.length == 0) - { - return 0; - } - int result = 0; - for (int j = 0; j < input.length; j++) - { - result |= (input[j] & 0xff) << (8 * (input.length - 1 - j)); - } - return result; - } - - /** - * Convert a byte array of length 4 beginning at offset into an - * integer. - * - * @param input the byte array - * @param inOff the offset into the byte array - * @return the resulting integer - */ - public static int OS2IP(byte[] input, int inOff) - { - int result = (input[inOff++] & 0xff) << 24; - result |= (input[inOff++] & 0xff) << 16; - result |= (input[inOff++] & 0xff) << 8; - result |= input[inOff] & 0xff; - return result; - } - - /** - * Convert an octet string to an integer according to IEEE 1363, Section - * 5.5.3. - * - * @param input the byte array holding the octet string - * @param inOff the offset in the input byte array where the octet string - * starts - * @param inLen the length of the encoded integer - * @return an integer representing the octet string bytes, or - * 0 if the represented integer is negative or too large - * or the byte array is empty - */ - public static int OS2IP(byte[] input, int inOff, int inLen) - { - if ((input.length == 0) || input.length < inOff + inLen - 1) - { - return 0; - } - int result = 0; - for (int j = 0; j < inLen; j++) - { - result |= (input[inOff + j] & 0xff) << (8 * (inLen - j - 1)); - } - return result; - } - - /** - * Convert a byte array of length 8 beginning at inOff into a - * long integer. - * - * @param input the byte array - * @param inOff the offset into the byte array - * @return the resulting long integer - */ - public static long OS2LIP(byte[] input, int inOff) - { - long result = ((long)input[inOff++] & 0xff) << 56; - result |= ((long)input[inOff++] & 0xff) << 48; - result |= ((long)input[inOff++] & 0xff) << 40; - result |= ((long)input[inOff++] & 0xff) << 32; - result |= ((long)input[inOff++] & 0xff) << 24; - result |= (input[inOff++] & 0xff) << 16; - result |= (input[inOff++] & 0xff) << 8; - result |= input[inOff] & 0xff; - return result; - } - - /** - * Convert an int array into a byte array. - * - * @param input the int array - * @return the converted array - */ - public static byte[] toByteArray(final int[] input) - { - byte[] result = new byte[input.length << 2]; - for (int i = 0; i < input.length; i++) - { - I2OSP(input[i], result, i << 2); - } - return result; - } - - /** - * Convert an int array into a byte array of the specified length. No length - * checking is performed (i.e., if the last integer cannot be encoded into - * length % 4 octets, it is truncated). - * - * @param input the int array - * @param length the length of the converted array - * @return the converted array - */ - public static byte[] toByteArray(final int[] input, int length) - { - final int intLen = input.length; - byte[] result = new byte[length]; - int index = 0; - for (int i = 0; i <= intLen - 2; i++, index += 4) - { - I2OSP(input[i], result, index); - } - I2OSP(input[intLen - 1], result, index, length - index); - return result; - } - - /** - * Convert a byte array into an int array. - * - * @param input the byte array - * @return the converted array - */ - public static int[] toIntArray(byte[] input) - { - final int intLen = (input.length + 3) / 4; - final int lastLen = input.length & 0x03; - int[] result = new int[intLen]; - - int index = 0; - for (int i = 0; i <= intLen - 2; i++, index += 4) - { - result[i] = OS2IP(input, index); - } - if (lastLen != 0) - { - result[intLen - 1] = OS2IP(input, index, lastLen); - } - else - { - result[intLen - 1] = OS2IP(input, index); - } - - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/BigIntUtils.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/BigIntUtils.java deleted file mode 100644 index e4078992e5..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/BigIntUtils.java +++ /dev/null @@ -1,138 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -import java.math.BigInteger; - -/** - * FIXME: is this really necessary?! - */ -public final class BigIntUtils -{ - - /** - * Default constructor (private). - */ - private BigIntUtils() - { - // empty - } - - /** - * Checks if two BigInteger arrays contain the same entries - * - * @param a first BigInteger array - * @param b second BigInteger array - * @return true or false - */ - public static boolean equals(BigInteger[] a, BigInteger[] b) - { - int flag = 0; - - if (a.length != b.length) - { - return false; - } - for (int i = 0; i < a.length; i++) - { - // avoid branches here! - // problem: compareTo on BigIntegers is not - // guaranteed constant-time! - flag |= a[i].compareTo(b[i]); - } - return flag == 0; - } - - /** - * Fill the given BigInteger array with the given value. - * - * @param array the array - * @param value the value - */ - public static void fill(BigInteger[] array, BigInteger value) - { - for (int i = array.length - 1; i >= 0; i--) - { - array[i] = value; - } - } - - /** - * Generates a subarray of a given BigInteger array. - * - * @param input - - * the input BigInteger array - * @param start - - * the start index - * @param end - - * the end index - * @return a subarray of input, ranging from start to - * end - */ - public static BigInteger[] subArray(BigInteger[] input, int start, int end) - { - BigInteger[] result = new BigInteger[end - start]; - System.arraycopy(input, start, result, 0, end - start); - return result; - } - - /** - * Converts a BigInteger array into an integer array - * - * @param input - - * the BigInteger array - * @return the integer array - */ - public static int[] toIntArray(BigInteger[] input) - { - int[] result = new int[input.length]; - for (int i = 0; i < input.length; i++) - { - result[i] = input[i].intValue(); - } - return result; - } - - /** - * Converts a BigInteger array into an integer array, reducing all - * BigIntegers mod q. - * - * @param q - - * the modulus - * @param input - - * the BigInteger array - * @return the integer array - */ - public static int[] toIntArrayModQ(int q, BigInteger[] input) - { - BigInteger bq = BigInteger.valueOf(q); - int[] result = new int[input.length]; - for (int i = 0; i < input.length; i++) - { - result[i] = input[i].mod(bq).intValue(); - } - return result; - } - - /** - * Return the value of big as a byte array. Although BigInteger - * has such a method, it uses an extra bit to indicate the sign of the - * number. For elliptic curve cryptography, the numbers usually are - * positive. Thus, this helper method returns a byte array of minimal - * length, ignoring the sign of the number. - * - * @param value the BigInteger value to be converted to a byte - * array - * @return the value big as byte array - */ - public static byte[] toMinimalByteArray(BigInteger value) - { - byte[] valBytes = value.toByteArray(); - if ((valBytes.length == 1) || (value.bitLength() & 0x07) != 0) - { - return valBytes; - } - byte[] result = new byte[value.bitLength() >> 3]; - System.arraycopy(valBytes, 1, result, 0, result.length); - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/ByteUtils.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/ByteUtils.java deleted file mode 100644 index 26eeaa69fd..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/ByteUtils.java +++ /dev/null @@ -1,418 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -import org.bouncycastle.util.Strings; - -/** - * This class is a utility class for manipulating byte arrays. - * - * @deprecated use org.bouncycastle.util.Arrays. - */ -public final class ByteUtils -{ - - private static final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', - '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - - /** - * Default constructor (private) - */ - private ByteUtils() - { - // empty - } - - /** - * Compare two byte arrays (perform null checks beforehand). - * - * @param left the first byte array - * @param right the second byte array - * @return the result of the comparison - */ - public static boolean equals(byte[] left, byte[] right) - { - if (left == null) - { - return right == null; - } - if (right == null) - { - return false; - } - - if (left.length != right.length) - { - return false; - } - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - result &= left[i] == right[i]; - } - return result; - } - - /** - * Compare two two-dimensional byte arrays. No null checks are performed. - * - * @param left the first byte array - * @param right the second byte array - * @return the result of the comparison - */ - public static boolean equals(byte[][] left, byte[][] right) - { - if (left.length != right.length) - { - return false; - } - - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - result &= ByteUtils.equals(left[i], right[i]); - } - - return result; - } - - /** - * Compare two three-dimensional byte arrays. No null checks are performed. - * - * @param left the first byte array - * @param right the second byte array - * @return the result of the comparison - */ - public static boolean equals(byte[][][] left, byte[][][] right) - { - if (left.length != right.length) - { - return false; - } - - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - if (left[i].length != right[i].length) - { - return false; - } - for (int j = left[i].length - 1; j >= 0; j--) - { - result &= ByteUtils.equals(left[i][j], right[i][j]); - } - } - - return result; - } - - /** - * Computes a hashcode based on the contents of a one-dimensional byte array - * rather than its identity. - * - * @param array the array to compute the hashcode of - * @return the hashcode - */ - public static int deepHashCode(byte[] array) - { - int result = 1; - for (int i = 0; i < array.length; i++) - { - result = 31 * result + array[i]; - } - return result; - } - - /** - * Computes a hashcode based on the contents of a two-dimensional byte array - * rather than its identity. - * - * @param array the array to compute the hashcode of - * @return the hashcode - */ - public static int deepHashCode(byte[][] array) - { - int result = 1; - for (int i = 0; i < array.length; i++) - { - result = 31 * result + deepHashCode(array[i]); - } - return result; - } - - /** - * Computes a hashcode based on the contents of a three-dimensional byte - * array rather than its identity. - * - * @param array the array to compute the hashcode of - * @return the hashcode - */ - public static int deepHashCode(byte[][][] array) - { - int result = 1; - for (int i = 0; i < array.length; i++) - { - result = 31 * result + deepHashCode(array[i]); - } - return result; - } - - - /** - * Return a clone of the given byte array (performs null check beforehand). - * - * @param array the array to clone - * @return the clone of the given array, or null if the array is - * null - */ - public static byte[] clone(byte[] array) - { - if (array == null) - { - return null; - } - byte[] result = new byte[array.length]; - System.arraycopy(array, 0, result, 0, array.length); - return result; - } - - /** - * Convert a string containing hexadecimal characters to a byte-array. - * - * @param s a hex string - * @return a byte array with the corresponding value - */ - public static byte[] fromHexString(String s) - { - char[] rawChars = Strings.toUpperCase(s).toCharArray(); - - int hexChars = 0; - for (int i = 0; i < rawChars.length; i++) - { - if ((rawChars[i] >= '0' && rawChars[i] <= '9') - || (rawChars[i] >= 'A' && rawChars[i] <= 'F')) - { - hexChars++; - } - } - - byte[] byteString = new byte[(hexChars + 1) >> 1]; - - int pos = hexChars & 1; - - for (int i = 0; i < rawChars.length; i++) - { - if (rawChars[i] >= '0' && rawChars[i] <= '9') - { - byteString[pos >> 1] <<= 4; - byteString[pos >> 1] |= rawChars[i] - '0'; - } - else if (rawChars[i] >= 'A' && rawChars[i] <= 'F') - { - byteString[pos >> 1] <<= 4; - byteString[pos >> 1] |= rawChars[i] - 'A' + 10; - } - else - { - continue; - } - pos++; - } - - return byteString; - } - - /** - * Convert a byte array to the corresponding hexstring. - * - * @param input the byte array to be converted - * @return the corresponding hexstring - */ - public static String toHexString(byte[] input) - { - String result = ""; - for (int i = 0; i < input.length; i++) - { - result += HEX_CHARS[(input[i] >>> 4) & 0x0f]; - result += HEX_CHARS[(input[i]) & 0x0f]; - } - return result; - } - - /** - * Convert a byte array to the corresponding hex string. - * - * @param input the byte array to be converted - * @param prefix the prefix to put at the beginning of the hex string - * @param seperator a separator string - * @return the corresponding hex string - */ - public static String toHexString(byte[] input, String prefix, - String seperator) - { - String result = new String(prefix); - for (int i = 0; i < input.length; i++) - { - result += HEX_CHARS[(input[i] >>> 4) & 0x0f]; - result += HEX_CHARS[(input[i]) & 0x0f]; - if (i < input.length - 1) - { - result += seperator; - } - } - return result; - } - - /** - * Convert a byte array to the corresponding bit string. - * - * @param input the byte array to be converted - * @return the corresponding bit string - */ - public static String toBinaryString(byte[] input) - { - String result = ""; - int i; - for (i = 0; i < input.length; i++) - { - int e = input[i]; - for (int ii = 0; ii < 8; ii++) - { - int b = (e >>> ii) & 1; - result += b; - } - if (i != input.length - 1) - { - result += " "; - } - } - return result; - } - - /** - * Compute the bitwise XOR of two arrays of bytes. The arrays have to be of - * same length. No length checking is performed. - * - * @param x1 the first array - * @param x2 the second array - * @return x1 XOR x2 - */ - public static byte[] xor(byte[] x1, byte[] x2) - { - byte[] out = new byte[x1.length]; - - for (int i = x1.length - 1; i >= 0; i--) - { - out[i] = (byte)(x1[i] ^ x2[i]); - } - return out; - } - - /** - * Concatenate two byte arrays. No null checks are performed. - * - * @param x1 the first array - * @param x2 the second array - * @return (x2 | | x1) (little-endian order, i.e. x1 is at lower memory - * addresses) - */ - public static byte[] concatenate(byte[] x1, byte[] x2) - { - byte[] result = new byte[x1.length + x2.length]; - - System.arraycopy(x1, 0, result, 0, x1.length); - System.arraycopy(x2, 0, result, x1.length, x2.length); - - return result; - } - - /** - * Convert a 2-dimensional byte array into a 1-dimensional byte array by - * concatenating all entries. - * - * @param array a 2-dimensional byte array - * @return the concatenated input array - */ - public static byte[] concatenate(byte[][] array) - { - int rowLength = array[0].length; - byte[] result = new byte[array.length * rowLength]; - int index = 0; - for (int i = 0; i < array.length; i++) - { - System.arraycopy(array[i], 0, result, index, rowLength); - index += rowLength; - } - return result; - } - - /** - * Split a byte array input into two arrays at index, - * i.e. the first array will have the lower index bytes, the - * second one the higher input.length - index bytes. - * - * @param input the byte array to be split - * @param index the index where the byte array is split - * @return the splitted input array as an array of two byte arrays - * @throws ArrayIndexOutOfBoundsException if index is out of bounds - */ - public static byte[][] split(byte[] input, int index) - throws ArrayIndexOutOfBoundsException - { - if (index > input.length) - { - throw new ArrayIndexOutOfBoundsException(); - } - byte[][] result = new byte[2][]; - result[0] = new byte[index]; - result[1] = new byte[input.length - index]; - System.arraycopy(input, 0, result[0], 0, index); - System.arraycopy(input, index, result[1], 0, input.length - index); - return result; - } - - /** - * Generate a subarray of a given byte array. - * - * @param input the input byte array - * @param start the start index - * @param end the end index - * @return a subarray of input, ranging from start - * (inclusively) to end (exclusively) - */ - public static byte[] subArray(byte[] input, int start, int end) - { - byte[] result = new byte[end - start]; - System.arraycopy(input, start, result, 0, end - start); - return result; - } - - /** - * Generate a subarray of a given byte array. - * - * @param input the input byte array - * @param start the start index - * @return a subarray of input, ranging from start to - * the end of the array - */ - public static byte[] subArray(byte[] input, int start) - { - return subArray(input, start, input.length); - } - - /** - * Rewrite a byte array as a char array - * - * @param input - - * the byte array - * @return char array - */ - public static char[] toCharArray(byte[] input) - { - char[] result = new char[input.length]; - for (int i = 0; i < input.length; i++) - { - result[i] = (char)input[i]; - } - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/CharUtils.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/CharUtils.java deleted file mode 100644 index 1f34fb5569..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/CharUtils.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -public final class CharUtils -{ - - /** - * Default constructor (private) - */ - private CharUtils() - { - // empty - } - - /** - * Return a clone of the given char array. No null checks are performed. - * - * @param array the array to clone - * @return the clone of the given array - */ - public static char[] clone(char[] array) - { - char[] result = new char[array.length]; - System.arraycopy(array, 0, result, 0, array.length); - return result; - } - - /** - * Convert the given char array into a byte array. - * - * @param chars the char array - * @return the converted array - */ - public static byte[] toByteArray(char[] chars) - { - byte[] result = new byte[chars.length]; - for (int i = chars.length - 1; i >= 0; i--) - { - result[i] = (byte)chars[i]; - } - return result; - } - - /** - * Convert the given char array into a - * byte array for use with PBE encryption. - * - * @param chars the char array - * @return the converted array - */ - public static byte[] toByteArrayForPBE(char[] chars) - { - - byte[] out = new byte[chars.length]; - - for (int i = 0; i < chars.length; i++) - { - out[i] = (byte)chars[i]; - } - - int length = out.length * 2; - byte[] ret = new byte[length + 2]; - - int j = 0; - for (int i = 0; i < out.length; i++) - { - j = i * 2; - ret[j] = 0; - ret[j + 1] = out[i]; - } - - ret[length] = 0; - ret[length + 1] = 0; - - return ret; - } - - /** - * Compare two char arrays. No null checks are performed. - * - * @param left the char byte array - * @param right the second char array - * @return the result of the comparison - */ - public static boolean equals(char[] left, char[] right) - { - if (left.length != right.length) - { - return false; - } - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - result &= left[i] == right[i]; - } - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2Matrix.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2Matrix.java deleted file mode 100644 index 7b17571acd..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2Matrix.java +++ /dev/null @@ -1,1325 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -import java.security.SecureRandom; - -import org.bouncycastle.util.Arrays; - -/** - * This class describes some operations with matrices over finite field GF(2) - * and is used in ecc and MQ-PKC (also has some specific methods and - * implementation) - */ -public class GF2Matrix - extends Matrix -{ - - /** - * For the matrix representation the array of type int[][] is used, thus one - * element of the array keeps 32 elements of the matrix (from one row and 32 - * columns) - */ - private int[][] matrix; - - /** - * the length of each array representing a row of this matrix, computed as - * (numColumns + 31) / 32 - */ - private int length; - - /** - * Create the matrix from encoded form. - * - * @param enc the encoded matrix - */ - public GF2Matrix(byte[] enc) - { - if (enc.length < 9) - { - throw new ArithmeticException( - "given array is not an encoded matrix over GF(2)"); - } - - numRows = LittleEndianConversions.OS2IP(enc, 0); - numColumns = LittleEndianConversions.OS2IP(enc, 4); - - int n = ((numColumns + 7) >>> 3) * numRows; - - if ((numRows <= 0) || (n != (enc.length - 8))) - { - throw new ArithmeticException( - "given array is not an encoded matrix over GF(2)"); - } - - length = (numColumns + 31) >>> 5; - matrix = new int[numRows][length]; - - // number of "full" integer - int q = numColumns >> 5; - // number of bits in non-full integer - int r = numColumns & 0x1f; - - int count = 8; - for (int i = 0; i < numRows; i++) - { - for (int j = 0; j < q; j++, count += 4) - { - matrix[i][j] = LittleEndianConversions.OS2IP(enc, count); - } - for (int j = 0; j < r; j += 8) - { - matrix[i][q] ^= (enc[count++] & 0xff) << j; - } - } - } - - /** - * Create the matrix with the contents of the given array. The matrix is not - * copied. Unused coefficients are masked out. - * - * @param numColumns the number of columns - * @param matrix the element array - */ - public GF2Matrix(int numColumns, int[][] matrix) - { - if (matrix[0].length != (numColumns + 31) >> 5) - { - throw new ArithmeticException( - "Int array does not match given number of columns."); - } - this.numColumns = numColumns; - numRows = matrix.length; - length = matrix[0].length; - int rest = numColumns & 0x1f; - int bitMask; - if (rest == 0) - { - bitMask = 0xffffffff; - } - else - { - bitMask = (1 << rest) - 1; - } - for (int i = 0; i < numRows; i++) - { - matrix[i][length - 1] &= bitMask; - } - this.matrix = matrix; - } - - /** - * Create an nxn matrix of the given type. - * - * @param n the number of rows (and columns) - * @param typeOfMatrix the martix type (see {@link Matrix} for predefined - * constants) - */ - public GF2Matrix(int n, char typeOfMatrix) - { - this(n, typeOfMatrix, new java.security.SecureRandom()); - } - - /** - * Create an nxn matrix of the given type. - * - * @param n the matrix size - * @param typeOfMatrix the matrix type - * @param sr the source of randomness - */ - public GF2Matrix(int n, char typeOfMatrix, SecureRandom sr) - { - if (n <= 0) - { - throw new ArithmeticException("Size of matrix is non-positive."); - } - - switch (typeOfMatrix) - { - - case Matrix.MATRIX_TYPE_ZERO: - assignZeroMatrix(n, n); - break; - - case Matrix.MATRIX_TYPE_UNIT: - assignUnitMatrix(n); - break; - - case Matrix.MATRIX_TYPE_RANDOM_LT: - assignRandomLowerTriangularMatrix(n, sr); - break; - - case Matrix.MATRIX_TYPE_RANDOM_UT: - assignRandomUpperTriangularMatrix(n, sr); - break; - - case Matrix.MATRIX_TYPE_RANDOM_REGULAR: - assignRandomRegularMatrix(n, sr); - break; - - default: - throw new ArithmeticException("Unknown matrix type."); - } - } - - /** - * Copy constructor. - * - * @param a another {@link GF2Matrix} - */ - public GF2Matrix(GF2Matrix a) - { - numColumns = a.getNumColumns(); - numRows = a.getNumRows(); - length = a.length; - matrix = new int[a.matrix.length][]; - for (int i = 0; i < matrix.length; i++) - { - matrix[i] = IntUtils.clone(a.matrix[i]); - } - - } - - /** - * create the mxn zero matrix - */ - private GF2Matrix(int m, int n) - { - if ((n <= 0) || (m <= 0)) - { - throw new ArithmeticException("size of matrix is non-positive"); - } - - assignZeroMatrix(m, n); - } - - /** - * Create the mxn zero matrix. - * - * @param m number of rows - * @param n number of columns - */ - private void assignZeroMatrix(int m, int n) - { - numRows = m; - numColumns = n; - length = (n + 31) >>> 5; - matrix = new int[numRows][length]; - for (int i = 0; i < numRows; i++) - { - for (int j = 0; j < length; j++) - { - matrix[i][j] = 0; - } - } - } - - /** - * Create the mxn unit matrix. - * - * @param n number of rows (and columns) - */ - private void assignUnitMatrix(int n) - { - numRows = n; - numColumns = n; - length = (n + 31) >>> 5; - matrix = new int[numRows][length]; - for (int i = 0; i < numRows; i++) - { - for (int j = 0; j < length; j++) - { - matrix[i][j] = 0; - } - } - for (int i = 0; i < numRows; i++) - { - int rest = i & 0x1f; - matrix[i][i >>> 5] = 1 << rest; - } - } - - /** - * Create a nxn random lower triangular matrix. - * - * @param n number of rows (and columns) - * @param sr source of randomness - */ - private void assignRandomLowerTriangularMatrix(int n, SecureRandom sr) - { - numRows = n; - numColumns = n; - length = (n + 31) >>> 5; - matrix = new int[numRows][length]; - for (int i = 0; i < numRows; i++) - { - int q = i >>> 5; - int r = i & 0x1f; - int s = 31 - r; - r = 1 << r; - for (int j = 0; j < q; j++) - { - matrix[i][j] = sr.nextInt(); - } - matrix[i][q] = (sr.nextInt() >>> s) | r; - for (int j = q + 1; j < length; j++) - { - matrix[i][j] = 0; - } - - } - - } - - /** - * Create a nxn random upper triangular matrix. - * - * @param n number of rows (and columns) - * @param sr source of randomness - */ - private void assignRandomUpperTriangularMatrix(int n, SecureRandom sr) - { - numRows = n; - numColumns = n; - length = (n + 31) >>> 5; - matrix = new int[numRows][length]; - int rest = n & 0x1f; - int help; - if (rest == 0) - { - help = 0xffffffff; - } - else - { - help = (1 << rest) - 1; - } - for (int i = 0; i < numRows; i++) - { - int q = i >>> 5; - int r = i & 0x1f; - int s = r; - r = 1 << r; - for (int j = 0; j < q; j++) - { - matrix[i][j] = 0; - } - matrix[i][q] = (sr.nextInt() << s) | r; - for (int j = q + 1; j < length; j++) - { - matrix[i][j] = sr.nextInt(); - } - matrix[i][length - 1] &= help; - } - - } - - /** - * Create an nxn random regular matrix. - * - * @param n number of rows (and columns) - * @param sr source of randomness - */ - private void assignRandomRegularMatrix(int n, SecureRandom sr) - { - numRows = n; - numColumns = n; - length = (n + 31) >>> 5; - matrix = new int[numRows][length]; - GF2Matrix lm = new GF2Matrix(n, Matrix.MATRIX_TYPE_RANDOM_LT, sr); - GF2Matrix um = new GF2Matrix(n, Matrix.MATRIX_TYPE_RANDOM_UT, sr); - GF2Matrix rm = (GF2Matrix)lm.rightMultiply(um); - Permutation perm = new Permutation(n, sr); - int[] p = perm.getVector(); - for (int i = 0; i < n; i++) - { - System.arraycopy(rm.matrix[i], 0, matrix[p[i]], 0, length); - } - } - - /** - * Create a nxn random regular matrix and its inverse. - * - * @param n number of rows (and columns) - * @param sr source of randomness - * @return the created random regular matrix and its inverse - */ - public static GF2Matrix[] createRandomRegularMatrixAndItsInverse(int n, - SecureRandom sr) - { - - GF2Matrix[] result = new GF2Matrix[2]; - - // ------------------------------------ - // First part: create regular matrix - // ------------------------------------ - - // ------ - int length = (n + 31) >> 5; - GF2Matrix lm = new GF2Matrix(n, Matrix.MATRIX_TYPE_RANDOM_LT, sr); - GF2Matrix um = new GF2Matrix(n, Matrix.MATRIX_TYPE_RANDOM_UT, sr); - GF2Matrix rm = (GF2Matrix)lm.rightMultiply(um); - Permutation p = new Permutation(n, sr); - int[] pVec = p.getVector(); - - int[][] matrix = new int[n][length]; - for (int i = 0; i < n; i++) - { - System.arraycopy(rm.matrix[pVec[i]], 0, matrix[i], 0, length); - } - - result[0] = new GF2Matrix(n, matrix); - - // ------------------------------------ - // Second part: create inverse matrix - // ------------------------------------ - - // inverse to lm - GF2Matrix invLm = new GF2Matrix(n, Matrix.MATRIX_TYPE_UNIT); - for (int i = 0; i < n; i++) - { - int rest = i & 0x1f; - int q = i >>> 5; - int r = 1 << rest; - for (int j = i + 1; j < n; j++) - { - int b = (lm.matrix[j][q]) & r; - if (b != 0) - { - for (int k = 0; k <= q; k++) - { - invLm.matrix[j][k] ^= invLm.matrix[i][k]; - } - } - } - } - // inverse to um - GF2Matrix invUm = new GF2Matrix(n, Matrix.MATRIX_TYPE_UNIT); - for (int i = n - 1; i >= 0; i--) - { - int rest = i & 0x1f; - int q = i >>> 5; - int r = 1 << rest; - for (int j = i - 1; j >= 0; j--) - { - int b = (um.matrix[j][q]) & r; - if (b != 0) - { - for (int k = q; k < length; k++) - { - invUm.matrix[j][k] ^= invUm.matrix[i][k]; - } - } - } - } - - // inverse matrix - result[1] = (GF2Matrix)invUm.rightMultiply(invLm.rightMultiply(p)); - - return result; - } - - /** - * @return the array keeping the matrix elements - */ - public int[][] getIntArray() - { - return matrix; - } - - /** - * @return the length of each array representing a row of this matrix - */ - public int getLength() - { - return length; - } - - /** - * Return the row of this matrix with the given index. - * - * @param index the index - * @return the row of this matrix with the given index - */ - public int[] getRow(int index) - { - return matrix[index]; - } - - /** - * Returns encoded matrix, i.e., this matrix in byte array form - * - * @return the encoded matrix - */ - public byte[] getEncoded() - { - int n = (numColumns + 7) >>> 3; - n *= numRows; - n += 8; - byte[] enc = new byte[n]; - - LittleEndianConversions.I2OSP(numRows, enc, 0); - LittleEndianConversions.I2OSP(numColumns, enc, 4); - - // number of "full" integer - int q = numColumns >>> 5; - // number of bits in non-full integer - int r = numColumns & 0x1f; - - int count = 8; - for (int i = 0; i < numRows; i++) - { - for (int j = 0; j < q; j++, count += 4) - { - LittleEndianConversions.I2OSP(matrix[i][j], enc, count); - } - for (int j = 0; j < r; j += 8) - { - enc[count++] = (byte)((matrix[i][q] >>> j) & 0xff); - } - - } - return enc; - } - - - /** - * Returns the percentage of the number of "ones" in this matrix. - * - * @return the Hamming weight of this matrix (as a ratio). - */ - public double getHammingWeight() - { - double counter = 0.0; - double elementCounter = 0.0; - int rest = numColumns & 0x1f; - int d; - if (rest == 0) - { - d = length; - } - else - { - d = length - 1; - } - - for (int i = 0; i < numRows; i++) - { - - for (int j = 0; j < d; j++) - { - int a = matrix[i][j]; - for (int k = 0; k < 32; k++) - { - int b = (a >>> k) & 1; - counter = counter + b; - elementCounter = elementCounter + 1; - } - } - int a = matrix[i][length - 1]; - for (int k = 0; k < rest; k++) - { - int b = (a >>> k) & 1; - counter = counter + b; - elementCounter = elementCounter + 1; - } - } - - return counter / elementCounter; - } - - /** - * Check if this is the zero matrix (i.e., all entries are zero). - * - * @return true if this is the zero matrix - */ - public boolean isZero() - { - for (int i = 0; i < numRows; i++) - { - for (int j = 0; j < length; j++) - { - if (matrix[i][j] != 0) - { - return false; - } - } - } - return true; - } - - /** - * Get the quadratic submatrix of this matrix consisting of the leftmost - * numRows columns. - * - * @return the (numRows x numRows) submatrix - */ - public GF2Matrix getLeftSubMatrix() - { - if (numColumns <= numRows) - { - throw new ArithmeticException("empty submatrix"); - } - int length = (numRows + 31) >> 5; - int[][] result = new int[numRows][length]; - int bitMask = (1 << (numRows & 0x1f)) - 1; - if (bitMask == 0) - { - bitMask = -1; - } - for (int i = numRows - 1; i >= 0; i--) - { - System.arraycopy(matrix[i], 0, result[i], 0, length); - result[i][length - 1] &= bitMask; - } - return new GF2Matrix(numRows, result); - } - - /** - * Compute the full form matrix (this | Id) from this matrix in - * left compact form, where Id is the k x k identity - * matrix and k is the number of rows of this matrix. - * - * @return (this | Id) - */ - public GF2Matrix extendLeftCompactForm() - { - int newNumColumns = numColumns + numRows; - GF2Matrix result = new GF2Matrix(numRows, newNumColumns); - - int ind = numRows - 1 + numColumns; - for (int i = numRows - 1; i >= 0; i--, ind--) - { - // copy this matrix to first columns - System.arraycopy(matrix[i], 0, result.matrix[i], 0, length); - // store the identity in last columns - result.matrix[i][ind >> 5] |= 1 << (ind & 0x1f); - } - - return result; - } - - /** - * Get the submatrix of this matrix consisting of the rightmost - * numColumns-numRows columns. - * - * @return the (numRows x (numColumns-numRows)) submatrix - */ - public GF2Matrix getRightSubMatrix() - { - if (numColumns <= numRows) - { - throw new ArithmeticException("empty submatrix"); - } - - int q = numRows >> 5; - int r = numRows & 0x1f; - - GF2Matrix result = new GF2Matrix(numRows, numColumns - numRows); - - for (int i = numRows - 1; i >= 0; i--) - { - // if words have to be shifted - if (r != 0) - { - int ind = q; - // process all but last word - for (int j = 0; j < result.length - 1; j++) - { - // shift to correct position - result.matrix[i][j] = (matrix[i][ind++] >>> r) - | (matrix[i][ind] << (32 - r)); - } - // process last word - result.matrix[i][result.length - 1] = matrix[i][ind++] >>> r; - if (ind < length) - { - result.matrix[i][result.length - 1] |= matrix[i][ind] << (32 - r); - } - } - else - { - // no shifting necessary - System.arraycopy(matrix[i], q, result.matrix[i], 0, - result.length); - } - } - return result; - } - - /** - * Compute the full form matrix (Id | this) from this matrix in - * right compact form, where Id is the k x k identity - * matrix and k is the number of rows of this matrix. - * - * @return (Id | this) - */ - public GF2Matrix extendRightCompactForm() - { - GF2Matrix result = new GF2Matrix(numRows, numRows + numColumns); - - int q = numRows >> 5; - int r = numRows & 0x1f; - - for (int i = numRows - 1; i >= 0; i--) - { - // store the identity in first columns - result.matrix[i][i >> 5] |= 1 << (i & 0x1f); - - // copy this matrix to last columns - - // if words have to be shifted - if (r != 0) - { - int ind = q; - // process all but last word - for (int j = 0; j < length - 1; j++) - { - // obtain matrix word - int mw = matrix[i][j]; - // shift to correct position - result.matrix[i][ind++] |= mw << r; - result.matrix[i][ind] |= mw >>> (32 - r); - } - // process last word - int mw = matrix[i][length - 1]; - result.matrix[i][ind++] |= mw << r; - if (ind < result.length) - { - result.matrix[i][ind] |= mw >>> (32 - r); - } - } - else - { - // no shifting necessary - System.arraycopy(matrix[i], 0, result.matrix[i], q, length); - } - } - - return result; - } - - /** - * Compute the transpose of this matrix. - * - * @return (this)T - */ - public Matrix computeTranspose() - { - int[][] result = new int[numColumns][(numRows + 31) >>> 5]; - for (int i = 0; i < numRows; i++) - { - for (int j = 0; j < numColumns; j++) - { - int qs = j >>> 5; - int rs = j & 0x1f; - int b = (matrix[i][qs] >>> rs) & 1; - int qt = i >>> 5; - int rt = i & 0x1f; - if (b == 1) - { - result[j][qt] |= 1 << rt; - } - } - } - - return new GF2Matrix(numRows, result); - } - - /** - * Compute the inverse of this matrix. - * - * @return the inverse of this matrix (newly created). - * @throws ArithmeticException if this matrix is not invertible. - */ - public Matrix computeInverse() - { - if (numRows != numColumns) - { - throw new ArithmeticException("Matrix is not invertible."); - } - - // clone this matrix - int[][] tmpMatrix = new int[numRows][length]; - for (int i = numRows - 1; i >= 0; i--) - { - tmpMatrix[i] = IntUtils.clone(matrix[i]); - } - - // initialize inverse matrix as unit matrix - int[][] invMatrix = new int[numRows][length]; - for (int i = numRows - 1; i >= 0; i--) - { - int q = i >> 5; - int r = i & 0x1f; - invMatrix[i][q] = 1 << r; - } - - // simultaneously compute Gaussian reduction of tmpMatrix and unit - // matrix - for (int i = 0; i < numRows; i++) - { - // i = q * 32 + (i mod 32) - int q = i >> 5; - int bitMask = 1 << (i & 0x1f); - // if diagonal element is zero - if ((tmpMatrix[i][q] & bitMask) == 0) - { - boolean foundNonZero = false; - // find a non-zero element in the same column - for (int j = i + 1; j < numRows; j++) - { - if ((tmpMatrix[j][q] & bitMask) != 0) - { - // found it, swap rows ... - foundNonZero = true; - swapRows(tmpMatrix, i, j); - swapRows(invMatrix, i, j); - // ... and quit searching - j = numRows; - continue; - } - } - // if no non-zero element was found ... - if (!foundNonZero) - { - // ... the matrix is not invertible - throw new ArithmeticException("Matrix is not invertible."); - } - } - - // normalize all but i-th row - for (int j = numRows - 1; j >= 0; j--) - { - if ((j != i) && ((tmpMatrix[j][q] & bitMask) != 0)) - { - addToRow(tmpMatrix[i], tmpMatrix[j], q); - addToRow(invMatrix[i], invMatrix[j], 0); - } - } - } - - return new GF2Matrix(numColumns, invMatrix); - } - - /** - * Compute the product of a permutation matrix (which is generated from an - * n-permutation) and this matrix. - * - * @param p the permutation - * @return {@link GF2Matrix} P*this - */ - public Matrix leftMultiply(Permutation p) - { - int[] pVec = p.getVector(); - if (pVec.length != numRows) - { - throw new ArithmeticException("length mismatch"); - } - - int[][] result = new int[numRows][]; - - for (int i = numRows - 1; i >= 0; i--) - { - result[i] = IntUtils.clone(matrix[pVec[i]]); - } - - return new GF2Matrix(numRows, result); - } - - /** - * compute product a row vector and this matrix - * - * @param vec a vector over GF(2) - * @return Vector product a*matrix - */ - public Vector leftMultiply(Vector vec) - { - - if (!(vec instanceof GF2Vector)) - { - throw new ArithmeticException("vector is not defined over GF(2)"); - } - - if (vec.length != numRows) - { - throw new ArithmeticException("length mismatch"); - } - - int[] v = ((GF2Vector)vec).getVecArray(); - int[] res = new int[length]; - - int q = numRows >> 5; - int r = 1 << (numRows & 0x1f); - - // compute scalar products with full words of vector - int row = 0; - for (int i = 0; i < q; i++) - { - int bitMask = 1; - do - { - int b = v[i] & bitMask; - if (b != 0) - { - for (int j = 0; j < length; j++) - { - res[j] ^= matrix[row][j]; - } - } - row++; - bitMask <<= 1; - } - while (bitMask != 0); - } - - // compute scalar products with last word of vector - int bitMask = 1; - while (bitMask != r) - { - int b = v[q] & bitMask; - if (b != 0) - { - for (int j = 0; j < length; j++) - { - res[j] ^= matrix[row][j]; - } - } - row++; - bitMask <<= 1; - } - - return new GF2Vector(res, numColumns); - } - - /** - * Compute the product of the matrix (this | Id) and a column - * vector, where Id is a (numRows x numRows) unit - * matrix. - * - * @param vec the vector over GF(2) - * @return (this | Id)*vector - */ - public Vector leftMultiplyLeftCompactForm(Vector vec) - { - if (!(vec instanceof GF2Vector)) - { - throw new ArithmeticException("vector is not defined over GF(2)"); - } - - if (vec.length != numRows) - { - throw new ArithmeticException("length mismatch"); - } - - int[] v = ((GF2Vector)vec).getVecArray(); - int[] res = new int[(numRows + numColumns + 31) >>> 5]; - - // process full words of vector - int words = numRows >>> 5; - int row = 0; - for (int i = 0; i < words; i++) - { - int bitMask = 1; - do - { - int b = v[i] & bitMask; - if (b != 0) - { - // compute scalar product part - for (int j = 0; j < length; j++) - { - res[j] ^= matrix[row][j]; - } - // set last bit - int q = (numColumns + row) >>> 5; - int r = (numColumns + row) & 0x1f; - res[q] |= 1 << r; - } - row++; - bitMask <<= 1; - } - while (bitMask != 0); - } - - // process last word of vector - int rem = 1 << (numRows & 0x1f); - int bitMask = 1; - while (bitMask != rem) - { - int b = v[words] & bitMask; - if (b != 0) - { - // compute scalar product part - for (int j = 0; j < length; j++) - { - res[j] ^= matrix[row][j]; - } - // set last bit - int q = (numColumns + row) >>> 5; - int r = (numColumns + row) & 0x1f; - res[q] |= 1 << r; - } - row++; - bitMask <<= 1; - } - - return new GF2Vector(res, numRows + numColumns); - } - - /** - * Compute the product of this matrix and a matrix A over GF(2). - * - * @param mat a matrix A over GF(2) - * @return matrix product this*matrixA - */ - public Matrix rightMultiply(Matrix mat) - { - if (!(mat instanceof GF2Matrix)) - { - throw new ArithmeticException("matrix is not defined over GF(2)"); - } - - if (mat.numRows != numColumns) - { - throw new ArithmeticException("length mismatch"); - } - - GF2Matrix a = (GF2Matrix)mat; - GF2Matrix result = new GF2Matrix(numRows, mat.numColumns); - - int d; - int rest = numColumns & 0x1f; - if (rest == 0) - { - d = length; - } - else - { - d = length - 1; - } - for (int i = 0; i < numRows; i++) - { - int count = 0; - for (int j = 0; j < d; j++) - { - int e = matrix[i][j]; - for (int h = 0; h < 32; h++) - { - int b = e & (1 << h); - if (b != 0) - { - for (int g = 0; g < a.length; g++) - { - result.matrix[i][g] ^= a.matrix[count][g]; - } - } - count++; - } - } - int e = matrix[i][length - 1]; - for (int h = 0; h < rest; h++) - { - int b = e & (1 << h); - if (b != 0) - { - for (int g = 0; g < a.length; g++) - { - result.matrix[i][g] ^= a.matrix[count][g]; - } - } - count++; - } - - } - - return result; - } - - /** - * Compute the product of this matrix and a permutation matrix which is - * generated from an n-permutation. - * - * @param p the permutation - * @return {@link GF2Matrix} this*P - */ - public Matrix rightMultiply(Permutation p) - { - - int[] pVec = p.getVector(); - if (pVec.length != numColumns) - { - throw new ArithmeticException("length mismatch"); - } - - GF2Matrix result = new GF2Matrix(numRows, numColumns); - - for (int i = numColumns - 1; i >= 0; i--) - { - int q = i >>> 5; - int r = i & 0x1f; - int pq = pVec[i] >>> 5; - int pr = pVec[i] & 0x1f; - for (int j = numRows - 1; j >= 0; j--) - { - result.matrix[j][q] |= ((matrix[j][pq] >>> pr) & 1) << r; - } - } - - return result; - } - - /** - * Compute the product of this matrix and the given column vector. - * - * @param vec the vector over GF(2) - * @return this*vector - */ - public Vector rightMultiply(Vector vec) - { - if (!(vec instanceof GF2Vector)) - { - throw new ArithmeticException("vector is not defined over GF(2)"); - } - - if (vec.length != numColumns) - { - throw new ArithmeticException("length mismatch"); - } - - int[] v = ((GF2Vector)vec).getVecArray(); - int[] res = new int[(numRows + 31) >>> 5]; - - for (int i = 0; i < numRows; i++) - { - // compute full word scalar products - int help = 0; - for (int j = 0; j < length; j++) - { - help ^= matrix[i][j] & v[j]; - } - // compute single word scalar product - int bitValue = 0; - for (int j = 0; j < 32; j++) - { - bitValue ^= (help >>> j) & 1; - } - // set result bit - if (bitValue == 1) - { - res[i >>> 5] |= 1 << (i & 0x1f); - } - } - - return new GF2Vector(res, numRows); - } - - /** - * Compute the product of the matrix (Id | this) and a column - * vector, where Id is a (numRows x numRows) unit - * matrix. - * - * @param vec the vector over GF(2) - * @return (Id | this)*vector - */ - public Vector rightMultiplyRightCompactForm(Vector vec) - { - if (!(vec instanceof GF2Vector)) - { - throw new ArithmeticException("vector is not defined over GF(2)"); - } - - if (vec.length != numColumns + numRows) - { - throw new ArithmeticException("length mismatch"); - } - - int[] v = ((GF2Vector)vec).getVecArray(); - int[] res = new int[(numRows + 31) >>> 5]; - - int q = numRows >> 5; - int r = numRows & 0x1f; - - // for all rows - for (int i = 0; i < numRows; i++) - { - // get vector bit - int help = (v[i >> 5] >>> (i & 0x1f)) & 1; - - // compute full word scalar products - int vInd = q; - // if words have to be shifted - if (r != 0) - { - int vw = 0; - // process all but last word - for (int j = 0; j < length - 1; j++) - { - // shift to correct position - vw = (v[vInd++] >>> r) | (v[vInd] << (32 - r)); - help ^= matrix[i][j] & vw; - } - // process last word - vw = v[vInd++] >>> r; - if (vInd < v.length) - { - vw |= v[vInd] << (32 - r); - } - help ^= matrix[i][length - 1] & vw; - } - else - { - // no shifting necessary - for (int j = 0; j < length; j++) - { - help ^= matrix[i][j] & v[vInd++]; - } - } - - // compute single word scalar product - int bitValue = 0; - for (int j = 0; j < 32; j++) - { - bitValue ^= help & 1; - help >>>= 1; - } - - // set result bit - if (bitValue == 1) - { - res[i >> 5] |= 1 << (i & 0x1f); - } - } - - return new GF2Vector(res, numRows); - } - - /** - * Compare this matrix with another object. - * - * @param other another object - * @return the result of the comparison - */ - public boolean equals(Object other) - { - - if (!(other instanceof GF2Matrix)) - { - return false; - } - GF2Matrix otherMatrix = (GF2Matrix)other; - - if ((numRows != otherMatrix.numRows) - || (numColumns != otherMatrix.numColumns) - || (length != otherMatrix.length)) - { - return false; - } - - for (int i = 0; i < numRows; i++) - { - if (!IntUtils.equals(matrix[i], otherMatrix.matrix[i])) - { - return false; - } - } - - return true; - } - - /** - * @return the hash code of this matrix - */ - public int hashCode() - { - int hash = (numRows * 31 + numColumns) * 31 + length; - for (int i = 0; i < numRows; i++) - { - hash = hash * 31 + Arrays.hashCode(matrix[i]); - } - return hash; - } - - /** - * @return a human readable form of the matrix - */ - public String toString() - { - int rest = numColumns & 0x1f; - int d; - if (rest == 0) - { - d = length; - } - else - { - d = length - 1; - } - - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < numRows; i++) - { - buf.append(i + ": "); - for (int j = 0; j < d; j++) - { - int a = matrix[i][j]; - for (int k = 0; k < 32; k++) - { - int b = (a >>> k) & 1; - if (b == 0) - { - buf.append('0'); - } - else - { - buf.append('1'); - } - } - buf.append(' '); - } - int a = matrix[i][length - 1]; - for (int k = 0; k < rest; k++) - { - int b = (a >>> k) & 1; - if (b == 0) - { - buf.append('0'); - } - else - { - buf.append('1'); - } - } - buf.append('\n'); - } - - return buf.toString(); - } - - /** - * Swap two rows of the given matrix. - * - * @param matrix the matrix - * @param first the index of the first row - * @param second the index of the second row - */ - private static void swapRows(int[][] matrix, int first, int second) - { - int[] tmp = matrix[first]; - matrix[first] = matrix[second]; - matrix[second] = tmp; - } - - /** - * Partially add one row to another. - * - * @param fromRow the addend - * @param toRow the row to add to - * @param startIndex the array index to start from - */ - private static void addToRow(int[] fromRow, int[] toRow, int startIndex) - { - for (int i = toRow.length - 1; i >= startIndex; i--) - { - toRow[i] = fromRow[i] ^ toRow[i]; - } - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2Polynomial.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2Polynomial.java deleted file mode 100644 index 5f5ed824fa..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2Polynomial.java +++ /dev/null @@ -1,2034 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - - -import java.math.BigInteger; -import java.util.Random; - -import org.bouncycastle.util.Arrays; - - -/** - * This class stores very long strings of bits and does some basic arithmetics. - * It is used by GF2nField, GF2nPolynomialField and - * GFnPolynomialElement. - * - * @see GF2nPolynomialElement - * @see GF2nField - */ -public class GF2Polynomial -{ - - // number of bits stored in this GF2Polynomial - private int len; - - // number of int used in value - private int blocks; - - // storage - private int[] value; - - // Random source - private static Random rand = new Random(); - - // Lookup-Table for vectorMult: parity[a]= #1(a) mod 2 == 1 - private static final boolean[] parity = {false, true, true, false, true, - false, false, true, true, false, false, true, false, true, true, - false, true, false, false, true, false, true, true, false, false, - true, true, false, true, false, false, true, true, false, false, - true, false, true, true, false, false, true, true, false, true, - false, false, true, false, true, true, false, true, false, false, - true, true, false, false, true, false, true, true, false, true, - false, false, true, false, true, true, false, false, true, true, - false, true, false, false, true, false, true, true, false, true, - false, false, true, true, false, false, true, false, true, true, - false, false, true, true, false, true, false, false, true, true, - false, false, true, false, true, true, false, true, false, false, - true, false, true, true, false, false, true, true, false, true, - false, false, true, true, false, false, true, false, true, true, - false, false, true, true, false, true, false, false, true, false, - true, true, false, true, false, false, true, true, false, false, - true, false, true, true, false, false, true, true, false, true, - false, false, true, true, false, false, true, false, true, true, - false, true, false, false, true, false, true, true, false, false, - true, true, false, true, false, false, true, false, true, true, - false, true, false, false, true, true, false, false, true, false, - true, true, false, true, false, false, true, false, true, true, - false, false, true, true, false, true, false, false, true, true, - false, false, true, false, true, true, false, false, true, true, - false, true, false, false, true, false, true, true, false, true, - false, false, true, true, false, false, true, false, true, true, - false}; - - // Lookup-Table for Squaring: squaringTable[a]=a^2 - private static final short[] squaringTable = {0x0000, 0x0001, 0x0004, - 0x0005, 0x0010, 0x0011, 0x0014, 0x0015, 0x0040, 0x0041, 0x0044, - 0x0045, 0x0050, 0x0051, 0x0054, 0x0055, 0x0100, 0x0101, 0x0104, - 0x0105, 0x0110, 0x0111, 0x0114, 0x0115, 0x0140, 0x0141, 0x0144, - 0x0145, 0x0150, 0x0151, 0x0154, 0x0155, 0x0400, 0x0401, 0x0404, - 0x0405, 0x0410, 0x0411, 0x0414, 0x0415, 0x0440, 0x0441, 0x0444, - 0x0445, 0x0450, 0x0451, 0x0454, 0x0455, 0x0500, 0x0501, 0x0504, - 0x0505, 0x0510, 0x0511, 0x0514, 0x0515, 0x0540, 0x0541, 0x0544, - 0x0545, 0x0550, 0x0551, 0x0554, 0x0555, 0x1000, 0x1001, 0x1004, - 0x1005, 0x1010, 0x1011, 0x1014, 0x1015, 0x1040, 0x1041, 0x1044, - 0x1045, 0x1050, 0x1051, 0x1054, 0x1055, 0x1100, 0x1101, 0x1104, - 0x1105, 0x1110, 0x1111, 0x1114, 0x1115, 0x1140, 0x1141, 0x1144, - 0x1145, 0x1150, 0x1151, 0x1154, 0x1155, 0x1400, 0x1401, 0x1404, - 0x1405, 0x1410, 0x1411, 0x1414, 0x1415, 0x1440, 0x1441, 0x1444, - 0x1445, 0x1450, 0x1451, 0x1454, 0x1455, 0x1500, 0x1501, 0x1504, - 0x1505, 0x1510, 0x1511, 0x1514, 0x1515, 0x1540, 0x1541, 0x1544, - 0x1545, 0x1550, 0x1551, 0x1554, 0x1555, 0x4000, 0x4001, 0x4004, - 0x4005, 0x4010, 0x4011, 0x4014, 0x4015, 0x4040, 0x4041, 0x4044, - 0x4045, 0x4050, 0x4051, 0x4054, 0x4055, 0x4100, 0x4101, 0x4104, - 0x4105, 0x4110, 0x4111, 0x4114, 0x4115, 0x4140, 0x4141, 0x4144, - 0x4145, 0x4150, 0x4151, 0x4154, 0x4155, 0x4400, 0x4401, 0x4404, - 0x4405, 0x4410, 0x4411, 0x4414, 0x4415, 0x4440, 0x4441, 0x4444, - 0x4445, 0x4450, 0x4451, 0x4454, 0x4455, 0x4500, 0x4501, 0x4504, - 0x4505, 0x4510, 0x4511, 0x4514, 0x4515, 0x4540, 0x4541, 0x4544, - 0x4545, 0x4550, 0x4551, 0x4554, 0x4555, 0x5000, 0x5001, 0x5004, - 0x5005, 0x5010, 0x5011, 0x5014, 0x5015, 0x5040, 0x5041, 0x5044, - 0x5045, 0x5050, 0x5051, 0x5054, 0x5055, 0x5100, 0x5101, 0x5104, - 0x5105, 0x5110, 0x5111, 0x5114, 0x5115, 0x5140, 0x5141, 0x5144, - 0x5145, 0x5150, 0x5151, 0x5154, 0x5155, 0x5400, 0x5401, 0x5404, - 0x5405, 0x5410, 0x5411, 0x5414, 0x5415, 0x5440, 0x5441, 0x5444, - 0x5445, 0x5450, 0x5451, 0x5454, 0x5455, 0x5500, 0x5501, 0x5504, - 0x5505, 0x5510, 0x5511, 0x5514, 0x5515, 0x5540, 0x5541, 0x5544, - 0x5545, 0x5550, 0x5551, 0x5554, 0x5555}; - - // pre-computed Bitmask for fast masking, bitMask[a]=0x1 << a - private static final int[] bitMask = {0x00000001, 0x00000002, 0x00000004, - 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080, - 0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00001000, - 0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000, - 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, - 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x00000000}; - - // pre-computed Bitmask for fast masking, rightMask[a]=0xffffffff >>> (32-a) - private static final int[] reverseRightMask = {0x00000000, 0x00000001, - 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, - 0x0000007f, 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, - 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff, - 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, - 0x003fffff, 0x007fffff, 0x00ffffff, 0x01ffffff, 0x03ffffff, - 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, - 0xffffffff}; - - /** - * Creates a new GF2Polynomial of the given length and value zero. - * - * @param length the desired number of bits to store - */ - public GF2Polynomial(int length) - { - int l = length; - if (l < 1) - { - l = 1; - } - blocks = ((l - 1) >> 5) + 1; - value = new int[blocks]; - len = l; - } - - /** - * Creates a new GF2Polynomial of the given length and random value. - * - * @param length the desired number of bits to store - * @param rand SecureRandom to use for randomization - */ - public GF2Polynomial(int length, Random rand) - { - int l = length; - if (l < 1) - { - l = 1; - } - blocks = ((l - 1) >> 5) + 1; - value = new int[blocks]; - len = l; - randomize(rand); - } - - /** - * Creates a new GF2Polynomial of the given length and value - * selected by value: - *

      - *
    • ZERO
    • - *
    • ONE
    • - *
    • RANDOM
    • - *
    • X
    • - *
    • ALL
    • - *
    - * - * @param length the desired number of bits to store - * @param value the value described by a String - */ - public GF2Polynomial(int length, String value) - { - int l = length; - if (l < 1) - { - l = 1; - } - blocks = ((l - 1) >> 5) + 1; - this.value = new int[blocks]; - len = l; - if (value.equalsIgnoreCase("ZERO")) - { - assignZero(); - } - else if (value.equalsIgnoreCase("ONE")) - { - assignOne(); - } - else if (value.equalsIgnoreCase("RANDOM")) - { - randomize(); - } - else if (value.equalsIgnoreCase("X")) - { - assignX(); - } - else if (value.equalsIgnoreCase("ALL")) - { - assignAll(); - } - else - { - throw new IllegalArgumentException( - "Error: GF2Polynomial was called using " + value - + " as value!"); - } - - } - - /** - * Creates a new GF2Polynomial of the given length using the given - * int[]. LSB is contained in bs[0]. - * - * @param length the desired number of bits to store - * @param bs contains the desired value, LSB in bs[0] - */ - public GF2Polynomial(int length, int[] bs) - { - int leng = length; - if (leng < 1) - { - leng = 1; - } - blocks = ((leng - 1) >> 5) + 1; - value = new int[blocks]; - len = leng; - int l = Math.min(blocks, bs.length); - System.arraycopy(bs, 0, value, 0, l); - zeroUnusedBits(); - } - - /** - * Creates a new GF2Polynomial by converting the given byte[] os - * according to 1363 and using the given length. - * - * @param length the intended length of this polynomial - * @param os the octet string to assign to this polynomial - * @see "P1363 5.5.2 p22f, OS2BSP" - */ - public GF2Polynomial(int length, byte[] os) - { - int l = length; - if (l < 1) - { - l = 1; - } - blocks = ((l - 1) >> 5) + 1; - value = new int[blocks]; - len = l; - int i, m; - int k = Math.min(((os.length - 1) >> 2) + 1, blocks); - for (i = 0; i < k - 1; i++) - { - m = os.length - (i << 2) - 1; - value[i] = (os[m]) & 0x000000ff; - value[i] |= (os[m - 1] << 8) & 0x0000ff00; - value[i] |= (os[m - 2] << 16) & 0x00ff0000; - value[i] |= (os[m - 3] << 24) & 0xff000000; - } - i = k - 1; - m = os.length - (i << 2) - 1; - value[i] = os[m] & 0x000000ff; - if (m > 0) - { - value[i] |= (os[m - 1] << 8) & 0x0000ff00; - } - if (m > 1) - { - value[i] |= (os[m - 2] << 16) & 0x00ff0000; - } - if (m > 2) - { - value[i] |= (os[m - 3] << 24) & 0xff000000; - } - zeroUnusedBits(); - reduceN(); - } - - /** - * Creates a new GF2Polynomial by converting the given FlexiBigInt bi - * according to 1363 and using the given length. - * - * @param length the intended length of this polynomial - * @param bi the FlexiBigInt to assign to this polynomial - * @see "P1363 5.5.1 p22, I2BSP" - */ - public GF2Polynomial(int length, BigInteger bi) - { - int l = length; - if (l < 1) - { - l = 1; - } - blocks = ((l - 1) >> 5) + 1; - value = new int[blocks]; - len = l; - int i; - byte[] val = bi.toByteArray(); - if (val[0] == 0) - { - byte[] dummy = new byte[val.length - 1]; - System.arraycopy(val, 1, dummy, 0, dummy.length); - val = dummy; - } - int ov = val.length & 0x03; - int k = ((val.length - 1) >> 2) + 1; - for (i = 0; i < ov; i++) - { - value[k - 1] |= (val[i] & 0x000000ff) << ((ov - 1 - i) << 3); - } - int m = 0; - for (i = 0; i <= (val.length - 4) >> 2; i++) - { - m = val.length - 1 - (i << 2); - value[i] = (val[m]) & 0x000000ff; - value[i] |= ((val[m - 1]) << 8) & 0x0000ff00; - value[i] |= ((val[m - 2]) << 16) & 0x00ff0000; - value[i] |= ((val[m - 3]) << 24) & 0xff000000; - } - if ((len & 0x1f) != 0) - { - value[blocks - 1] &= reverseRightMask[len & 0x1f]; - } - reduceN(); - } - - /** - * Creates a new GF2Polynomial by cloneing the given GF2Polynomial b. - * - * @param b the GF2Polynomial to clone - */ - public GF2Polynomial(GF2Polynomial b) - { - len = b.len; - blocks = b.blocks; - value = IntUtils.clone(b.value); - } - - /** - * @return a copy of this GF2Polynomial - */ - public Object clone() - { - return new GF2Polynomial(this); - } - - /** - * Returns the length of this GF2Polynomial. The length can be greater than - * the degree. To get the degree call reduceN() before calling getLength(). - * - * @return the length of this GF2Polynomial - */ - public int getLength() - { - return len; - } - - /** - * Returns the value of this GF2Polynomial in an int[]. - * - * @return the value of this GF2Polynomial in a new int[], LSB in int[0] - */ - public int[] toIntegerArray() - { - int[] result; - result = new int[blocks]; - System.arraycopy(value, 0, result, 0, blocks); - return result; - } - - /** - * Returns a string representing this GF2Polynomials value using hexadecimal - * or binary radix in MSB-first order. - * - * @param radix the radix to use (2 or 16, otherwise 2 is used) - * @return a String representing this GF2Polynomials value. - */ - public String toString(int radix) - { - final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', - '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - final String[] BIN_CHARS = {"0000", "0001", "0010", "0011", "0100", - "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", - "1101", "1110", "1111"}; - String res; - int i; - res = new String(); - if (radix == 16) - { - for (i = blocks - 1; i >= 0; i--) - { - res += HEX_CHARS[(value[i] >>> 28) & 0x0f]; - res += HEX_CHARS[(value[i] >>> 24) & 0x0f]; - res += HEX_CHARS[(value[i] >>> 20) & 0x0f]; - res += HEX_CHARS[(value[i] >>> 16) & 0x0f]; - res += HEX_CHARS[(value[i] >>> 12) & 0x0f]; - res += HEX_CHARS[(value[i] >>> 8) & 0x0f]; - res += HEX_CHARS[(value[i] >>> 4) & 0x0f]; - res += HEX_CHARS[(value[i]) & 0x0f]; - res += " "; - } - } - else - { - for (i = blocks - 1; i >= 0; i--) - { - res += BIN_CHARS[(value[i] >>> 28) & 0x0f]; - res += BIN_CHARS[(value[i] >>> 24) & 0x0f]; - res += BIN_CHARS[(value[i] >>> 20) & 0x0f]; - res += BIN_CHARS[(value[i] >>> 16) & 0x0f]; - res += BIN_CHARS[(value[i] >>> 12) & 0x0f]; - res += BIN_CHARS[(value[i] >>> 8) & 0x0f]; - res += BIN_CHARS[(value[i] >>> 4) & 0x0f]; - res += BIN_CHARS[(value[i]) & 0x0f]; - res += " "; - } - } - return res; - } - - /** - * Converts this polynomial to a byte[] (octet string) according to 1363. - * - * @return a byte[] representing the value of this polynomial - * @see "P1363 5.5.2 p22f, BS2OSP" - */ - public byte[] toByteArray() - { - int k = ((len - 1) >> 3) + 1; - int ov = k & 0x03; - int m; - byte[] res = new byte[k]; - int i; - for (i = 0; i < (k >> 2); i++) - { - m = k - (i << 2) - 1; - res[m] = (byte)((value[i] & 0x000000ff)); - res[m - 1] = (byte)((value[i] & 0x0000ff00) >>> 8); - res[m - 2] = (byte)((value[i] & 0x00ff0000) >>> 16); - res[m - 3] = (byte)((value[i] & 0xff000000) >>> 24); - } - for (i = 0; i < ov; i++) - { - m = (ov - i - 1) << 3; - res[i] = (byte)((value[blocks - 1] & (0x000000ff << m)) >>> m); - } - return res; - } - - /** - * Converts this polynomial to an integer according to 1363. - * - * @return a FlexiBigInt representing the value of this polynomial - * @see "P1363 5.5.1 p22, BS2IP" - */ - public BigInteger toFlexiBigInt() - { - if (len == 0 || isZero()) - { - return new BigInteger(0, new byte[0]); - } - return new BigInteger(1, toByteArray()); - } - - /** - * Sets the LSB to 1 and all other to 0, assigning 'one' to this - * GF2Polynomial. - */ - public void assignOne() - { - int i; - for (i = 1; i < blocks; i++) - { - value[i] = 0x00; - } - value[0] = 0x01; - } - - /** - * Sets Bit 1 to 1 and all other to 0, assigning 'x' to this GF2Polynomial. - */ - public void assignX() - { - int i; - for (i = 1; i < blocks; i++) - { - value[i] = 0x00; - } - value[0] = 0x02; - } - - /** - * Sets all Bits to 1. - */ - public void assignAll() - { - int i; - for (i = 0; i < blocks; i++) - { - value[i] = 0xffffffff; - } - zeroUnusedBits(); - } - - /** - * Resets all bits to zero. - */ - public void assignZero() - { - int i; - for (i = 0; i < blocks; i++) - { - value[i] = 0x00; - } - } - - /** - * Fills all len bits of this GF2Polynomial with random values. - */ - public void randomize() - { - int i; - for (i = 0; i < blocks; i++) - { - value[i] = rand.nextInt(); - } - zeroUnusedBits(); - } - - /** - * Fills all len bits of this GF2Polynomial with random values using the - * specified source of randomness. - * - * @param rand the source of randomness - */ - public void randomize(Random rand) - { - int i; - for (i = 0; i < blocks; i++) - { - value[i] = rand.nextInt(); - } - zeroUnusedBits(); - } - - /** - * Returns true if two GF2Polynomials have the same size and value and thus - * are equal. - * - * @param other the other GF2Polynomial - * @return true if this GF2Polynomial equals b (this == - * b) - */ - public boolean equals(Object other) - { - if (other == null || !(other instanceof GF2Polynomial)) - { - return false; - } - - GF2Polynomial otherPol = (GF2Polynomial)other; - - if (len != otherPol.len) - { - return false; - } - for (int i = 0; i < blocks; i++) - { - if (value[i] != otherPol.value[i]) - { - return false; - } - } - return true; - } - - /** - * @return the hash code of this polynomial - */ - public int hashCode() - { - return len + Arrays.hashCode(value); - } - - /** - * Tests if all bits equal zero. - * - * @return true if this GF2Polynomial equals 'zero' (this == 0) - */ - public boolean isZero() - { - int i; - if (len == 0) - { - return true; - } - for (i = 0; i < blocks; i++) - { - if (value[i] != 0) - { - return false; - } - } - return true; - } - - /** - * Tests if all bits are reset to 0 and LSB is set to 1. - * - * @return true if this GF2Polynomial equals 'one' (this == 1) - */ - public boolean isOne() - { - int i; - for (i = 1; i < blocks; i++) - { - if (value[i] != 0) - { - return false; - } - } - if (value[0] != 0x01) - { - return false; - } - return true; - } - - /** - * Adds b to this GF2Polynomial and assigns the result to this - * GF2Polynomial. b can be of different size. - * - * @param b GF2Polynomial to add to this GF2Polynomial - */ - public void addToThis(GF2Polynomial b) - { - expandN(b.len); - xorThisBy(b); - } - - /** - * Adds two GF2Polynomials, this and b, and returns the - * result. this and b can be of different size. - * - * @param b a GF2Polynomial - * @return a new GF2Polynomial (this + b) - */ - public GF2Polynomial add(GF2Polynomial b) - { - return xor(b); - } - - /** - * Subtracts b from this GF2Polynomial and assigns the result to - * this GF2Polynomial. b can be of different size. - * - * @param b a GF2Polynomial - */ - public void subtractFromThis(GF2Polynomial b) - { - expandN(b.len); - xorThisBy(b); - } - - /** - * Subtracts two GF2Polynomials, this and b, and returns the - * result in a new GF2Polynomial. this and b can be of - * different size. - * - * @param b a GF2Polynomial - * @return a new GF2Polynomial (this - b) - */ - public GF2Polynomial subtract(GF2Polynomial b) - { - return xor(b); - } - - /** - * Toggles the LSB of this GF2Polynomial, increasing its value by 'one'. - */ - public void increaseThis() - { - xorBit(0); - } - - /** - * Toggles the LSB of this GF2Polynomial, increasing the value by 'one' and - * returns the result in a new GF2Polynomial. - * - * @return this + 1 - */ - public GF2Polynomial increase() - { - GF2Polynomial result = new GF2Polynomial(this); - result.increaseThis(); - return result; - } - - /** - * Multiplies this GF2Polynomial with b and returns the result in a - * new GF2Polynomial. This method does not reduce the result in GF(2^N). - * This method uses classic multiplication (schoolbook). - * - * @param b a GF2Polynomial - * @return a new GF2Polynomial (this * b) - */ - public GF2Polynomial multiplyClassic(GF2Polynomial b) - { - GF2Polynomial result = new GF2Polynomial(Math.max(len, b.len) << 1); - GF2Polynomial[] m = new GF2Polynomial[32]; - int i, j; - m[0] = new GF2Polynomial(this); - for (i = 1; i <= 31; i++) - { - m[i] = m[i - 1].shiftLeft(); - } - for (i = 0; i < b.blocks; i++) - { - for (j = 0; j <= 31; j++) - { - if ((b.value[i] & bitMask[j]) != 0) - { - result.xorThisBy(m[j]); - } - } - for (j = 0; j <= 31; j++) - { - m[j].shiftBlocksLeft(); - } - } - return result; - } - - /** - * Multiplies this GF2Polynomial with b and returns the result in a - * new GF2Polynomial. This method does not reduce the result in GF(2^N). - * This method uses Karatzuba multiplication. - * - * @param b a GF2Polynomial - * @return a new GF2Polynomial (this * b) - */ - public GF2Polynomial multiply(GF2Polynomial b) - { - int n = Math.max(len, b.len); - expandN(n); - b.expandN(n); - return karaMult(b); - } - - /** - * Does the recursion for Karatzuba multiplication. - */ - private GF2Polynomial karaMult(GF2Polynomial b) - { - GF2Polynomial result = new GF2Polynomial(len << 1); - if (len <= 32) - { - result.value = mult32(value[0], b.value[0]); - return result; - } - if (len <= 64) - { - result.value = mult64(value, b.value); - return result; - } - if (len <= 128) - { - result.value = mult128(value, b.value); - return result; - } - if (len <= 256) - { - result.value = mult256(value, b.value); - return result; - } - if (len <= 512) - { - result.value = mult512(value, b.value); - return result; - } - - int n = IntegerFunctions.floorLog(len - 1); - n = bitMask[n]; - - GF2Polynomial a0 = lower(((n - 1) >> 5) + 1); - GF2Polynomial a1 = upper(((n - 1) >> 5) + 1); - GF2Polynomial b0 = b.lower(((n - 1) >> 5) + 1); - GF2Polynomial b1 = b.upper(((n - 1) >> 5) + 1); - - GF2Polynomial c = a1.karaMult(b1); // c = a1*b1 - GF2Polynomial e = a0.karaMult(b0); // e = a0*b0 - a0.addToThis(a1); // a0 = a0 + a1 - b0.addToThis(b1); // b0 = b0 + b1 - GF2Polynomial d = a0.karaMult(b0); // d = (a0+a1)*(b0+b1) - - result.shiftLeftAddThis(c, n << 1); - result.shiftLeftAddThis(c, n); - result.shiftLeftAddThis(d, n); - result.shiftLeftAddThis(e, n); - result.addToThis(e); - return result; - } - - /** - * 16-Integer Version of Karatzuba multiplication. - */ - private static int[] mult512(int[] a, int[] b) - { - int[] result = new int[32]; - int[] a0 = new int[8]; - System.arraycopy(a, 0, a0, 0, Math.min(8, a.length)); - int[] a1 = new int[8]; - if (a.length > 8) - { - System.arraycopy(a, 8, a1, 0, Math.min(8, a.length - 8)); - } - int[] b0 = new int[8]; - System.arraycopy(b, 0, b0, 0, Math.min(8, b.length)); - int[] b1 = new int[8]; - if (b.length > 8) - { - System.arraycopy(b, 8, b1, 0, Math.min(8, b.length - 8)); - } - int[] c = mult256(a1, b1); - result[31] ^= c[15]; - result[30] ^= c[14]; - result[29] ^= c[13]; - result[28] ^= c[12]; - result[27] ^= c[11]; - result[26] ^= c[10]; - result[25] ^= c[9]; - result[24] ^= c[8]; - result[23] ^= c[7] ^ c[15]; - result[22] ^= c[6] ^ c[14]; - result[21] ^= c[5] ^ c[13]; - result[20] ^= c[4] ^ c[12]; - result[19] ^= c[3] ^ c[11]; - result[18] ^= c[2] ^ c[10]; - result[17] ^= c[1] ^ c[9]; - result[16] ^= c[0] ^ c[8]; - result[15] ^= c[7]; - result[14] ^= c[6]; - result[13] ^= c[5]; - result[12] ^= c[4]; - result[11] ^= c[3]; - result[10] ^= c[2]; - result[9] ^= c[1]; - result[8] ^= c[0]; - a1[0] ^= a0[0]; - a1[1] ^= a0[1]; - a1[2] ^= a0[2]; - a1[3] ^= a0[3]; - a1[4] ^= a0[4]; - a1[5] ^= a0[5]; - a1[6] ^= a0[6]; - a1[7] ^= a0[7]; - b1[0] ^= b0[0]; - b1[1] ^= b0[1]; - b1[2] ^= b0[2]; - b1[3] ^= b0[3]; - b1[4] ^= b0[4]; - b1[5] ^= b0[5]; - b1[6] ^= b0[6]; - b1[7] ^= b0[7]; - int[] d = mult256(a1, b1); - result[23] ^= d[15]; - result[22] ^= d[14]; - result[21] ^= d[13]; - result[20] ^= d[12]; - result[19] ^= d[11]; - result[18] ^= d[10]; - result[17] ^= d[9]; - result[16] ^= d[8]; - result[15] ^= d[7]; - result[14] ^= d[6]; - result[13] ^= d[5]; - result[12] ^= d[4]; - result[11] ^= d[3]; - result[10] ^= d[2]; - result[9] ^= d[1]; - result[8] ^= d[0]; - int[] e = mult256(a0, b0); - result[23] ^= e[15]; - result[22] ^= e[14]; - result[21] ^= e[13]; - result[20] ^= e[12]; - result[19] ^= e[11]; - result[18] ^= e[10]; - result[17] ^= e[9]; - result[16] ^= e[8]; - result[15] ^= e[7] ^ e[15]; - result[14] ^= e[6] ^ e[14]; - result[13] ^= e[5] ^ e[13]; - result[12] ^= e[4] ^ e[12]; - result[11] ^= e[3] ^ e[11]; - result[10] ^= e[2] ^ e[10]; - result[9] ^= e[1] ^ e[9]; - result[8] ^= e[0] ^ e[8]; - result[7] ^= e[7]; - result[6] ^= e[6]; - result[5] ^= e[5]; - result[4] ^= e[4]; - result[3] ^= e[3]; - result[2] ^= e[2]; - result[1] ^= e[1]; - result[0] ^= e[0]; - return result; - } - - /** - * 8-Integer Version of Karatzuba multiplication. - */ - private static int[] mult256(int[] a, int[] b) - { - int[] result = new int[16]; - int[] a0 = new int[4]; - System.arraycopy(a, 0, a0, 0, Math.min(4, a.length)); - int[] a1 = new int[4]; - if (a.length > 4) - { - System.arraycopy(a, 4, a1, 0, Math.min(4, a.length - 4)); - } - int[] b0 = new int[4]; - System.arraycopy(b, 0, b0, 0, Math.min(4, b.length)); - int[] b1 = new int[4]; - if (b.length > 4) - { - System.arraycopy(b, 4, b1, 0, Math.min(4, b.length - 4)); - } - if (a1[3] == 0 && a1[2] == 0 && b1[3] == 0 && b1[2] == 0) - { - if (a1[1] == 0 && b1[1] == 0) - { - if (a1[0] != 0 || b1[0] != 0) - { // [3]=[2]=[1]=0, [0]!=0 - int[] c = mult32(a1[0], b1[0]); - result[9] ^= c[1]; - result[8] ^= c[0]; - result[5] ^= c[1]; - result[4] ^= c[0]; - } - } - else - { // [3]=[2]=0 [1]!=0, [0]!=0 - int[] c = mult64(a1, b1); - result[11] ^= c[3]; - result[10] ^= c[2]; - result[9] ^= c[1]; - result[8] ^= c[0]; - result[7] ^= c[3]; - result[6] ^= c[2]; - result[5] ^= c[1]; - result[4] ^= c[0]; - } - } - else - { // [3]!=0 [2]!=0 [1]!=0, [0]!=0 - int[] c = mult128(a1, b1); - result[15] ^= c[7]; - result[14] ^= c[6]; - result[13] ^= c[5]; - result[12] ^= c[4]; - result[11] ^= c[3] ^ c[7]; - result[10] ^= c[2] ^ c[6]; - result[9] ^= c[1] ^ c[5]; - result[8] ^= c[0] ^ c[4]; - result[7] ^= c[3]; - result[6] ^= c[2]; - result[5] ^= c[1]; - result[4] ^= c[0]; - } - a1[0] ^= a0[0]; - a1[1] ^= a0[1]; - a1[2] ^= a0[2]; - a1[3] ^= a0[3]; - b1[0] ^= b0[0]; - b1[1] ^= b0[1]; - b1[2] ^= b0[2]; - b1[3] ^= b0[3]; - int[] d = mult128(a1, b1); - result[11] ^= d[7]; - result[10] ^= d[6]; - result[9] ^= d[5]; - result[8] ^= d[4]; - result[7] ^= d[3]; - result[6] ^= d[2]; - result[5] ^= d[1]; - result[4] ^= d[0]; - int[] e = mult128(a0, b0); - result[11] ^= e[7]; - result[10] ^= e[6]; - result[9] ^= e[5]; - result[8] ^= e[4]; - result[7] ^= e[3] ^ e[7]; - result[6] ^= e[2] ^ e[6]; - result[5] ^= e[1] ^ e[5]; - result[4] ^= e[0] ^ e[4]; - result[3] ^= e[3]; - result[2] ^= e[2]; - result[1] ^= e[1]; - result[0] ^= e[0]; - return result; - } - - /** - * 4-Integer Version of Karatzuba multiplication. - */ - private static int[] mult128(int[] a, int[] b) - { - int[] result = new int[8]; - int[] a0 = new int[2]; - System.arraycopy(a, 0, a0, 0, Math.min(2, a.length)); - int[] a1 = new int[2]; - if (a.length > 2) - { - System.arraycopy(a, 2, a1, 0, Math.min(2, a.length - 2)); - } - int[] b0 = new int[2]; - System.arraycopy(b, 0, b0, 0, Math.min(2, b.length)); - int[] b1 = new int[2]; - if (b.length > 2) - { - System.arraycopy(b, 2, b1, 0, Math.min(2, b.length - 2)); - } - if (a1[1] == 0 && b1[1] == 0) - { - if (a1[0] != 0 || b1[0] != 0) - { - int[] c = mult32(a1[0], b1[0]); - result[5] ^= c[1]; - result[4] ^= c[0]; - result[3] ^= c[1]; - result[2] ^= c[0]; - } - } - else - { - int[] c = mult64(a1, b1); - result[7] ^= c[3]; - result[6] ^= c[2]; - result[5] ^= c[1] ^ c[3]; - result[4] ^= c[0] ^ c[2]; - result[3] ^= c[1]; - result[2] ^= c[0]; - } - a1[0] ^= a0[0]; - a1[1] ^= a0[1]; - b1[0] ^= b0[0]; - b1[1] ^= b0[1]; - if (a1[1] == 0 && b1[1] == 0) - { - int[] d = mult32(a1[0], b1[0]); - result[3] ^= d[1]; - result[2] ^= d[0]; - } - else - { - int[] d = mult64(a1, b1); - result[5] ^= d[3]; - result[4] ^= d[2]; - result[3] ^= d[1]; - result[2] ^= d[0]; - } - if (a0[1] == 0 && b0[1] == 0) - { - int[] e = mult32(a0[0], b0[0]); - result[3] ^= e[1]; - result[2] ^= e[0]; - result[1] ^= e[1]; - result[0] ^= e[0]; - } - else - { - int[] e = mult64(a0, b0); - result[5] ^= e[3]; - result[4] ^= e[2]; - result[3] ^= e[1] ^ e[3]; - result[2] ^= e[0] ^ e[2]; - result[1] ^= e[1]; - result[0] ^= e[0]; - } - return result; - } - - /** - * 2-Integer Version of Karatzuba multiplication. - */ - private static int[] mult64(int[] a, int[] b) - { - int[] result = new int[4]; - int a0 = a[0]; - int a1 = 0; - if (a.length > 1) - { - a1 = a[1]; - } - int b0 = b[0]; - int b1 = 0; - if (b.length > 1) - { - b1 = b[1]; - } - if (a1 != 0 || b1 != 0) - { - int[] c = mult32(a1, b1); - result[3] ^= c[1]; - result[2] ^= c[0] ^ c[1]; - result[1] ^= c[0]; - } - int[] d = mult32(a0 ^ a1, b0 ^ b1); - result[2] ^= d[1]; - result[1] ^= d[0]; - int[] e = mult32(a0, b0); - result[2] ^= e[1]; - result[1] ^= e[0] ^ e[1]; - result[0] ^= e[0]; - return result; - } - - /** - * 4-Byte Version of Karatzuba multiplication. Here the actual work is done. - */ - private static int[] mult32(int a, int b) - { - int[] result = new int[2]; - if (a == 0 || b == 0) - { - return result; - } - long b2 = b; - b2 &= 0x00000000ffffffffL; - int i; - long h = 0; - for (i = 1; i <= 32; i++) - { - if ((a & bitMask[i - 1]) != 0) - { - h ^= b2; - } - b2 <<= 1; - } - result[1] = (int)(h >>> 32); - result[0] = (int)(h & 0x00000000ffffffffL); - return result; - } - - /** - * Returns a new GF2Polynomial containing the upper k bytes of this - * GF2Polynomial. - * - * @param k - * @return a new GF2Polynomial containing the upper k bytes of this - * GF2Polynomial - * @see GF2Polynomial#karaMult - */ - private GF2Polynomial upper(int k) - { - int j = Math.min(k, blocks - k); - GF2Polynomial result = new GF2Polynomial(j << 5); - if (blocks >= k) - { - System.arraycopy(value, k, result.value, 0, j); - } - return result; - } - - /** - * Returns a new GF2Polynomial containing the lower k bytes of this - * GF2Polynomial. - * - * @param k - * @return a new GF2Polynomial containing the lower k bytes of this - * GF2Polynomial - * @see GF2Polynomial#karaMult - */ - private GF2Polynomial lower(int k) - { - GF2Polynomial result = new GF2Polynomial(k << 5); - System.arraycopy(value, 0, result.value, 0, Math.min(k, blocks)); - return result; - } - - /** - * Returns the remainder of this divided by g in a new - * GF2Polynomial. - * - * @param g GF2Polynomial != 0 - * @return a new GF2Polynomial (this % g) - */ - public GF2Polynomial remainder(GF2Polynomial g) - throws RuntimeException - { - /* a div b = q / r */ - GF2Polynomial a = new GF2Polynomial(this); - GF2Polynomial b = new GF2Polynomial(g); - GF2Polynomial j; - int i; - if (b.isZero()) - { - throw new RuntimeException(); - } - a.reduceN(); - b.reduceN(); - if (a.len < b.len) - { - return a; - } - i = a.len - b.len; - while (i >= 0) - { - j = b.shiftLeft(i); - a.subtractFromThis(j); - a.reduceN(); - i = a.len - b.len; - } - return a; - } - - /** - * Returns the absolute quotient of this divided by g in a - * new GF2Polynomial. - * - * @param g GF2Polynomial != 0 - * @return a new GF2Polynomial |_ this / g _| - */ - public GF2Polynomial quotient(GF2Polynomial g) - throws RuntimeException - { - /* a div b = q / r */ - GF2Polynomial q = new GF2Polynomial(len); - GF2Polynomial a = new GF2Polynomial(this); - GF2Polynomial b = new GF2Polynomial(g); - GF2Polynomial j; - int i; - if (b.isZero()) - { - throw new RuntimeException(); - } - a.reduceN(); - b.reduceN(); - if (a.len < b.len) - { - return new GF2Polynomial(0); - } - i = a.len - b.len; - q.expandN(i + 1); - - while (i >= 0) - { - j = b.shiftLeft(i); - a.subtractFromThis(j); - a.reduceN(); - q.xorBit(i); - i = a.len - b.len; - } - - return q; - } - - /** - * Divides this by g and returns the quotient and remainder - * in a new GF2Polynomial[2], quotient in [0], remainder in [1]. - * - * @param g GF2Polynomial != 0 - * @return a new GF2Polynomial[2] containing quotient and remainder - */ - public GF2Polynomial[] divide(GF2Polynomial g) - throws RuntimeException - { - /* a div b = q / r */ - GF2Polynomial[] result = new GF2Polynomial[2]; - GF2Polynomial q = new GF2Polynomial(len); - GF2Polynomial a = new GF2Polynomial(this); - GF2Polynomial b = new GF2Polynomial(g); - GF2Polynomial j; - int i; - if (b.isZero()) - { - throw new RuntimeException(); - } - a.reduceN(); - b.reduceN(); - if (a.len < b.len) - { - result[0] = new GF2Polynomial(0); - result[1] = a; - return result; - } - i = a.len - b.len; - q.expandN(i + 1); - - while (i >= 0) - { - j = b.shiftLeft(i); - a.subtractFromThis(j); - a.reduceN(); - q.xorBit(i); - i = a.len - b.len; - } - - result[0] = q; - result[1] = a; - return result; - } - - /** - * Returns the greatest common divisor of this and g in a - * new GF2Polynomial. - * - * @param g GF2Polynomial != 0 - * @return a new GF2Polynomial gcd(this,g) - * @throws ArithmeticException if this and g both are equal to zero - */ - public GF2Polynomial gcd(GF2Polynomial g) - throws RuntimeException - { - if (isZero() && g.isZero()) - { - throw new ArithmeticException("Both operands of gcd equal zero."); - } - if (isZero()) - { - return new GF2Polynomial(g); - } - if (g.isZero()) - { - return new GF2Polynomial(this); - } - GF2Polynomial a = new GF2Polynomial(this); - GF2Polynomial b = new GF2Polynomial(g); - GF2Polynomial c; - - while (!b.isZero()) - { - c = a.remainder(b); - a = b; - b = c; - } - - return a; - } - - /** - * Checks if this is irreducible, according to IEEE P1363, A.5.5, - * p103.
    - * Note: The algorithm from IEEE P1363, A5.5 can be used to check a - * polynomial with coefficients in GF(2^r) for irreducibility. As this class - * only represents polynomials with coefficients in GF(2), the algorithm is - * adapted to the case r=1. - * - * @return true if this is irreducible - * @see "P1363, A.5.5, p103" - */ - public boolean isIrreducible() - { - if (isZero()) - { - return false; - } - GF2Polynomial f = new GF2Polynomial(this); - int d, i; - GF2Polynomial u, g; - GF2Polynomial dummy; - f.reduceN(); - d = f.len - 1; - u = new GF2Polynomial(f.len, "X"); - - for (i = 1; i <= (d >> 1); i++) - { - u.squareThisPreCalc(); - u = u.remainder(f); - dummy = u.add(new GF2Polynomial(32, "X")); - if (!dummy.isZero()) - { - g = f.gcd(dummy); - if (!g.isOne()) - { - return false; - } - } - else - { - return false; - } - } - - return true; - } - - /** - * Reduces this GF2Polynomial using the trinomial x^m + x^tc + - * 1. - * - * @param m the degree of the used field - * @param tc degree of the middle x in the trinomial - */ - void reduceTrinomial(int m, int tc) - { - int i; - int p0, p1; - int q0, q1; - long t; - p0 = m >>> 5; // block which contains 2^m - q0 = 32 - (m & 0x1f); // (32-index) of 2^m within block p0 - p1 = (m - tc) >>> 5; // block which contains 2^tc - q1 = 32 - ((m - tc) & 0x1f); // (32-index) of 2^tc within block q1 - int max = ((m << 1) - 2) >>> 5; // block which contains 2^(2m-2) - int min = p0; // block which contains 2^m - for (i = max; i > min; i--) - { // for i = maxBlock to minBlock - // reduce coefficients contained in t - // t = block[i] - t = value[i] & 0x00000000ffffffffL; - // block[i-p0-1] ^= t << q0 - value[i - p0 - 1] ^= (int)(t << q0); - // block[i-p0] ^= t >>> (32-q0) - value[i - p0] ^= t >>> (32 - q0); - // block[i-p1-1] ^= << q1 - value[i - p1 - 1] ^= (int)(t << q1); - // block[i-p1] ^= t >>> (32-q1) - value[i - p1] ^= t >>> (32 - q1); - value[i] = 0x00; - } - // reduce last coefficients in block containing 2^m - t = value[min] & 0x00000000ffffffffL & (0xffffffffL << (m & 0x1f)); // t - // contains the last coefficients > m - value[0] ^= t >>> (32 - q0); - if (min - p1 - 1 >= 0) - { - value[min - p1 - 1] ^= (int)(t << q1); - } - value[min - p1] ^= t >>> (32 - q1); - - value[min] &= reverseRightMask[m & 0x1f]; - blocks = ((m - 1) >>> 5) + 1; - len = m; - } - - /** - * Reduces this GF2Polynomial using the pentanomial x^m + x^pc[2] + - * x^pc[1] + x^pc[0] + 1. - * - * @param m the degree of the used field - * @param pc degrees of the middle x's in the pentanomial - */ - void reducePentanomial(int m, int[] pc) - { - int i; - int p0, p1, p2, p3; - int q0, q1, q2, q3; - long t; - p0 = m >>> 5; - q0 = 32 - (m & 0x1f); - p1 = (m - pc[0]) >>> 5; - q1 = 32 - ((m - pc[0]) & 0x1f); - p2 = (m - pc[1]) >>> 5; - q2 = 32 - ((m - pc[1]) & 0x1f); - p3 = (m - pc[2]) >>> 5; - q3 = 32 - ((m - pc[2]) & 0x1f); - int max = ((m << 1) - 2) >>> 5; - int min = p0; - for (i = max; i > min; i--) - { - t = value[i] & 0x00000000ffffffffL; - value[i - p0 - 1] ^= (int)(t << q0); - value[i - p0] ^= t >>> (32 - q0); - value[i - p1 - 1] ^= (int)(t << q1); - value[i - p1] ^= t >>> (32 - q1); - value[i - p2 - 1] ^= (int)(t << q2); - value[i - p2] ^= t >>> (32 - q2); - value[i - p3 - 1] ^= (int)(t << q3); - value[i - p3] ^= t >>> (32 - q3); - value[i] = 0; - } - t = value[min] & 0x00000000ffffffffL & (0xffffffffL << (m & 0x1f)); - value[0] ^= t >>> (32 - q0); - if (min - p1 - 1 >= 0) - { - value[min - p1 - 1] ^= (int)(t << q1); - } - value[min - p1] ^= t >>> (32 - q1); - if (min - p2 - 1 >= 0) - { - value[min - p2 - 1] ^= (int)(t << q2); - } - value[min - p2] ^= t >>> (32 - q2); - if (min - p3 - 1 >= 0) - { - value[min - p3 - 1] ^= (int)(t << q3); - } - value[min - p3] ^= t >>> (32 - q3); - value[min] &= reverseRightMask[m & 0x1f]; - - blocks = ((m - 1) >>> 5) + 1; - len = m; - } - - /** - * Reduces len by finding the most significant bit set to one and reducing - * len and blocks. - */ - public void reduceN() - { - int i, j, h; - i = blocks - 1; - while ((value[i] == 0) && (i > 0)) - { - i--; - } - h = value[i]; - j = 0; - while (h != 0) - { - h >>>= 1; - j++; - } - len = (i << 5) + j; - blocks = i + 1; - } - - /** - * Expands len and int[] value to i. This is useful before adding - * two GF2Polynomials of different size. - * - * @param i the intended length - */ - public void expandN(int i) - { - int k; - int[] bs; - if (len >= i) - { - return; - } - len = i; - k = ((i - 1) >>> 5) + 1; - if (blocks >= k) - { - return; - } - if (value.length >= k) - { - int j; - for (j = blocks; j < k; j++) - { - value[j] = 0; - } - blocks = k; - return; - } - bs = new int[k]; - System.arraycopy(value, 0, bs, 0, blocks); - blocks = k; - value = null; - value = bs; - } - - /** - * Squares this GF2Polynomial and expands it accordingly. This method does - * not reduce the result in GF(2^N). There exists a faster method for - * squaring in GF(2^N). - * - * @see GF2nPolynomialElement#square - */ - public void squareThisBitwise() - { - int i, h, j, k; - if (isZero()) - { - return; - } - int[] result = new int[blocks << 1]; - for (i = blocks - 1; i >= 0; i--) - { - h = value[i]; - j = 0x00000001; - for (k = 0; k < 16; k++) - { - if ((h & 0x01) != 0) - { - result[i << 1] |= j; - } - if ((h & 0x00010000) != 0) - { - result[(i << 1) + 1] |= j; - } - j <<= 2; - h >>>= 1; - } - } - value = null; - value = result; - blocks = result.length; - len = (len << 1) - 1; - } - - /** - * Squares this GF2Polynomial by using precomputed values of squaringTable. - * This method does not reduce the result in GF(2^N). - */ - public void squareThisPreCalc() - { - int i; - if (isZero()) - { - return; - } - if (value.length >= (blocks << 1)) - { - for (i = blocks - 1; i >= 0; i--) - { - value[(i << 1) + 1] = GF2Polynomial.squaringTable[(value[i] & 0x00ff0000) >>> 16] - | (GF2Polynomial.squaringTable[(value[i] & 0xff000000) >>> 24] << 16); - value[i << 1] = GF2Polynomial.squaringTable[value[i] & 0x000000ff] - | (GF2Polynomial.squaringTable[(value[i] & 0x0000ff00) >>> 8] << 16); - } - blocks <<= 1; - len = (len << 1) - 1; - } - else - { - int[] result = new int[blocks << 1]; - for (i = 0; i < blocks; i++) - { - result[i << 1] = GF2Polynomial.squaringTable[value[i] & 0x000000ff] - | (GF2Polynomial.squaringTable[(value[i] & 0x0000ff00) >>> 8] << 16); - result[(i << 1) + 1] = GF2Polynomial.squaringTable[(value[i] & 0x00ff0000) >>> 16] - | (GF2Polynomial.squaringTable[(value[i] & 0xff000000) >>> 24] << 16); - } - value = null; - value = result; - blocks <<= 1; - len = (len << 1) - 1; - } - } - - /** - * Does a vector-multiplication modulo 2 and returns the result as boolean. - * - * @param b GF2Polynomial - * @return this x b as boolean (1->true, 0->false) - */ - public boolean vectorMult(GF2Polynomial b) - throws RuntimeException - { - int i; - int h; - boolean result = false; - if (len != b.len) - { - throw new RuntimeException(); - } - for (i = 0; i < blocks; i++) - { - h = value[i] & b.value[i]; - result ^= parity[h & 0x000000ff]; - result ^= parity[(h >>> 8) & 0x000000ff]; - result ^= parity[(h >>> 16) & 0x000000ff]; - result ^= parity[(h >>> 24) & 0x000000ff]; - } - return result; - } - - /** - * Returns the bitwise exclusive-or of this and b in a new - * GF2Polynomial. this and b can be of different size. - * - * @param b GF2Polynomial - * @return a new GF2Polynomial (this ^ b) - */ - public GF2Polynomial xor(GF2Polynomial b) - { - int i; - GF2Polynomial result; - int k = Math.min(blocks, b.blocks); - if (len >= b.len) - { - result = new GF2Polynomial(this); - for (i = 0; i < k; i++) - { - result.value[i] ^= b.value[i]; - } - } - else - { - result = new GF2Polynomial(b); - for (i = 0; i < k; i++) - { - result.value[i] ^= value[i]; - } - } - // If we xor'ed some bits too many by proceeding blockwise, - // restore them to zero: - result.zeroUnusedBits(); - return result; - } - - /** - * Computes the bitwise exclusive-or of this GF2Polynomial and b and - * stores the result in this GF2Polynomial. b can be of different - * size. - * - * @param b GF2Polynomial - */ - public void xorThisBy(GF2Polynomial b) - { - int i; - for (i = 0; i < Math.min(blocks, b.blocks); i++) - { - value[i] ^= b.value[i]; - } - // If we xor'ed some bits too many by proceeding blockwise, - // restore them to zero: - zeroUnusedBits(); - } - - /** - * If {@link #len} is not a multiple of the block size (32), some extra bits - * of the last block might have been modified during a blockwise operation. - * This method compensates for that by restoring these "extra" bits to zero. - */ - private void zeroUnusedBits() - { - if ((len & 0x1f) != 0) - { - value[blocks - 1] &= reverseRightMask[len & 0x1f]; - } - } - - /** - * Sets the bit at position i. - * - * @param i int - * @throws RuntimeException if (i < 0) || (i > (len - 1)) - */ - public void setBit(int i) - throws RuntimeException - { - if (i < 0 || i > (len - 1)) - { - throw new RuntimeException(); - } - value[i >>> 5] |= bitMask[i & 0x1f]; - } - - /** - * Returns the bit at position i. - * - * @param i int - * @return the bit at position i if i is a valid position, 0 - * otherwise. - */ - public int getBit(int i) - { - if (i < 0) - { - throw new RuntimeException(); - } - if (i > (len - 1)) - { - return 0; - } - return ((value[i >>> 5] & bitMask[i & 0x1f]) != 0) ? 1 : 0; - } - - /** - * Resets the bit at position i. - * - * @param i int - * @throws RuntimeException if (i < 0) || (i > (len - 1)) - */ - public void resetBit(int i) - throws RuntimeException - { - if (i < 0) - { - throw new RuntimeException(); - } - if (i > (len - 1)) - { - return; - } - value[i >>> 5] &= ~bitMask[i & 0x1f]; - } - - /** - * Xors the bit at position i. - * - * @param i int - * @throws RuntimeException if (i < 0) || (i > (len - 1)) - */ - public void xorBit(int i) - throws RuntimeException - { - if (i < 0 || i > (len - 1)) - { - throw new RuntimeException(); - } - value[i >>> 5] ^= bitMask[i & 0x1f]; - } - - /** - * Tests the bit at position i. - * - * @param i the position of the bit to be tested - * @return true if the bit at position i is set (a(i) == - * 1). False if (i < 0) || (i > (len - 1)) - */ - public boolean testBit(int i) - { - if (i < 0) - { - throw new RuntimeException(); - } - if (i > (len - 1)) - { - return false; - } - return (value[i >>> 5] & bitMask[i & 0x1f]) != 0; - } - - /** - * Returns this GF2Polynomial shift-left by 1 in a new GF2Polynomial. - * - * @return a new GF2Polynomial (this << 1) - */ - public GF2Polynomial shiftLeft() - { - GF2Polynomial result = new GF2Polynomial(len + 1, value); - int i; - for (i = result.blocks - 1; i >= 1; i--) - { - result.value[i] <<= 1; - result.value[i] |= result.value[i - 1] >>> 31; - } - result.value[0] <<= 1; - return result; - } - - /** - * Shifts-left this by one and enlarges the size of value if necesary. - */ - public void shiftLeftThis() - { - // @todo This is untested. - int i; - if ((len & 0x1f) == 0) - { // check if blocks increases - len += 1; - blocks += 1; - if (blocks > value.length) - { // enlarge value - int[] bs = new int[blocks]; - System.arraycopy(value, 0, bs, 0, value.length); - value = null; - value = bs; - } - for (i = blocks - 1; i >= 1; i--) - { - value[i] |= value[i - 1] >>> 31; - value[i - 1] <<= 1; - } - } - else - { - len += 1; - for (i = blocks - 1; i >= 1; i--) - { - value[i] <<= 1; - value[i] |= value[i - 1] >>> 31; - } - value[0] <<= 1; - } - } - - /** - * Returns this GF2Polynomial shift-left by k in a new - * GF2Polynomial. - * - * @param k int - * @return a new GF2Polynomial (this << k) - */ - public GF2Polynomial shiftLeft(int k) - { - // Variant 2, requiring a modified shiftBlocksLeft(k) - // In case of modification, consider a rename to doShiftBlocksLeft() - // with an explicit note that this method assumes that the polynomial - // has already been resized. Or consider doing things inline. - // Construct the resulting polynomial of appropriate length: - GF2Polynomial result = new GF2Polynomial(len + k, value); - // Shift left as many multiples of the block size as possible: - if (k >= 32) - { - result.doShiftBlocksLeft(k >>> 5); - } - // Shift left by the remaining (<32) amount: - final int remaining = k & 0x1f; - if (remaining != 0) - { - for (int i = result.blocks - 1; i >= 1; i--) - { - result.value[i] <<= remaining; - result.value[i] |= result.value[i - 1] >>> (32 - remaining); - } - result.value[0] <<= remaining; - } - return result; - } - - /** - * Shifts left b and adds the result to Its a fast version of - * this = add(b.shl(k)); - * - * @param b GF2Polynomial to shift and add to this - * @param k the amount to shift - * @see GF2nPolynomialElement#invertEEA - */ - public void shiftLeftAddThis(GF2Polynomial b, int k) - { - if (k == 0) - { - addToThis(b); - return; - } - int i; - expandN(b.len + k); - int d = k >>> 5; - for (i = b.blocks - 1; i >= 0; i--) - { - if ((i + d + 1 < blocks) && ((k & 0x1f) != 0)) - { - value[i + d + 1] ^= b.value[i] >>> (32 - (k & 0x1f)); - } - value[i + d] ^= b.value[i] << (k & 0x1f); - } - } - - /** - * Shifts-left this GF2Polynomial's value blockwise 1 block resulting in a - * shift-left by 32. - * - * @see GF2Polynomial#multiply - */ - void shiftBlocksLeft() - { - blocks += 1; - len += 32; - if (blocks <= value.length) - { - int i; - for (i = blocks - 1; i >= 1; i--) - { - value[i] = value[i - 1]; - } - value[0] = 0x00; - } - else - { - int[] result = new int[blocks]; - System.arraycopy(value, 0, result, 1, blocks - 1); - value = null; - value = result; - } - } - - /** - * Shifts left this GF2Polynomial's value blockwise b blocks - * resulting in a shift-left by b*32. This method assumes that {@link #len} - * and {@link #blocks} have already been updated to reflect the final state. - * - * @param b shift amount (in blocks) - */ - private void doShiftBlocksLeft(int b) - { - if (blocks <= value.length) - { - int i; - for (i = blocks - 1; i >= b; i--) - { - value[i] = value[i - b]; - } - for (i = 0; i < b; i++) - { - value[i] = 0x00; - } - } - else - { - int[] result = new int[blocks]; - System.arraycopy(value, 0, result, b, blocks - b); - value = null; - value = result; - } - } - - /** - * Returns this GF2Polynomial shift-right by 1 in a new GF2Polynomial. - * - * @return a new GF2Polynomial (this << 1) - */ - public GF2Polynomial shiftRight() - { - GF2Polynomial result = new GF2Polynomial(len - 1); - int i; - System.arraycopy(value, 0, result.value, 0, result.blocks); - for (i = 0; i <= result.blocks - 2; i++) - { - result.value[i] >>>= 1; - result.value[i] |= result.value[i + 1] << 31; - } - result.value[result.blocks - 1] >>>= 1; - if (result.blocks < blocks) - { - result.value[result.blocks - 1] |= value[result.blocks] << 31; - } - return result; - } - - /** - * Shifts-right this GF2Polynomial by 1. - */ - public void shiftRightThis() - { - int i; - len -= 1; - blocks = ((len - 1) >>> 5) + 1; - for (i = 0; i <= blocks - 2; i++) - { - value[i] >>>= 1; - value[i] |= value[i + 1] << 31; - } - value[blocks - 1] >>>= 1; - if ((len & 0x1f) == 0) - { - value[blocks - 1] |= value[blocks] << 31; - } - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2Vector.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2Vector.java deleted file mode 100644 index b0fa762acd..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2Vector.java +++ /dev/null @@ -1,541 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -import java.security.SecureRandom; - -import org.bouncycastle.util.Arrays; - -/** - * This class implements the abstract class Vector for the case of - * vectors over the finite field GF(2).
    - * For the vector representation the array of type int[] is used, thus one - * element of the array holds 32 elements of the vector. - * - * @see Vector - */ -public class GF2Vector - extends Vector -{ - - /** - * holds the elements of this vector - */ - private int[] v; - - /** - * Construct the zero vector of the given length. - * - * @param length the length of the vector - */ - public GF2Vector(int length) - { - if (length < 0) - { - throw new ArithmeticException("Negative length."); - } - this.length = length; - v = new int[(length + 31) >> 5]; - } - - /** - * Construct a random GF2Vector of the given length. - * - * @param length the length of the vector - * @param sr the source of randomness - */ - public GF2Vector(int length, SecureRandom sr) - { - this.length = length; - - int size = (length + 31) >> 5; - v = new int[size]; - - // generate random elements - for (int i = size - 1; i >= 0; i--) - { - v[i] = sr.nextInt(); - } - - // erase unused bits - int r = length & 0x1f; - if (r != 0) - { - // erase unused bits - v[size - 1] &= (1 << r) - 1; - } - } - - /** - * Construct a random GF2Vector of the given length with the specified - * number of non-zero coefficients. - * - * @param length the length of the vector - * @param t the number of non-zero coefficients - * @param sr the source of randomness - */ - public GF2Vector(int length, int t, SecureRandom sr) - { - if (t > length) - { - throw new ArithmeticException( - "The hamming weight is greater than the length of vector."); - } - this.length = length; - - int size = (length + 31) >> 5; - v = new int[size]; - - int[] help = new int[length]; - for (int i = 0; i < length; i++) - { - help[i] = i; - } - - int m = length; - for (int i = 0; i < t; i++) - { - int j = RandUtils.nextInt(sr, m); - setBit(help[j]); - m--; - help[j] = help[m]; - } - } - - /** - * Construct a GF2Vector of the given length and with elements from the - * given array. The array is copied and unused bits are masked out. - * - * @param length the length of the vector - * @param v the element array - */ - public GF2Vector(int length, int[] v) - { - if (length < 0) - { - throw new ArithmeticException("negative length"); - } - this.length = length; - - int size = (length + 31) >> 5; - - if (v.length != size) - { - throw new ArithmeticException("length mismatch"); - } - - this.v = IntUtils.clone(v); - - int r = length & 0x1f; - if (r != 0) - { - // erase unused bits - this.v[size - 1] &= (1 << r) - 1; - } - } - - /** - * Copy constructor. - * - * @param other another {@link GF2Vector} - */ - public GF2Vector(GF2Vector other) - { - this.length = other.length; - this.v = IntUtils.clone(other.v); - } - - /** - * Construct a new {@link GF2Vector} of the given length and with the given - * element array. The array is not changed and only a reference to the array - * is stored. No length checking is performed either. - * - * @param v the element array - * @param length the length of the vector - */ - protected GF2Vector(int[] v, int length) - { - this.v = v; - this.length = length; - } - - /** - * Construct a new GF2Vector with the given length out of the encoded - * vector. - * - * @param length the length of the vector - * @param encVec the encoded vector - * @return the decoded vector - */ - public static GF2Vector OS2VP(int length, byte[] encVec) - { - if (length < 0) - { - throw new ArithmeticException("negative length"); - } - - int byteLen = (length + 7) >> 3; - - if (encVec.length > byteLen) - { - throw new ArithmeticException("length mismatch"); - } - - return new GF2Vector(length, LittleEndianConversions.toIntArray(encVec)); - } - - /** - * Encode this vector as byte array. - * - * @return the encoded vector - */ - public byte[] getEncoded() - { - int byteLen = (length + 7) >> 3; - return LittleEndianConversions.toByteArray(v, byteLen); - } - - /** - * @return the int array representation of this vector - */ - public int[] getVecArray() - { - return v; - } - - /** - * Return the Hamming weight of this vector, i.e., compute the number of - * units of this vector. - * - * @return the Hamming weight of this vector - */ - public int getHammingWeight() - { - int weight = 0; - for (int i = 0; i < v.length; i++) - { - int e = v[i]; - for (int j = 0; j < 32; j++) - { - int b = e & 1; - if (b != 0) - { - weight++; - } - e >>>= 1; - } - } - return weight; - } - - /** - * @return whether this is the zero vector (i.e., all elements are zero) - */ - public boolean isZero() - { - for (int i = v.length - 1; i >= 0; i--) - { - if (v[i] != 0) - { - return false; - } - } - return true; - } - - /** - * Return the value of the bit of this vector at the specified index. - * - * @param index the index - * @return the value of the bit (0 or 1) - */ - public int getBit(int index) - { - if (index >= length) - { - throw new IndexOutOfBoundsException(); - } - int q = index >> 5; - int r = index & 0x1f; - return (v[q] & (1 << r)) >>> r; - } - - /** - * Set the coefficient at the given index to 1. If the index is out of - * bounds, do nothing. - * - * @param index the index of the coefficient to set - */ - public void setBit(int index) - { - if (index >= length) - { - throw new IndexOutOfBoundsException(); - } - v[index >> 5] |= 1 << (index & 0x1f); - } - - /** - * Adds another GF2Vector to this vector. - * - * @param other another GF2Vector - * @return this + other - * @throws ArithmeticException if the other vector is not a GF2Vector or has another - * length. - */ - public Vector add(Vector other) - { - if (!(other instanceof GF2Vector)) - { - throw new ArithmeticException("vector is not defined over GF(2)"); - } - - GF2Vector otherVec = (GF2Vector)other; - if (length != otherVec.length) - { - throw new ArithmeticException("length mismatch"); - } - - int[] vec = IntUtils.clone(((GF2Vector)other).v); - - for (int i = vec.length - 1; i >= 0; i--) - { - vec[i] ^= v[i]; - } - - return new GF2Vector(length, vec); - } - - /** - * Multiply this vector with a permutation. - * - * @param p the permutation - * @return this*p = p*this - */ - public Vector multiply(Permutation p) - { - int[] pVec = p.getVector(); - if (length != pVec.length) - { - throw new ArithmeticException("length mismatch"); - } - - GF2Vector result = new GF2Vector(length); - - for (int i = 0; i < pVec.length; i++) - { - int e = v[pVec[i] >> 5] & (1 << (pVec[i] & 0x1f)); - if (e != 0) - { - result.v[i >> 5] |= 1 << (i & 0x1f); - } - } - - return result; - } - - /** - * Return a new vector consisting of the elements of this vector with the - * indices given by the set setJ. - * - * @param setJ the set of indices of elements to extract - * @return the new {@link GF2Vector} - * [this_setJ[0], this_setJ[1], ..., this_setJ[#setJ-1]] - */ - public GF2Vector extractVector(int[] setJ) - { - int k = setJ.length; - if (setJ[k - 1] > length) - { - throw new ArithmeticException("invalid index set"); - } - - GF2Vector result = new GF2Vector(k); - - for (int i = 0; i < k; i++) - { - int e = v[setJ[i] >> 5] & (1 << (setJ[i] & 0x1f)); - if (e != 0) - { - result.v[i >> 5] |= 1 << (i & 0x1f); - } - } - - return result; - } - - /** - * Return a new vector consisting of the first k elements of this - * vector. - * - * @param k the number of elements to extract - * @return a new {@link GF2Vector} consisting of the first k - * elements of this vector - */ - public GF2Vector extractLeftVector(int k) - { - if (k > length) - { - throw new ArithmeticException("invalid length"); - } - - if (k == length) - { - return new GF2Vector(this); - } - - GF2Vector result = new GF2Vector(k); - - int q = k >> 5; - int r = k & 0x1f; - - System.arraycopy(v, 0, result.v, 0, q); - if (r != 0) - { - result.v[q] = v[q] & ((1 << r) - 1); - } - - return result; - } - - /** - * Return a new vector consisting of the last k elements of this - * vector. - * - * @param k the number of elements to extract - * @return a new {@link GF2Vector} consisting of the last k - * elements of this vector - */ - public GF2Vector extractRightVector(int k) - { - if (k > length) - { - throw new ArithmeticException("invalid length"); - } - - if (k == length) - { - return new GF2Vector(this); - } - - GF2Vector result = new GF2Vector(k); - - int q = (length - k) >> 5; - int r = (length - k) & 0x1f; - int length = (k + 31) >> 5; - - int ind = q; - // if words have to be shifted - if (r != 0) - { - // process all but last word - for (int i = 0; i < length - 1; i++) - { - result.v[i] = (v[ind++] >>> r) | (v[ind] << (32 - r)); - } - // process last word - result.v[length - 1] = v[ind++] >>> r; - if (ind < v.length) - { - result.v[length - 1] |= v[ind] << (32 - r); - } - } - else - { - // no shift necessary - System.arraycopy(v, q, result.v, 0, length); - } - - return result; - } - - /** - * Rewrite this vector as a vector over GF(2m) with - * t elements. - * - * @param field the finite field GF(2m) - * @return the converted vector over GF(2m) - */ - public GF2mVector toExtensionFieldVector(GF2mField field) - { - int m = field.getDegree(); - if ((length % m) != 0) - { - throw new ArithmeticException("conversion is impossible"); - } - - int t = length / m; - int[] result = new int[t]; - int count = 0; - for (int i = t - 1; i >= 0; i--) - { - for (int j = field.getDegree() - 1; j >= 0; j--) - { - int q = count >>> 5; - int r = count & 0x1f; - - int e = (v[q] >>> r) & 1; - if (e == 1) - { - result[i] ^= 1 << j; - } - count++; - } - } - return new GF2mVector(field, result); - } - - /** - * Check if the given object is equal to this vector. - * - * @param other vector - * @return the result of the comparison - */ - public boolean equals(Object other) - { - - if (!(other instanceof GF2Vector)) - { - return false; - } - GF2Vector otherVec = (GF2Vector)other; - - return (length == otherVec.length) && IntUtils.equals(v, otherVec.v); - } - - /** - * @return the hash code of this vector - */ - public int hashCode() - { - int hash = length; - hash = hash * 31 + Arrays.hashCode(v); - return hash; - } - - /** - * @return a human readable form of this vector - */ - public String toString() - { - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < length; i++) - { - if ((i != 0) && ((i & 0x1f) == 0)) - { - buf.append(' '); - } - int q = i >> 5; - int r = i & 0x1f; - int bit = v[q] & (1 << r); - if (bit == 0) - { - buf.append('0'); - } - else - { - buf.append('1'); - } - } - return buf.toString(); - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2mField.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2mField.java deleted file mode 100644 index 35e85b1732..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2mField.java +++ /dev/null @@ -1,371 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CryptoServicesRegistrar; - -/** - * This class describes operations with elements from the finite field F = - * GF(2^m). ( GF(2^m)= GF(2)[A] where A is a root of irreducible polynomial with - * degree m, each field element B has a polynomial basis representation, i.e. it - * is represented by a different binary polynomial of degree less than m, B = - * poly(A) ) All operations are defined only for field with 1< m <32. For the - * representation of field elements the map f: F->Z, poly(A)->poly(2) is used, - * where integers have the binary representation. For example: A^7+A^3+A+1 -> - * (00...0010001011)=139 Also for elements type Integer is used. - * - * @see PolynomialRingGF2 - */ -public class GF2mField -{ - - /* - * degree - degree of the field polynomial - the field polynomial ring - - * polynomial ring over the finite field GF(2) - */ - - private int degree = 0; - - private int polynomial; - - /** - * create a finite field GF(2^m) - * - * @param degree the degree of the field - */ - public GF2mField(int degree) - { - if (degree >= 32) - { - throw new IllegalArgumentException( - " Error: the degree of field is too large "); - } - if (degree < 1) - { - throw new IllegalArgumentException( - " Error: the degree of field is non-positive "); - } - this.degree = degree; - polynomial = PolynomialRingGF2.getIrreduciblePolynomial(degree); - } - - /** - * create a finite field GF(2^m) with the fixed field polynomial - * - * @param degree the degree of the field - * @param poly the field polynomial - */ - public GF2mField(int degree, int poly) - { - if (degree != PolynomialRingGF2.degree(poly)) - { - throw new IllegalArgumentException( - " Error: the degree is not correct"); - } - if (!PolynomialRingGF2.isIrreducible(poly)) - { - throw new IllegalArgumentException( - " Error: given polynomial is reducible"); - } - this.degree = degree; - polynomial = poly; - - } - - public GF2mField(byte[] enc) - { - if (enc.length != 4) - { - throw new IllegalArgumentException( - "byte array is not an encoded finite field"); - } - polynomial = LittleEndianConversions.OS2IP(enc); - if (!PolynomialRingGF2.isIrreducible(polynomial)) - { - throw new IllegalArgumentException( - "byte array is not an encoded finite field"); - } - - degree = PolynomialRingGF2.degree(polynomial); - } - - public GF2mField(GF2mField field) - { - degree = field.degree; - polynomial = field.polynomial; - } - - /** - * return degree of the field - * - * @return degree of the field - */ - public int getDegree() - { - return degree; - } - - /** - * return the field polynomial - * - * @return the field polynomial - */ - public int getPolynomial() - { - return polynomial; - } - - /** - * return the encoded form of this field - * - * @return the field in byte array form - */ - public byte[] getEncoded() - { - return LittleEndianConversions.I2OSP(polynomial); - } - - /** - * Return sum of two elements - * - * @param a - * @param b - * @return a+b - */ - public int add(int a, int b) - { - return a ^ b; - } - - /** - * Return product of two elements - * - * @param a - * @param b - * @return a*b - */ - public int mult(int a, int b) - { - return PolynomialRingGF2.modMultiply(a, b, polynomial); - } - - /** - * compute exponentiation a^k - * - * @param a a field element a - * @param k k degree - * @return a^k - */ - public int exp(int a, int k) - { - if (k == 0) - { - return 1; - } - if (a == 0) - { - return 0; - } - if (a == 1) - { - return 1; - } - int result = 1; - if (k < 0) - { - a = inverse(a); - k = -k; - } - while (k != 0) - { - if ((k & 1) == 1) - { - result = mult(result, a); - } - a = mult(a, a); - k >>>= 1; - } - return result; - } - - /** - * compute the multiplicative inverse of a - * - * @param a a field element a - * @return a-1 - */ - public int inverse(int a) - { - int d = (1 << degree) - 2; - - return exp(a, d); - } - - /** - * compute the square root of an integer - * - * @param a a field element a - * @return a1/2 - */ - public int sqRoot(int a) - { - for (int i = 1; i < degree; i++) - { - a = mult(a, a); - } - return a; - } - - /** - * create a random field element using PRNG sr - * - * @param sr SecureRandom - * @return a random element - */ - public int getRandomElement(SecureRandom sr) - { - int result = RandUtils.nextInt(sr, 1 << degree); - return result; - } - - /** - * create a random non-zero field element - * - * @return a random element - */ - public int getRandomNonZeroElement() - { - return getRandomNonZeroElement(CryptoServicesRegistrar.getSecureRandom()); - } - - /** - * create a random non-zero field element using PRNG sr - * - * @param sr SecureRandom - * @return a random non-zero element - */ - public int getRandomNonZeroElement(SecureRandom sr) - { - int controltime = 1 << 20; - int count = 0; - int result = RandUtils.nextInt(sr, 1 << degree); - while ((result == 0) && (count < controltime)) - { - result = RandUtils.nextInt(sr, 1 << degree); - count++; - } - if (count == controltime) - { - result = 1; - } - return result; - } - - /** - * @return true if e is encoded element of this field and false otherwise - */ - public boolean isElementOfThisField(int e) - { - // e is encoded element of this field iff 0<= e < |2^m| - if (degree == 31) - { - return e >= 0; - } - return e >= 0 && e < (1 << degree); - } - - /* - * help method for visual control - */ - public String elementToStr(int a) - { - String s = ""; - for (int i = 0; i < degree; i++) - { - if (((byte)a & 0x01) == 0) - { - s = "0" + s; - } - else - { - s = "1" + s; - } - a >>>= 1; - } - return s; - } - - /** - * checks if given object is equal to this field. - *

    - * The method returns false whenever the given object is not GF2m. - * - * @param other object - * @return true or false - */ - public boolean equals(Object other) - { - if ((other == null) || !(other instanceof GF2mField)) - { - return false; - } - - GF2mField otherField = (GF2mField)other; - - if ((degree == otherField.degree) - && (polynomial == otherField.polynomial)) - { - return true; - } - - return false; - } - - public int hashCode() - { - return polynomial; - } - - /** - * Returns a human readable form of this field. - * - * @return a human readable form of this field. - */ - public String toString() - { - String str = "Finite Field GF(2^" + degree + ") = " + "GF(2)[X]/<" - + polyToString(polynomial) + "> "; - return str; - } - - private static String polyToString(int p) - { - String str = ""; - if (p == 0) - { - str = "0"; - } - else - { - byte b = (byte)(p & 0x01); - if (b == 1) - { - str = "1"; - } - p >>>= 1; - int i = 1; - while (p != 0) - { - b = (byte)(p & 0x01); - if (b == 1) - { - str = str + "+x^" + i; - } - p >>>= 1; - i++; - } - } - return str; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2mMatrix.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2mMatrix.java deleted file mode 100644 index de7cc2963c..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2mMatrix.java +++ /dev/null @@ -1,377 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -/** - * This class describes some operations with matrices over finite field GF(2m) - * with small m (1< m <32). - * - * @see Matrix - */ -public class GF2mMatrix - extends Matrix -{ - - /** - * finite field GF(2^m) - */ - protected GF2mField field; - - /** - * For the matrix representation the array of type int[][] is used, thus - * every element of the array keeps one element of the matrix (element from - * finite field GF(2^m)) - */ - protected int[][] matrix; - - /** - * Constructor. - * - * @param field a finite field GF(2^m) - * @param enc byte[] matrix in byte array form - */ - public GF2mMatrix(GF2mField field, byte[] enc) - { - - this.field = field; - - // decode matrix - int d = 8; - int count = 1; - while (field.getDegree() > d) - { - count++; - d += 8; - } - - if (enc.length < 5) - { - throw new IllegalArgumentException( - " Error: given array is not encoded matrix over GF(2^m)"); - } - - this.numRows = ((enc[3] & 0xff) << 24) ^ ((enc[2] & 0xff) << 16) - ^ ((enc[1] & 0xff) << 8) ^ (enc[0] & 0xff); - - int n = count * this.numRows; - - if ((this.numRows <= 0) || (((enc.length - 4) % n) != 0)) - { - throw new IllegalArgumentException( - " Error: given array is not encoded matrix over GF(2^m)"); - } - - this.numColumns = (enc.length - 4) / n; - - matrix = new int[this.numRows][this.numColumns]; - count = 4; - for (int i = 0; i < this.numRows; i++) - { - for (int j = 0; j < this.numColumns; j++) - { - for (int jj = 0; jj < d; jj += 8) - { - matrix[i][j] ^= (enc[count++] & 0x000000ff) << jj; - } - if (!this.field.isElementOfThisField(matrix[i][j])) - { - throw new IllegalArgumentException( - " Error: given array is not encoded matrix over GF(2^m)"); - } - } - } - } - - /** - * Copy constructor. - * - * @param other another {@link GF2mMatrix} - */ - public GF2mMatrix(GF2mMatrix other) - { - numRows = other.numRows; - numColumns = other.numColumns; - field = other.field; - matrix = new int[numRows][]; - for (int i = 0; i < numRows; i++) - { - matrix[i] = IntUtils.clone(other.matrix[i]); - } - } - - /** - * Constructor. - * - * @param field a finite field GF(2^m) - * @param matrix the matrix as int array. Only the reference is copied. - */ - protected GF2mMatrix(GF2mField field, int[][] matrix) - { - this.field = field; - this.matrix = matrix; - numRows = matrix.length; - numColumns = matrix[0].length; - } - - /** - * @return a byte array encoding of this matrix - */ - public byte[] getEncoded() - { - int d = 8; - int count = 1; - while (field.getDegree() > d) - { - count++; - d += 8; - } - - byte[] bf = new byte[this.numRows * this.numColumns * count + 4]; - bf[0] = (byte)(this.numRows & 0xff); - bf[1] = (byte)((this.numRows >>> 8) & 0xff); - bf[2] = (byte)((this.numRows >>> 16) & 0xff); - bf[3] = (byte)((this.numRows >>> 24) & 0xff); - - count = 4; - for (int i = 0; i < this.numRows; i++) - { - for (int j = 0; j < this.numColumns; j++) - { - for (int jj = 0; jj < d; jj += 8) - { - bf[count++] = (byte)(matrix[i][j] >>> jj); - } - } - } - - return bf; - } - - /** - * Check if this is the zero matrix (i.e., all entries are zero). - * - * @return true if this is the zero matrix - */ - public boolean isZero() - { - for (int i = 0; i < numRows; i++) - { - for (int j = 0; j < numColumns; j++) - { - if (matrix[i][j] != 0) - { - return false; - } - } - } - return true; - } - - /** - * Compute the inverse of this matrix. - * - * @return the inverse of this matrix (newly created). - */ - public Matrix computeInverse() - { - if (numRows != numColumns) - { - throw new ArithmeticException("Matrix is not invertible."); - } - - // clone this matrix - int[][] tmpMatrix = new int[numRows][numRows]; - for (int i = numRows - 1; i >= 0; i--) - { - tmpMatrix[i] = IntUtils.clone(matrix[i]); - } - - // initialize inverse matrix as unit matrix - int[][] invMatrix = new int[numRows][numRows]; - for (int i = numRows - 1; i >= 0; i--) - { - invMatrix[i][i] = 1; - } - - // simultaneously compute Gaussian reduction of tmpMatrix and unit - // matrix - for (int i = 0; i < numRows; i++) - { - // if diagonal element is zero - if (tmpMatrix[i][i] == 0) - { - boolean foundNonZero = false; - // find a non-zero element in the same column - for (int j = i + 1; j < numRows; j++) - { - if (tmpMatrix[j][i] != 0) - { - // found it, swap rows ... - foundNonZero = true; - swapColumns(tmpMatrix, i, j); - swapColumns(invMatrix, i, j); - // ... and quit searching - j = numRows; - continue; - } - } - // if no non-zero element was found - if (!foundNonZero) - { - // the matrix is not invertible - throw new ArithmeticException("Matrix is not invertible."); - } - } - - // normalize i-th row - int coef = tmpMatrix[i][i]; - int invCoef = field.inverse(coef); - multRowWithElementThis(tmpMatrix[i], invCoef); - multRowWithElementThis(invMatrix[i], invCoef); - - // normalize all other rows - for (int j = 0; j < numRows; j++) - { - if (j != i) - { - coef = tmpMatrix[j][i]; - if (coef != 0) - { - int[] tmpRow = multRowWithElement(tmpMatrix[i], coef); - int[] tmpInvRow = multRowWithElement(invMatrix[i], coef); - addToRow(tmpRow, tmpMatrix[j]); - addToRow(tmpInvRow, invMatrix[j]); - } - } - } - } - - return new GF2mMatrix(field, invMatrix); - } - - private static void swapColumns(int[][] matrix, int first, int second) - { - int[] tmp = matrix[first]; - matrix[first] = matrix[second]; - matrix[second] = tmp; - } - - private void multRowWithElementThis(int[] row, int element) - { - for (int i = row.length - 1; i >= 0; i--) - { - row[i] = field.mult(row[i], element); - } - } - - private int[] multRowWithElement(int[] row, int element) - { - int[] result = new int[row.length]; - for (int i = row.length - 1; i >= 0; i--) - { - result[i] = field.mult(row[i], element); - } - return result; - } - - /** - * Add one row to another. - * - * @param fromRow the addend - * @param toRow the row to add to - */ - private void addToRow(int[] fromRow, int[] toRow) - { - for (int i = toRow.length - 1; i >= 0; i--) - { - toRow[i] = field.add(fromRow[i], toRow[i]); - } - } - - public Matrix rightMultiply(Matrix a) - { - throw new RuntimeException("Not implemented."); - } - - public Matrix rightMultiply(Permutation perm) - { - throw new RuntimeException("Not implemented."); - } - - public Vector leftMultiply(Vector vector) - { - throw new RuntimeException("Not implemented."); - } - - public Vector rightMultiply(Vector vector) - { - throw new RuntimeException("Not implemented."); - } - - /** - * Checks if given object is equal to this matrix. The method returns false - * whenever the given object is not a matrix over GF(2^m). - * - * @param other object - * @return true or false - */ - public boolean equals(Object other) - { - - if (other == null || !(other instanceof GF2mMatrix)) - { - return false; - } - - GF2mMatrix otherMatrix = (GF2mMatrix)other; - - if ((!this.field.equals(otherMatrix.field)) - || (otherMatrix.numRows != this.numColumns) - || (otherMatrix.numColumns != this.numColumns)) - { - return false; - } - - for (int i = 0; i < this.numRows; i++) - { - for (int j = 0; j < this.numColumns; j++) - { - if (this.matrix[i][j] != otherMatrix.matrix[i][j]) - { - return false; - } - } - } - - return true; - } - - public int hashCode() - { - int hash = (this.field.hashCode() * 31 + numRows) * 31 + numColumns; - for (int i = 0; i < this.numRows; i++) - { - for (int j = 0; j < this.numColumns; j++) - { - hash = hash * 31 + matrix[i][j]; - } - } - return hash; - } - - public String toString() - { - String str = this.numRows + " x " + this.numColumns + " Matrix over " - + this.field.toString() + ": \n"; - - for (int i = 0; i < this.numRows; i++) - { - for (int j = 0; j < this.numColumns; j++) - { - str = str + this.field.elementToStr(matrix[i][j]) + " : "; - } - str = str + "\n"; - } - - return str; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2mVector.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2mVector.java deleted file mode 100644 index 73f4192b4a..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2mVector.java +++ /dev/null @@ -1,258 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - - -import org.bouncycastle.util.Arrays; - -/** - * This class implements vectors over the finite field - * GF(2m) for small m (i.e., - * 1<m<32). It extends the abstract class {@link Vector}. - */ -public class GF2mVector - extends Vector -{ - - /** - * the finite field this vector is defined over - */ - private GF2mField field; - - /** - * the element array - */ - private int[] vector; - - /** - * creates the vector over GF(2^m) of given length and with elements from - * array v (beginning at the first bit) - * - * @param field finite field - * @param v array with elements of vector - */ - public GF2mVector(GF2mField field, byte[] v) - { - this.field = new GF2mField(field); - - // decode vector - int d = 8; - int count = 1; - while (field.getDegree() > d) - { - count++; - d += 8; - } - - if ((v.length % count) != 0) - { - throw new IllegalArgumentException( - "Byte array is not an encoded vector over the given finite field."); - } - - length = v.length / count; - vector = new int[length]; - count = 0; - for (int i = 0; i < vector.length; i++) - { - for (int j = 0; j < d; j += 8) - { - vector[i] |= (v[count++] & 0xff) << j; - } - if (!field.isElementOfThisField(vector[i])) - { - throw new IllegalArgumentException( - "Byte array is not an encoded vector over the given finite field."); - } - } - } - - /** - * Create a new vector over GF(2m) of the given - * length and element array. - * - * @param field the finite field GF(2m) - * @param vector the element array - */ - public GF2mVector(GF2mField field, int[] vector) - { - this.field = field; - length = vector.length; - for (int i = vector.length - 1; i >= 0; i--) - { - if (!field.isElementOfThisField(vector[i])) - { - throw new ArithmeticException( - "Element array is not specified over the given finite field."); - } - } - this.vector = IntUtils.clone(vector); - } - - /** - * Copy constructor. - * - * @param other another {@link GF2mVector} - */ - public GF2mVector(GF2mVector other) - { - field = new GF2mField(other.field); - length = other.length; - vector = IntUtils.clone(other.vector); - } - - /** - * @return the finite field this vector is defined over - */ - public GF2mField getField() - { - return field; - } - - /** - * @return int[] form of this vector - */ - public int[] getIntArrayForm() - { - return IntUtils.clone(vector); - } - - /** - * @return a byte array encoding of this vector - */ - public byte[] getEncoded() - { - int d = 8; - int count = 1; - while (field.getDegree() > d) - { - count++; - d += 8; - } - - byte[] res = new byte[vector.length * count]; - count = 0; - for (int i = 0; i < vector.length; i++) - { - for (int j = 0; j < d; j += 8) - { - res[count++] = (byte)(vector[i] >>> j); - } - } - - return res; - } - - /** - * @return whether this is the zero vector (i.e., all elements are zero) - */ - public boolean isZero() - { - for (int i = vector.length - 1; i >= 0; i--) - { - if (vector[i] != 0) - { - return false; - } - } - return true; - } - - /** - * Add another vector to this vector. Method is not yet implemented. - * - * @param addend the other vector - * @return this + addend - * @throws ArithmeticException if the other vector is not defined over the same field as - * this vector. - *

    - * TODO: implement this method - */ - public Vector add(Vector addend) - { - throw new RuntimeException("not implemented"); - } - - /** - * Multiply this vector with a permutation. - * - * @param p the permutation - * @return this*p = p*this - */ - public Vector multiply(Permutation p) - { - int[] pVec = p.getVector(); - if (length != pVec.length) - { - throw new ArithmeticException( - "permutation size and vector size mismatch"); - } - - int[] result = new int[length]; - for (int i = 0; i < pVec.length; i++) - { - result[i] = vector[pVec[i]]; - } - - return new GF2mVector(field, result); - } - - /** - * Compare this vector with another object. - * - * @param other the other object - * @return the result of the comparison - */ - public boolean equals(Object other) - { - - if (!(other instanceof GF2mVector)) - { - return false; - } - GF2mVector otherVec = (GF2mVector)other; - - if (!field.equals(otherVec.field)) - { - return false; - } - - return IntUtils.equals(vector, otherVec.vector); - } - - /** - * @return the hash code of this vector - */ - public int hashCode() - { - int hash = this.field.hashCode(); - hash = hash * 31 + Arrays.hashCode(vector); - return hash; - } - - /** - * @return a human readable form of this vector - */ - public String toString() - { - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < vector.length; i++) - { - for (int j = 0; j < field.getDegree(); j++) - { - int r = j & 0x1f; - int bitMask = 1 << r; - int coeff = vector[i] & bitMask; - if (coeff != 0) - { - buf.append('1'); - } - else - { - buf.append('0'); - } - } - buf.append(' '); - } - return buf.toString(); - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nElement.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nElement.java deleted file mode 100644 index 9bc8521e16..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nElement.java +++ /dev/null @@ -1,178 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - - -/** - * This abstract class implements an element of the finite field GF(2)n - * in either optimal normal basis representation (ONB) - * or in polynomial representation. It is extended by the classes GF2nONBElement and GF2nPolynomialElement . - * - * @see GF2nPolynomialElement - * @see GF2nONBElement - * @see GF2nONBField - */ -public abstract class GF2nElement - implements GFElement -{ - - // ///////////////////////////////////////////////////////////////////// - // member variables - // ///////////////////////////////////////////////////////////////////// - - /** - * holds a pointer to this element's corresponding field. - */ - protected GF2nField mField; - - /** - * holds the extension degree n of this element's corresponding - * field. - */ - protected int mDegree; - - // ///////////////////////////////////////////////////////////////////// - // pseudo-constructors - // ///////////////////////////////////////////////////////////////////// - - /** - * @return a copy of this GF2nElement - */ - public abstract Object clone(); - - // ///////////////////////////////////////////////////////////////////// - // assignments - // ///////////////////////////////////////////////////////////////////// - - /** - * Assign the value 0 to this element. - */ - abstract void assignZero(); - - /** - * Assigns the value 1 to this element. - */ - abstract void assignOne(); - - // ///////////////////////////////////////////////////////////////////// - // access - // ///////////////////////////////////////////////////////////////////// - - /** - * Returns whether the rightmost bit of the bit representation is set. This - * is needed for data conversion according to 1363. - * - * @return true if the rightmost bit of this element is set - */ - public abstract boolean testRightmostBit(); - - /** - * Checks whether the indexed bit of the bit representation is set - * - * @param index the index of the bit to test - * @return true if the indexed bit is set - */ - abstract boolean testBit(int index); - - /** - * Returns the field of this element. - * - * @return the field of this element - */ - public final GF2nField getField() - { - return mField; - } - - // ///////////////////////////////////////////////////////////////////// - // arithmetic - // ///////////////////////////////////////////////////////////////////// - - /** - * Returns this element + 1. - * - * @return this + 1 - */ - public abstract GF2nElement increase(); - - /** - * Increases this element by one. - */ - public abstract void increaseThis(); - - /** - * Compute the difference of this element and minuend. - * - * @param minuend the minuend - * @return this - minuend (newly created) - */ - public final GFElement subtract(GFElement minuend) - { - return add(minuend); - } - - /** - * Compute the difference of this element and minuend, - * overwriting this element. - * - * @param minuend the minuend - */ - public final void subtractFromThis(GFElement minuend) - { - addToThis(minuend); - } - - /** - * Returns this element to the power of 2. - * - * @return this2 - */ - public abstract GF2nElement square(); - - /** - * Squares this element. - */ - public abstract void squareThis(); - - /** - * Compute the square root of this element and return the result in a new - * {@link GF2nElement}. - * - * @return this1/2 (newly created) - */ - public abstract GF2nElement squareRoot(); - - /** - * Compute the square root of this element. - */ - public abstract void squareRootThis(); - - /** - * Performs a basis transformation of this element to the given GF2nField - * basis. - * - * @param basis the GF2nField representation to transform this element to - * @return this element in the representation of basis - */ - public final GF2nElement convert(GF2nField basis) - { - return mField.convert(this, basis); - } - - /** - * Returns the trace of this element. - * - * @return the trace of this element - */ - public abstract int trace(); - - /** - * Solves a quadratic equation.
    - * Let z2 + z = this. Then this method returns z. - * - * @return z with z2 + z = this - */ - public abstract GF2nElement solveQuadraticEquation() - throws RuntimeException; - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nField.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nField.java deleted file mode 100644 index 51e2b6e96f..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nField.java +++ /dev/null @@ -1,291 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - - -import java.security.SecureRandom; -import java.util.Vector; - - -/** - * This abstract class defines the finite field GF(2n). It - * holds the extension degree n, the characteristic, the irreducible - * fieldpolynomial and conversion matrices. GF2nField is implemented by the - * classes GF2nPolynomialField and GF2nONBField. - * - * @see GF2nONBField - * @see GF2nPolynomialField - */ -public abstract class GF2nField -{ - - protected final SecureRandom random; - - /** - * the degree of this field - */ - protected int mDegree; - - /** - * the irreducible fieldPolynomial stored in normal order (also for ONB) - */ - protected GF2Polynomial fieldPolynomial; - - /** - * holds a list of GF2nFields to which elements have been converted and thus - * a COB-Matrix exists - */ - protected Vector fields; - - /** - * the COB matrices - */ - protected Vector matrices; - - protected GF2nField(SecureRandom random) - { - this.random = random; - } - - /** - * Returns the degree n of this field. - * - * @return the degree n of this field - */ - public final int getDegree() - { - return mDegree; - } - - /** - * Returns the fieldpolynomial as a new Bitstring. - * - * @return a copy of the fieldpolynomial as a new Bitstring - */ - public final GF2Polynomial getFieldPolynomial() - { - if (fieldPolynomial == null) - { - computeFieldPolynomial(); - } - return new GF2Polynomial(fieldPolynomial); - } - - /** - * Decides whether the given object other is the same as this - * field. - * - * @param other another object - * @return (this = = other) - */ - public final boolean equals(Object other) - { - if (other == null || !(other instanceof GF2nField)) - { - return false; - } - - GF2nField otherField = (GF2nField)other; - - if (otherField.mDegree != mDegree) - { - return false; - } - if (!fieldPolynomial.equals(otherField.fieldPolynomial)) - { - return false; - } - if ((this instanceof GF2nPolynomialField) - && !(otherField instanceof GF2nPolynomialField)) - { - return false; - } - if ((this instanceof GF2nONBField) - && !(otherField instanceof GF2nONBField)) - { - return false; - } - return true; - } - - /** - * @return the hash code of this field - */ - public int hashCode() - { - return mDegree + fieldPolynomial.hashCode(); - } - - /** - * Computes a random root from the given irreducible fieldpolynomial - * according to IEEE 1363 algorithm A.5.6. This cal take very long for big - * degrees. - * - * @param B0FieldPolynomial the fieldpolynomial if the other basis as a Bitstring - * @return a random root of BOFieldPolynomial in representation according to - * this field - * @see "P1363 A.5.6, p103f" - */ - protected abstract GF2nElement getRandomRoot(GF2Polynomial B0FieldPolynomial); - - /** - * Computes the change-of-basis matrix for basis conversion according to - * 1363. The result is stored in the lists fields and matrices. - * - * @param B1 the GF2nField to convert to - * @see "P1363 A.7.3, p111ff" - */ - protected abstract void computeCOBMatrix(GF2nField B1); - - /** - * Computes the fieldpolynomial. This can take a long time for big degrees. - */ - protected abstract void computeFieldPolynomial(); - - /** - * Inverts the given matrix represented as bitstrings. - * - * @param matrix the matrix to invert as a Bitstring[] - * @return matrix^(-1) - */ - protected final GF2Polynomial[] invertMatrix(GF2Polynomial[] matrix) - { - GF2Polynomial[] a = new GF2Polynomial[matrix.length]; - GF2Polynomial[] inv = new GF2Polynomial[matrix.length]; - GF2Polynomial dummy; - int i, j; - // initialize a as a copy of matrix and inv as E(inheitsmatrix) - for (i = 0; i < mDegree; i++) - { - a[i] = new GF2Polynomial(matrix[i]); - inv[i] = new GF2Polynomial(mDegree); - inv[i].setBit(mDegree - 1 - i); - } - // construct triangle matrix so that for each a[i] the first i bits are - // zero - for (i = 0; i < mDegree - 1; i++) - { - // find column where bit i is set - j = i; - while ((j < mDegree) && !a[j].testBit(mDegree - 1 - i)) - { - j++; - } - if (j >= mDegree) - { - throw new RuntimeException( - "GF2nField.invertMatrix: Matrix cannot be inverted!"); - } - if (i != j) - { // swap a[i]/a[j] and inv[i]/inv[j] - dummy = a[i]; - a[i] = a[j]; - a[j] = dummy; - dummy = inv[i]; - inv[i] = inv[j]; - inv[j] = dummy; - } - for (j = i + 1; j < mDegree; j++) - { // add column i to all columns>i - // having their i-th bit set - if (a[j].testBit(mDegree - 1 - i)) - { - a[j].addToThis(a[i]); - inv[j].addToThis(inv[i]); - } - } - } - // construct Einheitsmatrix from a - for (i = mDegree - 1; i > 0; i--) - { - for (j = i - 1; j >= 0; j--) - { // eliminate the i-th bit in all - // columns < i - if (a[j].testBit(mDegree - 1 - i)) - { - a[j].addToThis(a[i]); - inv[j].addToThis(inv[i]); - } - } - } - return inv; - } - - /** - * Converts the given element in representation according to this field to a - * new element in representation according to B1 using the change-of-basis - * matrix calculated by computeCOBMatrix. - * - * @param elem the GF2nElement to convert - * @param basis the basis to convert elem to - * @return elem converted to a new element representation - * according to basis - * @see GF2nField#computeCOBMatrix - * @see GF2nField#getRandomRoot - * @see GF2nPolynomial - * @see "P1363 A.7 p109ff" - */ - public final GF2nElement convert(GF2nElement elem, GF2nField basis) - throws RuntimeException - { - if (basis == this) - { - return (GF2nElement)elem.clone(); - } - if (fieldPolynomial.equals(basis.fieldPolynomial)) - { - return (GF2nElement)elem.clone(); - } - if (mDegree != basis.mDegree) - { - throw new RuntimeException("GF2nField.convert: B1 has a" - + " different degree and thus cannot be coverted to!"); - } - - int i; - GF2Polynomial[] COBMatrix; - i = fields.indexOf(basis); - if (i == -1) - { - computeCOBMatrix(basis); - i = fields.indexOf(basis); - } - COBMatrix = (GF2Polynomial[])matrices.elementAt(i); - - GF2nElement elemCopy = (GF2nElement)elem.clone(); - if (elemCopy instanceof GF2nONBElement) - { - // remember: ONB treats its bits in reverse order - ((GF2nONBElement)elemCopy).reverseOrder(); - } - GF2Polynomial bs = new GF2Polynomial(mDegree, elemCopy.toFlexiBigInt()); - bs.expandN(mDegree); - GF2Polynomial result = new GF2Polynomial(mDegree); - for (i = 0; i < mDegree; i++) - { - if (bs.vectorMult(COBMatrix[i])) - { - result.setBit(mDegree - 1 - i); - } - } - if (basis instanceof GF2nPolynomialField) - { - return new GF2nPolynomialElement((GF2nPolynomialField)basis, - result); - } - else if (basis instanceof GF2nONBField) - { - GF2nONBElement res = new GF2nONBElement((GF2nONBField)basis, - result.toFlexiBigInt()); - // TODO Remember: ONB treats its Bits in reverse order !!! - res.reverseOrder(); - return res; - } - else - { - throw new RuntimeException( - "GF2nField.convert: B1 must be an instance of " - + "GF2nPolynomialField or GF2nONBField!"); - } - - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nONBElement.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nONBElement.java deleted file mode 100644 index 49cc38fda2..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nONBElement.java +++ /dev/null @@ -1,1150 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - - -import java.math.BigInteger; -import java.security.SecureRandom; - -import org.bouncycastle.util.Arrays; - -/** - * This class implements an element of the finite field GF(2n ). - * It is represented in an optimal normal basis representation and holds the - * pointer mField to its corresponding field. - * - * @see GF2nField - * @see GF2nElement - */ -public class GF2nONBElement - extends GF2nElement -{ - - // ///////////////////////////////////////////////////////////////////// - // member variables - // ///////////////////////////////////////////////////////////////////// - - private static final long[] mBitmask = new long[]{0x0000000000000001L, - 0x0000000000000002L, 0x0000000000000004L, 0x0000000000000008L, - 0x0000000000000010L, 0x0000000000000020L, 0x0000000000000040L, - 0x0000000000000080L, 0x0000000000000100L, 0x0000000000000200L, - 0x0000000000000400L, 0x0000000000000800L, 0x0000000000001000L, - 0x0000000000002000L, 0x0000000000004000L, 0x0000000000008000L, - 0x0000000000010000L, 0x0000000000020000L, 0x0000000000040000L, - 0x0000000000080000L, 0x0000000000100000L, 0x0000000000200000L, - 0x0000000000400000L, 0x0000000000800000L, 0x0000000001000000L, - 0x0000000002000000L, 0x0000000004000000L, 0x0000000008000000L, - 0x0000000010000000L, 0x0000000020000000L, 0x0000000040000000L, - 0x0000000080000000L, 0x0000000100000000L, 0x0000000200000000L, - 0x0000000400000000L, 0x0000000800000000L, 0x0000001000000000L, - 0x0000002000000000L, 0x0000004000000000L, 0x0000008000000000L, - 0x0000010000000000L, 0x0000020000000000L, 0x0000040000000000L, - 0x0000080000000000L, 0x0000100000000000L, 0x0000200000000000L, - 0x0000400000000000L, 0x0000800000000000L, 0x0001000000000000L, - 0x0002000000000000L, 0x0004000000000000L, 0x0008000000000000L, - 0x0010000000000000L, 0x0020000000000000L, 0x0040000000000000L, - 0x0080000000000000L, 0x0100000000000000L, 0x0200000000000000L, - 0x0400000000000000L, 0x0800000000000000L, 0x1000000000000000L, - 0x2000000000000000L, 0x4000000000000000L, 0x8000000000000000L}; - - private static final long[] mMaxmask = new long[]{0x0000000000000001L, - 0x0000000000000003L, 0x0000000000000007L, 0x000000000000000FL, - 0x000000000000001FL, 0x000000000000003FL, 0x000000000000007FL, - 0x00000000000000FFL, 0x00000000000001FFL, 0x00000000000003FFL, - 0x00000000000007FFL, 0x0000000000000FFFL, 0x0000000000001FFFL, - 0x0000000000003FFFL, 0x0000000000007FFFL, 0x000000000000FFFFL, - 0x000000000001FFFFL, 0x000000000003FFFFL, 0x000000000007FFFFL, - 0x00000000000FFFFFL, 0x00000000001FFFFFL, 0x00000000003FFFFFL, - 0x00000000007FFFFFL, 0x0000000000FFFFFFL, 0x0000000001FFFFFFL, - 0x0000000003FFFFFFL, 0x0000000007FFFFFFL, 0x000000000FFFFFFFL, - 0x000000001FFFFFFFL, 0x000000003FFFFFFFL, 0x000000007FFFFFFFL, - 0x00000000FFFFFFFFL, 0x00000001FFFFFFFFL, 0x00000003FFFFFFFFL, - 0x00000007FFFFFFFFL, 0x0000000FFFFFFFFFL, 0x0000001FFFFFFFFFL, - 0x0000003FFFFFFFFFL, 0x0000007FFFFFFFFFL, 0x000000FFFFFFFFFFL, - 0x000001FFFFFFFFFFL, 0x000003FFFFFFFFFFL, 0x000007FFFFFFFFFFL, - 0x00000FFFFFFFFFFFL, 0x00001FFFFFFFFFFFL, 0x00003FFFFFFFFFFFL, - 0x00007FFFFFFFFFFFL, 0x0000FFFFFFFFFFFFL, 0x0001FFFFFFFFFFFFL, - 0x0003FFFFFFFFFFFFL, 0x0007FFFFFFFFFFFFL, 0x000FFFFFFFFFFFFFL, - 0x001FFFFFFFFFFFFFL, 0x003FFFFFFFFFFFFFL, 0x007FFFFFFFFFFFFFL, - 0x00FFFFFFFFFFFFFFL, 0x01FFFFFFFFFFFFFFL, 0x03FFFFFFFFFFFFFFL, - 0x07FFFFFFFFFFFFFFL, 0x0FFFFFFFFFFFFFFFL, 0x1FFFFFFFFFFFFFFFL, - 0x3FFFFFFFFFFFFFFFL, 0x7FFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL}; - - // mIBy64[j * 16 + i] = (j * 16 + i)/64 - // i = - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - // - private static final int[] mIBY64 = new int[]{ - // j = - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 8 - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 9 - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 10 - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 11 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 12 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 13 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 14 - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 15 - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 16 - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 17 - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 18 - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 19 - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 20 - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 21 - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 22 - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 // 23 - }; - - private static final int MAXLONG = 64; - - /** - * holds the length of the polynomial with 64 bit sized fields. - */ - private int mLength; - - /** - * holds the value of mDeg % MAXLONG. - */ - private int mBit; - - /** - * holds this element in ONB representation. - */ - private long[] mPol; - - // ///////////////////////////////////////////////////////////////////// - // constructors - // ///////////////////////////////////////////////////////////////////// - - /** - * Construct a random element over the field gf2n, using the - * specified source of randomness. - * - * @param gf2n the field - * @param rand the source of randomness - */ - public GF2nONBElement(GF2nONBField gf2n, SecureRandom rand) - { - mField = gf2n; - mDegree = mField.getDegree(); - mLength = gf2n.getONBLength(); - mBit = gf2n.getONBBit(); - mPol = new long[mLength]; - if (mLength > 1) - { - for (int j = 0; j < mLength - 1; j++) - { - mPol[j] = rand.nextLong(); - } - long last = rand.nextLong(); - mPol[mLength - 1] = last >>> (MAXLONG - mBit); - } - else - { - mPol[0] = rand.nextLong(); - mPol[0] = mPol[0] >>> (MAXLONG - mBit); - } - } - - /** - * Construct a new GF2nONBElement from its encoding. - * - * @param gf2n the field - * @param e the encoded element - */ - public GF2nONBElement(GF2nONBField gf2n, byte[] e) - { - mField = gf2n; - mDegree = mField.getDegree(); - mLength = gf2n.getONBLength(); - mBit = gf2n.getONBBit(); - mPol = new long[mLength]; - assign(e); - } - - /** - * Construct the element of the field gf2n with the specified - * value val. - * - * @param gf2n the field - * @param val the value represented by a BigInteger - */ - public GF2nONBElement(GF2nONBField gf2n, BigInteger val) - { - mField = gf2n; - mDegree = mField.getDegree(); - mLength = gf2n.getONBLength(); - mBit = gf2n.getONBBit(); - mPol = new long[mLength]; - assign(val); - } - - /** - * Construct the element of the field gf2n with the specified - * value val. - * - * @param gf2n the field - * @param val the value in ONB representation - */ - private GF2nONBElement(GF2nONBField gf2n, long[] val) - { - mField = gf2n; - mDegree = mField.getDegree(); - mLength = gf2n.getONBLength(); - mBit = gf2n.getONBBit(); - mPol = val; - } - - // ///////////////////////////////////////////////////////////////////// - // pseudo-constructors - // ///////////////////////////////////////////////////////////////////// - - /** - * Copy constructor. - * - * @param gf2n the field - */ - public GF2nONBElement(GF2nONBElement gf2n) - { - - mField = gf2n.mField; - mDegree = mField.getDegree(); - mLength = ((GF2nONBField)mField).getONBLength(); - mBit = ((GF2nONBField)mField).getONBBit(); - mPol = new long[mLength]; - assign(gf2n.getElement()); - } - - /** - * Create a new GF2nONBElement by cloning this GF2nPolynomialElement. - * - * @return a copy of this element - */ - public Object clone() - { - return new GF2nONBElement(this); - } - - /** - * Create the zero element. - * - * @param gf2n the finite field - * @return the zero element in the given finite field - */ - public static GF2nONBElement ZERO(GF2nONBField gf2n) - { - long[] polynomial = new long[gf2n.getONBLength()]; - return new GF2nONBElement(gf2n, polynomial); - } - - /** - * Create the one element. - * - * @param gf2n the finite field - * @return the one element in the given finite field - */ - public static GF2nONBElement ONE(GF2nONBField gf2n) - { - int mLength = gf2n.getONBLength(); - long[] polynomial = new long[mLength]; - - // fill mDegree coefficients with one's - for (int i = 0; i < mLength - 1; i++) - { - polynomial[i] = 0xffffffffffffffffL; - } - polynomial[mLength - 1] = mMaxmask[gf2n.getONBBit() - 1]; - - return new GF2nONBElement(gf2n, polynomial); - } - - // ///////////////////////////////////////////////////////////////////// - // assignments - // ///////////////////////////////////////////////////////////////////// - - /** - * assigns to this element the zero element - */ - void assignZero() - { - mPol = new long[mLength]; - } - - /** - * assigns to this element the one element - */ - void assignOne() - { - // fill mDegree coefficients with one's - for (int i = 0; i < mLength - 1; i++) - { - mPol[i] = 0xffffffffffffffffL; - } - mPol[mLength - 1] = mMaxmask[mBit - 1]; - } - - /** - * assigns to this element the value val. - * - * @param val the value represented by a BigInteger - */ - private void assign(BigInteger val) - { - assign(val.toByteArray()); - } - - /** - * assigns to this element the value val. - * - * @param val the value in ONB representation - */ - private void assign(long[] val) - { - System.arraycopy(val, 0, mPol, 0, mLength); - } - - /** - * assigns to this element the value val. First: inverting the - * order of val into reversed[]. That means: reversed[0] = val[length - 1], - * ..., reversed[reversed.length - 1] = val[0]. Second: mPol[0] = sum{i = 0, - * ... 7} (val[i]<<(i*8)) .... mPol[1] = sum{i = 8, ... 15} (val[i]<<(i*8)) - * - * @param val the value in ONB representation - */ - private void assign(byte[] val) - { - int j; - mPol = new long[mLength]; - for (j = 0; j < val.length; j++) - { - mPol[j >>> 3] |= (val[val.length - 1 - j] & 0x00000000000000ffL) << ((j & 0x07) << 3); - } - } - - // ///////////////////////////////////////////////////////////////// - // comparison - // ///////////////////////////////////////////////////////////////// - - /** - * Checks whether this element is zero. - * - * @return true if this is the zero element - */ - public boolean isZero() - { - - boolean result = true; - - for (int i = 0; i < mLength && result; i++) - { - result = result && ((mPol[i] & 0xFFFFFFFFFFFFFFFFL) == 0); - } - - return result; - } - - /** - * Checks whether this element is one. - * - * @return true if this is the one element - */ - public boolean isOne() - { - - boolean result = true; - - for (int i = 0; i < mLength - 1 && result; i++) - { - result = result - && ((mPol[i] & 0xFFFFFFFFFFFFFFFFL) == 0xFFFFFFFFFFFFFFFFL); - } - - if (result) - { - result = result - && ((mPol[mLength - 1] & mMaxmask[mBit - 1]) == mMaxmask[mBit - 1]); - } - - return result; - } - - /** - * Compare this element with another object. - * - * @param other the other object - * @return true if the two objects are equal, false - * otherwise - */ - public boolean equals(Object other) - { - if (other == null || !(other instanceof GF2nONBElement)) - { - return false; - } - - GF2nONBElement otherElem = (GF2nONBElement)other; - - for (int i = 0; i < mLength; i++) - { - if (mPol[i] != otherElem.mPol[i]) - { - return false; - } - } - - return true; - } - - /** - * @return the hash code of this element - */ - public int hashCode() - { - return Arrays.hashCode(mPol); - } - - // ///////////////////////////////////////////////////////////////////// - // access - // ///////////////////////////////////////////////////////////////////// - - /** - * Returns whether the highest bit of the bit representation is set - * - * @return true, if the highest bit of mPol is set, false, otherwise - */ - public boolean testRightmostBit() - { - // due to the reverse bit order (compared to 1363) this method returns - // the value of the leftmost bit - return (mPol[mLength - 1] & mBitmask[mBit - 1]) != 0L; - } - - /** - * Checks whether the indexed bit of the bit representation is set. Warning: - * GF2nONBElement currently stores its bits in reverse order (compared to - * 1363) !!! - * - * @param index the index of the bit to test - * @return true if the indexed bit of mPol is set, false - * otherwise. - */ - boolean testBit(int index) - { - if (index < 0 || index > mDegree) - { - return false; - } - long test = mPol[index >>> 6] & mBitmask[index & 0x3f]; - return test != 0x0L; - } - - /** - * @return this element in its ONB representation - */ - private long[] getElement() - { - - long[] result = new long[mPol.length]; - System.arraycopy(mPol, 0, result, 0, mPol.length); - - return result; - } - - /** - * Returns the ONB representation of this element. The Bit-Order is - * exchanged (according to 1363)! - * - * @return this element in its representation and reverse bit-order - */ - private long[] getElementReverseOrder() - { - long[] result = new long[mPol.length]; - for (int i = 0; i < mDegree; i++) - { - if (testBit(mDegree - i - 1)) - { - result[i >>> 6] |= mBitmask[i & 0x3f]; - } - } - return result; - } - - /** - * Reverses the bit-order in this element(according to 1363). This is a - * hack! - */ - void reverseOrder() - { - mPol = getElementReverseOrder(); - } - - // ///////////////////////////////////////////////////////////////////// - // arithmetic - // ///////////////////////////////////////////////////////////////////// - - /** - * Compute the sum of this element and addend. - * - * @param addend the addend - * @return this + other (newly created) - */ - public GFElement add(GFElement addend) - throws RuntimeException - { - GF2nONBElement result = new GF2nONBElement(this); - result.addToThis(addend); - return result; - } - - /** - * Compute this + addend (overwrite this). - * - * @param addend the addend - */ - public void addToThis(GFElement addend) - throws RuntimeException - { - if (!(addend instanceof GF2nONBElement)) - { - throw new RuntimeException(); - } - if (!mField.equals(((GF2nONBElement)addend).mField)) - { - throw new RuntimeException(); - } - - for (int i = 0; i < mLength; i++) - { - mPol[i] ^= ((GF2nONBElement)addend).mPol[i]; - } - } - - /** - * returns this element + 1. - * - * @return this + 1 - */ - public GF2nElement increase() - { - GF2nONBElement result = new GF2nONBElement(this); - result.increaseThis(); - return result; - } - - /** - * increases this element. - */ - public void increaseThis() - { - addToThis(ONE((GF2nONBField)mField)); - } - - /** - * Compute the product of this element and factor. - * - * @param factor the factor - * @return this * factor (newly created) - */ - public GFElement multiply(GFElement factor) - throws RuntimeException - { - GF2nONBElement result = new GF2nONBElement(this); - result.multiplyThisBy(factor); - return result; - } - - /** - * Compute this * factor (overwrite this). - * - * @param factor the factor - */ - public void multiplyThisBy(GFElement factor) - throws RuntimeException - { - - if (!(factor instanceof GF2nONBElement)) - { - throw new RuntimeException("The elements have different" - + " representation: not yet" + " implemented"); - } - if (!mField.equals(((GF2nONBElement)factor).mField)) - { - throw new RuntimeException(); - } - - if (equals(factor)) - { - squareThis(); - } - else - { - - long[] a = mPol; - long[] b = ((GF2nONBElement)factor).mPol; - long[] c = new long[mLength]; - - int[][] m = ((GF2nONBField)mField).mMult; - - int degf, degb, s, fielda, fieldb, bita, bitb; - degf = mLength - 1; - degb = mBit - 1; - s = 0; - - long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1]; - long TWOTODEGB = mBitmask[degb]; - - boolean old, now; - - // the product c of a and b (a*b = c) is calculated in mDegree - // cicles - // in every cicle one coefficient of c is calculated and stored - // k indicates the coefficient - // - for (int k = 0; k < mDegree; k++) - { - - s = 0; - - for (int i = 0; i < mDegree; i++) - { - - // fielda = i / MAXLONG - // - fielda = mIBY64[i]; - - // bita = i % MAXLONG - // - bita = i & (MAXLONG - 1); - - // fieldb = m[i][0] / MAXLONG - // - fieldb = mIBY64[m[i][0]]; - - // bitb = m[i][0] % MAXLONG - // - bitb = m[i][0] & (MAXLONG - 1); - - if ((a[fielda] & mBitmask[bita]) != 0) - { - - if ((b[fieldb] & mBitmask[bitb]) != 0) - { - s ^= 1; - } - - if (m[i][1] != -1) - { - - // fieldb = m[i][1] / MAXLONG - // - fieldb = mIBY64[m[i][1]]; - - // bitb = m[i][1] % MAXLONG - // - bitb = m[i][1] & (MAXLONG - 1); - - if ((b[fieldb] & mBitmask[bitb]) != 0) - { - s ^= 1; - } - - } - } - } - fielda = mIBY64[k]; - bita = k & (MAXLONG - 1); - - if (s != 0) - { - c[fielda] ^= mBitmask[bita]; - } - - // Circular shift of x and y one bit to the right, - // respectively. - - if (mLength > 1) - { - - // Shift x. - // - old = (a[degf] & 1) == 1; - - for (int i = degf - 1; i >= 0; i--) - { - now = (a[i] & 1) != 0; - - a[i] = a[i] >>> 1; - - if (old) - { - a[i] ^= TWOTOMAXLONGM1; - } - - old = now; - } - a[degf] = a[degf] >>> 1; - - if (old) - { - a[degf] ^= TWOTODEGB; - } - - // Shift y. - // - old = (b[degf] & 1) == 1; - - for (int i = degf - 1; i >= 0; i--) - { - now = (b[i] & 1) != 0; - - b[i] = b[i] >>> 1; - - if (old) - { - b[i] ^= TWOTOMAXLONGM1; - } - - old = now; - } - - b[degf] = b[degf] >>> 1; - - if (old) - { - b[degf] ^= TWOTODEGB; - } - } - else - { - old = (a[0] & 1) == 1; - a[0] = a[0] >>> 1; - - if (old) - { - a[0] ^= TWOTODEGB; - } - - old = (b[0] & 1) == 1; - b[0] = b[0] >>> 1; - - if (old) - { - b[0] ^= TWOTODEGB; - } - } - } - assign(c); - } - } - - /** - * returns this element to the power of 2. - * - * @return this2 - */ - public GF2nElement square() - { - GF2nONBElement result = new GF2nONBElement(this); - result.squareThis(); - return result; - } - - /** - * squares this element. - */ - public void squareThis() - { - - long[] pol = getElement(); - - int f = mLength - 1; - int b = mBit - 1; - - // Shift the coefficients one bit to the left. - // - long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1]; - boolean old, now; - - old = (pol[f] & mBitmask[b]) != 0; - - for (int i = 0; i < f; i++) - { - - now = (pol[i] & TWOTOMAXLONGM1) != 0; - - pol[i] = pol[i] << 1; - - if (old) - { - pol[i] ^= 1; - } - - old = now; - } - now = (pol[f] & mBitmask[b]) != 0; - - pol[f] = pol[f] << 1; - - if (old) - { - pol[f] ^= 1; - } - - // Set the bit with index mDegree to zero. - // - if (now) - { - pol[f] ^= mBitmask[b + 1]; - } - - assign(pol); - } - - /** - * Compute the multiplicative inverse of this element. - * - * @return this-1 (newly created) - * @throws ArithmeticException if this is the zero element. - */ - public GFElement invert() - throws ArithmeticException - { - GF2nONBElement result = new GF2nONBElement(this); - result.invertThis(); - return result; - } - - /** - * Multiplicatively invert of this element (overwrite this). - * - * @throws ArithmeticException if this is the zero element. - */ - public void invertThis() - throws ArithmeticException - { - - if (isZero()) - { - throw new ArithmeticException(); - } - int r = 31; // mDegree kann nur 31 Bits lang sein!!! - - // Bitlaenge von mDegree: - for (boolean found = false; !found && r >= 0; r--) - { - - if (((mDegree - 1) & mBitmask[r]) != 0) - { - found = true; - } - } - r++; - - GF2nElement m = ZERO((GF2nONBField)mField); - GF2nElement n = new GF2nONBElement(this); - - int k = 1; - - for (int i = r - 1; i >= 0; i--) - { - m = (GF2nElement)n.clone(); - for (int j = 1; j <= k; j++) - { - m.squareThis(); - } - - n.multiplyThisBy(m); - - k <<= 1; - if (((mDegree - 1) & mBitmask[i]) != 0) - { - n.squareThis(); - - n.multiplyThisBy(this); - - k++; - } - } - n.squareThis(); - } - - /** - * returns the root ofthis element. - * - * @return this1/2 - */ - public GF2nElement squareRoot() - { - GF2nONBElement result = new GF2nONBElement(this); - result.squareRootThis(); - return result; - } - - /** - * square roots this element. - */ - public void squareRootThis() - { - - long[] pol = getElement(); - - int f = mLength - 1; - int b = mBit - 1; - - // Shift the coefficients one bit to the right. - // - long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1]; - boolean old, now; - - old = (pol[0] & 1) != 0; - - for (int i = f; i >= 0; i--) - { - now = (pol[i] & 1) != 0; - pol[i] = pol[i] >>> 1; - - if (old) - { - if (i == f) - { - pol[i] ^= mBitmask[b]; - } - else - { - pol[i] ^= TWOTOMAXLONGM1; - } - } - old = now; - } - assign(pol); - } - - /** - * Returns the trace of this element. - * - * @return the trace of this element - */ - public int trace() - { - - // trace = sum of coefficients - // - - int result = 0; - - int max = mLength - 1; - - for (int i = 0; i < max; i++) - { - - for (int j = 0; j < MAXLONG; j++) - { - - if ((mPol[i] & mBitmask[j]) != 0) - { - result ^= 1; - } - } - } - - int b = mBit; - - for (int j = 0; j < b; j++) - { - - if ((mPol[max] & mBitmask[j]) != 0) - { - result ^= 1; - } - } - return result; - } - - /** - * Solves a quadratic equation.
    - * Let z2 + z = this. Then this method returns z. - * - * @return z with z2 + z = this - */ - public GF2nElement solveQuadraticEquation() - throws RuntimeException - { - - if (trace() == 1) - { - throw new RuntimeException(); - } - - long TWOTOMAXLONGM1 = mBitmask[MAXLONG - 1]; - long ZERO = 0L; - long ONE = 1L; - - long[] p = new long[mLength]; - long z = 0L; - int j = 1; - for (int i = 0; i < mLength - 1; i++) - { - - for (j = 1; j < MAXLONG; j++) - { - - // - if (!((((mBitmask[j] & mPol[i]) != ZERO) && ((z & mBitmask[j - 1]) != ZERO)) || (((mPol[i] & mBitmask[j]) == ZERO) && ((z & mBitmask[j - 1]) == ZERO)))) - { - z ^= mBitmask[j]; - } - } - p[i] = z; - - if (((TWOTOMAXLONGM1 & z) != ZERO && (ONE & mPol[i + 1]) == ONE) - || ((TWOTOMAXLONGM1 & z) == ZERO && (ONE & mPol[i + 1]) == ZERO)) - { - z = ZERO; - } - else - { - z = ONE; - } - } - - int b = mDegree & (MAXLONG - 1); - - long LASTLONG = mPol[mLength - 1]; - - for (j = 1; j < b; j++) - { - if (!((((mBitmask[j] & LASTLONG) != ZERO) && ((mBitmask[j - 1] & z) != ZERO)) || (((mBitmask[j] & LASTLONG) == ZERO) && ((mBitmask[j - 1] & z) == ZERO)))) - { - z ^= mBitmask[j]; - } - } - p[mLength - 1] = z; - return new GF2nONBElement((GF2nONBField)mField, p); - } - - // ///////////////////////////////////////////////////////////////// - // conversion - // ///////////////////////////////////////////////////////////////// - - /** - * Returns a String representation of this element. - * - * @return String representation of this element with the specified radix - */ - public String toString() - { - return toString(16); - } - - /** - * Returns a String representation of this element. radix - * specifies the radix of the String representation.
    - * NOTE: ONLY radix = 2 or radix = 16 IS IMPLEMENTED - * - * @param radix specifies the radix of the String representation - * @return String representation of this element with the specified radix - */ - public String toString(int radix) - { - String s = ""; - - long[] a = getElement(); - int b = mBit; - - if (radix == 2) - { - - for (int j = b - 1; j >= 0; j--) - { - if ((a[a.length - 1] & ((long)1 << j)) == 0) - { - s += "0"; - } - else - { - s += "1"; - } - } - - for (int i = a.length - 2; i >= 0; i--) - { - for (int j = MAXLONG - 1; j >= 0; j--) - { - if ((a[i] & mBitmask[j]) == 0) - { - s += "0"; - } - else - { - s += "1"; - } - } - } - } - else if (radix == 16) - { - final char[] HEX_CHARS = {'0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - for (int i = a.length - 1; i >= 0; i--) - { - s += HEX_CHARS[(int)(a[i] >>> 60) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 56) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 52) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 48) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 44) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 40) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 36) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 32) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 28) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 24) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 20) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 16) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 12) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 8) & 0x0f]; - s += HEX_CHARS[(int)(a[i] >>> 4) & 0x0f]; - s += HEX_CHARS[(int)(a[i]) & 0x0f]; - s += " "; - } - } - return s; - } - - /** - * Returns this element as FlexiBigInt. The conversion is P1363-conform. - * - * @return this element as BigInteger - */ - public BigInteger toFlexiBigInt() - { - /* @todo this method does not reverse the bit-order as it should!!! */ - - return new BigInteger(1, toByteArray()); - } - - /** - * Returns this element as byte array. The conversion is P1363-conform. - * - * @return this element as byte array - */ - public byte[] toByteArray() - { - /* @todo this method does not reverse the bit-order as it should!!! */ - - int k = ((mDegree - 1) >> 3) + 1; - byte[] result = new byte[k]; - int i; - for (i = 0; i < k; i++) - { - result[k - i - 1] = (byte)((mPol[i >>> 3] & (0x00000000000000ffL << ((i & 0x07) << 3))) >>> ((i & 0x07) << 3)); - } - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nONBField.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nONBField.java deleted file mode 100644 index cda949ddc2..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nONBField.java +++ /dev/null @@ -1,547 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - - -import java.security.SecureRandom; -import java.util.Random; -import java.util.Vector; - - -/** - * This class implements the abstract class GF2nField for ONB - * representation. It computes the fieldpolynomial, multiplication matrix and - * one of its roots mONBRoot, (see for example Certicoms Whitepapers). - * GF2nField is used by GF2nONBElement which implements the elements of this - * field. - * - * @see GF2nField - * @see GF2nONBElement - */ -public class GF2nONBField - extends GF2nField -{ - - // /////////////////////////////////////////////////////////////////// - // Hashtable for irreducible normal polynomials // - // /////////////////////////////////////////////////////////////////// - - // i*5 + 0 i*5 + 1 i*5 + 2 i*5 + 3 i*5 + 4 - /* - * private static int[][] mNB = {{0, 0, 0}, {0, 0, 0}, {1, 0, 0}, {1, 0, 0}, - * {1, 0, 0}, // i = 0 {2, 0, 0}, {1, 0, 0}, {1, 0, 0}, {4, 3, 1}, {1, 0, - * 0}, // i = 1 {3, 0, 0}, {2, 0, 0}, {3, 0, 0}, {4, 3, 1}, {5, 0, 0}, // i = - * 2 {1, 0, 0}, {5, 3, 1}, {3, 0, 0}, {3, 0, 0}, {5, 2, 1}, // i = 3 {3, 0, - * 0}, {2, 0, 0}, {1, 0, 0}, {5, 0, 0}, {4, 3, 1}, // i = 4 {3, 0, 0}, {4, - * 3, 1}, {5, 2, 1}, {1, 0, 0}, {2, 0, 0}, // i = 5 {1, 0, 0}, {3, 0, 0}, - * {7, 3, 2}, {10, 0, 0}, {7, 0, 0}, // i = 6 {2, 0, 0}, {9, 0, 0}, {6, 4, - * 1}, {6, 5, 1}, {4, 0, 0}, // i = 7 {5, 4, 3}, {3, 0, 0}, {7, 0, 0}, {6, - * 4, 3}, {5, 0, 0}, // i = 8 {4, 3, 1}, {1, 0, 0}, {5, 0, 0}, {5, 3, 2}, - * {9, 0, 0}, // i = 9 {4, 3, 2}, {6, 3, 1}, {3, 0, 0}, {6, 2, 1}, {9, 0, - * 0}, // i = 10 {7, 0, 0}, {7, 4, 2}, {4, 0, 0}, {19, 0, 0}, {7, 4, 2}, // - * i = 11 {1, 0, 0}, {5, 2, 1}, {29, 0, 0}, {1, 0, 0}, {4, 3, 1}, // i = 12 - * {18, 0, 0}, {3, 0, 0}, {5, 2, 1}, {9, 0, 0}, {6, 5, 2}, // i = 13 {5, 3, - * 1}, {6, 0, 0}, {10, 9, 3}, {25, 0, 0}, {35, 0, 0}, // i = 14 {6, 3, 1}, - * {21, 0, 0}, {6, 5, 2}, {6, 5, 3}, {9, 0, 0}, // i = 15 {9, 4, 2}, {4, 0, - * 0}, {8, 3, 1}, {7, 4, 2}, {5, 0, 0}, // i = 16 {8, 2, 1}, {21, 0, 0}, - * {13, 0, 0}, {7, 6, 2}, {38, 0, 0}, // i = 17 {27, 0, 0}, {8, 5, 1}, {21, - * 0, 0}, {2, 0, 0}, {21, 0, 0}, // i = 18 {11, 0, 0}, {10, 9, 6}, {6, 0, - * 0}, {11, 0, 0}, {6, 3, 1}, // i = 19 {15, 0, 0}, {7, 6, 1}, {29, 0, 0}, - * {9, 0, 0}, {4, 3, 1}, // i = 20 {4, 0, 0}, {15, 0, 0}, {9, 7, 4}, {17, 0, - * 0}, {5, 4, 2}, // i = 21 {33, 0, 0}, {10, 0, 0}, {5, 4, 3}, {9, 0, 0}, - * {5, 3, 2}, // i = 22 {8, 7, 5}, {4, 2, 1}, {5, 2, 1}, {33, 0, 0}, {8, 0, - * 0}, // i = 23 {4, 3, 1}, {18, 0, 0}, {6, 2, 1}, {2, 0, 0}, {19, 0, 0}, // - * i = 24 {7, 6, 5}, {21, 0, 0}, {1, 0, 0}, {7, 2, 1}, {5, 0, 0}, // i = 25 - * {3, 0, 0}, {8, 3, 2}, {17, 0, 0}, {9, 8, 2}, {57, 0, 0}, // i = 26 {11, - * 0, 0}, {5, 3, 2}, {21, 0, 0}, {8, 7, 1}, {8, 5, 3}, // i = 27 {15, 0, 0}, - * {10, 4, 1}, {21, 0, 0}, {5, 3, 2}, {7, 4, 2}, // i = 28 {52, 0, 0}, {71, - * 0, 0}, {14, 0, 0}, {27, 0, 0}, {10, 9, 7}, // i = 29 {53, 0, 0}, {3, 0, - * 0}, {6, 3, 2}, {1, 0, 0}, {15, 0, 0}, // i = 30 {62, 0, 0}, {9, 0, 0}, - * {6, 5, 2}, {8, 6, 5}, {31, 0, 0}, // i = 31 {5, 3, 2}, {18, 0, 0 }, {27, - * 0, 0}, {7, 6, 3}, {10, 8, 7}, // i = 32 {9, 8, 3}, {37, 0, 0}, {6, 0, 0}, - * {15, 3, 2}, {34, 0, 0}, // i = 33 {11, 0, 0}, {6, 5, 2}, {1, 0, 0}, {8, - * 5, 2}, {13, 0, 0}, // i = 34 {6, 0, 0}, {11, 3, 2}, {8, 0, 0}, {31, 0, - * 0}, {4, 2, 1}, // i = 35 {3, 0, 0}, {7, 6, 1}, {81, 0, 0}, {56, 0, 0}, - * {9, 8, 7}, // i = 36 {24, 0, 0}, {11, 0, 0}, {7, 6, 5}, {6, 5, 2}, {6, 5, - * 2}, // i = 37 {8, 7, 6}, {9, 0, 0}, {7, 2, 1}, {15, 0, 0}, {87, 0, 0}, // - * i = 38 {8, 3, 2}, {3, 0, 0}, {9, 4, 2}, {9, 0, 0}, {34, 0, 0}, // i = 39 - * {5, 3, 2}, {14, 0, 0}, {55, 0, 0}, {8, 7, 1}, {27, 0, 0}, // i = 40 {9, - * 5, 2}, {10, 9, 5}, {43, 0, 0}, {8, 6, 2}, {6, 0, 0}, // i = 41 {7, 0, 0}, - * {11, 10, 8}, {105, 0, 0}, {6, 5, 2}, {73, 0, 0}}; // i = 42 - */ - // ///////////////////////////////////////////////////////////////////// - // member variables - // ///////////////////////////////////////////////////////////////////// - private static final int MAXLONG = 64; - - /** - * holds the length of the array-representation of degree mDegree. - */ - private int mLength; - - /** - * holds the number of relevant bits in mONBPol[mLength-1]. - */ - private int mBit; - - /** - * holds the type of mONB - */ - private int mType; - - /** - * holds the multiplication matrix - */ - int[][] mMult; - - // ///////////////////////////////////////////////////////////////////// - // constructors - // ///////////////////////////////////////////////////////////////////// - - /** - * constructs an instance of the finite field with 2deg - * elements and characteristic 2. - * - * @param deg -the extention degree of this field - * @param random - a source of randomness for generating polynomials on the field. - */ - public GF2nONBField(int deg, SecureRandom random) - throws RuntimeException - { - super(random); - - if (deg < 3) - { - throw new IllegalArgumentException("k must be at least 3"); - } - - mDegree = deg; - mLength = mDegree / MAXLONG; - mBit = mDegree & (MAXLONG - 1); - if (mBit == 0) - { - mBit = MAXLONG; - } - else - { - mLength++; - } - - computeType(); - - // only ONB-implementations for type 1 and type 2 - // - if (mType < 3) - { - mMult = new int[mDegree][2]; - for (int i = 0; i < mDegree; i++) - { - mMult[i][0] = -1; - mMult[i][1] = -1; - } - computeMultMatrix(); - } - else - { - throw new RuntimeException("\nThe type of this field is " - + mType); - } - computeFieldPolynomial(); - fields = new Vector(); - matrices = new Vector(); - } - - // ///////////////////////////////////////////////////////////////////// - // access - // ///////////////////////////////////////////////////////////////////// - - int getONBLength() - { - return mLength; - } - - int getONBBit() - { - return mBit; - } - - // ///////////////////////////////////////////////////////////////////// - // arithmetic - // ///////////////////////////////////////////////////////////////////// - - /** - * Computes a random root of the given polynomial. - * - * @param polynomial a polynomial - * @return a random root of the polynomial - * @see "P1363 A.5.6, p103f" - */ - protected GF2nElement getRandomRoot(GF2Polynomial polynomial) - { - // We are in B1!!! - GF2nPolynomial c; - GF2nPolynomial ut; - GF2nElement u; - GF2nPolynomial h; - int hDegree; - // 1. Set g(t) <- f(t) - GF2nPolynomial g = new GF2nPolynomial(polynomial, this); - int gDegree = g.getDegree(); - int i; - - // 2. while deg(g) > 1 - while (gDegree > 1) - { - do - { - // 2.1 choose random u (element of) GF(2^m) - u = new GF2nONBElement(this, random); - ut = new GF2nPolynomial(2, GF2nONBElement.ZERO(this)); - // 2.2 Set c(t) <- ut - ut.set(1, u); - c = new GF2nPolynomial(ut); - // 2.3 For i from 1 to m-1 do - for (i = 1; i <= mDegree - 1; i++) - { - // 2.3.1 c(t) <- (c(t)^2 + ut) mod g(t) - c = c.multiplyAndReduce(c, g); - c = c.add(ut); - } - // 2.4 set h(t) <- GCD(c(t), g(t)) - h = c.gcd(g); - // 2.5 if h(t) is constant or deg(g) = deg(h) then go to - // step 2.1 - hDegree = h.getDegree(); - gDegree = g.getDegree(); - } - while ((hDegree == 0) || (hDegree == gDegree)); - // 2.6 If 2deg(h) > deg(g) then set g(t) <- g(t)/h(t) ... - if ((hDegree << 1) > gDegree) - { - g = g.quotient(h); - } - else - { - // ... else g(t) <- h(t) - g = new GF2nPolynomial(h); - } - gDegree = g.getDegree(); - } - // 3. Output g(0) - return g.at(0); - - } - - /** - * Computes the change-of-basis matrix for basis conversion according to - * 1363. The result is stored in the lists fields and matrices. - * - * @param B1 the GF2nField to convert to - * @see "P1363 A.7.3, p111ff" - */ - protected void computeCOBMatrix(GF2nField B1) - { - // we are in B0 here! - if (mDegree != B1.mDegree) - { - throw new IllegalArgumentException( - "GF2nField.computeCOBMatrix: B1 has a " - + "different degree and thus cannot be coverted to!"); - } - int i, j; - GF2nElement[] gamma; - GF2nElement u; - GF2Polynomial[] COBMatrix = new GF2Polynomial[mDegree]; - for (i = 0; i < mDegree; i++) - { - COBMatrix[i] = new GF2Polynomial(mDegree); - } - - // find Random Root - do - { - // u is in representation according to B1 - u = B1.getRandomRoot(fieldPolynomial); - } - while (u.isZero()); - - gamma = new GF2nPolynomialElement[mDegree]; - // build gamma matrix by squaring - gamma[0] = (GF2nElement)u.clone(); - for (i = 1; i < mDegree; i++) - { - gamma[i] = gamma[i - 1].square(); - } - // convert horizontal gamma matrix by vertical Bitstrings - for (i = 0; i < mDegree; i++) - { - for (j = 0; j < mDegree; j++) - { - if (gamma[i].testBit(j)) - { - COBMatrix[mDegree - j - 1].setBit(mDegree - i - 1); - } - } - } - - fields.addElement(B1); - matrices.addElement(COBMatrix); - B1.fields.addElement(this); - B1.matrices.addElement(invertMatrix(COBMatrix)); - } - - /** - * Computes the field polynomial for a ONB according to IEEE 1363 A.7.2 - * (p110f). - * - * @see "P1363 A.7.2, p110f" - */ - protected void computeFieldPolynomial() - { - if (mType == 1) - { - fieldPolynomial = new GF2Polynomial(mDegree + 1, "ALL"); - } - else if (mType == 2) - { - // 1. q = 1 - GF2Polynomial q = new GF2Polynomial(mDegree + 1, "ONE"); - // 2. p = t+1 - GF2Polynomial p = new GF2Polynomial(mDegree + 1, "X"); - p.addToThis(q); - GF2Polynomial r; - int i; - // 3. for i = 1 to (m-1) do - for (i = 1; i < mDegree; i++) - { - // r <- q - r = q; - // q <- p - q = p; - // p = tq+r - p = q.shiftLeft(); - p.addToThis(r); - } - fieldPolynomial = p; - } - } - - /** - * Compute the inverse of a matrix a. - * - * @param a the matrix - * @return a-1 - */ - int[][] invMatrix(int[][] a) - { - - int[][] A = new int[mDegree][mDegree]; - A = a; - int[][] inv = new int[mDegree][mDegree]; - - for (int i = 0; i < mDegree; i++) - { - inv[i][i] = 1; - } - - for (int i = 0; i < mDegree; i++) - { - for (int j = i; j < mDegree; j++) - { - A[mDegree - 1 - i][j] = A[i][i]; - } - } - return null; - } - - private void computeType() - throws RuntimeException - { - if ((mDegree & 7) == 0) - { - throw new RuntimeException( - "The extension degree is divisible by 8!"); - } - // checking for the type - int s = 0; - int k = 0; - mType = 1; - for (int d = 0; d != 1; mType++) - { - s = mType * mDegree + 1; - if (IntegerFunctions.isPrime(s)) - { - k = IntegerFunctions.order(2, s); - d = IntegerFunctions.gcd(mType * mDegree / k, mDegree); - } - } - mType--; - if (mType == 1) - { - s = (mDegree << 1) + 1; - if (IntegerFunctions.isPrime(s)) - { - k = IntegerFunctions.order(2, s); - int d = IntegerFunctions.gcd((mDegree << 1) / k, mDegree); - if (d == 1) - { - mType++; - } - } - } - } - - private void computeMultMatrix() - { - - if ((mType & 7) != 0) - { - int p = mType * mDegree + 1; - - // compute sequence F[1] ... F[p-1] via A.3.7. of 1363. - // F[0] will not be filled! - // - int[] F = new int[p]; - - int u; - if (mType == 1) - { - u = 1; - } - else if (mType == 2) - { - u = p - 1; - } - else - { - u = elementOfOrder(mType, p); - } - - int w = 1; - int n; - for (int j = 0; j < mType; j++) - { - n = w; - - for (int i = 0; i < mDegree; i++) - { - F[n] = i; - n = (n << 1) % p; - if (n < 0) - { - n += p; - } - } - w = u * w % p; - if (w < 0) - { - w += p; - } - } - - // building the matrix (mDegree * 2) - // - if (mType == 1) - { - for (int k = 1; k < p - 1; k++) - { - if (mMult[F[k + 1]][0] == -1) - { - mMult[F[k + 1]][0] = F[p - k]; - } - else - { - mMult[F[k + 1]][1] = F[p - k]; - } - } - - int m_2 = mDegree >> 1; - for (int k = 1; k <= m_2; k++) - { - - if (mMult[k - 1][0] == -1) - { - mMult[k - 1][0] = m_2 + k - 1; - } - else - { - mMult[k - 1][1] = m_2 + k - 1; - } - - if (mMult[m_2 + k - 1][0] == -1) - { - mMult[m_2 + k - 1][0] = k - 1; - } - else - { - mMult[m_2 + k - 1][1] = k - 1; - } - } - } - else if (mType == 2) - { - for (int k = 1; k < p - 1; k++) - { - if (mMult[F[k + 1]][0] == -1) - { - mMult[F[k + 1]][0] = F[p - k]; - } - else - { - mMult[F[k + 1]][1] = F[p - k]; - } - } - } - else - { - throw new RuntimeException("only type 1 or type 2 implemented"); - } - } - else - { - throw new RuntimeException("bisher nur fuer Gausssche Normalbasen" - + " implementiert"); - } - } - - private int elementOfOrder(int k, int p) - { - Random random = new Random(); - int m = 0; - while (m == 0) - { - m = random.nextInt(); - m %= p - 1; - if (m < 0) - { - m += p - 1; - } - } - - int l = IntegerFunctions.order(m, p); - - while (l % k != 0 || l == 0) - { - while (m == 0) - { - m = random.nextInt(); - m %= p - 1; - if (m < 0) - { - m += p - 1; - } - } - l = IntegerFunctions.order(m, p); - } - int r = m; - - l = k / l; - - for (int i = 2; i <= l; i++) - { - r *= m; - } - - return r; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nPolynomial.java deleted file mode 100644 index 1e579b0bf5..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nPolynomial.java +++ /dev/null @@ -1,562 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -import org.bouncycastle.util.Arrays; - -/** - * This class implements polynomials over GF2nElements. - * - * @see GF2nElement - */ - -public class GF2nPolynomial -{ - - private GF2nElement[] coeff; // keeps the coefficients of this polynomial - - private int size; // the size of this polynomial - - /** - * Creates a new PolynomialGF2n of size deg and elem as - * coefficients. - * - * @param deg - - * the maximum degree + 1 - * @param elem - - * a GF2nElement - */ - public GF2nPolynomial(int deg, GF2nElement elem) - { - size = deg; - coeff = new GF2nElement[size]; - for (int i = 0; i < size; i++) - { - coeff[i] = (GF2nElement)elem.clone(); - } - } - - /** - * Creates a new PolynomialGF2n of size deg. - * - * @param deg the maximum degree + 1 - */ - private GF2nPolynomial(int deg) - { - size = deg; - coeff = new GF2nElement[size]; - } - - /** - * Creates a new PolynomialGF2n by cloning the given PolynomialGF2n a. - * - * @param a the PolynomialGF2n to clone - */ - public GF2nPolynomial(GF2nPolynomial a) - { - int i; - coeff = new GF2nElement[a.size]; - size = a.size; - for (i = 0; i < size; i++) - { - coeff[i] = (GF2nElement)a.coeff[i].clone(); - } - } - - /** - * Creates a new PolynomialGF2n from the given Bitstring polynomial - * over the GF2nField B1. - * - * @param polynomial the Bitstring to use - * @param B1 the field - */ - public GF2nPolynomial(GF2Polynomial polynomial, GF2nField B1) - { - size = B1.getDegree() + 1; - coeff = new GF2nElement[size]; - int i; - if (B1 instanceof GF2nONBField) - { - for (i = 0; i < size; i++) - { - if (polynomial.testBit(i)) - { - coeff[i] = GF2nONBElement.ONE((GF2nONBField)B1); - } - else - { - coeff[i] = GF2nONBElement.ZERO((GF2nONBField)B1); - } - } - } - else if (B1 instanceof GF2nPolynomialField) - { - for (i = 0; i < size; i++) - { - if (polynomial.testBit(i)) - { - coeff[i] = GF2nPolynomialElement - .ONE((GF2nPolynomialField)B1); - } - else - { - coeff[i] = GF2nPolynomialElement - .ZERO((GF2nPolynomialField)B1); - } - } - } - else - { - throw new IllegalArgumentException( - "PolynomialGF2n(Bitstring, GF2nField): B1 must be " - + "an instance of GF2nONBField or GF2nPolynomialField!"); - } - } - - public final void assignZeroToElements() - { - int i; - for (i = 0; i < size; i++) - { - coeff[i].assignZero(); - } - } - - /** - * Returns the size (=maximum degree + 1) of this PolynomialGF2n. This is - * not the degree, use getDegree instead. - * - * @return the size (=maximum degree + 1) of this PolynomialGF2n. - */ - public final int size() - { - return size; - } - - /** - * Returns the degree of this PolynomialGF2n. - * - * @return the degree of this PolynomialGF2n. - */ - public final int getDegree() - { - int i; - for (i = size - 1; i >= 0; i--) - { - if (!coeff[i].isZero()) - { - return i; - } - } - return -1; - } - - /** - * Enlarges the size of this PolynomialGF2n to k + 1. - * - * @param k the new maximum degree - */ - public final void enlarge(int k) - { - if (k <= size) - { - return; - } - int i; - GF2nElement[] res = new GF2nElement[k]; - System.arraycopy(coeff, 0, res, 0, size); - GF2nField f = coeff[0].getField(); - if (coeff[0] instanceof GF2nPolynomialElement) - { - for (i = size; i < k; i++) - { - res[i] = GF2nPolynomialElement.ZERO((GF2nPolynomialField)f); - } - } - else if (coeff[0] instanceof GF2nONBElement) - { - for (i = size; i < k; i++) - { - res[i] = GF2nONBElement.ZERO((GF2nONBField)f); - } - } - size = k; - coeff = res; - } - - public final void shrink() - { - int i = size - 1; - while (coeff[i].isZero() && (i > 0)) - { - i--; - } - i++; - if (i < size) - { - GF2nElement[] res = new GF2nElement[i]; - System.arraycopy(coeff, 0, res, 0, i); - coeff = res; - size = i; - } - } - - /** - * Sets the coefficient at index to elem. - * - * @param index the index - * @param elem the GF2nElement to store as coefficient index - */ - public final void set(int index, GF2nElement elem) - { - if (!(elem instanceof GF2nPolynomialElement) - && !(elem instanceof GF2nONBElement)) - { - throw new IllegalArgumentException( - "PolynomialGF2n.set f must be an " - + "instance of either GF2nPolynomialElement or GF2nONBElement!"); - } - coeff[index] = (GF2nElement)elem.clone(); - } - - /** - * Returns the coefficient at index. - * - * @param index the index - * @return the GF2nElement stored as coefficient index - */ - public final GF2nElement at(int index) - { - return coeff[index]; - } - - /** - * Returns true if all coefficients equal zero. - * - * @return true if all coefficients equal zero. - */ - public final boolean isZero() - { - int i; - for (i = 0; i < size; i++) - { - if (coeff[i] != null) - { - if (!coeff[i].isZero()) - { - return false; - } - } - } - return true; - } - - public final boolean equals(Object other) - { - if (other == null || !(other instanceof GF2nPolynomial)) - { - return false; - } - - GF2nPolynomial otherPol = (GF2nPolynomial)other; - - if (getDegree() != otherPol.getDegree()) - { - return false; - } - int i; - for (i = 0; i < size; i++) - { - if (!coeff[i].equals(otherPol.coeff[i])) - { - return false; - } - } - return true; - } - - /** - * @return the hash code of this polynomial - */ - public int hashCode() - { - return getDegree() * 7 + Arrays.hashCode(coeff); - } - - /** - * Adds the PolynomialGF2n b to this and returns the - * result in a new PolynomialGF2n. - * - * @param b - - * the PolynomialGF2n to add - * @return this + b - */ - public final GF2nPolynomial add(GF2nPolynomial b) - { - GF2nPolynomial result; - if (size() >= b.size()) - { - result = new GF2nPolynomial(size()); - int i; - for (i = 0; i < b.size(); i++) - { - result.coeff[i] = (GF2nElement)coeff[i].add(b.coeff[i]); - } - for (; i < size(); i++) - { - result.coeff[i] = coeff[i]; - } - } - else - { - result = new GF2nPolynomial(b.size()); - int i; - for (i = 0; i < size(); i++) - { - result.coeff[i] = (GF2nElement)coeff[i].add(b.coeff[i]); - } - for (; i < b.size(); i++) - { - result.coeff[i] = b.coeff[i]; - } - } - return result; - } - - /** - * Multiplies the scalar s to each coefficient of this - * PolynomialGF2n and returns the result in a new PolynomialGF2n. - * - * @param s the scalar to multiply - * @return this x s - */ - public final GF2nPolynomial scalarMultiply(GF2nElement s) - { - GF2nPolynomial result = new GF2nPolynomial(size()); - int i; - for (i = 0; i < size(); i++) - { - result.coeff[i] = (GF2nElement)coeff[i].multiply(s); // result[i] - // = - // a[i]*s - } - return result; - } - - /** - * Multiplies this by b and returns the result in a new - * PolynomialGF2n. - * - * @param b the PolynomialGF2n to multiply - * @return this * b - */ - public final GF2nPolynomial multiply(GF2nPolynomial b) - { - int i, j; - int aDegree = size(); - int bDegree = b.size(); - if (aDegree != bDegree) - { - throw new IllegalArgumentException( - "PolynomialGF2n.multiply: this and b must " - + "have the same size!"); - } - GF2nPolynomial result = new GF2nPolynomial((aDegree << 1) - 1); - for (i = 0; i < size(); i++) - { - for (j = 0; j < b.size(); j++) - { - if (result.coeff[i + j] == null) - { - result.coeff[i + j] = (GF2nElement)coeff[i] - .multiply(b.coeff[j]); - } - else - { - result.coeff[i + j] = (GF2nElement)result.coeff[i + j] - .add(coeff[i].multiply(b.coeff[j])); - } - } - } - return result; - } - - /** - * Multiplies this by b, reduces the result by g and - * returns it in a new PolynomialGF2n. - * - * @param b the PolynomialGF2n to multiply - * @param g the modul - * @return this * b mod g - */ - public final GF2nPolynomial multiplyAndReduce(GF2nPolynomial b, - GF2nPolynomial g) - { - return multiply(b).reduce(g); - } - - /** - * Reduces this by g and returns the result in a new - * PolynomialGF2n. - * - * @param g - - * the modulus - * @return this % g - */ - public final GF2nPolynomial reduce(GF2nPolynomial g) - throws RuntimeException, ArithmeticException - { - return remainder(g); // return this % g - } - - /** - * Shifts left this by amount and stores the result in - * this PolynomialGF2n. - * - * @param amount the amount to shift the coefficients - */ - public final void shiftThisLeft(int amount) - { - if (amount > 0) - { - int i; - int oldSize = size; - GF2nField f = coeff[0].getField(); - enlarge(size + amount); - for (i = oldSize - 1; i >= 0; i--) - { - coeff[i + amount] = coeff[i]; - } - if (coeff[0] instanceof GF2nPolynomialElement) - { - for (i = amount - 1; i >= 0; i--) - { - coeff[i] = GF2nPolynomialElement - .ZERO((GF2nPolynomialField)f); - } - } - else if (coeff[0] instanceof GF2nONBElement) - { - for (i = amount - 1; i >= 0; i--) - { - coeff[i] = GF2nONBElement.ZERO((GF2nONBField)f); - } - } - } - } - - public final GF2nPolynomial shiftLeft(int amount) - { - if (amount <= 0) - { - return new GF2nPolynomial(this); - } - GF2nPolynomial result = new GF2nPolynomial(size + amount, coeff[0]); - result.assignZeroToElements(); - for (int i = 0; i < size; i++) - { - result.coeff[i + amount] = coeff[i]; - } - return result; - } - - /** - * Divides this by b and stores the result in a new - * PolynomialGF2n[2], quotient in result[0] and remainder in result[1]. - * - * @param b the divisor - * @return the quotient and remainder of this / b - */ - public final GF2nPolynomial[] divide(GF2nPolynomial b) - { - GF2nPolynomial[] result = new GF2nPolynomial[2]; - GF2nPolynomial a = new GF2nPolynomial(this); - a.shrink(); - GF2nPolynomial shift; - GF2nElement factor; - int bDegree = b.getDegree(); - GF2nElement inv = (GF2nElement)b.coeff[bDegree].invert(); - if (a.getDegree() < bDegree) - { - result[0] = new GF2nPolynomial(this); - result[0].assignZeroToElements(); - result[0].shrink(); - result[1] = new GF2nPolynomial(this); - result[1].shrink(); - return result; - } - result[0] = new GF2nPolynomial(this); - result[0].assignZeroToElements(); - int i = a.getDegree() - bDegree; - while (i >= 0) - { - factor = (GF2nElement)a.coeff[a.getDegree()].multiply(inv); - shift = b.scalarMultiply(factor); - shift.shiftThisLeft(i); - a = a.add(shift); - a.shrink(); - result[0].coeff[i] = (GF2nElement)factor.clone(); - i = a.getDegree() - bDegree; - } - result[1] = a; - result[0].shrink(); - return result; - } - - /** - * Divides this by b and stores the remainder in a new - * PolynomialGF2n. - * - * @param b the divisor - * @return the remainder this % b - */ - public final GF2nPolynomial remainder(GF2nPolynomial b) - throws RuntimeException, ArithmeticException - { - GF2nPolynomial[] result = new GF2nPolynomial[2]; - result = divide(b); - return result[1]; - } - - /** - * Divides this by b and stores the quotient in a new - * PolynomialGF2n. - * - * @param b the divisor - * @return the quotient this / b - */ - public final GF2nPolynomial quotient(GF2nPolynomial b) - throws RuntimeException, ArithmeticException - { - GF2nPolynomial[] result = new GF2nPolynomial[2]; - result = divide(b); - return result[0]; - } - - /** - * Computes the greatest common divisor of this and g and - * returns the result in a new PolynomialGF2n. - * - * @param g - - * a GF2nPolynomial - * @return gcd(this, g) - */ - public final GF2nPolynomial gcd(GF2nPolynomial g) - { - GF2nPolynomial a = new GF2nPolynomial(this); - GF2nPolynomial b = new GF2nPolynomial(g); - a.shrink(); - b.shrink(); - GF2nPolynomial c; - GF2nPolynomial result; - GF2nElement alpha; - while (!b.isZero()) - { - c = a.remainder(b); - a = b; - b = c; - } - alpha = a.coeff[a.getDegree()]; - result = a.scalarMultiply((GF2nElement)alpha.invert()); - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nPolynomialElement.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nPolynomialElement.java deleted file mode 100644 index 0b5651fedd..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nPolynomialElement.java +++ /dev/null @@ -1,1015 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - - -import java.math.BigInteger; -import java.util.Random; - - -/** - * This class implements elements of finite binary fields GF(2n) - * using polynomial representation. For more information on the arithmetic see - * for example IEEE Standard 1363 or Certicom online-tutorial. - * - * @see "GF2nField" - * @see GF2nPolynomialField - * @see GF2nONBElement - * @see GF2Polynomial - */ -public class GF2nPolynomialElement - extends GF2nElement -{ - - // pre-computed Bitmask for fast masking, bitMask[a]=0x1 << a - private static final int[] bitMask = {0x00000001, 0x00000002, 0x00000004, - 0x00000008, 0x00000010, 0x00000020, 0x00000040, 0x00000080, - 0x00000100, 0x00000200, 0x00000400, 0x00000800, 0x00001000, - 0x00002000, 0x00004000, 0x00008000, 0x00010000, 0x00020000, - 0x00040000, 0x00080000, 0x00100000, 0x00200000, 0x00400000, - 0x00800000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x00000000}; - - // the used GF2Polynomial which stores the coefficients - private GF2Polynomial polynomial; - - /** - * Create a new random GF2nPolynomialElement using the given field and - * source of randomness. - * - * @param f the GF2nField to use - * @param rand the source of randomness - */ - public GF2nPolynomialElement(GF2nPolynomialField f, Random rand) - { - mField = f; - mDegree = mField.getDegree(); - polynomial = new GF2Polynomial(mDegree); - randomize(rand); - } - - /** - * Creates a new GF2nPolynomialElement using the given field and Bitstring. - * - * @param f the GF2nPolynomialField to use - * @param bs the desired value as Bitstring - */ - public GF2nPolynomialElement(GF2nPolynomialField f, GF2Polynomial bs) - { - mField = f; - mDegree = mField.getDegree(); - polynomial = new GF2Polynomial(bs); - polynomial.expandN(mDegree); - } - - /** - * Creates a new GF2nPolynomialElement using the given field f and - * byte[] os as value. The conversion is done according to 1363. - * - * @param f the GF2nField to use - * @param os the octet string to assign to this GF2nPolynomialElement - * @see "P1363 5.5.5 p23, OS2FEP/OS2BSP" - */ - public GF2nPolynomialElement(GF2nPolynomialField f, byte[] os) - { - mField = f; - mDegree = mField.getDegree(); - polynomial = new GF2Polynomial(mDegree, os); - polynomial.expandN(mDegree); - } - - /** - * Creates a new GF2nPolynomialElement using the given field f and - * int[] is as value. - * - * @param f the GF2nField to use - * @param is the integer string to assign to this GF2nPolynomialElement - */ - public GF2nPolynomialElement(GF2nPolynomialField f, int[] is) - { - mField = f; - mDegree = mField.getDegree(); - polynomial = new GF2Polynomial(mDegree, is); - polynomial.expandN(f.mDegree); - } - - /** - * Creates a new GF2nPolynomialElement by cloning the given - * GF2nPolynomialElement b. - * - * @param other the GF2nPolynomialElement to clone - */ - public GF2nPolynomialElement(GF2nPolynomialElement other) - { - mField = other.mField; - mDegree = other.mDegree; - polynomial = new GF2Polynomial(other.polynomial); - } - - // ///////////////////////////////////////////////////////////////////// - // pseudo-constructors - // ///////////////////////////////////////////////////////////////////// - - /** - * Creates a new GF2nPolynomialElement by cloning this - * GF2nPolynomialElement. - * - * @return a copy of this element - */ - public Object clone() - { - return new GF2nPolynomialElement(this); - } - - // ///////////////////////////////////////////////////////////////////// - // assignments - // ///////////////////////////////////////////////////////////////////// - - /** - * Assigns the value 'zero' to this Polynomial. - */ - void assignZero() - { - polynomial.assignZero(); - } - - /** - * Create the zero element. - * - * @param f the finite field - * @return the zero element in the given finite field - */ - public static GF2nPolynomialElement ZERO(GF2nPolynomialField f) - { - GF2Polynomial polynomial = new GF2Polynomial(f.getDegree()); - return new GF2nPolynomialElement(f, polynomial); - } - - /** - * Create the one element. - * - * @param f the finite field - * @return the one element in the given finite field - */ - public static GF2nPolynomialElement ONE(GF2nPolynomialField f) - { - GF2Polynomial polynomial = new GF2Polynomial(f.getDegree(), - new int[]{1}); - return new GF2nPolynomialElement(f, polynomial); - } - - /** - * Assigns the value 'one' to this Polynomial. - */ - void assignOne() - { - polynomial.assignOne(); - } - - /** - * Assign a random value to this GF2nPolynomialElement using the specified - * source of randomness. - * - * @param rand the source of randomness - */ - private void randomize(Random rand) - { - polynomial.expandN(mDegree); - polynomial.randomize(rand); - } - - // ///////////////////////////////////////////////////////////////////// - // comparison - // ///////////////////////////////////////////////////////////////////// - - /** - * Checks whether this element is zero. - * - * @return true if this is the zero element - */ - public boolean isZero() - { - return polynomial.isZero(); - } - - /** - * Tests if the GF2nPolynomialElement has 'one' as value. - * - * @return true if this equals one (this == 1) - */ - public boolean isOne() - { - return polynomial.isOne(); - } - - /** - * Compare this element with another object. - * - * @param other the other object - * @return true if the two objects are equal, false - * otherwise - */ - public boolean equals(Object other) - { - if (other == null || !(other instanceof GF2nPolynomialElement)) - { - return false; - } - GF2nPolynomialElement otherElem = (GF2nPolynomialElement)other; - - if (mField != otherElem.mField) - { - if (!mField.getFieldPolynomial().equals( - otherElem.mField.getFieldPolynomial())) - { - return false; - } - } - - return polynomial.equals(otherElem.polynomial); - } - - /** - * @return the hash code of this element - */ - public int hashCode() - { - return mField.hashCode() + polynomial.hashCode(); - } - - // ///////////////////////////////////////////////////////////////////// - // access - // ///////////////////////////////////////////////////////////////////// - - /** - * Returns the value of this GF2nPolynomialElement in a new Bitstring. - * - * @return the value of this GF2nPolynomialElement in a new Bitstring - */ - private GF2Polynomial getGF2Polynomial() - { - return new GF2Polynomial(polynomial); - } - - /** - * Checks whether the indexed bit of the bit representation is set. - * - * @param index the index of the bit to test - * @return true if the indexed bit is set - */ - boolean testBit(int index) - { - return polynomial.testBit(index); - } - - /** - * Returns whether the rightmost bit of the bit representation is set. This - * is needed for data conversion according to 1363. - * - * @return true if the rightmost bit of this element is set - */ - public boolean testRightmostBit() - { - return polynomial.testBit(0); - } - - /** - * Compute the sum of this element and addend. - * - * @param addend the addend - * @return this + other (newly created) - */ - public GFElement add(GFElement addend) - throws RuntimeException - { - GF2nPolynomialElement result = new GF2nPolynomialElement(this); - result.addToThis(addend); - return result; - } - - /** - * Compute this + addend (overwrite this). - * - * @param addend the addend - */ - public void addToThis(GFElement addend) - throws RuntimeException - { - if (!(addend instanceof GF2nPolynomialElement)) - { - throw new RuntimeException(); - } - if (!mField.equals(((GF2nPolynomialElement)addend).mField)) - { - throw new RuntimeException(); - } - polynomial.addToThis(((GF2nPolynomialElement)addend).polynomial); - } - - /** - * Returns this element + 'one". - * - * @return this + 'one' - */ - public GF2nElement increase() - { - GF2nPolynomialElement result = new GF2nPolynomialElement(this); - result.increaseThis(); - return result; - } - - /** - * Increases this element by 'one'. - */ - public void increaseThis() - { - polynomial.increaseThis(); - } - - /** - * Compute the product of this element and factor. - * - * @param factor the factor - * @return this * factor (newly created) - */ - public GFElement multiply(GFElement factor) - throws RuntimeException - { - GF2nPolynomialElement result = new GF2nPolynomialElement(this); - result.multiplyThisBy(factor); - return result; - } - - /** - * Compute this * factor (overwrite this). - * - * @param factor the factor - */ - public void multiplyThisBy(GFElement factor) - throws RuntimeException - { - if (!(factor instanceof GF2nPolynomialElement)) - { - throw new RuntimeException(); - } - if (!mField.equals(((GF2nPolynomialElement)factor).mField)) - { - throw new RuntimeException(); - } - if (equals(factor)) - { - squareThis(); - return; - } - polynomial = polynomial - .multiply(((GF2nPolynomialElement)factor).polynomial); - reduceThis(); - } - - /** - * Compute the multiplicative inverse of this element. - * - * @return this-1 (newly created) - * @throws ArithmeticException if this is the zero element. - * @see GF2nPolynomialElement#invertMAIA - * @see GF2nPolynomialElement#invertEEA - * @see GF2nPolynomialElement#invertSquare - */ - public GFElement invert() - throws ArithmeticException - { - return invertMAIA(); - } - - /** - * Calculates the multiplicative inverse of this and returns the - * result in a new GF2nPolynomialElement. - * - * @return this^(-1) - * @throws ArithmeticException if this equals zero - */ - public GF2nPolynomialElement invertEEA() - throws ArithmeticException - { - if (isZero()) - { - throw new ArithmeticException(); - } - GF2Polynomial b = new GF2Polynomial(mDegree + 32, "ONE"); - b.reduceN(); - GF2Polynomial c = new GF2Polynomial(mDegree + 32); - c.reduceN(); - GF2Polynomial u = getGF2Polynomial(); - GF2Polynomial v = mField.getFieldPolynomial(); - GF2Polynomial h; - int j; - u.reduceN(); - while (!u.isOne()) - { - u.reduceN(); - v.reduceN(); - j = u.getLength() - v.getLength(); - if (j < 0) - { - h = u; - u = v; - v = h; - h = b; - b = c; - c = h; - j = -j; - c.reduceN(); // this increases the performance - } - u.shiftLeftAddThis(v, j); - b.shiftLeftAddThis(c, j); - } - b.reduceN(); - return new GF2nPolynomialElement((GF2nPolynomialField)mField, b); - } - - /** - * Calculates the multiplicative inverse of this and returns the - * result in a new GF2nPolynomialElement. - * - * @return this^(-1) - * @throws ArithmeticException if this equals zero - */ - public GF2nPolynomialElement invertSquare() - throws ArithmeticException - { - GF2nPolynomialElement n; - GF2nPolynomialElement u; - int i, j, k, b; - - if (isZero()) - { - throw new ArithmeticException(); - } - // b = (n-1) - b = mField.getDegree() - 1; - // n = a - n = new GF2nPolynomialElement(this); - n.polynomial.expandN((mDegree << 1) + 32); // increase performance - n.polynomial.reduceN(); - // k = 1 - k = 1; - - // for i = (r-1) downto 0 do, r=bitlength(b) - for (i = IntegerFunctions.floorLog(b) - 1; i >= 0; i--) - { - // u = n - u = new GF2nPolynomialElement(n); - // for j = 1 to k do - for (j = 1; j <= k; j++) - { - // u = u^2 - u.squareThisPreCalc(); - } - // n = nu - n.multiplyThisBy(u); - // k = 2k - k <<= 1; - // if b(i)==1 - if ((b & bitMask[i]) != 0) - { - // n = n^2 * b - n.squareThisPreCalc(); - n.multiplyThisBy(this); - // k = k+1 - k += 1; - } - } - - // outpur n^2 - n.squareThisPreCalc(); - return n; - } - - /** - * Calculates the multiplicative inverse of this using the modified - * almost inverse algorithm and returns the result in a new - * GF2nPolynomialElement. - * - * @return this^(-1) - * @throws ArithmeticException if this equals zero - */ - public GF2nPolynomialElement invertMAIA() - throws ArithmeticException - { - if (isZero()) - { - throw new ArithmeticException(); - } - GF2Polynomial b = new GF2Polynomial(mDegree, "ONE"); - GF2Polynomial c = new GF2Polynomial(mDegree); - GF2Polynomial u = getGF2Polynomial(); - GF2Polynomial v = mField.getFieldPolynomial(); - GF2Polynomial h; - while (true) - { - while (!u.testBit(0)) - { // x|u (x divides u) - u.shiftRightThis(); // u = u / x - if (!b.testBit(0)) - { - b.shiftRightThis(); - } - else - { - b.addToThis(mField.getFieldPolynomial()); - b.shiftRightThis(); - } - } - if (u.isOne()) - { - return new GF2nPolynomialElement((GF2nPolynomialField)mField, - b); - } - u.reduceN(); - v.reduceN(); - if (u.getLength() < v.getLength()) - { - h = u; - u = v; - v = h; - h = b; - b = c; - c = h; - } - u.addToThis(v); - b.addToThis(c); - } - } - - /** - * This method is used internally to map the square()-calls within - * GF2nPolynomialElement to one of the possible squaring methods. - * - * @return this2 (newly created) - * @see GF2nPolynomialElement#squarePreCalc - */ - public GF2nElement square() - { - return squarePreCalc(); - } - - /** - * This method is used internally to map the square()-calls within - * GF2nPolynomialElement to one of the possible squaring methods. - */ - public void squareThis() - { - squareThisPreCalc(); - } - - /** - * Squares this GF2nPolynomialElement using GF2nField's squaring matrix. - * This is supposed to be fast when using a polynomial (no tri- or - * pentanomial) as fieldpolynomial. Use squarePreCalc when using a tri- or - * pentanomial as fieldpolynomial instead. - * - * @return this2 (newly created) - * @see GF2Polynomial#vectorMult - * @see GF2nPolynomialElement#squarePreCalc - * @see GF2nPolynomialElement#squareBitwise - */ - public GF2nPolynomialElement squareMatrix() - { - GF2nPolynomialElement result = new GF2nPolynomialElement(this); - result.squareThisMatrix(); - result.reduceThis(); - return result; - } - - /** - * Squares this GF2nPolynomialElement using GF2nFields squaring matrix. This - * is supposed to be fast when using a polynomial (no tri- or pentanomial) - * as fieldpolynomial. Use squarePreCalc when using a tri- or pentanomial as - * fieldpolynomial instead. - * - * @see GF2Polynomial#vectorMult - * @see GF2nPolynomialElement#squarePreCalc - * @see GF2nPolynomialElement#squareBitwise - */ - public void squareThisMatrix() - { - GF2Polynomial result = new GF2Polynomial(mDegree); - for (int i = 0; i < mDegree; i++) - { - if (polynomial - .vectorMult(((GF2nPolynomialField)mField).squaringMatrix[mDegree - - i - 1])) - { - result.setBit(i); - - } - } - polynomial = result; - } - - /** - * Squares this GF2nPolynomialElement by shifting left its Bitstring and - * reducing. This is supposed to be the slowest method. Use squarePreCalc or - * squareMatrix instead. - * - * @return this2 (newly created) - * @see GF2nPolynomialElement#squareMatrix - * @see GF2nPolynomialElement#squarePreCalc - * @see GF2Polynomial#squareThisBitwise - */ - public GF2nPolynomialElement squareBitwise() - { - GF2nPolynomialElement result = new GF2nPolynomialElement(this); - result.squareThisBitwise(); - result.reduceThis(); - return result; - } - - /** - * Squares this GF2nPolynomialElement by shifting left its Bitstring and - * reducing. This is supposed to be the slowest method. Use squarePreCalc or - * squareMatrix instead. - * - * @see GF2nPolynomialElement#squareMatrix - * @see GF2nPolynomialElement#squarePreCalc - * @see GF2Polynomial#squareThisBitwise - */ - public void squareThisBitwise() - { - polynomial.squareThisBitwise(); - reduceThis(); - } - - /** - * Squares this GF2nPolynomialElement by using precalculated values and - * reducing. This is supposed to de fastest when using a trinomial or - * pentanomial as field polynomial. Use squareMatrix when using a ordinary - * polynomial as field polynomial. - * - * @return this2 (newly created) - * @see GF2nPolynomialElement#squareMatrix - * @see GF2Polynomial#squareThisPreCalc - */ - public GF2nPolynomialElement squarePreCalc() - { - GF2nPolynomialElement result = new GF2nPolynomialElement(this); - result.squareThisPreCalc(); - result.reduceThis(); - return result; - } - - /** - * Squares this GF2nPolynomialElement by using precalculated values and - * reducing. This is supposed to de fastest when using a tri- or pentanomial - * as fieldpolynomial. Use squareMatrix when using a ordinary polynomial as - * fieldpolynomial. - * - * @see GF2nPolynomialElement#squareMatrix - * @see GF2Polynomial#squareThisPreCalc - */ - public void squareThisPreCalc() - { - polynomial.squareThisPreCalc(); - reduceThis(); - } - - /** - * Calculates this to the power of k and returns the result - * in a new GF2nPolynomialElement. - * - * @param k the power - * @return this^k in a new GF2nPolynomialElement - */ - public GF2nPolynomialElement power(int k) - { - if (k == 1) - { - return new GF2nPolynomialElement(this); - } - - GF2nPolynomialElement result = GF2nPolynomialElement - .ONE((GF2nPolynomialField)mField); - if (k == 0) - { - return result; - } - - GF2nPolynomialElement x = new GF2nPolynomialElement(this); - x.polynomial.expandN((x.mDegree << 1) + 32); // increase performance - x.polynomial.reduceN(); - - for (int i = 0; i < mDegree; i++) - { - if ((k & (1 << i)) != 0) - { - result.multiplyThisBy(x); - } - x.square(); - } - - return result; - } - - /** - * Compute the square root of this element and return the result in a new - * {@link GF2nPolynomialElement}. - * - * @return this1/2 (newly created) - */ - public GF2nElement squareRoot() - { - GF2nPolynomialElement result = new GF2nPolynomialElement(this); - result.squareRootThis(); - return result; - } - - /** - * Compute the square root of this element. - */ - public void squareRootThis() - { - // increase performance - polynomial.expandN((mDegree << 1) + 32); - polynomial.reduceN(); - for (int i = 0; i < mField.getDegree() - 1; i++) - { - squareThis(); - } - } - - /** - * Solves the quadratic equation z2 + z = this if - * such a solution exists. This method returns one of the two possible - * solutions. The other solution is z + 1. Use z.increase() to - * compute this solution. - * - * @return a GF2nPolynomialElement representing one z satisfying the - * equation z2 + z = this - * @see "IEEE 1363, Annex A.4.7" - */ - public GF2nElement solveQuadraticEquation() - throws RuntimeException - { - if (isZero()) - { - return ZERO((GF2nPolynomialField)mField); - } - - if ((mDegree & 1) == 1) - { - return halfTrace(); - } - - // TODO this can be sped-up by precomputation of p and w's - GF2nPolynomialElement z, w; - do - { - // step 1. - GF2nPolynomialElement p = new GF2nPolynomialElement( - (GF2nPolynomialField)mField, new Random()); - // step 2. - z = ZERO((GF2nPolynomialField)mField); - w = (GF2nPolynomialElement)p.clone(); - // step 3. - for (int i = 1; i < mDegree; i++) - { - // compute z = z^2 + w^2 * this - // and w = w^2 + p - z.squareThis(); - w.squareThis(); - z.addToThis(w.multiply(this)); - w.addToThis(p); - } - } - while (w.isZero()); // step 4. - - if (!equals(z.square().add(z))) - { - throw new RuntimeException(); - } - - // step 5. - return z; - } - - /** - * Returns the trace of this GF2nPolynomialElement. - * - * @return the trace of this GF2nPolynomialElement - */ - public int trace() - { - GF2nPolynomialElement t = new GF2nPolynomialElement(this); - int i; - - for (i = 1; i < mDegree; i++) - { - t.squareThis(); - t.addToThis(this); - } - - if (t.isOne()) - { - return 1; - } - return 0; - } - - /** - * Returns the half-trace of this GF2nPolynomialElement. - * - * @return a GF2nPolynomialElement representing the half-trace of this - * GF2nPolynomialElement. - */ - private GF2nPolynomialElement halfTrace() - throws RuntimeException - { - if ((mDegree & 0x01) == 0) - { - throw new RuntimeException(); - } - int i; - GF2nPolynomialElement h = new GF2nPolynomialElement(this); - - for (i = 1; i <= ((mDegree - 1) >> 1); i++) - { - h.squareThis(); - h.squareThis(); - h.addToThis(this); - } - - return h; - } - - /** - * Reduces this GF2nPolynomialElement modulo the field-polynomial. - * - * @see GF2Polynomial#reduceTrinomial - * @see GF2Polynomial#reducePentanomial - */ - private void reduceThis() - { - if (polynomial.getLength() > mDegree) - { // really reduce ? - if (((GF2nPolynomialField)mField).isTrinomial()) - { // fieldpolonomial - // is trinomial - int tc; - try - { - tc = ((GF2nPolynomialField)mField).getTc(); - } - catch (RuntimeException NATExc) - { - throw new RuntimeException( - "GF2nPolynomialElement.reduce: the field" - + " polynomial is not a trinomial"); - } - if (((mDegree - tc) <= 32) // do we have to use slow - // bitwise reduction ? - || (polynomial.getLength() > (mDegree << 1))) - { - reduceTrinomialBitwise(tc); - return; - } - polynomial.reduceTrinomial(mDegree, tc); - return; - } - else if (((GF2nPolynomialField)mField).isPentanomial()) - { // fieldpolynomial - // is - // pentanomial - int[] pc; - try - { - pc = ((GF2nPolynomialField)mField).getPc(); - } - catch (RuntimeException NATExc) - { - throw new RuntimeException( - "GF2nPolynomialElement.reduce: the field" - + " polynomial is not a pentanomial"); - } - if (((mDegree - pc[2]) <= 32) // do we have to use slow - // bitwise reduction ? - || (polynomial.getLength() > (mDegree << 1))) - { - reducePentanomialBitwise(pc); - return; - } - polynomial.reducePentanomial(mDegree, pc); - return; - } - else - { // fieldpolynomial is something else - polynomial = polynomial.remainder(mField.getFieldPolynomial()); - polynomial.expandN(mDegree); - return; - } - } - if (polynomial.getLength() < mDegree) - { - polynomial.expandN(mDegree); - } - } - - /** - * Reduce this GF2nPolynomialElement using the trinomial x^n + x^tc + 1 as - * fieldpolynomial. The coefficients are reduced bit by bit. - */ - private void reduceTrinomialBitwise(int tc) - { - int i; - int k = mDegree - tc; - for (i = polynomial.getLength() - 1; i >= mDegree; i--) - { - if (polynomial.testBit(i)) - { - - polynomial.xorBit(i); - polynomial.xorBit(i - k); - polynomial.xorBit(i - mDegree); - - } - } - polynomial.reduceN(); - polynomial.expandN(mDegree); - } - - /** - * Reduce this GF2nPolynomialElement using the pentanomial x^n + x^pc[2] + - * x^pc[1] + x^pc[0] + 1 as fieldpolynomial. The coefficients are reduced - * bit by bit. - */ - private void reducePentanomialBitwise(int[] pc) - { - int i; - int k = mDegree - pc[2]; - int l = mDegree - pc[1]; - int m = mDegree - pc[0]; - for (i = polynomial.getLength() - 1; i >= mDegree; i--) - { - if (polynomial.testBit(i)) - { - polynomial.xorBit(i); - polynomial.xorBit(i - k); - polynomial.xorBit(i - l); - polynomial.xorBit(i - m); - polynomial.xorBit(i - mDegree); - - } - } - polynomial.reduceN(); - polynomial.expandN(mDegree); - } - - // ///////////////////////////////////////////////////////////////////// - // conversion - // ///////////////////////////////////////////////////////////////////// - - /** - * Returns a string representing this Bitstrings value using hexadecimal - * radix in MSB-first order. - * - * @return a String representing this Bitstrings value. - */ - public String toString() - { - return polynomial.toString(16); - } - - /** - * Returns a string representing this Bitstrings value using hexadecimal or - * binary radix in MSB-first order. - * - * @param radix the radix to use (2 or 16, otherwise 2 is used) - * @return a String representing this Bitstrings value. - */ - public String toString(int radix) - { - return polynomial.toString(radix); - } - - /** - * Converts this GF2nPolynomialElement to a byte[] according to 1363. - * - * @return a byte[] representing the value of this GF2nPolynomialElement - * @see "P1363 5.5.2 p22f BS2OSP, FE2OSP" - */ - public byte[] toByteArray() - { - return polynomial.toByteArray(); - } - - /** - * Converts this GF2nPolynomialElement to an integer according to 1363. - * - * @return a BigInteger representing the value of this - * GF2nPolynomialElement - * @see "P1363 5.5.1 p22 BS2IP" - */ - public BigInteger toFlexiBigInt() - { - return polynomial.toFlexiBigInt(); - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nPolynomialField.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nPolynomialField.java deleted file mode 100644 index 854cddf09d..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GF2nPolynomialField.java +++ /dev/null @@ -1,559 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - - -import java.security.SecureRandom; -import java.util.Vector; - - -/** - * This class implements the abstract class GF2nField for polynomial - * representation. It computes the field polynomial and the squaring matrix. - * GF2nField is used by GF2nPolynomialElement which implements the elements of - * this field. - * - * @see GF2nField - * @see GF2nPolynomialElement - */ -public class GF2nPolynomialField - extends GF2nField -{ - - /** - * Matrix used for fast squaring - */ - GF2Polynomial[] squaringMatrix; - - // field polynomial is a trinomial - private boolean isTrinomial = false; - - // field polynomial is a pentanomial - private boolean isPentanomial = false; - - // middle coefficient of the field polynomial in case it is a trinomial - private int tc; - - // middle 3 coefficients of the field polynomial in case it is a pentanomial - private int[] pc = new int[3]; - - /** - * constructs an instance of the finite field with 2deg - * elements and characteristic 2. - * - * @param deg the extention degree of this field - * @param random source of randomness for generating new polynomials. - */ - public GF2nPolynomialField(int deg, SecureRandom random) - { - super(random); - - if (deg < 3) - { - throw new IllegalArgumentException("k must be at least 3"); - } - mDegree = deg; - computeFieldPolynomial(); - computeSquaringMatrix(); - fields = new Vector(); - matrices = new Vector(); - } - - /** - * constructs an instance of the finite field with 2deg - * elements and characteristic 2. - * - * @param deg the degree of this field - * @param random source of randomness for generating new polynomials. - * @param file true if you want to read the field polynomial from the - * file false if you want to use a random fielpolynomial - * (this can take very long for huge degrees) - */ - public GF2nPolynomialField(int deg, SecureRandom random, boolean file) - { - super(random); - - if (deg < 3) - { - throw new IllegalArgumentException("k must be at least 3"); - } - mDegree = deg; - if (file) - { - computeFieldPolynomial(); - } - else - { - computeFieldPolynomial2(); - } - computeSquaringMatrix(); - fields = new Vector(); - matrices = new Vector(); - } - - /** - * Creates a new GF2nField of degree i and uses the given - * polynomial as field polynomial. The polynomial is checked - * whether it is irreducible. This can take some time if i is huge! - * - * @param deg degree of the GF2nField - * @param random source of randomness for generating new polynomials. - * @param polynomial the field polynomial to use - */ - public GF2nPolynomialField(int deg, SecureRandom random, GF2Polynomial polynomial) - throws RuntimeException - { - super(random); - - if (deg < 3) - { - throw new IllegalArgumentException("degree must be at least 3"); - } - if (polynomial.getLength() != deg + 1) - { - throw new RuntimeException(); - } - if (!polynomial.isIrreducible()) - { - throw new RuntimeException(); - } - mDegree = deg; - // fieldPolynomial = new Bitstring(polynomial); - fieldPolynomial = polynomial; - computeSquaringMatrix(); - int k = 2; // check if the polynomial is a trinomial or pentanomial - for (int j = 1; j < fieldPolynomial.getLength() - 1; j++) - { - if (fieldPolynomial.testBit(j)) - { - k++; - if (k == 3) - { - tc = j; - } - if (k <= 5) - { - pc[k - 3] = j; - } - } - } - if (k == 3) - { - isTrinomial = true; - } - if (k == 5) - { - isPentanomial = true; - } - fields = new Vector(); - matrices = new Vector(); - } - - /** - * Returns true if the field polynomial is a trinomial. The coefficient can - * be retrieved using getTc(). - * - * @return true if the field polynomial is a trinomial - */ - public boolean isTrinomial() - { - return isTrinomial; - } - - /** - * Returns true if the field polynomial is a pentanomial. The coefficients - * can be retrieved using getPc(). - * - * @return true if the field polynomial is a pentanomial - */ - public boolean isPentanomial() - { - return isPentanomial; - } - - /** - * Returns the degree of the middle coefficient of the used field trinomial - * (x^n + x^(getTc()) + 1). - * - * @return the middle coefficient of the used field trinomial - */ - public int getTc() - throws RuntimeException - { - if (!isTrinomial) - { - throw new RuntimeException(); - } - return tc; - } - - /** - * Returns the degree of the middle coefficients of the used field - * pentanomial (x^n + x^(getPc()[2]) + x^(getPc()[1]) + x^(getPc()[0]) + 1). - * - * @return the middle coefficients of the used field pentanomial - */ - public int[] getPc() - throws RuntimeException - { - if (!isPentanomial) - { - throw new RuntimeException(); - } - int[] result = new int[3]; - System.arraycopy(pc, 0, result, 0, 3); - return result; - } - - /** - * Return row vector i of the squaring matrix. - * - * @param i the index of the row vector to return - * @return a copy of squaringMatrix[i] - * @see GF2nPolynomialElement#squareMatrix - */ - public GF2Polynomial getSquaringVector(int i) - { - return new GF2Polynomial(squaringMatrix[i]); - } - - /** - * Compute a random root of the given GF2Polynomial. - * - * @param polynomial the polynomial - * @return a random root of polynomial - */ - protected GF2nElement getRandomRoot(GF2Polynomial polynomial) - { - // We are in B1!!! - GF2nPolynomial c; - GF2nPolynomial ut; - GF2nElement u; - GF2nPolynomial h; - int hDegree; - // 1. Set g(t) <- f(t) - GF2nPolynomial g = new GF2nPolynomial(polynomial, this); - int gDegree = g.getDegree(); - int i; - - // 2. while deg(g) > 1 - while (gDegree > 1) - { - do - { - // 2.1 choose random u (element of) GF(2^m) - u = new GF2nPolynomialElement(this, random); - ut = new GF2nPolynomial(2, GF2nPolynomialElement.ZERO(this)); - // 2.2 Set c(t) <- ut - ut.set(1, u); - c = new GF2nPolynomial(ut); - // 2.3 For i from 1 to m-1 do - for (i = 1; i <= mDegree - 1; i++) - { - // 2.3.1 c(t) <- (c(t)^2 + ut) mod g(t) - c = c.multiplyAndReduce(c, g); - c = c.add(ut); - } - // 2.4 set h(t) <- GCD(c(t), g(t)) - h = c.gcd(g); - // 2.5 if h(t) is constant or deg(g) = deg(h) then go to - // step 2.1 - hDegree = h.getDegree(); - gDegree = g.getDegree(); - } - while ((hDegree == 0) || (hDegree == gDegree)); - // 2.6 If 2deg(h) > deg(g) then set g(t) <- g(t)/h(t) ... - if ((hDegree << 1) > gDegree) - { - g = g.quotient(h); - } - else - { - // ... else g(t) <- h(t) - g = new GF2nPolynomial(h); - } - gDegree = g.getDegree(); - } - // 3. Output g(0) - return g.at(0); - - } - - /** - * Computes the change-of-basis matrix for basis conversion according to - * 1363. The result is stored in the lists fields and matrices. - * - * @param B1 the GF2nField to convert to - * @see "P1363 A.7.3, p111ff" - */ - protected void computeCOBMatrix(GF2nField B1) - { - // we are in B0 here! - if (mDegree != B1.mDegree) - { - throw new IllegalArgumentException( - "GF2nPolynomialField.computeCOBMatrix: B1 has a different " - + "degree and thus cannot be coverted to!"); - } - if (B1 instanceof GF2nONBField) - { - // speedup (calculation is done in PolynomialElements instead of - // ONB) - B1.computeCOBMatrix(this); - return; - } - int i, j; - GF2nElement[] gamma; - GF2nElement u; - GF2Polynomial[] COBMatrix = new GF2Polynomial[mDegree]; - for (i = 0; i < mDegree; i++) - { - COBMatrix[i] = new GF2Polynomial(mDegree); - } - - // find Random Root - do - { - // u is in representation according to B1 - u = B1.getRandomRoot(fieldPolynomial); - } - while (u.isZero()); - - // build gamma matrix by multiplying by u - if (u instanceof GF2nONBElement) - { - gamma = new GF2nONBElement[mDegree]; - gamma[mDegree - 1] = GF2nONBElement.ONE((GF2nONBField)B1); - } - else - { - gamma = new GF2nPolynomialElement[mDegree]; - gamma[mDegree - 1] = GF2nPolynomialElement - .ONE((GF2nPolynomialField)B1); - } - gamma[mDegree - 2] = u; - for (i = mDegree - 3; i >= 0; i--) - { - gamma[i] = (GF2nElement)gamma[i + 1].multiply(u); - } - if (B1 instanceof GF2nONBField) - { - // convert horizontal gamma matrix by vertical Bitstrings - for (i = 0; i < mDegree; i++) - { - for (j = 0; j < mDegree; j++) - { - // TODO remember: ONB treats its Bits in reverse order !!! - if (gamma[i].testBit(mDegree - j - 1)) - { - COBMatrix[mDegree - j - 1].setBit(mDegree - i - 1); - } - } - } - } - else - { - // convert horizontal gamma matrix by vertical Bitstrings - for (i = 0; i < mDegree; i++) - { - for (j = 0; j < mDegree; j++) - { - if (gamma[i].testBit(j)) - { - COBMatrix[mDegree - j - 1].setBit(mDegree - i - 1); - } - } - } - } - - // store field and matrix for further use - fields.addElement(B1); - matrices.addElement(COBMatrix); - // store field and inverse matrix for further use in B1 - B1.fields.addElement(this); - B1.matrices.addElement(invertMatrix(COBMatrix)); - } - - /** - * Computes a new squaring matrix used for fast squaring. - * - * @see GF2nPolynomialElement#square - */ - private void computeSquaringMatrix() - { - GF2Polynomial[] d = new GF2Polynomial[mDegree - 1]; - int i, j; - squaringMatrix = new GF2Polynomial[mDegree]; - for (i = 0; i < squaringMatrix.length; i++) - { - squaringMatrix[i] = new GF2Polynomial(mDegree, "ZERO"); - } - - for (i = 0; i < mDegree - 1; i++) - { - d[i] = new GF2Polynomial(1, "ONE").shiftLeft(mDegree + i) - .remainder(fieldPolynomial); - } - for (i = 1; i <= Math.abs(mDegree >> 1); i++) - { - for (j = 1; j <= mDegree; j++) - { - if (d[mDegree - (i << 1)].testBit(mDegree - j)) - { - squaringMatrix[j - 1].setBit(mDegree - i); - } - } - } - for (i = Math.abs(mDegree >> 1) + 1; i <= mDegree; i++) - { - squaringMatrix[(i << 1) - mDegree - 1].setBit(mDegree - i); - } - - } - - /** - * Computes the field polynomial. This can take a long time for big degrees. - */ - protected void computeFieldPolynomial() - { - if (testTrinomials()) - { - return; - } - if (testPentanomials()) - { - return; - } - testRandom(); - } - - /** - * Computes the field polynomial. This can take a long time for big degrees. - */ - protected void computeFieldPolynomial2() - { - if (testTrinomials()) - { - return; - } - if (testPentanomials()) - { - return; - } - testRandom(); - } - - /** - * Tests all trinomials of degree (n+1) until a irreducible is found and - * stores the result in field polynomial. Returns false if no - * irreducible trinomial exists in GF(2^n). This can take very long for huge - * degrees. - * - * @return true if an irreducible trinomial is found - */ - private boolean testTrinomials() - { - int i, l; - boolean done = false; - l = 0; - - fieldPolynomial = new GF2Polynomial(mDegree + 1); - fieldPolynomial.setBit(0); - fieldPolynomial.setBit(mDegree); - for (i = 1; (i < mDegree) && !done; i++) - { - fieldPolynomial.setBit(i); - done = fieldPolynomial.isIrreducible(); - l++; - if (done) - { - isTrinomial = true; - tc = i; - return done; - } - fieldPolynomial.resetBit(i); - done = fieldPolynomial.isIrreducible(); - } - - return done; - } - - /** - * Tests all pentanomials of degree (n+1) until a irreducible is found and - * stores the result in field polynomial. Returns false if no - * irreducible pentanomial exists in GF(2^n). This can take very long for - * huge degrees. - * - * @return true if an irreducible pentanomial is found - */ - private boolean testPentanomials() - { - int i, j, k, l; - boolean done = false; - l = 0; - - fieldPolynomial = new GF2Polynomial(mDegree + 1); - fieldPolynomial.setBit(0); - fieldPolynomial.setBit(mDegree); - for (i = 1; (i <= (mDegree - 3)) && !done; i++) - { - fieldPolynomial.setBit(i); - for (j = i + 1; (j <= (mDegree - 2)) && !done; j++) - { - fieldPolynomial.setBit(j); - for (k = j + 1; (k <= (mDegree - 1)) && !done; k++) - { - fieldPolynomial.setBit(k); - if (((mDegree & 1) != 0) | ((i & 1) != 0) | ((j & 1) != 0) - | ((k & 1) != 0)) - { - done = fieldPolynomial.isIrreducible(); - l++; - if (done) - { - isPentanomial = true; - pc[0] = i; - pc[1] = j; - pc[2] = k; - return done; - } - } - fieldPolynomial.resetBit(k); - } - fieldPolynomial.resetBit(j); - } - fieldPolynomial.resetBit(i); - } - - return done; - } - - /** - * Tests random polynomials of degree (n+1) until an irreducible is found - * and stores the result in field polynomial. This can take very - * long for huge degrees. - * - * @return true - */ - private boolean testRandom() - { - int l; - boolean done = false; - - fieldPolynomial = new GF2Polynomial(mDegree + 1); - l = 0; - while (!done) - { - l++; - fieldPolynomial.randomize(); - fieldPolynomial.setBit(mDegree); - fieldPolynomial.setBit(0); - if (fieldPolynomial.isIrreducible()) - { - done = true; - return done; - } - } - - return done; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GFElement.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GFElement.java deleted file mode 100644 index 2caba9d082..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GFElement.java +++ /dev/null @@ -1,151 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -import java.math.BigInteger; - - -/** - * This interface defines a finite field element. It is implemented by the - * class {@link GF2nElement}. - * - * @see GF2nElement - */ -public interface GFElement -{ - - /** - * @return a copy of this GFElement - */ - Object clone(); - - // ///////////////////////////////////////////////////////////////// - // comparison - // ///////////////////////////////////////////////////////////////// - - /** - * Compare this curve with another object. - * - * @param other the other object - * @return the result of the comparison - */ - boolean equals(Object other); - - /** - * @return the hash code of this element - */ - int hashCode(); - - /** - * Checks whether this element is zero. - * - * @return true if this is the zero element - */ - boolean isZero(); - - /** - * Checks whether this element is one. - * - * @return true if this is the one element - */ - boolean isOne(); - - // ///////////////////////////////////////////////////////////////////// - // arithmetic - // ///////////////////////////////////////////////////////////////////// - - /** - * Compute the sum of this element and the addend. - * - * @param addend the addend - * @return this + other (newly created) - */ - GFElement add(GFElement addend) - throws RuntimeException; - - /** - * Compute the sum of this element and the addend, overwriting this element. - * - * @param addend the addend - */ - void addToThis(GFElement addend) - throws RuntimeException; - - /** - * Compute the difference of this element and minuend. - * - * @param minuend the minuend - * @return this - minuend (newly created) - */ - GFElement subtract(GFElement minuend) - throws RuntimeException; - - /** - * Compute the difference of this element and minuend, - * overwriting this element. - * - * @param minuend the minuend - */ - void subtractFromThis(GFElement minuend); - - /** - * Compute the product of this element and factor. - * - * @param factor the factor - * @return this * factor (newly created) - */ - GFElement multiply(GFElement factor) - throws RuntimeException; - - /** - * Compute this * factor (overwrite this). - * - * @param factor the factor - */ - void multiplyThisBy(GFElement factor) - throws RuntimeException; - - /** - * Compute the multiplicative inverse of this element. - * - * @return this-1 (newly created) - * @throws ArithmeticException if this is the zero element. - */ - GFElement invert() - throws ArithmeticException; - - // ///////////////////////////////////////////////////////////////////// - // conversion - // ///////////////////////////////////////////////////////////////////// - - /** - * Returns this element as FlexiBigInt. The conversion is P1363-conform. - * - * @return this element as BigInt - */ - BigInteger toFlexiBigInt(); - - /** - * Returns this element as byte array. The conversion is P1363-conform. - * - * @return this element as byte array - */ - byte[] toByteArray(); - - /** - * Return a String representation of this element. - * - * @return String representation of this element - */ - String toString(); - - /** - * Return a String representation of this element. radix - * specifies the radix of the String representation. - * - * @param radix specifies the radix of the String representation - * @return String representation of this element with the specified radix - */ - String toString(int radix); - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GoppaCode.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GoppaCode.java deleted file mode 100644 index 2a03ff5361..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/GoppaCode.java +++ /dev/null @@ -1,310 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -import java.security.SecureRandom; - -/** - * This class describes decoding operations of an irreducible binary Goppa code. - * A check matrix H of the Goppa code and an irreducible Goppa polynomial are - * used the operations are worked over a finite field GF(2^m) - * - * @see GF2mField - * @see PolynomialGF2mSmallM - */ -public final class GoppaCode -{ - - /** - * Default constructor (private). - */ - private GoppaCode() - { - // empty - } - - /** - * This class is a container for two instances of {@link GF2Matrix} and one - * instance of {@link Permutation}. It is used to hold the systematic form - * S*H*P = (Id|M) of the check matrix H as returned by - * {@link GoppaCode#computeSystematicForm(GF2Matrix, SecureRandom)}. - * - * @see GF2Matrix - * @see Permutation - */ - public static class MaMaPe - { - - private GF2Matrix s, h; - - private Permutation p; - - /** - * Construct a new {@link MaMaPe} container with the given parameters. - * - * @param s the first matrix - * @param h the second matrix - * @param p the permutation - */ - public MaMaPe(GF2Matrix s, GF2Matrix h, Permutation p) - { - this.s = s; - this.h = h; - this.p = p; - } - - /** - * @return the first matrix - */ - public GF2Matrix getFirstMatrix() - { - return s; - } - - /** - * @return the second matrix - */ - public GF2Matrix getSecondMatrix() - { - return h; - } - - /** - * @return the permutation - */ - public Permutation getPermutation() - { - return p; - } - } - - /** - * This class is a container for an instance of {@link GF2Matrix} and one - * int[]. It is used to hold a generator matrix and the set of indices such - * that the submatrix of the generator matrix consisting of the specified - * columns is the identity. - * - * @see GF2Matrix - * @see Permutation - */ - public static class MatrixSet - { - - private GF2Matrix g; - - private int[] setJ; - - /** - * Construct a new {@link MatrixSet} container with the given - * parameters. - * - * @param g the generator matrix - * @param setJ the set of indices such that the submatrix of the - * generator matrix consisting of the specified columns - * is the identity - */ - public MatrixSet(GF2Matrix g, int[] setJ) - { - this.g = g; - this.setJ = setJ; - } - - /** - * @return the generator matrix - */ - public GF2Matrix getG() - { - return g; - } - - /** - * @return the set of indices such that the submatrix of the generator - * matrix consisting of the specified columns is the identity - */ - public int[] getSetJ() - { - return setJ; - } - } - - /** - * Construct the check matrix of a Goppa code in canonical form from the - * irreducible Goppa polynomial over the finite field - * GF(2m). - * - * @param field the finite field - * @param gp the irreducible Goppa polynomial - */ - public static GF2Matrix createCanonicalCheckMatrix(GF2mField field, - PolynomialGF2mSmallM gp) - { - int m = field.getDegree(); - int n = 1 << m; - int t = gp.getDegree(); - - /* create matrix H over GF(2^m) */ - - int[][] hArray = new int[t][n]; - - // create matrix YZ - int[][] yz = new int[t][n]; - for (int j = 0; j < n; j++) - { - // here j is used as index and as element of field GF(2^m) - yz[0][j] = field.inverse(gp.evaluateAt(j)); - } - - for (int i = 1; i < t; i++) - { - for (int j = 0; j < n; j++) - { - // here j is used as index and as element of field GF(2^m) - yz[i][j] = field.mult(yz[i - 1][j], j); - } - } - - // create matrix H = XYZ - for (int i = 0; i < t; i++) - { - for (int j = 0; j < n; j++) - { - for (int k = 0; k <= i; k++) - { - hArray[i][j] = field.add(hArray[i][j], field.mult(yz[k][j], - gp.getCoefficient(t + k - i))); - } - } - } - - /* convert to matrix over GF(2) */ - - int[][] result = new int[t * m][(n + 31) >>> 5]; - - for (int j = 0; j < n; j++) - { - int q = j >>> 5; - int r = 1 << (j & 0x1f); - for (int i = 0; i < t; i++) - { - int e = hArray[i][j]; - for (int u = 0; u < m; u++) - { - int b = (e >>> u) & 1; - if (b != 0) - { - int ind = (i + 1) * m - u - 1; - result[ind][q] ^= r; - } - } - } - } - - return new GF2Matrix(n, result); - } - - /** - * Given a check matrix H, compute matrices S, - * M, and a random permutation P such that - * S*H*P = (Id|M). Return S^-1, M, and - * P as {@link MaMaPe}. The matrix (Id | M) is called - * the systematic form of H. - * - * @param h the check matrix - * @param sr a source of randomness - * @return the tuple (S^-1, M, P) - */ - public static MaMaPe computeSystematicForm(GF2Matrix h, SecureRandom sr) - { - int n = h.getNumColumns(); - GF2Matrix hp, sInv; - GF2Matrix s = null; - Permutation p; - boolean found = false; - - do - { - p = new Permutation(n, sr); - hp = (GF2Matrix)h.rightMultiply(p); - sInv = hp.getLeftSubMatrix(); - try - { - found = true; - s = (GF2Matrix)sInv.computeInverse(); - } - catch (ArithmeticException ae) - { - found = false; - } - } - while (!found); - - GF2Matrix shp = (GF2Matrix)s.rightMultiply(hp); - GF2Matrix m = shp.getRightSubMatrix(); - - return new MaMaPe(sInv, m, p); - } - - /** - * Find an error vector e over GF(2) from an input - * syndrome s over GF(2m). - * - * @param syndVec the syndrome - * @param field the finite field - * @param gp the irreducible Goppa polynomial - * @param sqRootMatrix the matrix for computing square roots in - * (GF(2m))t - * @return the error vector - */ - public static GF2Vector syndromeDecode(GF2Vector syndVec, GF2mField field, - PolynomialGF2mSmallM gp, PolynomialGF2mSmallM[] sqRootMatrix) - { - - int n = 1 << field.getDegree(); - - // the error vector - GF2Vector errors = new GF2Vector(n); - - // if the syndrome vector is zero, the error vector is also zero - if (!syndVec.isZero()) - { - // convert syndrome vector to polynomial over GF(2^m) - PolynomialGF2mSmallM syndrome = new PolynomialGF2mSmallM(syndVec - .toExtensionFieldVector(field)); - - // compute T = syndrome^-1 mod gp - PolynomialGF2mSmallM t = syndrome.modInverse(gp); - - // compute tau = sqRoot(T + X) mod gp - PolynomialGF2mSmallM tau = t.addMonomial(1); - tau = tau.modSquareRootMatrix(sqRootMatrix); - - // compute polynomials a and b satisfying a + b*tau = 0 mod gp - PolynomialGF2mSmallM[] ab = tau.modPolynomialToFracton(gp); - - // compute the polynomial a^2 + X*b^2 - PolynomialGF2mSmallM a2 = ab[0].multiply(ab[0]); - PolynomialGF2mSmallM b2 = ab[1].multiply(ab[1]); - PolynomialGF2mSmallM xb2 = b2.multWithMonomial(1); - PolynomialGF2mSmallM a2plusXb2 = a2.add(xb2); - - // normalize a^2 + X*b^2 to obtain the error locator polynomial - int headCoeff = a2plusXb2.getHeadCoefficient(); - int invHeadCoeff = field.inverse(headCoeff); - PolynomialGF2mSmallM elp = a2plusXb2.multWithElement(invHeadCoeff); - - // for all elements i of GF(2^m) - for (int i = 0; i < n; i++) - { - // evaluate the error locator polynomial at i - int z = elp.evaluateAt(i); - // if polynomial evaluates to zero - if (z == 0) - { - // set the i-th coefficient of the error vector - errors.setBit(i); - } - } - } - - return errors; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/IntUtils.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/IntUtils.java deleted file mode 100644 index 3afc04dab2..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/IntUtils.java +++ /dev/null @@ -1,179 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -public final class IntUtils -{ - - /** - * Default constructor (private). - */ - private IntUtils() - { - // empty - } - - /** - * Compare two int arrays. No null checks are performed. - * - * @param left the first int array - * @param right the second int array - * @return the result of the comparison - */ - public static boolean equals(int[] left, int[] right) - { - if (left.length != right.length) - { - return false; - } - boolean result = true; - for (int i = left.length - 1; i >= 0; i--) - { - result &= left[i] == right[i]; - } - return result; - } - - /** - * Return a clone of the given int array. No null checks are performed. - * - * @param array the array to clone - * @return the clone of the given array - */ - public static int[] clone(int[] array) - { - int[] result = new int[array.length]; - System.arraycopy(array, 0, result, 0, array.length); - return result; - } - - /** - * Fill the given int array with the given value. - * - * @param array the array - * @param value the value - */ - public static void fill(int[] array, int value) - { - for (int i = array.length - 1; i >= 0; i--) - { - array[i] = value; - } - } - - /** - * Sorts this array of integers according to the Quicksort algorithm. After - * calling this method this array is sorted in ascending order with the - * smallest integer taking position 0 in the array. - *

    - * This implementation is based on the quicksort algorithm as described in - * Data Structures In Java by Thomas A. Standish, Chapter 10, - * ISBN 0-201-30564-X. - * - * @param source the array of integers that needs to be sorted. - */ - public static void quicksort(int[] source) - { - quicksort(source, 0, source.length - 1); - } - - /** - * Sort a subarray of a source array. The subarray is specified by its start - * and end index. - * - * @param source the int array to be sorted - * @param left the start index of the subarray - * @param right the end index of the subarray - */ - public static void quicksort(int[] source, int left, int right) - { - if (right > left) - { - int index = partition(source, left, right, right); - quicksort(source, left, index - 1); - quicksort(source, index + 1, right); - } - } - - /** - * Split a subarray of a source array into two partitions. The left - * partition contains elements that have value less than or equal to the - * pivot element, the right partition contains the elements that have larger - * value. - * - * @param source the int array whose subarray will be splitted - * @param left the start position of the subarray - * @param right the end position of the subarray - * @param pivotIndex the index of the pivot element inside the array - * @return the new index of the pivot element inside the array - */ - private static int partition(int[] source, int left, int right, - int pivotIndex) - { - - int pivot = source[pivotIndex]; - source[pivotIndex] = source[right]; - source[right] = pivot; - - int index = left; - - for (int i = left; i < right; i++) - { - if (source[i] <= pivot) - { - int tmp = source[index]; - source[index] = source[i]; - source[i] = tmp; - index++; - } - } - - int tmp = source[index]; - source[index] = source[right]; - source[right] = tmp; - - return index; - } - - /** - * Generates a subarray of a given int array. - * - * @param input - - * the input int array - * @param start - - * the start index - * @param end - - * the end index - * @return a subarray of input, ranging from start to - * end - */ - public static int[] subArray(final int[] input, final int start, - final int end) - { - int[] result = new int[end - start]; - System.arraycopy(input, start, result, 0, end - start); - return result; - } - - /** - * @param input an int array - * @return a human readable form of the given int array - */ - public static String toString(int[] input) - { - String result = ""; - for (int i = 0; i < input.length; i++) - { - result += input[i] + " "; - } - return result; - } - - /** - * @param input an int arary - * @return the int array as hex string - */ - public static String toHexString(int[] input) - { - return ByteUtils.toHexString(BigEndianConversions.toByteArray(input)); - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/IntegerFunctions.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/IntegerFunctions.java deleted file mode 100644 index 8e44d10523..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/IntegerFunctions.java +++ /dev/null @@ -1,1276 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -import java.math.BigInteger; -import java.security.SecureRandom; - -import org.bouncycastle.crypto.CryptoServicesRegistrar; -import org.bouncycastle.util.BigIntegers; - -/** - * Class of number-theory related functions for use with integers represented as - * int's or BigInteger objects. - */ -public final class IntegerFunctions -{ - - private static final BigInteger ZERO = BigInteger.valueOf(0); - - private static final BigInteger ONE = BigInteger.valueOf(1); - - private static final BigInteger TWO = BigInteger.valueOf(2); - - private static final BigInteger FOUR = BigInteger.valueOf(4); - - private static final int[] SMALL_PRIMES = {3, 5, 7, 11, 13, 17, 19, 23, - 29, 31, 37, 41}; - - private static final long SMALL_PRIME_PRODUCT = 3L * 5 * 7 * 11 * 13 * 17 - * 19 * 23 * 29 * 31 * 37 * 41; - - private static SecureRandom sr = null; - - // the jacobi function uses this lookup table - private static final int[] jacobiTable = {0, 1, 0, -1, 0, -1, 0, 1}; - - private IntegerFunctions() - { - // empty - } - - /** - * Computes the value of the Jacobi symbol (A|B). The following properties - * hold for the Jacobi symbol which makes it a very efficient way to - * evaluate the Legendre symbol - *

    - * (A|B) = 0 IF gcd(A,B) > 1
    - * (-1|B) = 1 IF n = 1 (mod 1)
    - * (-1|B) = -1 IF n = 3 (mod 4)
    - * (A|B) (C|B) = (AC|B)
    - * (A|B) (A|C) = (A|CB)
    - * (A|B) = (C|B) IF A = C (mod B)
    - * (2|B) = 1 IF N = 1 OR 7 (mod 8)
    - * (2|B) = 1 IF N = 3 OR 5 (mod 8) - * - * @param A integer value - * @param B integer value - * @return value of the jacobi symbol (A|B) - */ - public static int jacobi(BigInteger A, BigInteger B) - { - BigInteger a, b, v; - long k = 1; - - k = 1; - - // test trivial cases - if (B.equals(ZERO)) - { - a = A.abs(); - return a.equals(ONE) ? 1 : 0; - } - - if (!A.testBit(0) && !B.testBit(0)) - { - return 0; - } - - a = A; - b = B; - - if (b.signum() == -1) - { // b < 0 - b = b.negate(); // b = -b - if (a.signum() == -1) - { - k = -1; - } - } - - v = ZERO; - while (!b.testBit(0)) - { - v = v.add(ONE); // v = v + 1 - b = b.divide(TWO); // b = b/2 - } - - if (v.testBit(0)) - { - k = k * jacobiTable[a.intValue() & 7]; - } - - if (a.signum() < 0) - { // a < 0 - if (b.testBit(1)) - { - k = -k; // k = -k - } - a = a.negate(); // a = -a - } - - // main loop - while (a.signum() != 0) - { - v = ZERO; - while (!a.testBit(0)) - { // a is even - v = v.add(ONE); - a = a.divide(TWO); - } - if (v.testBit(0)) - { - k = k * jacobiTable[b.intValue() & 7]; - } - - if (a.compareTo(b) < 0) - { // a < b - // swap and correct intermediate result - BigInteger x = a; - a = b; - b = x; - if (a.testBit(1) && b.testBit(1)) - { - k = -k; - } - } - a = a.subtract(b); - } - - return b.equals(ONE) ? (int)k : 0; - } - - /** - * Computes the greatest common divisor of the two specified integers - * - * @param u - first integer - * @param v - second integer - * @return gcd(a, b) - */ - public static int gcd(int u, int v) - { - return BigInteger.valueOf(u).gcd(BigInteger.valueOf(v)).intValue(); - } - - /** - * Extended euclidian algorithm (computes gcd and representation). - * - * @param a the first integer - * @param b the second integer - * @return (g,u,v), where g = gcd(abs(a),abs(b)) = ua + vb - */ - public static int[] extGCD(int a, int b) - { - BigInteger ba = BigInteger.valueOf(a); - BigInteger bb = BigInteger.valueOf(b); - BigInteger[] bresult = extgcd(ba, bb); - int[] result = new int[3]; - result[0] = bresult[0].intValue(); - result[1] = bresult[1].intValue(); - result[2] = bresult[2].intValue(); - return result; - } - - public static BigInteger divideAndRound(BigInteger a, BigInteger b) - { - if (a.signum() < 0) - { - return divideAndRound(a.negate(), b).negate(); - } - if (b.signum() < 0) - { - return divideAndRound(a, b.negate()).negate(); - } - return a.shiftLeft(1).add(b).divide(b.shiftLeft(1)); - } - - public static BigInteger[] divideAndRound(BigInteger[] a, BigInteger b) - { - BigInteger[] out = new BigInteger[a.length]; - for (int i = 0; i < a.length; i++) - { - out[i] = divideAndRound(a[i], b); - } - return out; - } - - /** - * Compute the smallest integer that is greater than or equal to the - * logarithm to the base 2 of the given BigInteger. - * - * @param a the integer - * @return ceil[log(a)] - */ - public static int ceilLog(BigInteger a) - { - int result = 0; - BigInteger p = ONE; - while (p.compareTo(a) < 0) - { - result++; - p = p.shiftLeft(1); - } - return result; - } - - /** - * Compute the smallest integer that is greater than or equal to the - * logarithm to the base 2 of the given integer. - * - * @param a the integer - * @return ceil[log(a)] - */ - public static int ceilLog(int a) - { - int log = 0; - int i = 1; - while (i < a) - { - i <<= 1; - log++; - } - return log; - } - - /** - * Compute ceil(log_256 n), the number of bytes needed to encode - * the integer n. - * - * @param n the integer - * @return the number of bytes needed to encode n - */ - public static int ceilLog256(int n) - { - if (n == 0) - { - return 1; - } - int m; - if (n < 0) - { - m = -n; - } - else - { - m = n; - } - - int d = 0; - while (m > 0) - { - d++; - m >>>= 8; - } - return d; - } - - /** - * Compute ceil(log_256 n), the number of bytes needed to encode - * the long integer n. - * - * @param n the long integer - * @return the number of bytes needed to encode n - */ - public static int ceilLog256(long n) - { - if (n == 0) - { - return 1; - } - long m; - if (n < 0) - { - m = -n; - } - else - { - m = n; - } - - int d = 0; - while (m > 0) - { - d++; - m >>>= 8; - } - return d; - } - - /** - * Compute the integer part of the logarithm to the base 2 of the given - * integer. - * - * @param a the integer - * @return floor[log(a)] - */ - public static int floorLog(BigInteger a) - { - int result = -1; - BigInteger p = ONE; - while (p.compareTo(a) <= 0) - { - result++; - p = p.shiftLeft(1); - } - return result; - } - - /** - * Compute the integer part of the logarithm to the base 2 of the given - * integer. - * - * @param a the integer - * @return floor[log(a)] - */ - public static int floorLog(int a) - { - int h = 0; - if (a <= 0) - { - return -1; - } - int p = a >>> 1; - while (p > 0) - { - h++; - p >>>= 1; - } - - return h; - } - - /** - * Compute the largest h with 2^h | a if a!=0. - * - * @param a an integer - * @return the largest h with 2^h | a if a!=0, - * 0 otherwise - */ - public static int maxPower(int a) - { - int h = 0; - if (a != 0) - { - int p = 1; - while ((a & p) == 0) - { - h++; - p <<= 1; - } - } - - return h; - } - - /** - * @param a an integer - * @return the number of ones in the binary representation of an integer - * a - */ - public static int bitCount(int a) - { - int h = 0; - while (a != 0) - { - h += a & 1; - a >>>= 1; - } - - return h; - } - - /** - * determines the order of g modulo p, p prime and 1 < g < p. This algorithm - * is only efficient for small p (see X9.62-1998, p. 68). - * - * @param g an integer with 1 < g < p - * @param p a prime - * @return the order k of g (that is k is the smallest integer with - * gk = 1 mod p - */ - public static int order(int g, int p) - { - int b, j; - - b = g % p; // Reduce g mod p first. - j = 1; - - // Check whether g == 0 mod p (avoiding endless loop). - if (b == 0) - { - throw new IllegalArgumentException(g + " is not an element of Z/(" - + p + "Z)^*; it is not meaningful to compute its order."); - } - - // Compute the order of g mod p: - while (b != 1) - { - b *= g; - b %= p; - if (b < 0) - { - b += p; - } - j++; - } - - return j; - } - - /** - * Reduces an integer into a given interval - * - * @param n - the integer - * @param begin - left bound of the interval - * @param end - right bound of the interval - * @return n reduced into [begin,end] - */ - public static BigInteger reduceInto(BigInteger n, BigInteger begin, - BigInteger end) - { - return n.subtract(begin).mod(end.subtract(begin)).add(begin); - } - - /** - * Compute ae. - * - * @param a the base - * @param e the exponent - * @return ae - */ - public static int pow(int a, int e) - { - int result = 1; - while (e > 0) - { - if ((e & 1) == 1) - { - result *= a; - } - a *= a; - e >>>= 1; - } - return result; - } - - /** - * Compute ae. - * - * @param a the base - * @param e the exponent - * @return ae - */ - public static long pow(long a, int e) - { - long result = 1; - while (e > 0) - { - if ((e & 1) == 1) - { - result *= a; - } - a *= a; - e >>>= 1; - } - return result; - } - - /** - * Compute ae mod n. - * - * @param a the base - * @param e the exponent - * @param n the modulus - * @return ae mod n - */ - public static int modPow(int a, int e, int n) - { - if (n <= 0 || ((long)n * n) > Integer.MAX_VALUE || e < 0) - { - return 0; - } - int result = 1; - a = (a % n + n) % n; - while (e > 0) - { - if ((e & 1) == 1) - { - result = (result * a) % n; - } - a = (a * a) % n; - e >>>= 1; - } - return result; - } - - /** - * Extended euclidian algorithm (computes gcd and representation). - * - * @param a - the first integer - * @param b - the second integer - * @return (d,u,v), where d = gcd(a,b) = ua + vb - */ - public static BigInteger[] extgcd(BigInteger a, BigInteger b) - { - BigInteger u = ONE; - BigInteger v = ZERO; - BigInteger d = a; - if (b.signum() != 0) - { - BigInteger v1 = ZERO; - BigInteger v3 = b; - while (v3.signum() != 0) - { - BigInteger[] tmp = d.divideAndRemainder(v3); - BigInteger q = tmp[0]; - BigInteger t3 = tmp[1]; - BigInteger t1 = u.subtract(q.multiply(v1)); - u = v1; - d = v3; - v1 = t1; - v3 = t3; - } - v = d.subtract(a.multiply(u)).divide(b); - } - return new BigInteger[]{d, u, v}; - } - - /** - * Computation of the least common multiple of a set of BigIntegers. - * - * @param numbers - the set of numbers - * @return the lcm(numbers) - */ - public static BigInteger leastCommonMultiple(BigInteger[] numbers) - { - int n = numbers.length; - BigInteger result = numbers[0]; - for (int i = 1; i < n; i++) - { - BigInteger gcd = result.gcd(numbers[i]); - result = result.multiply(numbers[i]).divide(gcd); - } - return result; - } - - /** - * Returns a long integer whose value is (a mod m). This method - * differs from % in that it always returns a non-negative - * integer. - * - * @param a value on which the modulo operation has to be performed. - * @param m the modulus. - * @return a mod m - */ - public static long mod(long a, long m) - { - long result = a % m; - if (result < 0) - { - result += m; - } - return result; - } - - /** - * Computes the modular inverse of an integer a - * - * @param a - the integer to invert - * @param mod - the modulus - * @return a-1 mod n - */ - public static int modInverse(int a, int mod) - { - return BigInteger.valueOf(a).modInverse(BigInteger.valueOf(mod)) - .intValue(); - } - - /** - * Computes the modular inverse of an integer a - * - * @param a - the integer to invert - * @param mod - the modulus - * @return a-1 mod n - */ - public static long modInverse(long a, long mod) - { - return BigInteger.valueOf(a).modInverse(BigInteger.valueOf(mod)) - .longValue(); - } - - /** - * Tests whether an integer a is power of another integer - * p. - * - * @param a - the first integer - * @param p - the second integer - * @return n if a = p^n or -1 otherwise - */ - public static int isPower(int a, int p) - { - if (a <= 0) - { - return -1; - } - int n = 0; - int d = a; - while (d > 1) - { - if (d % p != 0) - { - return -1; - } - d /= p; - n++; - } - return n; - } - - /** - * Find and return the least non-trivial divisor of an integer a. - * - * @param a - the integer - * @return divisor p >1 or 1 if a = -1,0,1 - */ - public static int leastDiv(int a) - { - if (a < 0) - { - a = -a; - } - if (a == 0) - { - return 1; - } - if ((a & 1) == 0) - { - return 2; - } - int p = 3; - while (p <= (a / p)) - { - if ((a % p) == 0) - { - return p; - } - p += 2; - } - - return a; - } - - /** - * Miller-Rabin-Test, determines wether the given integer is probably prime - * or composite. This method returns true if the given integer is - * prime with probability 1 - 2-20. - * - * @param n the integer to test for primality - * @return true if the given integer is prime with probability - * 2-100, false otherwise - */ - public static boolean isPrime(int n) - { - if (n < 2) - { - return false; - } - if (n == 2) - { - return true; - } - if ((n & 1) == 0) - { - return false; - } - if (n < 42) - { - for (int i = 0; i < SMALL_PRIMES.length; i++) - { - if (n == SMALL_PRIMES[i]) - { - return true; - } - } - } - - if ((n % 3 == 0) || (n % 5 == 0) || (n % 7 == 0) || (n % 11 == 0) - || (n % 13 == 0) || (n % 17 == 0) || (n % 19 == 0) - || (n % 23 == 0) || (n % 29 == 0) || (n % 31 == 0) - || (n % 37 == 0) || (n % 41 == 0)) - { - return false; - } - - return BigInteger.valueOf(n).isProbablePrime(20); - } - - /** - * Short trial-division test to find out whether a number is not prime. This - * test is usually used before a Miller-Rabin primality test. - * - * @param candidate the number to test - * @return true if the number has no factor of the tested primes, - * false if the number is definitely composite - */ - public static boolean passesSmallPrimeTest(BigInteger candidate) - { - final int[] smallPrime = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, - 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, - 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, - 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, - 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, - 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, - 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, - 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, - 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, - 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, - 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, - 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, - 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, - 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, - 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, - 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, - 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, - 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, - 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, - 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, - 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499}; - - for (int i = 0; i < smallPrime.length; i++) - { - if (candidate.mod(BigInteger.valueOf(smallPrime[i])).equals( - ZERO)) - { - return false; - } - } - return true; - } - - /** - * Returns the largest prime smaller than the given integer - * - * @param n - upper bound - * @return the largest prime smaller than n, or 1 if - * n <= 2 - */ - public static int nextSmallerPrime(int n) - { - if (n <= 2) - { - return 1; - } - - if (n == 3) - { - return 2; - } - - if ((n & 1) == 0) - { - n--; - } - else - { - n -= 2; - } - - while (n > 3 && !isPrime(n)) - { - n -= 2; - } - return n; - } - - /** - * Compute the next probable prime greater than n with the - * specified certainty. - * - * @param n a integer number - * @param certainty the certainty that the generated number is prime - * @return the next prime greater than n - */ - public static BigInteger nextProbablePrime(BigInteger n, int certainty) - { - - if (n.signum() < 0 || n.signum() == 0 || n.equals(ONE)) - { - return TWO; - } - - BigInteger result = n.add(ONE); - - // Ensure an odd number - if (!result.testBit(0)) - { - result = result.add(ONE); - } - - while (true) - { - // Do cheap "pre-test" if applicable - if (result.bitLength() > 6) - { - long r = result.remainder( - BigInteger.valueOf(SMALL_PRIME_PRODUCT)).longValue(); - if ((r % 3 == 0) || (r % 5 == 0) || (r % 7 == 0) - || (r % 11 == 0) || (r % 13 == 0) || (r % 17 == 0) - || (r % 19 == 0) || (r % 23 == 0) || (r % 29 == 0) - || (r % 31 == 0) || (r % 37 == 0) || (r % 41 == 0)) - { - result = result.add(TWO); - continue; // Candidate is composite; try another - } - } - - // All candidates of bitLength 2 and 3 are prime by this point - if (result.bitLength() < 4) - { - return result; - } - - // The expensive test - if (result.isProbablePrime(certainty)) - { - return result; - } - - result = result.add(TWO); - } - } - - /** - * Compute the next probable prime greater than n with the default - * certainty (20). - * - * @param n a integer number - * @return the next prime greater than n - */ - public static BigInteger nextProbablePrime(BigInteger n) - { - return nextProbablePrime(n, 20); - } - - /** - * Computes the next prime greater than n. - * - * @param n a integer number - * @return the next prime greater than n - */ - public static BigInteger nextPrime(long n) - { - long i; - boolean found = false; - long result = 0; - - if (n <= 1) - { - return BigInteger.valueOf(2); - } - if (n == 2) - { - return BigInteger.valueOf(3); - } - - for (i = n + 1 + (n & 1); (i <= n << 1) && !found; i += 2) - { - for (long j = 3; (j <= i >> 1) && !found; j += 2) - { - if (i % j == 0) - { - found = true; - } - } - if (found) - { - found = false; - } - else - { - result = i; - found = true; - } - } - return BigInteger.valueOf(result); - } - - /** - * Computes the binomial coefficient (n|t) ("n over t"). Formula: - *

      - *
    • if n !=0 and t != 0 then (n|t) = Mult(i=1, t): (n-(i-1))/i
    • - *
    • if t = 0 then (n|t) = 1
    • - *
    • if n = 0 and t > 0 then (n|t) = 0
    • - *
    - * - * @param n - the "upper" integer - * @param t - the "lower" integer - * @return the binomialcoefficient "n over t" as BigInteger - */ - public static BigInteger binomial(int n, int t) - { - - BigInteger result = ONE; - - if (n == 0) - { - if (t == 0) - { - return result; - } - return ZERO; - } - - // the property (n|t) = (n|n-t) be used to reduce numbers of operations - if (t > (n >>> 1)) - { - t = n - t; - } - - for (int i = 1; i <= t; i++) - { - result = (result.multiply(BigInteger.valueOf(n - (i - 1)))) - .divide(BigInteger.valueOf(i)); - } - - return result; - } - - public static BigInteger randomize(BigInteger upperBound) - { - if (sr == null) - { - sr = CryptoServicesRegistrar.getSecureRandom(); - } - return randomize(upperBound, sr); - } - - public static BigInteger randomize(BigInteger upperBound, - SecureRandom prng) - { - int blen = upperBound.bitLength(); - BigInteger randomNum = BigInteger.valueOf(0); - - if (prng == null) - { - prng = sr != null ? sr : CryptoServicesRegistrar.getSecureRandom(); - } - - for (int i = 0; i < 20; i++) - { - randomNum = BigIntegers.createRandomBigInteger(blen, prng); - if (randomNum.compareTo(upperBound) < 0) - { - return randomNum; - } - } - return randomNum.mod(upperBound); - } - - /** - * Extract the truncated square root of a BigInteger. - * - * @param a - value out of which we extract the square root - * @return the truncated square root of a - */ - public static BigInteger squareRoot(BigInteger a) - { - int bl; - BigInteger result, remainder, b; - - if (a.compareTo(ZERO) < 0) - { - throw new ArithmeticException( - "cannot extract root of negative number" + a + "."); - } - - bl = a.bitLength(); - result = ZERO; - remainder = ZERO; - - // if the bit length is odd then extra step - if ((bl & 1) != 0) - { - result = result.add(ONE); - bl--; - } - - while (bl > 0) - { - remainder = remainder.multiply(FOUR); - remainder = remainder.add(BigInteger.valueOf((a.testBit(--bl) ? 2 - : 0) - + (a.testBit(--bl) ? 1 : 0))); - b = result.multiply(FOUR).add(ONE); - result = result.multiply(TWO); - if (remainder.compareTo(b) != -1) - { - result = result.add(ONE); - remainder = remainder.subtract(b); - } - } - - return result; - } - - /** - * Takes an approximation of the root from an integer base, using newton's - * algorithm - * - * @param base the base to take the root from - * @param root the root, for example 2 for a square root - */ - public static float intRoot(int base, int root) - { - float gNew = base / root; - float gOld = 0; - int counter = 0; - while (Math.abs(gOld - gNew) > 0.0001) - { - float gPow = floatPow(gNew, root); - while (Float.isInfinite(gPow)) - { - gNew = (gNew + gOld) / 2; - gPow = floatPow(gNew, root); - } - counter += 1; - gOld = gNew; - gNew = gOld - (gPow - base) / (root * floatPow(gOld, root - 1)); - } - return gNew; - } - - /** - * int power of a base float, only use for small ints - * - * @param f base float - * @param i power to be raised to. - * @return int power i of f - */ - public static float floatPow(float f, int i) - { - float g = 1; - for (; i > 0; i--) - { - g *= f; - } - return g; - } - - /** - * calculate the logarithm to the base 2. - * - * @param x any double value - * @return log_2(x) - * @deprecated use MathFunctions.log(double) instead - */ - public static double log(double x) - { - if (x > 0 && x < 1) - { - double d = 1 / x; - double result = -log(d); - return result; - } - - int tmp = 0; - double tmp2 = 1; - double d = x; - - while (d > 2) - { - d = d / 2; - tmp += 1; - tmp2 *= 2; - } - double rem = x / tmp2; - rem = logBKM(rem); - return tmp + rem; - } - - /** - * calculate the logarithm to the base 2. - * - * @param x any long value >=1 - * @return log_2(x) - * @deprecated use MathFunctions.log(long) instead - */ - public static double log(long x) - { - int tmp = floorLog(BigInteger.valueOf(x)); - long tmp2 = 1 << tmp; - double rem = (double)x / (double)tmp2; - rem = logBKM(rem); - return tmp + rem; - } - - /** - * BKM Algorithm to calculate logarithms to the base 2. - * - * @param arg a double value with 1<= arg<= 4.768462058 - * @return log_2(arg) - * @deprecated use MathFunctions.logBKM(double) instead - */ - private static double logBKM(double arg) - { - double ae[] = // A_e[k] = log_2 (1 + 0.5^k) - { - 1.0000000000000000000000000000000000000000000000000000000000000000000000000000, - 0.5849625007211561814537389439478165087598144076924810604557526545410982276485, - 0.3219280948873623478703194294893901758648313930245806120547563958159347765589, - 0.1699250014423123629074778878956330175196288153849621209115053090821964552970, - 0.0874628412503394082540660108104043540112672823448206881266090643866965081686, - 0.0443941193584534376531019906736094674630459333742491317685543002674288465967, - 0.0223678130284545082671320837460849094932677948156179815932199216587899627785, - 0.0112272554232541203378805844158839407281095943600297940811823651462712311786, - 0.0056245491938781069198591026740666017211096815383520359072957784732489771013, - 0.0028150156070540381547362547502839489729507927389771959487826944878598909400, - 0.0014081943928083889066101665016890524233311715793462235597709051792834906001, - 0.0007042690112466432585379340422201964456668872087249334581924550139514213168, - 0.0003521774803010272377989609925281744988670304302127133979341729842842377649, - 0.0001760994864425060348637509459678580940163670081839283659942864068257522373, - 0.0000880524301221769086378699983597183301490534085738474534831071719854721939, - 0.0000440268868273167176441087067175806394819146645511899503059774914593663365, - 0.0000220136113603404964890728830697555571275493801909791504158295359319433723, - 0.0000110068476674814423006223021573490183469930819844945565597452748333526464, - 0.0000055034343306486037230640321058826431606183125807276574241540303833251704, - 0.0000027517197895612831123023958331509538486493412831626219340570294203116559, - 0.0000013758605508411382010566802834037147561973553922354232704569052932922954, - 0.0000006879304394358496786728937442939160483304056131990916985043387874690617, - 0.0000003439652607217645360118314743718005315334062644619363447395987584138324, - 0.0000001719826406118446361936972479533123619972434705828085978955697643547921, - 0.0000000859913228686632156462565208266682841603921494181830811515318381744650, - 0.0000000429956620750168703982940244684787907148132725669106053076409624949917, - 0.0000000214978311976797556164155504126645192380395989504741781512309853438587, - 0.0000000107489156388827085092095702361647949603617203979413516082280717515504, - 0.0000000053744578294520620044408178949217773318785601260677517784797554422804, - 0.0000000026872289172287079490026152352638891824761667284401180026908031182361, - 0.0000000013436144592400232123622589569799954658536700992739887706412976115422, - 0.0000000006718072297764289157920422846078078155859484240808550018085324187007, - 0.0000000003359036149273187853169587152657145221968468364663464125722491530858, - 0.0000000001679518074734354745159899223037458278711244127245990591908996412262, - 0.0000000000839759037391617577226571237484864917411614198675604731728132152582, - 0.0000000000419879518701918839775296677020135040214077417929807824842667285938, - 0.0000000000209939759352486932678195559552767641474249812845414125580747434389, - 0.0000000000104969879676625344536740142096218372850561859495065136990936290929, - 0.0000000000052484939838408141817781356260462777942148580518406975851213868092, - 0.0000000000026242469919227938296243586262369156865545638305682553644113887909, - 0.0000000000013121234959619935994960031017850191710121890821178731821983105443, - 0.0000000000006560617479811459709189576337295395590603644549624717910616347038, - 0.0000000000003280308739906102782522178545328259781415615142931952662153623493, - 0.0000000000001640154369953144623242936888032768768777422997704541618141646683, - 0.0000000000000820077184976595619616930350508356401599552034612281802599177300, - 0.0000000000000410038592488303636807330652208397742314215159774270270147020117, - 0.0000000000000205019296244153275153381695384157073687186580546938331088730952, - 0.0000000000000102509648122077001764119940017243502120046885379813510430378661, - 0.0000000000000051254824061038591928917243090559919209628584150482483994782302, - 0.0000000000000025627412030519318726172939815845367496027046030028595094737777, - 0.0000000000000012813706015259665053515049475574143952543145124550608158430592, - 0.0000000000000006406853007629833949364669629701200556369782295210193569318434, - 0.0000000000000003203426503814917330334121037829290364330169106716787999052925, - 0.0000000000000001601713251907458754080007074659337446341494733882570243497196, - 0.0000000000000000800856625953729399268240176265844257044861248416330071223615, - 0.0000000000000000400428312976864705191179247866966320469710511619971334577509, - 0.0000000000000000200214156488432353984854413866994246781519154793320684126179, - 0.0000000000000000100107078244216177339743404416874899847406043033792202127070, - 0.0000000000000000050053539122108088756700751579281894640362199287591340285355, - 0.0000000000000000025026769561054044400057638132352058574658089256646014899499, - 0.0000000000000000012513384780527022205455634651853807110362316427807660551208, - 0.0000000000000000006256692390263511104084521222346348012116229213309001913762, - 0.0000000000000000003128346195131755552381436585278035120438976487697544916191, - 0.0000000000000000001564173097565877776275512286165232838833090480508502328437, - 0.0000000000000000000782086548782938888158954641464170239072244145219054734086, - 0.0000000000000000000391043274391469444084776945327473574450334092075712154016, - 0.0000000000000000000195521637195734722043713378812583900953755962557525252782, - 0.0000000000000000000097760818597867361022187915943503728909029699365320287407, - 0.0000000000000000000048880409298933680511176764606054809062553340323879609794, - 0.0000000000000000000024440204649466840255609083961603140683286362962192177597, - 0.0000000000000000000012220102324733420127809717395445504379645613448652614939, - 0.0000000000000000000006110051162366710063906152551383735699323415812152114058, - 0.0000000000000000000003055025581183355031953399739107113727036860315024588989, - 0.0000000000000000000001527512790591677515976780735407368332862218276873443537, - 0.0000000000000000000000763756395295838757988410584167137033767056170417508383, - 0.0000000000000000000000381878197647919378994210346199431733717514843471513618, - 0.0000000000000000000000190939098823959689497106436628681671067254111334889005, - 0.0000000000000000000000095469549411979844748553534196582286585751228071408728, - 0.0000000000000000000000047734774705989922374276846068851506055906657137209047, - 0.0000000000000000000000023867387352994961187138442777065843718711089344045782, - 0.0000000000000000000000011933693676497480593569226324192944532044984865894525, - 0.0000000000000000000000005966846838248740296784614396011477934194852481410926, - 0.0000000000000000000000002983423419124370148392307506484490384140516252814304, - 0.0000000000000000000000001491711709562185074196153830361933046331030629430117, - 0.0000000000000000000000000745855854781092537098076934460888486730708440475045, - 0.0000000000000000000000000372927927390546268549038472050424734256652501673274, - 0.0000000000000000000000000186463963695273134274519237230207489851150821191330, - 0.0000000000000000000000000093231981847636567137259618916352525606281553180093, - 0.0000000000000000000000000046615990923818283568629809533488457973317312233323, - 0.0000000000000000000000000023307995461909141784314904785572277779202790023236, - 0.0000000000000000000000000011653997730954570892157452397493151087737428485431, - 0.0000000000000000000000000005826998865477285446078726199923328593402722606924, - 0.0000000000000000000000000002913499432738642723039363100255852559084863397344, - 0.0000000000000000000000000001456749716369321361519681550201473345138307215067, - 0.0000000000000000000000000000728374858184660680759840775119123438968122488047, - 0.0000000000000000000000000000364187429092330340379920387564158411083803465567, - 0.0000000000000000000000000000182093714546165170189960193783228378441837282509, - 0.0000000000000000000000000000091046857273082585094980096891901482445902524441, - 0.0000000000000000000000000000045523428636541292547490048446022564529197237262, - 0.0000000000000000000000000000022761714318270646273745024223029238091160103901}; - int n = 53; - double x = 1; - double y = 0; - double z; - double s = 1; - int k; - - for (k = 0; k < n; k++) - { - z = x + x * s; - if (z <= arg) - { - x = z; - y += ae[k]; - } - s *= 0.5; - } - return y; - } - - public static boolean isIncreasing(int[] a) - { - for (int i = 1; i < a.length; i++) - { - if (a[i - 1] >= a[i]) - { - return false; - } - } - return true; - } - - public static byte[] integerToOctets(BigInteger val) - { - byte[] valBytes = val.abs().toByteArray(); - - // check whether the array includes a sign bit - if ((val.bitLength() & 7) != 0) - { - return valBytes; - } - // get rid of the sign bit (first byte) - byte[] tmp = new byte[val.bitLength() >> 3]; - System.arraycopy(valBytes, 1, tmp, 0, tmp.length); - return tmp; - } - - public static BigInteger octetsToInteger(byte[] data, int offset, - int length) - { - byte[] val = new byte[length + 1]; - - val[0] = 0; - System.arraycopy(data, offset, val, 1, length); - return new BigInteger(val); - } - - public static BigInteger octetsToInteger(byte[] data) - { - return octetsToInteger(data, 0, data.length); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/LittleEndianConversions.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/LittleEndianConversions.java deleted file mode 100644 index a9e3448783..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/LittleEndianConversions.java +++ /dev/null @@ -1,230 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -/** - * This is a utility class containing data type conversions using little-endian - * byte order. - * - * @see BigEndianConversions - */ -public final class LittleEndianConversions -{ - - /** - * Default constructor (private). - */ - private LittleEndianConversions() - { - // empty - } - - /** - * Convert an octet string of length 4 to an integer. No length checking is - * performed. - * - * @param input the byte array holding the octet string - * @return an integer representing the octet string input - * @throws ArithmeticException if the length of the given octet string is larger than 4. - */ - public static int OS2IP(byte[] input) - { - return ((input[0] & 0xff)) | ((input[1] & 0xff) << 8) - | ((input[2] & 0xff) << 16) | ((input[3] & 0xff)) << 24; - } - - /** - * Convert an byte array of length 4 beginning at offset into an - * integer. - * - * @param input the byte array - * @param inOff the offset into the byte array - * @return the resulting integer - */ - public static int OS2IP(byte[] input, int inOff) - { - int result = input[inOff++] & 0xff; - result |= (input[inOff++] & 0xff) << 8; - result |= (input[inOff++] & 0xff) << 16; - result |= (input[inOff] & 0xff) << 24; - return result; - } - - /** - * Convert a byte array of the given length beginning at offset - * into an integer. - * - * @param input the byte array - * @param inOff the offset into the byte array - * @param inLen the length of the encoding - * @return the resulting integer - */ - public static int OS2IP(byte[] input, int inOff, int inLen) - { - int result = 0; - for (int i = inLen - 1; i >= 0; i--) - { - result |= (input[inOff + i] & 0xff) << (8 * i); - } - return result; - } - - /** - * Convert a byte array of length 8 beginning at inOff into a - * long integer. - * - * @param input the byte array - * @param inOff the offset into the byte array - * @return the resulting long integer - */ - public static long OS2LIP(byte[] input, int inOff) - { - long result = input[inOff++] & 0xff; - result |= (input[inOff++] & 0xff) << 8; - result |= (input[inOff++] & 0xff) << 16; - result |= ((long)input[inOff++] & 0xff) << 24; - result |= ((long)input[inOff++] & 0xff) << 32; - result |= ((long)input[inOff++] & 0xff) << 40; - result |= ((long)input[inOff++] & 0xff) << 48; - result |= ((long)input[inOff++] & 0xff) << 56; - return result; - } - - /** - * Convert an integer to an octet string of length 4. - * - * @param x the integer to convert - * @return the converted integer - */ - public static byte[] I2OSP(int x) - { - byte[] result = new byte[4]; - result[0] = (byte)x; - result[1] = (byte)(x >>> 8); - result[2] = (byte)(x >>> 16); - result[3] = (byte)(x >>> 24); - return result; - } - - /** - * Convert an integer into a byte array beginning at the specified offset. - * - * @param value the integer to convert - * @param output the byte array to hold the result - * @param outOff the integer offset into the byte array - */ - public static void I2OSP(int value, byte[] output, int outOff) - { - output[outOff++] = (byte)value; - output[outOff++] = (byte)(value >>> 8); - output[outOff++] = (byte)(value >>> 16); - output[outOff++] = (byte)(value >>> 24); - } - - /** - * Convert an integer to a byte array beginning at the specified offset. No - * length checking is performed (i.e., if the integer cannot be encoded with - * length octets, it is truncated). - * - * @param value the integer to convert - * @param output the byte array to hold the result - * @param outOff the integer offset into the byte array - * @param outLen the length of the encoding - */ - public static void I2OSP(int value, byte[] output, int outOff, int outLen) - { - for (int i = outLen - 1; i >= 0; i--) - { - output[outOff + i] = (byte)(value >>> (8 * i)); - } - } - - /** - * Convert an integer to a byte array of length 8. - * - * @param input the integer to convert - * @return the converted integer - */ - public static byte[] I2OSP(long input) - { - byte[] output = new byte[8]; - output[0] = (byte)input; - output[1] = (byte)(input >>> 8); - output[2] = (byte)(input >>> 16); - output[3] = (byte)(input >>> 24); - output[4] = (byte)(input >>> 32); - output[5] = (byte)(input >>> 40); - output[6] = (byte)(input >>> 48); - output[7] = (byte)(input >>> 56); - return output; - } - - /** - * Convert an integer to a byte array of length 8. - * - * @param input the integer to convert - * @param output byte array holding the output - * @param outOff offset in output array where the result is stored - */ - public static void I2OSP(long input, byte[] output, int outOff) - { - output[outOff++] = (byte)input; - output[outOff++] = (byte)(input >>> 8); - output[outOff++] = (byte)(input >>> 16); - output[outOff++] = (byte)(input >>> 24); - output[outOff++] = (byte)(input >>> 32); - output[outOff++] = (byte)(input >>> 40); - output[outOff++] = (byte)(input >>> 48); - output[outOff] = (byte)(input >>> 56); - } - - /** - * Convert an int array to a byte array of the specified length. No length - * checking is performed (i.e., if the last integer cannot be encoded with - * length % 4 octets, it is truncated). - * - * @param input the int array - * @param outLen the length of the converted array - * @return the converted array - */ - public static byte[] toByteArray(int[] input, int outLen) - { - int intLen = input.length; - byte[] result = new byte[outLen]; - int index = 0; - for (int i = 0; i <= intLen - 2; i++, index += 4) - { - I2OSP(input[i], result, index); - } - I2OSP(input[intLen - 1], result, index, outLen - index); - return result; - } - - /** - * Convert a byte array to an int array. - * - * @param input the byte array - * @return the converted array - */ - public static int[] toIntArray(byte[] input) - { - int intLen = (input.length + 3) / 4; - int lastLen = input.length & 0x03; - int[] result = new int[intLen]; - - int index = 0; - for (int i = 0; i <= intLen - 2; i++, index += 4) - { - result[i] = OS2IP(input, index); - } - if (lastLen != 0) - { - result[intLen - 1] = OS2IP(input, index, lastLen); - } - else - { - result[intLen - 1] = OS2IP(input, index); - } - - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/Matrix.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/Matrix.java deleted file mode 100644 index be4ed3a2cb..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/Matrix.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -/** - * This abstract class defines matrices. It holds the number of rows and the - * number of columns of the matrix and defines some basic methods. - */ -public abstract class Matrix -{ - - /** - * number of rows - */ - protected int numRows; - - /** - * number of columns - */ - protected int numColumns; - - // ---------------------------------------------------- - // some constants (matrix types) - // ---------------------------------------------------- - - /** - * zero matrix - */ - public static final char MATRIX_TYPE_ZERO = 'Z'; - - /** - * unit matrix - */ - public static final char MATRIX_TYPE_UNIT = 'I'; - - /** - * random lower triangular matrix - */ - public static final char MATRIX_TYPE_RANDOM_LT = 'L'; - - /** - * random upper triangular matrix - */ - public static final char MATRIX_TYPE_RANDOM_UT = 'U'; - - /** - * random regular matrix - */ - public static final char MATRIX_TYPE_RANDOM_REGULAR = 'R'; - - // ---------------------------------------------------- - // getters - // ---------------------------------------------------- - - /** - * @return the number of rows in the matrix - */ - public int getNumRows() - { - return numRows; - } - - /** - * @return the number of columns in the binary matrix - */ - public int getNumColumns() - { - return numColumns; - } - - /** - * @return the encoded matrix, i.e., this matrix in byte array form. - */ - public abstract byte[] getEncoded(); - - // ---------------------------------------------------- - // arithmetic - // ---------------------------------------------------- - - /** - * Compute the inverse of this matrix. - * - * @return the inverse of this matrix (newly created). - */ - public abstract Matrix computeInverse(); - - /** - * Check if this is the zero matrix (i.e., all entries are zero). - * - * @return true if this is the zero matrix - */ - public abstract boolean isZero(); - - /** - * Compute the product of this matrix and another matrix. - * - * @param a the other matrix - * @return this * a (newly created) - */ - public abstract Matrix rightMultiply(Matrix a); - - /** - * Compute the product of this matrix and a permutation. - * - * @param p the permutation - * @return this * p (newly created) - */ - public abstract Matrix rightMultiply(Permutation p); - - /** - * Compute the product of a vector and this matrix. If the length of the - * vector is greater than the number of rows of this matrix, the matrix is - * multiplied by each m-bit part of the vector. - * - * @param vector a vector - * @return vector * this (newly created) - */ - public abstract Vector leftMultiply(Vector vector); - - /** - * Compute the product of this matrix and a vector. - * - * @param vector a vector - * @return this * vector (newly created) - */ - public abstract Vector rightMultiply(Vector vector); - - /** - * @return a human readable form of the matrix. - */ - public abstract String toString(); - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/Permutation.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/Permutation.java deleted file mode 100644 index 8faece7403..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/Permutation.java +++ /dev/null @@ -1,249 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -import java.security.SecureRandom; - -import org.bouncycastle.util.Arrays; - -/** - * This class implements permutations of the set {0,1,...,n-1} for some given n - * > 0, i.e., ordered sequences containing each number m (0 <= - * m < n) - * once and only once. - */ -public class Permutation -{ - - /** - * perm holds the elements of the permutation vector, i.e. [perm(0), - * perm(1), ..., perm(n-1)] - */ - private int[] perm; - - /** - * Create the identity permutation of the given size. - * - * @param n the size of the permutation - */ - public Permutation(int n) - { - if (n <= 0) - { - throw new IllegalArgumentException("invalid length"); - } - - perm = new int[n]; - for (int i = n - 1; i >= 0; i--) - { - perm[i] = i; - } - } - - /** - * Create a permutation using the given permutation vector. - * - * @param perm the permutation vector - */ - public Permutation(int[] perm) - { - if (!isPermutation(perm)) - { - throw new IllegalArgumentException( - "array is not a permutation vector"); - } - - this.perm = IntUtils.clone(perm); - } - - /** - * Create a permutation from an encoded permutation. - * - * @param enc the encoded permutation - */ - public Permutation(byte[] enc) - { - if (enc.length <= 4) - { - throw new IllegalArgumentException("invalid encoding"); - } - - int n = LittleEndianConversions.OS2IP(enc, 0); - int size = IntegerFunctions.ceilLog256(n - 1); - - if (enc.length != 4 + n * size) - { - throw new IllegalArgumentException("invalid encoding"); - } - - perm = new int[n]; - for (int i = 0; i < n; i++) - { - perm[i] = LittleEndianConversions.OS2IP(enc, 4 + i * size, size); - } - - if (!isPermutation(perm)) - { - throw new IllegalArgumentException("invalid encoding"); - } - - } - - /** - * Create a random permutation of the given size. - * - * @param n the size of the permutation - * @param sr the source of randomness - */ - public Permutation(int n, SecureRandom sr) - { - if (n <= 0) - { - throw new IllegalArgumentException("invalid length"); - } - - perm = new int[n]; - - int[] help = new int[n]; - for (int i = 0; i < n; i++) - { - help[i] = i; - } - - int k = n; - for (int j = 0; j < n; j++) - { - int i = RandUtils.nextInt(sr, k); - k--; - perm[j] = help[i]; - help[i] = help[k]; - } - } - - /** - * Encode this permutation as byte array. - * - * @return the encoded permutation - */ - public byte[] getEncoded() - { - int n = perm.length; - int size = IntegerFunctions.ceilLog256(n - 1); - byte[] result = new byte[4 + n * size]; - LittleEndianConversions.I2OSP(n, result, 0); - for (int i = 0; i < n; i++) - { - LittleEndianConversions.I2OSP(perm[i], result, 4 + i * size, size); - } - return result; - } - - /** - * @return the permutation vector (perm(0),perm(1),...,perm(n-1)) - */ - public int[] getVector() - { - return IntUtils.clone(perm); - } - - /** - * Compute the inverse permutation P-1. - * - * @return this-1 - */ - public Permutation computeInverse() - { - Permutation result = new Permutation(perm.length); - for (int i = perm.length - 1; i >= 0; i--) - { - result.perm[perm[i]] = i; - } - return result; - } - - /** - * Compute the product of this permutation and another permutation. - * - * @param p the other permutation - * @return this * p - */ - public Permutation rightMultiply(Permutation p) - { - if (p.perm.length != perm.length) - { - throw new IllegalArgumentException("length mismatch"); - } - Permutation result = new Permutation(perm.length); - for (int i = perm.length - 1; i >= 0; i--) - { - result.perm[i] = perm[p.perm[i]]; - } - return result; - } - - /** - * checks if given object is equal to this permutation. - *

    - * The method returns false whenever the given object is not permutation. - * - * @param other - - * permutation - * @return true or false - */ - public boolean equals(Object other) - { - - if (!(other instanceof Permutation)) - { - return false; - } - Permutation otherPerm = (Permutation)other; - - return IntUtils.equals(perm, otherPerm.perm); - } - - /** - * @return a human readable form of the permutation - */ - public String toString() - { - String result = "[" + perm[0]; - for (int i = 1; i < perm.length; i++) - { - result += ", " + perm[i]; - } - result += "]"; - return result; - } - - /** - * @return the hash code of this permutation - */ - public int hashCode() - { - return Arrays.hashCode(perm); - } - - /** - * Check that the given array corresponds to a permutation of the set - * {0, 1, ..., n-1}. - * - * @param perm permutation vector - * @return true if perm represents an n-permutation and false otherwise - */ - private boolean isPermutation(int[] perm) - { - int n = perm.length; - boolean[] onlyOnce = new boolean[n]; - - for (int i = 0; i < n; i++) - { - if ((perm[i] < 0) || (perm[i] >= n) || onlyOnce[perm[i]]) - { - return false; - } - onlyOnce[perm[i]] = true; - } - - return true; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/PolynomialGF2mSmallM.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/PolynomialGF2mSmallM.java deleted file mode 100644 index c84a45ef55..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/PolynomialGF2mSmallM.java +++ /dev/null @@ -1,1124 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -import java.security.SecureRandom; - -/** - * This class describes operations with polynomials from the ring R = - * GF(2^m)[X], where 2 <= m <=31. - * - * @see GF2mField - * @see PolynomialRingGF2m - */ -public class PolynomialGF2mSmallM -{ - - /** - * the finite field GF(2^m) - */ - private GF2mField field; - - /** - * the degree of this polynomial - */ - private int degree; - - /** - * For the polynomial representation the map f: R->Z*, - * poly(X) -> [coef_0, coef_1, ...] is used, where - * coef_i is the ith coefficient of the polynomial - * represented as int (see {@link GF2mField}). The polynomials are stored - * as int arrays. - */ - private int[] coefficients; - - /* - * some types of polynomials - */ - - /** - * Constant used for polynomial construction (see constructor - * {@link #PolynomialGF2mSmallM(GF2mField, int, char, SecureRandom)}). - */ - public static final char RANDOM_IRREDUCIBLE_POLYNOMIAL = 'I'; - - /** - * Construct the zero polynomial over the finite field GF(2^m). - * - * @param field the finite field GF(2^m) - */ - public PolynomialGF2mSmallM(GF2mField field) - { - this.field = field; - degree = -1; - coefficients = new int[1]; - } - - /** - * Construct a polynomial over the finite field GF(2^m). - * - * @param field the finite field GF(2^m) - * @param deg degree of polynomial - * @param typeOfPolynomial type of polynomial - * @param sr PRNG - */ - public PolynomialGF2mSmallM(GF2mField field, int deg, - char typeOfPolynomial, SecureRandom sr) - { - this.field = field; - - switch (typeOfPolynomial) - { - case PolynomialGF2mSmallM.RANDOM_IRREDUCIBLE_POLYNOMIAL: - coefficients = createRandomIrreduciblePolynomial(deg, sr); - break; - default: - throw new IllegalArgumentException(" Error: type " - + typeOfPolynomial - + " is not defined for GF2smallmPolynomial"); - } - computeDegree(); - } - - /** - * Create an irreducible polynomial with the given degree over the field - * GF(2^m). - * - * @param deg polynomial degree - * @param sr source of randomness - * @return the generated irreducible polynomial - */ - private int[] createRandomIrreduciblePolynomial(int deg, SecureRandom sr) - { - int[] resCoeff = new int[deg + 1]; - resCoeff[deg] = 1; - resCoeff[0] = field.getRandomNonZeroElement(sr); - for (int i = 1; i < deg; i++) - { - resCoeff[i] = field.getRandomElement(sr); - } - while (!isIrreducible(resCoeff)) - { - int n = RandUtils.nextInt(sr, deg); - if (n == 0) - { - resCoeff[0] = field.getRandomNonZeroElement(sr); - } - else - { - resCoeff[n] = field.getRandomElement(sr); - } - } - return resCoeff; - } - - /** - * Construct a monomial of the given degree over the finite field GF(2^m). - * - * @param field the finite field GF(2^m) - * @param degree the degree of the monomial - */ - public PolynomialGF2mSmallM(GF2mField field, int degree) - { - this.field = field; - this.degree = degree; - coefficients = new int[degree + 1]; - coefficients[degree] = 1; - } - - /** - * Construct the polynomial over the given finite field GF(2^m) from the - * given coefficient vector. - * - * @param field finite field GF2m - * @param coeffs the coefficient vector - */ - public PolynomialGF2mSmallM(GF2mField field, int[] coeffs) - { - this.field = field; - coefficients = normalForm(coeffs); - computeDegree(); - } - - /** - * Create a polynomial over the finite field GF(2^m). - * - * @param field the finite field GF(2^m) - * @param enc byte[] polynomial in byte array form - */ - public PolynomialGF2mSmallM(GF2mField field, byte[] enc) - { - this.field = field; - - // decodes polynomial - int d = 8; - int count = 1; - while (field.getDegree() > d) - { - count++; - d += 8; - } - - if ((enc.length % count) != 0) - { - throw new IllegalArgumentException( - " Error: byte array is not encoded polynomial over given finite field GF2m"); - } - - coefficients = new int[enc.length / count]; - count = 0; - for (int i = 0; i < coefficients.length; i++) - { - for (int j = 0; j < d; j += 8) - { - coefficients[i] ^= (enc[count++] & 0x000000ff) << j; - } - if (!this.field.isElementOfThisField(coefficients[i])) - { - throw new IllegalArgumentException( - " Error: byte array is not encoded polynomial over given finite field GF2m"); - } - } - // if HC = 0 for non-zero polynomial, returns error - if ((coefficients.length != 1) - && (coefficients[coefficients.length - 1] == 0)) - { - throw new IllegalArgumentException( - " Error: byte array is not encoded polynomial over given finite field GF2m"); - } - computeDegree(); - } - - /** - * Copy constructor. - * - * @param other another {@link PolynomialGF2mSmallM} - */ - public PolynomialGF2mSmallM(PolynomialGF2mSmallM other) - { - // field needs not to be cloned since it is immutable - field = other.field; - degree = other.degree; - coefficients = IntUtils.clone(other.coefficients); - } - - /** - * Create a polynomial over the finite field GF(2^m) out of the given - * coefficient vector. The finite field is also obtained from the - * {@link GF2mVector}. - * - * @param vect the coefficient vector - */ - public PolynomialGF2mSmallM(GF2mVector vect) - { - this(vect.getField(), vect.getIntArrayForm()); - } - - /* - * ------------------------ - */ - - /** - * Return the degree of this polynomial - * - * @return int degree of this polynomial if this is zero polynomial return - * -1 - */ - public int getDegree() - { - int d = coefficients.length - 1; - if (coefficients[d] == 0) - { - return -1; - } - return d; - } - - /** - * @return the head coefficient of this polynomial - */ - public int getHeadCoefficient() - { - if (degree == -1) - { - return 0; - } - return coefficients[degree]; - } - - /** - * Return the head coefficient of a polynomial. - * - * @param a the polynomial - * @return the head coefficient of a - */ - private static int headCoefficient(int[] a) - { - int degree = computeDegree(a); - if (degree == -1) - { - return 0; - } - return a[degree]; - } - - /** - * Return the coefficient with the given index. - * - * @param index the index - * @return the coefficient with the given index - */ - public int getCoefficient(int index) - { - if ((index < 0) || (index > degree)) - { - return 0; - } - return coefficients[index]; - } - - /** - * Returns encoded polynomial, i.e., this polynomial in byte array form - * - * @return the encoded polynomial - */ - public byte[] getEncoded() - { - int d = 8; - int count = 1; - while (field.getDegree() > d) - { - count++; - d += 8; - } - - byte[] res = new byte[coefficients.length * count]; - count = 0; - for (int i = 0; i < coefficients.length; i++) - { - for (int j = 0; j < d; j += 8) - { - res[count++] = (byte)(coefficients[i] >>> j); - } - } - - return res; - } - - /** - * Evaluate this polynomial p at a value e (in - * GF(2^m)) with the Horner scheme. - * - * @param e the element of the finite field GF(2^m) - * @return this(e) - */ - public int evaluateAt(int e) - { - int result = coefficients[degree]; - for (int i = degree - 1; i >= 0; i--) - { - result = field.mult(result, e) ^ coefficients[i]; - } - return result; - } - - /** - * Compute the sum of this polynomial and the given polynomial. - * - * @param addend the addend - * @return this + a (newly created) - */ - public PolynomialGF2mSmallM add(PolynomialGF2mSmallM addend) - { - int[] resultCoeff = add(coefficients, addend.coefficients); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Add the given polynomial to this polynomial (overwrite this). - * - * @param addend the addend - */ - public void addToThis(PolynomialGF2mSmallM addend) - { - coefficients = add(coefficients, addend.coefficients); - computeDegree(); - } - - /** - * Compute the sum of two polynomials a and b over the finite field - * GF(2^m). - * - * @param a the first polynomial - * @param b the second polynomial - * @return a + b - */ - private int[] add(int[] a, int[] b) - { - int[] result, addend; - if (a.length < b.length) - { - result = new int[b.length]; - System.arraycopy(b, 0, result, 0, b.length); - addend = a; - } - else - { - result = new int[a.length]; - System.arraycopy(a, 0, result, 0, a.length); - addend = b; - } - - for (int i = addend.length - 1; i >= 0; i--) - { - result[i] = field.add(result[i], addend[i]); - } - - return result; - } - - /** - * Compute the sum of this polynomial and the monomial of the given degree. - * - * @param degree the degree of the monomial - * @return this + X^k - */ - public PolynomialGF2mSmallM addMonomial(int degree) - { - int[] monomial = new int[degree + 1]; - monomial[degree] = 1; - int[] resultCoeff = add(coefficients, monomial); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute the product of this polynomial with an element from GF(2^m). - * - * @param element an element of the finite field GF(2^m) - * @return this * element (newly created) - * @throws ArithmeticException if element is not an element of the finite - * field this polynomial is defined over. - */ - public PolynomialGF2mSmallM multWithElement(int element) - { - if (!field.isElementOfThisField(element)) - { - throw new ArithmeticException( - "Not an element of the finite field this polynomial is defined over."); - } - int[] resultCoeff = multWithElement(coefficients, element); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Multiply this polynomial with an element from GF(2^m). - * - * @param element an element of the finite field GF(2^m) - * @throws ArithmeticException if element is not an element of the finite - * field this polynomial is defined over. - */ - public void multThisWithElement(int element) - { - if (!field.isElementOfThisField(element)) - { - throw new ArithmeticException( - "Not an element of the finite field this polynomial is defined over."); - } - coefficients = multWithElement(coefficients, element); - computeDegree(); - } - - /** - * Compute the product of a polynomial a with an element from the finite - * field GF(2^m). - * - * @param a the polynomial - * @param element an element of the finite field GF(2^m) - * @return a * element - */ - private int[] multWithElement(int[] a, int element) - { - int degree = computeDegree(a); - if (degree == -1 || element == 0) - { - return new int[1]; - } - - if (element == 1) - { - return IntUtils.clone(a); - } - - int[] result = new int[degree + 1]; - for (int i = degree; i >= 0; i--) - { - result[i] = field.mult(a[i], element); - } - - return result; - } - - /** - * Compute the product of this polynomial with a monomial X^k. - * - * @param k the degree of the monomial - * @return this * X^k - */ - public PolynomialGF2mSmallM multWithMonomial(int k) - { - int[] resultCoeff = multWithMonomial(coefficients, k); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute the product of a polynomial with a monomial X^k. - * - * @param a the polynomial - * @param k the degree of the monomial - * @return a * X^k - */ - private static int[] multWithMonomial(int[] a, int k) - { - int d = computeDegree(a); - if (d == -1) - { - return new int[1]; - } - int[] result = new int[d + k + 1]; - System.arraycopy(a, 0, result, k, d + 1); - return result; - } - - /** - * Divide this polynomial by the given polynomial. - * - * @param f a polynomial - * @return polynomial pair = {q,r} where this = q*f+r and deg(r) < - * deg(f); - */ - public PolynomialGF2mSmallM[] div(PolynomialGF2mSmallM f) - { - int[][] resultCoeffs = div(coefficients, f.coefficients); - return new PolynomialGF2mSmallM[]{ - new PolynomialGF2mSmallM(field, resultCoeffs[0]), - new PolynomialGF2mSmallM(field, resultCoeffs[1])}; - } - - /** - * Compute the result of the division of two polynomials over the field - * GF(2^m). - * - * @param a the first polynomial - * @param f the second polynomial - * @return int[][] {q,r}, where a = q*f+r and deg(r) < deg(f); - */ - private int[][] div(int[] a, int[] f) - { - int df = computeDegree(f); - int da = computeDegree(a) + 1; - if (df == -1) - { - throw new ArithmeticException("Division by zero."); - } - int[][] result = new int[2][]; - result[0] = new int[1]; - result[1] = new int[da]; - int hc = headCoefficient(f); - hc = field.inverse(hc); - result[0][0] = 0; - System.arraycopy(a, 0, result[1], 0, result[1].length); - while (df <= computeDegree(result[1])) - { - int[] q; - int[] coeff = new int[1]; - coeff[0] = field.mult(headCoefficient(result[1]), hc); - q = multWithElement(f, coeff[0]); - int n = computeDegree(result[1]) - df; - q = multWithMonomial(q, n); - coeff = multWithMonomial(coeff, n); - result[0] = add(coeff, result[0]); - result[1] = add(q, result[1]); - } - return result; - } - - /** - * Return the greatest common divisor of this and a polynomial f - * - * @param f polynomial - * @return GCD(this, f) - */ - public PolynomialGF2mSmallM gcd(PolynomialGF2mSmallM f) - { - int[] resultCoeff = gcd(coefficients, f.coefficients); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Return the greatest common divisor of two polynomials over the field - * GF(2^m). - * - * @param f the first polynomial - * @param g the second polynomial - * @return gcd(f, g) - */ - private int[] gcd(int[] f, int[] g) - { - int[] a = f; - int[] b = g; - if (computeDegree(a) == -1) - { - return b; - } - while (computeDegree(b) != -1) - { - int[] c = mod(a, b); - a = new int[b.length]; - System.arraycopy(b, 0, a, 0, a.length); - b = new int[c.length]; - System.arraycopy(c, 0, b, 0, b.length); - } - int coeff = field.inverse(headCoefficient(a)); - return multWithElement(a, coeff); - } - - /** - * Compute the product of this polynomial and the given factor using a - * Karatzuba like scheme. - * - * @param factor the polynomial - * @return this * factor - */ - public PolynomialGF2mSmallM multiply(PolynomialGF2mSmallM factor) - { - int[] resultCoeff = multiply(coefficients, factor.coefficients); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute the product of two polynomials over the field GF(2^m) - * using a Karatzuba like multiplication. - * - * @param a the first polynomial - * @param b the second polynomial - * @return a * b - */ - private int[] multiply(int[] a, int[] b) - { - int[] mult1, mult2; - if (computeDegree(a) < computeDegree(b)) - { - mult1 = b; - mult2 = a; - } - else - { - mult1 = a; - mult2 = b; - } - - mult1 = normalForm(mult1); - mult2 = normalForm(mult2); - - if (mult2.length == 1) - { - return multWithElement(mult1, mult2[0]); - } - - int d1 = mult1.length; - int d2 = mult2.length; - int[] result = new int[d1 + d2 - 1]; - - if (d2 != d1) - { - int[] res1 = new int[d2]; - int[] res2 = new int[d1 - d2]; - System.arraycopy(mult1, 0, res1, 0, res1.length); - System.arraycopy(mult1, d2, res2, 0, res2.length); - res1 = multiply(res1, mult2); - res2 = multiply(res2, mult2); - res2 = multWithMonomial(res2, d2); - result = add(res1, res2); - } - else - { - d2 = (d1 + 1) >>> 1; - int d = d1 - d2; - int[] firstPartMult1 = new int[d2]; - int[] firstPartMult2 = new int[d2]; - int[] secondPartMult1 = new int[d]; - int[] secondPartMult2 = new int[d]; - System - .arraycopy(mult1, 0, firstPartMult1, 0, - firstPartMult1.length); - System.arraycopy(mult1, d2, secondPartMult1, 0, - secondPartMult1.length); - System - .arraycopy(mult2, 0, firstPartMult2, 0, - firstPartMult2.length); - System.arraycopy(mult2, d2, secondPartMult2, 0, - secondPartMult2.length); - int[] helpPoly1 = add(firstPartMult1, secondPartMult1); - int[] helpPoly2 = add(firstPartMult2, secondPartMult2); - int[] res1 = multiply(firstPartMult1, firstPartMult2); - int[] res2 = multiply(helpPoly1, helpPoly2); - int[] res3 = multiply(secondPartMult1, secondPartMult2); - res2 = add(res2, res1); - res2 = add(res2, res3); - res3 = multWithMonomial(res3, d2); - result = add(res2, res3); - result = multWithMonomial(result, d2); - result = add(result, res1); - } - - return result; - } - - /* - * ---------------- PART II ---------------- - * - */ - - /** - * Check a polynomial for irreducibility over the field GF(2^m). - * - * @param a the polynomial to check - * @return true if a is irreducible, false otherwise - */ - private boolean isIrreducible(int[] a) - { - if (a[0] == 0) - { - return false; - } - int d = computeDegree(a) >> 1; - int[] u = {0, 1}; - final int[] Y = {0, 1}; - int fieldDegree = field.getDegree(); - for (int i = 0; i < d; i++) - { - for (int j = fieldDegree - 1; j >= 0; j--) - { - u = modMultiply(u, u, a); - } - u = normalForm(u); - int[] g = gcd(add(u, Y), a); - if (computeDegree(g) != 0) - { - return false; - } - } - return true; - } - - /** - * Reduce this polynomial modulo another polynomial. - * - * @param f the reduction polynomial - * @return this mod f - */ - public PolynomialGF2mSmallM mod(PolynomialGF2mSmallM f) - { - int[] resultCoeff = mod(coefficients, f.coefficients); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Reduce a polynomial modulo another polynomial. - * - * @param a the polynomial - * @param f the reduction polynomial - * @return a mod f - */ - private int[] mod(int[] a, int[] f) - { - int df = computeDegree(f); - if (df == -1) - { - throw new ArithmeticException("Division by zero"); - } - int[] result = new int[a.length]; - int hc = headCoefficient(f); - hc = field.inverse(hc); - System.arraycopy(a, 0, result, 0, result.length); - while (df <= computeDegree(result)) - { - int[] q; - int coeff = field.mult(headCoefficient(result), hc); - q = multWithMonomial(f, computeDegree(result) - df); - q = multWithElement(q, coeff); - result = add(q, result); - } - return result; - } - - /** - * Compute the product of this polynomial and another polynomial modulo a - * third polynomial. - * - * @param a another polynomial - * @param b the reduction polynomial - * @return this * a mod b - */ - public PolynomialGF2mSmallM modMultiply(PolynomialGF2mSmallM a, - PolynomialGF2mSmallM b) - { - int[] resultCoeff = modMultiply(coefficients, a.coefficients, - b.coefficients); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Square this polynomial using a squaring matrix. - * - * @param matrix the squaring matrix - * @return this^2 modulo the reduction polynomial implicitly - * given via the squaring matrix - */ - public PolynomialGF2mSmallM modSquareMatrix(PolynomialGF2mSmallM[] matrix) - { - - int length = matrix.length; - - int[] resultCoeff = new int[length]; - int[] thisSquare = new int[length]; - - // square each entry of this polynomial - for (int i = 0; i < coefficients.length; i++) - { - thisSquare[i] = field.mult(coefficients[i], coefficients[i]); - } - - // do matrix-vector multiplication - for (int i = 0; i < length; i++) - { - // compute scalar product of i-th row and coefficient vector - for (int j = 0; j < length; j++) - { - if (i >= matrix[j].coefficients.length) - { - continue; - } - int scalarTerm = field.mult(matrix[j].coefficients[i], - thisSquare[j]); - resultCoeff[i] = field.add(resultCoeff[i], scalarTerm); - } - } - - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute the product of two polynomials modulo a third polynomial over the - * finite field GF(2^m). - * - * @param a the first polynomial - * @param b the second polynomial - * @param g the reduction polynomial - * @return a * b mod g - */ - private int[] modMultiply(int[] a, int[] b, int[] g) - { - return mod(multiply(a, b), g); - } - - /** - * Compute the square root of this polynomial modulo the given polynomial. - * - * @param a the reduction polynomial - * @return this^(1/2) mod a - */ - public PolynomialGF2mSmallM modSquareRoot(PolynomialGF2mSmallM a) - { - int[] resultCoeff = IntUtils.clone(coefficients); - int[] help = modMultiply(resultCoeff, resultCoeff, a.coefficients); - while (!isEqual(help, coefficients)) - { - resultCoeff = normalForm(help); - help = modMultiply(resultCoeff, resultCoeff, a.coefficients); - } - - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute the square root of this polynomial using a square root matrix. - * - * @param matrix the matrix for computing square roots in - * (GF(2^m))^t the polynomial ring defining the - * square root matrix - * @return this^(1/2) modulo the reduction polynomial implicitly - * given via the square root matrix - */ - public PolynomialGF2mSmallM modSquareRootMatrix( - PolynomialGF2mSmallM[] matrix) - { - - int length = matrix.length; - - int[] resultCoeff = new int[length]; - - // do matrix multiplication - for (int i = 0; i < length; i++) - { - // compute scalar product of i-th row and j-th column - for (int j = 0; j < length; j++) - { - if (i >= matrix[j].coefficients.length) - { - continue; - } - if (j < coefficients.length) - { - int scalarTerm = field.mult(matrix[j].coefficients[i], - coefficients[j]); - resultCoeff[i] = field.add(resultCoeff[i], scalarTerm); - } - } - } - - // compute the square root of each entry of the result coefficients - for (int i = 0; i < length; i++) - { - resultCoeff[i] = field.sqRoot(resultCoeff[i]); - } - - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute the result of the division of this polynomial by another - * polynomial modulo a third polynomial. - * - * @param divisor the divisor - * @param modulus the reduction polynomial - * @return this * divisor^(-1) mod modulus - */ - public PolynomialGF2mSmallM modDiv(PolynomialGF2mSmallM divisor, - PolynomialGF2mSmallM modulus) - { - int[] resultCoeff = modDiv(coefficients, divisor.coefficients, - modulus.coefficients); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute the result of the division of two polynomials modulo a third - * polynomial over the field GF(2^m). - * - * @param a the first polynomial - * @param b the second polynomial - * @param g the reduction polynomial - * @return a * b^(-1) mod g - */ - private int[] modDiv(int[] a, int[] b, int[] g) - { - int[] r0 = normalForm(g); - int[] r1 = mod(b, g); - int[] s0 = {0}; - int[] s1 = mod(a, g); - int[] s2; - int[][] q; - while (computeDegree(r1) != -1) - { - q = div(r0, r1); - r0 = normalForm(r1); - r1 = normalForm(q[1]); - s2 = add(s0, modMultiply(q[0], s1, g)); - s0 = normalForm(s1); - s1 = normalForm(s2); - - } - int hc = headCoefficient(r0); - s0 = multWithElement(s0, field.inverse(hc)); - return s0; - } - - /** - * Compute the inverse of this polynomial modulo the given polynomial. - * - * @param a the reduction polynomial - * @return this^(-1) mod a - */ - public PolynomialGF2mSmallM modInverse(PolynomialGF2mSmallM a) - { - int[] unit = {1}; - int[] resultCoeff = modDiv(unit, coefficients, a.coefficients); - return new PolynomialGF2mSmallM(field, resultCoeff); - } - - /** - * Compute a polynomial pair (a,b) from this polynomial and the given - * polynomial g with the property b*this = a mod g and deg(a)<=deg(g)/2. - * - * @param g the reduction polynomial - * @return PolynomialGF2mSmallM[] {a,b} with b*this = a mod g and deg(a)<= - * deg(g)/2 - */ - public PolynomialGF2mSmallM[] modPolynomialToFracton(PolynomialGF2mSmallM g) - { - int dg = g.degree >> 1; - int[] a0 = normalForm(g.coefficients); - int[] a1 = mod(coefficients, g.coefficients); - int[] b0 = {0}; - int[] b1 = {1}; - while (computeDegree(a1) > dg) - { - int[][] q = div(a0, a1); - a0 = a1; - a1 = q[1]; - int[] b2 = add(b0, modMultiply(q[0], b1, g.coefficients)); - b0 = b1; - b1 = b2; - } - - return new PolynomialGF2mSmallM[]{ - new PolynomialGF2mSmallM(field, a1), - new PolynomialGF2mSmallM(field, b1)}; - } - - /** - * checks if given object is equal to this polynomial. - *

    - * The method returns false whenever the given object is not polynomial over - * GF(2^m). - * - * @param other object - * @return true or false - */ - public boolean equals(Object other) - { - - if (other == null || !(other instanceof PolynomialGF2mSmallM)) - { - return false; - } - - PolynomialGF2mSmallM p = (PolynomialGF2mSmallM)other; - - if ((field.equals(p.field)) && (degree == p.degree) - && (isEqual(coefficients, p.coefficients))) - { - return true; - } - - return false; - } - - /** - * Compare two polynomials given as int arrays. - * - * @param a the first polynomial - * @param b the second polynomial - * @return true if a and b represent the - * same polynomials, false otherwise - */ - private static boolean isEqual(int[] a, int[] b) - { - int da = computeDegree(a); - int db = computeDegree(b); - if (da != db) - { - return false; - } - for (int i = 0; i <= da; i++) - { - if (a[i] != b[i]) - { - return false; - } - } - return true; - } - - /** - * @return the hash code of this polynomial - */ - public int hashCode() - { - int hash = field.hashCode(); - for (int j = 0; j < coefficients.length; j++) - { - hash = hash * 31 + coefficients[j]; - } - return hash; - } - - /** - * Returns a human readable form of the polynomial. - * - * @return a human readable form of the polynomial. - */ - public String toString() - { - String str = " Polynomial over " + field.toString() + ": \n"; - - for (int i = 0; i < coefficients.length; i++) - { - str = str + field.elementToStr(coefficients[i]) + "Y^" + i + "+"; - } - str = str + ";"; - - return str; - } - - /** - * Compute the degree of this polynomial. If this is the zero polynomial, - * the degree is -1. - */ - private void computeDegree() - { - for (degree = coefficients.length - 1; degree >= 0 - && coefficients[degree] == 0; degree--) - { - ; - } - } - - /** - * Compute the degree of a polynomial. - * - * @param a the polynomial - * @return the degree of the polynomial a. If a is - * the zero polynomial, return -1. - */ - private static int computeDegree(int[] a) - { - int degree; - for (degree = a.length - 1; degree >= 0 && a[degree] == 0; degree--) - { - ; - } - return degree; - } - - /** - * Strip leading zero coefficients from the given polynomial. - * - * @param a the polynomial - * @return the reduced polynomial - */ - private static int[] normalForm(int[] a) - { - int d = computeDegree(a); - - // if a is the zero polynomial - if (d == -1) - { - // return new zero polynomial - return new int[1]; - } - - // if a already is in normal form - if (a.length == d + 1) - { - // return a clone of a - return IntUtils.clone(a); - } - - // else, reduce a - int[] result = new int[d + 1]; - System.arraycopy(a, 0, result, 0, d + 1); - return result; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/PolynomialRingGF2.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/PolynomialRingGF2.java deleted file mode 100644 index c58f6a7e1a..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/PolynomialRingGF2.java +++ /dev/null @@ -1,282 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -/** - * This class describes operations with polynomials over finite field GF(2), i e - * polynomial ring R = GF(2)[X]. All operations are defined only for polynomials - * with degree <=32. For the polynomial representation the map f: R->Z, - * poly(X)->poly(2) is used, where integers have the binary representation. For - * example: X^7+X^3+X+1 -> (00...0010001011)=139 Also for polynomials type - * Integer is used. - * - * @see GF2mField - */ -public final class PolynomialRingGF2 -{ - - /** - * Default constructor (private). - */ - private PolynomialRingGF2() - { - // empty - } - - /** - * Return sum of two polyomials - * - * @param p polynomial - * @param q polynomial - * @return p+q - */ - - public static int add(int p, int q) - { - return p ^ q; - } - - /** - * Return product of two polynomials - * - * @param p polynomial - * @param q polynomial - * @return p*q - */ - - public static long multiply(int p, int q) - { - long result = 0; - if (q != 0) - { - long q1 = q & 0x00000000ffffffffL; - - while (p != 0) - { - byte b = (byte)(p & 0x01); - if (b == 1) - { - result ^= q1; - } - p >>>= 1; - q1 <<= 1; - - } - } - return result; - } - - /** - * Compute the product of two polynomials modulo a third polynomial. - * - * @param a the first polynomial - * @param b the second polynomial - * @param r the reduction polynomial - * @return a * b mod r - */ - public static int modMultiply(int a, int b, int r) - { - int result = 0; - int p = remainder(a, r); - int q = remainder(b, r); - if (q != 0) - { - int d = 1 << degree(r); - - while (p != 0) - { - byte pMod2 = (byte)(p & 0x01); - if (pMod2 == 1) - { - result ^= q; - } - p >>>= 1; - q <<= 1; - if (q >= d) - { - q ^= r; - } - } - } - return result; - } - - /** - * Return the degree of a polynomial - * - * @param p polynomial p - * @return degree(p) - */ - - public static int degree(int p) - { - int result = -1; - while (p != 0) - { - result++; - p >>>= 1; - } - return result; - } - - /** - * Return the degree of a polynomial - * - * @param p polynomial p - * @return degree(p) - */ - - public static int degree(long p) - { - int result = 0; - while (p != 0) - { - result++; - p >>>= 1; - } - return result - 1; - } - - /** - * Return the remainder of a polynomial division of two polynomials. - * - * @param p dividend - * @param q divisor - * @return p mod q - */ - public static int remainder(int p, int q) - { - int result = p; - - if (q == 0) - { - // -DM System.err.println - System.err.println("Error: to be divided by 0"); - return 0; - } - - while (degree(result) >= degree(q)) - { - result ^= q << (degree(result) - degree(q)); - } - - return result; - } - - /** - * Return the rest of devision two polynomials - * - * @param p polinomial - * @param q polinomial - * @return p mod q - */ - - public static int rest(long p, int q) - { - long p1 = p; - if (q == 0) - { - // -DM System.err.println - System.err.println("Error: to be divided by 0"); - return 0; - } - long q1 = q & 0x00000000ffffffffL; - while ((p1 >>> 32) != 0) - { - p1 ^= q1 << (degree(p1) - degree(q1)); - } - - int result = (int)(p1 & 0xffffffff); - while (degree(result) >= degree(q)) - { - result ^= q << (degree(result) - degree(q)); - } - - return result; - } - - /** - * Return the greatest common divisor of two polynomials - * - * @param p polinomial - * @param q polinomial - * @return GCD(p, q) - */ - - public static int gcd(int p, int q) - { - int a, b, c; - a = p; - b = q; - while (b != 0) - { - c = remainder(a, b); - a = b; - b = c; - - } - return a; - } - - /** - * Checking polynomial for irreducibility - * - * @param p polinomial - * @return true if p is irreducible and false otherwise - */ - - public static boolean isIrreducible(int p) - { - if (p == 0) - { - return false; - } - int d = degree(p) >>> 1; - int u = 2; - for (int i = 0; i < d; i++) - { - u = modMultiply(u, u, p); - if (gcd(u ^ 2, p) != 1) - { - return false; - } - } - return true; - } - - /** - * Creates irreducible polynomial with degree d - * - * @param deg polynomial degree - * @return irreducible polynomial p - */ - public static int getIrreduciblePolynomial(int deg) - { - if (deg < 0) - { - // -DM System.err.println - System.err.println("The Degree is negative"); - return 0; - } - if (deg > 31) - { - // -DM System.err.println - System.err.println("The Degree is more then 31"); - return 0; - } - if (deg == 0) - { - return 1; - } - int a = 1 << deg; - a++; - int b = 1 << (deg + 1); - for (int i = a; i < b; i += 2) - { - if (isIrreducible(i)) - { - return i; - } - } - return 0; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/PolynomialRingGF2m.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/PolynomialRingGF2m.java deleted file mode 100644 index c67441ff46..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/PolynomialRingGF2m.java +++ /dev/null @@ -1,175 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -/** - * This class represents polynomial rings GF(2^m)[X]/p(X) for - * m<32. If p(X) is irreducible, the polynomial ring - * is in fact an extension field of GF(2^m). - */ -public class PolynomialRingGF2m -{ - - /** - * the finite field this polynomial ring is defined over - */ - private GF2mField field; - - /** - * the reduction polynomial - */ - private PolynomialGF2mSmallM p; - - /** - * the squaring matrix for this polynomial ring (given as the array of its - * row vectors) - */ - protected PolynomialGF2mSmallM[] sqMatrix; - - /** - * the matrix for computing square roots in this polynomial ring (given as - * the array of its row vectors). This matrix is computed as the inverse of - * the squaring matrix. - */ - protected PolynomialGF2mSmallM[] sqRootMatrix; - - /** - * Constructor. - * - * @param field the finite field - * @param p the reduction polynomial - */ - public PolynomialRingGF2m(GF2mField field, PolynomialGF2mSmallM p) - { - this.field = field; - this.p = p; - computeSquaringMatrix(); - computeSquareRootMatrix(); - } - - /** - * @return the squaring matrix for this polynomial ring - */ - public PolynomialGF2mSmallM[] getSquaringMatrix() - { - return sqMatrix; - } - - /** - * @return the matrix for computing square roots for this polynomial ring - */ - public PolynomialGF2mSmallM[] getSquareRootMatrix() - { - return sqRootMatrix; - } - - /** - * Compute the squaring matrix for this polynomial ring, using the base - * field and the reduction polynomial. - */ - private void computeSquaringMatrix() - { - int numColumns = p.getDegree(); - sqMatrix = new PolynomialGF2mSmallM[numColumns]; - for (int i = 0; i < numColumns >> 1; i++) - { - int[] monomCoeffs = new int[(i << 1) + 1]; - monomCoeffs[i << 1] = 1; - sqMatrix[i] = new PolynomialGF2mSmallM(field, monomCoeffs); - } - for (int i = numColumns >> 1; i < numColumns; i++) - { - int[] monomCoeffs = new int[(i << 1) + 1]; - monomCoeffs[i << 1] = 1; - PolynomialGF2mSmallM monomial = new PolynomialGF2mSmallM(field, - monomCoeffs); - sqMatrix[i] = monomial.mod(p); - } - } - - /** - * Compute the matrix for computing square roots in this polynomial ring by - * inverting the squaring matrix. - */ - private void computeSquareRootMatrix() - { - int numColumns = p.getDegree(); - - // clone squaring matrix - PolynomialGF2mSmallM[] tmpMatrix = new PolynomialGF2mSmallM[numColumns]; - for (int i = numColumns - 1; i >= 0; i--) - { - tmpMatrix[i] = new PolynomialGF2mSmallM(sqMatrix[i]); - } - - // initialize square root matrix as unit matrix - sqRootMatrix = new PolynomialGF2mSmallM[numColumns]; - for (int i = numColumns - 1; i >= 0; i--) - { - sqRootMatrix[i] = new PolynomialGF2mSmallM(field, i); - } - - // simultaneously compute Gaussian reduction of squaring matrix and unit - // matrix - for (int i = 0; i < numColumns; i++) - { - // if diagonal element is zero - if (tmpMatrix[i].getCoefficient(i) == 0) - { - boolean foundNonZero = false; - // find a non-zero element in the same row - for (int j = i + 1; j < numColumns; j++) - { - if (tmpMatrix[j].getCoefficient(i) != 0) - { - // found it, swap columns ... - foundNonZero = true; - swapColumns(tmpMatrix, i, j); - swapColumns(sqRootMatrix, i, j); - // ... and quit searching - j = numColumns; - continue; - } - } - // if no non-zero element was found - if (!foundNonZero) - { - // the matrix is not invertible - throw new ArithmeticException( - "Squaring matrix is not invertible."); - } - } - - // normalize i-th column - int coef = tmpMatrix[i].getCoefficient(i); - int invCoef = field.inverse(coef); - tmpMatrix[i].multThisWithElement(invCoef); - sqRootMatrix[i].multThisWithElement(invCoef); - - // normalize all other columns - for (int j = 0; j < numColumns; j++) - { - if (j != i) - { - coef = tmpMatrix[j].getCoefficient(i); - if (coef != 0) - { - PolynomialGF2mSmallM tmpSqColumn = tmpMatrix[i] - .multWithElement(coef); - PolynomialGF2mSmallM tmpInvColumn = sqRootMatrix[i] - .multWithElement(coef); - tmpMatrix[j].addToThis(tmpSqColumn); - sqRootMatrix[j].addToThis(tmpInvColumn); - } - } - } - } - } - - private static void swapColumns(PolynomialGF2mSmallM[] matrix, int first, - int second) - { - PolynomialGF2mSmallM tmp = matrix[first]; - matrix[first] = matrix[second]; - matrix[second] = tmp; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/RandUtils.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/RandUtils.java deleted file mode 100644 index 0aea40f56d..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/RandUtils.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -import java.security.SecureRandom; - -public class RandUtils -{ - static int nextInt(SecureRandom rand, int n) - { - - if ((n & -n) == n) // i.e., n is a power of 2 - { - return (int)((n * (long)(rand.nextInt() >>> 1)) >> 31); - } - - int bits, value; - do - { - bits = rand.nextInt() >>> 1; - value = bits % n; - } - while (bits - value + (n - 1) < 0); - - return value; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/Vector.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/Vector.java deleted file mode 100644 index 6a55aad9d7..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/linearalgebra/Vector.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.linearalgebra; - -/** - * This abstract class defines vectors. It holds the length of vector. - */ -public abstract class Vector -{ - - /** - * the length of this vector - */ - protected int length; - - /** - * @return the length of this vector - */ - public final int getLength() - { - return length; - } - - /** - * @return this vector as byte array - */ - public abstract byte[] getEncoded(); - - /** - * Return whether this is the zero vector (i.e., all elements are zero). - * - * @return true if this is the zero vector, false - * otherwise - */ - public abstract boolean isZero(); - - /** - * Add another vector to this vector. - * - * @param addend the other vector - * @return this + addend - */ - public abstract Vector add(Vector addend); - - /** - * Multiply this vector with a permutation. - * - * @param p the permutation - * @return this*p = p*this - */ - public abstract Vector multiply(Permutation p); - - /** - * Check if the given object is equal to this vector. - * - * @param other vector - * @return the result of the comparison - */ - public abstract boolean equals(Object other); - - /** - * @return the hash code of this vector - */ - public abstract int hashCode(); - - /** - * @return a human readable form of this vector - */ - public abstract String toString(); - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/BigIntEuclidean.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/BigIntEuclidean.java deleted file mode 100644 index d13fea97f2..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/BigIntEuclidean.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.euclid; - -import java.math.BigInteger; - -/** - * Extended Euclidean Algorithm in BigIntegers - */ -public class BigIntEuclidean -{ - public BigInteger x, y, gcd; - - private BigIntEuclidean() - { - } - - /** - * Runs the EEA on two BigIntegers
    - * Implemented from pseudocode on Wikipedia. - * - * @param a - * @param b - * @return a BigIntEuclidean object that contains the result in the variables x, y, and gcd - */ - public static BigIntEuclidean calculate(BigInteger a, BigInteger b) - { - BigInteger x = BigInteger.ZERO; - BigInteger lastx = BigInteger.ONE; - BigInteger y = BigInteger.ONE; - BigInteger lasty = BigInteger.ZERO; - while (!b.equals(BigInteger.ZERO)) - { - BigInteger[] quotientAndRemainder = a.divideAndRemainder(b); - BigInteger quotient = quotientAndRemainder[0]; - - BigInteger temp = a; - a = b; - b = quotientAndRemainder[1]; - - temp = x; - x = lastx.subtract(quotient.multiply(x)); - lastx = temp; - - temp = y; - y = lasty.subtract(quotient.multiply(y)); - lasty = temp; - } - - BigIntEuclidean result = new BigIntEuclidean(); - result.x = lastx; - result.y = lasty; - result.gcd = a; - return result; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/IntEuclidean.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/IntEuclidean.java deleted file mode 100644 index 40f3312943..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/IntEuclidean.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.euclid; - -/** - * Extended Euclidean Algorithm in ints - */ -public class IntEuclidean -{ - public int x, y, gcd; - - private IntEuclidean() - { - } - - /** - * Runs the EEA on two ints
    - * Implemented from pseudocode on Wikipedia. - * - * @param a - * @param b - * @return a IntEuclidean object that contains the result in the variables x, y, and gcd - */ - public static IntEuclidean calculate(int a, int b) - { - int x = 0; - int lastx = 1; - int y = 1; - int lasty = 0; - while (b != 0) - { - int quotient = a / b; - - int temp = a; - a = b; - b = temp % b; - - temp = x; - x = lastx - quotient * x; - lastx = temp; - - temp = y; - y = lasty - quotient * y; - lasty = temp; - } - - IntEuclidean result = new IntEuclidean(); - result.x = lastx; - result.y = lasty; - result.gcd = a; - return result; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/BigDecimalPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/BigDecimalPolynomial.java deleted file mode 100644 index f9eb5c8149..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/BigDecimalPolynomial.java +++ /dev/null @@ -1,258 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial; - -import java.math.BigDecimal; - -/** - * A polynomial with {@link BigDecimal} coefficients. - * Some methods (like add) change the polynomial, others (like mult) do - * not but return the result as a new polynomial. - */ -public class BigDecimalPolynomial -{ - private static final BigDecimal ZERO = new BigDecimal("0"); - private static final BigDecimal ONE_HALF = new BigDecimal("0.5"); - - BigDecimal[] coeffs; - - /** - * Constructs a new polynomial with N coefficients initialized to 0. - * - * @param N the number of coefficients - */ - BigDecimalPolynomial(int N) - { - coeffs = new BigDecimal[N]; - for (int i = 0; i < N; i++) - { - coeffs[i] = ZERO; - } - } - - /** - * Constructs a new polynomial with a given set of coefficients. - * - * @param coeffs the coefficients - */ - BigDecimalPolynomial(BigDecimal[] coeffs) - { - this.coeffs = coeffs; - } - - /** - * Constructs a BigDecimalPolynomial from a BigIntPolynomial. The two polynomials are independent of each other. - * - * @param p the original polynomial - */ - public BigDecimalPolynomial(BigIntPolynomial p) - { - int N = p.coeffs.length; - coeffs = new BigDecimal[N]; - for (int i = 0; i < N; i++) - { - coeffs[i] = new BigDecimal(p.coeffs[i]); - } - } - - /** - * Divides all coefficients by 2. - */ - public void halve() - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] = coeffs[i].multiply(ONE_HALF); - } - } - - /** - * Multiplies the polynomial by another. Does not change this polynomial - * but returns the result as a new polynomial. - * - * @param poly2 the polynomial to multiply by - * @return a new polynomial - */ - public BigDecimalPolynomial mult(BigIntPolynomial poly2) - { - return mult(new BigDecimalPolynomial(poly2)); - } - - /** - * Multiplies the polynomial by another, taking the indices mod N. Does not - * change this polynomial but returns the result as a new polynomial. - * - * @param poly2 the polynomial to multiply by - * @return a new polynomial - */ - public BigDecimalPolynomial mult(BigDecimalPolynomial poly2) - { - int N = coeffs.length; - if (poly2.coeffs.length != N) - { - throw new IllegalArgumentException("Number of coefficients must be the same"); - } - - BigDecimalPolynomial c = multRecursive(poly2); - - if (c.coeffs.length > N) - { - for (int k = N; k < c.coeffs.length; k++) - { - c.coeffs[k - N] = c.coeffs[k - N].add(c.coeffs[k]); - } - c.coeffs = copyOf(c.coeffs, N); - } - return c; - } - - /** - * Karazuba multiplication - */ - private BigDecimalPolynomial multRecursive(BigDecimalPolynomial poly2) - { - BigDecimal[] a = coeffs; - BigDecimal[] b = poly2.coeffs; - - int n = poly2.coeffs.length; - if (n <= 1) - { - BigDecimal[] c = coeffs.clone(); - for (int i = 0; i < coeffs.length; i++) - { - c[i] = c[i].multiply(poly2.coeffs[0]); - } - return new BigDecimalPolynomial(c); - } - else - { - int n1 = n / 2; - - BigDecimalPolynomial a1 = new BigDecimalPolynomial(copyOf(a, n1)); - BigDecimalPolynomial a2 = new BigDecimalPolynomial(copyOfRange(a, n1, n)); - BigDecimalPolynomial b1 = new BigDecimalPolynomial(copyOf(b, n1)); - BigDecimalPolynomial b2 = new BigDecimalPolynomial(copyOfRange(b, n1, n)); - - BigDecimalPolynomial A = (BigDecimalPolynomial)a1.clone(); - A.add(a2); - BigDecimalPolynomial B = (BigDecimalPolynomial)b1.clone(); - B.add(b2); - - BigDecimalPolynomial c1 = a1.multRecursive(b1); - BigDecimalPolynomial c2 = a2.multRecursive(b2); - BigDecimalPolynomial c3 = A.multRecursive(B); - c3.sub(c1); - c3.sub(c2); - - BigDecimalPolynomial c = new BigDecimalPolynomial(2 * n - 1); - for (int i = 0; i < c1.coeffs.length; i++) - { - c.coeffs[i] = c1.coeffs[i]; - } - for (int i = 0; i < c3.coeffs.length; i++) - { - c.coeffs[n1 + i] = c.coeffs[n1 + i].add(c3.coeffs[i]); - } - for (int i = 0; i < c2.coeffs.length; i++) - { - c.coeffs[2 * n1 + i] = c.coeffs[2 * n1 + i].add(c2.coeffs[i]); - } - return c; - } - } - - /** - * Adds another polynomial which can have a different number of coefficients. - * - * @param b another polynomial - */ - public void add(BigDecimalPolynomial b) - { - if (b.coeffs.length > coeffs.length) - { - int N = coeffs.length; - coeffs = copyOf(coeffs, b.coeffs.length); - for (int i = N; i < coeffs.length; i++) - { - coeffs[i] = ZERO; - } - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] = coeffs[i].add(b.coeffs[i]); - } - } - - /** - * Subtracts another polynomial which can have a different number of coefficients. - * - * @param b - */ - void sub(BigDecimalPolynomial b) - { - if (b.coeffs.length > coeffs.length) - { - int N = coeffs.length; - coeffs = copyOf(coeffs, b.coeffs.length); - for (int i = N; i < coeffs.length; i++) - { - coeffs[i] = ZERO; - } - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] = coeffs[i].subtract(b.coeffs[i]); - } - } - - /** - * Rounds all coefficients to the nearest integer. - * - * @return a new polynomial with BigInteger coefficients - */ - public BigIntPolynomial round() - { - int N = coeffs.length; - BigIntPolynomial p = new BigIntPolynomial(N); - for (int i = 0; i < N; i++) - { - p.coeffs[i] = coeffs[i].setScale(0, BigDecimal.ROUND_HALF_EVEN).toBigInteger(); - } - return p; - } - - /** - * Makes a copy of the polynomial that is independent of the original. - */ - public Object clone() - { - return new BigDecimalPolynomial(coeffs.clone()); - } - - private BigDecimal[] copyOf(BigDecimal[] a, int length) - { - BigDecimal[] tmp = new BigDecimal[length]; - - System.arraycopy(a, 0, tmp, 0, a.length < length ? a.length : length); - - return tmp; - } - - private BigDecimal[] copyOfRange(BigDecimal[] a, int from, int to) - { - int newLength = to - from; - BigDecimal[] tmp = new BigDecimal[to - from]; - - System.arraycopy(a, from, tmp, 0, (a.length - from) < newLength ? (a.length - from) : newLength); - - return tmp; - } - - public BigDecimal[] getCoeffs() - { - BigDecimal[] tmp = new BigDecimal[coeffs.length]; - - System.arraycopy(coeffs, 0, tmp, 0, coeffs.length); - - return tmp; - } - -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/BigIntPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/BigIntPolynomial.java deleted file mode 100644 index 50f1517782..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/BigIntPolynomial.java +++ /dev/null @@ -1,394 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.bouncycastle.crypto.CryptoServicesRegistrar; -import org.bouncycastle.util.Arrays; - -/** - * A polynomial with {@link BigInteger} coefficients.
    - * Some methods (like add) change the polynomial, others (like mult) do - * not but return the result as a new polynomial. - */ -public class BigIntPolynomial -{ - private final static double LOG_10_2 = Math.log10(2); - - BigInteger[] coeffs; - - /** - * Constructs a new polynomial with N coefficients initialized to 0. - * - * @param N the number of coefficients - */ - BigIntPolynomial(int N) - { - coeffs = new BigInteger[N]; - for (int i = 0; i < N; i++) - { - coeffs[i] = Constants.BIGINT_ZERO; - } - } - - /** - * Constructs a new polynomial with a given set of coefficients. - * - * @param coeffs the coefficients - */ - BigIntPolynomial(BigInteger[] coeffs) - { - this.coeffs = coeffs; - } - - /** - * Constructs a BigIntPolynomial from a IntegerPolynomial. The two polynomials are - * independent of each other. - * - * @param p the original polynomial - */ - public BigIntPolynomial(IntegerPolynomial p) - { - coeffs = new BigInteger[p.coeffs.length]; - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] = BigInteger.valueOf(p.coeffs[i]); - } - } - - /** - * Generates a random polynomial with numOnes coefficients equal to 1, - * numNegOnes coefficients equal to -1, and the rest equal to 0. - * - * @param N number of coefficients - * @param numOnes number of 1's - * @param numNegOnes number of -1's - * @return a random polynomial. - */ - static BigIntPolynomial generateRandomSmall(int N, int numOnes, int numNegOnes) - { - List coeffs = new ArrayList(); - for (int i = 0; i < numOnes; i++) - { - coeffs.add(Constants.BIGINT_ONE); - } - for (int i = 0; i < numNegOnes; i++) - { - coeffs.add(BigInteger.valueOf(-1)); - } - while (coeffs.size() < N) - { - coeffs.add(Constants.BIGINT_ZERO); - } - Collections.shuffle(coeffs, CryptoServicesRegistrar.getSecureRandom()); - - BigIntPolynomial poly = new BigIntPolynomial(N); - for (int i = 0; i < coeffs.size(); i++) - { - poly.coeffs[i] = (BigInteger)coeffs.get(i); - } - return poly; - } - - /** - * Multiplies the polynomial by another, taking the indices mod N. Does not - * change this polynomial but returns the result as a new polynomial.
    - * Both polynomials must have the same number of coefficients. - * - * @param poly2 the polynomial to multiply by - * @return a new polynomial - */ - public BigIntPolynomial mult(BigIntPolynomial poly2) - { - int N = coeffs.length; - if (poly2.coeffs.length != N) - { - throw new IllegalArgumentException("Number of coefficients must be the same"); - } - - BigIntPolynomial c = multRecursive(poly2); - - if (c.coeffs.length > N) - { - for (int k = N; k < c.coeffs.length; k++) - { - c.coeffs[k - N] = c.coeffs[k - N].add(c.coeffs[k]); - } - c.coeffs = Arrays.copyOf(c.coeffs, N); - } - return c; - } - - /** - * Karazuba multiplication - */ - private BigIntPolynomial multRecursive(BigIntPolynomial poly2) - { - BigInteger[] a = coeffs; - BigInteger[] b = poly2.coeffs; - - int n = poly2.coeffs.length; - if (n <= 1) - { - BigInteger[] c = Arrays.clone(coeffs); - for (int i = 0; i < coeffs.length; i++) - { - c[i] = c[i].multiply(poly2.coeffs[0]); - } - return new BigIntPolynomial(c); - } - else - { - int n1 = n / 2; - - BigIntPolynomial a1 = new BigIntPolynomial(Arrays.copyOf(a, n1)); - BigIntPolynomial a2 = new BigIntPolynomial(Arrays.copyOfRange(a, n1, n)); - BigIntPolynomial b1 = new BigIntPolynomial(Arrays.copyOf(b, n1)); - BigIntPolynomial b2 = new BigIntPolynomial(Arrays.copyOfRange(b, n1, n)); - - BigIntPolynomial A = (BigIntPolynomial)a1.clone(); - A.add(a2); - BigIntPolynomial B = (BigIntPolynomial)b1.clone(); - B.add(b2); - - BigIntPolynomial c1 = a1.multRecursive(b1); - BigIntPolynomial c2 = a2.multRecursive(b2); - BigIntPolynomial c3 = A.multRecursive(B); - c3.sub(c1); - c3.sub(c2); - - BigIntPolynomial c = new BigIntPolynomial(2 * n - 1); - for (int i = 0; i < c1.coeffs.length; i++) - { - c.coeffs[i] = c1.coeffs[i]; - } - for (int i = 0; i < c3.coeffs.length; i++) - { - c.coeffs[n1 + i] = c.coeffs[n1 + i].add(c3.coeffs[i]); - } - for (int i = 0; i < c2.coeffs.length; i++) - { - c.coeffs[2 * n1 + i] = c.coeffs[2 * n1 + i].add(c2.coeffs[i]); - } - return c; - } - } - - /** - * Adds another polynomial which can have a different number of coefficients, - * and takes the coefficient values mod modulus. - * - * @param b another polynomial - */ - void add(BigIntPolynomial b, BigInteger modulus) - { - add(b); - mod(modulus); - } - - /** - * Adds another polynomial which can have a different number of coefficients. - * - * @param b another polynomial - */ - public void add(BigIntPolynomial b) - { - if (b.coeffs.length > coeffs.length) - { - int N = coeffs.length; - coeffs = Arrays.copyOf(coeffs, b.coeffs.length); - for (int i = N; i < coeffs.length; i++) - { - coeffs[i] = Constants.BIGINT_ZERO; - } - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] = coeffs[i].add(b.coeffs[i]); - } - } - - /** - * Subtracts another polynomial which can have a different number of coefficients. - * - * @param b another polynomial - */ - public void sub(BigIntPolynomial b) - { - if (b.coeffs.length > coeffs.length) - { - int N = coeffs.length; - coeffs = Arrays.copyOf(coeffs, b.coeffs.length); - for (int i = N; i < coeffs.length; i++) - { - coeffs[i] = Constants.BIGINT_ZERO; - } - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] = coeffs[i].subtract(b.coeffs[i]); - } - } - - /** - * Multiplies each coefficient by a BigInteger. Does not return a new polynomial but modifies this polynomial. - * - * @param factor - */ - public void mult(BigInteger factor) - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] = coeffs[i].multiply(factor); - } - } - - /** - * Multiplies each coefficient by a int. Does not return a new polynomial but modifies this polynomial. - * - * @param factor - */ - void mult(int factor) - { - mult(BigInteger.valueOf(factor)); - } - - /** - * Divides each coefficient by a BigInteger and rounds the result to the nearest whole number.
    - * Does not return a new polynomial but modifies this polynomial. - * - * @param divisor the number to divide by - */ - public void div(BigInteger divisor) - { - BigInteger d = divisor.add(Constants.BIGINT_ONE).divide(BigInteger.valueOf(2)); - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] = coeffs[i].compareTo(Constants.BIGINT_ZERO) > 0 ? coeffs[i].add(d) : coeffs[i].add(d.negate()); - coeffs[i] = coeffs[i].divide(divisor); - } - } - - /** - * Divides each coefficient by a BigDecimal and rounds the result to decimalPlaces places. - * - * @param divisor the number to divide by - * @param decimalPlaces the number of fractional digits to round the result to - * @return a new BigDecimalPolynomial - */ - public BigDecimalPolynomial div(BigDecimal divisor, int decimalPlaces) - { - BigInteger max = maxCoeffAbs(); - int coeffLength = (int)(max.bitLength() * LOG_10_2) + 1; - // factor = 1/divisor - BigDecimal factor = Constants.BIGDEC_ONE.divide(divisor, coeffLength + decimalPlaces + 1, BigDecimal.ROUND_HALF_EVEN); - - // multiply each coefficient by factor - BigDecimalPolynomial p = new BigDecimalPolynomial(coeffs.length); - for (int i = 0; i < coeffs.length; i++) - // multiply, then truncate after decimalPlaces so subsequent operations aren't slowed down - { - p.coeffs[i] = new BigDecimal(coeffs[i]).multiply(factor).setScale(decimalPlaces, BigDecimal.ROUND_HALF_EVEN); - } - - return p; - } - - /** - * Returns the base10 length of the largest coefficient. - * - * @return length of the longest coefficient - */ - public int getMaxCoeffLength() - { - return (int)(maxCoeffAbs().bitLength() * LOG_10_2) + 1; - } - - private BigInteger maxCoeffAbs() - { - BigInteger max = coeffs[0].abs(); - for (int i = 1; i < coeffs.length; i++) - { - BigInteger coeff = coeffs[i].abs(); - if (coeff.compareTo(max) > 0) - { - max = coeff; - } - } - return max; - } - - /** - * Takes each coefficient modulo a number. - * - * @param modulus - */ - public void mod(BigInteger modulus) - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] = coeffs[i].mod(modulus); - } - } - - /** - * Returns the sum of all coefficients, i.e. evaluates the polynomial at 0. - * - * @return the sum of all coefficients - */ - BigInteger sumCoeffs() - { - BigInteger sum = Constants.BIGINT_ZERO; - for (int i = 0; i < coeffs.length; i++) - { - sum = sum.add(coeffs[i]); - } - return sum; - } - - /** - * Makes a copy of the polynomial that is independent of the original. - */ - public Object clone() - { - return new BigIntPolynomial(coeffs.clone()); - } - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + Arrays.hashCode(coeffs); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - BigIntPolynomial other = (BigIntPolynomial)obj; - if (!Arrays.areEqual(coeffs, other.coeffs)) - { - return false; - } - return true; - } - - public BigInteger[] getCoeffs() - { - return Arrays.clone(coeffs); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/Constants.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/Constants.java deleted file mode 100644 index 7f65663f93..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/Constants.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial; - -import java.math.BigDecimal; -import java.math.BigInteger; - -public class Constants -{ - static final BigInteger BIGINT_ZERO = BigInteger.valueOf(0); - static final BigInteger BIGINT_ONE = BigInteger.valueOf(1); - - static final BigDecimal BIGDEC_ONE = BigDecimal.valueOf(1); -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/DenseTernaryPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/DenseTernaryPolynomial.java deleted file mode 100644 index a154970d5d..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/DenseTernaryPolynomial.java +++ /dev/null @@ -1,142 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial; - -import java.security.SecureRandom; - -import org.bouncycastle.pqc.legacy.math.ntru.util.Util; -import org.bouncycastle.util.Arrays; - -/** - * A TernaryPolynomial with a "high" number of nonzero coefficients. - */ -public class DenseTernaryPolynomial - extends IntegerPolynomial - implements TernaryPolynomial -{ - - /** - * Constructs a new DenseTernaryPolynomial with N coefficients. - * - * @param N the number of coefficients - */ - DenseTernaryPolynomial(int N) - { - super(N); - checkTernarity(); - } - - /** - * Constructs a DenseTernaryPolynomial from a IntegerPolynomial. The two polynomials are - * independent of each other. - * - * @param intPoly the original polynomial - */ - public DenseTernaryPolynomial(IntegerPolynomial intPoly) - { - this(intPoly.coeffs); - } - - /** - * Constructs a new DenseTernaryPolynomial with a given set of coefficients. - * - * @param coeffs the coefficients - */ - public DenseTernaryPolynomial(int[] coeffs) - { - super(coeffs); - checkTernarity(); - } - - private void checkTernarity() - { - for (int i = 0; i != coeffs.length; i++) - { - int c = coeffs[i]; - if (c < -1 || c > 1) - { - throw new IllegalStateException("Illegal value: " + c + ", must be one of {-1, 0, 1}"); - } - } - } - - /** - * Generates a random polynomial with numOnes coefficients equal to 1, - * numNegOnes coefficients equal to -1, and the rest equal to 0. - * - * @param N number of coefficients - * @param numOnes number of 1's - * @param numNegOnes number of -1's - */ - public static DenseTernaryPolynomial generateRandom(int N, int numOnes, int numNegOnes, SecureRandom random) - { - int[] coeffs = Util.generateRandomTernary(N, numOnes, numNegOnes, random); - return new DenseTernaryPolynomial(coeffs); - } - - /** - * Generates a polynomial with coefficients randomly selected from {-1, 0, 1}. - * - * @param N number of coefficients - */ - public static DenseTernaryPolynomial generateRandom(int N, SecureRandom random) - { - DenseTernaryPolynomial poly = new DenseTernaryPolynomial(N); - for (int i = 0; i < N; i++) - { - poly.coeffs[i] = random.nextInt(3) - 1; - } - return poly; - } - - public IntegerPolynomial mult(IntegerPolynomial poly2, int modulus) - { - // even on 32-bit systems, LongPolynomial5 multiplies faster than IntegerPolynomial - if (modulus == 2048) - { - IntegerPolynomial poly2Pos = (IntegerPolynomial)poly2.clone(); - poly2Pos.modPositive(2048); - LongPolynomial5 poly5 = new LongPolynomial5(poly2Pos); - return poly5.mult(this).toIntegerPolynomial(); - } - else - { - return super.mult(poly2, modulus); - } - } - - public int[] getOnes() - { - int N = coeffs.length; - int[] ones = new int[N]; - int onesIdx = 0; - for (int i = 0; i < N; i++) - { - int c = coeffs[i]; - if (c == 1) - { - ones[onesIdx++] = i; - } - } - return Arrays.copyOf(ones, onesIdx); - } - - public int[] getNegOnes() - { - int N = coeffs.length; - int[] negOnes = new int[N]; - int negOnesIdx = 0; - for (int i = 0; i < N; i++) - { - int c = coeffs[i]; - if (c == -1) - { - negOnes[negOnesIdx++] = i; - } - } - return Arrays.copyOf(negOnes, negOnesIdx); - } - - public int size() - { - return coeffs.length; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/IntegerPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/IntegerPolynomial.java deleted file mode 100644 index a81cbb22c0..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/IntegerPolynomial.java +++ /dev/null @@ -1,1379 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial; - -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.LinkedBlockingQueue; - -import org.bouncycastle.pqc.legacy.math.ntru.euclid.BigIntEuclidean; -import org.bouncycastle.pqc.legacy.math.ntru.util.ArrayEncoder; -import org.bouncycastle.pqc.legacy.math.ntru.util.Util; -import org.bouncycastle.util.Arrays; - -/** - * A polynomial with int coefficients.
    - * Some methods (like add) change the polynomial, others (like mult) do - * not but return the result as a new polynomial. - */ -public class IntegerPolynomial - implements Polynomial -{ - private static final int NUM_EQUAL_RESULTANTS = 3; - /** - * Prime numbers > 4500 for resultant computation. Starting them below ~4400 causes incorrect results occasionally. - * Fortunately, 4500 is about the optimum number for performance.
    - * This array contains enough prime numbers so primes never have to be computed on-line for any standard {@link org.bouncycastle.pqc.legacy.crypto.ntru.NTRUSigningParameters}. - */ - private static final int[] PRIMES = new int[]{ - 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, - 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, - 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, - 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, - 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, - 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, - 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, - 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, - 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, - 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, - 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, - 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, - 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, - 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, - 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, - 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, - 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, - 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, - 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, - 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, - 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, - 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, - 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, - 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, - 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, - 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, - 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, - 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, - 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, - 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, - 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, - 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, - 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, - 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, - 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, - 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, - 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, - 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, - 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, - 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, - 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, - 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, - 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, - 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, - 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, - 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, - 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, - 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, - 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, - 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, - 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, - 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, - 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, - 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, - 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, - 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, - 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, - 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, - 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, - 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, - 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, - 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973}; - private static final List BIGINT_PRIMES; - - static - { - BIGINT_PRIMES = new ArrayList(); - for (int i = 0; i != PRIMES.length; i++) - { - BIGINT_PRIMES.add(BigInteger.valueOf(PRIMES[i])); - } - } - - public int[] coeffs; - - /** - * Constructs a new polynomial with N coefficients initialized to 0. - * - * @param N the number of coefficients - */ - public IntegerPolynomial(int N) - { - coeffs = new int[N]; - } - - /** - * Constructs a new polynomial with a given set of coefficients. - * - * @param coeffs the coefficients - */ - public IntegerPolynomial(int[] coeffs) - { - this.coeffs = coeffs; - } - - /** - * Constructs a IntegerPolynomial from a BigIntPolynomial. The two polynomials are independent of each other. - * - * @param p the original polynomial - */ - public IntegerPolynomial(BigIntPolynomial p) - { - coeffs = new int[p.coeffs.length]; - for (int i = 0; i < p.coeffs.length; i++) - { - coeffs[i] = p.coeffs[i].intValue(); - } - } - - /** - * Decodes a byte array to a polynomial with N ternary coefficients
    - * Ignores any excess bytes. - * - * @param data an encoded ternary polynomial - * @param N number of coefficients - * @return the decoded polynomial - */ - public static IntegerPolynomial fromBinary3Sves(byte[] data, int N) - { - return new IntegerPolynomial(ArrayEncoder.decodeMod3Sves(data, N)); - } - - /** - * Converts a byte array produced by {@link #toBinary3Tight()} to a polynomial. - * - * @param b a byte array - * @param N number of coefficients - * @return the decoded polynomial - */ - public static IntegerPolynomial fromBinary3Tight(byte[] b, int N) - { - return new IntegerPolynomial(ArrayEncoder.decodeMod3Tight(b, N)); - } - - /** - * Reads data produced by {@link #toBinary3Tight()} from an input stream and converts it to a polynomial. - * - * @param is an input stream - * @param N number of coefficients - * @return the decoded polynomial - */ - public static IntegerPolynomial fromBinary3Tight(InputStream is, int N) - throws IOException - { - return new IntegerPolynomial(ArrayEncoder.decodeMod3Tight(is, N)); - } - - /** - * Returns a polynomial with N coefficients between 0 and q-1.
    - * q must be a power of 2.
    - * Ignores any excess bytes. - * - * @param data an encoded ternary polynomial - * @param N number of coefficients - * @param q - * @return the decoded polynomial - */ - public static IntegerPolynomial fromBinary(byte[] data, int N, int q) - { - return new IntegerPolynomial(ArrayEncoder.decodeModQ(data, N, q)); - } - - /** - * Returns a polynomial with N coefficients between 0 and q-1.
    - * q must be a power of 2.
    - * Ignores any excess bytes. - * - * @param is an encoded ternary polynomial - * @param N number of coefficients - * @param q - * @return the decoded polynomial - */ - public static IntegerPolynomial fromBinary(InputStream is, int N, int q) - throws IOException - { - return new IntegerPolynomial(ArrayEncoder.decodeModQ(is, N, q)); - } - - /** - * Encodes a polynomial with ternary coefficients to binary. - * coeffs[2*i] and coeffs[2*i+1] must not both equal -1 for any integer i, - * so this method is only safe to use with polynomials produced by fromBinary3Sves(). - * - * @return the encoded polynomial - */ - public byte[] toBinary3Sves() - { - return ArrayEncoder.encodeMod3Sves(coeffs); - } - - /** - * Converts a polynomial with ternary coefficients to binary. - * - * @return the encoded polynomial - */ - public byte[] toBinary3Tight() - { - BigInteger sum = Constants.BIGINT_ZERO; - for (int i = coeffs.length - 1; i >= 0; i--) - { - sum = sum.multiply(BigInteger.valueOf(3)); - sum = sum.add(BigInteger.valueOf(coeffs[i] + 1)); - } - - int size = (BigInteger.valueOf(3).pow(coeffs.length).bitLength() + 7) / 8; - byte[] arr = sum.toByteArray(); - - if (arr.length < size) - { - // pad with leading zeros so arr.length==size - byte[] arr2 = new byte[size]; - System.arraycopy(arr, 0, arr2, size - arr.length, arr.length); - return arr2; - } - - if (arr.length > size) - // drop sign bit - { - arr = Arrays.copyOfRange(arr, 1, arr.length); - } - return arr; - } - - /** - * Encodes a polynomial whose coefficients are between 0 and q, to binary. q must be a power of 2. - * - * @param q - * @return the encoded polynomial - */ - public byte[] toBinary(int q) - { - return ArrayEncoder.encodeModQ(coeffs, q); - } - - /** - * Multiplies the polynomial with another, taking the values mod modulus and the indices mod N - */ - public IntegerPolynomial mult(IntegerPolynomial poly2, int modulus) - { - IntegerPolynomial c = mult(poly2); - c.mod(modulus); - return c; - } - - /** - * Multiplies the polynomial with another, taking the indices mod N - */ - public IntegerPolynomial mult(IntegerPolynomial poly2) - { - int N = coeffs.length; - if (poly2.coeffs.length != N) - { - throw new IllegalArgumentException("Number of coefficients must be the same"); - } - - IntegerPolynomial c = multRecursive(poly2); - - if (c.coeffs.length > N) - { - for (int k = N; k < c.coeffs.length; k++) - { - c.coeffs[k - N] += c.coeffs[k]; - } - c.coeffs = Arrays.copyOf(c.coeffs, N); - } - return c; - } - - public BigIntPolynomial mult(BigIntPolynomial poly2) - { - return new BigIntPolynomial(this).mult(poly2); - } - - /** - * Karazuba multiplication - */ - private IntegerPolynomial multRecursive(IntegerPolynomial poly2) - { - int[] a = coeffs; - int[] b = poly2.coeffs; - - int n = poly2.coeffs.length; - if (n <= 32) - { - int cn = 2 * n - 1; - IntegerPolynomial c = new IntegerPolynomial(new int[cn]); - for (int k = 0; k < cn; k++) - { - for (int i = Math.max(0, k - n + 1); i <= Math.min(k, n - 1); i++) - { - c.coeffs[k] += b[i] * a[k - i]; - } - } - return c; - } - else - { - int n1 = n / 2; - - IntegerPolynomial a1 = new IntegerPolynomial(Arrays.copyOf(a, n1)); - IntegerPolynomial a2 = new IntegerPolynomial(Arrays.copyOfRange(a, n1, n)); - IntegerPolynomial b1 = new IntegerPolynomial(Arrays.copyOf(b, n1)); - IntegerPolynomial b2 = new IntegerPolynomial(Arrays.copyOfRange(b, n1, n)); - - IntegerPolynomial A = (IntegerPolynomial)a1.clone(); - A.add(a2); - IntegerPolynomial B = (IntegerPolynomial)b1.clone(); - B.add(b2); - - IntegerPolynomial c1 = a1.multRecursive(b1); - IntegerPolynomial c2 = a2.multRecursive(b2); - IntegerPolynomial c3 = A.multRecursive(B); - c3.sub(c1); - c3.sub(c2); - - IntegerPolynomial c = new IntegerPolynomial(2 * n - 1); - for (int i = 0; i < c1.coeffs.length; i++) - { - c.coeffs[i] = c1.coeffs[i]; - } - for (int i = 0; i < c3.coeffs.length; i++) - { - c.coeffs[n1 + i] += c3.coeffs[i]; - } - for (int i = 0; i < c2.coeffs.length; i++) - { - c.coeffs[2 * n1 + i] += c2.coeffs[i]; - } - return c; - } - } - - /** - * Computes the inverse mod q; q must be a power of 2.
    - * Returns null if the polynomial is not invertible. - * - * @param q the modulus - * @return a new polynomial - */ - public IntegerPolynomial invertFq(int q) - { - int N = coeffs.length; - int k = 0; - IntegerPolynomial b = new IntegerPolynomial(N + 1); - b.coeffs[0] = 1; - IntegerPolynomial c = new IntegerPolynomial(N + 1); - IntegerPolynomial f = new IntegerPolynomial(N + 1); - f.coeffs = Arrays.copyOf(coeffs, N + 1); - f.modPositive(2); - // set g(x) = x^N − 1 - IntegerPolynomial g = new IntegerPolynomial(N + 1); - g.coeffs[0] = 1; - g.coeffs[N] = 1; - while (true) - { - while (f.coeffs[0] == 0) - { - for (int i = 1; i <= N; i++) - { - f.coeffs[i - 1] = f.coeffs[i]; // f(x) = f(x) / x - c.coeffs[N + 1 - i] = c.coeffs[N - i]; // c(x) = c(x) * x - } - f.coeffs[N] = 0; - c.coeffs[0] = 0; - k++; - if (f.equalsZero()) - { - return null; // not invertible - } - } - if (f.equalsOne()) - { - break; - } - if (f.degree() < g.degree()) - { - // exchange f and g - IntegerPolynomial temp = f; - f = g; - g = temp; - // exchange b and c - temp = b; - b = c; - c = temp; - } - f.add(g, 2); - b.add(c, 2); - } - - if (b.coeffs[N] != 0) - { - return null; - } - // Fq(x) = x^(N-k) * b(x) - IntegerPolynomial Fq = new IntegerPolynomial(N); - int j = 0; - k %= N; - for (int i = N - 1; i >= 0; i--) - { - j = i - k; - if (j < 0) - { - j += N; - } - Fq.coeffs[j] = b.coeffs[i]; - } - - return mod2ToModq(Fq, q); - } - - /** - * Computes the inverse mod q from the inverse mod 2 - * - * @param Fq - * @param q - * @return The inverse of this polynomial mod q - */ - private IntegerPolynomial mod2ToModq(IntegerPolynomial Fq, int q) - { - if (Util.is64BitJVM() && q == 2048) - { - LongPolynomial2 thisLong = new LongPolynomial2(this); - LongPolynomial2 FqLong = new LongPolynomial2(Fq); - int v = 2; - while (v < q) - { - v *= 2; - LongPolynomial2 temp = (LongPolynomial2)FqLong.clone(); - temp.mult2And(v - 1); - FqLong = thisLong.mult(FqLong).mult(FqLong); - temp.subAnd(FqLong, v - 1); - FqLong = temp; - } - return FqLong.toIntegerPolynomial(); - } - else - { - int v = 2; - while (v < q) - { - v *= 2; - IntegerPolynomial temp = new IntegerPolynomial(Arrays.copyOf(Fq.coeffs, Fq.coeffs.length)); - temp.mult2(v); - Fq = mult(Fq, v).mult(Fq, v); - temp.sub(Fq, v); - Fq = temp; - } - return Fq; - } - } - - /** - * Computes the inverse mod 3. - * Returns null if the polynomial is not invertible. - * - * @return a new polynomial - */ - public IntegerPolynomial invertF3() - { - int N = coeffs.length; - int k = 0; - IntegerPolynomial b = new IntegerPolynomial(N + 1); - b.coeffs[0] = 1; - IntegerPolynomial c = new IntegerPolynomial(N + 1); - IntegerPolynomial f = new IntegerPolynomial(N + 1); - f.coeffs = Arrays.copyOf(coeffs, N + 1); - f.modPositive(3); - // set g(x) = x^N − 1 - IntegerPolynomial g = new IntegerPolynomial(N + 1); - g.coeffs[0] = -1; - g.coeffs[N] = 1; - while (true) - { - while (f.coeffs[0] == 0) - { - for (int i = 1; i <= N; i++) - { - f.coeffs[i - 1] = f.coeffs[i]; // f(x) = f(x) / x - c.coeffs[N + 1 - i] = c.coeffs[N - i]; // c(x) = c(x) * x - } - f.coeffs[N] = 0; - c.coeffs[0] = 0; - k++; - if (f.equalsZero()) - { - return null; // not invertible - } - } - if (f.equalsAbsOne()) - { - break; - } - if (f.degree() < g.degree()) - { - // exchange f and g - IntegerPolynomial temp = f; - f = g; - g = temp; - // exchange b and c - temp = b; - b = c; - c = temp; - } - if (f.coeffs[0] == g.coeffs[0]) - { - f.sub(g, 3); - b.sub(c, 3); - } - else - { - f.add(g, 3); - b.add(c, 3); - } - } - - if (b.coeffs[N] != 0) - { - return null; - } - // Fp(x) = [+-] x^(N-k) * b(x) - IntegerPolynomial Fp = new IntegerPolynomial(N); - int j = 0; - k %= N; - for (int i = N - 1; i >= 0; i--) - { - j = i - k; - if (j < 0) - { - j += N; - } - Fp.coeffs[j] = f.coeffs[0] * b.coeffs[i]; - } - - Fp.ensurePositive(3); - return Fp; - } - - /** - * Resultant of this polynomial with x^n-1 using a probabilistic algorithm. - *

    - * Unlike EESS, this implementation does not compute all resultants modulo primes - * such that their product exceeds the maximum possible resultant, but rather stops - * when NUM_EQUAL_RESULTANTS consecutive modular resultants are equal.
    - * This means the return value may be incorrect. Experiments show this happens in - * about 1 out of 100 cases when N=439 and NUM_EQUAL_RESULTANTS=2, - * so the likelyhood of leaving the loop too early is (1/100)^(NUM_EQUAL_RESULTANTS-1). - *

    - * Because of the above, callers must verify the output and try a different polynomial if necessary. - * - * @return (rho, res) satisfying res = rho*this + t*(x^n-1) for some integer t. - */ - public Resultant resultant() - { - int N = coeffs.length; - - // Compute resultants modulo prime numbers. Continue until NUM_EQUAL_RESULTANTS consecutive modular resultants are equal. - LinkedList modResultants = new LinkedList(); - BigInteger pProd = Constants.BIGINT_ONE; - BigInteger res = Constants.BIGINT_ONE; - int numEqual = 1; // number of consecutive modular resultants equal to each other - - PrimeGenerator primes = new PrimeGenerator(); - - while (true) - { - BigInteger prime = primes.nextPrime(); - ModularResultant crr = resultant(prime.intValue()); - modResultants.add(crr); - - BigInteger temp = pProd.multiply(prime); - BigIntEuclidean er = BigIntEuclidean.calculate(prime, pProd); - BigInteger resPrev = res; - res = res.multiply(er.x.multiply(prime)); - BigInteger res2 = crr.res.multiply(er.y.multiply(pProd)); - res = res.add(res2).mod(temp); - pProd = temp; - - BigInteger pProd2 = pProd.divide(BigInteger.valueOf(2)); - BigInteger pProd2n = pProd2.negate(); - if (res.compareTo(pProd2) > 0) - { - res = res.subtract(pProd); - } - else if (res.compareTo(pProd2n) < 0) - { - res = res.add(pProd); - } - - if (res.equals(resPrev)) - { - numEqual++; - if (numEqual >= NUM_EQUAL_RESULTANTS) - { - break; - } - } - else - { - numEqual = 1; - } - } - - // Combine modular rho's to obtain the final rho. - // For efficiency, first combine all pairs of small resultants to bigger resultants, - // then combine pairs of those, etc. until only one is left. - while (modResultants.size() > 1) - { - ModularResultant modRes1 = modResultants.removeFirst(); - ModularResultant modRes2 = modResultants.removeFirst(); - ModularResultant modRes3 = ModularResultant.combineRho(modRes1, modRes2); - modResultants.addLast(modRes3); - } - BigIntPolynomial rhoP = modResultants.getFirst().rho; - - BigInteger pProd2 = pProd.divide(BigInteger.valueOf(2)); - BigInteger pProd2n = pProd2.negate(); - if (res.compareTo(pProd2) > 0) - { - res = res.subtract(pProd); - } - if (res.compareTo(pProd2n) < 0) - { - res = res.add(pProd); - } - - for (int i = 0; i < N; i++) - { - BigInteger c = rhoP.coeffs[i]; - if (c.compareTo(pProd2) > 0) - { - rhoP.coeffs[i] = c.subtract(pProd); - } - if (c.compareTo(pProd2n) < 0) - { - rhoP.coeffs[i] = c.add(pProd); - } - } - - return new Resultant(rhoP, res); - } - - /** - * Multithreaded version of {@link #resultant()}. - * - * @return (rho, res) satisfying res = rho*this + t*(x^n-1) for some integer t. - */ - public Resultant resultantMultiThread() - { - int N = coeffs.length; - - // upper bound for resultant(f, g) = ||f, 2||^deg(g) * ||g, 2||^deg(f) = squaresum(f)^(N/2) * 2^(deg(f)/2) because g(x)=x^N-1 - // see https://jondalon.mathematik.uni-osnabrueck.de/staff/phpages/brunsw/CompAlg.pdf chapter 3 - BigInteger max = squareSum().pow((N + 1) / 2); - max = max.multiply(BigInteger.valueOf(2).pow((degree() + 1) / 2)); - BigInteger max2 = max.multiply(BigInteger.valueOf(2)); - - // compute resultants modulo prime numbers - BigInteger prime = BigInteger.valueOf(10000); - BigInteger pProd = Constants.BIGINT_ONE; - LinkedBlockingQueue> resultantTasks = new LinkedBlockingQueue>(); - Iterator primes = BIGINT_PRIMES.iterator(); - ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); - while (pProd.compareTo(max2) < 0) - { - if (primes.hasNext()) - { - prime = primes.next(); - } - else - { - prime = prime.nextProbablePrime(); - } - Future task = executor.submit(new ModResultantTask(prime.intValue())); - resultantTasks.add(task); - pProd = pProd.multiply(prime); - } - - // Combine modular resultants to obtain the resultant. - // For efficiency, first combine all pairs of small resultants to bigger resultants, - // then combine pairs of those, etc. until only one is left. - ModularResultant overallResultant = null; - while (!resultantTasks.isEmpty()) - { - try - { - Future modRes1 = resultantTasks.take(); - Future modRes2 = resultantTasks.poll(); - if (modRes2 == null) - { - // modRes1 is the only one left - overallResultant = modRes1.get(); - break; - } - Future newTask = executor.submit(new CombineTask(modRes1.get(), modRes2.get())); - resultantTasks.add(newTask); - } - catch (Exception e) - { - throw new IllegalStateException(e.toString()); - } - } - executor.shutdown(); - BigInteger res = overallResultant.res; - BigIntPolynomial rhoP = overallResultant.rho; - - BigInteger pProd2 = pProd.divide(BigInteger.valueOf(2)); - BigInteger pProd2n = pProd2.negate(); - - if (res.compareTo(pProd2) > 0) - { - res = res.subtract(pProd); - } - if (res.compareTo(pProd2n) < 0) - { - res = res.add(pProd); - } - - for (int i = 0; i < N; i++) - { - BigInteger c = rhoP.coeffs[i]; - if (c.compareTo(pProd2) > 0) - { - rhoP.coeffs[i] = c.subtract(pProd); - } - if (c.compareTo(pProd2n) < 0) - { - rhoP.coeffs[i] = c.add(pProd); - } - } - - return new Resultant(rhoP, res); - } - - /** - * Resultant of this polynomial with x^n-1 mod p. - * - * @return (rho, res) satisfying res = rho*this + t*(x^n-1) mod p for some integer t. - */ - public ModularResultant resultant(int p) - { - // Add a coefficient as the following operations involve polynomials of degree deg(f)+1 - int[] fcoeffs = Arrays.copyOf(coeffs, coeffs.length + 1); - IntegerPolynomial f = new IntegerPolynomial(fcoeffs); - int N = fcoeffs.length; - - IntegerPolynomial a = new IntegerPolynomial(N); - a.coeffs[0] = -1; - a.coeffs[N - 1] = 1; - IntegerPolynomial b = new IntegerPolynomial(f.coeffs); - IntegerPolynomial v1 = new IntegerPolynomial(N); - IntegerPolynomial v2 = new IntegerPolynomial(N); - v2.coeffs[0] = 1; - int da = N - 1; - int db = b.degree(); - int ta = da; - int c = 0; - int r = 1; - while (db > 0) - { - c = Util.invert(b.coeffs[db], p); - c = (c * a.coeffs[da]) % p; - a.multShiftSub(b, c, da - db, p); - v1.multShiftSub(v2, c, da - db, p); - - da = a.degree(); - if (da < db) - { - r *= Util.pow(b.coeffs[db], ta - da, p); - r %= p; - if (ta % 2 == 1 && db % 2 == 1) - { - r = (-r) % p; - } - IntegerPolynomial temp = a; - a = b; - b = temp; - int tempdeg = da; - da = db; - temp = v1; - v1 = v2; - v2 = temp; - ta = db; - db = tempdeg; - } - } - r *= Util.pow(b.coeffs[0], da, p); - r %= p; - c = Util.invert(b.coeffs[0], p); - v2.mult(c); - v2.mod(p); - v2.mult(r); - v2.mod(p); - - // drop the highest coefficient so #coeffs matches the original input - v2.coeffs = Arrays.copyOf(v2.coeffs, v2.coeffs.length - 1); - return new ModularResultant(new BigIntPolynomial(v2), BigInteger.valueOf(r), BigInteger.valueOf(p)); - } - - /** - * Computes this-b*c*(x^k) mod p and stores the result in this polynomial.
    - * See steps 4a,4b in EESS algorithm 2.2.7.1. - * - * @param b - * @param c - * @param k - * @param p - */ - private void multShiftSub(IntegerPolynomial b, int c, int k, int p) - { - int N = coeffs.length; - for (int i = k; i < N; i++) - { - coeffs[i] = (coeffs[i] - b.coeffs[i - k] * c) % p; - } - } - - /** - * Adds the squares of all coefficients. - * - * @return the sum of squares - */ - private BigInteger squareSum() - { - BigInteger sum = Constants.BIGINT_ZERO; - for (int i = 0; i < coeffs.length; i++) - { - sum = sum.add(BigInteger.valueOf(coeffs[i] * coeffs[i])); - } - return sum; - } - - /** - * Returns the degree of the polynomial - * - * @return the degree - */ - int degree() - { - int degree = coeffs.length - 1; - while (degree > 0 && coeffs[degree] == 0) - { - degree--; - } - return degree; - } - - /** - * Adds another polynomial which can have a different number of coefficients, - * and takes the coefficient values mod modulus. - * - * @param b another polynomial - */ - public void add(IntegerPolynomial b, int modulus) - { - add(b); - mod(modulus); - } - - /** - * Adds another polynomial which can have a different number of coefficients. - * - * @param b another polynomial - */ - public void add(IntegerPolynomial b) - { - if (b.coeffs.length > coeffs.length) - { - coeffs = Arrays.copyOf(coeffs, b.coeffs.length); - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] += b.coeffs[i]; - } - } - - /** - * Subtracts another polynomial which can have a different number of coefficients, - * and takes the coefficient values mod modulus. - * - * @param b another polynomial - */ - public void sub(IntegerPolynomial b, int modulus) - { - sub(b); - mod(modulus); - } - - /** - * Subtracts another polynomial which can have a different number of coefficients. - * - * @param b another polynomial - */ - public void sub(IntegerPolynomial b) - { - if (b.coeffs.length > coeffs.length) - { - coeffs = Arrays.copyOf(coeffs, b.coeffs.length); - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] -= b.coeffs[i]; - } - } - - /** - * Subtracts a int from each coefficient. Does not return a new polynomial but modifies this polynomial. - * - * @param b - */ - void sub(int b) - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] -= b; - } - } - - /** - * Multiplies each coefficient by a int. Does not return a new polynomial but modifies this polynomial. - * - * @param factor - */ - public void mult(int factor) - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] *= factor; - } - } - - /** - * Multiplies each coefficient by a 2 and applies a modulus. Does not return a new polynomial but modifies this polynomial. - * - * @param modulus a modulus - */ - private void mult2(int modulus) - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] *= 2; - coeffs[i] %= modulus; - } - } - - /** - * Multiplies each coefficient by a 2 and applies a modulus. Does not return a new polynomial but modifies this polynomial. - * - * @param modulus a modulus - */ - public void mult3(int modulus) - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] *= 3; - coeffs[i] %= modulus; - } - } - - /** - * Divides each coefficient by k and rounds to the nearest integer. Does not return a new polynomial but modifies this polynomial. - * - * @param k the divisor - */ - public void div(int k) - { - int k2 = (k + 1) / 2; - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] += coeffs[i] > 0 ? k2 : -k2; - coeffs[i] /= k; - } - } - - /** - * Takes each coefficient modulo 3 such that all coefficients are ternary. - */ - public void mod3() - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] %= 3; - if (coeffs[i] > 1) - { - coeffs[i] -= 3; - } - if (coeffs[i] < -1) - { - coeffs[i] += 3; - } - } - } - - /** - * Ensures all coefficients are between 0 and modulus-1 - * - * @param modulus a modulus - */ - public void modPositive(int modulus) - { - mod(modulus); - ensurePositive(modulus); - } - - /** - * Reduces all coefficients to the interval [-modulus/2, modulus/2) - */ - void modCenter(int modulus) - { - mod(modulus); - for (int j = 0; j < coeffs.length; j++) - { - while (coeffs[j] < modulus / 2) - { - coeffs[j] += modulus; - } - while (coeffs[j] >= modulus / 2) - { - coeffs[j] -= modulus; - } - } - } - - /** - * Takes each coefficient modulo modulus. - */ - public void mod(int modulus) - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] %= modulus; - } - } - - /** - * Adds modulus until all coefficients are above 0. - * - * @param modulus a modulus - */ - public void ensurePositive(int modulus) - { - for (int i = 0; i < coeffs.length; i++) - { - while (coeffs[i] < 0) - { - coeffs[i] += modulus; - } - } - } - - /** - * Computes the centered euclidean norm of the polynomial. - * - * @param q a modulus - * @return the centered norm - */ - public long centeredNormSq(int q) - { - int N = coeffs.length; - IntegerPolynomial p = (IntegerPolynomial)clone(); - p.shiftGap(q); - - long sum = 0; - long sqSum = 0; - for (int i = 0; i != p.coeffs.length; i++) - { - int c = p.coeffs[i]; - sum += c; - sqSum += c * c; - } - - long centeredNormSq = sqSum - sum * sum / N; - return centeredNormSq; - } - - /** - * Shifts all coefficients so the largest gap is centered around -q/2. - * - * @param q a modulus - */ - void shiftGap(int q) - { - modCenter(q); - - int[] sorted = Arrays.clone(coeffs); - - sort(sorted); - - int maxrange = 0; - int maxrangeStart = 0; - for (int i = 0; i < sorted.length - 1; i++) - { - int range = sorted[i + 1] - sorted[i]; - if (range > maxrange) - { - maxrange = range; - maxrangeStart = sorted[i]; - } - } - - int pmin = sorted[0]; - int pmax = sorted[sorted.length - 1]; - - int j = q - pmax + pmin; - int shift; - if (j > maxrange) - { - shift = (pmax + pmin) / 2; - } - else - { - shift = maxrangeStart + maxrange / 2 + q / 2; - } - - sub(shift); - } - - private void sort(int[] ints) - { - boolean swap = true; - - while (swap) - { - swap = false; - for (int i = 0; i != ints.length - 1; i++) - { - if (ints[i] > ints[i+1]) - { - int tmp = ints[i]; - ints[i] = ints[i+1]; - ints[i+1] = tmp; - swap = true; - } - } - } - } - - /** - * Shifts the values of all coefficients to the interval [-q/2, q/2]. - * - * @param q a modulus - */ - public void center0(int q) - { - for (int i = 0; i < coeffs.length; i++) - { - while (coeffs[i] < -q / 2) - { - coeffs[i] += q; - } - while (coeffs[i] > q / 2) - { - coeffs[i] -= q; - } - } - } - - /** - * Returns the sum of all coefficients, i.e. evaluates the polynomial at 0. - * - * @return the sum of all coefficients - */ - public int sumCoeffs() - { - int sum = 0; - for (int i = 0; i < coeffs.length; i++) - { - sum += coeffs[i]; - } - return sum; - } - - /** - * Tests if p(x) = 0. - * - * @return true iff all coefficients are zeros - */ - private boolean equalsZero() - { - for (int i = 0; i < coeffs.length; i++) - { - if (coeffs[i] != 0) - { - return false; - } - } - return true; - } - - /** - * Tests if p(x) = 1. - * - * @return true iff all coefficients are equal to zero, except for the lowest coefficient which must equal 1 - */ - public boolean equalsOne() - { - for (int i = 1; i < coeffs.length; i++) - { - if (coeffs[i] != 0) - { - return false; - } - } - return coeffs[0] == 1; - } - - /** - * Tests if |p(x)| = 1. - * - * @return true iff all coefficients are equal to zero, except for the lowest coefficient which must equal 1 or -1 - */ - private boolean equalsAbsOne() - { - for (int i = 1; i < coeffs.length; i++) - { - if (coeffs[i] != 0) - { - return false; - } - } - return Math.abs(coeffs[0]) == 1; - } - - /** - * Counts the number of coefficients equal to an integer - * - * @param value an integer - * @return the number of coefficients equal to value - */ - public int count(int value) - { - int count = 0; - for (int i = 0; i != coeffs.length; i++) - { - if (coeffs[i] == value) - { - count++; - } - } - return count; - } - - /** - * Multiplication by X in Z[X]/Z[X^n-1]. - */ - public void rotate1() - { - int clast = coeffs[coeffs.length - 1]; - for (int i = coeffs.length - 1; i > 0; i--) - { - coeffs[i] = coeffs[i - 1]; - } - coeffs[0] = clast; - } - - public void clear() - { - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] = 0; - } - } - - public IntegerPolynomial toIntegerPolynomial() - { - return (IntegerPolynomial)clone(); - } - - public Object clone() - { - return new IntegerPolynomial(coeffs.clone()); - } - - public boolean equals(Object obj) - { - if (obj instanceof IntegerPolynomial) - { - return Arrays.areEqual(coeffs, ((IntegerPolynomial)obj).coeffs); - } - else - { - return false; - } - } - - /** - * Calls {@link IntegerPolynomial#resultant(int) - */ - private class ModResultantTask - implements Callable - { - private int modulus; - - private ModResultantTask(int modulus) - { - this.modulus = modulus; - } - - public ModularResultant call() - { - return resultant(modulus); - } - } - - /** - * Calls {@link ModularResultant#combineRho(ModularResultant, ModularResultant) - */ - private static class CombineTask - implements Callable - { - private ModularResultant modRes1; - private ModularResultant modRes2; - - private CombineTask(ModularResultant modRes1, ModularResultant modRes2) - { - this.modRes1 = modRes1; - this.modRes2 = modRes2; - } - - public ModularResultant call() - { - return ModularResultant.combineRho(modRes1, modRes2); - } - } - - private static class PrimeGenerator - { - private int index = 0; - private BigInteger prime; - - public BigInteger nextPrime() - { - if (index < BIGINT_PRIMES.size()) - { - prime = (BigInteger)BIGINT_PRIMES.get(index++); - } - else - { - prime = prime.nextProbablePrime(); - } - - return prime; - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/LongPolynomial2.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/LongPolynomial2.java deleted file mode 100644 index aadc4b8ace..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/LongPolynomial2.java +++ /dev/null @@ -1,255 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial; - -import org.bouncycastle.util.Arrays; - -/** - * A polynomial class that combines two coefficients into one long value for - * faster multiplication in 64 bit environments.
    - * Coefficients can be between 0 and 2047 and are stored in pairs in the bits 0..10 and 24..34 of a long number. - */ -public class LongPolynomial2 -{ - private long[] coeffs; // each representing two coefficients in the original IntegerPolynomial - private int numCoeffs; - - /** - * Constructs a LongPolynomial2 from a IntegerPolynomial. The two polynomials are independent of each other. - * - * @param p the original polynomial. Coefficients must be between 0 and 2047. - */ - public LongPolynomial2(IntegerPolynomial p) - { - numCoeffs = p.coeffs.length; - coeffs = new long[(numCoeffs + 1) / 2]; - int idx = 0; - for (int pIdx = 0; pIdx < numCoeffs; ) - { - int c0 = p.coeffs[pIdx++]; - while (c0 < 0) - { - c0 += 2048; - } - long c1 = pIdx < numCoeffs ? p.coeffs[pIdx++] : 0; - while (c1 < 0) - { - c1 += 2048; - } - coeffs[idx] = c0 + (c1 << 24); - idx++; - } - } - - private LongPolynomial2(long[] coeffs) - { - this.coeffs = coeffs; - } - - private LongPolynomial2(int N) - { - coeffs = new long[N]; - } - - /** - * Multiplies the polynomial with another, taking the indices mod N and the values mod 2048. - */ - public LongPolynomial2 mult(LongPolynomial2 poly2) - { - int N = coeffs.length; - if (poly2.coeffs.length != N || numCoeffs != poly2.numCoeffs) - { - throw new IllegalArgumentException("Number of coefficients must be the same"); - } - - LongPolynomial2 c = multRecursive(poly2); - - if (c.coeffs.length > N) - { - if (numCoeffs % 2 == 0) - { - for (int k = N; k < c.coeffs.length; k++) - { - c.coeffs[k - N] = (c.coeffs[k - N] + c.coeffs[k]) & 0x7FF0007FFL; - } - c.coeffs = Arrays.copyOf(c.coeffs, N); - } - else - { - for (int k = N; k < c.coeffs.length; k++) - { - c.coeffs[k - N] = c.coeffs[k - N] + (c.coeffs[k - 1] >> 24); - c.coeffs[k - N] = c.coeffs[k - N] + ((c.coeffs[k] & 2047) << 24); - c.coeffs[k - N] &= 0x7FF0007FFL; - } - c.coeffs = Arrays.copyOf(c.coeffs, N); - c.coeffs[c.coeffs.length - 1] &= 2047; - } - } - - c = new LongPolynomial2(c.coeffs); - c.numCoeffs = numCoeffs; - return c; - } - - public IntegerPolynomial toIntegerPolynomial() - { - int[] intCoeffs = new int[numCoeffs]; - int uIdx = 0; - for (int i = 0; i < coeffs.length; i++) - { - intCoeffs[uIdx++] = (int)(coeffs[i] & 2047); - if (uIdx < numCoeffs) - { - intCoeffs[uIdx++] = (int)((coeffs[i] >> 24) & 2047); - } - } - return new IntegerPolynomial(intCoeffs); - } - - /** - * Karazuba multiplication - */ - private LongPolynomial2 multRecursive(LongPolynomial2 poly2) - { - long[] a = coeffs; - long[] b = poly2.coeffs; - - int n = poly2.coeffs.length; - if (n <= 32) - { - int cn = 2 * n; - LongPolynomial2 c = new LongPolynomial2(new long[cn]); - for (int k = 0; k < cn; k++) - { - for (int i = Math.max(0, k - n + 1); i <= Math.min(k, n - 1); i++) - { - long c0 = a[k - i] * b[i]; - long cu = c0 & 0x7FF000000L + (c0 & 2047); - long co = (c0 >>> 48) & 2047; - - c.coeffs[k] = (c.coeffs[k] + cu) & 0x7FF0007FFL; - c.coeffs[k + 1] = (c.coeffs[k + 1] + co) & 0x7FF0007FFL; - } - } - return c; - } - else - { - int n1 = n / 2; - - LongPolynomial2 a1 = new LongPolynomial2(Arrays.copyOf(a, n1)); - LongPolynomial2 a2 = new LongPolynomial2(Arrays.copyOfRange(a, n1, n)); - LongPolynomial2 b1 = new LongPolynomial2(Arrays.copyOf(b, n1)); - LongPolynomial2 b2 = new LongPolynomial2(Arrays.copyOfRange(b, n1, n)); - - LongPolynomial2 A = (LongPolynomial2)a1.clone(); - A.add(a2); - LongPolynomial2 B = (LongPolynomial2)b1.clone(); - B.add(b2); - - LongPolynomial2 c1 = a1.multRecursive(b1); - LongPolynomial2 c2 = a2.multRecursive(b2); - LongPolynomial2 c3 = A.multRecursive(B); - c3.sub(c1); - c3.sub(c2); - - LongPolynomial2 c = new LongPolynomial2(2 * n); - for (int i = 0; i < c1.coeffs.length; i++) - { - c.coeffs[i] = c1.coeffs[i] & 0x7FF0007FFL; - } - for (int i = 0; i < c3.coeffs.length; i++) - { - c.coeffs[n1 + i] = (c.coeffs[n1 + i] + c3.coeffs[i]) & 0x7FF0007FFL; - } - for (int i = 0; i < c2.coeffs.length; i++) - { - c.coeffs[2 * n1 + i] = (c.coeffs[2 * n1 + i] + c2.coeffs[i]) & 0x7FF0007FFL; - } - return c; - } - } - - /** - * Adds another polynomial which can have a different number of coefficients. - * - * @param b another polynomial - */ - private void add(LongPolynomial2 b) - { - if (b.coeffs.length > coeffs.length) - { - coeffs = Arrays.copyOf(coeffs, b.coeffs.length); - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] = (coeffs[i] + b.coeffs[i]) & 0x7FF0007FFL; - } - } - - /** - * Subtracts another polynomial which can have a different number of coefficients. - * - * @param b another polynomial - */ - private void sub(LongPolynomial2 b) - { - if (b.coeffs.length > coeffs.length) - { - coeffs = Arrays.copyOf(coeffs, b.coeffs.length); - } - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] = (0x0800000800000L + coeffs[i] - b.coeffs[i]) & 0x7FF0007FFL; - } - } - - /** - * Subtracts another polynomial which must have the same number of coefficients, - * and applies an AND mask to the upper and lower halves of each coefficients. - * - * @param b another polynomial - * @param mask a bit mask less than 2048 to apply to each 11-bit coefficient - */ - public void subAnd(LongPolynomial2 b, int mask) - { - long longMask = (((long)mask) << 24) + mask; - for (int i = 0; i < b.coeffs.length; i++) - { - coeffs[i] = (0x0800000800000L + coeffs[i] - b.coeffs[i]) & longMask; - } - } - - /** - * Multiplies this polynomial by 2 and applies an AND mask to the upper and - * lower halves of each coefficients. - * - * @param mask a bit mask less than 2048 to apply to each 11-bit coefficient - */ - public void mult2And(int mask) - { - long longMask = (((long)mask) << 24) + mask; - for (int i = 0; i < coeffs.length; i++) - { - coeffs[i] = (coeffs[i] << 1) & longMask; - } - } - - public Object clone() - { - LongPolynomial2 p = new LongPolynomial2(coeffs.clone()); - p.numCoeffs = numCoeffs; - return p; - } - - public boolean equals(Object obj) - { - if (obj instanceof LongPolynomial2) - { - return Arrays.areEqual(coeffs, ((LongPolynomial2)obj).coeffs); - } - else - { - return false; - } - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/LongPolynomial5.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/LongPolynomial5.java deleted file mode 100644 index c5ef7961f3..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/LongPolynomial5.java +++ /dev/null @@ -1,149 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial; - -import org.bouncycastle.util.Arrays; - -/** - * A polynomial class that combines five coefficients into one long value for - * faster multiplication by a ternary polynomial.
    - * Coefficients can be between 0 and 2047 and are stored in bits 0..11, 12..23, ..., 48..59 of a long number. - */ -public class LongPolynomial5 -{ - private long[] coeffs; // groups of 5 coefficients - private int numCoeffs; - - /** - * Constructs a LongPolynomial5 from a IntegerPolynomial. The two polynomials are independent of each other. - * - * @param p the original polynomial. Coefficients must be between 0 and 2047. - */ - public LongPolynomial5(IntegerPolynomial p) - { - numCoeffs = p.coeffs.length; - - coeffs = new long[(numCoeffs + 4) / 5]; - int cIdx = 0; - int shift = 0; - for (int i = 0; i < numCoeffs; i++) - { - coeffs[cIdx] |= ((long)p.coeffs[i]) << shift; - shift += 12; - if (shift >= 60) - { - shift = 0; - cIdx++; - } - } - } - - private LongPolynomial5(long[] coeffs, int numCoeffs) - { - this.coeffs = coeffs; - this.numCoeffs = numCoeffs; - } - - /** - * Multiplies the polynomial with a TernaryPolynomial, taking the indices mod N and the values mod 2048. - */ - public LongPolynomial5 mult(TernaryPolynomial poly2) - { - long[][] prod = new long[5][coeffs.length + (poly2.size() + 4) / 5 - 1]; // intermediate results, the subarrays are shifted by 0,...,4 coefficients - - // multiply ones - int[] ones = poly2.getOnes(); - for (int idx = 0; idx != ones.length; idx++) - { - int pIdx = ones[idx]; - int cIdx = pIdx / 5; - int m = pIdx - cIdx * 5; // m = pIdx % 5 - for (int i = 0; i < coeffs.length; i++) - { - prod[m][cIdx] = (prod[m][cIdx] + coeffs[i]) & 0x7FF7FF7FF7FF7FFL; - cIdx++; - } - } - - // multiply negative ones - int[] negOnes = poly2.getNegOnes(); - for (int idx = 0; idx != negOnes.length; idx++) - { - int pIdx = negOnes[idx]; - int cIdx = pIdx / 5; - int m = pIdx - cIdx * 5; // m = pIdx % 5 - for (int i = 0; i < coeffs.length; i++) - { - prod[m][cIdx] = (0x800800800800800L + prod[m][cIdx] - coeffs[i]) & 0x7FF7FF7FF7FF7FFL; - cIdx++; - } - } - - // combine shifted coefficients (5 arrays) into a single array of length prod[*].length+1 - long[] cCoeffs = Arrays.copyOf(prod[0], prod[0].length + 1); - for (int m = 1; m <= 4; m++) - { - int shift = m * 12; - int shift60 = 60 - shift; - long mask = (1L << shift60) - 1; - int pLen = prod[m].length; - for (int i = 0; i < pLen; i++) - { - long upper, lower; - upper = prod[m][i] >> shift60; - lower = prod[m][i] & mask; - - cCoeffs[i] = (cCoeffs[i] + (lower << shift)) & 0x7FF7FF7FF7FF7FFL; - int nextIdx = i + 1; - cCoeffs[nextIdx] = (cCoeffs[nextIdx] + upper) & 0x7FF7FF7FF7FF7FFL; - } - } - - // reduce indices of cCoeffs modulo numCoeffs - int shift = 12 * (numCoeffs % 5); - for (int cIdx = coeffs.length - 1; cIdx < cCoeffs.length; cIdx++) - { - long iCoeff; // coefficient to shift into the [0..numCoeffs-1] range - int newIdx; - if (cIdx == coeffs.length - 1) - { - iCoeff = numCoeffs == 5 ? 0 : cCoeffs[cIdx] >> shift; - newIdx = 0; - } - else - { - iCoeff = cCoeffs[cIdx]; - newIdx = cIdx * 5 - numCoeffs; - } - - int base = newIdx / 5; - int m = newIdx - base * 5; // m = newIdx % 5 - long lower = iCoeff << (12 * m); - long upper = iCoeff >> (12 * (5 - m)); - cCoeffs[base] = (cCoeffs[base] + lower) & 0x7FF7FF7FF7FF7FFL; - int base1 = base + 1; - if (base1 < coeffs.length) - { - cCoeffs[base1] = (cCoeffs[base1] + upper) & 0x7FF7FF7FF7FF7FFL; - } - } - - return new LongPolynomial5(cCoeffs, numCoeffs); - } - - public IntegerPolynomial toIntegerPolynomial() - { - int[] intCoeffs = new int[numCoeffs]; - int cIdx = 0; - int shift = 0; - for (int i = 0; i < numCoeffs; i++) - { - intCoeffs[i] = (int)((coeffs[cIdx] >> shift) & 2047); - shift += 12; - if (shift >= 60) - { - shift = 0; - cIdx++; - } - } - return new IntegerPolynomial(intCoeffs); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/ModularResultant.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/ModularResultant.java deleted file mode 100644 index 5f9d6c50d9..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/ModularResultant.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial; - -import java.math.BigInteger; - -import org.bouncycastle.pqc.legacy.math.ntru.euclid.BigIntEuclidean; - -/** - * A resultant modulo a BigInteger - */ -public class ModularResultant - extends Resultant -{ - BigInteger modulus; - - ModularResultant(BigIntPolynomial rho, BigInteger res, BigInteger modulus) - { - super(rho, res); - this.modulus = modulus; - } - - /** - * Calculates a rho modulo m1*m2 from - * two resultants whose rhos are modulo m1 and m2.
    - * res is set to null. - * - * @param modRes1 - * @param modRes2 - * @return rho modulo modRes1.modulus * modRes2.modulus, and null for res. - */ - static ModularResultant combineRho(ModularResultant modRes1, ModularResultant modRes2) - { - BigInteger mod1 = modRes1.modulus; - BigInteger mod2 = modRes2.modulus; - BigInteger prod = mod1.multiply(mod2); - BigIntEuclidean er = BigIntEuclidean.calculate(mod2, mod1); - - BigIntPolynomial rho1 = (BigIntPolynomial)modRes1.rho.clone(); - rho1.mult(er.x.multiply(mod2)); - BigIntPolynomial rho2 = (BigIntPolynomial)modRes2.rho.clone(); - rho2.mult(er.y.multiply(mod1)); - rho1.add(rho2); - rho1.mod(prod); - - return new ModularResultant(rho1, null, prod); - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/Polynomial.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/Polynomial.java deleted file mode 100644 index 9c5a3f36fa..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/Polynomial.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial; - -public interface Polynomial -{ - - /** - * Multiplies the polynomial by an IntegerPolynomial, - * taking the indices mod N. - * - * @param poly2 a polynomial - * @return the product of the two polynomials - */ - IntegerPolynomial mult(IntegerPolynomial poly2); - - /** - * Multiplies the polynomial by an IntegerPolynomial, - * taking the coefficient values mod modulus and the indices mod N. - * - * @param poly2 a polynomial - * @param modulus a modulus to apply - * @return the product of the two polynomials - */ - IntegerPolynomial mult(IntegerPolynomial poly2, int modulus); - - /** - * Returns a polynomial that is equal to this polynomial (in the sense that {@link #mult(IntegerPolynomial, int)} - * returns equal IntegerPolynomials). The new polynomial is guaranteed to be independent of the original. - * - * @return a new IntegerPolynomial. - */ - IntegerPolynomial toIntegerPolynomial(); - - /** - * Multiplies the polynomial by a BigIntPolynomial, taking the indices mod N. Does not - * change this polynomial but returns the result as a new polynomial.
    - * Both polynomials must have the same number of coefficients. - * - * @param poly2 the polynomial to multiply by - * @return a new polynomial - */ - BigIntPolynomial mult(BigIntPolynomial poly2); -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/ProductFormPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/ProductFormPolynomial.java deleted file mode 100644 index 4c9979c50d..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/ProductFormPolynomial.java +++ /dev/null @@ -1,153 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.SecureRandom; - -import org.bouncycastle.util.Arrays; - -/** - * A polynomial of the form f1*f2+f3, where - * f1,f2,f3 are very sparsely populated ternary polynomials. - */ -public class ProductFormPolynomial - implements Polynomial -{ - private SparseTernaryPolynomial f1, f2, f3; - - public ProductFormPolynomial(SparseTernaryPolynomial f1, SparseTernaryPolynomial f2, SparseTernaryPolynomial f3) - { - this.f1 = f1; - this.f2 = f2; - this.f3 = f3; - } - - public static ProductFormPolynomial generateRandom(int N, int df1, int df2, int df3Ones, int df3NegOnes, SecureRandom random) - { - SparseTernaryPolynomial f1 = SparseTernaryPolynomial.generateRandom(N, df1, df1, random); - SparseTernaryPolynomial f2 = SparseTernaryPolynomial.generateRandom(N, df2, df2, random); - SparseTernaryPolynomial f3 = SparseTernaryPolynomial.generateRandom(N, df3Ones, df3NegOnes, random); - return new ProductFormPolynomial(f1, f2, f3); - } - - public static ProductFormPolynomial fromBinary(byte[] data, int N, int df1, int df2, int df3Ones, int df3NegOnes) - throws IOException - { - return fromBinary(new ByteArrayInputStream(data), N, df1, df2, df3Ones, df3NegOnes); - } - - public static ProductFormPolynomial fromBinary(InputStream is, int N, int df1, int df2, int df3Ones, int df3NegOnes) - throws IOException - { - SparseTernaryPolynomial f1; - - f1 = SparseTernaryPolynomial.fromBinary(is, N, df1, df1); - SparseTernaryPolynomial f2 = SparseTernaryPolynomial.fromBinary(is, N, df2, df2); - SparseTernaryPolynomial f3 = SparseTernaryPolynomial.fromBinary(is, N, df3Ones, df3NegOnes); - return new ProductFormPolynomial(f1, f2, f3); - } - - public byte[] toBinary() - { - byte[] f1Bin = f1.toBinary(); - byte[] f2Bin = f2.toBinary(); - byte[] f3Bin = f3.toBinary(); - - byte[] all = Arrays.copyOf(f1Bin, f1Bin.length + f2Bin.length + f3Bin.length); - System.arraycopy(f2Bin, 0, all, f1Bin.length, f2Bin.length); - System.arraycopy(f3Bin, 0, all, f1Bin.length + f2Bin.length, f3Bin.length); - return all; - } - - public IntegerPolynomial mult(IntegerPolynomial b) - { - IntegerPolynomial c = f1.mult(b); - c = f2.mult(c); - c.add(f3.mult(b)); - return c; - } - - public BigIntPolynomial mult(BigIntPolynomial b) - { - BigIntPolynomial c = f1.mult(b); - c = f2.mult(c); - c.add(f3.mult(b)); - return c; - } - - public IntegerPolynomial toIntegerPolynomial() - { - IntegerPolynomial i = f1.mult(f2.toIntegerPolynomial()); - i.add(f3.toIntegerPolynomial()); - return i; - } - - public IntegerPolynomial mult(IntegerPolynomial poly2, int modulus) - { - IntegerPolynomial c = mult(poly2); - c.mod(modulus); - return c; - } - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + ((f1 == null) ? 0 : f1.hashCode()); - result = prime * result + ((f2 == null) ? 0 : f2.hashCode()); - result = prime * result + ((f3 == null) ? 0 : f3.hashCode()); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - ProductFormPolynomial other = (ProductFormPolynomial)obj; - if (f1 == null) - { - if (other.f1 != null) - { - return false; - } - } - else if (!f1.equals(other.f1)) - { - return false; - } - if (f2 == null) - { - if (other.f2 != null) - { - return false; - } - } - else if (!f2.equals(other.f2)) - { - return false; - } - if (f3 == null) - { - if (other.f3 != null) - { - return false; - } - } - else if (!f3.equals(other.f3)) - { - return false; - } - return true; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/Resultant.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/Resultant.java deleted file mode 100644 index e4e17636d4..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/Resultant.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial; - -import java.math.BigInteger; - -/** - * Contains a resultant and a polynomial rho such that - * res = rho*this + t*(x^n-1) for some integer t. - * - * @see IntegerPolynomial#resultant() - * @see IntegerPolynomial#resultant(int) - */ -public class Resultant -{ - /** - * A polynomial such that res = rho*this + t*(x^n-1) for some integer t - */ - public BigIntPolynomial rho; - /** - * Resultant of a polynomial with x^n-1 - */ - public BigInteger res; - - Resultant(BigIntPolynomial rho, BigInteger res) - { - this.rho = rho; - this.res = res; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/SparseTernaryPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/SparseTernaryPolynomial.java deleted file mode 100644 index d3c0347873..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/SparseTernaryPolynomial.java +++ /dev/null @@ -1,320 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial; - -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; -import java.security.SecureRandom; - -import org.bouncycastle.pqc.legacy.math.ntru.util.ArrayEncoder; -import org.bouncycastle.pqc.legacy.math.ntru.util.Util; -import org.bouncycastle.util.Arrays; - -/** - * A TernaryPolynomial with a "low" number of nonzero coefficients. - */ -public class SparseTernaryPolynomial - implements TernaryPolynomial -{ - /** - * Number of bits to use for each coefficient. Determines the upper bound for N. - */ - private static final int BITS_PER_INDEX = 11; - - private int N; - private int[] ones; - private int[] negOnes; - - /** - * Constructs a new polynomial. - * - * @param N total number of coefficients including zeros - * @param ones indices of coefficients equal to 1 - * @param negOnes indices of coefficients equal to -1 - */ - SparseTernaryPolynomial(int N, int[] ones, int[] negOnes) - { - this.N = N; - this.ones = ones; - this.negOnes = negOnes; - } - - /** - * Constructs a DenseTernaryPolynomial from a IntegerPolynomial. The two polynomials are - * independent of each other. - * - * @param intPoly the original polynomial - */ - public SparseTernaryPolynomial(IntegerPolynomial intPoly) - { - this(intPoly.coeffs); - } - - /** - * Constructs a new SparseTernaryPolynomial with a given set of coefficients. - * - * @param coeffs the coefficients - */ - public SparseTernaryPolynomial(int[] coeffs) - { - N = coeffs.length; - ones = new int[N]; - negOnes = new int[N]; - int onesIdx = 0; - int negOnesIdx = 0; - for (int i = 0; i < N; i++) - { - int c = coeffs[i]; - switch (c) - { - case 1: - ones[onesIdx++] = i; - break; - case -1: - negOnes[negOnesIdx++] = i; - break; - case 0: - break; - default: - throw new IllegalArgumentException("Illegal value: " + c + ", must be one of {-1, 0, 1}"); - } - } - ones = Arrays.copyOf(ones, onesIdx); - negOnes = Arrays.copyOf(negOnes, negOnesIdx); - } - - /** - * Decodes a byte array encoded with {@link #toBinary()} to a ploynomial. - * - * @param is an input stream containing an encoded polynomial - * @param N number of coefficients including zeros - * @param numOnes number of coefficients equal to 1 - * @param numNegOnes number of coefficients equal to -1 - * @return the decoded polynomial - * @throws IOException - */ - public static SparseTernaryPolynomial fromBinary(InputStream is, int N, int numOnes, int numNegOnes) - throws IOException - { - int maxIndex = 1 << BITS_PER_INDEX; - int bitsPerIndex = 32 - Integer.numberOfLeadingZeros(maxIndex - 1); - - int data1Len = (numOnes * bitsPerIndex + 7) / 8; - byte[] data1 = Util.readFullLength(is, data1Len); - int[] ones = ArrayEncoder.decodeModQ(data1, numOnes, maxIndex); - - int data2Len = (numNegOnes * bitsPerIndex + 7) / 8; - byte[] data2 = Util.readFullLength(is, data2Len); - int[] negOnes = ArrayEncoder.decodeModQ(data2, numNegOnes, maxIndex); - - return new SparseTernaryPolynomial(N, ones, negOnes); - } - - /** - * Generates a random polynomial with numOnes coefficients equal to 1, - * numNegOnes coefficients equal to -1, and the rest equal to 0. - * - * @param N number of coefficients - * @param numOnes number of 1's - * @param numNegOnes number of -1's - */ - public static SparseTernaryPolynomial generateRandom(int N, int numOnes, int numNegOnes, SecureRandom random) - { - int[] coeffs = Util.generateRandomTernary(N, numOnes, numNegOnes, random); - return new SparseTernaryPolynomial(coeffs); - } - - public IntegerPolynomial mult(IntegerPolynomial poly2) - { - int[] b = poly2.coeffs; - if (b.length != N) - { - throw new IllegalArgumentException("Number of coefficients must be the same"); - } - - int[] c = new int[N]; - for (int idx = 0; idx != ones.length; idx++) - { - int i = ones[idx]; - int j = N - 1 - i; - for (int k = N - 1; k >= 0; k--) - { - c[k] += b[j]; - j--; - if (j < 0) - { - j = N - 1; - } - } - } - - for (int idx = 0; idx != negOnes.length; idx++) - { - int i = negOnes[idx]; - int j = N - 1 - i; - for (int k = N - 1; k >= 0; k--) - { - c[k] -= b[j]; - j--; - if (j < 0) - { - j = N - 1; - } - } - } - - return new IntegerPolynomial(c); - } - - public IntegerPolynomial mult(IntegerPolynomial poly2, int modulus) - { - IntegerPolynomial c = mult(poly2); - c.mod(modulus); - return c; - } - - public BigIntPolynomial mult(BigIntPolynomial poly2) - { - BigInteger[] b = poly2.coeffs; - if (b.length != N) - { - throw new IllegalArgumentException("Number of coefficients must be the same"); - } - - BigInteger[] c = new BigInteger[N]; - for (int i = 0; i < N; i++) - { - c[i] = BigInteger.ZERO; - } - - for (int idx = 0; idx != ones.length; idx++) - { - int i = ones[idx]; - int j = N - 1 - i; - for (int k = N - 1; k >= 0; k--) - { - c[k] = c[k].add(b[j]); - j--; - if (j < 0) - { - j = N - 1; - } - } - } - - for (int idx = 0; idx != negOnes.length; idx++) - { - int i = negOnes[idx]; - int j = N - 1 - i; - for (int k = N - 1; k >= 0; k--) - { - c[k] = c[k].subtract(b[j]); - j--; - if (j < 0) - { - j = N - 1; - } - } - } - - return new BigIntPolynomial(c); - } - - public int[] getOnes() - { - return ones; - } - - public int[] getNegOnes() - { - return negOnes; - } - - /** - * Encodes the polynomial to a byte array writing BITS_PER_INDEX bits for each coefficient. - * - * @return the encoded polynomial - */ - public byte[] toBinary() - { - int maxIndex = 1 << BITS_PER_INDEX; - byte[] bin1 = ArrayEncoder.encodeModQ(ones, maxIndex); - byte[] bin2 = ArrayEncoder.encodeModQ(negOnes, maxIndex); - - byte[] bin = Arrays.copyOf(bin1, bin1.length + bin2.length); - System.arraycopy(bin2, 0, bin, bin1.length, bin2.length); - return bin; - } - - public IntegerPolynomial toIntegerPolynomial() - { - int[] coeffs = new int[N]; - for (int idx = 0; idx != ones.length; idx++) - { - int i = ones[idx]; - coeffs[i] = 1; - } - for (int idx = 0; idx != negOnes.length; idx++) - { - int i = negOnes[idx]; - coeffs[i] = -1; - } - return new IntegerPolynomial(coeffs); - } - - public int size() - { - return N; - } - - public void clear() - { - for (int i = 0; i < ones.length; i++) - { - ones[i] = 0; - } - for (int i = 0; i < negOnes.length; i++) - { - negOnes[i] = 0; - } - } - - public int hashCode() - { - final int prime = 31; - int result = 1; - result = prime * result + N; - result = prime * result + Arrays.hashCode(negOnes); - result = prime * result + Arrays.hashCode(ones); - return result; - } - - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - SparseTernaryPolynomial other = (SparseTernaryPolynomial)obj; - if (N != other.N) - { - return false; - } - if (!Arrays.areEqual(negOnes, other.negOnes)) - { - return false; - } - if (!Arrays.areEqual(ones, other.ones)) - { - return false; - } - return true; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/TernaryPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/TernaryPolynomial.java deleted file mode 100644 index 6bb6105f51..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/TernaryPolynomial.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial; - -/** - * A polynomial whose coefficients are all equal to -1, 0, or 1 - */ -public interface TernaryPolynomial - extends Polynomial -{ - - /** - * Multiplies the polynomial by an IntegerPolynomial, taking the indices mod N - */ - IntegerPolynomial mult(IntegerPolynomial poly2); - - int[] getOnes(); - - int[] getNegOnes(); - - /** - * Returns the maximum number of coefficients the polynomial can have - */ - int size(); - - void clear(); -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/util/ArrayEncoder.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/util/ArrayEncoder.java deleted file mode 100644 index e0fc589be3..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/util/ArrayEncoder.java +++ /dev/null @@ -1,294 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.util; - -import java.io.IOException; -import java.io.InputStream; -import java.math.BigInteger; - -import org.bouncycastle.util.Arrays; - -/** - * Converts a coefficient array to a compact byte array and vice versa. - */ -public class ArrayEncoder -{ - /** - * Bit string to coefficient conversion table from P1363.1. Also found at - * {@link https://stackoverflow.com/questions/1562548/how-to-make-a-message-into-a-polynomial} - *

    - * Convert each three-bit quantity to two ternary coefficients as follows, and concatenate the resulting - * ternary quantities to obtain [the output]. - *

    - * - * {0, 0, 0} -> {0, 0}
    - * {0, 0, 1} -> {0, 1}
    - * {0, 1, 0} -> {0, -1}
    - * {0, 1, 1} -> {1, 0}
    - * {1, 0, 0} -> {1, 1}
    - * {1, 0, 1} -> {1, -1}
    - * {1, 1, 0} -> {-1, 0}
    - * {1, 1, 1} -> {-1, 1}
    - *
    - *

    - */ - private static final int[] COEFF1_TABLE = {0, 0, 0, 1, 1, 1, -1, -1}; - private static final int[] COEFF2_TABLE = {0, 1, -1, 0, 1, -1, 0, 1}; - /** - * Coefficient to bit string conversion table from P1363.1. Also found at - * {@link https://stackoverflow.com/questions/1562548/how-to-make-a-message-into-a-polynomial} - *

    - * Convert each set of two ternary coefficients to three bits as follows, and concatenate the resulting bit - * quantities to obtain [the output]: - *

    - * - * {-1, -1} -> set "fail" to 1 and set bit string to {1, 1, 1} - * {-1, 0} -> {1, 1, 0}
    - * {-1, 1} -> {1, 1, 1}
    - * {0, -1} -> {0, 1, 0}
    - * {0, 0} -> {0, 0, 0}
    - * {0, 1} -> {0, 0, 1}
    - * {1, -1} -> {1, 0, 1}
    - * {1, 0} -> {0, 1, 1}
    - * {1, 1} -> {1, 0, 0}
    - *
    \ - *

    - */ - private static final int[] BIT1_TABLE = {1, 1, 1, 0, 0, 0, 1, 0, 1}; - private static final int[] BIT2_TABLE = {1, 1, 1, 1, 0, 0, 0, 1, 0}; - private static final int[] BIT3_TABLE = {1, 0, 1, 0, 0, 1, 1, 1, 0}; - - /** - * Encodes an int array whose elements are between 0 and q, - * to a byte array leaving no gaps between bits.
    - * q must be a power of 2. - * - * @param a the input array - * @param q the modulus - * @return the encoded array - */ - public static byte[] encodeModQ(int[] a, int q) - { - int bitsPerCoeff = 31 - Integer.numberOfLeadingZeros(q); - int numBits = a.length * bitsPerCoeff; - int numBytes = (numBits + 7) / 8; - byte[] data = new byte[numBytes]; - int bitIndex = 0; - int byteIndex = 0; - for (int i = 0; i < a.length; i++) - { - for (int j = 0; j < bitsPerCoeff; j++) - { - int currentBit = (a[i] >> j) & 1; - data[byteIndex] |= currentBit << bitIndex; - if (bitIndex == 7) - { - bitIndex = 0; - byteIndex++; - } - else - { - bitIndex++; - } - } - } - return data; - } - - /** - * Decodes a byte array encoded with {@link #encodeModQ(int[], int)} back to an int array.
    - * N is the number of coefficients. q must be a power of 2.
    - * Ignores any excess bytes. - * - * @param data an encoded ternary polynomial - * @param N number of coefficients - * @param q - * @return an array containing N coefficients between 0 and q-1 - */ - public static int[] decodeModQ(byte[] data, int N, int q) - { - int[] coeffs = new int[N]; - int bitsPerCoeff = 31 - Integer.numberOfLeadingZeros(q); - int numBits = N * bitsPerCoeff; - int coeffIndex = 0; - for (int bitIndex = 0; bitIndex < numBits; bitIndex++) - { - if (bitIndex > 0 && bitIndex % bitsPerCoeff == 0) - { - coeffIndex++; - } - int bit = getBit(data, bitIndex); - coeffs[coeffIndex] += bit << (bitIndex % bitsPerCoeff); - } - return coeffs; - } - - /** - * Decodes data encoded with {@link #encodeModQ(int[], int)} back to an int array.
    - * N is the number of coefficients. q must be a power of 2.
    - * Ignores any excess bytes. - * - * @param is an encoded ternary polynomial - * @param N number of coefficients - * @param q - * @return the decoded polynomial - */ - public static int[] decodeModQ(InputStream is, int N, int q) - throws IOException - { - int qBits = 31 - Integer.numberOfLeadingZeros(q); - int size = (N * qBits + 7) / 8; - byte[] arr = Util.readFullLength(is, size); - return decodeModQ(arr, N, q); - } - - /** - * Decodes a byte array encoded with {@link #encodeMod3Sves(int[])} back to an int array - * with N coefficients between -1 and 1.
    - * Ignores any excess bytes.
    - * See P1363.1 section 9.2.2. - * - * @param data an encoded ternary polynomial - * @param N number of coefficients - * @return the decoded coefficients - */ - public static int[] decodeMod3Sves(byte[] data, int N) - { - int[] coeffs = new int[N]; - int coeffIndex = 0; - for (int bitIndex = 0; bitIndex < data.length * 8; ) - { - int bit1 = getBit(data, bitIndex++); - int bit2 = getBit(data, bitIndex++); - int bit3 = getBit(data, bitIndex++); - int coeffTableIndex = bit1 * 4 + bit2 * 2 + bit3; - coeffs[coeffIndex++] = COEFF1_TABLE[coeffTableIndex]; - coeffs[coeffIndex++] = COEFF2_TABLE[coeffTableIndex]; - // ignore bytes that can't fit - if (coeffIndex > N - 2) - { - break; - } - } - return coeffs; - } - - /** - * Encodes an int array whose elements are between -1 and 1, to a byte array. - * coeffs[2*i] and coeffs[2*i+1] must not both equal -1 for any integer i, - * so this method is only safe to use with arrays produced by {@link #decodeMod3Sves(byte[], int)}.
    - * See P1363.1 section 9.2.3. - * - * @param arr - * @return the encoded array - */ - public static byte[] encodeMod3Sves(int[] arr) - { - int numBits = (arr.length * 3 + 1) / 2; - int numBytes = (numBits + 7) / 8; - byte[] data = new byte[numBytes]; - int bitIndex = 0; - int byteIndex = 0; - for (int i = 0; i < arr.length / 2 * 2; ) - { // if length is an odd number, throw away the highest coeff - int coeff1 = arr[i++] + 1; - int coeff2 = arr[i++] + 1; - if (coeff1 == 0 && coeff2 == 0) - { - throw new IllegalStateException("Illegal encoding!"); - } - int bitTableIndex = coeff1 * 3 + coeff2; - int[] bits = new int[]{BIT1_TABLE[bitTableIndex], BIT2_TABLE[bitTableIndex], BIT3_TABLE[bitTableIndex]}; - for (int j = 0; j < 3; j++) - { - data[byteIndex] |= bits[j] << bitIndex; - if (bitIndex == 7) - { - bitIndex = 0; - byteIndex++; - } - else - { - bitIndex++; - } - } - } - return data; - } - - /** - * Encodes an int array whose elements are between -1 and 1, to a byte array. - * - * @return the encoded array - */ - public static byte[] encodeMod3Tight(int[] intArray) - { - BigInteger sum = BigInteger.ZERO; - for (int i = intArray.length - 1; i >= 0; i--) - { - sum = sum.multiply(BigInteger.valueOf(3)); - sum = sum.add(BigInteger.valueOf(intArray[i] + 1)); - } - - int size = (BigInteger.valueOf(3).pow(intArray.length).bitLength() + 7) / 8; - byte[] arr = sum.toByteArray(); - - if (arr.length < size) - { - // pad with leading zeros so arr.length==size - byte[] arr2 = new byte[size]; - System.arraycopy(arr, 0, arr2, size - arr.length, arr.length); - return arr2; - } - - if (arr.length > size) - // drop sign bit - { - arr = Arrays.copyOfRange(arr, 1, arr.length); - } - return arr; - } - - /** - * Converts a byte array produced by {@link #encodeMod3Tight(int[])} back to an int array. - * - * @param b a byte array - * @param N number of coefficients - * @return the decoded array - */ - public static int[] decodeMod3Tight(byte[] b, int N) - { - BigInteger sum = new BigInteger(1, b); - int[] coeffs = new int[N]; - for (int i = 0; i < N; i++) - { - coeffs[i] = sum.mod(BigInteger.valueOf(3)).intValue() - 1; - if (coeffs[i] > 1) - { - coeffs[i] -= 3; - } - sum = sum.divide(BigInteger.valueOf(3)); - } - return coeffs; - } - - /** - * Converts data produced by {@link #encodeMod3Tight(int[])} back to an int array. - * - * @param is an input stream containing the data to decode - * @param N number of coefficients - * @return the decoded array - */ - public static int[] decodeMod3Tight(InputStream is, int N) - throws IOException - { - int size = (int)Math.ceil(N * Math.log(3) / Math.log(2) / 8); - byte[] arr = Util.readFullLength(is, size); - return decodeMod3Tight(arr, N); - } - - private static int getBit(byte[] arr, int bitIndex) - { - int byteIndex = bitIndex / 8; - int arrElem = arr[byteIndex] & 0xFF; - return (arrElem >> (bitIndex % 8)) & 1; - } -} diff --git a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/util/Util.java b/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/util/Util.java deleted file mode 100644 index 45fe7dbfeb..0000000000 --- a/core/src/main/java/org/bouncycastle/pqc/legacy/math/ntru/util/Util.java +++ /dev/null @@ -1,158 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.util; - -import java.io.IOException; -import java.io.InputStream; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.bouncycastle.pqc.legacy.math.ntru.euclid.IntEuclidean; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.SparseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.TernaryPolynomial; -import org.bouncycastle.util.Integers; - -public class Util -{ - private static volatile boolean IS_64_BITNESS_KNOWN; - private static volatile boolean IS_64_BIT_JVM; - - /** - * Calculates the inverse of n mod modulus - */ - public static int invert(int n, int modulus) - { - n %= modulus; - if (n < 0) - { - n += modulus; - } - return IntEuclidean.calculate(n, modulus).x; - } - - /** - * Calculates a^b mod modulus - */ - public static int pow(int a, int b, int modulus) - { - int p = 1; - for (int i = 0; i < b; i++) - { - p = (p * a) % modulus; - } - return p; - } - - /** - * Calculates a^b mod modulus - */ - public static long pow(long a, int b, long modulus) - { - long p = 1; - for (int i = 0; i < b; i++) - { - p = (p * a) % modulus; - } - return p; - } - - /** - * Generates a "sparse" or "dense" polynomial containing numOnes ints equal to 1, - * numNegOnes int equal to -1, and the rest equal to 0. - * - * @param N - * @param numOnes - * @param numNegOnes - * @param sparse whether to create a {@link SparseTernaryPolynomial} or {@link DenseTernaryPolynomial} - * @return a ternary polynomial - */ - public static TernaryPolynomial generateRandomTernary(int N, int numOnes, int numNegOnes, boolean sparse, SecureRandom random) - { - if (sparse) - { - return SparseTernaryPolynomial.generateRandom(N, numOnes, numNegOnes, random); - } - else - { - return DenseTernaryPolynomial.generateRandom(N, numOnes, numNegOnes, random); - } - } - - /** - * Generates an array containing numOnes ints equal to 1, - * numNegOnes int equal to -1, and the rest equal to 0. - * - * @param N - * @param numOnes - * @param numNegOnes - * @return an array of integers - */ - public static int[] generateRandomTernary(int N, int numOnes, int numNegOnes, SecureRandom random) - { - Integer one = Integers.valueOf(1); - Integer minusOne = Integers.valueOf(-1); - Integer zero = Integers.valueOf(0); - - List list = new ArrayList(); - for (int i = 0; i < numOnes; i++) - { - list.add(one); - } - for (int i = 0; i < numNegOnes; i++) - { - list.add(minusOne); - } - while (list.size() < N) - { - list.add(zero); - } - - Collections.shuffle(list, random); - - int[] arr = new int[N]; - for (int i = 0; i < N; i++) - { - arr[i] = ((Integer)list.get(i)).intValue(); - } - return arr; - } - - /** - * Takes an educated guess as to whether 64 bits are supported by the JVM. - * - * @return true if 64-bit support detected, false otherwise - */ - public static boolean is64BitJVM() - { - if (!IS_64_BITNESS_KNOWN) - { - String arch = System.getProperty("os.arch"); - String sunModel = System.getProperty("sun.arch.data.model"); - IS_64_BIT_JVM = "amd64".equals(arch) || "x86_64".equals(arch) || "ppc64".equals(arch) || "64".equals(sunModel); - IS_64_BITNESS_KNOWN = true; - } - return IS_64_BIT_JVM; - } - - /** - * Reads a given number of bytes from an InputStream. - * If there are not enough bytes in the stream, an IOException - * is thrown. - * - * @param is - * @param length - * @return an array of length length - * @throws IOException - */ - public static byte[] readFullLength(InputStream is, int length) - throws IOException - { - byte[] arr = new byte[length]; - if (is.read(arr) != arr.length) - { - throw new IOException("Not enough bytes to read."); - } - return arr; - } -} \ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/util/Arrays.java b/core/src/main/java/org/bouncycastle/util/Arrays.java index 27371dd423..804d683f66 100644 --- a/core/src/main/java/org/bouncycastle/util/Arrays.java +++ b/core/src/main/java/org/bouncycastle/util/Arrays.java @@ -149,6 +149,37 @@ public static boolean constantTimeAreEqual(int len, byte[] a, int aOff, byte[] b return 0 == d; } + public static boolean constantTimeAreEqual(int len, long[] a, int aOff, long[] b, int bOff) + { + if (null == a) + { + throw new NullPointerException("'a' cannot be null"); + } + if (null == b) + { + throw new NullPointerException("'b' cannot be null"); + } + if (len < 0) + { + throw new IllegalArgumentException("'len' cannot be negative"); + } + if (aOff > (a.length - len)) + { + throw new IndexOutOfBoundsException("'aOff' value invalid for specified length"); + } + if (bOff > (b.length - len)) + { + throw new IndexOutOfBoundsException("'bOff' value invalid for specified length"); + } + + long d = 0; + for (int i = 0; i < len; ++i) + { + d |= (a[aOff + i] ^ b[bOff + i]); + } + return 0L == d; + } + /** * A constant time equals comparison - does not terminate early if * comparison fails. For best results always pass the expected value @@ -190,6 +221,36 @@ public static boolean constantTimeAreEqual( return nonEqual == 0; } + public static boolean constantTimeAreEqual( + long[] expected, + long[] supplied) + { + if (expected == null || supplied == null) + { + return false; + } + + if (expected == supplied) + { + return true; + } + + int len = (expected.length < supplied.length) ? expected.length : supplied.length; + + long nonEqual = expected.length ^ supplied.length; + + for (int i = 0; i != len; i++) + { + nonEqual |= (expected[i] ^ supplied[i]); + } + for (int i = len; i < supplied.length; i++) + { + nonEqual |= (supplied[i] ^ ~supplied[i]); + } + + return nonEqual == 0; + } + public static int compareUnsigned(byte[] a, byte[] b) { if (a == b) @@ -1209,6 +1270,27 @@ public static void clear(int[] data) } } + public static void clear(long[] data) + { + if (null != data) + { + java.util.Arrays.fill(data, 0); + } + } + + /** + * Fill input array by zeros + * + * @param data input array + */ + public static void clear(char[] data) + { + if (null != data) + { + java.util.Arrays.fill(data, (char)0x00); + } + } + public static boolean isNullOrContainsNull(Object[] array) { if (null == array) @@ -1240,4 +1322,38 @@ public static boolean isNullOrEmpty(Object[] array) { return null == array || array.length < 1; } + + public static boolean segmentsOverlap(int aOff, int aLen, int bOff, int bLen) + { + return aLen > 0 + && bLen > 0 + && aOff - bOff < bLen + && bOff - aOff < aLen; + } + + public static void validateRange(byte[] buf, int from, int to) + { + if (buf == null) + { + throw new NullPointerException("'buf' cannot be null"); + } + if ((from | (buf.length - from) | (to - from) | (buf.length - to)) < 0) + { + throw new IndexOutOfBoundsException("buf.length: " + buf.length + ", from: " + from + ", to: " + to); + } + } + + public static void validateSegment(byte[] buf, int off, int len) + { + if (buf == null) + { + throw new NullPointerException("'buf' cannot be null"); + } + int available = buf.length - off; + int remaining = available - len; + if ((off | len | available | remaining) < 0) + { + throw new IndexOutOfBoundsException("buf.length: " + buf.length + ", off: " + off + ", len: " + len); + } + } } diff --git a/core/src/main/java/org/bouncycastle/util/BigIntegers.java b/core/src/main/java/org/bouncycastle/util/BigIntegers.java index 7e70366cdc..72307d1390 100644 --- a/core/src/main/java/org/bouncycastle/util/BigIntegers.java +++ b/core/src/main/java/org/bouncycastle/util/BigIntegers.java @@ -1,5 +1,7 @@ package org.bouncycastle.util; +import java.io.IOException; +import java.io.OutputStream; import java.math.BigInteger; import java.security.SecureRandom; import java.util.Map; @@ -393,6 +395,16 @@ public static BigInteger createRandomPrime(int bitLength, int certainty, SecureR return rv; } + public static void writeUnsignedByteArray(OutputStream out, BigInteger n) throws IOException + { + byte[] b = n.toByteArray(); + + int off = b[0] == 0 ? 1 : 0; + int len = b.length - off; + + out.write(b, off, len); + } + private static byte[] createRandom(int bitLength, SecureRandom random) throws IllegalArgumentException { diff --git a/core/src/main/java/org/bouncycastle/util/Bytes.java b/core/src/main/java/org/bouncycastle/util/Bytes.java index 4db85758a0..b3081734da 100644 --- a/core/src/main/java/org/bouncycastle/util/Bytes.java +++ b/core/src/main/java/org/bouncycastle/util/Bytes.java @@ -16,6 +16,14 @@ public static void xor(int len, byte[] x, byte[] y, byte[] z) } } + public static void xor(int len, byte[] x, int xOff, byte[] y, byte[] z, int zOff) + { + for (int i = 0; i < len; ++i) + { + z[zOff++] = (byte)(x[xOff++] ^ y[i]); + } + } + public static void xor(int len, byte[] x, int xOff, byte[] y, int yOff, byte[] z, int zOff) { for (int i = 0; i < len; ++i) @@ -24,6 +32,22 @@ public static void xor(int len, byte[] x, int xOff, byte[] y, int yOff, byte[] z } } + public static void xor(int len, byte[] x, byte[] y, byte[] z, int zOff) + { + for (int i = 0; i < len; ++i) + { + z[zOff++] = (byte)(x[i] ^ y[i]); + } + } + + public static void xor(int len, byte[] x, byte[] y, int yOff, byte[] z, int zOff) + { + for (int i = 0; i < len; ++i) + { + z[zOff++] = (byte)(x[i] ^ y[yOff++]); + } + } + public static void xorTo(int len, byte[] x, byte[] z) { for (int i = 0; i < len; ++i) @@ -32,6 +56,14 @@ public static void xorTo(int len, byte[] x, byte[] z) } } + public static void xorTo(int len, byte[] x, int xOff, byte[] z) + { + for (int i = 0; i < len; ++i) + { + z[i] ^= x[xOff++]; + } + } + public static void xorTo(int len, byte[] x, int xOff, byte[] z, int zOff) { for (int i = 0; i < len; ++i) diff --git a/core/src/main/java/org/bouncycastle/util/Fingerprint.java b/core/src/main/java/org/bouncycastle/util/Fingerprint.java index 7027d4948c..e9cd32e6cb 100644 --- a/core/src/main/java/org/bouncycastle/util/Fingerprint.java +++ b/core/src/main/java/org/bouncycastle/util/Fingerprint.java @@ -45,6 +45,7 @@ public Fingerprint(byte[] source, int bitLength) * @param useSHA512t use the old SHA512/160 calculation. * @deprecated use the SHAKE only version. */ + @Deprecated public Fingerprint(byte[] source, boolean useSHA512t) { if (useSHA512t) @@ -64,7 +65,7 @@ public byte[] getFingerprint() public String toString() { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (int i = 0; i != fingerprint.length; i++) { if (i > 0) @@ -143,6 +144,7 @@ public static byte[] calculateFingerprint(byte[] input, int bitLength) * @return a byte array containing a 20 byte fingerprint. * @deprecated use the SHAKE based version. */ + @Deprecated public static byte[] calculateFingerprintSHA512_160(byte[] input) { SHA512tDigest digest = new SHA512tDigest(160); diff --git a/core/src/main/java/org/bouncycastle/util/GF16.java b/core/src/main/java/org/bouncycastle/util/GF16.java new file mode 100644 index 0000000000..3cb0878965 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/util/GF16.java @@ -0,0 +1,178 @@ +package org.bouncycastle.util; + +public class GF16 +{ + private static final byte[] F_STAR = {1, 2, 4, 8, 3, 6, 12, 11, 5, 10, 7, 14, 15, 13, 9}; + private static final byte[] MT4B = new byte[256]; + private static final byte[] INV4B = new byte[16]; + + static byte mt(int p, int q) + { + return MT4B[((p) << 4) ^ (q)]; + } + + static + { + // Initialize multiplication table + for (int i = 0; i < 15; i++) + { + for (int j = 0; j < 15; j++) + { + MT4B[(F_STAR[i] << 4) ^ F_STAR[j]] = F_STAR[(i + j) % 15]; + } + } + + int g = F_STAR[1], g_inv = F_STAR[14], gn = 1, gn_inv = 1; + // Initialize inversion table + INV4B[1] = 1; + for (int i = 0; i < 14; i++) + { + gn = mt(gn, g); + gn_inv = mt(gn_inv, g_inv); + INV4B[gn] = (byte)gn_inv; + } + } + + /** + * GF(16) multiplication mod x^4 + x + 1. + *

    + * This method multiplies two elements in GF(16) (represented as integers 0–15) + * using carryless multiplication followed by reduction modulo x^4 + x + 1. + * Please ensure a <= 0x0F and b <= 0x0F + * + * @param a an element in GF(16) (only the lower 4 bits are used) + * @param b an element in GF(16) (only the lower 4 bits are used) + * @return the product a * b in GF(16) + */ + public static byte mul(byte a, byte b) + { + return MT4B[a << 4 | b]; + } + + /** + * GF(16) multiplication mod x^4 + x + 1. + *

    + * This method multiplies two elements in GF(16) (represented as integers 0–15) + * using carryless multiplication followed by reduction modulo x^4 + x + 1. + * Please ensure a <= 0x0F and b <= 0x0F + * + * @param a an element in GF(16) (only the lower 4 bits are used) + * @param b an element in GF(16) (only the lower 4 bits are used) + * @return the product a * b in GF(16) + */ + public static int mul(int a, int b) + { + return MT4B[a << 4 | b]; + } + + /** + * Computes the multiplicative inverse in GF(16) for a GF(16) element. + */ + public static byte inv(byte a) + { + return INV4B[a & 0xF]; +// int a2 = GF16.mul(a, a); +// int a4 = GF16.mul(a2, a2); +// int a8 = GF16.mul(a4, a4); +// int a6 = GF16.mul(a2, a4); +// return (byte)GF16.mul(a8, a6); + } + + /** + * Decodes an encoded byte array. + * Each byte in the input contains two nibbles (4-bit values); the lower nibble is stored first, + * followed by the upper nibble. + * + * @param input the input byte array (each byte holds two 4-bit values) + * @param output the output array that will hold the decoded nibbles (one per byte) + * @param outputLen the total number of nibbles to decode + */ + public static void decode(byte[] input, byte[] output, int outputLen) + { + int i, decIndex = 0, blocks = outputLen >> 1; + // Process pairs of nibbles from each byte + for (i = 0; i < blocks; i++) + { + // Extract the lower nibble + output[decIndex++] = (byte)(input[i] & 0x0F); + // Extract the upper nibble (shift right 4 bits) + output[decIndex++] = (byte)((input[i] >>> 4) & 0x0F); + } + // If there is an extra nibble (odd number of nibbles), decode only the lower nibble + if ((outputLen & 1) == 1) + { + output[decIndex] = (byte)(input[i] & 0x0F); + } + } + + public static void decode(byte[] input, int inOff, byte[] output, int outOff, int outputLen) + { + // Process pairs of nibbles from each byte + int blocks = outputLen >> 1; + for (int i = 0; i < blocks; i++) + { + // Extract the lower nibble + output[outOff++] = (byte)(input[inOff] & 0x0F); + // Extract the upper nibble (shift right 4 bits) + output[outOff++] = (byte)((input[inOff++] >>> 4) & 0x0F); + } + // If there is an extra nibble (odd number of nibbles), decode only the lower nibble + if ((outputLen & 1) == 1) + { + output[outOff] = (byte)(input[inOff] & 0x0F); + } + } + + /** + * Encodes an array of 4-bit values into a byte array. + * Two 4-bit values are packed into one byte, with the first nibble stored in the lower 4 bits + * and the second nibble stored in the upper 4 bits. + * + * @param input the input array of 4-bit values (stored as bytes, only lower 4 bits used) + * @param output the output byte array that will hold the encoded bytes + * @param inputLen the number of nibbles in the input array + */ + public static void encode(byte[] input, byte[] output, int inputLen) + { + int i, inOff = 0, blocks = inputLen >> 1; + // Process pairs of 4-bit values + for (i = 0; i < blocks; i++) + { + int lowerNibble = input[inOff++] & 0x0F; + int upperNibble = (input[inOff++] & 0x0F) << 4; + output[i] = (byte)(lowerNibble | upperNibble); + } + // If there is an extra nibble (odd number of nibbles), store it directly in lower 4 bits. + if ((inputLen & 1) == 1) + { + output[i] = (byte)(input[inOff] & 0x0F); + } + } + + public static void encode(byte[] input, byte[] output, int outOff, int inputLen) + { + int i, inOff = 0, blocks = inputLen >> 1; + // Process pairs of 4-bit values + for (i = 0; i < blocks; i++) + { + int lowerNibble = input[inOff++] & 0x0F; + int upperNibble = (input[inOff++] & 0x0F) << 4; + output[outOff++] = (byte)(lowerNibble | upperNibble); + } + // If there is an extra nibble (odd number of nibbles), store it directly in lower 4 bits. + if ((inputLen & 1) == 1) + { + output[outOff] = (byte)(input[inOff] & 0x0F); + } + } + + public static byte innerProduct(byte[] a, int aOff, byte[] b, int bOff, int rank) + { + byte result = 0; + for (int k = 0; k < rank; ++k, bOff += rank) + { + result ^= mul(a[aOff++], b[bOff]); + } + return result; + } +} diff --git a/core/src/main/java/org/bouncycastle/util/Integers.java b/core/src/main/java/org/bouncycastle/util/Integers.java index 9af524bf82..534bb11b1f 100644 --- a/core/src/main/java/org/bouncycastle/util/Integers.java +++ b/core/src/main/java/org/bouncycastle/util/Integers.java @@ -13,6 +13,20 @@ public static int bitCount(int i) return Integer.bitCount(i); } + public static int compare(int x, int y) + { + // @since 1.7 +// return Integer.compare(x, y); + return x < y ? -1 : x == y ? 0 : 1; + } + + public static int compareUnsigned(int x, int y) + { + // @since 1.8 +// return Integer.compareUnsigned(x, y); + return compare(x + Integer.MIN_VALUE, y + Integer.MIN_VALUE); + } + public static int highestOneBit(int i) { return Integer.highestOneBit(i); diff --git a/core/src/main/java/org/bouncycastle/util/Longs.java b/core/src/main/java/org/bouncycastle/util/Longs.java index 443e310f4f..ac5694c849 100644 --- a/core/src/main/java/org/bouncycastle/util/Longs.java +++ b/core/src/main/java/org/bouncycastle/util/Longs.java @@ -8,6 +8,20 @@ public class Longs public static final int BYTES = 8; public static final int SIZE = Long.SIZE; + public static int compare(long x, long y) + { + // @since 1.7 +// return Long.compare(x, y); + return x < y ? -1 : x == y ? 0 : 1; + } + + public static int compareUnsigned(long x, long y) + { + // @since 1.8 +// return Long.compareUnsigned(x, y); + return compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE); + } + public static long highestOneBit(long i) { return Long.highestOneBit(i); @@ -52,4 +66,12 @@ public static Long valueOf(long value) { return Long.valueOf(value); } + + public static void xorTo(int len, long[] x, int xOff, long[] z, int zOff) + { + for (int i = 0; i < len; ++i) + { + z[zOff + i] ^= x[xOff + i]; + } + } } diff --git a/core/src/main/java/org/bouncycastle/util/Pack.java b/core/src/main/java/org/bouncycastle/util/Pack.java index d3a360975f..486920aae5 100644 --- a/core/src/main/java/org/bouncycastle/util/Pack.java +++ b/core/src/main/java/org/bouncycastle/util/Pack.java @@ -39,6 +39,24 @@ public static void bigEndianToInt(byte[] bs, int off, int[] ns, int nsOff, int n } } + public static int bigEndianToInt_High(byte[] bs, int off, int len) + { + return bigEndianToInt_Low(bs, off, len) << ((4 - len) << 3); + } + + public static int bigEndianToInt_Low(byte[] bs, int off, int len) + { +// assert 1 <= len && len <= 4; + + int result = bs[off] & 0xFF; + for (int i = 1; i < len; ++i) + { + result <<= 8; + result |= bs[off + i] & 0xFF; + } + return result; + } + public static byte[] intToBigEndian(int n) { byte[] bs = new byte[4]; @@ -46,6 +64,14 @@ public static byte[] intToBigEndian(int n) return bs; } + public static void intToBigEndian(int n, byte[] bs) + { + bs[0] = (byte)(n >>> 24); + bs[1] = (byte)(n >>> 16); + bs[2] = (byte)(n >>> 8); + bs[3] = (byte)(n); + } + public static void intToBigEndian(int n, byte[] bs, int off) { bs[off] = (byte)(n >>> 24); @@ -79,6 +105,24 @@ public static void intToBigEndian(int[] ns, int nsOff, int nsLen, byte[] bs, int } } + public static void intToBigEndian_High(int n, byte[] bs, int off, int len) + { +// assert 1 <= len && len <= 4; + + int pos = 24; + bs[off] = (byte)(n >>> pos); + for (int i = 1; i < len; ++i) + { + pos -= 8; + bs[off + i] = (byte)(n >>> pos); + } + } + + public static void intToBigEndian_Low(int n, byte[] bs, int off, int len) + { + intToBigEndian_High(n << ((4 - len) << 3), bs, off, len); + } + public static long bigEndianToLong(byte[] bs, int off) { int hi = bigEndianToInt(bs, off); @@ -104,14 +148,22 @@ public static void bigEndianToLong(byte[] bs, int bsOff, long[] ns, int nsOff, i } } - public static long bigEndianToLong(byte[] bs, int off, int len) + public static long bigEndianToLong_High(byte[] bs, int off, int len) { - long x = 0; - for (int i = 0; i < len; ++i) + return bigEndianToLong_Low(bs, off, len) << ((8 - len) << 3); + } + + public static long bigEndianToLong_Low(byte[] bs, int off, int len) + { +// assert 1 <= len && len <= 8; + + long result = bs[off] & 0xFFL; + for (int i = 1; i < len; ++i) { - x |= (bs[i + off] & 0xFFL) << ((7 - i) << 3); + result <<= 8; + result |= bs[off + i] & 0xFFL; } - return x; + return result; } public static byte[] longToBigEndian(long n) @@ -152,22 +204,24 @@ public static void longToBigEndian(long[] ns, int nsOff, int nsLen, byte[] bs, i } } - /** - * @param value The number - * @param bs The target. - * @param off Position in target to start. - * @param bytes number of bytes to write. - * @deprecated Will be removed - */ - public static void longToBigEndian(long value, byte[] bs, int off, int bytes) + public static void longToBigEndian_High(long n, byte[] bs, int off, int len) { - for (int i = bytes - 1; i >= 0; i--) +// assert 1 <= len && len <= 8; + + int pos = 56; + bs[off] = (byte)(n >>> pos); + for (int i = 1; i < len; ++i) { - bs[i + off] = (byte)(value & 0xff); - value >>>= 8; + pos -= 8; + bs[off + i] = (byte)(n >>> pos); } } + public static void longToBigEndian_Low(long n, byte[] bs, int off, int len) + { + longToBigEndian_High(n << ((8 - len) << 3), bs, off, len); + } + public static short littleEndianToShort(byte[] bs, int off) { int n = bs[off] & 0xff; @@ -175,6 +229,23 @@ public static short littleEndianToShort(byte[] bs, int off) return (short)n; } + public static void littleEndianToShort(byte[] bs, int bOff, short[] ns, int nOff, int count) + { + for (int i = 0; i < count; ++i) + { + ns[nOff + i] = littleEndianToShort(bs, bOff); + bOff += 2; + } + } + + public static int littleEndianToInt24(byte[] bs, int off) + { + int n = bs[off] & 0xff; + n |= (bs[++off] & 0xff) << 8; + n |= (bs[++off] & 0xff) << 16; + return n; + } + public static int littleEndianToInt(byte[] bs, int off) { int n = bs[off] & 0xff; @@ -245,6 +316,14 @@ public static void shortToLittleEndian(short n, byte[] bs, int off) bs[++off] = (byte)(n >>> 8); } + public static void shortToLittleEndian(short[] ns, int nsOff, int nsLen, byte[] bs, int bsOff) + { + for (int i = 0; i < nsLen; ++i) + { + shortToLittleEndian(ns[nsOff + i], bs, bsOff); + bsOff += 2; + } + } public static byte[] shortToBigEndian(short n) { @@ -300,6 +379,23 @@ public static void intToLittleEndian(int[] ns, int nsOff, int nsLen, byte[] bs, } } + public static void intToLittleEndian_High(int n, byte[] bs, int off, int len) + { + intToLittleEndian_Low(n >> ((4 - len) << 3), bs, off, len); + } + + public static void intToLittleEndian_Low(int n, byte[] bs, int off, int len) + { +// assert 1 <= len && len <= 4; + + bs[off] = (byte)n; + for (int i = 1; i < len; ++i) + { + n >>>= 8; + bs[off + i] = (byte)n; + } + } + public static long littleEndianToLong(byte[] bs, int off) { int lo = littleEndianToInt(bs, off); @@ -316,16 +412,6 @@ public static void littleEndianToLong(byte[] bs, int off, long[] ns) } } - public static long littleEndianToLong(byte[] input, int off, int len) - { - long result = 0; - for (int i = 0; i < len; ++i) - { - result |= (input[off + i] & 0xFFL) << (i << 3); - } - return result; - } - public static void littleEndianToLong(byte[] bs, int bsOff, long[] ns, int nsOff, int nsLen) { for (int i = 0; i < nsLen; ++i) @@ -335,31 +421,6 @@ public static void littleEndianToLong(byte[] bs, int bsOff, long[] ns, int nsOff } } - public static void longToLittleEndian_High(long n, byte[] bs, int off, int len) - { - //Debug.Assert(1 <= len && len <= 8); - int pos = 56; - bs[off] = (byte)(n >>> pos); - for (int i = 1; i < len; ++i) - { - pos -= 8; - bs[off + i] = (byte)(n >>> pos); - } - } - - public static void longToLittleEndian(long n, byte[] bs, int off, int len) - { - for (int i = 0; i < len; ++i) - { - bs[off + i] = (byte)(n >>> (i << 3)); - } - } - -// public static void longToLittleEndian_Low(long n, byte[] bs, int off, int len) -// { -// longToLittleEndian_High(n << ((8 - len) << 3), bs, off, len); -// } - public static long littleEndianToLong_High(byte[] bs, int off, int len) { return littleEndianToLong_Low(bs, off, len) << ((8 - len) << 3); @@ -367,12 +428,14 @@ public static long littleEndianToLong_High(byte[] bs, int off, int len) public static long littleEndianToLong_Low(byte[] bs, int off, int len) { - //Debug.Assert(1 <= len && len <= 8); - long result = bs[off] & 0xFF; +// assert 1 <= len && len <= 8; + + long result = bs[off] & 0xFFL; + int pos = 0; for (int i = 1; i < len; ++i) { - result <<= 8; - result |= bs[off + i] & 0xFF; + pos += 8; + result |= (bs[off + i] & 0xFFL) << pos; } return result; } @@ -415,5 +478,20 @@ public static void longToLittleEndian(long[] ns, int nsOff, int nsLen, byte[] bs } } + public static void longToLittleEndian_High(long n, byte[] bs, int off, int len) + { + longToLittleEndian_Low(n >>> ((8 - len) << 3), bs, off, len); + } + + public static void longToLittleEndian_Low(long n, byte[] bs, int off, int len) + { +// assert 1 <= len && len <= 8; + bs[off] = (byte)n; + for (int i = 1; i < len; ++i) + { + n >>>= 8; + bs[off + i] = (byte)n; + } + } } diff --git a/core/src/main/java/org/bouncycastle/util/Strings.java b/core/src/main/java/org/bouncycastle/util/Strings.java index a568149791..28f32f1079 100644 --- a/core/src/main/java/org/bouncycastle/util/Strings.java +++ b/core/src/main/java/org/bouncycastle/util/Strings.java @@ -47,13 +47,7 @@ public String run() public static String fromUTF8ByteArray(byte[] bytes) { - char[] chars = new char[bytes.length]; - int len = UTF8.transcodeToUTF16(bytes, chars); - if (len < 0) - { - throw new IllegalArgumentException("Invalid UTF-8 input"); - } - return new String(chars, 0, len); + return fromUTF8ByteArray(bytes, 0, bytes.length); } public static String fromUTF8ByteArray(byte[] bytes, int off, int length) @@ -73,12 +67,17 @@ public static byte[] toUTF8ByteArray(String string) } public static byte[] toUTF8ByteArray(char[] string) + { + return toUTF8ByteArray(string, 0, string.length); + } + + public static byte[] toUTF8ByteArray(char[] cs, int csOff, int csLen) { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); try { - toUTF8ByteArray(string, bOut); + toUTF8ByteArray(cs, csOff, csLen, bOut); } catch (IOException e) { @@ -91,54 +90,81 @@ public static byte[] toUTF8ByteArray(char[] string) public static void toUTF8ByteArray(char[] string, OutputStream sOut) throws IOException { - char[] c = string; - int i = 0; + toUTF8ByteArray(string, 0, string.length, sOut); + } + + public static void toUTF8ByteArray(char[] cs, int csOff, int csLen, OutputStream sOut) + throws IOException + { + if (csLen < 1) + { + return; + } + + byte[] buf = new byte[64]; - while (i < c.length) + int bufPos = 0, i = 0; + do { - char ch = c[i]; + int c = cs[csOff + i++]; - if (ch < 0x0080) + if (c < 0x0080) { - sOut.write(ch); + buf[bufPos++] = (byte)c; } - else if (ch < 0x0800) + else if (c < 0x0800) { - sOut.write(0xc0 | (ch >> 6)); - sOut.write(0x80 | (ch & 0x3f)); + buf[bufPos++] = (byte)(0xC0 | (c >> 6)); + buf[bufPos++] = (byte)(0x80 | (c & 0x3F)); } // surrogate pair - else if (ch >= 0xD800 && ch <= 0xDFFF) + else if (c >= 0xD800 && c <= 0xDFFF) { - // in error - can only happen, if the Java String class has a - // bug. - if (i + 1 >= c.length) + /* + * Various checks that shouldn't fail unless the Java String class has a bug. + */ + int W1 = c; + if (W1 > 0xDBFF) { - throw new IllegalStateException("invalid UTF-16 codepoint"); + throw new IllegalStateException("invalid UTF-16 high surrogate"); } - char W1 = ch; - ch = c[++i]; - char W2 = ch; - // in error - can only happen, if the Java String class has a - // bug. - if (W1 > 0xDBFF) + + if (i >= csLen) { - throw new IllegalStateException("invalid UTF-16 codepoint"); + throw new IllegalStateException("invalid UTF-16 codepoint (truncated surrogate pair)"); } + + int W2 = cs[csOff + i++]; + if (W2 < 0xDC00 || W2 > 0xDFFF) + { + throw new IllegalStateException("invalid UTF-16 low surrogate"); + } + int codePoint = (((W1 & 0x03FF) << 10) | (W2 & 0x03FF)) + 0x10000; - sOut.write(0xf0 | (codePoint >> 18)); - sOut.write(0x80 | ((codePoint >> 12) & 0x3F)); - sOut.write(0x80 | ((codePoint >> 6) & 0x3F)); - sOut.write(0x80 | (codePoint & 0x3F)); + buf[bufPos++] = (byte)(0xF0 | (codePoint >> 18)); + buf[bufPos++] = (byte)(0x80 | ((codePoint >> 12) & 0x3F)); + buf[bufPos++] = (byte)(0x80 | ((codePoint >> 6) & 0x3F)); + buf[bufPos++] = (byte)(0x80 | (codePoint & 0x3F)); } else { - sOut.write(0xe0 | (ch >> 12)); - sOut.write(0x80 | ((ch >> 6) & 0x3F)); - sOut.write(0x80 | (ch & 0x3F)); + buf[bufPos++] = (byte)(0xE0 | (c >> 12)); + buf[bufPos++] = (byte)(0x80 | ((c >> 6) & 0x3F)); + buf[bufPos++] = (byte)(0x80 | (c & 0x3F)); } - i++; + if (bufPos + 4 > buf.length) + { + sOut.write(buf, 0, bufPos); + bufPos = 0; + } + } + while (i < csLen); + + if (bufPos > 0) + { + sOut.write(buf, 0, bufPos); +// bufPos = 0; } } @@ -307,7 +333,7 @@ public static String[] split(String input, char delimiter) while (moreTokens) { int tokenLocation = input.indexOf(delimiter); - if (tokenLocation > 0) + if (tokenLocation >= 0) { subString = input.substring(0, tokenLocation); v.addElement(subString); @@ -382,6 +408,4 @@ public String[] toStringArray(int from, int to) return strs; } } - - } diff --git a/core/src/main/java/org/bouncycastle/util/encoders/Base64.java b/core/src/main/java/org/bouncycastle/util/encoders/Base64.java index 72e0a716f2..345b54a410 100644 --- a/core/src/main/java/org/bouncycastle/util/encoders/Base64.java +++ b/core/src/main/java/org/bouncycastle/util/encoders/Base64.java @@ -97,15 +97,23 @@ public static int encode( * * @return a byte array representing the decoded data. */ - public static byte[] decode( - byte[] data) + public static byte[] decode(byte[] data) { - int len = data.length / 4 * 3; - ByteArrayOutputStream bOut = new ByteArrayOutputStream(len); + return decode(data, 0, data.length); + } + + /** + * decode the base 64 encoded input data. It is assumed the input data is valid. + * + * @return a byte array representing the decoded data. + */ + public static byte[] decode(byte[] data, int off, int length) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(length / 4 * 3); try { - encoder.decode(data, 0, data.length, bOut); + encoder.decode(data, off, length, bOut); } catch (Exception e) { diff --git a/core/src/main/java/org/bouncycastle/util/encoders/Hex.java b/core/src/main/java/org/bouncycastle/util/encoders/Hex.java index b51c879a10..5ffc7657bc 100644 --- a/core/src/main/java/org/bouncycastle/util/encoders/Hex.java +++ b/core/src/main/java/org/bouncycastle/util/encoders/Hex.java @@ -96,14 +96,23 @@ public static int encode( * * @return a byte array representing the decoded data. */ - public static byte[] decode( - byte[] data) + public static byte[] decode(byte[] data) { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + return decode(data, 0, data.length); + } + + /** + * decode the Hex encoded input data. It is assumed the input data is valid. + * + * @return a byte array representing the decoded data. + */ + public static byte[] decode(byte[] data, int off, int length) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(length / 2); try { - encoder.decode(data, 0, data.length, bOut); + encoder.decode(data, off, length, bOut); } catch (Exception e) { diff --git a/core/src/main/java/org/bouncycastle/util/encoders/UTF8.java b/core/src/main/java/org/bouncycastle/util/encoders/UTF8.java index cd9073d39f..e339c7249c 100644 --- a/core/src/main/java/org/bouncycastle/util/encoders/UTF8.java +++ b/core/src/main/java/org/bouncycastle/util/encoders/UTF8.java @@ -184,8 +184,8 @@ public static int transcodeToUTF16(byte[] utf8, int utf8Off, int utf8Length, cha } // Code points above U+10FFFF are caught by the DFA - utf16[j++] = (char)(0xD7C0 + (codePoint >>> 10)); - utf16[j++] = (char)(0xDC00 | (codePoint & 0x3FF)); + utf16[j++] = (char)(0xD7C0 + (codePoint >>> 10)); // [0xD800, 0xDBFF] high surrogate (W1) + utf16[j++] = (char)(0xDC00 | (codePoint & 0x3FF)); // [0xDC00, 0xDFFF] low surrogate (W2) } } diff --git a/core/src/main/java/org/bouncycastle/util/io/Streams.java b/core/src/main/java/org/bouncycastle/util/io/Streams.java index c72a476fa1..21eb4a4ebe 100644 --- a/core/src/main/java/org/bouncycastle/util/io/Streams.java +++ b/core/src/main/java/org/bouncycastle/util/io/Streams.java @@ -5,6 +5,8 @@ import java.io.InputStream; import java.io.OutputStream; +import org.bouncycastle.util.Arrays; + /** * Utility methods to assist with stream processing. */ @@ -160,16 +162,7 @@ public static int readFully(InputStream inStr, byte[] buf, int off, int len) public static void validateBufferArguments(byte[] buf, int off, int len) { - if (buf == null) - { - throw new NullPointerException(); - } - int available = buf.length - off; - int remaining = available - len; - if ((off | len | available | remaining) < 0) - { - throw new IndexOutOfBoundsException(); - } + Arrays.validateSegment(buf, off, len); } public static void writeBufTo(ByteArrayOutputStream buf, OutputStream output) diff --git a/core/src/main/java/org/bouncycastle/util/test/SimpleTest.java b/core/src/main/java/org/bouncycastle/util/test/SimpleTest.java index 53fc71bf17..2d29635e54 100644 --- a/core/src/main/java/org/bouncycastle/util/test/SimpleTest.java +++ b/core/src/main/java/org/bouncycastle/util/test/SimpleTest.java @@ -16,7 +16,7 @@ private TestResult success() return SimpleTestResult.successful(this, "Okay"); } - protected void fail( + public void fail( String message) { throw new TestFailedException(SimpleTestResult.failed(this, message)); @@ -163,7 +163,7 @@ protected void fail( throw new TestFailedException(SimpleTestResult.failed(this, message, throwable)); } - protected void fail( + public void fail( String message, Object expected, Object found) @@ -178,7 +178,7 @@ protected boolean areEqual( return Arrays.areEqual(a, b); } - protected boolean areEqual(byte[] a, int aFromIndex, int aToIndex, byte[] b, int bFromIndex, int bToIndex) + public boolean areEqual(byte[] a, int aFromIndex, int aToIndex, byte[] b, int bFromIndex, int bToIndex) { return Arrays.areEqual(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex); } diff --git a/core/src/main/java/org/bouncycastle/util/test/SimpleTestResult.java b/core/src/main/java/org/bouncycastle/util/test/SimpleTestResult.java index e047ac819d..e62667fa10 100644 --- a/core/src/main/java/org/bouncycastle/util/test/SimpleTestResult.java +++ b/core/src/main/java/org/bouncycastle/util/test/SimpleTestResult.java @@ -57,7 +57,7 @@ public static TestResult failed( public static String failedMessage(String algorithm, String testName, String expected, String actual) { - StringBuffer sb = new StringBuffer(algorithm); + StringBuilder sb = new StringBuilder(algorithm); sb.append(" failing ").append(testName); sb.append(SEPARATOR).append(" expected: ").append(expected); sb.append(SEPARATOR).append(" got : ").append(actual); diff --git a/core/src/main/jdk1.1/java/security/SecurityUtil.java b/core/src/main/jdk1.1/java/security/SecurityUtil.java index 13c313cf69..fbc8d5a323 100644 --- a/core/src/main/jdk1.1/java/security/SecurityUtil.java +++ b/core/src/main/jdk1.1/java/security/SecurityUtil.java @@ -33,7 +33,7 @@ Provider getProvider() * * @return null if no algorithm found, an Implementation if it is. */ - static private Implementation getImplementation( + private static Implementation getImplementation( String baseName, String algorithm, Provider prov) diff --git a/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java b/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java index db7f61dbe3..1f511070b4 100644 --- a/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java +++ b/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java @@ -20,7 +20,6 @@ import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.pqc.asn1.CMCEPrivateKey; import org.bouncycastle.pqc.asn1.FalconPrivateKey; -import org.bouncycastle.pqc.asn1.McElieceCCA2PrivateKey; import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import org.bouncycastle.pqc.crypto.bike.BIKEParameters; @@ -49,7 +48,6 @@ import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAParameters; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPrivateKeyParameters; import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PrivateKeyParameters; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; @@ -159,10 +157,10 @@ else if (algOID.equals(NISTObjectIdentifiers.id_alg_ml_kem_512) || algOID.equals(NISTObjectIdentifiers.id_alg_ml_kem_768) || algOID.equals(NISTObjectIdentifiers.id_alg_ml_kem_1024)) { - ASN1OctetString kyberKey = ASN1OctetString.getInstance(keyInfo.parsePrivateKey()); - MLKEMParameters kyberParams = Utils.mlkemParamsLookup(algOID); + ASN1OctetString mlkemKey = ASN1OctetString.getInstance(keyInfo.parsePrivateKey()); + MLKEMParameters mlkemParams = Utils.mlkemParamsLookup(algOID); - return new MLKEMPrivateKeyParameters(kyberParams, kyberKey.getOctets()); + return new MLKEMPrivateKeyParameters(mlkemParams, mlkemKey.getOctets()); } else if (Utils.mldsaParams.containsKey(algOID)) { @@ -299,12 +297,6 @@ else if (algOID.on(BCObjectIdentifiers.pqc_kem_hqc)) return new HQCPrivateKeyParameters(hqcParams, keyEnc); } - else if (algOID.equals(PQCObjectIdentifiers.mcElieceCca2)) - { - McElieceCCA2PrivateKey mKey = McElieceCCA2PrivateKey.getInstance(keyInfo.parsePrivateKey()); - - return new McElieceCCA2PrivateKeyParameters(mKey.getN(), mKey.getK(), mKey.getField(), mKey.getGoppaPoly(), mKey.getP(), Utils.getDigestName(mKey.getDigest().getAlgorithm())); - } else { throw new RuntimeException("algorithm identifier in private key not recognised"); diff --git a/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java b/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java index 0363f6ef51..5f74f7e79a 100644 --- a/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java +++ b/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java @@ -14,7 +14,6 @@ import org.bouncycastle.pqc.asn1.CMCEPublicKey; import org.bouncycastle.pqc.asn1.FalconPrivateKey; import org.bouncycastle.pqc.asn1.FalconPublicKey; -import org.bouncycastle.pqc.asn1.McElieceCCA2PrivateKey; import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import org.bouncycastle.pqc.crypto.bike.BIKEPrivateKeyParameters; @@ -32,7 +31,6 @@ import org.bouncycastle.pqc.crypto.saber.SABERPrivateKeyParameters; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPrivateKeyParameters; import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PrivateKeyParameters; import org.bouncycastle.util.Pack; /** @@ -120,14 +118,6 @@ else if (privateKey instanceof CMCEPrivateKeyParameters) CMCEPrivateKey cmcePriv = new CMCEPrivateKey(0, params.getDelta(), params.getC(), params.getG(), params.getAlpha(), params.getS(), cmcePub); return new PrivateKeyInfo(algorithmIdentifier, cmcePriv, attributes); } - else if (privateKey instanceof McElieceCCA2PrivateKeyParameters) - { - McElieceCCA2PrivateKeyParameters priv = (McElieceCCA2PrivateKeyParameters)privateKey; - McElieceCCA2PrivateKey mcEliecePriv = new McElieceCCA2PrivateKey(priv.getN(), priv.getK(), priv.getField(), priv.getGoppaPoly(), priv.getP(), Utils.getAlgorithmIdentifier(priv.getDigest())); - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.mcElieceCca2); - - return new PrivateKeyInfo(algorithmIdentifier, mcEliecePriv); - } else if (privateKey instanceof FrodoPrivateKeyParameters) { FrodoPrivateKeyParameters params = (FrodoPrivateKeyParameters)privateKey; diff --git a/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java b/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java index 1329caa6d4..9d600575c6 100644 --- a/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java +++ b/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java @@ -19,8 +19,6 @@ import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers; import org.bouncycastle.pqc.asn1.CMCEPublicKey; -import org.bouncycastle.pqc.asn1.KyberPublicKey; -import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey; import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import org.bouncycastle.pqc.crypto.bike.BIKEParameters; @@ -47,7 +45,6 @@ import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAParameters; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPublicKeyParameters; import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPublicKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PublicKeyParameters; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; @@ -63,7 +60,6 @@ public class PublicKeyFactory { converters.put(PQCObjectIdentifiers.sphincs256, new SPHINCSConverter()); converters.put(PQCObjectIdentifiers.newHope, new NHConverter()); - converters.put(PQCObjectIdentifiers.mcElieceCca2, new McElieceCCA2Converter()); converters.put(BCObjectIdentifiers.mceliece348864_r3, new CMCEConverter()); converters.put(BCObjectIdentifiers.mceliece348864f_r3, new CMCEConverter()); converters.put(BCObjectIdentifiers.mceliece460896_r3, new CMCEConverter()); @@ -112,12 +108,12 @@ public class PublicKeyFactory converters.put(BCObjectIdentifiers.picnicl5full, new PicnicConverter()); converters.put(BCObjectIdentifiers.falcon_512, new FalconConverter()); converters.put(BCObjectIdentifiers.falcon_1024, new FalconConverter()); - converters.put(NISTObjectIdentifiers.id_alg_ml_kem_512, new KyberConverter()); - converters.put(NISTObjectIdentifiers.id_alg_ml_kem_768, new KyberConverter()); - converters.put(NISTObjectIdentifiers.id_alg_ml_kem_1024, new KyberConverter()); - converters.put(BCObjectIdentifiers.kyber512_aes, new KyberConverter()); - converters.put(BCObjectIdentifiers.kyber768_aes, new KyberConverter()); - converters.put(BCObjectIdentifiers.kyber1024_aes, new KyberConverter()); + converters.put(NISTObjectIdentifiers.id_alg_ml_kem_512, new MLKEMConverter()); + converters.put(NISTObjectIdentifiers.id_alg_ml_kem_768, new MLKEMConverter()); + converters.put(NISTObjectIdentifiers.id_alg_ml_kem_1024, new MLKEMConverter()); + converters.put(BCObjectIdentifiers.kyber512_aes, new MLKEMConverter()); + converters.put(BCObjectIdentifiers.kyber768_aes, new MLKEMConverter()); + converters.put(BCObjectIdentifiers.kyber1024_aes, new MLKEMConverter()); converters.put(NISTObjectIdentifiers.id_ml_dsa_44, new MLDSAConverter()); converters.put(NISTObjectIdentifiers.id_ml_dsa_65, new MLDSAConverter()); converters.put(NISTObjectIdentifiers.id_ml_dsa_87, new MLDSAConverter()); @@ -311,18 +307,6 @@ AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Obje } } - private static class McElieceCCA2Converter - extends SubjectPublicKeyInfoConverter - { - AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) - throws IOException - { - McElieceCCA2PublicKey mKey = McElieceCCA2PublicKey.getInstance(keyInfo.parsePublicKey()); - - return new McElieceCCA2PublicKeyParameters(mKey.getN(), mKey.getT(), mKey.getG(), Utils.getDigestName(mKey.getDigest().getAlgorithm())); - } - } - private static class FrodoConverter extends SubjectPublicKeyInfoConverter { @@ -367,26 +351,16 @@ AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Obje } } - private static class KyberConverter + private static class MLKEMConverter extends SubjectPublicKeyInfoConverter { AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) throws IOException { - MLKEMParameters kyberParameters = Utils.mlkemParamsLookup(keyInfo.getAlgorithm().getAlgorithm()); + MLKEMParameters mlkemParameters = Utils.mlkemParamsLookup(keyInfo.getAlgorithm().getAlgorithm()); - try - { - ASN1Primitive obj = keyInfo.parsePublicKey(); - KyberPublicKey kyberKey = KyberPublicKey.getInstance(obj); - - return new MLKEMPublicKeyParameters(kyberParameters, kyberKey.getT(), kyberKey.getRho()); - } - catch (Exception e) - { - // we're a raw encoding - return new MLKEMPublicKeyParameters(kyberParameters, keyInfo.getPublicKeyData().getOctets()); - } + // we're a raw encoding + return new MLKEMPublicKeyParameters(mlkemParameters, keyInfo.getPublicKeyData().getOctets()); } } diff --git a/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java b/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java index 579822a06e..fd56ccdd43 100644 --- a/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java +++ b/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java @@ -9,7 +9,6 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers; -import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey; import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import org.bouncycastle.pqc.crypto.bike.BIKEPublicKeyParameters; @@ -25,7 +24,6 @@ import org.bouncycastle.pqc.crypto.saber.SABERPublicKeyParameters; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPublicKeyParameters; import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPublicKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PublicKeyParameters; /** * Factory to create ASN.1 subject public key info objects from lightweight public keys. @@ -81,14 +79,6 @@ else if (publicKey instanceof CMCEPublicKeyParameters) return new SubjectPublicKeyInfo(algorithmIdentifier, encoding); } - else if (publicKey instanceof McElieceCCA2PublicKeyParameters) - { - McElieceCCA2PublicKeyParameters pub = (McElieceCCA2PublicKeyParameters)publicKey; - McElieceCCA2PublicKey mcEliecePub = new McElieceCCA2PublicKey(pub.getN(), pub.getT(), pub.getG(), Utils.getAlgorithmIdentifier(pub.getDigest())); - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.mcElieceCca2); - - return new SubjectPublicKeyInfo(algorithmIdentifier, mcEliecePub); - } else if (publicKey instanceof FrodoPublicKeyParameters) { FrodoPublicKeyParameters params = (FrodoPublicKeyParameters)publicKey; diff --git a/core/src/main/jdk1.2/org/bouncycastle/math/ec/ECCurve.java b/core/src/main/jdk1.2/org/bouncycastle/math/ec/ECCurve.java index fe62e8f1fd..8539b62c24 100644 --- a/core/src/main/jdk1.2/org/bouncycastle/math/ec/ECCurve.java +++ b/core/src/main/jdk1.2/org/bouncycastle/math/ec/ECCurve.java @@ -596,9 +596,14 @@ protected AbstractFp(BigInteger q) super(FiniteFields.getPrimeField(q)); } + public BigInteger getQ() + { + return getField().getCharacteristic(); + } + public boolean isValidFieldElement(BigInteger x) { - return x != null && x.signum() >= 0 && x.compareTo(this.getField().getCharacteristic()) < 0; + return x != null && x.signum() >= 0 && x.compareTo(this.getQ()) < 0; } public ECFieldElement randomFieldElement(SecureRandom r) @@ -607,7 +612,7 @@ public ECFieldElement randomFieldElement(SecureRandom r) * NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we * use the product of two independent elements to mitigate side-channels. */ - BigInteger p = this.getField().getCharacteristic(); + BigInteger p = this.getQ(); ECFieldElement fe1 = this.fromBigInteger(implRandomFieldElement(r, p)); ECFieldElement fe2 = this.fromBigInteger(implRandomFieldElement(r, p)); return fe1.multiply(fe2); @@ -619,7 +624,7 @@ public ECFieldElement randomFieldElementMult(SecureRandom r) * NOTE: BigInteger comparisons in the rejection sampling are not constant-time, so we * use the product of two independent elements to mitigate side-channels. */ - BigInteger p = this.getField().getCharacteristic(); + BigInteger p = this.getQ(); ECFieldElement fe1 = this.fromBigInteger(implRandomFieldElementMult(r, p)); ECFieldElement fe2 = this.fromBigInteger(implRandomFieldElementMult(r, p)); return fe1.multiply(fe2); @@ -702,12 +707,11 @@ public Fp(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger if (isInternal) { - this.q = q; knownQs.add(q); } else if (knownQs.contains(q) || validatedQs.contains(q)) { - this.q = q; + // No need to validate } else { @@ -727,10 +731,9 @@ else if (knownQs.contains(q) || validatedQs.contains(q)) } validatedQs.add(q); - - this.q = q; } + this.q = q; this.r = ECFieldElement.Fp.calculateResidue(q); this.infinity = new ECPoint.Fp(this, null, null); diff --git a/core/src/main/jdk1.4/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/core/src/main/jdk1.4/org/bouncycastle/asn1/ASN1ObjectIdentifier.java index addc076e51..816207b9f1 100644 --- a/core/src/main/jdk1.4/org/bouncycastle/asn1/ASN1ObjectIdentifier.java +++ b/core/src/main/jdk1.4/org/bouncycastle/asn1/ASN1ObjectIdentifier.java @@ -105,7 +105,7 @@ public static ASN1ObjectIdentifier getInstance(ASN1TaggedObject taggedObject, bo } } - return (ASN1ObjectIdentifier)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1ObjectIdentifier)TYPE.getContextTagged(taggedObject, explicit); } public static ASN1ObjectIdentifier tryFromID(String identifier) diff --git a/core/src/main/jdk1.4/org/bouncycastle/asn1/ASN1RelativeOID.java b/core/src/main/jdk1.4/org/bouncycastle/asn1/ASN1RelativeOID.java index eb8e42956f..51a75353fe 100644 --- a/core/src/main/jdk1.4/org/bouncycastle/asn1/ASN1RelativeOID.java +++ b/core/src/main/jdk1.4/org/bouncycastle/asn1/ASN1RelativeOID.java @@ -73,7 +73,7 @@ else if (obj instanceof byte[]) public static ASN1RelativeOID getInstance(ASN1TaggedObject taggedObject, boolean explicit) { - return (ASN1RelativeOID)TYPE.getContextInstance(taggedObject, explicit); + return (ASN1RelativeOID)TYPE.getContextTagged(taggedObject, explicit); } public static ASN1RelativeOID tryFromID(String identifier) diff --git a/core/src/main/jdk1.4/org/bouncycastle/asn1/x500/style/IETFUtils.java b/core/src/main/jdk1.4/org/bouncycastle/asn1/x500/style/IETFUtils.java new file mode 100644 index 0000000000..21c33697d3 --- /dev/null +++ b/core/src/main/jdk1.4/org/bouncycastle/asn1/x500/style/IETFUtils.java @@ -0,0 +1,588 @@ +package org.bouncycastle.asn1.x500.style; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1String; +import org.bouncycastle.asn1.ASN1UniversalString; +import org.bouncycastle.asn1.x500.AttributeTypeAndValue; +import org.bouncycastle.asn1.x500.RDN; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x500.X500NameStyle; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Hex; + +public class IETFUtils +{ + private static String unescape(String elt) + { + if (elt.length() == 0) + { + return elt; + } + if (elt.indexOf('\\') < 0 && elt.indexOf('"') < 0) + { + return elt.trim(); + } + + boolean escaped = false; + boolean quoted = false; + StringBuffer buf = new StringBuffer(elt.length()); + int start = 0; + + // if it's an escaped hash string and not an actual encoding in string form + // we need to leave it escaped. + if (elt.charAt(0) == '\\') + { + if (elt.charAt(1) == '#') + { + start = 2; + buf.append("\\#"); + } + } + + boolean nonWhiteSpaceEncountered = false; + int lastEscaped = 0; + char hex1 = 0; + + for (int i = start; i != elt.length(); i++) + { + char c = elt.charAt(i); + + if (c != ' ') + { + nonWhiteSpaceEncountered = true; + } + + if (c == '"') + { + if (!escaped) + { + quoted = !quoted; + } + else + { + buf.append(c); + escaped = false; + } + } + else if (c == '\\' && !(escaped || quoted)) + { + escaped = true; + lastEscaped = buf.length(); + } + else + { + if (c == ' ' && !escaped && !nonWhiteSpaceEncountered) + { + continue; + } + if (escaped && isHexDigit(c)) + { + if (hex1 != 0) + { + buf.append((char)(convertHex(hex1) * 16 + convertHex(c))); + escaped = false; + hex1 = 0; + continue; + } + hex1 = c; + continue; + } + buf.append(c); + escaped = false; + } + } + + if (buf.length() > 0) + { + while (buf.charAt(buf.length() - 1) == ' ' && lastEscaped != (buf.length() - 1)) + { + buf.setLength(buf.length() - 1); + } + } + + return buf.toString(); + } + + private static boolean isHexDigit(char c) + { + return ('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'); + } + + private static int convertHex(char c) + { + if ('0' <= c && c <= '9') + { + return c - '0'; + } + if ('a' <= c && c <= 'f') + { + return c - 'a' + 10; + } + return c - 'A' + 10; + } + + public static RDN[] rDNsFromString(String name, X500NameStyle x500Style) + { + X500NameBuilder builder = new X500NameBuilder(x500Style); + + addRDNs(builder, new X500NameTokenizer(name)); + + return builder.buildRDNs(); + } + + private static void addRDNs(X500NameBuilder builder, X500NameTokenizer tokenizer) + { + String token; + while ((token = tokenizer.nextToken()) != null) + { + if (token.indexOf('+') >= 0) + { + addMultiValuedRDN(builder, new X500NameTokenizer(token, '+')); + } + else + { + addRDN(builder, token); + } + } + } + + private static void addMultiValuedRDN(X500NameBuilder builder, X500NameTokenizer tokenizer) + { + String token = tokenizer.nextToken(); + if (token == null) + { + throw new IllegalArgumentException("badly formatted directory string"); + } + + if (!tokenizer.hasMoreTokens()) + { + addRDN(builder, token); + return; + } + + Vector oids = new Vector(); + Vector values = new Vector(); + + X500NameStyle style = builder.getStyle(); + do + { + collectAttributeTypeAndValue(style, oids, values, token); + token = tokenizer.nextToken(); + } + while (token != null); + + builder.addMultiValuedRDN(toOIDArray(oids), toValueArray(values)); + } + + private static void addRDN(X500NameBuilder builder, String token) + { + X500NameTokenizer tokenizer = new X500NameTokenizer(token, '='); + + String typeToken = nextToken(tokenizer, true); + String valueToken = nextToken(tokenizer, false); + + ASN1ObjectIdentifier oid = builder.getStyle().attrNameToOID(typeToken.trim()); + String value = unescape(valueToken); + + builder.addRDN(oid, value); + } + + private static void collectAttributeTypeAndValue(X500NameStyle style, Vector oids, Vector values, String token) + { + X500NameTokenizer tokenizer = new X500NameTokenizer(token, '='); + + String typeToken = nextToken(tokenizer, true); + String valueToken = nextToken(tokenizer, false); + + ASN1ObjectIdentifier oid = style.attrNameToOID(typeToken.trim()); + String value = unescape(valueToken); + + oids.addElement(oid); + values.addElement(value); + } + + private static String nextToken(X500NameTokenizer tokenizer, boolean expectMoreTokens) + { + String token = tokenizer.nextToken(); + if (token == null || tokenizer.hasMoreTokens() != expectMoreTokens) + { + throw new IllegalArgumentException("badly formatted directory string"); + } + return token; + } + + private static String[] toValueArray(Vector values) + { + String[] tmp = new String[values.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = (String)values.elementAt(i); + } + + return tmp; + } + + private static ASN1ObjectIdentifier[] toOIDArray(Vector oids) + { + ASN1ObjectIdentifier[] tmp = new ASN1ObjectIdentifier[oids.size()]; + + for (int i = 0; i != tmp.length; i++) + { + tmp[i] = (ASN1ObjectIdentifier)oids.elementAt(i); + } + + return tmp; + } + + public static String[] findAttrNamesForOID( + ASN1ObjectIdentifier oid, + Hashtable lookup) + { + int count = 0; + for (Enumeration en = lookup.elements(); en.hasMoreElements();) + { + if (oid.equals(en.nextElement())) + { + count++; + } + } + + String[] aliases = new String[count]; + count = 0; + + for (Enumeration en = lookup.keys(); en.hasMoreElements();) + { + String key = (String)en.nextElement(); + if (oid.equals(lookup.get(key))) + { + aliases[count++] = key; + } + } + + return aliases; + } + + public static ASN1ObjectIdentifier decodeAttrName(String name, Hashtable lookUp) + { + if (name.regionMatches(true, 0, "OID.", 0, 4)) + { + return new ASN1ObjectIdentifier(name.substring(4)); + } + + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.tryFromID(name); + if (oid != null) + { + return oid; + } + + oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name)); + if (oid != null) + { + return oid; + } + + throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name"); + } + + public static ASN1Encodable valueFromHexString( + String str, + int off) + throws IOException + { + byte[] data = new byte[(str.length() - off) / 2]; + for (int index = 0; index != data.length; index++) + { + char left = str.charAt((index * 2) + off); + char right = str.charAt((index * 2) + off + 1); + + data[index] = (byte)((convertHex(left) << 4) | convertHex(right)); + } + + return ASN1Primitive.fromByteArray(data); + } + + public static void appendRDN( + StringBuffer buf, + RDN rdn, + Hashtable oidSymbols) + { + if (rdn.isMultiValued()) + { + AttributeTypeAndValue[] atv = rdn.getTypesAndValues(); + boolean firstAtv = true; + + for (int j = 0; j != atv.length; j++) + { + if (firstAtv) + { + firstAtv = false; + } + else + { + buf.append('+'); + } + + IETFUtils.appendTypeAndValue(buf, atv[j], oidSymbols); + } + } + else + { + if (rdn.getFirst() != null) + { + IETFUtils.appendTypeAndValue(buf, rdn.getFirst(), oidSymbols); + } + } + } + + public static void appendTypeAndValue( + StringBuffer buf, + AttributeTypeAndValue typeAndValue, + Hashtable oidSymbols) + { + String sym = (String)oidSymbols.get(typeAndValue.getType()); + + if (sym != null) + { + buf.append(sym); + } + else + { + buf.append(typeAndValue.getType().getId()); + } + + buf.append('='); + + buf.append(valueToString(typeAndValue.getValue())); + } + + public static String valueToString(ASN1Encodable value) + { + StringBuffer vBuf = new StringBuffer(); + + if (value instanceof ASN1String && !(value instanceof ASN1UniversalString)) + { + String v = ((ASN1String)value).getString(); + if (v.length() > 0 && v.charAt(0) == '#') + { + vBuf.append('\\'); + } + + vBuf.append(v); + } + else + { + try + { + vBuf.append('#'); + // -DM Hex.toHexString + vBuf.append(Hex.toHexString(value.toASN1Primitive().getEncoded(ASN1Encoding.DER))); + } + catch (IOException e) + { + throw new IllegalArgumentException("Other value has no encoded form"); + } + } + + int end = vBuf.length(); + int index = 0; + + if (vBuf.length() >= 2 && vBuf.charAt(0) == '\\' && vBuf.charAt(1) == '#') + { + index += 2; + } + + while (index != end) + { + switch (vBuf.charAt(index)) + { + case ',': + case '"': + case '\\': + case '+': + case '=': + case '<': + case '>': + case ';': + { + vBuf.insert(index, "\\"); + index += 2; + ++end; + break; + } + default: + { + ++index; + break; + } + } + } + + int start = 0; + if (vBuf.length() > 0) + { + while (vBuf.length() > start && vBuf.charAt(start) == ' ') + { + vBuf.insert(start, "\\"); + start += 2; + } + } + + int endBuf = vBuf.length() - 1; + + while (endBuf >= start && vBuf.charAt(endBuf) == ' ') + { + vBuf.insert(endBuf, '\\'); + endBuf--; + } + + return vBuf.toString(); + } + + public static String canonicalize(String s) + { + if (s.length() > 0 && s.charAt(0) == '#') + { + ASN1Primitive obj = decodeObject(s); + if (obj instanceof ASN1String) + { + s = ((ASN1String)obj).getString(); + } + } + + s = Strings.toLowerCase(s); + + int length = s.length(); + if (length < 2) + { + return s; + } + + int start = 0, last = length - 1; + while (start < last && s.charAt(start) == '\\' && s.charAt(start + 1) == ' ') + { + start += 2; + } + + int end = last, first = start + 1; + while (end > first && s.charAt(end - 1) == '\\' && s.charAt(end) == ' ') + { + end -= 2; + } + + if (start > 0 || end < last) + { + s = s.substring(start, end + 1); + } + + return stripInternalSpaces(s); + } + + public static String canonicalString(ASN1Encodable value) + { + return canonicalize(valueToString(value)); + } + + private static ASN1Primitive decodeObject(String oValue) + { + try + { + return ASN1Primitive.fromByteArray(Hex.decodeStrict(oValue, 1, oValue.length() - 1)); + } + catch (IOException e) + { + throw new IllegalStateException("unknown encoding in name: " + e); + } + } + + public static String stripInternalSpaces( + String str) + { + if (str.indexOf(" ") < 0) + { + return str; + } + + StringBuffer res = new StringBuffer(); + + char c1 = str.charAt(0); + res.append(c1); + + for (int k = 1; k < str.length(); k++) + { + char c2 = str.charAt(k); + if (!(c1 == ' ' && c2 == ' ')) + { + res.append(c2); + c1 = c2; + } + } + + return res.toString(); + } + + public static boolean rDNAreEqual(RDN rdn1, RDN rdn2) + { + if (rdn1.size() != rdn2.size()) + { + return false; + } + + AttributeTypeAndValue[] atvs1 = rdn1.getTypesAndValues(); + AttributeTypeAndValue[] atvs2 = rdn2.getTypesAndValues(); + + if (atvs1.length != atvs2.length) + { + return false; + } + + for (int i = 0; i != atvs1.length; i++) + { + if (!atvAreEqual(atvs1[i], atvs2[i])) + { + return false; + } + } + + return true; + } + + private static boolean atvAreEqual(AttributeTypeAndValue atv1, AttributeTypeAndValue atv2) + { + if (atv1 == atv2) + { + return true; + } + + if (null == atv1 || null == atv2) + { + return false; + } + + ASN1ObjectIdentifier o1 = atv1.getType(); + ASN1ObjectIdentifier o2 = atv2.getType(); + + if (!o1.equals(o2)) + { + return false; + } + + String v1 = canonicalString(atv1.getValue()); + String v2 = canonicalString(atv2.getValue()); + + if (!v1.equals(v2)) + { + return false; + } + + return true; + } +} diff --git a/core/src/main/jdk1.4/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java b/core/src/main/jdk1.4/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java deleted file mode 100644 index 23f0ee7fb6..0000000000 --- a/core/src/main/jdk1.4/org/bouncycastle/crypto/engines/AEADBufferBaseEngine.java +++ /dev/null @@ -1,420 +0,0 @@ -package org.bouncycastle.crypto.engines; - -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.OutputLengthException; -import org.bouncycastle.util.Arrays; - -abstract class AEADBufferBaseEngine - extends AEADBaseEngine -{ - protected static final int UNINITIALIZED = 0; - protected static final int ENCINIT = 1; - protected static final int ENCAAD = 2; - protected static final int ENCDATA = 3; - protected static final int ENCFINAL = 4; - protected static final int DECINIT = 5; - protected static final int DECAAD = 6; - protected static final int DECDATA = 7; - protected static final int DECFINAL = 8; - - protected static final State Uninitialized = new State(UNINITIALIZED); - protected static final State EncInit = new State(ENCINIT); - protected static final State EncAad = new State(ENCAAD); - protected static final State EncData = new State(ENCDATA); - protected static final State EncFinal = new State(ENCFINAL); - protected static final State DecInit = new State(DECINIT); - protected static final State DecAad = new State(DECAAD); - protected static final State DecData = new State(DECDATA); - protected static final State DecFinal = new State(DECFINAL); - - protected static class State - { - int ord; - - private State(int ord) - { - this.ord = ord; - } - } - - protected byte[] m_buf; - protected byte[] m_aad; - protected int m_bufPos; - protected int m_aadPos; - protected boolean aadFinished; - protected boolean initialised = false; - protected int AADBufferSize; - protected int BlockSize; - protected State m_state = Uninitialized; - - @Override - public void processAADByte(byte input) - { - checkAAD(); - if (m_aadPos == AADBufferSize) - { - processBufferAAD(m_aad, 0); - m_aadPos = 0; - } - m_aad[m_aadPos++] = input; - } - - @Override - public void processAADBytes(byte[] input, int inOff, int len) - { - if ((inOff + len) > input.length) - { - throw new DataLengthException("input buffer too short"); - } - // Don't enter AAD state until we actually get input - if (len <= 0) - { - return; - } - - checkAAD(); - if (m_aadPos > 0) - { - int available = AADBufferSize - m_aadPos; - if (len <= available) - { - System.arraycopy(input, inOff, m_aad, m_aadPos, len); - m_aadPos += len; - return; - } - - System.arraycopy(input, inOff, m_aad, m_aadPos, available); - inOff += available; - len -= available; - - processBufferAAD(m_aad, 0); - m_aadPos = 0; - } - while (len > AADBufferSize) - { - processBufferAAD(input, inOff); - inOff += AADBufferSize; - len -= AADBufferSize; - } - System.arraycopy(input, inOff, m_aad, m_aadPos, len); - m_aadPos += len; - } - - @Override - public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) - throws DataLengthException - { - if (inOff + len > input.length) - { - throw new DataLengthException("input buffer too short"); - } - - boolean forEncryption = checkData(); - - int resultLength = 0; - - if (forEncryption) - { - if (m_bufPos > 0) - { - int available = BlockSize - m_bufPos; - if (len <= available) - { - System.arraycopy(input, inOff, m_buf, m_bufPos, len); - m_bufPos += len; - return 0; - } - - System.arraycopy(input, inOff, m_buf, m_bufPos, available); - inOff += available; - len -= available; - - validateAndProcessBuffer(m_buf, 0, output, outOff); - resultLength = BlockSize; - //m_bufPos = 0; - } - - while (len > BlockSize) - { - validateAndProcessBuffer(input, inOff, output, outOff + resultLength); - inOff += BlockSize; - len -= BlockSize; - resultLength += BlockSize; - } - } - else - { - int available = BlockSize + MAC_SIZE - m_bufPos; - if (len <= available) - { - System.arraycopy(input, inOff, m_buf, m_bufPos, len); - m_bufPos += len; - return 0; - } - if (BlockSize >= MAC_SIZE) - { - if (m_bufPos > BlockSize) - { - validateAndProcessBuffer(m_buf, 0, output, outOff); - m_bufPos -= BlockSize; - System.arraycopy(m_buf, BlockSize, m_buf, 0, m_bufPos); - resultLength = BlockSize; - - available += BlockSize; - if (len <= available) - { - System.arraycopy(input, inOff, m_buf, m_bufPos, len); - m_bufPos += len; - return resultLength; - } - } - - available = BlockSize - m_bufPos; - System.arraycopy(input, inOff, m_buf, m_bufPos, available); - inOff += available; - len -= available; - validateAndProcessBuffer(m_buf, 0, output, outOff + resultLength); - resultLength += BlockSize; - //m_bufPos = 0; - } - else - { - while (m_bufPos > BlockSize && len + m_bufPos > BlockSize + MAC_SIZE) - { - validateAndProcessBuffer(m_buf, resultLength, output, outOff + resultLength); - m_bufPos -= BlockSize; - resultLength += BlockSize; - } - if (m_bufPos != 0) - { - System.arraycopy(m_buf, resultLength, m_buf, 0, m_bufPos); - if (m_bufPos + len > BlockSize + MAC_SIZE) - { - available = Math.max(BlockSize - m_bufPos, 0); - System.arraycopy(input, inOff, m_buf, m_bufPos, available); - inOff += available; - validateAndProcessBuffer(m_buf, 0, output, outOff + resultLength); - resultLength += BlockSize; - len -= available; - } - else - { - System.arraycopy(input, inOff, m_buf, m_bufPos, len); - m_bufPos += len; - return resultLength; - } - } - } - while (len > BlockSize + MAC_SIZE) - { - validateAndProcessBuffer(input, inOff, output, outOff + resultLength); - inOff += BlockSize; - len -= BlockSize; - resultLength += BlockSize; - } - } - - System.arraycopy(input, inOff, m_buf, 0, len); - m_bufPos = len; - - return resultLength; - } - - @Override - public int doFinal(byte[] output, int outOff) - throws IllegalStateException, InvalidCipherTextException - { - boolean forEncryption = checkData(); - int resultLength; - if (forEncryption) - { - resultLength = m_bufPos + MAC_SIZE; - } - else - { - if (m_bufPos < MAC_SIZE) - { - throw new InvalidCipherTextException("data too short"); - } - - m_bufPos -= MAC_SIZE; - - resultLength = m_bufPos; - } - - if (outOff > output.length - resultLength) - { - throw new OutputLengthException("output buffer too short"); - } - processFinalBlock(output, outOff); - if (forEncryption) - { - System.arraycopy(mac, 0, output, outOff + resultLength - MAC_SIZE, MAC_SIZE); - } - else - { - if (!Arrays.constantTimeAreEqual(MAC_SIZE, mac, 0, m_buf, m_bufPos)) - { - throw new InvalidCipherTextException(algorithmName + " mac does not match"); - } - } - reset(!forEncryption); - return resultLength; - } - - public int getBlockSize() - { - return BlockSize; - } - - public int getUpdateOutputSize(int len) - { - // The -1 is to account for the lazy processing of a full buffer - int total = Math.max(0, len) - 1; - - switch (m_state.ord) - { - case DECINIT: - case DECAAD: - total = Math.max(0, total - MAC_SIZE); - break; - case DECDATA: - case DECFINAL: - total = Math.max(0, total + m_bufPos - MAC_SIZE); - break; - case ENCDATA: - case ENCFINAL: - total = Math.max(0, total + m_bufPos); - break; - default: - break; - } - return total - total % BlockSize; - } - - public int getOutputSize(int len) - { - int total = Math.max(0, len); - - switch (m_state.ord) - { - case DECINIT: - case DECAAD: - return Math.max(0, total - MAC_SIZE); - case DECDATA: - case DECFINAL: - return Math.max(0, total + m_bufPos - MAC_SIZE); - case ENCDATA: - case ENCFINAL: - return total + m_bufPos + MAC_SIZE; - default: - return total + MAC_SIZE; - } - } - - protected void checkAAD() - { - switch (m_state.ord) - { - case DECINIT: - m_state = DecAad; - break; - case ENCINIT: - m_state = EncAad; - break; - case DECAAD: - case ENCAAD: - break; - case ENCFINAL: - throw new IllegalStateException(getAlgorithmName() + " cannot be reused for encryption"); - default: - throw new IllegalStateException(getAlgorithmName() + " needs to be initialized"); - } - } - - protected boolean checkData() - { - switch (m_state.ord) - { - case DECINIT: - case DECAAD: - finishAAD(DecData); - return false; - case ENCINIT: - case ENCAAD: - finishAAD(EncData); - return true; - case DECDATA: - return false; - case ENCDATA: - return true; - case ENCFINAL: - throw new IllegalStateException(getAlgorithmName() + " cannot be reused for encryption"); - default: - throw new IllegalStateException(getAlgorithmName() + " needs to be initialized"); - } - } - - private void finishAAD(State nextState) - { - // State indicates whether we ever received AAD - switch (m_state.ord) - { - case DECAAD: - case ENCAAD: - { - processFinalAAD(); - break; - } - default: - break; - } - - m_aadPos = 0; - m_state = nextState; - } - - protected void bufferReset() - { - Arrays.fill(m_buf, (byte)0); - Arrays.fill(m_aad, (byte)0); - m_bufPos = 0; - m_aadPos = 0; - switch (m_state.ord) - { - case DECINIT: - case ENCINIT: - break; - case DECAAD: - case DECDATA: - case DECFINAL: - m_state = DecInit; - break; - case ENCAAD: - case ENCDATA: - case ENCFINAL: - m_state = EncFinal; - return; - default: - throw new IllegalStateException(getAlgorithmName() + " needs to be initialized"); - } - } - - protected void validateAndProcessBuffer(byte[] input, int inOff, byte[] output, int outOff) - { - if (outOff > output.length - BlockSize) - { - throw new OutputLengthException("output buffer too short"); - } - processBuffer(input, inOff, output, outOff); - } - - protected abstract void processFinalBlock(byte[] output, int outOff); - - protected abstract void processBufferAAD(byte[] input, int inOff); - - protected abstract void processFinalAAD(); - - protected abstract void processBuffer(byte[] input, int inOff, byte[] output, int outOff); -} diff --git a/core/src/main/jdk1.4/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java b/core/src/main/jdk1.4/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java new file mode 100644 index 0000000000..a4b3b89fb6 --- /dev/null +++ b/core/src/main/jdk1.4/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java @@ -0,0 +1,218 @@ +package org.bouncycastle.crypto.util; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.HashSet; +import java.util.Set; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.RSAPublicKey; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.DSAParameter; +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.X9ObjectIdentifiers; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.DSAParameters; +import org.bouncycastle.crypto.params.DSAPublicKeyParameters; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECGOST3410Parameters; +import org.bouncycastle.crypto.params.ECNamedDomainParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +import org.bouncycastle.crypto.params.Ed448PublicKeyParameters; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.crypto.params.X25519PublicKeyParameters; +import org.bouncycastle.crypto.params.X448PublicKeyParameters; +import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers; +import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers; +import org.bouncycastle.util.Arrays; + +/** + * Factory to create ASN.1 subject public key info objects from lightweight public keys. + */ +public class SubjectPublicKeyInfoFactory +{ + private static final byte tag_OctetString = (byte)0x04; + private static Set cryptoProOids = new HashSet(5); + + static + { + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A); + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_B); + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_C); + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchA); + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchB); + } + + private SubjectPublicKeyInfoFactory() + { + + } + + /** + * Create a SubjectPublicKeyInfo public key. + * + * @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 + { + if (publicKey instanceof RSAKeyParameters) + { + RSAKeyParameters pub = (RSAKeyParameters)publicKey; + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPublicKey(pub.getModulus(), pub.getExponent())); + } + else if (publicKey instanceof DSAPublicKeyParameters) + { + DSAPublicKeyParameters pub = (DSAPublicKeyParameters)publicKey; + + DSAParameter params = null; + DSAParameters dsaParams = pub.getParameters(); + if (dsaParams != null) + { + params = new DSAParameter(dsaParams.getP(), dsaParams.getQ(), dsaParams.getG()); + } + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, params), new ASN1Integer(pub.getY())); + } + else if (publicKey instanceof ECPublicKeyParameters) + { + ECPublicKeyParameters pub = (ECPublicKeyParameters)publicKey; + ECDomainParameters domainParams = pub.getParameters(); + ASN1Encodable params; + + if (domainParams == null) + { + params = new X962Parameters(DERNull.INSTANCE); // Implicitly CA + } + else if (domainParams instanceof ECGOST3410Parameters) + { + ECGOST3410Parameters gostParams = (ECGOST3410Parameters)domainParams; + + BigInteger bX = pub.getQ().getAffineXCoord().toBigInteger(); + BigInteger bY = pub.getQ().getAffineYCoord().toBigInteger(); + + params = new GOST3410PublicKeyAlgParameters(gostParams.getPublicKeyParamSet(), gostParams.getDigestParamSet()); + + int encKeySize; + int offset; + ASN1ObjectIdentifier algIdentifier; + + + if (cryptoProOids.contains(gostParams.getPublicKeyParamSet())) + { + encKeySize = 64; + offset = 32; + algIdentifier = CryptoProObjectIdentifiers.gostR3410_2001; + } + else + { + boolean is512 = (bX.bitLength() > 256); + if (is512) + { + encKeySize = 128; + offset = 64; + algIdentifier = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512; + } + else + { + encKeySize = 64; + offset = 32; + algIdentifier = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256; + } + } + + byte[] encKey = new byte[encKeySize]; + extractBytes(encKey, encKeySize / 2, 0, bX); + extractBytes(encKey, encKeySize / 2, offset, bY); + + try + { + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(algIdentifier, params), new DEROctetString(encKey)); + } + catch (IOException e) + { + return null; + } + } + else if (domainParams instanceof ECNamedDomainParameters) + { + params = new X962Parameters(((ECNamedDomainParameters)domainParams).getName()); + } + else + { + X9ECParameters ecP = new X9ECParameters( + domainParams.getCurve(), + // TODO Support point compression + new X9ECPoint(domainParams.getG(), false), + domainParams.getN(), + domainParams.getH(), + domainParams.getSeed()); + + params = new X962Parameters(ecP); + } + + // TODO Support point compression + byte[] pubKeyOctets = pub.getQ().getEncoded(false); + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), pubKeyOctets); + } + else if (publicKey instanceof X448PublicKeyParameters) + { + X448PublicKeyParameters key = (X448PublicKeyParameters)publicKey; + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448), key.getEncoded()); + } + else if (publicKey instanceof X25519PublicKeyParameters) + { + X25519PublicKeyParameters key = (X25519PublicKeyParameters)publicKey; + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519), key.getEncoded()); + } + else if (publicKey instanceof Ed448PublicKeyParameters) + { + Ed448PublicKeyParameters key = (Ed448PublicKeyParameters)publicKey; + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448), key.getEncoded()); + } + else if (publicKey instanceof Ed25519PublicKeyParameters) + { + Ed25519PublicKeyParameters key = (Ed25519PublicKeyParameters)publicKey; + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), key.getEncoded()); + } + else + { + throw new IOException("key parameters not recognized"); + } + } + + private static void extractBytes(byte[] encKey, int size, int offSet, BigInteger bI) + { + byte[] val = bI.toByteArray(); + if (val.length < size) + { + byte[] tmp = new byte[size]; + System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length); + val = tmp; + } + + for (int i = 0; i != size; i++) + { + encKey[offSet + i] = val[val.length - 1 - i]; + } + } +} diff --git a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java index df14bcd4e1..1e4fb817ae 100644 --- a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java +++ b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java @@ -20,7 +20,6 @@ import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.pqc.asn1.CMCEPrivateKey; import org.bouncycastle.pqc.asn1.FalconPrivateKey; -import org.bouncycastle.pqc.asn1.McElieceCCA2PrivateKey; import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import org.bouncycastle.pqc.asn1.SPHINCSPLUSPrivateKey; @@ -43,6 +42,7 @@ import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mlkem.MLKEMPublicKeyParameters; import org.bouncycastle.pqc.crypto.newhope.NHPrivateKeyParameters; import org.bouncycastle.pqc.crypto.ntru.NTRUParameters; import org.bouncycastle.pqc.crypto.ntru.NTRUPrivateKeyParameters; @@ -59,7 +59,6 @@ import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPrivateKeyParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusPrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PrivateKeyParameters; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; @@ -147,22 +146,12 @@ else if (algOID.on(BCObjectIdentifiers.sphincsPlus) || algOID.on(BCObjectIdentif return new SPHINCSPlusPrivateKeyParameters(spParams, ASN1OctetString.getInstance(obj).getOctets()); } } - else if (Utils.shldsaParams.containsKey(algOID)) + else if (Utils.slhdsaParams.containsKey(algOID)) { SLHDSAParameters spParams = Utils.slhdsaParamsLookup(algOID); + ASN1OctetString slhdsaKey = parseOctetString(keyInfo.getPrivateKey(), spParams.getN() * 4); - ASN1Encodable obj = keyInfo.parsePrivateKey(); - if (obj instanceof ASN1Sequence) - { - SPHINCSPLUSPrivateKey spKey = SPHINCSPLUSPrivateKey.getInstance(obj); - SPHINCSPLUSPublicKey publicKey = spKey.getPublicKey(); - return new SLHDSAPrivateKeyParameters(spParams, spKey.getSkseed(), spKey.getSkprf(), - publicKey.getPkseed(), publicKey.getPkroot()); - } - else - { - return new SLHDSAPrivateKeyParameters(spParams, ASN1OctetString.getInstance(obj).getOctets()); - } + return new SLHDSAPrivateKeyParameters(spParams, slhdsaKey.getOctets()); } else if (algOID.on(BCObjectIdentifiers.picnic)) { @@ -203,10 +192,37 @@ else if (algOID.equals(NISTObjectIdentifiers.id_alg_ml_kem_512) || algOID.equals(NISTObjectIdentifiers.id_alg_ml_kem_768) || algOID.equals(NISTObjectIdentifiers.id_alg_ml_kem_1024)) { - ASN1OctetString kyberKey = ASN1OctetString.getInstance(keyInfo.parsePrivateKey()); - MLKEMParameters kyberParams = Utils.mlkemParamsLookup(algOID); + ASN1Primitive mlkemKey = parsePrimitiveString(keyInfo.getPrivateKey(), 64); + MLKEMParameters mlkemParams = Utils.mlkemParamsLookup(algOID); + + MLKEMPublicKeyParameters pubParams = null; + if (keyInfo.getPublicKeyData() != null) + { + pubParams = PublicKeyFactory.MLKEMKeyConverter.getPublicKeyParams(mlkemParams, keyInfo.getPublicKeyData()); + } + + if (mlkemKey instanceof ASN1OctetString) + { + // TODO This should be explicitly EXPANDED_KEY or SEED (tag already removed) but is length-flexible + return new MLKEMPrivateKeyParameters(mlkemParams, ((ASN1OctetString)mlkemKey).getOctets(), pubParams); + } + else if (mlkemKey instanceof ASN1Sequence) + { + ASN1Sequence keySeq = (ASN1Sequence)mlkemKey; + byte[] seed = ASN1OctetString.getInstance(keySeq.getObjectAt(0)).getOctets(); + byte[] encoding = ASN1OctetString.getInstance(keySeq.getObjectAt(1)).getOctets(); + + // TODO This should only allow seed but is length-flexible + MLKEMPrivateKeyParameters mlkemPriv = new MLKEMPrivateKeyParameters(mlkemParams, seed, pubParams); + if (!Arrays.constantTimeAreEqual(mlkemPriv.getEncoded(), encoding)) + { + throw new IllegalArgumentException("inconsistent " + mlkemParams.getName() + " private key"); + } + + return mlkemPriv; + } - return new MLKEMPrivateKeyParameters(kyberParams, kyberKey.getOctets()); + throw new IllegalArgumentException("invalid " + mlkemParams.getName() + " private key"); } else if (algOID.on(BCObjectIdentifiers.pqc_kem_ntrulprime)) { @@ -235,58 +251,37 @@ else if (algOID.on(BCObjectIdentifiers.pqc_kem_sntruprime)) } else if (Utils.mldsaParams.containsKey(algOID)) { - ASN1Encodable keyObj = keyInfo.parsePrivateKey(); - MLDSAParameters spParams = Utils.mldsaParamsLookup(algOID); + ASN1Encodable mldsaKey = parsePrimitiveString(keyInfo.getPrivateKey(), 32); + MLDSAParameters mldsaParams = Utils.mldsaParamsLookup(algOID); - if (keyObj instanceof ASN1Sequence) + MLDSAPublicKeyParameters pubParams = null; + if (keyInfo.getPublicKeyData() != null) { - ASN1Sequence keyEnc = ASN1Sequence.getInstance(keyObj); - - int version = ASN1Integer.getInstance(keyEnc.getObjectAt(0)).intValueExact(); - if (version != 0) - { - throw new IOException("unknown private key version: " + version); - } - - if (keyInfo.getPublicKeyData() != null) - { - MLDSAPublicKeyParameters pubParams = PublicKeyFactory.MLDSAConverter.getPublicKeyParams(spParams, keyInfo.getPublicKeyData()); + pubParams = PublicKeyFactory.MLDSAConverter.getPublicKeyParams(mldsaParams, keyInfo.getPublicKeyData()); + } - return new MLDSAPrivateKeyParameters(spParams, - ASN1BitString.getInstance(keyEnc.getObjectAt(1)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(2)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(3)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(4)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(5)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(6)).getOctets(), - pubParams.getT1()); // encT1 - } - else - { - return new MLDSAPrivateKeyParameters(spParams, - ASN1BitString.getInstance(keyEnc.getObjectAt(1)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(2)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(3)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(4)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(5)).getOctets(), - ASN1BitString.getInstance(keyEnc.getObjectAt(6)).getOctets(), - null); - } + if (mldsaKey instanceof ASN1OctetString) + { + // TODO This should be explicitly EXPANDED_KEY or SEED (tag already removed) but is length-flexible + return new MLDSAPrivateKeyParameters(mldsaParams, ((ASN1OctetString)mldsaKey).getOctets(), pubParams); } - else if (keyObj instanceof DEROctetString) + else if (mldsaKey instanceof ASN1Sequence) { - byte[] data = ASN1OctetString.getInstance(keyObj).getOctets(); - if (keyInfo.getPublicKeyData() != null) + ASN1Sequence keySeq = (ASN1Sequence)mldsaKey; + byte[] seed = ASN1OctetString.getInstance(keySeq.getObjectAt(0)).getOctets(); + byte[] encoding = ASN1OctetString.getInstance(keySeq.getObjectAt(1)).getOctets(); + + // TODO This should only allow seed but is length-flexible + MLDSAPrivateKeyParameters mldsaPriv = new MLDSAPrivateKeyParameters(mldsaParams, seed, pubParams); + if (!Arrays.constantTimeAreEqual(mldsaPriv.getEncoded(), encoding)) { - MLDSAPublicKeyParameters pubParams = PublicKeyFactory.MLDSAConverter.getPublicKeyParams(spParams, keyInfo.getPublicKeyData()); - return new MLDSAPrivateKeyParameters(spParams, data, pubParams); + throw new IllegalArgumentException("inconsistent " + mldsaParams.getName() + " private key"); } - return new MLDSAPrivateKeyParameters(spParams, data); - } - else - { - throw new IOException("not supported"); + + return mldsaPriv; } + + throw new IllegalArgumentException("invalid " + mldsaParams.getName() + " private key"); } else if (algOID.equals(BCObjectIdentifiers.dilithium2) || algOID.equals(BCObjectIdentifiers.dilithium3) || algOID.equals(BCObjectIdentifiers.dilithium5)) @@ -368,16 +363,70 @@ else if (algOID.on(BCObjectIdentifiers.pqc_kem_hqc)) return new HQCPrivateKeyParameters(hqcParams, keyEnc); } - else if (algOID.equals(PQCObjectIdentifiers.mcElieceCca2)) + else + { + throw new RuntimeException("algorithm identifier in private key not recognised"); + } + } + + /** + * So it seems for the new PQC algorithms, there's a couple of approaches to what goes in the OCTET STRING + */ + private static ASN1OctetString parseOctetString(ASN1OctetString octStr, int expectedLength) + throws IOException + { + byte[] data = octStr.getOctets(); + // + // it's the right length for a RAW encoding, just return it. + // + if (data.length == expectedLength) + { + return octStr; + } + + // + // possible internal OCTET STRING, possibly long form with or without the internal OCTET STRING + ASN1OctetString obj = Utils.parseOctetData(data); + + if (obj != null) { - McElieceCCA2PrivateKey mKey = McElieceCCA2PrivateKey.getInstance(keyInfo.parsePrivateKey()); + return ASN1OctetString.getInstance(obj); + } - return new McElieceCCA2PrivateKeyParameters(mKey.getN(), mKey.getK(), mKey.getField(), mKey.getGoppaPoly(), mKey.getP(), Utils.getDigestName(mKey.getDigest().getAlgorithm())); + return octStr; + } + + /** + * So it seems for the new PQC algorithms, there's a couple of approaches to what goes in the OCTET STRING + * and in this case there may also be SEQUENCE. + */ + private static ASN1Primitive parsePrimitiveString(ASN1OctetString octStr, int expectedLength) + throws IOException + { + byte[] data = octStr.getOctets(); + // + // it's the right length for a RAW encoding, just return it. + // + if (data.length == expectedLength) + { + return octStr; } - else + + // + // possible internal OCTET STRING, possibly long form with or without the internal OCTET STRING + // or possible SEQUENCE + ASN1Encodable obj = Utils.parseData(data); + + if (obj instanceof ASN1OctetString) { - throw new RuntimeException("algorithm identifier in private key not recognised"); + return ASN1OctetString.getInstance(obj); } + if (obj instanceof ASN1Sequence) + { + return ASN1Sequence.getInstance(obj); + } + + return octStr; } private static short[] convert(byte[] octets) diff --git a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java index 9c5b3554a0..c20588758a 100644 --- a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java +++ b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java @@ -3,9 +3,11 @@ import java.io.IOException; import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; @@ -14,7 +16,6 @@ import org.bouncycastle.pqc.asn1.CMCEPublicKey; import org.bouncycastle.pqc.asn1.FalconPrivateKey; import org.bouncycastle.pqc.asn1.FalconPublicKey; -import org.bouncycastle.pqc.asn1.McElieceCCA2PrivateKey; import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import org.bouncycastle.pqc.crypto.bike.BIKEPrivateKeyParameters; @@ -36,7 +37,6 @@ import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPrivateKeyParameters; import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPrivateKeyParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusPrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PrivateKeyParameters; import org.bouncycastle.util.Pack; /** @@ -55,7 +55,8 @@ private PrivateKeyInfoFactory() * @return the appropriate PrivateKeyInfo * @throws java.io.IOException on an error encoding the key */ - public static PrivateKeyInfo createPrivateKeyInfo(AsymmetricKeyParameter privateKey) throws IOException + public static PrivateKeyInfo createPrivateKeyInfo(AsymmetricKeyParameter privateKey) + throws IOException { return createPrivateKeyInfo(privateKey, null); } @@ -68,7 +69,8 @@ public static PrivateKeyInfo createPrivateKeyInfo(AsymmetricKeyParameter private * @return the appropriate PrivateKeyInfo * @throws java.io.IOException on an error encoding the key */ - public static PrivateKeyInfo createPrivateKeyInfo(AsymmetricKeyParameter privateKey, ASN1Set attributes) throws IOException + public static PrivateKeyInfo createPrivateKeyInfo(AsymmetricKeyParameter privateKey, ASN1Set attributes) + throws IOException { if (privateKey instanceof SPHINCSPrivateKeyParameters) { @@ -97,7 +99,7 @@ else if (privateKey instanceof NHPrivateKeyParameters) else if (privateKey instanceof SPHINCSPlusPrivateKeyParameters) { SPHINCSPlusPrivateKeyParameters params = (SPHINCSPlusPrivateKeyParameters)privateKey; - + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.sphincsPlusOidLookup(params.getParameters())); return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getEncoded()), attributes, params.getPublicKey()); @@ -108,7 +110,7 @@ else if (privateKey instanceof SLHDSAPrivateKeyParameters) AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.slhdsaOidLookup(params.getParameters())); - return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getEncoded()), attributes, params.getPublicKey()); + return new PrivateKeyInfo(algorithmIdentifier, params.getEncoded(), attributes); } else if (privateKey instanceof PicnicPrivateKeyParameters) { @@ -132,14 +134,6 @@ else if (privateKey instanceof CMCEPrivateKeyParameters) CMCEPrivateKey cmcePriv = new CMCEPrivateKey(0, params.getDelta(), params.getC(), params.getG(), params.getAlpha(), params.getS(), cmcePub); return new PrivateKeyInfo(algorithmIdentifier, cmcePriv, attributes); } - else if (privateKey instanceof McElieceCCA2PrivateKeyParameters) - { - McElieceCCA2PrivateKeyParameters priv = (McElieceCCA2PrivateKeyParameters)privateKey; - McElieceCCA2PrivateKey mcEliecePriv = new McElieceCCA2PrivateKey(priv.getN(), priv.getK(), priv.getField(), priv.getGoppaPoly(), priv.getP(), Utils.getAlgorithmIdentifier(priv.getDigest())); - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.mcElieceCca2); - - return new PrivateKeyInfo(algorithmIdentifier, mcEliecePriv); - } else if (privateKey instanceof FrodoPrivateKeyParameters) { FrodoPrivateKeyParameters params = (FrodoPrivateKeyParameters)privateKey; @@ -184,7 +178,7 @@ else if (privateKey instanceof FalconPrivateKeyParameters) else if (privateKey instanceof MLKEMPrivateKeyParameters) { MLKEMPrivateKeyParameters params = (MLKEMPrivateKeyParameters)privateKey; - + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.mlkemOidLookup(params.getParameters())); byte[] seed = params.getSeed(); @@ -234,19 +228,15 @@ else if (privateKey instanceof MLDSAPrivateKeyParameters) AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Utils.mldsaOidLookup(params.getParameters())); - byte[] seed = params.getSeed(); - if (seed == null) + if (params.getPreferredFormat() == MLDSAPrivateKeyParameters.SEED_ONLY) { - MLDSAPublicKeyParameters pubParams = params.getPublicKeyParameters(); - - return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getEncoded()), attributes, pubParams.getEncoded()); + return new PrivateKeyInfo(algorithmIdentifier, new DERTaggedObject(false, 0, new DEROctetString(params.getSeed())), attributes); } - else + else if (params.getPreferredFormat() == MLDSAPrivateKeyParameters.EXPANDED_KEY) { - MLDSAPublicKeyParameters pubParams = params.getPublicKeyParameters(); - - return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getSeed()), attributes); + return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getEncoded()), attributes); } + return new PrivateKeyInfo(algorithmIdentifier, getBasicPQCEncoding(params.getSeed(), params.getEncoded()), attributes); } else if (privateKey instanceof DilithiumPrivateKeyParameters) { @@ -277,4 +267,15 @@ else if (privateKey instanceof HQCPrivateKeyParameters) throw new IOException("key parameters not recognized"); } } + + private static ASN1Sequence getBasicPQCEncoding(byte[] seed, byte[] expanded) + { + ASN1EncodableVector v = new ASN1EncodableVector(2); + + v.add(new DEROctetString(seed)); + + v.add(new DEROctetString(expanded)); + + return new DERSequence(v); + } } diff --git a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java index 29e2807611..8533fe8256 100644 --- a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java +++ b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java @@ -19,8 +19,6 @@ import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers; import org.bouncycastle.pqc.asn1.CMCEPublicKey; -import org.bouncycastle.pqc.asn1.KyberPublicKey; -import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey; import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import org.bouncycastle.pqc.crypto.bike.BIKEParameters; @@ -55,7 +53,6 @@ import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPublicKeyParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusPublicKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PublicKeyParameters; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; @@ -71,7 +68,6 @@ public class PublicKeyFactory { converters.put(PQCObjectIdentifiers.sphincs256, new SPHINCSConverter()); converters.put(PQCObjectIdentifiers.newHope, new NHConverter()); - converters.put(PQCObjectIdentifiers.mcElieceCca2, new McElieceCCA2Converter()); converters.put(BCObjectIdentifiers.sphincsPlus, new SPHINCSPlusConverter()); converters.put(BCObjectIdentifiers.sphincsPlus_sha2_128s_r3, new SPHINCSPlusConverter()); @@ -167,12 +163,12 @@ public class PublicKeyFactory converters.put(BCObjectIdentifiers.ntruhrss1373, new NtruConverter()); converters.put(BCObjectIdentifiers.falcon_512, new FalconConverter()); converters.put(BCObjectIdentifiers.falcon_1024, new FalconConverter()); - converters.put(NISTObjectIdentifiers.id_alg_ml_kem_512, new KyberConverter()); - converters.put(NISTObjectIdentifiers.id_alg_ml_kem_768, new KyberConverter()); - converters.put(NISTObjectIdentifiers.id_alg_ml_kem_1024, new KyberConverter()); - converters.put(BCObjectIdentifiers.kyber512_aes, new KyberConverter()); - converters.put(BCObjectIdentifiers.kyber768_aes, new KyberConverter()); - converters.put(BCObjectIdentifiers.kyber1024_aes, new KyberConverter()); + converters.put(NISTObjectIdentifiers.id_alg_ml_kem_512, new MLKEMKeyConverter()); + converters.put(NISTObjectIdentifiers.id_alg_ml_kem_768, new MLKEMKeyConverter()); + converters.put(NISTObjectIdentifiers.id_alg_ml_kem_1024, new MLKEMKeyConverter()); + converters.put(BCObjectIdentifiers.kyber512_aes, new MLKEMKeyConverter()); + converters.put(BCObjectIdentifiers.kyber768_aes, new MLKEMKeyConverter()); + converters.put(BCObjectIdentifiers.kyber1024_aes, new MLKEMKeyConverter()); converters.put(BCObjectIdentifiers.ntrulpr653, new NTRULPrimeConverter()); converters.put(BCObjectIdentifiers.ntrulpr761, new NTRULPrimeConverter()); converters.put(BCObjectIdentifiers.ntrulpr857, new NTRULPrimeConverter()); @@ -402,18 +398,6 @@ AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Obje } } - private static class McElieceCCA2Converter - extends SubjectPublicKeyInfoConverter - { - AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) - throws IOException - { - McElieceCCA2PublicKey mKey = McElieceCCA2PublicKey.getInstance(keyInfo.parsePublicKey()); - - return new McElieceCCA2PublicKeyParameters(mKey.getN(), mKey.getT(), mKey.getG(), Utils.getDigestName(mKey.getDigest().getAlgorithm())); - } - } - private static class FrodoConverter extends SubjectPublicKeyInfoConverter { @@ -472,25 +456,42 @@ AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Obje } } - private static class KyberConverter + static class MLKEMKeyConverter extends SubjectPublicKeyInfoConverter { AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) throws IOException { - MLKEMParameters kyberParameters = Utils.mlkemParamsLookup(keyInfo.getAlgorithm().getAlgorithm()); + MLKEMParameters parameters = Utils.mlkemParamsLookup(keyInfo.getAlgorithm().getAlgorithm()); + // we're a raw encoding + return new MLKEMPublicKeyParameters(parameters, keyInfo.getPublicKeyData().getOctets()); + } + + static MLKEMPublicKeyParameters getPublicKeyParams(MLKEMParameters parameters, ASN1BitString publicKeyData) + { try { - ASN1Primitive obj = keyInfo.parsePublicKey(); - KyberPublicKey kyberKey = KyberPublicKey.getInstance(obj); + ASN1Primitive obj = ASN1Primitive.fromByteArray(publicKeyData.getOctets()); + if (obj instanceof ASN1Sequence) + { + ASN1Sequence keySeq = ASN1Sequence.getInstance(obj); + + return new MLKEMPublicKeyParameters(parameters, + ASN1OctetString.getInstance(keySeq.getObjectAt(0)).getOctets(), + ASN1OctetString.getInstance(keySeq.getObjectAt(1)).getOctets()); + } + else + { + byte[] encKey = ASN1OctetString.getInstance(obj).getOctets(); - return new MLKEMPublicKeyParameters(kyberParameters, kyberKey.getT(), kyberKey.getRho()); + return new MLKEMPublicKeyParameters(parameters, encKey); + } } catch (Exception e) { // we're a raw encoding - return new MLKEMPublicKeyParameters(kyberParameters, keyInfo.getPublicKeyData().getOctets()); + return new MLKEMPublicKeyParameters(parameters, publicKeyData.getOctets()); } } } diff --git a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java index 33ecbd4c2c..6053c238d0 100644 --- a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java +++ b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java @@ -9,7 +9,6 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers; -import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey; import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import org.bouncycastle.pqc.crypto.bike.BIKEPublicKeyParameters; @@ -29,7 +28,6 @@ import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPublicKeyParameters; import org.bouncycastle.pqc.crypto.sphincs.SPHINCSPublicKeyParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusPublicKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PublicKeyParameters; /** * Factory to create ASN.1 subject public key info objects from lightweight public keys. @@ -94,14 +92,6 @@ else if (publicKey instanceof CMCEPublicKeyParameters) return new SubjectPublicKeyInfo(algorithmIdentifier, encoding); } - else if (publicKey instanceof McElieceCCA2PublicKeyParameters) - { - McElieceCCA2PublicKeyParameters pub = (McElieceCCA2PublicKeyParameters)publicKey; - McElieceCCA2PublicKey mcEliecePub = new McElieceCCA2PublicKey(pub.getN(), pub.getT(), pub.getG(), Utils.getAlgorithmIdentifier(pub.getDigest())); - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.mcElieceCca2); - - return new SubjectPublicKeyInfo(algorithmIdentifier, mcEliecePub); - } else if (publicKey instanceof FrodoPublicKeyParameters) { FrodoPublicKeyParameters params = (FrodoPublicKeyParameters)publicKey; diff --git a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/Utils.java b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/Utils.java index 9fc442139b..2c7d923e7a 100644 --- a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/Utils.java +++ b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/Utils.java @@ -1,9 +1,15 @@ package org.bouncycastle.pqc.crypto.util; +import java.io.ByteArrayInputStream; import java.util.HashMap; import java.util.Map; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.bc.BCObjectIdentifiers; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; @@ -88,9 +94,9 @@ class Utils static final Map mldsaOids = new HashMap(); static final Map mldsaParams = new HashMap(); - static final Map shldsaOids = new HashMap(); - static final Map shldsaParams = new HashMap(); - + static final Map slhdsaOids = new HashMap(); + static final Map slhdsaParams = new HashMap(); + static { mcElieceOids.put(CMCEParameters.mceliece348864r3, BCObjectIdentifiers.mceliece348864_r3); @@ -215,7 +221,7 @@ class Utils mlkemOids.put(MLKEMParameters.ml_kem_512, NISTObjectIdentifiers.id_alg_ml_kem_512); mlkemOids.put(MLKEMParameters.ml_kem_768, NISTObjectIdentifiers.id_alg_ml_kem_768); - mlkemOids.put(MLKEMParameters.ml_kem_1024,NISTObjectIdentifiers.id_alg_ml_kem_1024); + mlkemOids.put(MLKEMParameters.ml_kem_1024, NISTObjectIdentifiers.id_alg_ml_kem_1024); mlkemParams.put(NISTObjectIdentifiers.id_alg_ml_kem_512, MLKEMParameters.ml_kem_512); mlkemParams.put(NISTObjectIdentifiers.id_alg_ml_kem_768, MLKEMParameters.ml_kem_768); @@ -287,57 +293,57 @@ class Utils hqcOids.put(HQCParameters.hqc192, BCObjectIdentifiers.hqc192); hqcOids.put(HQCParameters.hqc256, BCObjectIdentifiers.hqc256); - shldsaOids.put(SLHDSAParameters.sha2_128s, NISTObjectIdentifiers.id_slh_dsa_sha2_128s); - shldsaOids.put(SLHDSAParameters.sha2_128f, NISTObjectIdentifiers.id_slh_dsa_sha2_128f); - shldsaOids.put(SLHDSAParameters.sha2_192s, NISTObjectIdentifiers.id_slh_dsa_sha2_192s); - shldsaOids.put(SLHDSAParameters.sha2_192f, NISTObjectIdentifiers.id_slh_dsa_sha2_192f); - shldsaOids.put(SLHDSAParameters.sha2_256s, NISTObjectIdentifiers.id_slh_dsa_sha2_256s); - shldsaOids.put(SLHDSAParameters.sha2_256f, NISTObjectIdentifiers.id_slh_dsa_sha2_256f); - shldsaOids.put(SLHDSAParameters.shake_128s, NISTObjectIdentifiers.id_slh_dsa_shake_128s); - shldsaOids.put(SLHDSAParameters.shake_128f, NISTObjectIdentifiers.id_slh_dsa_shake_128f); - shldsaOids.put(SLHDSAParameters.shake_192s, NISTObjectIdentifiers.id_slh_dsa_shake_192s); - shldsaOids.put(SLHDSAParameters.shake_192f, NISTObjectIdentifiers.id_slh_dsa_shake_192f); - shldsaOids.put(SLHDSAParameters.shake_256s, NISTObjectIdentifiers.id_slh_dsa_shake_256s); - shldsaOids.put(SLHDSAParameters.shake_256f, NISTObjectIdentifiers.id_slh_dsa_shake_256f); - - shldsaOids.put(SLHDSAParameters.sha2_128s_with_sha256, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128s_with_sha256); - shldsaOids.put(SLHDSAParameters.sha2_128f_with_sha256, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128f_with_sha256); - shldsaOids.put(SLHDSAParameters.sha2_192s_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192s_with_sha512); - shldsaOids.put(SLHDSAParameters.sha2_192f_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192f_with_sha512); - shldsaOids.put(SLHDSAParameters.sha2_256s_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256s_with_sha512); - shldsaOids.put(SLHDSAParameters.sha2_256f_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256f_with_sha512); - shldsaOids.put(SLHDSAParameters.shake_128s_with_shake128, NISTObjectIdentifiers.id_hash_slh_dsa_shake_128s_with_shake128); - shldsaOids.put(SLHDSAParameters.shake_128f_with_shake128, NISTObjectIdentifiers.id_hash_slh_dsa_shake_128f_with_shake128); - shldsaOids.put(SLHDSAParameters.shake_192s_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_192s_with_shake256); - shldsaOids.put(SLHDSAParameters.shake_192f_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256); - shldsaOids.put(SLHDSAParameters.shake_256s_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256); - shldsaOids.put(SLHDSAParameters.shake_256f_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256); - - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_128s, SLHDSAParameters.sha2_128s); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_128f, SLHDSAParameters.sha2_128f); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_192s, SLHDSAParameters.sha2_192s); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_192f, SLHDSAParameters.sha2_192f); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_256s, SLHDSAParameters.sha2_256s); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_256f, SLHDSAParameters.sha2_256f); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_128s, SLHDSAParameters.shake_128s); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_128f, SLHDSAParameters.shake_128f); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_192s, SLHDSAParameters.shake_192s); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_192f, SLHDSAParameters.shake_192f); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_256s, SLHDSAParameters.shake_256s); - shldsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_256f, SLHDSAParameters.shake_256f); - - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128s_with_sha256, SLHDSAParameters.sha2_128s_with_sha256); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128f_with_sha256, SLHDSAParameters.sha2_128f_with_sha256); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192s_with_sha512, SLHDSAParameters.sha2_192s_with_sha512); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192f_with_sha512, SLHDSAParameters.sha2_192f_with_sha512); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256s_with_sha512, SLHDSAParameters.sha2_256s_with_sha512); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256f_with_sha512, SLHDSAParameters.sha2_256f_with_sha512); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_128s_with_shake128, SLHDSAParameters.shake_128s_with_shake128); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_128f_with_shake128, SLHDSAParameters.shake_128f_with_shake128); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_192s_with_shake256, SLHDSAParameters.shake_192s_with_shake256); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256, SLHDSAParameters.shake_192f_with_shake256); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256, SLHDSAParameters.shake_256s_with_shake256); - shldsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256, SLHDSAParameters.shake_256f_with_shake256); + slhdsaOids.put(SLHDSAParameters.sha2_128s, NISTObjectIdentifiers.id_slh_dsa_sha2_128s); + slhdsaOids.put(SLHDSAParameters.sha2_128f, NISTObjectIdentifiers.id_slh_dsa_sha2_128f); + slhdsaOids.put(SLHDSAParameters.sha2_192s, NISTObjectIdentifiers.id_slh_dsa_sha2_192s); + slhdsaOids.put(SLHDSAParameters.sha2_192f, NISTObjectIdentifiers.id_slh_dsa_sha2_192f); + slhdsaOids.put(SLHDSAParameters.sha2_256s, NISTObjectIdentifiers.id_slh_dsa_sha2_256s); + slhdsaOids.put(SLHDSAParameters.sha2_256f, NISTObjectIdentifiers.id_slh_dsa_sha2_256f); + slhdsaOids.put(SLHDSAParameters.shake_128s, NISTObjectIdentifiers.id_slh_dsa_shake_128s); + slhdsaOids.put(SLHDSAParameters.shake_128f, NISTObjectIdentifiers.id_slh_dsa_shake_128f); + slhdsaOids.put(SLHDSAParameters.shake_192s, NISTObjectIdentifiers.id_slh_dsa_shake_192s); + slhdsaOids.put(SLHDSAParameters.shake_192f, NISTObjectIdentifiers.id_slh_dsa_shake_192f); + slhdsaOids.put(SLHDSAParameters.shake_256s, NISTObjectIdentifiers.id_slh_dsa_shake_256s); + slhdsaOids.put(SLHDSAParameters.shake_256f, NISTObjectIdentifiers.id_slh_dsa_shake_256f); + + slhdsaOids.put(SLHDSAParameters.sha2_128s_with_sha256, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128s_with_sha256); + slhdsaOids.put(SLHDSAParameters.sha2_128f_with_sha256, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128f_with_sha256); + slhdsaOids.put(SLHDSAParameters.sha2_192s_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192s_with_sha512); + slhdsaOids.put(SLHDSAParameters.sha2_192f_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192f_with_sha512); + slhdsaOids.put(SLHDSAParameters.sha2_256s_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256s_with_sha512); + slhdsaOids.put(SLHDSAParameters.sha2_256f_with_sha512, NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256f_with_sha512); + slhdsaOids.put(SLHDSAParameters.shake_128s_with_shake128, NISTObjectIdentifiers.id_hash_slh_dsa_shake_128s_with_shake128); + slhdsaOids.put(SLHDSAParameters.shake_128f_with_shake128, NISTObjectIdentifiers.id_hash_slh_dsa_shake_128f_with_shake128); + slhdsaOids.put(SLHDSAParameters.shake_192s_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_192s_with_shake256); + slhdsaOids.put(SLHDSAParameters.shake_192f_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256); + slhdsaOids.put(SLHDSAParameters.shake_256s_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256); + slhdsaOids.put(SLHDSAParameters.shake_256f_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256); + + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_128s, SLHDSAParameters.sha2_128s); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_128f, SLHDSAParameters.sha2_128f); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_192s, SLHDSAParameters.sha2_192s); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_192f, SLHDSAParameters.sha2_192f); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_256s, SLHDSAParameters.sha2_256s); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_sha2_256f, SLHDSAParameters.sha2_256f); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_128s, SLHDSAParameters.shake_128s); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_128f, SLHDSAParameters.shake_128f); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_192s, SLHDSAParameters.shake_192s); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_192f, SLHDSAParameters.shake_192f); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_256s, SLHDSAParameters.shake_256s); + slhdsaParams.put(NISTObjectIdentifiers.id_slh_dsa_shake_256f, SLHDSAParameters.shake_256f); + + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128s_with_sha256, SLHDSAParameters.sha2_128s_with_sha256); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_128f_with_sha256, SLHDSAParameters.sha2_128f_with_sha256); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192s_with_sha512, SLHDSAParameters.sha2_192s_with_sha512); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_192f_with_sha512, SLHDSAParameters.sha2_192f_with_sha512); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256s_with_sha512, SLHDSAParameters.sha2_256s_with_sha512); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_sha2_256f_with_sha512, SLHDSAParameters.sha2_256f_with_sha512); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_128s_with_shake128, SLHDSAParameters.shake_128s_with_shake128); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_128f_with_shake128, SLHDSAParameters.shake_128f_with_shake128); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_192s_with_shake256, SLHDSAParameters.shake_192s_with_shake256); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_192f_with_shake256, SLHDSAParameters.shake_192f_with_shake256); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256, SLHDSAParameters.shake_256s_with_shake256); + slhdsaParams.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256, SLHDSAParameters.shake_256f_with_shake256); sphincsPlusOids.put(SLHDSAParameters.sha2_128s, BCObjectIdentifiers.sphincsPlus_sha2_128s); sphincsPlusOids.put(SLHDSAParameters.sha2_128f, BCObjectIdentifiers.sphincsPlus_sha2_128f); @@ -442,12 +448,12 @@ class Utils static ASN1ObjectIdentifier slhdsaOidLookup(SLHDSAParameters params) { - return (ASN1ObjectIdentifier)shldsaOids.get(params); + return (ASN1ObjectIdentifier)slhdsaOids.get(params); } static SLHDSAParameters slhdsaParamsLookup(ASN1ObjectIdentifier oid) { - return (SLHDSAParameters)shldsaParams.get(oid); + return (SLHDSAParameters)slhdsaParams.get(oid); } static AlgorithmIdentifier sphincs256LookupTreeAlgID(String treeDigest) @@ -697,4 +703,81 @@ static HQCParameters hqcParamsLookup(ASN1ObjectIdentifier oid) { return (HQCParameters)hqcParams.get(oid); } + + + private static boolean isRaw(byte[] data) + { + // check well-formed first + ByteArrayInputStream bIn = new ByteArrayInputStream(data); + + int tag = bIn.read(); + int len = readLen(bIn); + if (len != bIn.available()) + { + return true; + } + + return false; + } + + static ASN1OctetString parseOctetData(byte[] data) + { + // check well-formed first + if (!isRaw(data)) + { + if (data[0] == BERTags.OCTET_STRING) + { + return ASN1OctetString.getInstance(data); + } + } + + return null; + } + + static ASN1Primitive parseData(byte[] data) + { + // check well-formed first + if (!isRaw(data)) + { + if (data[0] == (BERTags.SEQUENCE | BERTags.CONSTRUCTED)) + { + return ASN1Sequence.getInstance(data); + } + + if (data[0] == BERTags.OCTET_STRING) + { + return ASN1OctetString.getInstance(data); + } + + if ((data[0] & 0xff) == BERTags.TAGGED) + { + return ASN1OctetString.getInstance(ASN1TaggedObject.getInstance(data), false); + } + } + + return null; + } + + /** + * ASN.1 length reader. + */ + static int readLen(ByteArrayInputStream bIn) + { + int length = bIn.read(); + if (length < 0) + { + return -1; + } + if (length != (length & 0x7f)) + { + int count = length & 0x7f; + length = 0; + while (count-- != 0) + { + length = (length << 8) + bIn.read(); + } + } + + return length; + } } diff --git a/core/src/main/jdk1.4/org/bouncycastle/util/Arrays.java b/core/src/main/jdk1.4/org/bouncycastle/util/Arrays.java index ef5d23662f..ee65cdac3d 100644 --- a/core/src/main/jdk1.4/org/bouncycastle/util/Arrays.java +++ b/core/src/main/jdk1.4/org/bouncycastle/util/Arrays.java @@ -147,6 +147,67 @@ public static boolean constantTimeAreEqual(int len, byte[] a, int aOff, byte[] b return 0 == d; } + public static boolean constantTimeAreEqual( + long[] expected, + long[] supplied) + { + if (expected == null || supplied == null) + { + return false; + } + + if (expected == supplied) + { + return true; + } + + int len = (expected.length < supplied.length) ? expected.length : supplied.length; + + long nonEqual = expected.length ^ supplied.length; + + for (int i = 0; i != len; i++) + { + nonEqual |= (expected[i] ^ supplied[i]); + } + for (int i = len; i < supplied.length; i++) + { + nonEqual |= (supplied[i] ^ ~supplied[i]); + } + + return nonEqual == 0; + } + + public static boolean constantTimeAreEqual(int len, long[] a, int aOff, long[] b, int bOff) + { + if (null == a) + { + throw new NullPointerException("'a' cannot be null"); + } + if (null == b) + { + throw new NullPointerException("'b' cannot be null"); + } + if (len < 0) + { + throw new IllegalArgumentException("'len' cannot be negative"); + } + if (aOff > (a.length - len)) + { + throw new IndexOutOfBoundsException("'aOff' value invalid for specified length"); + } + if (bOff > (b.length - len)) + { + throw new IndexOutOfBoundsException("'bOff' value invalid for specified length"); + } + + long d = 0; + for (int i = 0; i < len; ++i) + { + d |= (a[aOff + i] ^ b[bOff + i]); + } + return 0L == d; + } + public static int compareUnsigned(byte[] a, byte[] b) { if (a == b) @@ -875,7 +936,7 @@ public static void reverse(byte[] input, byte[] output) output[i] = input[last - i]; } } - + public static byte[] reverseInPlace(byte[] a) { if (null == a) @@ -940,7 +1001,7 @@ public static int[] reverseInPlace(int[] a) return a; } - + /** * Fill input array by zeros * @@ -962,6 +1023,14 @@ public static void clear(int[] data) } } + public static void clear(long[] data) + { + if (null != data) + { + java.util.Arrays.fill(data, 0); + } + } + public static boolean isNullOrContainsNull(Object[] array) { if (null == array) @@ -1137,6 +1206,28 @@ public static int hashCode(Object[] data) return hc; } + public static boolean segmentsOverlap(int aOff, int aLen, int bOff, int bLen) + { + return aLen > 0 + && bLen > 0 + && aOff - bOff < bLen + && bOff - aOff < aLen; + } + + public static void validateSegment(byte[] buf, int off, int len) + { + if (buf == null) + { + throw new NullPointerException("'buf' cannot be null"); + } + int available = buf.length - off; + int remaining = available - len; + if ((off | len | available | remaining) < 0) + { + throw new IndexOutOfBoundsException("buf.length: " + buf.length + ", off: " + off + ", len: " + len); + } + } + /** * Iterator backed by a specific array. */ diff --git a/core/src/main/jdk1.4/org/bouncycastle/util/Bytes.java b/core/src/main/jdk1.4/org/bouncycastle/util/Bytes.java index 526a27659e..25a9ce4431 100644 --- a/core/src/main/jdk1.4/org/bouncycastle/util/Bytes.java +++ b/core/src/main/jdk1.4/org/bouncycastle/util/Bytes.java @@ -16,6 +16,14 @@ public static void xor(int len, byte[] x, byte[] y, byte[] z) } } + public static void xor(int len, byte[] x, int xOff, byte[] y, byte[] z, int zOff) + { + for (int i = 0; i < len; ++i) + { + z[zOff++] = (byte)(x[xOff++] ^ y[i]); + } + } + public static void xor(int len, byte[] x, int xOff, byte[] y, int yOff, byte[] z, int zOff) { for (int i = 0; i < len; ++i) @@ -23,7 +31,23 @@ public static void xor(int len, byte[] x, int xOff, byte[] y, int yOff, byte[] z z[zOff + i] = (byte)(x[xOff + i] ^ y[yOff + i]); } } - + + public static void xor(int len, byte[] x, byte[] y, byte[] z, int zOff) + { + for (int i = 0; i < len; ++i) + { + z[zOff++] = (byte)(x[i] ^ y[i]); + } + } + + public static void xor(int len, byte[] x, byte[] y, int yOff, byte[] z, int zOff) + { + for (int i = 0; i < len; ++i) + { + z[zOff++] = (byte)(x[i] ^ y[yOff++]); + } + } + public static void xorTo(int len, byte[] x, byte[] z) { for (int i = 0; i < len; ++i) @@ -32,6 +56,14 @@ public static void xorTo(int len, byte[] x, byte[] z) } } + public static void xorTo(int len, byte[] x, int xOff, byte[] z) + { + for (int i = 0; i < len; ++i) + { + z[i] ^= x[xOff++]; + } + } + public static void xorTo(int len, byte[] x, int xOff, byte[] z, int zOff) { for (int i = 0; i < len; ++i) diff --git a/core/src/main/jdk1.4/org/bouncycastle/util/Integers.java b/core/src/main/jdk1.4/org/bouncycastle/util/Integers.java index bd53723dc0..5849b2c8fc 100644 --- a/core/src/main/jdk1.4/org/bouncycastle/util/Integers.java +++ b/core/src/main/jdk1.4/org/bouncycastle/util/Integers.java @@ -22,6 +22,16 @@ public static int bitCount(int i) return i; } + public static int compare(int x, int y) + { + return x < y ? -1 : x == y ? 0 : 1; + } + + public static int compareUnsigned(int x, int y) + { + return compare(x + Integer.MIN_VALUE, y + Integer.MIN_VALUE); + } + public static int highestOneBit(int i) { i |= (i >> 1); diff --git a/core/src/main/jdk1.4/org/bouncycastle/util/Longs.java b/core/src/main/jdk1.4/org/bouncycastle/util/Longs.java index 5baea19a67..214f26c654 100644 --- a/core/src/main/jdk1.4/org/bouncycastle/util/Longs.java +++ b/core/src/main/jdk1.4/org/bouncycastle/util/Longs.java @@ -13,6 +13,16 @@ public class Longs 0x3E, 0x33, 0x05, 0x19, 0x24, 0x27, 0x20, 0x2E, 0x3C, 0x2C, 0x2A, 0x14, 0x16, 0x39, 0x10, 0x09, 0x32, 0x18, 0x23, 0x1F, 0x3B, 0x13, 0x38, 0x0F, 0x31, 0x1E, 0x12, 0x0E, 0x1D, 0x0D, 0x0C, 0x0B }; + public static int compare(long x, long y) + { + return x < y ? -1 : x == y ? 0 : 1; + } + + public static int compareUnsigned(long x, long y) + { + return compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE); + } + public static long highestOneBit(long i) { i |= (i >> 1); @@ -77,4 +87,12 @@ public static Long valueOf(long value) { return new Long(value); } + + public static void xorTo(int len, long[] x, int xOff, long[] z, int zOff) + { + for (int i = 0; i < len; ++i) + { + z[zOff + i] ^= x[xOff + i]; + } + } } diff --git a/core/src/main/jdk1.5/org/bouncycastle/util/Exceptions.java b/core/src/main/jdk1.5/org/bouncycastle/util/Exceptions.java new file mode 100644 index 0000000000..25599d3cd9 --- /dev/null +++ b/core/src/main/jdk1.5/org/bouncycastle/util/Exceptions.java @@ -0,0 +1,27 @@ +package org.bouncycastle.util; + +import java.io.IOException; + +public class Exceptions +{ + public static IllegalArgumentException illegalArgumentException(String message, Throwable cause) + { + return new IllegalArgumentException(message, cause); + } + + public static IllegalStateException illegalStateException(String message, Throwable cause) + { + return new IllegalStateException(message, cause); + } + + public static IOException ioException(String message, final Throwable cause) + { + return new IOException(message + "-" + cause.getMessage()) + { + public synchronized Throwable getCause() + { + return cause; + } + }; + } +} diff --git a/core/src/test/java/org/bouncycastle/asn1/test/DERApplicationSpecificTest.java b/core/src/test/java/org/bouncycastle/asn1/test/DERApplicationSpecificTest.java index 6d72137fa5..2c5d1570a2 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/DERApplicationSpecificTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/DERApplicationSpecificTest.java @@ -100,7 +100,7 @@ public void performTest() fail("wrong tag detected"); } - ASN1Integer value = new ASN1Integer(9); + ASN1Integer value = ASN1Integer.valueOf(9); DERTaggedObject tagged = new DERTaggedObject(false, BERTags.APPLICATION, 3, value); diff --git a/core/src/test/java/org/bouncycastle/asn1/test/DERPrivateTest.java b/core/src/test/java/org/bouncycastle/asn1/test/DERPrivateTest.java index 904b76ce79..49434823d1 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/DERPrivateTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/DERPrivateTest.java @@ -93,7 +93,7 @@ public void performTest() fail("wrong tag detected"); } - ASN1Integer value = new ASN1Integer(9); + ASN1Integer value = ASN1Integer.valueOf(9); ASN1TaggedObject tagged = new DERTaggedObject(false, BERTags.PRIVATE, 3, value); diff --git a/core/src/test/java/org/bouncycastle/asn1/test/DLExternalTest.java b/core/src/test/java/org/bouncycastle/asn1/test/DLExternalTest.java index ecc8a3021d..0ff80b0c90 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/DLExternalTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/DLExternalTest.java @@ -64,7 +64,7 @@ public void testInstantiationByVector() { isEquals("check message", "too few objects in input sequence", iae.getMessage()); } - vec.add(new DLTaggedObject(true, 0, new ASN1Integer(1234567890L))); + vec.add(new DLTaggedObject(true, 0, ASN1Integer.valueOf(1234567890))); DLExternal dle = new DLExternal(new DLSequence(vec)); @@ -81,9 +81,9 @@ public void testInstantiationByVector() isEquals("check value of external content", "1234567890", ((ASN1Integer)dle.getExternalContent()).getValue().toString()); vec = new ASN1EncodableVector(); - vec.add(new ASN1Integer(9L)); + vec.add(ASN1Integer.valueOf(9)); vec.add(new DERUTF8String("something completely different")); - vec.add(new DLTaggedObject(true, 0, new ASN1Integer(1234567890L))); + vec.add(new DLTaggedObject(true, 0, ASN1Integer.valueOf(1234567890))); dle = new DLExternal(vec); isEquals("check direct reference", null, dle.getDirectReference()); @@ -184,7 +184,7 @@ private void checkRealDataExample(int encoding, DLExternal dle) isTrue("check tag", objNameTagged.hasContextTag(3)); isEquals("check implicit", false, objNameTagged.isExplicit()); isEquals("check tagged object: " + objNameTagged.getBaseUniversal(false, BERTags.OCTET_STRING).getClass(), DEROctetString.class.getName(), objNameTagged.getBaseUniversal(false, BERTags.OCTET_STRING).getClass().getName()); - isEquals("check O", "Organization", new String(((DEROctetString)objNameTagged.getBaseUniversal(false, BERTags.OCTET_STRING)).getOctets(), "8859_1")); + isEquals("check O", "Organization", StringTestUtil.fromISO_8891(((DEROctetString)objNameTagged.getBaseUniversal(false, BERTags.OCTET_STRING)).getOctets())); isEquals("check fourth element in set: " + objNameElems.getObjectAt(3).getClass(), DLTaggedObject.class.getName(), objNameElems.getObjectAt(3).getClass().getName()); objNameTagged = (DLTaggedObject)objNameElems.getObjectAt(3); isTrue("check tag", objNameTagged.hasContextTag(5)); @@ -194,7 +194,7 @@ private void checkRealDataExample(int encoding, DLExternal dle) isTrue("check tag", objNameTagged.hasContextTag(0)); isEquals("check implicit", false, objNameTagged.isExplicit()); isEquals("check tagged object: " + objNameTagged.getBaseUniversal(false, BERTags.OCTET_STRING).getClass(), DEROctetString.class.getName(), objNameTagged.getBaseUniversal(false, BERTags.OCTET_STRING).getClass().getName()); - isEquals("check CN", "Common Name", new String(((DEROctetString)objNameTagged.getBaseUniversal(false, BERTags.OCTET_STRING)).getOctets(), "8859_1")); + isEquals("check CN", "Common Name", StringTestUtil.fromISO_8891(((DEROctetString)objNameTagged.getBaseUniversal(false, BERTags.OCTET_STRING)).getOctets())); isEquals("check second element in set: " + msBindSet.getObjectAt(1).getClass(), DLTaggedObject.class.getName(), msBindSet.getObjectAt(1).getClass().getName()); DLTaggedObject password = (DLTaggedObject)msBindSet.getObjectAt(1); @@ -210,14 +210,14 @@ private ASN1EncodableVector createRealDataExample(int encoding) ASN1EncodableVector vec = new ASN1EncodableVector(); vec.add(new ASN1ObjectIdentifier("2.1.1")); - vec.add(new ASN1Integer(9)); + vec.add(ASN1Integer.valueOf(9)); vec.add(new DERUTF8String("example data representing the User Data of an OSI.6 ConnectP containing an MSBind with username and password")); ASN1EncodableVector objectNameVec = new ASN1EncodableVector(); objectNameVec.add(new DLTaggedObject(BERTags.APPLICATION, 0, new DERPrintableString("de"))); objectNameVec.add(new DLTaggedObject(BERTags.APPLICATION, 2, new DERPrintableString("viaT"))); - objectNameVec.add(new DLTaggedObject(false, 3, new DEROctetString("Organization".getBytes("8859_1")))); - objectNameVec.add(new DLTaggedObject(true, 5, new DLTaggedObject(false, 0, new DEROctetString("Common Name".getBytes("8859_1"))))); + objectNameVec.add(new DLTaggedObject(false, 3, new DEROctetString(StringTestUtil.toISO_8891("Organization")))); + objectNameVec.add(new DLTaggedObject(true, 5, new DLTaggedObject(false, 0, new DEROctetString(StringTestUtil.toISO_8891("Common Name"))))); DLTaggedObject objectName = new DLTaggedObject(BERTags.APPLICATION, 0, new DLSequence(objectNameVec)); DLTaggedObject password = new DLTaggedObject(true, 2, new DERIA5String("SomePassword")); diff --git a/core/src/test/java/org/bouncycastle/asn1/test/EqualsAndHashCodeTest.java b/core/src/test/java/org/bouncycastle/asn1/test/EqualsAndHashCodeTest.java index bdfb74969a..6392c748c8 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/EqualsAndHashCodeTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/EqualsAndHashCodeTest.java @@ -62,7 +62,7 @@ public TestResult perform() new DERGeneralizedTime("20070315173729Z"), new DERGeneralString("hello world"), new DERIA5String("hello"), - new ASN1Integer(1000), + ASN1Integer.valueOf(1000), DERNull.INSTANCE, new DERNumericString("123456"), new ASN1ObjectIdentifier("1.1.1.10000.1"), diff --git a/core/src/test/java/org/bouncycastle/asn1/test/GenerationTest.java b/core/src/test/java/org/bouncycastle/asn1/test/GenerationTest.java index 86acbe2dcf..0a4c4aa5b3 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/GenerationTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/GenerationTest.java @@ -83,7 +83,7 @@ private void tbsV1CertGen() Date startDate = new Date(1000); Date endDate = new Date(12000); - gen.setSerialNumber(new ASN1Integer(1)); + gen.setSerialNumber(ASN1Integer.ONE); gen.setStartDate(new Time(startDate)); gen.setEndDate(new Time(endDate)); @@ -139,7 +139,7 @@ private void tbsV3CertGen() Date startDate = new Date(1000); Date endDate = new Date(2000); - gen.setSerialNumber(new ASN1Integer(2)); + gen.setSerialNumber(ASN1Integer.TWO); gen.setStartDate(new Time(startDate)); gen.setEndDate(new Time(endDate)); @@ -149,7 +149,7 @@ private void tbsV3CertGen() gen.setSignature(new AlgorithmIdentifier(PKCSObjectIdentifiers.md5WithRSAEncryption, DERNull.INSTANCE)); - SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalParameter(BigInteger.valueOf(1), BigInteger.valueOf(2))), new ASN1Integer(3)); + SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalParameter(BigInteger.valueOf(1), BigInteger.valueOf(2))), ASN1Integer.THREE); gen.setSubjectPublicKeyInfo(info); @@ -191,7 +191,7 @@ private void tbsV3CertGenWithNullSubject() Date startDate = new Date(1000); Date endDate = new Date(2000); - gen.setSerialNumber(new ASN1Integer(2)); + gen.setSerialNumber(ASN1Integer.TWO); gen.setStartDate(new Time(startDate)); gen.setEndDate(new Time(endDate)); @@ -200,7 +200,7 @@ private void tbsV3CertGenWithNullSubject() gen.setSignature(new AlgorithmIdentifier(PKCSObjectIdentifiers.md5WithRSAEncryption, DERNull.INSTANCE)); - SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalParameter(BigInteger.valueOf(1), BigInteger.valueOf(2))), new ASN1Integer(3)); + SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalParameter(BigInteger.valueOf(1), BigInteger.valueOf(2))), ASN1Integer.THREE); gen.setSubjectPublicKeyInfo(info); @@ -253,7 +253,7 @@ private void tbsV2CertListGen() gen.setIssuer(new X500Name("CN=AU,O=Bouncy Castle")); - gen.addCRLEntry(new ASN1Integer(1), new Time(new Date(1000)), CRLReason.aACompromise); + gen.addCRLEntry(ASN1Integer.ONE, new Time(new Date(1000)), CRLReason.aACompromise); gen.setNextUpdate(new Time(new Date(2000))); @@ -264,19 +264,19 @@ private void tbsV2CertListGen() // // extensions // - SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalParameter(BigInteger.valueOf(1), BigInteger.valueOf(2))), new ASN1Integer(3)); + SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalParameter(BigInteger.valueOf(1), BigInteger.valueOf(2))), ASN1Integer.THREE); ExtensionsGenerator extGen = new ExtensionsGenerator(); extGen.addExtension(Extension.authorityKeyIdentifier, true, createAuthorityKeyId(info, new X500Name("CN=AU,O=Bouncy Castle,OU=Test 2"), 2)); extGen.addExtension(Extension.issuerAlternativeName, false, new GeneralNames(new GeneralName(new X500Name("CN=AU,O=Bouncy Castle,OU=Test 3")))); - extGen.addExtension(Extension.cRLNumber, false, new ASN1Integer(1)); + extGen.addExtension(Extension.cRLNumber, false, ASN1Integer.ONE); extGen.addExtension(Extension.issuingDistributionPoint, true, IssuingDistributionPoint.getInstance(new DERSequence())); isTrue(extGen.hasExtension(Extension.cRLNumber)); isTrue(!extGen.hasExtension(Extension.freshestCRL)); - isEquals(new Extension(Extension.cRLNumber, false, new ASN1Integer(1).getEncoded()), extGen.getExtension(Extension.cRLNumber)); + isEquals(new Extension(Extension.cRLNumber, false, ASN1Integer.ONE.getEncoded()), extGen.getExtension(Extension.cRLNumber)); Extensions ex = extGen.generate(); @@ -292,9 +292,9 @@ private void tbsV2CertListGen() } // extGen - check replacement. - extGen.replaceExtension(Extension.cRLNumber, false, new ASN1Integer(2)); + extGen.replaceExtension(Extension.cRLNumber, false, ASN1Integer.TWO); - isEquals(new Extension(Extension.cRLNumber, false, new ASN1Integer(2).getEncoded()), extGen.getExtension(Extension.cRLNumber)); + isEquals(new Extension(Extension.cRLNumber, false, ASN1Integer.TWO.getEncoded()), extGen.getExtension(Extension.cRLNumber)); // extGen - check remove. extGen.removeExtension(Extension.cRLNumber); @@ -318,11 +318,11 @@ private void tbsV2CertListGen() // // check we can add a custom reason // - gen.addCRLEntry(new ASN1Integer(1), new Time(new Date(1000)), CRLReason.aACompromise); + gen.addCRLEntry(ASN1Integer.ONE, new Time(new Date(1000)), CRLReason.aACompromise); // // check invalidity date - gen.addCRLEntry(new ASN1Integer(2), new Time(new Date(1000)), CRLReason.affiliationChanged, new ASN1GeneralizedTime(new Date(2000))); + gen.addCRLEntry(ASN1Integer.TWO, new Time(new Date(1000)), CRLReason.affiliationChanged, new ASN1GeneralizedTime(new Date(2000))); TBSCertList crl = gen.generateTBSCertList(); @@ -331,7 +331,7 @@ private void tbsV2CertListGen() { TBSCertList.CRLEntry entry = entries[i]; - if (entry.getUserCertificate().equals(new ASN1Integer(1))) + if (entry.getUserCertificate().equals(ASN1Integer.ONE)) { Extensions extensions = entry.getExtensions(); Extension ext = extensions.getExtension(Extension.reasonCode); @@ -343,7 +343,7 @@ private void tbsV2CertListGen() fail("reason code mismatch"); } } - else if (entry.getUserCertificate().equals(new ASN1Integer(2))) + else if (entry.getUserCertificate().equals(ASN1Integer.TWO)) { Extensions extensions = entry.getExtensions(); Extension ext = extensions.getExtension(Extension.reasonCode); diff --git a/core/src/test/java/org/bouncycastle/asn1/test/GetInstanceTest.java b/core/src/test/java/org/bouncycastle/asn1/test/GetInstanceTest.java index faff2ffb3c..3fb70f17e0 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/GetInstanceTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/GetInstanceTest.java @@ -328,7 +328,7 @@ public void testGetInstance() doFullGetInstanceTest(DERT61String.class, new DERT61String("hello world")); doFullGetInstanceTest(DERVisibleString.class, new DERVisibleString("hello world")); - doFullGetInstanceTest(ASN1Integer.class, new ASN1Integer(1)); + doFullGetInstanceTest(ASN1Integer.class, ASN1Integer.ONE); doFullGetInstanceTest(ASN1GeneralizedTime.class, new ASN1GeneralizedTime(new Date())); doFullGetInstanceTest(ASN1UTCTime.class, new ASN1UTCTime(new Date())); doFullGetInstanceTest(ASN1Enumerated.class, new ASN1Enumerated(1)); @@ -362,7 +362,7 @@ public void testGetInstance() BasicOCSPResponse.getInstance(null); BasicOCSPResponse.getInstance(null); - doFullGetInstanceTest(CertID.class, new CertID(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE), new DEROctetString(new byte[1]), new DEROctetString(new byte[1]), new ASN1Integer(1))); + doFullGetInstanceTest(CertID.class, new CertID(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE), new DEROctetString(new byte[1]), new DEROctetString(new byte[1]), ASN1Integer.ONE)); CertStatus.getInstance(null); CertStatus.getInstance(null); diff --git a/core/src/test/java/org/bouncycastle/asn1/test/IANAObjectIdentifierTest.java b/core/src/test/java/org/bouncycastle/asn1/test/IANAObjectIdentifierTest.java new file mode 100644 index 0000000000..eee00f0bec --- /dev/null +++ b/core/src/test/java/org/bouncycastle/asn1/test/IANAObjectIdentifierTest.java @@ -0,0 +1,50 @@ +package org.bouncycastle.asn1.test; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers; +import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.TestResult; + +public class IANAObjectIdentifierTest + extends SimpleTest +{ + public String getName() + { + return "IANAObjectIdentifier"; + } + + public void performTest() + throws Exception + { + isEquals("wrong internet", new ASN1ObjectIdentifier("1.3.6.1"), IANAObjectIdentifiers.internet); + isEquals("wrong id-alg", new ASN1ObjectIdentifier("1.3.6.1.5.5.7.6"), IANAObjectIdentifiers.id_alg); + + isEquals(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256.getId(), "1.3.6.1.5.5.7.6.37"); + isEquals(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256.getId(), "1.3.6.1.5.5.7.6.38"); + isEquals(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512.getId(), "1.3.6.1.5.5.7.6.39"); + isEquals(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.getId(), "1.3.6.1.5.5.7.6.40"); + isEquals(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512.getId(), "1.3.6.1.5.5.7.6.41"); + isEquals(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512.getId(), "1.3.6.1.5.5.7.6.42"); + isEquals(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512.getId(), "1.3.6.1.5.5.7.6.43"); + isEquals(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512.getId(), "1.3.6.1.5.5.7.6.44"); + isEquals(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512.getId(), "1.3.6.1.5.5.7.6.45"); + isEquals(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512.getId(), "1.3.6.1.5.5.7.6.46"); + isEquals(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512.getId(), "1.3.6.1.5.5.7.6.47"); + isEquals(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512.getId(), "1.3.6.1.5.5.7.6.48"); + isEquals(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512.getId(), "1.3.6.1.5.5.7.6.49"); + isEquals(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512.getId(), "1.3.6.1.5.5.7.6.50"); + isEquals(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256.getId(), "1.3.6.1.5.5.7.6.51"); + isEquals(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512.getId(), "1.3.6.1.5.5.7.6.52"); + isEquals(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512.getId(), "1.3.6.1.5.5.7.6.53"); + isEquals(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512.getId(), "1.3.6.1.5.5.7.6.54"); + } + + public static void main( + String[] args) + { + IANAObjectIdentifierTest test = new IANAObjectIdentifierTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/core/src/test/java/org/bouncycastle/asn1/test/IssuingDistributionPointUnitTest.java b/core/src/test/java/org/bouncycastle/asn1/test/IssuingDistributionPointUnitTest.java index fa0af30aca..75eb9a2ef2 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/IssuingDistributionPointUnitTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/IssuingDistributionPointUnitTest.java @@ -27,7 +27,9 @@ public void performTest() new GeneralNames(new GeneralName(new X500Name("cn=test")))); ReasonFlags reasonFlags = new ReasonFlags(ReasonFlags.cACompromise); - checkPoint(6, name, true, true, reasonFlags, true, true); + checkOnlyException(name, true, true, reasonFlags, true, true); + checkOnlyException(name, true, true, reasonFlags, true, false); + checkOnlyException(name, true, false, reasonFlags, true, true); checkPoint(2, name, false, false, reasonFlags, false, false); @@ -45,6 +47,26 @@ public void performTest() } } + private void checkOnlyException( + DistributionPointName distributionPoint, + boolean onlyContainsUserCerts, + boolean onlyContainsCACerts, + ReasonFlags onlySomeReasons, + boolean indirectCRL, + boolean onlyContainsAttributeCerts) + throws IOException + { + try + { + new IssuingDistributionPoint(distributionPoint, onlyContainsUserCerts, onlyContainsCACerts, onlySomeReasons, indirectCRL, onlyContainsAttributeCerts); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("only one of onlyContainsCACerts, onlyContainsUserCerts, or onlyContainsAttributeCerts can be true", e.getMessage()); + } + } + private void checkPoint( int size, DistributionPointName distributionPoint, diff --git a/core/src/test/java/org/bouncycastle/asn1/test/KMACParamsTest.java b/core/src/test/java/org/bouncycastle/asn1/test/KMACParamsTest.java index 91fff5a722..10d6453981 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/KMACParamsTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/KMACParamsTest.java @@ -19,25 +19,25 @@ public void performTest() isTrue(Arrays.areEqual(new KMACwithSHAKE128_params(256).getEncoded(), new DERSequence().getEncoded())); isTrue(Arrays.areEqual(new KMACwithSHAKE256_params(512).getEncoded(), new DERSequence().getEncoded())); - isTrue(Arrays.areEqual(new KMACwithSHAKE128_params(512).getEncoded(), new DERSequence(new ASN1Integer(512)).getEncoded())); - isTrue(Arrays.areEqual(new KMACwithSHAKE256_params(256).getEncoded(), new DERSequence(new ASN1Integer(256)).getEncoded())); + isTrue(Arrays.areEqual(new KMACwithSHAKE128_params(512).getEncoded(), new DERSequence(ASN1Integer.valueOf(512)).getEncoded())); + isTrue(Arrays.areEqual(new KMACwithSHAKE256_params(256).getEncoded(), new DERSequence(ASN1Integer.valueOf(256)).getEncoded())); - isTrue(Arrays.areEqual(new KMACwithSHAKE128_params(512).getEncoded(), KMACwithSHAKE128_params.getInstance(new DERSequence(new ASN1Integer(512))).getEncoded())); - isTrue(Arrays.areEqual(new KMACwithSHAKE256_params(256).getEncoded(), KMACwithSHAKE256_params.getInstance(new DERSequence(new ASN1Integer(256))).getEncoded())); + isTrue(Arrays.areEqual(new KMACwithSHAKE128_params(512).getEncoded(), KMACwithSHAKE128_params.getInstance(new DERSequence(ASN1Integer.valueOf(512))).getEncoded())); + isTrue(Arrays.areEqual(new KMACwithSHAKE256_params(256).getEncoded(), KMACwithSHAKE256_params.getInstance(new DERSequence(ASN1Integer.valueOf(256))).getEncoded())); byte[] customizationString = Strings.toByteArray("hello, world!"); isTrue(Arrays.areEqual(new KMACwithSHAKE128_params(512, customizationString).getEncoded(), new DERSequence( - new ASN1Encodable[] { new ASN1Integer(512), new DEROctetString(customizationString) }).getEncoded())); + new ASN1Encodable[] { ASN1Integer.valueOf(512), new DEROctetString(customizationString) }).getEncoded())); isTrue(Arrays.areEqual(new KMACwithSHAKE256_params(256, customizationString).getEncoded(), new DERSequence( - new ASN1Encodable[] { new ASN1Integer(256), new DEROctetString(customizationString) }).getEncoded())); + new ASN1Encodable[] { ASN1Integer.valueOf(256), new DEROctetString(customizationString) }).getEncoded())); isTrue(Arrays.areEqual(new KMACwithSHAKE128_params(512, customizationString).getEncoded(), KMACwithSHAKE128_params.getInstance( - new DERSequence(new ASN1Encodable[] { new ASN1Integer(512), new DEROctetString(customizationString) })).getEncoded())); + new DERSequence(new ASN1Encodable[] { ASN1Integer.valueOf(512), new DEROctetString(customizationString) })).getEncoded())); isTrue(Arrays.areEqual(new KMACwithSHAKE256_params(256, customizationString).getEncoded(), KMACwithSHAKE256_params.getInstance(new DERSequence( - new ASN1Encodable[] { new ASN1Integer(256), new DEROctetString(customizationString) })).getEncoded())); + new ASN1Encodable[] { ASN1Integer.valueOf(256), new DEROctetString(customizationString) })).getEncoded())); isTrue(Arrays.areEqual(new KMACwithSHAKE128_params(256, customizationString).getEncoded(), new DERSequence( new ASN1Encodable[] { new DEROctetString(customizationString) }).getEncoded())); diff --git a/core/src/test/java/org/bouncycastle/asn1/test/LinkedCertificateTest.java b/core/src/test/java/org/bouncycastle/asn1/test/LinkedCertificateTest.java index 340e5f317d..72e9eb5294 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/LinkedCertificateTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/LinkedCertificateTest.java @@ -70,11 +70,7 @@ private void checkConstruction( checkValues(linked, digestInfo, certLocation, certIssuer, caCerts); - ASN1InputStream aIn = new ASN1InputStream(linked.toASN1Primitive().getEncoded()); - - ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); - - linked = LinkedCertificate.getInstance(seq); + linked = LinkedCertificate.getInstance(linked.getEncoded()); checkValues(linked, digestInfo, certLocation, certIssuer, caCerts); } diff --git a/core/src/test/java/org/bouncycastle/asn1/test/PolicyConstraintsTest.java b/core/src/test/java/org/bouncycastle/asn1/test/PolicyConstraintsTest.java index bc0d2f09bd..3359867898 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/PolicyConstraintsTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/PolicyConstraintsTest.java @@ -44,7 +44,7 @@ public void performTest() isTrue("encoding test", Arrays.areEqual( new PolicyConstraints(BigInteger.valueOf(1), null).getEncoded(), - new DERSequence(new DERTaggedObject(false, 0, new ASN1Integer(1))).getEncoded())); + new DERSequence(new DERTaggedObject(false, 0, ASN1Integer.ONE)).getEncoded())); } public static void main( diff --git a/core/src/test/java/org/bouncycastle/asn1/test/RegressionTest.java b/core/src/test/java/org/bouncycastle/asn1/test/RegressionTest.java index 0cdcfbf37a..c6fa0b88f8 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/RegressionTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/RegressionTest.java @@ -56,7 +56,8 @@ public class RegressionTest new KMACParamsTest(), new DERPrivateTest(), new X509AltTest(), - new CertIDTest() + new CertIDTest(), + new IANAObjectIdentifierTest() }; public static void main(String[] args) diff --git a/core/src/test/java/org/bouncycastle/asn1/test/SetTest.java b/core/src/test/java/org/bouncycastle/asn1/test/SetTest.java index d1f1707cd0..5d720308fb 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/SetTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/SetTest.java @@ -48,13 +48,13 @@ public void performTest() v.add(new DEROctetString(data)); v.add(new DERBitString(data)); - v.add(new ASN1Integer(100)); + v.add(ASN1Integer.valueOf(100)); v.add(ASN1Boolean.getInstance(true)); checkedSortedSet(0, new DERSet(v)); v = new ASN1EncodableVector(); - v.add(new ASN1Integer(100)); + v.add(ASN1Integer.valueOf(100)); v.add(ASN1Boolean.getInstance(true)); v.add(new DEROctetString(data)); v.add(new DERBitString(data)); @@ -65,7 +65,7 @@ public void performTest() v.add(ASN1Boolean.getInstance(true)); v.add(new DEROctetString(data)); v.add(new DERBitString(data)); - v.add(new ASN1Integer(100)); + v.add(ASN1Integer.valueOf(100)); checkedSortedSet(2, new DERSet(v)); @@ -73,7 +73,7 @@ public void performTest() v = new ASN1EncodableVector(); v.add(new DERBitString(data)); v.add(new DEROctetString(data)); - v.add(new ASN1Integer(100)); + v.add(ASN1Integer.valueOf(100)); v.add(ASN1Boolean.getInstance(true)); checkedSortedSet(3, new DERSet(v)); @@ -81,7 +81,7 @@ public void performTest() v = new ASN1EncodableVector(); v.add(new DEROctetString(data)); v.add(new DERBitString(data)); - v.add(new ASN1Integer(100)); + v.add(ASN1Integer.valueOf(100)); v.add(ASN1Boolean.getInstance(true)); ASN1Set s = new BERSet(v); diff --git a/core/src/test/java/org/bouncycastle/asn1/test/StringTest.java b/core/src/test/java/org/bouncycastle/asn1/test/StringTest.java index 50c9535ad5..27c8860010 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/StringTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/StringTest.java @@ -1,7 +1,6 @@ package org.bouncycastle.asn1.test; import java.io.IOException; -import java.io.UnsupportedEncodingException; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1String; @@ -90,7 +89,7 @@ public void performTest() try { - String t61String = new String(t61Bytes, "iso-8859-1"); + String t61String = StringTestUtil.fromISO_8891(t61Bytes); ASN1T61String t61 = new DERT61String(Strings.fromByteArray(t61Bytes)); if (!t61.getString().equals(t61String)) @@ -103,8 +102,8 @@ public void performTest() fail("DERT61String.toString() result incorrect"); } } - catch (UnsupportedEncodingException e) - { + catch (IllegalStateException e) + { // ignore test } diff --git a/core/src/test/java/org/bouncycastle/asn1/test/StringTestUtil.java b/core/src/test/java/org/bouncycastle/asn1/test/StringTestUtil.java new file mode 100644 index 0000000000..4430f7970a --- /dev/null +++ b/core/src/test/java/org/bouncycastle/asn1/test/StringTestUtil.java @@ -0,0 +1,32 @@ +package org.bouncycastle.asn1.test; + +import java.io.UnsupportedEncodingException; + +import org.bouncycastle.util.Exceptions; + +class StringTestUtil +{ + static byte[] toISO_8891(String str) + { + try + { + return str.getBytes("iso-8859-1"); + } + catch (UnsupportedEncodingException e) + { + throw Exceptions.illegalStateException(e.getMessage(), e); + } + } + + static String fromISO_8891(byte[] encStr) + { + try + { + return new String(encStr, "iso-8859-1"); + } + catch (UnsupportedEncodingException e) + { + throw Exceptions.illegalStateException(e.getMessage(), e); + } + } +} diff --git a/core/src/test/java/org/bouncycastle/asn1/test/TagTest.java b/core/src/test/java/org/bouncycastle/asn1/test/TagTest.java index 4f6edad492..b225c1b43b 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/TagTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/TagTest.java @@ -110,7 +110,7 @@ public void performTest() } } - tagged = new DERTaggedObject(false, 34, new DERTaggedObject(true, 1000, new ASN1Integer(1))); + tagged = new DERTaggedObject(false, 34, new DERTaggedObject(true, 1000, ASN1Integer.ONE)); if (!areEqual(taggedInteger, tagged.getEncoded())) { fail("incorrect encoding for implicit explicit tagged integer"); diff --git a/core/src/test/java/org/bouncycastle/asn1/test/X500NameTest.java b/core/src/test/java/org/bouncycastle/asn1/test/X500NameTest.java index e05b9ccb73..8ddbdc87f4 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/X500NameTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/X500NameTest.java @@ -435,6 +435,8 @@ public void performTest() fail("strict comparison failed"); } + equalityTest(new X500Name(""), new X500Name("")); + // // inequality to sequences // diff --git a/core/src/test/java/org/bouncycastle/asn1/test/X509NameTest.java b/core/src/test/java/org/bouncycastle/asn1/test/X509NameTest.java index 9d5880cf28..0378c83e74 100644 --- a/core/src/test/java/org/bouncycastle/asn1/test/X509NameTest.java +++ b/core/src/test/java/org/bouncycastle/asn1/test/X509NameTest.java @@ -402,6 +402,8 @@ public void performTest() equalityTest(n1, n2); + equalityTest(new X509Name(""), new X509Name("")); + // // inequality to sequences // diff --git a/core/src/test/java/org/bouncycastle/crypto/agreement/test/ECJPAKEUtilTest.java b/core/src/test/java/org/bouncycastle/crypto/agreement/test/ECJPAKEUtilTest.java index 86f7ab2571..59e16d2fd9 100644 --- a/core/src/test/java/org/bouncycastle/crypto/agreement/test/ECJPAKEUtilTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/agreement/test/ECJPAKEUtilTest.java @@ -18,7 +18,6 @@ public class ECJPAKEUtilTest extends TestCase { - private static final BigInteger TEN = BigInteger.valueOf(10); private static final BigInteger ONE = BigInteger.valueOf(1); public void testValidateParticipantIdsDiffer() @@ -217,7 +216,7 @@ public void testValidateZeroKnowledgeProof() } // (x,y) elements for Gx are not in Fq ie: not in [0,q-1] - ECCurve.Fp curve = (ECCurve.Fp)curve1.getCurve(); + ECCurve.AbstractFp curve = curve1.getCurve(); try { ECPoint invalidGx_1 = curve.createPoint(ONE.negate(), ONE); diff --git a/core/src/test/java/org/bouncycastle/crypto/test/AsconTest.java b/core/src/test/java/org/bouncycastle/crypto/test/AsconTest.java index 010262c35f..3d996ee8d1 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/AsconTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/AsconTest.java @@ -3,6 +3,7 @@ import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; +import java.security.SecureRandom; import java.util.HashMap; import java.util.Random; @@ -44,9 +45,16 @@ public String getName() public void performTest() throws Exception { + testCounter(); + testVectorsAsconCXof128_512(); + DigestTest.checkXof(new AsconXof128(), 1429, 317, new SecureRandom(), this); + DigestTest.checkXof(new AsconCXof128(), 1429, 317, new SecureRandom(), this); + DigestTest.checkXof(new AsconXof(AsconXof.AsconParameters.AsconXof), 1429, 317, new SecureRandom(), this); + DigestTest.checkXof(new AsconXof(AsconXof.AsconParameters.AsconXofA), 1429, 317, new SecureRandom(), this); + + testVectorsEngine_asconaead128(); testVectorsDigest_AsconHash256(); testVectorsXof_AsconXof128(); - testVectorsEngine_asconaead128(); testBufferingEngine_asconaead128(); testBufferingEngine_ascon128(); @@ -63,10 +71,15 @@ public void performTest() testExceptionsEngine_ascon80pq(); testExceptionsXof_AsconXof128(); - testExceptionsXof_AsconCxof128(); + testExceptionsXof_AsconCXof128(); testExceptionsXof_AsconXof(); testExceptionsXof_AsconXofA(); + testOutputXof_AsconXof128(); + testOutputXof_AsconCXof128(); + testOutputXof_AsconXof(); + testOutputXof_AsconXofA(); + testParametersDigest_AsconHash256(); testParametersDigest_AsconHash(); testParametersDigest_AsconHashA(); @@ -77,7 +90,7 @@ public void performTest() testParametersEngine_ascon80pq(); testParametersXof_AsconXof128(); - testParametersXof_AsconCxof128(); + testParametersXof_AsconCXof128(); testParametersXof_AsconXof(); testParametersXof_AsconXofA(); @@ -91,10 +104,16 @@ public void performTest() testVectorsXof_AsconXof(); testVectorsXof_AsconXofA(); - CipherTest.checkAEADParemeter(this, 16,16, 16, 16, new AsconAEAD128()); - CipherTest.checkAEADParemeter(this, 16,16, 16, 16, new AsconEngine(AsconEngine.AsconParameters.ascon128)); - CipherTest.checkAEADParemeter(this, 16,16, 16, 16, new AsconEngine(AsconEngine.AsconParameters.ascon128a)); - CipherTest.checkAEADParemeter(this, 20,16, 16, 16, new AsconEngine(AsconEngine.AsconParameters.ascon80pq)); + CipherTest.checkAEADParemeter(this, 16, 16, 16, 16, new AsconAEAD128()); + CipherTest.checkAEADParemeter(this, 16, 16, 16, 16, new AsconEngine(AsconEngine.AsconParameters.ascon128)); + CipherTest.checkAEADParemeter(this, 16, 16, 16, 16, new AsconEngine(AsconEngine.AsconParameters.ascon128a)); + CipherTest.checkAEADParemeter(this, 20, 16, 16, 16, new AsconEngine(AsconEngine.AsconParameters.ascon80pq)); + + CipherTest.testOverlapping(this, 16, 16, 16, 16, new AsconAEAD128()); + CipherTest.testOverlapping(this, 16, 16, 16, 16, new AsconEngine(AsconEngine.AsconParameters.ascon128)); + CipherTest.testOverlapping(this, 16, 16, 16, 16, new AsconEngine(AsconEngine.AsconParameters.ascon128a)); + CipherTest.testOverlapping(this, 20, 16, 16, 16, new AsconEngine(AsconEngine.AsconParameters.ascon80pq)); + CipherTest.checkCipher(32, 16, 100, 128, new CipherTest.Instance() { @@ -140,10 +159,6 @@ public AEADCipher createInstance() DigestTest.checkDigestReset(this, new AsconXof(AsconXof.AsconParameters.AsconXofA)); DigestTest.checkDigestReset(this, new AsconDigest(AsconDigest.AsconParameters.AsconHash)); DigestTest.checkDigestReset(this, new AsconDigest(AsconDigest.AsconParameters.AsconHashA)); - CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 41, 10, 128, 16, new AsconAEAD128()); - CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 41, 10, 128, 16, new AsconEngine(AsconEngine.AsconParameters.ascon128)); - CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 41, 10, 128, 16, new AsconEngine(AsconEngine.AsconParameters.ascon128a)); - CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 41, 10, 160, 16, new AsconEngine(AsconEngine.AsconParameters.ascon80pq)); } public void testBufferingEngine_ascon128() @@ -328,7 +343,7 @@ public ExtendedDigest createDigest() }); } - public void testExceptionsXof_AsconCxof128() + public void testExceptionsXof_AsconCXof128() throws Exception { implTestExceptionsXof(new CreateDigest() @@ -341,6 +356,26 @@ public ExtendedDigest createDigest() }); } + public void testOutputXof_AsconXof() + { + implTestOutputXof(new AsconXof(AsconXof.AsconParameters.AsconXof)); + } + + public void testOutputXof_AsconXofA() + { + implTestOutputXof(new AsconXof(AsconXof.AsconParameters.AsconXofA)); + } + + public void testOutputXof_AsconXof128() + { + implTestOutputXof(new AsconXof128()); + } + + public void testOutputXof_AsconCXof128() + { + implTestOutputXof(new AsconCXof128()); + } + public void testParametersDigest_AsconHash() throws Exception { @@ -457,7 +492,7 @@ public ExtendedDigest createDigest() }, 32); } - public void testParametersXof_AsconCxof128() + public void testParametersXof_AsconCXof128() throws Exception { implTestParametersDigest(new CreateDigest() @@ -518,6 +553,12 @@ public void testVectorsXof_AsconXof128() implTestVectorsXof(new AsconXof128(), "crypto/ascon/asconxof128", "LWC_HASH_KAT_256.txt"); } + public void testVectorsAsconCXof128_512() + throws Exception + { + implTestVectorsAsconCXof128(512 / 8, "crypto/ascon/asconcxof128", "LWC_CXOF_KAT_128_512.txt"); + } + public void testVectorsXof_AsconXof() throws Exception { @@ -996,6 +1037,35 @@ private void implTestExceptionsXof(CreateDigest operator) } } + private void implTestOutputXof(Xof ascon) + { + Random random = new Random(); + + byte[] expected = new byte[64]; + ascon.doFinal(expected, 0, expected.length); + + byte[] output = new byte[64]; + for (int i = 0; i < 64; ++i) + { + random.nextBytes(output); + + int pos = 0; + while (pos <= output.length - 16) + { + int len = random.nextInt(17); + ascon.doOutput(output, pos, len); + pos += len; + } + + ascon.doFinal(output, pos, output.length - pos); + + if (!areEqual(expected, output)) + { + fail(""); + } + } + } + private void implTestParametersDigest(CreateDigest operator, int digestSize) { ExtendedDigest ascon = operator.createDigest(); @@ -1170,6 +1240,54 @@ private void implTestVectorsEngine(AEADCipher ascon, String path, String filenam } } + private void implTestVectorsAsconCXof128(int hash_length, String path, String filename) + throws Exception + { + Random random = new Random(); + + InputStream src = TestResourceFinder.findTestResource(path, filename); + BufferedReader bin = new BufferedReader(new InputStreamReader(src)); + String line; + HashMap map = new HashMap(); + while ((line = bin.readLine()) != null) + { + int a = line.indexOf('='); + if (a < 0) + { + byte[] zByte = Hex.decode((String)map.get("Z")); + byte[] ptByte = Hex.decode((String)map.get("Msg")); + byte[] expected = Hex.decode((String)map.get("MD")); + + byte[] hash = new byte[hash_length]; + + AsconCXof128 ascon = new AsconCXof128(zByte); + ascon.update(ptByte, 0, ptByte.length); + ascon.doFinal(hash, 0, hash_length); + if (!areEqual(hash, expected)) + { + mismatch("Keystream " + map.get("Count"), (String)map.get("MD"), hash); + } + + if (ptByte.length > 1) + { + int split = random.nextInt(ptByte.length - 1) + 1; + ascon = new AsconCXof128(zByte); + ascon.update(ptByte, 0, split); + ascon.update(ptByte, split, ptByte.length - split); + ascon.doFinal(hash, 0, hash_length); + if (!areEqual(hash, expected)) + { + mismatch("Keystream " + map.get("Count"), (String)map.get("MD"), hash); + } + } + } + else + { + map.put(line.substring(0, a).trim(), line.substring(a + 1).trim()); + } + } + } + private void implTestVectorsXof(Xof ascon, String path, String filename) throws Exception { @@ -1238,4 +1356,127 @@ private static void initEngine(AEADCipher ascon, boolean forEncryption) AEADParameters parameters = new AEADParameters(new KeyParameter(new byte[keySize]), macSize, new byte[ivSize], null); ascon.init(forEncryption, parameters); } + + protected static class Counter + { + int n; + int[] counter; + + public void init(int n) + { + if (this.n != n) + { + this.n = n; + int len = (n + 31) >>> 5; + if (counter == null || len != counter.length) + { + counter = new int[len]; + } + else + { + reset(); + } + } + } + + public boolean increment() + { + int i = counter.length; + while (--i >= 0) + { + if (++counter[i] != 0) + { + break; + } + } + int r = n & 31; + return i <= 0 && counter[0] == (r == 0 ? 0 : (1 << r)); + } + + public boolean increment(int delta) + { + // Convert to long to handle unsigned arithmetic + long carry = delta & 0xFFFFFFFFL; + // Process each word starting from LSB + int i = counter.length; + while (carry != 0 && --i >= 0) + { + long sum = (counter[i] & 0xFFFFFFFFL) + carry; + counter[i] = (int)sum; + carry = sum >>> 32; + } + + // Final limit check if we didn't overflow + return carry != 0 || checkLimit(); + } + + private boolean checkLimit() + { + int bitIndex = ((n - 1) & 31) + 1; + long bound = 1L << bitIndex; + long val = counter[0] & 0xFFFFFFFFL; + if (val > bound) + { + return true; + } + if (val < bound) + { + return false; + } + // Check if we've reached/exceeded 2^n + for (int i = 1; i < counter.length; ++i) + { + val = counter[i] & 0xFFFFFFFFL; + if (val > 0) + { + return true; + } + } + return true; // Exactly equal to 2^n + } + + public void reset() + { + Arrays.fill(counter, 0); + } + } + + public void testCounter() + { + Counter counter = new Counter(); + counter.init(64); + isTrue(!counter.increment(-1)); + isTrue(!counter.increment()); + isTrue(!counter.increment(-1)); + isTrue(!counter.increment()); + + counter.init(33); + isTrue(!counter.increment(-1)); + isTrue(!counter.increment()); + isTrue(!counter.increment(-1)); + isTrue(counter.increment()); + + counter.init(32); + isTrue(!counter.increment(-1)); + isTrue(counter.increment()); + counter.reset(); + isTrue(!counter.increment()); + counter.reset(); + isTrue(!counter.increment(-1)); + isTrue(counter.increment(1)); + + counter.init(31); + isTrue(!counter.increment((1 << 31) - 1)); + isTrue(counter.increment()); + counter.reset(); + isTrue(!counter.increment(1 << 30)); + isTrue(counter.increment(1 << 30)); + counter.reset(); + isTrue(!counter.increment(1 << 30)); + isTrue(counter.increment((1 << 30) + 1)); + + counter.init(5); + isTrue(!counter.increment((1 << 5) - 1)); + isTrue(counter.increment()); + } } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/CCMTest.java b/core/src/test/java/org/bouncycastle/crypto/test/CCMTest.java index b6511e2ae5..5a79a811cd 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/CCMTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/CCMTest.java @@ -4,6 +4,7 @@ import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.engines.DESEngine; import org.bouncycastle.crypto.modes.CCMBlockCipher; +import org.bouncycastle.crypto.modes.CCMModeCipher; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; @@ -56,6 +57,8 @@ public class CCMTest public void performTest() throws Exception { + // TODO Need to resolve dependency on processPacket methods (add them to CCMModeCipher?) +// CCMModeCipher ccm = CCMBlockCipher.newInstance(AESEngine.newInstance()); CCMBlockCipher ccm = new CCMBlockCipher(AESEngine.newInstance()); checkVectors(0, ccm, K1, 32, N1, A1, P1, T1, C1); @@ -131,6 +134,8 @@ public void performTest() try { + // TODO Need to resolve dependency on processPacket methods (add them to CCMModeCipher?) +// ccm = CCMBlockCipher.newInstance(new DESEngine()); ccm = new CCMBlockCipher(new DESEngine()); fail("incorrect block size not picked up"); @@ -198,12 +203,13 @@ public void performTest() } } - AEADTestUtil.testReset(this, new CCMBlockCipher(AESEngine.newInstance()), new CCMBlockCipher(AESEngine.newInstance()), new AEADParameters(new KeyParameter(K1), 32, N2)); + AEADTestUtil.testReset(this, CCMBlockCipher.newInstance(AESEngine.newInstance()), + CCMBlockCipher.newInstance(AESEngine.newInstance()), new AEADParameters(new KeyParameter(K1), 32, N2)); AEADTestUtil.testTampering(this, ccm, new AEADParameters(new KeyParameter(K1), 32, N2)); - AEADTestUtil.testOutputSizes(this, new CCMBlockCipher(AESEngine.newInstance()), new AEADParameters( - new KeyParameter(K1), 32, N2)); - AEADTestUtil.testBufferSizeChecks(this, new CCMBlockCipher(AESEngine.newInstance()), new AEADParameters( - new KeyParameter(K1), 32, N2)); + AEADTestUtil.testOutputSizes(this, CCMBlockCipher.newInstance(AESEngine.newInstance()), + new AEADParameters(new KeyParameter(K1), 32, N2)); + AEADTestUtil.testBufferSizeChecks(this, CCMBlockCipher.newInstance(AESEngine.newInstance()), + new AEADParameters(new KeyParameter(K1), 32, N2)); } private boolean isEqual(byte[] exp, byte[] other, int off) @@ -221,7 +227,7 @@ private boolean isEqual(byte[] exp, byte[] other, int off) private void checkVectors( int count, - CCMBlockCipher ccm, + CCMModeCipher ccm, byte[] k, int macSize, byte[] n, @@ -244,7 +250,7 @@ private void checkVectors( private void checkVectors( int count, - CCMBlockCipher ccm, + CCMModeCipher ccm, String additionalDataType, byte[] k, int macSize, @@ -307,7 +313,7 @@ private void checkVectors( private void ivParamTest( int count, - CCMBlockCipher ccm, + CCMModeCipher ccm, byte[] k, byte[] n) throws InvalidCipherTextException diff --git a/core/src/test/java/org/bouncycastle/crypto/test/CSHAKETest.java b/core/src/test/java/org/bouncycastle/crypto/test/CSHAKETest.java index f86e87f44d..743515920e 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/CSHAKETest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/CSHAKETest.java @@ -1,11 +1,11 @@ package org.bouncycastle.crypto.test; +import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.CSHAKEDigest; import org.bouncycastle.crypto.digests.SHAKEDigest; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.test.SimpleTest; /** * CSHAKE test vectors from: @@ -13,16 +13,48 @@ * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/cSHAKE_samples.pdf */ public class CSHAKETest - extends SimpleTest + extends DigestTest { + private static String[] messages = + { + "", + "a", + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + }; + + private static String[] digests = + { + "28a0e58d342a45ef1522d69cd41748beee29c188364df18c84ed4ab8bed0cc85", + "cb0a67f6ff4a3b64497a757a85bda4a275cf11970ff226abd2bf2bbcba5890ea", + "346c136daea11c436d8d9e668e08888bd4e341dae05da4cb8773f74402c5bdbc", + "64602dc88c880bdfb6d0c9163a72b2e3653ab6114e4f4e25d7aaf5b8d441e36f" + }; + + public CSHAKETest() + { + super(new CSHAKEDigest(128, new byte[1], new byte[1]), messages, digests); + } + public String getName() { return "CSHAKE"; } + protected Digest cloneDigest(Digest digest) + { + return new CSHAKEDigest((CSHAKEDigest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new CSHAKEDigest(encodedState); + } + public void performTest() - throws Exception { + super.performTest(); + CSHAKEDigest cshake = new CSHAKEDigest(128, new byte[0], Strings.toByteArray("Email Signature")); cshake.update(Hex.decode("00010203"), 0, 4); diff --git a/core/src/test/java/org/bouncycastle/crypto/test/CTSTest.java b/core/src/test/java/org/bouncycastle/crypto/test/CTSTest.java index e59c95844b..5b61e8d2d2 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/CTSTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/CTSTest.java @@ -1,5 +1,7 @@ package org.bouncycastle.crypto.test; +import java.security.SecureRandom; + import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.CipherParameters; @@ -14,6 +16,7 @@ import org.bouncycastle.crypto.modes.SICBlockCipher; 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; @@ -23,22 +26,22 @@ public class CTSTest extends SimpleTest { - static byte[] in1 = Hex.decode("4e6f7720697320746865207420"); - static byte[] in2 = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f0aaa"); - static byte[] out1 = Hex.decode("9952f131588465033fa40e8a98"); - static byte[] out2 = Hex.decode("358f84d01eb42988dc34efb994"); - static byte[] out3 = Hex.decode("170171cfad3f04530c509b0c1f0be0aefbd45a8e3755a873bff5ea198504b71683c6"); - + static byte[] in1 = Hex.decode("4e6f7720697320746865207420"); + static byte[] in2 = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f0aaa"); + static byte[] out1 = Hex.decode("9952f131588465033fa40e8a98"); + static byte[] out2 = Hex.decode("358f84d01eb42988dc34efb994"); + static byte[] out3 = Hex.decode("170171cfad3f04530c509b0c1f0be0aefbd45a8e3755a873bff5ea198504b71683c6"); + private void testCTS( - int id, - BlockCipher cipher, - CipherParameters params, - byte[] input, - byte[] output) + int id, + BlockCipher cipher, + CipherParameters params, + byte[] input, + byte[] output) throws Exception { - byte[] out = new byte[input.length]; - BufferedBlockCipher engine = new CTSBlockCipher(cipher); + byte[] out = new byte[input.length]; + BufferedBlockCipher engine = new CTSBlockCipher(cipher); engine.init(true, params); @@ -64,15 +67,15 @@ private void testCTS( } private void testOldCTS( - int id, - BlockCipher cipher, - CipherParameters params, - byte[] input, - byte[] output) - throws Exception + int id, + BlockCipher cipher, + CipherParameters params, + byte[] input, + byte[] output) + throws Exception { - byte[] out = new byte[input.length]; - BufferedBlockCipher engine = new OldCTSBlockCipher(cipher); + byte[] out = new byte[input.length]; + BufferedBlockCipher engine = new OldCTSBlockCipher(cipher); engine.init(true, params); @@ -97,77 +100,159 @@ private void testOldCTS( } } - private void testExceptions() throws InvalidCipherTextException + private void testExceptions() + throws InvalidCipherTextException { BufferedBlockCipher engine = new CTSBlockCipher(new DESEngine()); CipherParameters params = new KeyParameter(new byte[engine.getBlockSize()]); engine.init(true, params); byte[] out = new byte[engine.getOutputSize(engine.getBlockSize())]; - + engine.processBytes(new byte[engine.getBlockSize() - 1], 0, engine.getBlockSize() - 1, out, 0); - try + try { engine.doFinal(out, 0); fail("Expected CTS encrypt error on < 1 block input"); - } catch(DataLengthException e) + } + catch (DataLengthException e) { // Expected } engine.init(true, params); engine.processBytes(new byte[engine.getBlockSize()], 0, engine.getBlockSize(), out, 0); - try + try { engine.doFinal(out, 0); - } catch(DataLengthException e) + } + catch (DataLengthException e) { fail("Unexpected CTS encrypt error on == 1 block input"); } engine.init(false, params); engine.processBytes(new byte[engine.getBlockSize() - 1], 0, engine.getBlockSize() - 1, out, 0); - try + try { engine.doFinal(out, 0); fail("Expected CTS decrypt error on < 1 block input"); - } catch(DataLengthException e) + } + catch (DataLengthException e) { // Expected } engine.init(false, params); engine.processBytes(new byte[engine.getBlockSize()], 0, engine.getBlockSize(), out, 0); - try + try { engine.doFinal(out, 0); - } catch(DataLengthException e) + } + catch (DataLengthException e) { fail("Unexpected CTS decrypt error on == 1 block input"); } - try + try { new CTSBlockCipher(SICBlockCipher.newInstance(AESEngine.newInstance())); fail("Expected CTS construction error - only ECB/CBC supported."); - } catch(IllegalArgumentException e) + } + catch (IllegalArgumentException e) { // Expected } } + private void testOverlapping() + throws Exception + { + //Skip the dofinal of the test + CTSBlockCipher bc = new CTSBlockCipher(AESEngine.newInstance()); + SecureRandom random = new SecureRandom(); + byte[] keyBytes = new byte[16]; + random.nextBytes(keyBytes); + KeyParameter key = new KeyParameter(keyBytes); + + int offset = 1 + random.nextInt(bc.getBlockSize() - 1) + bc.getBlockSize(); + byte[] data = new byte[bc.getBlockSize() * 4 + offset]; + byte[] expected = new byte[bc.getOutputSize(bc.getBlockSize() * 3)]; + random.nextBytes(data); + + bc.init(true, key); + int len = bc.processBytes(data, 0, expected.length, expected, 0); + bc.doFinal(expected, len); + bc.init(true, key); + len = bc.processBytes(data, 0, expected.length, data, offset); + bc.doFinal(data, offset + len); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + expected.length))) + { + fail("failed for overlapping encryption"); + } + + bc.init(false, key); + bc.processBytes(data, 0, expected.length, expected, 0); + bc.init(false, key); + bc.processBytes(data, 0, expected.length, data, offset); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + expected.length))) + { + fail("failed for overlapping decryption"); + } + } + + private void testOverlapping2() + throws Exception + { + //Skip the dofinal of the test + OldCTSBlockCipher bc = new OldCTSBlockCipher(AESEngine.newInstance()); + SecureRandom random = new SecureRandom(); + byte[] keyBytes = new byte[16]; + random.nextBytes(keyBytes); + KeyParameter key = new KeyParameter(keyBytes); + + int offset = 1 + random.nextInt(bc.getBlockSize() - 1) + bc.getBlockSize(); + byte[] data = new byte[bc.getBlockSize() * 4 + offset]; + byte[] expected = new byte[bc.getOutputSize(bc.getBlockSize() * 3)]; + random.nextBytes(data); + + bc.init(true, key); + int len = bc.processBytes(data, 0, expected.length, expected, 0); + bc.doFinal(expected, len); + bc.init(true, key); + len = bc.processBytes(data, 0, expected.length, data, offset); + bc.doFinal(data, offset + len); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + expected.length))) + { + fail("failed for overlapping encryption"); + } + + bc.init(false, key); + bc.processBytes(data, 0, expected.length, expected, 0); + bc.init(false, key); + bc.processBytes(data, 0, expected.length, data, offset); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + expected.length))) + { + fail("failed for overlapping decryption"); + } + } + public String getName() { return "CTS"; } - public void performTest() + public void performTest() throws Exception { - byte[] key1 = { (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF }; - byte[] key2 = { (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF, (byte)0xee, (byte)0xff }; - byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8 }; + byte[] key1 = {(byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF}; + byte[] key2 = {(byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF, (byte)0xee, (byte)0xff}; + byte[] iv = {1, 2, 3, 4, 5, 6, 7, 8}; testCTS(1, new DESEngine(), new KeyParameter(key1), in1, out1); testCTS(2, new CBCBlockCipher(new DESEngine()), new ParametersWithIV(new KeyParameter(key1), iv), in1, out2); @@ -177,11 +262,11 @@ public void performTest() // test vectors from rfc3962 // byte[] aes128 = Hex.decode("636869636b656e207465726979616b69"); - byte[] aesIn1 = Hex.decode("4920776f756c64206c696b652074686520"); + byte[] aesIn1 = Hex.decode("4920776f756c64206c696b652074686520"); byte[] aesOut1 = Hex.decode("c6353568f2bf8cb4d8a580362da7ff7f97"); - byte[] aesIn2 = Hex.decode("4920776f756c64206c696b65207468652047656e6572616c20476175277320"); + byte[] aesIn2 = Hex.decode("4920776f756c64206c696b65207468652047656e6572616c20476175277320"); byte[] aesOut2 = Hex.decode("fc00783e0efdb2c1d445d4c8eff7ed2297687268d6ecccc0c07b25e25ecfe5"); - byte[] aesIn3 = Hex.decode("4920776f756c64206c696b65207468652047656e6572616c2047617527732043"); + byte[] aesIn3 = Hex.decode("4920776f756c64206c696b65207468652047656e6572616c2047617527732043"); byte[] aesOut3 = Hex.decode("39312523a78662d5be7fcbcc98ebf5a897687268d6ecccc0c07b25e25ecfe584"); testCTS(4, new CBCBlockCipher(AESEngine.newInstance()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aesIn1, aesOut1); @@ -202,16 +287,18 @@ public void performTest() testOldCTS(9, new CBCBlockCipher(AESEngine.newInstance()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aes1Block, preErrata); byte[] aes128b = Hex.decode("aafd12f659cae63489b479e5076ddec2f06cb58faafd12f6"); - byte[] aesIn1b = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"); + byte[] aesIn1b = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"); byte[] aesOut1b = Hex.decode("6db2f802d99e1ef0a5940f306079e083cf87f4d8bb9d1abb36cdd9f44ead7d04"); testCTS(10, new CBCBlockCipher(AESEngine.newInstance()), new ParametersWithIV(new KeyParameter(aes128b), Hex.decode("aafd12f659cae63489b479e5076ddec2")), aesIn1b, aesOut1b); testExceptions(); + testOverlapping(); + testOverlapping2(); } public static void main( - String[] args) + String[] args) { runTest(new CTSTest()); } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/ChaCha20Poly1305Test.java b/core/src/test/java/org/bouncycastle/crypto/test/ChaCha20Poly1305Test.java index 042049f03b..b8dc6a5c29 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/ChaCha20Poly1305Test.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/ChaCha20Poly1305Test.java @@ -3,10 +3,13 @@ import java.security.SecureRandom; import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.macs.SipHash; +import org.bouncycastle.crypto.modes.CTSBlockCipher; import org.bouncycastle.crypto.modes.ChaCha20Poly1305; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; import org.bouncycastle.util.Times; import org.bouncycastle.util.encoders.Hex; @@ -48,6 +51,7 @@ public String getName() public void performTest() throws Exception { + testOverlapping(); for (int i = 0; i < TEST_VECTORS.length; ++i) { runTestCase(TEST_VECTORS[i]); @@ -439,6 +443,55 @@ private void testExceptions() throws InvalidCipherTextException } } + private void testOverlapping() + throws Exception + { + SecureRandom random = new SecureRandom(); + int kLength = 32; + byte[] K = new byte[kLength]; + random.nextBytes(K); + + int aLength = random.nextInt() >>> 24; + byte[] A = new byte[aLength]; + random.nextBytes(A); + + int nonceLength = 12; + byte[] nonce = new byte[nonceLength]; + random.nextBytes(nonce); + + AEADParameters parameters = new AEADParameters(new KeyParameter(K), 16 * 8, nonce, A); + + ChaCha20Poly1305 bc = initCipher(true, parameters); + + final int blockSize = 64; + int offset = 1 + random.nextInt(blockSize - 1) + blockSize; + byte[] data = new byte[blockSize * 4 + offset]; + byte[] expected = new byte[bc.getOutputSize(blockSize * 3)]; + random.nextBytes(data); + + + int len = bc.processBytes(data, 0, blockSize * 3, expected, 0); + bc.doFinal(expected, len); + bc = initCipher(true, parameters); + len = bc.processBytes(data, 0, blockSize * 3, data, offset); + bc.doFinal(data, offset + len); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + expected.length))) + { + fail("failed for overlapping encryption"); + } + + bc = initCipher(false, parameters); + bc.processBytes(data, 0, expected.length, expected, 0); + bc = initCipher(false, parameters); + bc.processBytes(data, 0, expected.length, data, offset); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + expected.length))) + { + fail("failed for overlapping decryption"); + } + } + public static void main(String[] args) { runTest(new ChaCha20Poly1305Test()); diff --git a/core/src/test/java/org/bouncycastle/crypto/test/CipherStreamTest.java b/core/src/test/java/org/bouncycastle/crypto/test/CipherStreamTest.java index 69d134ec33..20941ce155 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/CipherStreamTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/CipherStreamTest.java @@ -552,7 +552,7 @@ private void testModes(BlockCipher cipher1, BlockCipher cipher2, int keySize) { testMode(CCMBlockCipher.newInstance(cipher1), new ParametersWithIV(key, new byte[7])); // TODO: need to have a GCM safe version of testMode. -// testMode(new GCMBlockCipher(cipher1), withIv); +// testMode(GCMBlockCipher.newInstance(cipher1), withIv); testMode(new OCBBlockCipher(cipher1, cipher2), new ParametersWithIV(key, new byte[15])); } } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/CipherTest.java b/core/src/test/java/org/bouncycastle/crypto/test/CipherTest.java index bfe80251cb..2cc1d15776 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/CipherTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/CipherTest.java @@ -1,19 +1,28 @@ package org.bouncycastle.crypto.test; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Random; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.CipherKeyGenerator; +import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.DefaultBufferedBlockCipher; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.KeyGenerationParameters; +import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.modes.AEADCipher; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.test.TestResourceFinder; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; import org.bouncycastle.util.test.SimpleTestResult; import org.bouncycastle.util.test.TestFailedException; @@ -322,7 +331,11 @@ static void checkAEADParemeter(SimpleTest test, int keySize, int ivSize, final i { cipher.processAADByte(aad[i]); } - int len = cipher.processBytes(plaintext, 0, plaintext.length, ciphertext1, 0); + int len = 0; + for (int i = 0; i < plaintext.length; ++i) + { + len += cipher.processByte(plaintext[i], ciphertext1, len); + } len += cipher.doFinal(ciphertext1, len); int aadSplit = random.nextInt(aad.length) + 1; cipher.init(true, new AEADParameters(new KeyParameter(key), macSize * 8, iv, Arrays.copyOf(aad, aadSplit))); @@ -330,9 +343,26 @@ static void checkAEADParemeter(SimpleTest test, int keySize, int ivSize, final i byte[] ciphertext2 = new byte[cipher.getOutputSize(plaintext.length)]; len = cipher.processBytes(plaintext, 0, plaintext.length, ciphertext2, 0); len += cipher.doFinal(ciphertext2, len); + cipher.init(true, new ParametersWithIV(new KeyParameter(key), iv)); + byte[] ciphertext3 = new byte[cipher.getOutputSize(plaintext.length)]; + cipher.processAADBytes(aad, 0, aad.length); + len = cipher.processBytes(plaintext, 0, plaintext.length, ciphertext3, 0); + len += cipher.doFinal(ciphertext3, len); test.isTrue("cipher text check", Arrays.areEqual(ciphertext1, ciphertext2)); + cipher.init(false, new ParametersWithIV(new KeyParameter(key), iv)); + for (int i = 0; i < aad.length; ++i) + { + cipher.processAADByte(aad[i]); + } + len = 0; + byte[] plaintext1 = new byte[plaintext.length]; + for (int i = 0; i < ciphertext1.length; ++i) + { + len += cipher.processByte(ciphertext1[i], plaintext1, len); + } + len += cipher.doFinal(plaintext1, len); - test.testException("Invalid value for MAC size: ", "IllegalArgumentException", new TestExceptionOperation() + test.testException("MAC size", "IllegalArgumentException", new TestExceptionOperation() { @Override public void operation() @@ -354,7 +384,7 @@ public void operation() * @param PARTLEN Partial Data length. Must be greater than or equal to internal buffer length to exhibit problem. * @param AEADLEN AEAD length. * @param NONCELEN Nonce length. - * */ + */ static void checkAEADCipherMultipleBlocks(SimpleTest test, int DATALEN, int PARTLEN, int AEADLEN, int strength, int NONCELEN, final AEADCipher pCipher) throws InvalidCipherTextException { @@ -413,4 +443,504 @@ static void checkAEADCipherMultipleBlocks(SimpleTest test, int DATALEN, int PART /* Check that we have the same result */ test.isTrue("cipher text check", Arrays.areEqual(myData, myResult)); } + + static void implTestVectorsEngine(AEADCipher cipher, String path, String filename, SimpleTest test) + throws Exception + { + Random random = new Random(); + InputStream src = TestResourceFinder.findTestResource(path, filename); + BufferedReader bin = new BufferedReader(new InputStreamReader(src)); + String line; + HashMap map = new HashMap(); + while ((line = bin.readLine()) != null) + { + int a = line.indexOf('='); + if (a < 0) + { + int count = Integer.parseInt((String)map.get("Count")); +// if (count != 67) +// { +// continue; +// } + byte[] key = Hex.decode((String)map.get("Key")); + byte[] nonce = Hex.decode((String)map.get("Nonce")); + byte[] ad = Hex.decode((String)map.get("AD")); + byte[] pt = Hex.decode((String)map.get("PT")); + byte[] ct = Hex.decode((String)map.get("CT")); + + CipherParameters parameters = new ParametersWithIV(new KeyParameter(key), nonce); + + // Encrypt + { + cipher.init(true, parameters); + + byte[] rv = new byte[cipher.getOutputSize(pt.length)]; + random.nextBytes(rv); // should overwrite any existing data + + cipher.processAADBytes(ad, 0, ad.length); + int len = cipher.processBytes(pt, 0, pt.length, rv, 0); + len += cipher.doFinal(rv, len); + + if (!test.areEqual(rv, 0, len, ct, 0, ct.length)) + { + mismatch("Keystream " + map.get("Count"), (String)map.get("CT"), rv, test); + } + } + + // Decrypt + { + cipher.init(false, parameters); + + byte[] rv = new byte[cipher.getOutputSize(ct.length)]; + random.nextBytes(rv); // should overwrite any existing data + + cipher.processAADBytes(ad, 0, ad.length); + int len = cipher.processBytes(ct, 0, ct.length, rv, 0); + len += cipher.doFinal(rv, len); + + if (!test.areEqual(rv, 0, len, pt, 0, pt.length)) + { + mismatch("Reccover Keystream " + map.get("Count"), (String)map.get("PT"), rv, test); + } + } + //System.out.println("pass " + count); + map.clear(); + } + else + { + map.put(line.substring(0, a).trim(), line.substring(a + 1).trim()); + } + } + } + + static void mismatch(String name, String expected, byte[] found, SimpleTest test) + throws Exception + { + test.fail("mismatch on " + name, expected, new String(Hex.encode(found))); + } + + static void implTestBufferingEngine(int keySize, int ivSize, final int macSize, SimpleTest test, Instance instance) + throws Exception + { + Random random = new Random(); + + int plaintextLength = 256; + byte[] plaintext = new byte[plaintextLength]; + random.nextBytes(plaintext); + + AEADCipher cipher0 = instance.createInstance(); + AEADParameters parameters = new AEADParameters(new KeyParameter(new byte[keySize]), macSize, new byte[ivSize], null); + cipher0.init(true, parameters); + + byte[] ciphertext = new byte[cipher0.getOutputSize(plaintextLength)]; + random.nextBytes(ciphertext); + + int ciphertextLength = cipher0.processBytes(plaintext, 0, plaintextLength, ciphertext, 0); + ciphertextLength += cipher0.doFinal(ciphertext, ciphertextLength); + + byte[] output = new byte[ciphertextLength]; + + // Encryption + for (int split = 1; split < plaintextLength; ++split) + { + AEADCipher cipher = instance.createInstance(); + cipher.init(true, parameters); + + random.nextBytes(output); + + int length = cipher.processBytes(plaintext, 0, split, output, 0); + + if (0 != cipher.getUpdateOutputSize(0)) + { + test.fail("fail in implTestBufferingEngine encryption"); + } + + length += cipher.processBytes(plaintext, split, plaintextLength - split, output, length); + length += cipher.doFinal(output, length); + + if (!Arrays.areEqual(ciphertext, 0, ciphertextLength, output, 0, length)) + { + test.fail("encryption failed with split: " + split); + } + } + + // Decryption + for (int split = 16; split < ciphertextLength; ++split) + { + AEADCipher cipher = instance.createInstance(); + cipher.init(false, parameters); + + random.nextBytes(output); + + int length = cipher.processBytes(ciphertext, 0, split, output, 0); + + if (0 != cipher.getUpdateOutputSize(0)) + { + test.fail("fail in implTestBufferingEngine decryption"); + } + + length += cipher.processBytes(ciphertext, split, ciphertextLength - split, output, length); + length += cipher.doFinal(output, length); + + if (!Arrays.areEqual(plaintext, 0, plaintextLength, output, 0, length)) + { + test.fail("decryption failed with split: " + split); + } + } + } + + static void implTestExceptionsEngine(int keysize, int ivsize, SimpleTest test, Instance instance) + throws Exception + { + AEADCipher cipher = instance.createInstance(); + + int offset; + byte[] k = new byte[keysize]; + byte[] iv = new byte[ivsize]; + byte[] m = new byte[0]; + CipherParameters params = new ParametersWithIV(new KeyParameter(k), iv); + try + { + cipher.processBytes(m, 0, m.length, null, 0); + test.fail(cipher.getAlgorithmName() + " need to be initialized before processBytes"); + } + catch (IllegalStateException e) + { + //expected + } + + try + { + cipher.processByte((byte)0, null, 0); + test.fail(cipher.getAlgorithmName() + " need to be initialized before processByte"); + } + catch (IllegalStateException e) + { + //expected + } + + try + { + cipher.reset(); + test.fail(cipher.getAlgorithmName() + " need to be initialized before reset"); + } + catch (IllegalStateException e) + { + //expected + } + + try + { + cipher.doFinal(null, m.length); + test.fail(cipher.getAlgorithmName() + " need to be initialized before dofinal"); + } + catch (IllegalStateException e) + { + //expected + } + + try + { + cipher.getMac(); + cipher.getOutputSize(0); + cipher.getUpdateOutputSize(0); + } + catch (IllegalStateException e) + { + //expected + test.fail(cipher.getAlgorithmName() + " functions can be called before initialization"); + } + + Random rand = new Random(); + int randomNum; + while ((randomNum = rand.nextInt(100)) == keysize) ; + byte[] k1 = new byte[randomNum]; + while ((randomNum = rand.nextInt(100)) == ivsize) ; + byte[] iv1 = new byte[randomNum]; + try + { + cipher.init(true, new ParametersWithIV(new KeyParameter(k1), iv)); + test.fail(cipher.getAlgorithmName() + " k size does not match"); + } + catch (IllegalArgumentException e) + { + //expected + } + try + { + cipher.init(true, new ParametersWithIV(new KeyParameter(k), iv1)); + test.fail(cipher.getAlgorithmName() + "iv size does not match"); + } + catch (IllegalArgumentException e) + { + //expected + } + + try + { + cipher.init(true, new AEADParameters(new KeyParameter(k), 0, iv)); + test.fail(cipher.getAlgorithmName() + " wrong type of CipherParameters"); + } + catch (IllegalArgumentException e) + { + //expected + } + + cipher.init(true, params); + byte[] c1 = new byte[cipher.getOutputSize(m.length)]; + try + { + cipher.doFinal(c1, m.length); + } + catch (Exception e) + { + test.fail(cipher.getAlgorithmName() + " allows no input for AAD and plaintext"); + } + byte[] mac2 = cipher.getMac(); + if (mac2 == null) + { + test.fail("mac should not be empty after dofinal"); + } + if (!Arrays.areEqual(mac2, c1)) + { + test.fail("mac should be equal when calling dofinal and getMac"); + } + cipher.init(true, params); + cipher.processAADByte((byte)0); + byte[] mac1 = new byte[cipher.getOutputSize(0)]; + cipher.doFinal(mac1, 0); + if (Arrays.areEqual(mac1, mac2)) + { + test.fail("mac should not match"); + } + cipher.init(true, params); + cipher.processByte((byte)0, new byte[1], 0); + try + { + cipher.processAADByte((byte)0); + // Romuls-M stores message into Stream, so the procssAADbyte(s) is allowed + if (!cipher.getAlgorithmName().equals("Romulus-M")) + { + test.fail("processAADByte(s) cannot be called after encryption/decryption"); + } + } + catch (IllegalStateException e) + { + //expected + } + try + { + cipher.processAADBytes(new byte[]{0}, 0, 1); + if (!cipher.getAlgorithmName().equals("Romulus-M")) + { + test.fail("processAADByte(s) cannot be called once only"); + } + } + catch (IllegalStateException e) + { + //expected + } + + cipher.reset(); + try + { + cipher.processAADBytes(new byte[]{0}, 1, 1); + test.fail("input for processAADBytes is too short"); + } + catch (DataLengthException e) + { + //expected + } + try + { + cipher.processBytes(new byte[]{0}, 1, 1, c1, 0); + test.fail("input for processBytes is too short"); + } + catch (DataLengthException e) + { + //expected + } + cipher.init(true, params); + try + { + int need = cipher.getUpdateOutputSize(64); + cipher.processBytes(new byte[64], 0, 64, new byte[need], 1); + if (!cipher.getAlgorithmName().equals("Romulus-M")) + { + test.fail("output for processBytes is too short"); + } + } + catch (OutputLengthException e) + { + //expected + } + try + { + cipher.doFinal(new byte[2], 2); + test.fail("output for dofinal is too short"); + } + catch (OutputLengthException e) + { + //expected + } + + implTestExceptionsGetUpdateOutputSize(cipher, false, params, 100, test); + implTestExceptionsGetUpdateOutputSize(cipher, true, params, 100, test); + + mac1 = new byte[cipher.getOutputSize(0)]; + mac2 = new byte[cipher.getOutputSize(0)]; + cipher.init(true, params); + cipher.processAADBytes(new byte[]{0, 0}, 0, 2); + cipher.doFinal(mac1, 0); + cipher.init(true, params); + cipher.processAADByte((byte)0); + cipher.processAADByte((byte)0); + cipher.doFinal(mac2, 0); + if (!Arrays.areEqual(mac1, mac2)) + { + test.fail("mac should match for the same AAD with different ways of inputing"); + } + + byte[] c2 = new byte[cipher.getOutputSize(10)]; + byte[] c3 = new byte[cipher.getOutputSize(10) + 2]; + + byte[] aad2 = {0, 1, 2, 3, 4}; + byte[] aad3 = {0, 0, 1, 2, 3, 4, 5}; + byte[] m2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + byte[] m3 = {0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + byte[] m4 = new byte[m2.length]; + cipher.init(true, params); + cipher.processAADBytes(aad2, 0, aad2.length); + offset = cipher.processBytes(m2, 0, m2.length, c2, 0); + cipher.doFinal(c2, offset); + cipher.init(true, params); + cipher.processAADBytes(aad3, 1, aad2.length); + offset = cipher.processBytes(m3, 1, m2.length, c3, 1); + cipher.doFinal(c3, offset + 1); + byte[] c3_partial = new byte[c2.length]; + System.arraycopy(c3, 1, c3_partial, 0, c2.length); + if (!Arrays.areEqual(c2, c3_partial)) + { + test.fail("mac should match for the same AAD and message with different offset for both input and output"); + } + cipher.init(false, params); + cipher.processAADBytes(aad2, 0, aad2.length); + offset = cipher.processBytes(c2, 0, c2.length, m4, 0); + cipher.doFinal(m4, offset); + if (!Arrays.areEqual(m2, m4)) + { + test.fail("The encryption and decryption does not recover the plaintext"); + } + c2[c2.length - 1] ^= 1; + cipher.init(false, params); + cipher.processAADBytes(aad2, 0, aad2.length); + offset = cipher.processBytes(c2, 0, c2.length, m4, 0); + try + { + cipher.doFinal(m4, offset); + test.fail("The decryption should fail"); + } + catch (InvalidCipherTextException e) + { + //expected; + } + + byte[] m7 = new byte[32 + rand.nextInt(32)]; + rand.nextBytes(m7); + + cipher.init(true, params); + byte[] c7 = new byte[cipher.getOutputSize(m7.length)]; + byte[] c8 = new byte[c7.length]; + byte[] c9 = new byte[c7.length]; + cipher.processAADBytes(aad2, 0, aad2.length); + offset = cipher.processBytes(m7, 0, m7.length, c7, 0); + cipher.doFinal(c7, offset); + + cipher.init(true, params); + cipher.processAADBytes(aad2, 0, aad2.length); + offset = cipher.processBytes(m7, 0, m7.length / 2, c8, 0); + offset += cipher.processBytes(m7, m7.length / 2, m7.length - m7.length / 2, c8, offset); + cipher.doFinal(c8, offset); + + cipher.init(true, params); + int split = rand.nextInt(m7.length - 1) + 1; + cipher.processAADBytes(aad2, 0, aad2.length); + offset = cipher.processBytes(m7, 0, split, c9, 0); + offset += cipher.processBytes(m7, split, m7.length - split, c9, offset); + cipher.doFinal(c9, offset); + + if (!Arrays.areEqual(c7, c8) || !Arrays.areEqual(c7, c9)) + { + test.fail("Splitting input of plaintext should output the same ciphertext"); + } + } + + static void implTestExceptionsGetUpdateOutputSize(AEADCipher cipher, boolean forEncryption, + CipherParameters parameters, int maxInputSize, SimpleTest test) + { + cipher.init(forEncryption, parameters); + + int maxOutputSize = cipher.getUpdateOutputSize(maxInputSize); + + byte[] input = new byte[maxInputSize]; + byte[] output = new byte[maxOutputSize]; + + for (int inputSize = 0; inputSize <= maxInputSize; ++inputSize) + { + cipher.init(forEncryption, parameters); + + int outputSize = cipher.getUpdateOutputSize(inputSize); + if (outputSize > 0) + { + try + { + cipher.processBytes(input, 0, inputSize, output, maxOutputSize - outputSize + 1); + test.fail("output for processBytes is too short"); + } + catch (OutputLengthException e) + { + //expected + } + } + else + { + cipher.processBytes(input, 0, inputSize, null, 0); + } + } + } + + static void testOverlapping(SimpleTest test, int keySize, int ivSize, int macSize, int blockSize, AEADCipher cipher) + throws Exception + { + SecureRandom random = new SecureRandom(); + byte[] keyBytes = new byte[keySize]; + byte[] ivBytes = new byte[ivSize]; + int offset = 1 + random.nextInt(blockSize - 1); + byte[] data = new byte[blockSize * 2 + offset + macSize]; + byte[] expected; + random.nextBytes(keyBytes); + random.nextBytes(ivBytes); + random.nextBytes(data); + AEADParameters parameters = new AEADParameters(new KeyParameter(new byte[keySize]), macSize * 8, new byte[ivSize], null); + cipher.init(true, parameters); + expected = new byte[cipher.getOutputSize(blockSize * 2)]; + int len = cipher.processBytes(data, 0, blockSize * 2, expected, 0); + cipher.doFinal(expected, len); + cipher.init(true, parameters); + len = cipher.processBytes(data, 0, blockSize * 2, data, offset); + cipher.doFinal(data, len + offset); + test.isTrue("fail on testing overlapping of encryption for " + cipher.getAlgorithmName(), + Arrays.areEqual(expected, 0, expected.length, data, offset, offset + expected.length)); + System.arraycopy(data, offset, data, 0, expected.length); + cipher.init(false, parameters); + expected = new byte[cipher.getOutputSize(data.length)]; + len = cipher.processBytes(data, 0, blockSize * 2 + macSize, expected, 0); + cipher.doFinal(expected, len); + cipher.init(false, parameters); + len = cipher.processBytes(data, 0, blockSize * 2 + macSize, data, offset); + cipher.doFinal(data, len + offset); + test.isTrue("fail on testing overlapping of decryption for " + cipher.getAlgorithmName(), + Arrays.areEqual(expected, 0, blockSize * 2, data, offset, offset + blockSize * 2)); + + } } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/DHKEKGeneratorTest.java b/core/src/test/java/org/bouncycastle/crypto/test/DHKEKGeneratorTest.java index 8a83d2a395..d43b81c96f 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/DHKEKGeneratorTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/DHKEKGeneratorTest.java @@ -1,5 +1,7 @@ package org.bouncycastle.crypto.test; +import java.security.SecureRandom; + import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.crypto.DerivationFunction; @@ -16,6 +18,8 @@ public class DHKEKGeneratorTest extends SimpleTest { + private static final SecureRandom RANDOM = new SecureRandom(); + private byte[] seed1 = Hex.decode("000102030405060708090a0b0c0d0e0f10111213"); private ASN1ObjectIdentifier alg1 = PKCSObjectIdentifiers.id_alg_CMS3DESwrap; private byte[] result1 = Hex.decode("a09661392376f7044d9052a397883246b67f5f1ef63eb5fb"); @@ -45,7 +49,8 @@ private void checkMask( DerivationParameters params, byte[] result) { - byte[] data = new byte[result.length]; + byte[] data = new byte[result.length]; + RANDOM.nextBytes(data); kdf.init(params); diff --git a/core/src/test/java/org/bouncycastle/crypto/test/DSTU7624Test.java b/core/src/test/java/org/bouncycastle/crypto/test/DSTU7624Test.java index 2af7f7978c..084f400862 100755 --- a/core/src/test/java/org/bouncycastle/crypto/test/DSTU7624Test.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/DSTU7624Test.java @@ -96,6 +96,7 @@ public void performTest() CCMModeTests(); XTSModeTests(); GCMModeTests(); + testOverlapping(); } public static void main( @@ -1464,4 +1465,41 @@ private void doFinalTest(AEADBlockCipher cipher, byte[] key, byte[] iv, byte[] a fail("Failed doFinal test - after: " + cipher.getAlgorithmName()); } } + + private void testOverlapping() + { + SecureRandom random = new SecureRandom(); + byte[] keyBytes = new byte[16]; + byte[] iv = new byte[16]; + random.nextBytes(keyBytes); + KXTSBlockCipher bc = new KXTSBlockCipher(new DSTU7624Engine(128)); + ParametersWithIV param = new ParametersWithIV(new KeyParameter(keyBytes), iv); + + int offset = 1 + random.nextInt(bc.getBlockSize() - 1) + bc.getBlockSize(); + byte[] data = new byte[bc.getBlockSize() * 4 + offset]; + byte[] expected = new byte[bc.getOutputSize(bc.getBlockSize() * 3)]; + random.nextBytes(data); + + bc.init(true, param); + int len = bc.processBytes(data, 0, expected.length, expected, 0); + bc.doFinal(expected, len); + bc.init(true, param); + len = bc.processBytes(data, 0, expected.length, data, offset); + bc.doFinal(data, offset + len); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + expected.length))) + { + fail("failed for overlapping encryption"); + } + + bc.init(false, param); + bc.processBytes(data, 0, expected.length, expected, 0); + bc.init(false, param); + bc.processBytes(data, 0, expected.length, data, offset); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + expected.length))) + { + fail("failed for overlapping decryption"); + } + } } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/DigestTest.java b/core/src/test/java/org/bouncycastle/crypto/test/DigestTest.java index 50fb248271..fd32e704fa 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/DigestTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/DigestTest.java @@ -1,9 +1,20 @@ package org.bouncycastle.crypto.test; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Random; +import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.ExtendedDigest; +import org.bouncycastle.crypto.OutputLengthException; +import org.bouncycastle.crypto.Xof; import org.bouncycastle.crypto.digests.EncodableDigest; +import org.bouncycastle.crypto.digests.TupleHash; +import org.bouncycastle.test.TestResourceFinder; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Memoable; import org.bouncycastle.util.encoders.Hex; @@ -27,16 +38,16 @@ public abstract class DigestTest this.input = input; this.results = results; } - + public String getName() { return digest.getAlgorithmName(); } - + public void performTest() { byte[] resBuf = new byte[digest.getDigestSize()]; - + for (int i = 0; i < input.length - 1; i++) { byte[] m = toByteArray(input[i]); @@ -48,7 +59,7 @@ public void performTest() byte[] lastV = toByteArray(input[input.length - 1]); byte[] lastDigest = Hex.decode(results[input.length - 1]); - + vectorTest(digest, input.length - 1, resBuf, lastV, Hex.decode(results[input.length - 1])); testClone(resBuf, lastV, lastDigest); @@ -61,71 +72,115 @@ public void performTest() private void testEncodedState(byte[] resBuf, byte[] input, byte[] expected) { - // test state encoding; - digest.update(input, 0, input.length / 2); + if (digest instanceof TupleHash) + { + digest.update(input, 0, input.length); + Digest copy1 = cloneDigest(((EncodableDigest)digest).getEncodedState()); + Digest copy2 = cloneDigest(((EncodableDigest)copy1).getEncodedState()); - // copy the Digest - Digest copy1 = cloneDigest(((EncodableDigest)digest).getEncodedState()); - Digest copy2 = cloneDigest(((EncodableDigest)copy1).getEncodedState()); + digest.doFinal(resBuf, 0); - digest.update(input, input.length / 2, input.length - input.length / 2); + if (!areEqual(expected, resBuf)) + { + fail("failing TupleHash state vector test", expected, new String(Hex.encode(resBuf))); + } - digest.doFinal(resBuf, 0); + copy2.doFinal(resBuf, 0); - if (!areEqual(expected, resBuf)) - { - fail("failing state vector test", expected, new String(Hex.encode(resBuf))); + if (!areEqual(expected, resBuf)) + { + fail("failing TupleHash state copy2 vector test", expected, new String(Hex.encode(resBuf))); + } } + else + { + // test state encoding; + digest.update(input, 0, input.length / 2); - copy1.update(input, input.length / 2, input.length - input.length / 2); - copy1.doFinal(resBuf, 0); + // copy the Digest + Digest copy1 = cloneDigest(((EncodableDigest)digest).getEncodedState()); + Digest copy2 = cloneDigest(((EncodableDigest)copy1).getEncodedState()); - if (!areEqual(expected, resBuf)) - { - fail("failing state copy1 vector test", expected, new String(Hex.encode(resBuf))); - } + digest.update(input, input.length / 2, input.length - input.length / 2); - copy2.update(input, input.length / 2, input.length - input.length / 2); - copy2.doFinal(resBuf, 0); + digest.doFinal(resBuf, 0); - if (!areEqual(expected, resBuf)) - { - fail("failing state copy2 vector test", expected, new String(Hex.encode(resBuf))); + if (!areEqual(expected, resBuf)) + { + fail("failing state vector test", expected, new String(Hex.encode(resBuf))); + } + + copy1.update(input, input.length / 2, input.length - input.length / 2); + copy1.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing state copy1 vector test", expected, new String(Hex.encode(resBuf))); + } + + copy2.update(input, input.length / 2, input.length - input.length / 2); + copy2.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing state copy2 vector test", expected, new String(Hex.encode(resBuf))); + } } } private void testMemo(byte[] resBuf, byte[] input, byte[] expected) { - Memoable m = (Memoable)digest; + if (digest instanceof TupleHash) + { + Memoable m = (Memoable)digest; - digest.update(input, 0, input.length/2); + digest.update(input, 0, input.length); - // copy the Digest - Memoable copy1 = m.copy(); - Memoable copy2 = copy1.copy(); + Memoable copy1 = m.copy(); + Memoable copy2 = copy1.copy(); - digest.update(input, input.length/2, input.length - input.length/2); - digest.doFinal(resBuf, 0); + digest.doFinal(resBuf, 0); + if (!areEqual(expected, resBuf)) + { + fail("failing tuplehash memo vector test 1", results[results.length - 1], new String(Hex.encode(resBuf))); + } - if (!areEqual(expected, resBuf)) - { - fail("failing memo vector test", results[results.length - 1], new String(Hex.encode(resBuf))); + Digest d = (Digest)copy2; + d.doFinal(resBuf, 0); } + else + { + Memoable m = (Memoable)digest; - m.reset(copy1); + digest.update(input, 0, input.length / 2); - digest.update(input, input.length/2, input.length - input.length/2); - digest.doFinal(resBuf, 0); + // copy the Digest + Memoable copy1 = m.copy(); + Memoable copy2 = copy1.copy(); - if (!areEqual(expected, resBuf)) - { - fail("failing memo reset vector test", results[results.length - 1], new String(Hex.encode(resBuf))); - } + digest.update(input, input.length / 2, input.length - input.length / 2); + digest.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing memo vector test", results[results.length - 1], new String(Hex.encode(resBuf))); + } - Digest md = (Digest)copy2; + m.reset(copy1); - md.update(input, input.length/2, input.length - input.length/2); - md.doFinal(resBuf, 0); + digest.update(input, input.length / 2, input.length - input.length / 2); + digest.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing memo reset vector test", results[results.length - 1], new String(Hex.encode(resBuf))); + } + + Digest md = (Digest)copy2; + + md.update(input, input.length / 2, input.length - input.length / 2); + md.doFinal(resBuf, 0); + } if (!areEqual(expected, resBuf)) { @@ -135,21 +190,32 @@ private void testMemo(byte[] resBuf, byte[] input, byte[] expected) private void testClone(byte[] resBuf, byte[] input, byte[] expected) { - digest.update(input, 0, input.length / 2); + if (digest instanceof TupleHash) + { + // can't support multiple updates like the others - it's the whole point! + Digest d = cloneDigest(digest); - // clone the Digest - Digest d = cloneDigest(digest); + d.update(input, 0, input.length); + d.doFinal(resBuf, 0); + } + else + { + digest.update(input, 0, input.length / 2); - digest.update(input, input.length/2, input.length - input.length/2); - digest.doFinal(resBuf, 0); + // clone the Digest + Digest d = cloneDigest(digest); - if (!areEqual(expected, resBuf)) - { - fail("failing clone vector test", results[results.length - 1], new String(Hex.encode(resBuf))); - } + digest.update(input, input.length / 2, input.length - input.length / 2); + digest.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing clone vector test", results[results.length - 1], new String(Hex.encode(resBuf))); + } - d.update(input, input.length/2, input.length - input.length/2); - d.doFinal(resBuf, 0); + d.update(input, input.length / 2, input.length - input.length / 2); + d.doFinal(resBuf, 0); + } if (!areEqual(expected, resBuf)) { @@ -160,15 +226,15 @@ private void testClone(byte[] resBuf, byte[] input, byte[] expected) protected byte[] toByteArray(String input) { byte[] bytes = new byte[input.length()]; - + for (int i = 0; i != bytes.length; i++) { bytes[i] = (byte)input.charAt(i); } - + return bytes; } - + private void vectorTest( Digest digest, int count, @@ -216,12 +282,12 @@ protected void millionATest( String expected) { byte[] resBuf = new byte[digest.getDigestSize()]; - + for (int i = 0; i < 1000000; i++) { digest.update((byte)'a'); } - + digest.doFinal(resBuf, 0); if (!areEqual(resBuf, Hex.decode(expected))) @@ -229,17 +295,17 @@ protected void millionATest( fail("Million a's failed", expected, new String(Hex.encode(resBuf))); } } - + protected void sixtyFourKTest( String expected) { byte[] resBuf = new byte[digest.getDigestSize()]; - + for (int i = 0; i < 65536; i++) { digest.update((byte)(i & 0xff)); } - + digest.doFinal(resBuf, 0); if (!areEqual(resBuf, Hex.decode(expected))) @@ -271,7 +337,130 @@ static void checkDigestReset(final SimpleTest test, final Digest pDigest) /* Check that we have the same result */ if (!java.util.Arrays.equals(myFirst, mySecond)) { - throw new TestFailedException(SimpleTestResult.failed(test,"Digest " + pDigest.getAlgorithmName() + " does not reset properly on doFinal()")); + throw new TestFailedException(SimpleTestResult.failed(test, "Digest " + pDigest.getAlgorithmName() + " does not reset properly on doFinal()")); + } + } + + static void implTestExceptionsAndParametersDigest(final SimpleTest test, final Digest pDigest, final int digestsize) + { + if (pDigest.getDigestSize() != digestsize) + { + test.fail(pDigest.getAlgorithmName() + ": digest size is not correct"); + } + + try + { + pDigest.update(new byte[1], 1, 1); + test.fail(pDigest.getAlgorithmName() + ": input for update is too short"); + } + catch (DataLengthException e) + { + //expected + } + + try + { + pDigest.doFinal(new byte[pDigest.getDigestSize() - 1], 2); + test.fail(pDigest.getAlgorithmName() + ": output for dofinal is too short"); + } + catch (OutputLengthException e) + { + //expected + } + } + + static void implTestVectorsDigest(SimpleTest test, ExtendedDigest digest, String path, String filename) + throws Exception + { + Random random = new Random(); + InputStream src = TestResourceFinder.findTestResource(path, filename); + BufferedReader bin = new BufferedReader(new InputStreamReader(src)); + String line; + HashMap map = new HashMap(); + while ((line = bin.readLine()) != null) + { + int a = line.indexOf('='); + if (a < 0) + { + int count = Integer.parseInt((String)map.get("Count")); + if (count != 21) + { + continue; + } + byte[] ptByte = Hex.decode((String)map.get("Msg")); + byte[] expected = Hex.decode((String)map.get("MD")); + + byte[] hash = new byte[digest.getDigestSize()]; + + digest.update(ptByte, 0, ptByte.length); + digest.doFinal(hash, 0); + if (!Arrays.areEqual(hash, expected)) + { + mismatch(test, "Keystream " + map.get("Count"), (String)map.get("MD"), hash); + } + + if (ptByte.length > 1) + { + int split = random.nextInt(ptByte.length - 1) + 1; + digest.update(ptByte, 0, split); + digest.update(ptByte, split, ptByte.length - split); + digest.doFinal(hash, 0); + if (!Arrays.areEqual(hash, expected)) + { + mismatch(test, "Keystream " + map.get("Count"), (String)map.get("MD"), hash); + } + } + + map.clear(); + } + else + { + map.put(line.substring(0, a).trim(), line.substring(a + 1).trim()); + } + } + } + + private static void mismatch(SimpleTest test, String name, String expected, byte[] found) + { + test.fail("mismatch on " + name, expected, new String(Hex.encode(found))); + } + + /** + * Check xof. + * + * @param pXof the xof + * @param DATALEN DataLength + * @param PARTIALLEN Partial length + */ + public static void checkXof(final Xof pXof, int DATALEN, int PARTIALLEN, SecureRandom random, SimpleTest test) + { + /* Create the data */ + final byte[] myData = new byte[DATALEN]; + random.nextBytes(myData); + + /* Update the Xof with the data */ + pXof.update(myData, 0, DATALEN); + + /* Extract Xof as single block */ + final byte[] myFull = new byte[DATALEN]; + pXof.doFinal(myFull, 0, DATALEN); + + /* Update the Xof with the data */ + pXof.update(myData, 0, DATALEN); + final byte[] myPart = new byte[DATALEN]; + + /* Create the xof as partial blocks */ + for (int myPos = 0; myPos < DATALEN; myPos += PARTIALLEN) + { + final int myLen = Math.min(PARTIALLEN, DATALEN - myPos); + pXof.doOutput(myPart, myPos, myLen); + } + pXof.doFinal(myPart, 0, 0); + + /* Check that they are identical */ + if (!Arrays.areEqual(myPart, myFull)) + { + test.fail(pXof.getAlgorithmName() + ": Mismatch on partial vs full xof"); } } } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java b/core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java new file mode 100644 index 0000000000..7559cf2a90 --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/test/ECCSISignerTest.java @@ -0,0 +1,181 @@ +package org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.AsconHash256; +import org.bouncycastle.crypto.digests.MD5Digest; +import org.bouncycastle.crypto.digests.SHA224Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA3Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.digests.SHAKEDigest; +import org.bouncycastle.crypto.ec.CustomNamedCurves; +import org.bouncycastle.crypto.generators.ECCSIKeyPairGenerator; +import org.bouncycastle.crypto.params.ECCSIKeyGenerationParameters; +import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.signers.ECCSISigner; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.BigIntegers; +import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.test.FixedSecureRandom; +import org.bouncycastle.util.test.SimpleTest; + +public class ECCSISignerTest + extends SimpleTest +{ + String[] curveNames = { + "curve25519", + "secp128r1", + "secp160k1", + "secp160r1", + "secp160r2", + "secp192k1", + "secp192r1", + "secp224k1", + "secp224r1", + "secp256k1", + "secp256r1", + "secp384r1", + "secp521r1", + "sect113r1", + "sect113r2", + "sect131r1", + "sect131r2", + "sect163k1", + "sect163r1", + "sect163r2", + "sect193r1", + "sect193r2", + "sect233k1", + "sect233r1", + "sect239k1", + "sect283k1", + "sect283r1", + "sect409k1", + "sect409r1", + "sect571k1", + "sect571r1", + "sm2p256v1" + }; + + Digest[] digests = new Digest[]{ + new SHA256Digest(), + new SHA3Digest(), + new SHA3Digest(512), + new SHA224Digest(), + new SHA512Digest(), + new AsconHash256(), + new SHAKEDigest(256), + new SHAKEDigest(128), + new MD5Digest() + }; + + + public static void main(String[] args) + throws Exception + { + ECCSISignerTest test = new ECCSISignerTest(); + test.performTest(); + } + + @Override + public String getName() + { + return "ECCSISigner Test"; + } + + @Override + public void performTest() + throws Exception + { + testTestVector(); + for (int i = 0; i < curveNames.length; ++i) + { + for (int j = 0; j < digests.length; ++j) + { + testRandom(curveNames[i], digests[j]); + } + } + } + + private void testTestVector() + throws Exception + { + BigInteger ksak = BigInteger.valueOf(0x12345); + BigInteger v = BigInteger.valueOf(0x23456); + BigInteger j = BigInteger.valueOf(0x34567); + ECCSIKeyPairGenerator generator = new ECCSIKeyPairGenerator(); + SecureRandom random = new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(BigIntegers.asUnsignedByteArray(32, ksak)), + new FixedSecureRandom.Data(BigIntegers.asUnsignedByteArray(32, v)), + new FixedSecureRandom.Data(BigIntegers.asUnsignedByteArray(32, j))}); + ECCSIKeyGenerationParameters keyGenerationParameters = new ECCSIKeyGenerationParameters(random, + CustomNamedCurves.getByName("secP256r1"), new SHA256Digest(), "2011-02\0tel:+447700900123\0".getBytes()); + generator.init(keyGenerationParameters); + AsymmetricCipherKeyPair keyPair = generator.generateKeyPair(); + ECCSIPublicKeyParameters pub = (ECCSIPublicKeyParameters)keyPair.getPublic(); + ECCSIPrivateKeyParameters priv = (ECCSIPrivateKeyParameters)keyPair.getPrivate(); +// System.out.println(new String(Hex.encode(pub.getPVT().getXCoord().toBigInteger().toByteArray()))); +// System.out.println(new String(Hex.encode(pub.getPVT().getYCoord().toBigInteger().toByteArray()))); +// System.out.println(new String(Hex.encode(priv.getSSK().toByteArray()))); + + byte[] M = "message\0".getBytes(); + + ECCSISigner signer = new ECCSISigner(keyGenerationParameters.getKPAK(), CustomNamedCurves.getByName("secP256r1"), new SHA256Digest(), keyGenerationParameters.getId()); + signer.init(true, new ParametersWithRandom(priv, random)); + signer.update(M, 0, M.length); + byte[] sig = signer.generateSignature(); + isTrue(Arrays.areEqual(sig, Hex.decode("269D4C8F DEB66A74 E4EF8C0D 5DCC597D\n" + + " DFE6029C 2AFFC493 6008CD2C C1045D81\n" + + " E09B528D 0EF8D6DF 1AA3ECBF 80110CFC\n" + + " EC9FC682 52CEBB67 9F413484 6940CCFD\n" + + " 04\n" + + "\n" + + " 758A1427 79BE89E8 29E71984 CB40EF75\n" + + " 8CC4AD77 5FC5B9A3 E1C8ED52 F6FA36D9\n" + + " A79D2476 92F4EDA3 A6BDAB77 D6AA6474\n" + + " A464AE49 34663C52 65BA7018 BA091F79"))); +// System.out.println("sig: " + new String(Hex.encode(sig))); + + signer.init(false, pub); + signer.update(M, 0, M.length); + isTrue(signer.verifySignature(sig)); + } + + private void testRandom(String curveName, Digest digest) + throws Exception + { + SecureRandom random = new SecureRandom(); + ECCSIKeyPairGenerator generator = new ECCSIKeyPairGenerator(); + byte[] id = new byte[16]; + random.nextBytes(id); + X9ECParameters params = CustomNamedCurves.getByName(curveName); + ECCSIKeyGenerationParameters keyGenerationParameters = new ECCSIKeyGenerationParameters(random, + params, digest, id); + generator.init(keyGenerationParameters); + AsymmetricCipherKeyPair keyPair = generator.generateKeyPair(); + ECCSIPublicKeyParameters pub = (ECCSIPublicKeyParameters)keyPair.getPublic(); + ECCSIPrivateKeyParameters priv = (ECCSIPrivateKeyParameters)keyPair.getPrivate(); + + byte[] M = "message\0".getBytes(); + + ECCSISigner signer = new ECCSISigner(keyGenerationParameters.getKPAK(), params, digest, keyGenerationParameters.getId()); + signer.init(true, new ParametersWithRandom(priv, random)); + signer.update(M, 0, M.length); + signer.reset(); + signer.update(M, 0, M.length); + byte[] sig = signer.generateSignature(); + signer = new ECCSISigner(keyGenerationParameters.getKPAK(), params, digest, keyGenerationParameters.getId()); + signer.init(false, pub); + signer.update(M, 0, M.length); + signer.reset(); + signer.update(M, 0, M.length); + isTrue(signer.verifySignature(sig)); + } + +} diff --git a/core/src/test/java/org/bouncycastle/crypto/test/ECDHKEKGeneratorTest.java b/core/src/test/java/org/bouncycastle/crypto/test/ECDHKEKGeneratorTest.java index d75b13962d..6e81f5ccb0 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/ECDHKEKGeneratorTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/ECDHKEKGeneratorTest.java @@ -1,5 +1,7 @@ package org.bouncycastle.crypto.test; +import java.security.SecureRandom; + import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; @@ -17,6 +19,8 @@ public class ECDHKEKGeneratorTest extends SimpleTest { + private static final SecureRandom RANDOM = new SecureRandom(); + private byte[] seed1 = Hex.decode("db4a8daba1f98791d54e940175dd1a5f3a0826a1066aa9b668d4dc1e1e0790158dcad1533c03b44214d1b61fefa8b579"); private ASN1ObjectIdentifier alg1 = NISTObjectIdentifiers.id_aes256_wrap; private byte[] result1 = Hex.decode("8ecc6d85caf25eaba823a7d620d4ab0d33e4c645f2"); @@ -46,7 +50,8 @@ private void checkMask( DerivationParameters params, byte[] result) { - byte[] data = new byte[result.length]; + byte[] data = new byte[result.length]; + RANDOM.nextBytes(data); kdf.init(params); diff --git a/core/src/test/java/org/bouncycastle/crypto/test/ElephantTest.java b/core/src/test/java/org/bouncycastle/crypto/test/ElephantTest.java index 590f017a77..5d2408a8d7 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/ElephantTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/ElephantTest.java @@ -8,6 +8,7 @@ import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.engines.ElephantEngine; import org.bouncycastle.crypto.modes.AEADCipher; import org.bouncycastle.crypto.params.KeyParameter; @@ -27,19 +28,26 @@ public String getName() public void performTest() throws Exception { + testVectors(ElephantEngine.ElephantParameters.elephant200, "v200"); + testVectors(ElephantEngine.ElephantParameters.elephant160, "v160"); + testVectors(ElephantEngine.ElephantParameters.elephant176, "v176"); + CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 41, 10, 128, 12, new ElephantEngine(ElephantEngine.ElephantParameters.elephant160)); CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 41, 10, 128, 12, new ElephantEngine(ElephantEngine.ElephantParameters.elephant176)); CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 41, 10, 128, 12, new ElephantEngine(ElephantEngine.ElephantParameters.elephant200)); CipherTest.checkAEADParemeter(this, 16, 12, 8, 20, new ElephantEngine(ElephantEngine.ElephantParameters.elephant160)); CipherTest.checkAEADParemeter(this, 16, 12, 8, 22, new ElephantEngine(ElephantEngine.ElephantParameters.elephant176)); CipherTest.checkAEADParemeter(this, 16, 12, 16, 25, new ElephantEngine(ElephantEngine.ElephantParameters.elephant200)); + CipherTest.testOverlapping(this, 16, 12, 8, 20, new ElephantEngine(ElephantEngine.ElephantParameters.elephant160)); + CipherTest.testOverlapping(this, 16, 12, 8, 22, new ElephantEngine(ElephantEngine.ElephantParameters.elephant176)); + CipherTest.testOverlapping(this, 16, 12, 16, 25, new ElephantEngine(ElephantEngine.ElephantParameters.elephant200)); CipherTest.checkAEADCipherOutputSize(this, 16, 12, 20, 8, new ElephantEngine(ElephantEngine.ElephantParameters.elephant160)); CipherTest.checkAEADCipherOutputSize(this, 16, 12, 22, 8, new ElephantEngine(ElephantEngine.ElephantParameters.elephant176)); CipherTest.checkAEADCipherOutputSize(this, 16, 12, 25, 16, new ElephantEngine(ElephantEngine.ElephantParameters.elephant200)); // //testVectors(ElephantEngine.ElephantParameters.elephant160, "v160_2"); ElephantEngine elephant = new ElephantEngine(ElephantEngine.ElephantParameters.elephant200); testExceptions(elephant, elephant.getKeyBytesSize(), elephant.getIVBytesSize(), elephant.getBlockSize()); - testParameters(elephant, 16, 12, 16); + implTestParametersEngine(elephant, 16, 12, 16); CipherTest.checkCipher(10, 12, 40, 128, new CipherTest.Instance() { public AEADCipher createInstance() @@ -61,17 +69,15 @@ public AEADCipher createInstance() return new ElephantEngine(ElephantEngine.ElephantParameters.elephant200); } }); - testVectors(ElephantEngine.ElephantParameters.elephant200, "v200"); - testVectors(ElephantEngine.ElephantParameters.elephant160, "v160"); - testVectors(ElephantEngine.ElephantParameters.elephant176, "v176"); + elephant = new ElephantEngine(ElephantEngine.ElephantParameters.elephant160); testExceptions(elephant, elephant.getKeyBytesSize(), elephant.getIVBytesSize(), elephant.getBlockSize()); - testParameters(elephant, 16, 12, 8); + implTestParametersEngine(elephant, 16, 12, 8); elephant = new ElephantEngine(ElephantEngine.ElephantParameters.elephant176); testExceptions(elephant, elephant.getKeyBytesSize(), elephant.getIVBytesSize(), elephant.getBlockSize()); - testParameters(elephant, 16, 12, 8); + implTestParametersEngine(elephant, 16, 12, 8); } @@ -92,7 +98,7 @@ private void testVectors(ElephantEngine.ElephantParameters pbp, String filename) int a = line.indexOf('='); if (a < 0) { -// if (!map.get("Count").equals("34")) +// if (!map.get("Count").equals("689")) // { // continue; // } @@ -185,7 +191,7 @@ private void testExceptions(AEADCipher aeadBlockCipher, int keysize, int ivsize, aeadBlockCipher.doFinal(c1, m.length); fail(aeadBlockCipher.getAlgorithmName() + " need to be initialed before dofinal"); } - catch (IllegalArgumentException e) + catch (IllegalStateException e) { //expected } @@ -197,7 +203,7 @@ private void testExceptions(AEADCipher aeadBlockCipher, int keysize, int ivsize, // aeadBlockCipher.getOutputSize(0); // aeadBlockCipher.getUpdateOutputSize(0); } - catch (IllegalArgumentException e) + catch (IllegalStateException e) { //expected fail(aeadBlockCipher.getAlgorithmName() + " functions can be called before initialisation"); @@ -306,6 +312,7 @@ private void testExceptions(AEADCipher aeadBlockCipher, int keysize, int ivsize, // } try { + aeadBlockCipher.init(true, params); aeadBlockCipher.doFinal(new byte[2], 2); fail(aeadBlockCipher.getAlgorithmName() + ": output for dofinal is too short"); } @@ -328,15 +335,14 @@ private void testExceptions(AEADCipher aeadBlockCipher, int keysize, int ivsize, fail(aeadBlockCipher.getAlgorithmName() + ": mac should match for the same AAD with different ways of inputing"); } - byte[] c2 = new byte[aeadBlockCipher.getOutputSize(10)]; - byte[] c3 = new byte[aeadBlockCipher.getOutputSize(10) + 2]; - byte[] aad2 = {0, 1, 2, 3, 4}; byte[] aad3 = {0, 0, 1, 2, 3, 4, 5}; byte[] m2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; byte[] m3 = {0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; byte[] m4 = new byte[m2.length]; aeadBlockCipher.init(true, params); + byte[] c2 = new byte[aeadBlockCipher.getOutputSize(10)]; + byte[] c3 = new byte[aeadBlockCipher.getOutputSize(10) + 2]; aeadBlockCipher.processAADBytes(aad2, 0, aad2.length); int offset = aeadBlockCipher.processBytes(m2, 0, m2.length, c2, 0); aeadBlockCipher.doFinal(c2, offset); @@ -370,7 +376,7 @@ private void testExceptions(AEADCipher aeadBlockCipher, int keysize, int ivsize, aeadBlockCipher.doFinal(m4, offset); fail(aeadBlockCipher.getAlgorithmName() + ": The decryption should fail"); } - catch (IllegalArgumentException e) + catch (InvalidCipherTextException e) { //expected; } @@ -411,21 +417,31 @@ private void testExceptions(AEADCipher aeadBlockCipher, int keysize, int ivsize, // System.out.println(aeadBlockCipher.getAlgorithmName() + " test Exceptions pass"); } - private void testParameters(ElephantEngine isap, int keySize, int ivSize, int macSize) + private void implTestParametersEngine(ElephantEngine cipher, int keySize, int ivSize, + int macSize) { - if (isap.getKeyBytesSize() != keySize) + if (cipher.getKeyBytesSize() != keySize) { - fail(isap.getAlgorithmName() + ": key bytes of " + isap.getAlgorithmName() + " is not correct"); + fail("key bytes of " + cipher.getAlgorithmName() + " is not correct"); } - if (isap.getIVBytesSize() != ivSize) + if (cipher.getIVBytesSize() != ivSize) { - fail(isap.getAlgorithmName() + ": iv bytes of " + isap.getAlgorithmName() + " is not correct"); + fail("iv bytes of " + cipher.getAlgorithmName() + " is not correct"); } - if (isap.getOutputSize(0) != macSize) + + CipherParameters parameters = new ParametersWithIV(new KeyParameter(new byte[keySize]), new byte[ivSize]); + + cipher.init(true, parameters); + if (cipher.getOutputSize(0) != macSize) + { + fail("getOutputSize of " + cipher.getAlgorithmName() + " is incorrect for encryption"); + } + + cipher.init(false, parameters); + if (cipher.getOutputSize(macSize) != 0) { - fail(isap.getAlgorithmName() + ": mac bytes of " + isap.getAlgorithmName() + " is not correct"); + fail("getOutputSize of " + cipher.getAlgorithmName() + " is incorrect for decryption"); } - // System.out.println(isap.getAlgorithmName() + " test Parameters pass"); } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/GCMTest.java b/core/src/test/java/org/bouncycastle/crypto/test/GCMTest.java index f1037c25a1..10305919be 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/GCMTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/GCMTest.java @@ -317,7 +317,7 @@ public void performTest() throws Exception private void testResetBehavior() throws Exception { - GCMBlockCipher gcm = new GCMBlockCipher(createAESEngine()); + GCMModeCipher gcm = createGCM(createAESEngine()); SecureRandom rnd = new SecureRandom(); int[] ivLens = new int[]{10,12,16}; @@ -372,13 +372,18 @@ protected BlockCipher createAESEngine() return AESEngine.newInstance(); } + protected GCMModeCipher createGCM(BlockCipher cipher) + { + return GCMBlockCipher.newInstance(cipher); + } + private void testExceptions() throws InvalidCipherTextException { - GCMBlockCipher gcm = new GCMBlockCipher(createAESEngine()); + GCMModeCipher gcm = createGCM(createAESEngine()); try { - gcm = new GCMBlockCipher(new DESEngine()); + gcm = createGCM(new DESEngine()); fail("incorrect block size not picked up"); } catch (IllegalArgumentException e) diff --git a/core/src/test/java/org/bouncycastle/crypto/test/GOST3412Test.java b/core/src/test/java/org/bouncycastle/crypto/test/GOST3412Test.java index 48a78e18db..d8e498c180 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/GOST3412Test.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/GOST3412Test.java @@ -1,5 +1,6 @@ package org.bouncycastle.crypto.test; +import org.bouncycastle.crypto.StreamBlockCipher; import org.bouncycastle.crypto.engines.GOST3412_2015Engine; import org.bouncycastle.crypto.modes.G3413CBCBlockCipher; import org.bouncycastle.crypto.modes.G3413CFBBlockCipher; @@ -7,6 +8,7 @@ import org.bouncycastle.crypto.modes.G3413OFBBlockCipher; 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; @@ -87,10 +89,66 @@ public void performTest() { super.performTest(); + ctrTest(); // cfbTest(); // ofbTest(); } + private void ctrTest() + throws Exception + { + StreamBlockCipher sb = new G3413CTRBlockCipher(new GOST3412_2015Engine(), 8); + + sb.init(true, new ParametersWithIV(new KeyParameter(Hex.decode("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")), + Hex.decode("0001020304050607"))); + + byte[] block = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] output = new byte[16]; + byte[] last = new byte[16]; + + sb.processBytes(block, 0, block.length, last, 0); + + for (int i = 1; i < 255; i++) + { + sb.processBytes(block, 0, block.length, output, 0); + if (Arrays.areEqual(last, output)) + { + fail("cipher text repeats 1"); + } + } + + sb.processBytes(block, 0, block.length, output, 0); + if (Arrays.areEqual(last, output)) + { + fail("cipher text repeats 2"); + } + + sb = new G3413CTRBlockCipher(new GOST3412_2015Engine(), 8); + + sb.init(true, new ParametersWithIV(new KeyParameter(Hex.decode("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")), + Hex.decode("0001020304050607"))); + + sb.processBytes(block, 0, block.length, last, 0); + + for (int i = 1; i != ((1 << 15) - 1); i++) + { + sb.processBytes(block, 0, block.length, output, 0); + if (Arrays.areEqual(last, output)) + { + fail("cipher text repeats 3"); + } + byte[] tmp = last; + last = output; + output = tmp; + } + + sb.processBytes(block, 0, block.length, output, 0); + if (Arrays.areEqual(last, output)) + { + fail("cipher text repeats"); + } + } + public static void main( String[] args) { diff --git a/core/src/test/java/org/bouncycastle/crypto/test/GiftCofbTest.java b/core/src/test/java/org/bouncycastle/crypto/test/GiftCofbTest.java new file mode 100644 index 0000000000..a7d18239f1 --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/test/GiftCofbTest.java @@ -0,0 +1,84 @@ +package org.bouncycastle.crypto.test; + +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.engines.GiftCofbEngine; +import org.bouncycastle.crypto.modes.AEADCipher; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.test.SimpleTest; + +public class GiftCofbTest + extends SimpleTest +{ + public String getName() + { + return "GiftCofb"; + } + + public void performTest() + throws Exception + { + CipherTest.checkAEADCipherOutputSize(this, 16, 16, 16, 16, new GiftCofbEngine()); + CipherTest.implTestVectorsEngine(new GiftCofbEngine(), "crypto/giftcofb", "giftcofb_LWC_AEAD_KAT_128_128.txt", this); + CipherTest.implTestBufferingEngine(16, 16, 128, this, new CipherTest.Instance() + { + @Override + public AEADCipher createInstance() + { + return new GiftCofbEngine(); + } + }); + CipherTest.implTestExceptionsEngine(16, 16, this, new CipherTest.Instance() + { + @Override + public AEADCipher createInstance() + { + return new GiftCofbEngine(); + } + }); + implTestParametersEngine(new GiftCofbEngine(), 16, 16, 16); + CipherTest.checkAEADParemeter(this, 16, 16, 16, 16, new GiftCofbEngine()); + CipherTest.testOverlapping(this, 16, 16, 16, 16, new GiftCofbEngine()); + CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 33, 16, 128, 16, new GiftCofbEngine()); + + CipherTest.checkCipher(16, 16, 40, 128, new CipherTest.Instance() + { + public AEADCipher createInstance() + { + return new GiftCofbEngine(); + } + }); + } + + private void implTestParametersEngine(GiftCofbEngine cipher, int keySize, int ivSize, + int macSize) + { + if (cipher.getKeyBytesSize() != keySize) + { + fail("key bytes of " + cipher.getAlgorithmName() + " is not correct"); + } + if (cipher.getIVBytesSize() != ivSize) + { + fail("iv bytes of " + cipher.getAlgorithmName() + " is not correct"); + } + + CipherParameters parameters = new ParametersWithIV(new KeyParameter(new byte[keySize]), new byte[ivSize]); + + cipher.init(true, parameters); + if (cipher.getOutputSize(0) != macSize) + { + fail("getOutputSize of " + cipher.getAlgorithmName() + " is incorrect for encryption"); + } + + cipher.init(false, parameters); + if (cipher.getOutputSize(macSize) != 0) + { + fail("getOutputSize of " + cipher.getAlgorithmName() + " is incorrect for decryption"); + } + } + + public static void main(String[] args) + { + runTest(new GiftCofbTest()); + } +} diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java b/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java index 1d9395faaf..5937166965 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/Grain128AEADTest.java @@ -1,19 +1,17 @@ package org.bouncycastle.crypto.test; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.HashMap; +import java.security.SecureRandom; -import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.engines.Grain128AEADEngine; +import org.bouncycastle.crypto.modes.AEADCipher; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; -import org.bouncycastle.test.TestResourceFinder; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.SimpleTestResult; +import org.bouncycastle.util.test.TestFailedException; public class Grain128AEADTest extends SimpleTest @@ -26,50 +24,27 @@ public String getName() public void performTest() throws Exception { - CipherTest.checkAEADParemeter(this, 16, 12, 8, 16, new Grain128AEADEngine()); - testVectors(); + CipherTest.testOverlapping(this, 16, 12, 8, 20, new Grain128AEADEngine()); + CipherTest.implTestVectorsEngine(new Grain128AEADEngine(), "crypto", "LWC_AEAD_KAT_128_96.txt", this); + checkAEADCipherOutputSize(this, 16, 12, 8, new Grain128AEADEngine()); + CipherTest.checkCipher(32, 12, 100, 128, new CipherTest.Instance() + { + @Override + public AEADCipher createInstance() + { + return new Grain128AEADEngine(); + } + }); + CipherTest.checkAEADCipherMultipleBlocks(this, 1024, 7, 100, 128, 12, new Grain128AEADEngine()); + + + CipherTest.checkAEADParemeter(this, 16, 12, 8, 20, new Grain128AEADEngine()); + testSplitUpdate(); testExceptions(); testLongAEAD(); } - private void testVectors() - throws Exception - { - Grain128AEADEngine grain = new Grain128AEADEngine(); - CipherParameters params; - InputStream src = TestResourceFinder.findTestResource("crypto", "LWC_AEAD_KAT_128_96.txt"); - BufferedReader bin = new BufferedReader(new InputStreamReader(src)); - String line; - byte[] ptByte, adByte; - byte[] rv; - HashMap map = new HashMap(); - while ((line = bin.readLine()) != null) - { - int a = line.indexOf('='); - if (a < 0) - { - params = new ParametersWithIV(new KeyParameter(Hex.decode((String)map.get("Key"))), Hex.decode((String)map.get("Nonce"))); - grain.init(true, params); - adByte = Hex.decode((String)map.get("AD")); - grain.processAADBytes(adByte, 0, adByte.length); - ptByte = Hex.decode((String)map.get("PT")); - rv = new byte[ptByte.length]; - grain.processBytes(ptByte, 0, ptByte.length, rv, 0); - byte[] mac = new byte[8]; - grain.doFinal(mac, 0); - if (!areEqual(Arrays.concatenate(rv, mac), Hex.decode((String)map.get("CT")))) - { - mismatch("Keystream " + map.get("Count"), (String)map.get("CT"), rv); - } - map.clear(); - } - else - { - map.put(line.substring(0, a).trim(), line.substring(a + 1).trim()); - } - } - } private void testSplitUpdate() throws InvalidCipherTextException @@ -96,7 +71,7 @@ private void testSplitUpdate() grain.doFinal(rv, len); isTrue(Arrays.areEqual(rv, CT)); - + grain.init(true, params); grain.processBytes(PT, 0, 10, rv, 0); try { @@ -105,7 +80,7 @@ private void testSplitUpdate() } catch (IllegalStateException e) { - isEquals("associated data must be added before plaintext/ciphertext", e.getMessage()); + isEquals("Grain-128 AEAD needs to be initialized", e.getMessage()); } try @@ -115,7 +90,7 @@ private void testSplitUpdate() } catch (IllegalStateException e) { - isEquals("associated data must be added before plaintext/ciphertext", e.getMessage()); + isEquals("Grain-128 AEAD needs to be initialized", e.getMessage()); } } @@ -128,11 +103,11 @@ private void testLongAEAD() byte[] AD = Hex.decode( // 186 bytes "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9"); byte[] CT = Hex.decode("731DAA8B1D15317A1CCB4E3DD320095FB27E5BB2A10F2C669F870538637D4F162298C70430A2B560"); - + Grain128AEADEngine grain = new Grain128AEADEngine(); ParametersWithIV params = new ParametersWithIV(new KeyParameter(Key), Nonce); grain.init(true, params); - + grain.processAADBytes(AD, 0, AD.length); byte[] rv = new byte[CT.length]; @@ -141,9 +116,9 @@ private void testLongAEAD() len += grain.processBytes(PT, 11, PT.length - 11, rv, len); grain.doFinal(rv, len); - - isTrue(Arrays.areEqual(rv, CT)); + isTrue(Arrays.areEqual(rv, CT)); + grain.init(true, params); grain.processBytes(PT, 0, 10, rv, 0); try { @@ -152,7 +127,7 @@ private void testLongAEAD() } catch (IllegalStateException e) { - isEquals("associated data must be added before plaintext/ciphertext", e.getMessage()); + isEquals("Grain-128 AEAD needs to be initialized", e.getMessage()); } try @@ -162,7 +137,7 @@ private void testLongAEAD() } catch (IllegalStateException e) { - isEquals("associated data must be added before plaintext/ciphertext", e.getMessage()); + isEquals("Grain-128 AEAD needs to be initialized", e.getMessage()); } } @@ -178,7 +153,7 @@ private void testExceptions() } catch (IllegalArgumentException e) { - isEquals("invalid parameters passed to Grain-128AEAD", e.getMessage()); + isEquals("invalid parameters passed to Grain-128 AEAD", e.getMessage()); } try @@ -190,7 +165,7 @@ private void testExceptions() } catch (IllegalArgumentException e) { - isEquals("Grain-128AEAD requires exactly 12 bytes of IV", e.getMessage()); + isEquals("Grain-128 AEAD requires exactly 12 bytes of IV", e.getMessage()); } try @@ -202,13 +177,57 @@ private void testExceptions() } catch (IllegalArgumentException e) { - isEquals("Grain-128AEAD key must be 16 bytes long", e.getMessage()); + isEquals("Grain-128 AEAD key must be 16 bytes long", e.getMessage()); } } - private void mismatch(String name, String expected, byte[] found) + static void checkAEADCipherOutputSize(SimpleTest parent, int keySize, int ivSize, int tagSize, AEADCipher cipher) + throws InvalidCipherTextException { - fail("mismatch on " + name, expected, new String(Hex.encode(found))); + final SecureRandom random = new SecureRandom(); + int tmpLength = random.nextInt(tagSize - 1) + 1; + final byte[] plaintext = new byte[tmpLength]; + byte[] key = new byte[keySize]; + byte[] iv = new byte[ivSize]; + random.nextBytes(key); + random.nextBytes(iv); + random.nextBytes(plaintext); + cipher.init(true, new ParametersWithIV(new KeyParameter(key), iv)); + byte[] ciphertext = new byte[cipher.getOutputSize(plaintext.length)]; + //before the encrypt + isEqualTo(parent, plaintext.length + tagSize, ciphertext.length); + isEqualTo(parent, plaintext.length, cipher.getUpdateOutputSize(plaintext.length)); + //during the encrypt process of the first block + int len = cipher.processBytes(plaintext, 0, tmpLength, ciphertext, 0); + isEqualTo(parent, plaintext.length + tagSize, len + cipher.getOutputSize(plaintext.length - tmpLength)); + isEqualTo(parent, plaintext.length, len + cipher.getUpdateOutputSize(plaintext.length - tmpLength)); + //process doFinal + len += cipher.doFinal(ciphertext, len); + isEqualTo(parent, len, ciphertext.length); + + cipher.init(false, new ParametersWithIV(new KeyParameter(key), iv)); + //before the encrypt + isEqualTo(parent, plaintext.length, cipher.getOutputSize(ciphertext.length)); + isEqualTo(parent, plaintext.length, cipher.getUpdateOutputSize(ciphertext.length)); + //during the encrypt process of the first block + len = cipher.processBytes(ciphertext, 0, tmpLength, plaintext, 0); + isEqualTo(parent, plaintext.length, len + cipher.getOutputSize(ciphertext.length - tmpLength)); + isEqualTo(parent, plaintext.length, len + cipher.getUpdateOutputSize(ciphertext.length - tmpLength)); + //process doFinal + len = cipher.processBytes(ciphertext, tmpLength, tagSize, plaintext, 0); + len += cipher.doFinal(plaintext, len); + isEqualTo(parent, len, plaintext.length); + } + + static void isEqualTo( + SimpleTest parent, + int a, + int b) + { + if (a != b) + { + throw new TestFailedException(SimpleTestResult.failed(parent, "no message")); + } } public static void main(String[] args) @@ -216,4 +235,3 @@ public static void main(String[] args) runTest(new Grain128AEADTest()); } } - diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Grain128Test.java b/core/src/test/java/org/bouncycastle/crypto/test/Grain128Test.java index 64ede1a738..cf58fbdec9 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/Grain128Test.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/Grain128Test.java @@ -15,8 +15,8 @@ public class Grain128Test extends SimpleTest { - String keyStream1 = "f09b7bf7d7f6b5c2de2ffc73ac21397f"; - String keyStream2 = "afb5babfa8de896b4b9c6acaf7c4fbfd"; + String keyStream1 = "4bdb20824c5dce6fc63e94456c3281d4"; + String keyStream2 = "ba399daf90df8eba103d9ea83c805904"; public String getName() { diff --git a/core/src/test/java/org/bouncycastle/crypto/test/HCFamilyVecTest.java b/core/src/test/java/org/bouncycastle/crypto/test/HCFamilyVecTest.java index 99f70e868b..e5134a1949 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/HCFamilyVecTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/HCFamilyVecTest.java @@ -93,7 +93,7 @@ private void runAllVectors(StreamCipher hc, String fileName, PeekableLineReader private String dellChar(String s, char c) { - StringBuffer b = new StringBuffer(); + StringBuilder b = new StringBuilder(); for (int i = 0; i != s.length(); i++) { diff --git a/core/src/test/java/org/bouncycastle/crypto/test/HPKETestVectors.java b/core/src/test/java/org/bouncycastle/crypto/test/HPKETestVectors.java index 7f3c12579b..830535a040 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/HPKETestVectors.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/HPKETestVectors.java @@ -8,7 +8,6 @@ import java.util.HashMap; import java.util.Iterator; -import junit.framework.TestCase; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.hpke.AEAD; @@ -16,10 +15,14 @@ import org.bouncycastle.crypto.hpke.HPKEContext; import org.bouncycastle.crypto.hpke.HPKEContextWithEncapsulation; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.math.ec.rfc7748.X25519; +import org.bouncycastle.math.ec.rfc7748.X448; import org.bouncycastle.test.TestResourceFinder; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; +import junit.framework.TestCase; + public class HPKETestVectors extends TestCase { @@ -259,26 +262,50 @@ public void testVectors() // generate a private key from skRm and pkRm AsymmetricCipherKeyPair kp = hpke.deserializePrivateKey(skRm, pkRm); + byte[] skRm_serialized = Arrays.clone(skRm); + byte[] skSm_serialized = Arrays.clone(skSm); + byte[] skEm_serialized = Arrays.clone(skEm); + + switch (kem_id) + { + case HPKE.kem_X25519_SHA256: + X25519.clampPrivateKey(skRm_serialized); + if (mode == 2 || mode == 3) + { + X25519.clampPrivateKey(skSm_serialized); + } + X25519.clampPrivateKey(skEm_serialized); + break; + case HPKE.kem_X448_SHA512: + X448.clampPrivateKey(skRm_serialized); + if (mode == 2 || mode == 3) + { + X448.clampPrivateKey(skSm_serialized); + } + X448.clampPrivateKey(skEm_serialized); + break; + } + // tesing serialize assertTrue("serialize public key failed", Arrays.areEqual(pkRm, hpke.serializePublicKey(kp.getPublic()))); - assertTrue("serialize private key failed", Arrays.areEqual(skRm, hpke.serializePrivateKey(kp.getPrivate()))); + assertTrue("serialize private key failed", Arrays.areEqual(skRm_serialized, hpke.serializePrivateKey(kp.getPrivate()))); // testing receiver derive key pair assertTrue("receiver derived public key pair incorrect", Arrays.areEqual(pkRm, hpke.serializePublicKey(derivedKeyPairR.getPublic()))); - assertTrue("receiver derived secret key pair incorrect", Arrays.areEqual(skRm, hpke.serializePrivateKey(derivedKeyPairR.getPrivate()))); + assertTrue("receiver derived secret key pair incorrect", Arrays.areEqual(skRm_serialized, hpke.serializePrivateKey(derivedKeyPairR.getPrivate()))); // testing sender's derived key pair if (mode == 2 || mode == 3) { AsymmetricCipherKeyPair derivedSenderKeyPair = hpke.deriveKeyPair(ikmS); assertTrue("sender derived public key pair incorrect", Arrays.areEqual(pkSm, hpke.serializePublicKey(derivedSenderKeyPair.getPublic()))); - assertTrue("sender derived private key pair incorrect", Arrays.areEqual(skSm, hpke.serializePrivateKey(derivedSenderKeyPair.getPrivate()))); + assertTrue("sender derived private key pair incorrect", Arrays.areEqual(skSm_serialized, hpke.serializePrivateKey(derivedSenderKeyPair.getPrivate()))); } // testing ephemeral derived key pair AsymmetricCipherKeyPair derivedEKeyPair = hpke.deriveKeyPair(ikmE); assertTrue("ephemeral derived public key pair incorrect", Arrays.areEqual(pkEm, hpke.serializePublicKey(derivedEKeyPair.getPublic()))); - assertTrue("ephemeral derived private key pair incorrect", Arrays.areEqual(skEm, hpke.serializePrivateKey(derivedEKeyPair.getPrivate()))); + assertTrue("ephemeral derived private key pair incorrect", Arrays.areEqual(skEm_serialized, hpke.serializePrivateKey(derivedEKeyPair.getPrivate()))); // create a context with setupRecv // use pkEm as encap, private key from above, info as info diff --git a/core/src/test/java/org/bouncycastle/crypto/test/ISAPTest.java b/core/src/test/java/org/bouncycastle/crypto/test/ISAPTest.java index 57eea8f2e4..007fa98f90 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/ISAPTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/ISAPTest.java @@ -8,7 +8,6 @@ import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.digests.ISAPDigest; @@ -33,7 +32,9 @@ public String getName() public void performTest() throws Exception { - CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 33, 16, 128, 16, new ISAPEngine(IsapType.ISAP_A_128A)); + DigestTest.implTestVectorsDigest(this, new ISAPDigest(), "crypto/isap", "LWC_HASH_KAT_256.txt"); + DigestTest.checkDigestReset(this, new ISAPDigest()); + DigestTest.implTestExceptionsAndParametersDigest(this, new ISAPDigest(), 32); testVectors("isapa128av20", IsapType.ISAP_A_128A); testVectors("isapa128v20", IsapType.ISAP_A_128); testVectors("isapk128av20", IsapType.ISAP_K_128A); @@ -50,9 +51,7 @@ public void performTest() ISAP = new ISAPEngine(IsapType.ISAP_A_128); testExceptions(ISAP, ISAP.getKeyBytesSize(), ISAP.getIVBytesSize(), ISAP.getBlockSize()); testParameters(ISAP, 16, 16, 16); - testExceptions(new ISAPDigest(), 32); - testVectors(); CipherTest.checkCipher(32, 16, 100, 128, new CipherTest.Instance() { @Override @@ -89,13 +88,17 @@ public AEADCipher createInstance() CipherTest.checkAEADParemeter(this, 16, 16, 16, 16, new ISAPEngine(IsapType.ISAP_K_128)); CipherTest.checkAEADParemeter(this, 16, 16, 16, 8, new ISAPEngine(IsapType.ISAP_A_128A)); CipherTest.checkAEADParemeter(this, 16, 16, 16, 8, new ISAPEngine(IsapType.ISAP_A_128)); + CipherTest.testOverlapping(this, 16, 16, 16, 16, new ISAPEngine(IsapType.ISAP_K_128A)); + CipherTest.testOverlapping(this, 16, 16, 16, 16, new ISAPEngine(IsapType.ISAP_K_128)); + CipherTest.testOverlapping(this, 16, 16, 16, 8, new ISAPEngine(IsapType.ISAP_A_128A)); + CipherTest.testOverlapping(this, 16, 16, 16, 8, new ISAPEngine(IsapType.ISAP_A_128)); CipherTest.checkAEADCipherOutputSize(this, 16, 16, 18, 16, new ISAPEngine(IsapType.ISAP_K_128A)); CipherTest.checkAEADCipherOutputSize(this, 16, 16, 18, 16, new ISAPEngine(IsapType.ISAP_K_128)); CipherTest.checkAEADCipherOutputSize(this, 16, 16, 8, 16, new ISAPEngine(IsapType.ISAP_A_128A)); CipherTest.checkAEADCipherOutputSize(this, 16, 16, 8, 16, new ISAPEngine(IsapType.ISAP_A_128)); CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 33, 16, 128, 16, new ISAPEngine(IsapType.ISAP_K_128A)); CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 33, 16, 128, 16, new ISAPEngine(IsapType.ISAP_K_128)); - + CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 33, 16, 128, 16, new ISAPEngine(IsapType.ISAP_A_128A)); CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 33, 16, 128, 16, new ISAPEngine(IsapType.ISAP_A_128)); } @@ -114,10 +117,10 @@ private void testVectors(String filename, IsapType isapType) int a = line.indexOf('='); if (a < 0) { -// if (!map.get("Count").equals("19")) -// { -// continue; -// } + if (!map.get("Count").equals("265")) + { + continue; + } byte[] key = Hex.decode(map.get("Key")); byte[] nonce = Hex.decode(map.get("Nonce")); byte[] ad = Hex.decode(map.get("AD")); @@ -163,74 +166,6 @@ private void testVectors(String filename, IsapType isapType) //System.out.print.println(filename + " pass"); } - private void testVectors() - throws Exception - { - ISAPDigest isap = new ISAPDigest(); - InputStream src = TestResourceFinder.findTestResource("crypto/isap", "LWC_HASH_KAT_256.txt"); - BufferedReader bin = new BufferedReader(new InputStreamReader(src)); - String line; - byte[] ptByte; - HashMap map = new HashMap(); - while ((line = bin.readLine()) != null) - { - int a = line.indexOf('='); - if (a < 0) - { -// if (!map.get("Count").equals("10")) -// { -// continue; -// } - ptByte = Hex.decode((String)map.get("Msg")); - isap.update(ptByte, 0, ptByte.length); - byte[] hash = new byte[32]; - isap.doFinal(hash, 0); - if (!areEqual(hash, Hex.decode((String)map.get("MD")))) - { - mismatch("Keystream " + map.get("Count"), (String)map.get("MD"), hash); - } -// else -// { -// System.out.println(map.get("Count") + " pass"); -// } - map.clear(); - isap.reset(); - } - else - { - map.put(line.substring(0, a).trim(), line.substring(a + 1).trim()); - } - } - //System.out.print.println("ISAP Hash pass"); - } - - private void testExceptions(Digest digest, int digestsize) - { - if (digest.getDigestSize() != digestsize) - { - fail(digest.getAlgorithmName() + ": digest size is not correct"); - } - - try - { - digest.update(new byte[1], 1, 1); - fail(digest.getAlgorithmName() + ": input for update is too short"); - } - catch (DataLengthException e) - { - //expected - } - try - { - digest.doFinal(new byte[digest.getDigestSize() - 1], 2); - fail(digest.getAlgorithmName() + ": output for dofinal is too short"); - } - catch (DataLengthException e) - { - //expected - } - //System.out.print.println(digest.getAlgorithmName() + " test Exceptions pass"); - } private void testExceptions(AEADCipher aeadBlockCipher, int keysize, int ivsize, int blocksize) throws Exception @@ -346,6 +281,7 @@ private void testExceptions(AEADCipher aeadBlockCipher, int keysize, int ivsize, fail(aeadBlockCipher.getAlgorithmName() + ": mac should not match"); } aeadBlockCipher.reset(); + aeadBlockCipher.init(true, params); aeadBlockCipher.processBytes(new byte[16], 0, 16, new byte[16], 0); // try // { @@ -387,6 +323,7 @@ private void testExceptions(AEADCipher aeadBlockCipher, int keysize, int ivsize, } try { + aeadBlockCipher.init(true, params); aeadBlockCipher.processBytes(new byte[blocksize + 1], 0, blocksize + 1, new byte[blocksize], blocksize >> 1); fail(aeadBlockCipher.getAlgorithmName() + ": output for processBytes is too short"); } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/KMACTest.java b/core/src/test/java/org/bouncycastle/crypto/test/KMACTest.java index 52f9fb73d1..55355c7513 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/KMACTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/KMACTest.java @@ -1,8 +1,11 @@ package org.bouncycastle.crypto.test; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.EncodableService; import org.bouncycastle.crypto.macs.KMAC; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Memoable; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; @@ -137,7 +140,15 @@ public void performTest() checkKMAC(256, new KMAC(256, null), Hex.decode("eeaabeef")); checkKMAC(128, new KMAC(128, new byte[0]), Hex.decode("eeaabeef")); checkKMAC(128, new KMAC(128, null), Hex.decode("eeaabeef")); - checkKMAC(256, new KMAC(256, null), Hex.decode("eeaabeef")); + checkKMAC(256, new KMAC(256, null), Hex.decode("eeaabeef")); + + byte[] resBuf = new byte[32]; + byte[] message = Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"); + byte[] expected = Hex.decode("059a2eb4961b482ff5bb6a0278d3ad2117b20aafb2f0df33e7748176648c8192"); + + testClone(resBuf, message, expected, new KMAC(128, new byte[0]), Hex.decode("eeaabeef")); + testMemo(resBuf, message, expected, new KMAC(128, new byte[0]), Hex.decode("eeaabeef")); + testEncodedState(resBuf, message, expected, new KMAC(128, new byte[0]), Hex.decode("eeaabeef")); } private void doFinalTest() @@ -146,7 +157,7 @@ private void doFinalTest() kmac.init(new KeyParameter(Hex.decode( "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"))); - + kmac.update(Hex.decode("00010203"), 0, 4); byte[] res = new byte[32]; @@ -236,7 +247,7 @@ private void checkKMAC(int bitSize, KMAC kmac, byte[] msg) ref.init(new KeyParameter(new byte[0])); kmac.init(new KeyParameter(new byte[0])); - + ref.update(msg, 0, msg.length); kmac.update(msg, 0, msg.length); @@ -249,6 +260,110 @@ private void checkKMAC(int bitSize, KMAC kmac, byte[] msg) isTrue(Arrays.areEqual(res1, res2)); } + private void testEncodedState(byte[] resBuf, byte[] input, byte[] expected, KMAC kmac, byte[] key) + { + kmac.init(new KeyParameter(key)); + + // test state encoding; + kmac.update(input, 0, input.length / 2); + + // copy the Digest + Digest copy1 = new KMAC(((EncodableService)kmac).getEncodedState()); + Digest copy2 = new KMAC(((EncodableService)copy1).getEncodedState()); + + kmac.update(input, input.length / 2, input.length - input.length / 2); + + kmac.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing state vector test", expected, new String(Hex.encode(resBuf))); + } + + copy1.update(input, input.length / 2, input.length - input.length / 2); + copy1.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing state copy1 vector test", expected, new String(Hex.encode(resBuf))); + } + + copy2.update(input, input.length / 2, input.length - input.length / 2); + copy2.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing state copy2 vector test", expected, new String(Hex.encode(resBuf))); + } + } + + private void testMemo(byte[] resBuf, byte[] input, byte[] expected, KMAC kmac, byte[] key) + { + kmac.init(new KeyParameter(key)); + + Memoable m = (Memoable)kmac; + + kmac.update(input, 0, input.length / 2); + + // copy the Digest + Memoable copy1 = m.copy(); + Memoable copy2 = copy1.copy(); + + kmac.update(input, input.length / 2, input.length - input.length / 2); + kmac.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing memo vector test", Hex.toHexString(expected), Hex.toHexString(resBuf)); + } + + m.reset(copy1); + + kmac.update(input, input.length / 2, input.length - input.length / 2); + kmac.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing memo reset vector test", Hex.toHexString(expected), Hex.toHexString(resBuf)); + } + + KMAC md = (KMAC)copy2; + + md.update(input, input.length / 2, input.length - input.length / 2); + md.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing memo copy vector test", Hex.toHexString(expected), Hex.toHexString(resBuf)); + } + } + + private void testClone(byte[] resBuf, byte[] input, byte[] expected, KMAC kmac, byte[] key) + { + kmac.init(new KeyParameter(key)); + + kmac.update(input, 0, input.length / 2); + + // clone the Digest + KMAC d = new KMAC(kmac); + + kmac.update(input, input.length / 2, input.length - input.length / 2); + kmac.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing clone vector test", Hex.toHexString(expected), Hex.toHexString(resBuf)); + } + + d.update(input, input.length / 2, input.length - input.length / 2); + d.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing second clone vector test", Hex.toHexString(expected), Hex.toHexString(resBuf)); + } + } + public static void main( String[] args) { diff --git a/core/src/test/java/org/bouncycastle/crypto/test/KangarooTest.java b/core/src/test/java/org/bouncycastle/crypto/test/KangarooTest.java index c1c5b668dc..7f9d3b4bcc 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/KangarooTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/KangarooTest.java @@ -8,7 +8,8 @@ /** * Test Cases for Kangaroo12. No TestVectors are available for MarsupilamiFourteen. - * Test Vectors taken from https://tools.ietf.org/html/draft-viguier-kangarootwelve-04. + * Test Vectors taken from https://tools.ietf.org/html/draft-viguier-kangarootwelve-04, + * and generated using the reference implementation given in https://keccak.team/files/KangarooTwelve.pdf. */ public class KangarooTest extends SimpleTest @@ -147,7 +148,13 @@ static class Kangaroo12Test "FAB658DB63E94A246188BF7AF69A133045F46EE984C56E3C3328CAAF1AA1A583", "D848C5068CED736F4462159B9867FD4C20B808ACC3D5BC48E0B06BA0A3762EC4", "C389E5009AE57120854C2E8C64670AC01358CF4C1BAF89447A724234DC7CED74", - "75D2F86A2E644566726B4FBCFC5657B9DBCF070C7B0DCA06450AB291D7443BCF" + "75D2F86A2E644566726B4FBCFC5657B9DBCF070C7B0DCA06450AB291D7443BCF", + "61F2AD5657F4F2632A0822138EFE20C6A68A1885E1C0643EBF5587103219301D", + "CBBE9DD1E423F20003FBA7BB219491C8D1F445FA5C4199D6C6C70C9FDC101964", + "77DF46FD2D22BCE26E636E02CE10F9A42AE925E071F9056A9236328DB01BA411", + "711835517A182DD4BC0E816BF5C72A278B227AE0B3D68F82577F97AD3CBFCA6A", + "640728E5B4BE29F04A4FFFA645CB308102170F4D2B69D61F030CDC569BC74BAC", + "5D7D68B49A5D999B8699FC4EDBEF0F0B4E4E7E904FE4B2B6B10C7C922407CF66" }; /** @@ -170,6 +177,12 @@ void checkDigests(final KangarooTest pTest) pTest.testKangaroo(1, false, 41, EXPECTED[11]); pTest.testKangaroo(3, false, 41*41, EXPECTED[12]); pTest.testKangaroo(7, false, 41*41*41, EXPECTED[13]); + pTest.testKangaroo(165, true, 0, EXPECTED[14]); + pTest.testKangaroo(166, true, 0, EXPECTED[15]); + pTest.testKangaroo(167, true, 0, EXPECTED[16]); + pTest.testKangaroo(8192 + 165, false, 0, EXPECTED[17]); + pTest.testKangaroo(8192 + 166, false, 0, EXPECTED[18]); + pTest.testKangaroo(8192 + 167, false, 0, EXPECTED[19]); } } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/NISTCTSTest.java b/core/src/test/java/org/bouncycastle/crypto/test/NISTCTSTest.java index b1febcd4ca..11d1009a86 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/NISTCTSTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/NISTCTSTest.java @@ -1,14 +1,19 @@ package org.bouncycastle.crypto.test; +import java.security.SecureRandom; + import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.BufferedBlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.engines.DSTU7624Engine; +import org.bouncycastle.crypto.modes.KXTSBlockCipher; import org.bouncycastle.crypto.modes.NISTCTSBlockCipher; 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; @@ -36,23 +41,23 @@ public class NISTCTSTest private static byte[] cs2NotQuiteTwoBlockOut = Hex.decode("f098097ca69b72e3a46e9ca21bb5ebbc22ecf2ac77"); private static byte[] cs3NotQuiteTwoBlockOut = Hex.decode("f098097ca69b72e3a46e9ca21bb5ebbc22ecf2ac77"); - static byte[] in1 = Hex.decode("4e6f7720697320746865207420"); - static byte[] in2 = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f0aaa"); - static byte[] out1 = Hex.decode("9952f131588465033fa40e8a98"); - static byte[] out2 = Hex.decode("358f84d01eb42988dc34efb994"); - static byte[] out3 = Hex.decode("170171cfad3f04530c509b0c1f0be0aefbd45a8e3755a873bff5ea198504b71683c6"); - + static byte[] in1 = Hex.decode("4e6f7720697320746865207420"); + static byte[] in2 = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f0aaa"); + static byte[] out1 = Hex.decode("9952f131588465033fa40e8a98"); + static byte[] out2 = Hex.decode("358f84d01eb42988dc34efb994"); + static byte[] out3 = Hex.decode("170171cfad3f04530c509b0c1f0be0aefbd45a8e3755a873bff5ea198504b71683c6"); + private void testCTS( - int id, - int type, - BlockCipher cipher, - CipherParameters params, - byte[] input, - byte[] output) + int id, + int type, + BlockCipher cipher, + CipherParameters params, + byte[] input, + byte[] output) throws Exception { - byte[] out = new byte[input.length]; - BufferedBlockCipher engine = new NISTCTSBlockCipher(type, cipher); + byte[] out = new byte[input.length]; + BufferedBlockCipher engine = new NISTCTSBlockCipher(type, cipher); engine.init(true, params); @@ -77,63 +82,106 @@ private void testCTS( } } - private void testExceptions() throws InvalidCipherTextException + private void testExceptions() + throws InvalidCipherTextException { BufferedBlockCipher engine = new NISTCTSBlockCipher(NISTCTSBlockCipher.CS1, AESEngine.newInstance()); CipherParameters params = new KeyParameter(new byte[engine.getBlockSize()]); engine.init(true, params); byte[] out = new byte[engine.getOutputSize(engine.getBlockSize())]; - + engine.processBytes(new byte[engine.getBlockSize() - 1], 0, engine.getBlockSize() - 1, out, 0); - try + try { engine.doFinal(out, 0); fail("Expected CTS encrypt error on < 1 block input"); - } catch(DataLengthException e) + } + catch (DataLengthException e) { // Expected } engine.init(true, params); engine.processBytes(new byte[engine.getBlockSize()], 0, engine.getBlockSize(), out, 0); - try + try { engine.doFinal(out, 0); - } catch(DataLengthException e) + } + catch (DataLengthException e) { fail("Unexpected CTS encrypt error on == 1 block input"); } engine.init(false, params); engine.processBytes(new byte[engine.getBlockSize() - 1], 0, engine.getBlockSize() - 1, out, 0); - try + try { engine.doFinal(out, 0); fail("Expected CTS decrypt error on < 1 block input"); - } catch(DataLengthException e) + } + catch (DataLengthException e) { // Expected } engine.init(false, params); engine.processBytes(new byte[engine.getBlockSize()], 0, engine.getBlockSize(), out, 0); - try + try { engine.doFinal(out, 0); - } catch(DataLengthException e) + } + catch (DataLengthException e) { fail("Unexpected CTS decrypt error on == 1 block input"); } } + private void testOverlapping() + throws Exception + { + SecureRandom random = new SecureRandom(); + byte[] keyBytes = new byte[16]; + byte[] iv = new byte[16]; + random.nextBytes(keyBytes); + BufferedBlockCipher bc = new NISTCTSBlockCipher(NISTCTSBlockCipher.CS1, AESEngine.newInstance()); + ParametersWithIV param = new ParametersWithIV(new KeyParameter(keyBytes), iv); + + int offset = 1 + random.nextInt(bc.getBlockSize() - 1) + bc.getBlockSize(); + byte[] data = new byte[bc.getBlockSize() * 4 + offset]; + byte[] expected = new byte[bc.getOutputSize(bc.getBlockSize() * 3)]; + random.nextBytes(data); + + bc.init(true, param); + int len = bc.processBytes(data, 0, expected.length, expected, 0); + bc.doFinal(expected, len); + bc.init(true, param); + len = bc.processBytes(data, 0, expected.length, data, offset); + bc.doFinal(data, offset + len); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + expected.length))) + { + fail("failed for overlapping encryption"); + } + + bc.init(false, param); + bc.processBytes(data, 0, expected.length, expected, 0); + bc.init(false, param); + bc.processBytes(data, 0, expected.length, data, offset); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + expected.length))) + { + fail("failed for overlapping decryption"); + } + } + public String getName() { return "NISTCTS"; } - public void performTest() + public void performTest() throws Exception { testCTS(1, NISTCTSBlockCipher.CS1, AESEngine.newInstance(), new ParametersWithIV(key, iv), singleBlock, singleOut); @@ -149,7 +197,7 @@ public void performTest() testCTS(9, NISTCTSBlockCipher.CS3, AESEngine.newInstance(), new ParametersWithIV(key, iv), notQuiteTwo, cs3NotQuiteTwoBlockOut); byte[] aes128b = Hex.decode("aafd12f659cae63489b479e5076ddec2f06cb58faafd12f6"); - byte[] aesIn1b = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"); + byte[] aesIn1b = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"); byte[] aesOut1b = Hex.decode("6db2f802d99e1ef0a5940f306079e083cf87f4d8bb9d1abb36cdd9f44ead7d04"); testCTS(10, NISTCTSBlockCipher.CS3, AESEngine.newInstance(), new ParametersWithIV(new KeyParameter(aes128b), Hex.decode("aafd12f659cae63489b479e5076ddec2")), aesIn1b, aesOut1b); @@ -160,10 +208,11 @@ public void performTest() testCTS(11, NISTCTSBlockCipher.CS3, AESEngine.newInstance(), new ParametersWithIV(new KeyParameter(aes128c), Hex.decode("aafd12f659cae63489b479e5076ddec2")), aesIn1b, aesOut1c); testExceptions(); + testOverlapping(); } public static void main( - String[] args) + String[] args) { runTest(new NISTCTSTest()); } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/PKCS12Test.java b/core/src/test/java/org/bouncycastle/crypto/test/PKCS12Test.java index a5402aeae0..e158379013 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/PKCS12Test.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/PKCS12Test.java @@ -6,6 +6,7 @@ import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; 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.SimpleTestResult; import org.bouncycastle.util.test.Test; @@ -22,26 +23,6 @@ public class PKCS12Test char[] password1 = { 's', 'm', 'e', 'g' }; char[] password2 = { 'q', 'u', 'e', 'e', 'g' }; - private boolean isEqual( - byte[] a, - byte[] b) - { - if (a.length != b.length) - { - return false; - } - - for (int i = 0; i != a.length; i++) - { - if (a[i] != b[i]) - { - return false; - } - } - - return true; - } - private TestResult run1( int id, char[] password, @@ -59,7 +40,7 @@ private TestResult run1( CipherParameters key = generator.generateDerivedParameters(24 * 8); - if (isEqual(result, ((KeyParameter)key).getKey())) + if (Arrays.areEqual(result, ((KeyParameter)key).getKey())) { return new SimpleTestResult(true, "PKCS12Test: Okay"); } @@ -87,7 +68,7 @@ private TestResult run2( ParametersWithIV params = (ParametersWithIV)generator.generateDerivedParameters(64, 64); - if (isEqual(result, params.getIV())) + if (Arrays.areEqual(result, params.getIV())) { return new SimpleTestResult(true, "PKCS12Test: Okay"); } @@ -115,7 +96,7 @@ private TestResult run3( CipherParameters key = generator.generateDerivedMacParameters(160); - if (isEqual(result, ((KeyParameter)key).getKey())) + if (Arrays.areEqual(result, ((KeyParameter)key).getKey())) { return new SimpleTestResult(true, "PKCS12Test: Okay"); } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/PaddingTest.java b/core/src/test/java/org/bouncycastle/crypto/test/PaddingTest.java index c963b26e4f..3c6f6fd24f 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/PaddingTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/PaddingTest.java @@ -13,6 +13,7 @@ import org.bouncycastle.crypto.paddings.ZeroBytePadding; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; @@ -27,28 +28,28 @@ public PaddingTest() } private void blockCheck( - PaddedBufferedBlockCipher cipher, - BlockCipherPadding padding, - KeyParameter key, - byte[] data) + PaddedBufferedBlockCipher cipher, + BlockCipherPadding padding, + KeyParameter key, + byte[] data) { - byte[] out = new byte[data.length + 8]; - byte[] dec = new byte[data.length]; - + byte[] out = new byte[data.length + 8]; + byte[] dec = new byte[data.length]; + try - { + { cipher.init(true, key); - - int len = cipher.processBytes(data, 0, data.length, out, 0); - + + int len = cipher.processBytes(data, 0, data.length, out, 0); + len += cipher.doFinal(out, len); - + cipher.init(false, key); - - int decLen = cipher.processBytes(out, 0, len, dec, 0); - + + int decLen = cipher.processBytes(out, 0, len, dec, 0); + decLen += cipher.doFinal(dec, decLen); - + if (!areEqual(data, dec)) { fail("failed to decrypt - i = " + data.length + ", padding = " + padding.getPaddingName()); @@ -59,31 +60,31 @@ private void blockCheck( fail("Exception - " + e.toString(), e); } } - + public void testPadding( - BlockCipherPadding padding, - SecureRandom rand, - byte[] ffVector, - byte[] ZeroVector) + BlockCipherPadding padding, + SecureRandom rand, + byte[] ffVector, + byte[] ZeroVector) { - PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new DESEngine(), padding); - KeyParameter key = new KeyParameter(Hex.decode("0011223344556677")); - + PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new DESEngine(), padding); + KeyParameter key = new KeyParameter(Hex.decode("0011223344556677")); + // // ff test // - byte[] data = { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0 }; - + byte[] data = {(byte)0xff, (byte)0xff, (byte)0xff, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0}; + if (ffVector != null) { padding.addPadding(data, 3); - + if (!areEqual(data, ffVector)) { fail("failed ff test for " + padding.getPaddingName()); } } - + // // zero test // @@ -91,23 +92,23 @@ public void testPadding( { data = new byte[8]; padding.addPadding(data, 4); - + if (!areEqual(data, ZeroVector)) { fail("failed zero test for " + padding.getPaddingName()); } } - + for (int i = 1; i != 200; i++) { data = new byte[i]; - + rand.nextBytes(data); blockCheck(cipher, padding, key, data); } } - + private void testOutputSizes() { PaddedBufferedBlockCipher bc = new PaddedBufferedBlockCipher(new DESEngine(), new PKCS7Padding()); @@ -138,15 +139,51 @@ private void testOutputSizes() } } + private void testOverlapping() + { + //Skip the dofinal of the test + PaddedBufferedBlockCipher bc = new PaddedBufferedBlockCipher(new DESEngine(), new PKCS7Padding()); + SecureRandom random = new SecureRandom(); + byte[] keyBytes = new byte[8]; + random.nextBytes(keyBytes); + KeyParameter key = new KeyParameter(keyBytes); + + int offset = 2 + random.nextInt(bc.getBlockSize() - 1); + byte[] data = new byte[bc.getBlockSize() * 2 + offset]; + byte[] expected = new byte[bc.getOutputSize(bc.getBlockSize() * 2)]; + random.nextBytes(data); + + bc.init(true, key); + bc.processBytes(data, 0, bc.getBlockSize() * 2 + 1, expected, 0); + bc.init(true, key); + bc.processBytes(data, 0, bc.getBlockSize() * 2 + 1, data, offset); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + bc.getBlockSize() * 2))) + { + fail("failed for overlapping encryption"); + } + + bc.init(false, key); + bc.processBytes(data, 0, bc.getBlockSize() * 2 + 1, expected, 0); + bc.init(false, key); + bc.processBytes(data, 0, bc.getBlockSize() * 2 + 1, data, offset); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + bc.getBlockSize() * 2))) + { + fail("failed for overlapping decryption"); + } + } + public void performTest() { - SecureRandom rand = new SecureRandom(new byte[20]); - + testOverlapping(); + SecureRandom rand = new SecureRandom(new byte[20]); + rand.setSeed(System.currentTimeMillis()); - + testPadding(new PKCS7Padding(), rand, - Hex.decode("ffffff0505050505"), - Hex.decode("0000000004040404")); + Hex.decode("ffffff0505050505"), + Hex.decode("0000000004040404")); PKCS7Padding padder = new PKCS7Padding(); try @@ -161,27 +198,27 @@ public void performTest() { fail("wrong exception for corrupt padding: " + e); } - } + } testPadding(new ISO10126d2Padding(), rand, - null, - null); - + null, + null); + testPadding(new X923Padding(), rand, - null, - null); + null, + null); testPadding(new TBCPadding(), rand, - Hex.decode("ffffff0000000000"), - Hex.decode("00000000ffffffff")); + Hex.decode("ffffff0000000000"), + Hex.decode("00000000ffffffff")); testPadding(new ZeroBytePadding(), rand, - Hex.decode("ffffff0000000000"), - null); - + Hex.decode("ffffff0000000000"), + null); + testPadding(new ISO7816d4Padding(), rand, - Hex.decode("ffffff8000000000"), - Hex.decode("0000000080000000")); + Hex.decode("ffffff8000000000"), + Hex.decode("0000000080000000")); testOutputSizes(); @@ -193,7 +230,7 @@ public String getName() } public static void main( - String[] args) + String[] args) { runTest(new PaddingTest()); } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/ParallelHashTest.java b/core/src/test/java/org/bouncycastle/crypto/test/ParallelHashTest.java index 05080caf2d..5d825cf705 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/ParallelHashTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/ParallelHashTest.java @@ -1,5 +1,6 @@ package org.bouncycastle.crypto.test; + import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.ParallelHash; import org.bouncycastle.util.Arrays; @@ -23,6 +24,7 @@ public String getName() public void performTest() throws Exception { + testException(); ParallelHash pHash = new ParallelHash(128, new byte[0], 8); byte[] data = Hex.decode("00 01 02 03 04 05 06 07 10 11 12 13 14 15 16 17 20 21 22 23 24 25 26 27"); @@ -164,6 +166,19 @@ private void testClone() } } + private void testException() + { + testException("block size should be greater than 0", "IllegalArgumentException", new TestExceptionOperation() + { + @Override + public void operation() + throws Exception + { + Digest digest = new ParallelHash(128, null, 0); + } + }); + } + public static void main( String[] args) { diff --git a/core/src/test/java/org/bouncycastle/crypto/test/PhotonBeetleTest.java b/core/src/test/java/org/bouncycastle/crypto/test/PhotonBeetleTest.java index de75ee1330..3e223b93c5 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/PhotonBeetleTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/PhotonBeetleTest.java @@ -31,12 +31,15 @@ public String getName() public void performTest() throws Exception { + DigestTest.implTestVectorsDigest(this, new PhotonBeetleDigest(), "crypto/photonbeetle", "LWC_HASH_KAT_256.txt"); + DigestTest.checkDigestReset(this, new PhotonBeetleDigest()); + DigestTest.implTestExceptionsAndParametersDigest(this, new PhotonBeetleDigest(), 32); CipherTest.checkAEADCipherMultipleBlocks(this, 1024, 19, 100, 128, 16, new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb128)); CipherTest.checkAEADCipherMultipleBlocks(this, 1024, 19, 100, 128, 16, new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb32)); testVectors(PhotonBeetleEngine.PhotonBeetleParameters.pb32, "v32"); testVectors(PhotonBeetleEngine.PhotonBeetleParameters.pb128, "v128"); DigestTest.checkDigestReset(this, new PhotonBeetleDigest()); - testVectorsHash(); + PhotonBeetleEngine pb = new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb32); testExceptions(pb, pb.getKeyBytesSize(), pb.getIVBytesSize(), pb.getBlockSize()); testParameters(pb, 16, 16, 16); @@ -47,43 +50,12 @@ public void performTest() testExceptions(new PhotonBeetleDigest(), 32); CipherTest.checkAEADParemeter(this, 16, 16, 16, 16, new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb128)); CipherTest.checkAEADParemeter(this, 16, 16, 16, 16, new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb32)); + CipherTest.testOverlapping(this, 16, 16, 16, 16, new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb128)); + CipherTest.testOverlapping(this, 16, 16, 16, 16, new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb32)); CipherTest.checkAEADCipherOutputSize(this, 16, 16, 16, 16, new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb128)); CipherTest.checkAEADCipherOutputSize(this, 16, 16, 4, 16, new PhotonBeetleEngine(PhotonBeetleEngine.PhotonBeetleParameters.pb32)); } - private void testVectorsHash() - throws Exception - { - PhotonBeetleDigest PhotonBeetle = new PhotonBeetleDigest(); - InputStream src = TestResourceFinder.findTestResource("crypto/photonbeetle", "LWC_HASH_KAT_256.txt"); - BufferedReader bin = new BufferedReader(new InputStreamReader(src)); - String line; - byte[] ptByte; - HashMap map = new HashMap(); - while ((line = bin.readLine()) != null) - { - int a = line.indexOf('='); - if (a < 0) - { - PhotonBeetle.reset(); - ptByte = Hex.decode((String)map.get("Msg")); - PhotonBeetle.update(ptByte, 0, ptByte.length); - byte[] hash = new byte[32]; - PhotonBeetle.doFinal(hash, 0); - if (!areEqual(hash, Hex.decode((String)map.get("MD")))) - { - mismatch("Keystream " + map.get("Count"), (String)map.get("MD"), hash); - } - map.clear(); - PhotonBeetle.reset(); - } - else - { - map.put(line.substring(0, a).trim(), line.substring(a + 1).trim()); - } - } - } - private void testVectors(PhotonBeetleEngine.PhotonBeetleParameters pbp, String filename) throws Exception { @@ -178,7 +150,7 @@ private void testExceptions(AEADCipher aeadBlockCipher, int keysize, int ivsize, aeadBlockCipher.reset(); fail(aeadBlockCipher.getAlgorithmName() + " need to be initialed before reset"); } - catch (IllegalArgumentException e) + catch (IllegalStateException e) { //expected } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/RSABlindedTest.java b/core/src/test/java/org/bouncycastle/crypto/test/RSABlindedTest.java index 27a9aeb449..9327710476 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/RSABlindedTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/RSABlindedTest.java @@ -1,5 +1,8 @@ package org.bouncycastle.crypto.test; +import java.math.BigInteger; +import java.security.SecureRandom; + import org.bouncycastle.crypto.AsymmetricBlockCipher; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.InvalidCipherTextException; @@ -13,9 +16,6 @@ import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; -import java.math.BigInteger; -import java.security.SecureRandom; - public class RSABlindedTest extends SimpleTest { @@ -426,6 +426,29 @@ public void performTest() { // expected } + + // null public exponent + privParameters = new RSAPrivateCrtKeyParameters(mod, null, privExp, p, q, pExp, qExp, crtCoef); + + RSABlindedEngine bEng = new RSABlindedEngine(); + + bEng.init(true, privParameters); + + bEng.processBlock(new byte[]{ 1 }, 0, 1); + + privParameters = new RSAPrivateCrtKeyParameters(mod, null, null, p, q, pExp, qExp, crtCoef); + + bEng.init(true, privParameters); + + try + { + bEng.processBlock(new byte[]{1}, 0, 1); + fail("no exception"); + } + catch (IllegalStateException e) + { + // ignore - expected. + } } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/RSADigestSignerTest.java b/core/src/test/java/org/bouncycastle/crypto/test/RSADigestSignerTest.java index 717807e2f7..0ef078e966 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/RSADigestSignerTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/RSADigestSignerTest.java @@ -2,15 +2,25 @@ import java.math.BigInteger; +import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.DigestInfo; import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import org.bouncycastle.crypto.CryptoException; import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.Signer; +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; @@ -46,12 +56,13 @@ public void performTest() throws Exception 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); - checkNullDigest(rsaPublic, rsaPrivate, new SHA1Digest(), X509ObjectIdentifiers.id_SHA1); + checkDigest(rsaPublic, rsaPrivate, new RIPEMD128Digest(), TeleTrusTObjectIdentifiers.ripemd128); + checkDigest(rsaPublic, rsaPrivate, new RIPEMD160Digest(), TeleTrusTObjectIdentifiers.ripemd160); + checkDigest(rsaPublic, rsaPrivate, new RIPEMD256Digest(), TeleTrusTObjectIdentifiers.ripemd256); + checkDigest(rsaPublic, rsaPrivate, new SHA1Digest(), X509ObjectIdentifiers.id_SHA1); checkDigest(rsaPublic, rsaPrivate, new SHA224Digest(), NISTObjectIdentifiers.id_sha224); checkDigest(rsaPublic, rsaPrivate, SHA256Digest.newInstance(), NISTObjectIdentifiers.id_sha256); - checkNullDigest(rsaPublic, rsaPrivate, SHA256Digest.newInstance(), 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); @@ -62,12 +73,17 @@ public void performTest() throws Exception checkDigest(rsaPublic, rsaPrivate, new SHA3Digest(384), NISTObjectIdentifiers.id_sha3_384); checkDigest(rsaPublic, rsaPrivate, new SHA3Digest(512), NISTObjectIdentifiers.id_sha3_512); + checkDigest(rsaPublic, rsaPrivate, new MD2Digest(), PKCSObjectIdentifiers.md2); + checkDigest(rsaPublic, rsaPrivate, new MD4Digest(), PKCSObjectIdentifiers.md4); + checkDigest(rsaPublic, rsaPrivate, new MD5Digest(), PKCSObjectIdentifiers.md5); + + checkNullDigest(rsaPublic, rsaPrivate, new SHA1Digest(), X509ObjectIdentifiers.id_SHA1); + checkNullDigest(rsaPublic, rsaPrivate, SHA256Digest.newInstance(), NISTObjectIdentifiers.id_sha256); + // Null format test - RSADigestSigner signer = new RSADigestSigner(new NullDigest()); - + RSADigestSigner signer = createPrehashSigner(); signer.init(true, rsaPrivate); - - signer.update(new byte[16], 0, 16); + signer.update(new byte[20], 0, 20); try { @@ -76,7 +92,7 @@ public void performTest() throws Exception } catch (CryptoException e) { - isTrue(e.getMessage().startsWith("unable to encode signature: malformed DigestInfo")); + isTrue(e.getMessage().startsWith("unable to encode signature: ")); } } @@ -104,14 +120,14 @@ private void checkNullDigest(RSAKeyParameters rsaPublic, RSAPrivateCrtKeyParamet { byte[] msg = new byte[] { 1, 6, 3, 32, 7, 43, 2, 5, 7, 78, 4, 23 }; - RSADigestSigner signer = new RSADigestSigner(new NullDigest()); + RSADigestSigner signer = createPrehashSigner(); byte[] hash = new byte[digest.getDigestSize()]; digest.update(msg, 0, msg.length); digest.doFinal(hash, 0); DigestInfo digInfo = new DigestInfo(new AlgorithmIdentifier(digOid, DERNull.INSTANCE), hash); - byte[] infoEnc = digInfo.getEncoded(); + byte[] infoEnc = digInfo.getEncoded(ASN1Encoding.DER); signer.init(true, rsaPrivate); @@ -127,7 +143,7 @@ private void checkNullDigest(RSAKeyParameters rsaPublic, RSAPrivateCrtKeyParamet fail("NONE - RSA Digest Signer failed."); } - signer = new RSADigestSigner(new NullDigest()); + signer = createPrehashSigner(); signer.init(false, rsaPublic); signer.update(infoEnc, 0, infoEnc.length); if (!signer.verifySignature(sig)) @@ -140,4 +156,9 @@ public static void main(String[] args) { runTest(new RSADigestSignerTest()); } + + private static RSADigestSigner createPrehashSigner() + { + return new RSADigestSigner(new NullDigest()); + } } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java b/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java index c945e3154a..ea18403483 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/RegressionTest.java @@ -195,6 +195,9 @@ public class RegressionTest new SparkleTest(), new ISAPTest(), new ConcatenationKDFTest(), + new GiftCofbTest(), + new RomulusTest(), + new SAKKEKEMSTest(), }; public static void main(String[] args) diff --git a/core/src/test/java/org/bouncycastle/crypto/test/RomulusTest.java b/core/src/test/java/org/bouncycastle/crypto/test/RomulusTest.java new file mode 100644 index 0000000000..d94318812f --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/test/RomulusTest.java @@ -0,0 +1,265 @@ +package org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import org.bouncycastle.crypto.CipherKeyGenerator; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.KeyGenerationParameters; +import org.bouncycastle.crypto.digests.RomulusDigest; +import org.bouncycastle.crypto.engines.RomulusEngine; +import org.bouncycastle.crypto.modes.AEADCipher; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.crypto.params.ParametersWithIV; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.test.SimpleTest; + +public class RomulusTest + extends SimpleTest +{ + /** + * Data length. + */ + private static final int DATALEN = 1025; + + /** + * AEAD length. + */ + private static final int AEADLEN = 10; + + + /** + * Check cipher. + * + * @param pCipher the cipher + */ + private static void checkCipher(final AEADCipher pCipher, + final int pNonceLen) + throws Exception + { + try + { + /* Obtain some random data */ + final byte[] myData = new byte[DATALEN]; + final SecureRandom myRandom = new SecureRandom(); + myRandom.nextBytes(myData); + + /* Obtain some random AEAD */ + final byte[] myAEAD = new byte[AEADLEN]; + myRandom.nextBytes(myAEAD); + + /* Create the Key parameters */ + final CipherKeyGenerator myGenerator = new CipherKeyGenerator(); + final KeyGenerationParameters myGenParams = new KeyGenerationParameters(myRandom, 128); + myGenerator.init(myGenParams); + final byte[] myKey = myGenerator.generateKey(); + final KeyParameter myKeyParams = new KeyParameter(myKey); + + /* Create the nonce */ + final byte[] myNonce = new byte[pNonceLen]; + myRandom.nextBytes(myNonce); + final ParametersWithIV myParams = new ParametersWithIV(myKeyParams, myNonce); + + /* Initialise the cipher for encryption */ + pCipher.init(true, myParams); + final int myMaxOutLen = pCipher.getOutputSize(DATALEN); + final byte[] myEncrypted = new byte[myMaxOutLen]; + //pCipher.processAADBytes(myAEAD, 0, AEADLEN); + int myOutLen = pCipher.processBytes(myData, 0, DATALEN, myEncrypted, 0); + int myRemaining = pCipher.getOutputSize(0); + if (myRemaining + myOutLen < myMaxOutLen) + { + // + // FAILS HERE */ + // + System.out.println("Bad outputLength on encryption for " + pCipher.getAlgorithmName()); + } + int myProcessed = pCipher.doFinal(myEncrypted, myOutLen); + if (myOutLen + myProcessed != myMaxOutLen) + { + System.out.println("Bad total on encryption for " + pCipher.getAlgorithmName()); + } + + /* Note that myOutLen is too large by DATALEN */ + + /* Initialise the cipher for decryption */ + pCipher.init(false, myParams); + final int myMaxClearLen = pCipher.getOutputSize(myMaxOutLen); + final byte[] myDecrypted = new byte[myMaxClearLen]; + //pCipher.processAADBytes(myAEAD, 0, AEADLEN); + int myClearLen = pCipher.processBytes(myEncrypted, 0, myEncrypted.length, myDecrypted, 0); + myRemaining = pCipher.getOutputSize(0); + if (myRemaining + myClearLen < myMaxClearLen) + { + System.out.println("Bad outputLength on decryption for " + pCipher.getAlgorithmName()); + } + myProcessed = pCipher.doFinal(myDecrypted, myClearLen); + if (myClearLen + myProcessed != myMaxClearLen) + { + System.out.println("Bad total on decryption for " + pCipher.getAlgorithmName()); + } + final byte[] myResult = Arrays.copyOf(myDecrypted, DATALEN); + + /* Check that we have the same result */ + if (!Arrays.areEqual(myData, myResult)) + { + System.out.println("Cipher " + pCipher.getAlgorithmName() + " failed"); + } + } + catch (InvalidCipherTextException e) + { + throw new RuntimeException(e); + } + } + + public String getName() + { + return "Romulus"; + } + + public void performTest() + throws Exception + { + checkCipher(new RomulusEngine(RomulusEngine.RomulusParameters.RomulusM), 16); + DigestTest.implTestVectorsDigest(this, new RomulusDigest(), "crypto/romulus", "LWC_HASH_KAT_256.txt"); + DigestTest.checkDigestReset(this, new RomulusDigest()); + DigestTest.implTestExceptionsAndParametersDigest(this, new RomulusDigest(), 32); + + CipherTest.implTestVectorsEngine(new RomulusEngine(RomulusEngine.RomulusParameters.RomulusM), "crypto/romulus", "m_LWC_AEAD_KAT_128_128.txt", this); + CipherTest.implTestVectorsEngine(new RomulusEngine(RomulusEngine.RomulusParameters.RomulusT), "crypto/romulus", "t_LWC_AEAD_KAT_128_128.txt", this); + CipherTest.implTestVectorsEngine(new RomulusEngine(RomulusEngine.RomulusParameters.RomulusN), "crypto/romulus", "n_LWC_AEAD_KAT_128_128.txt", this); + + //TODO: StreamDataOperator does not suit for implTestBufferingEngine +// CipherTest.implTestBufferingEngine(16, 16, 128, this, new CipherTest.Instance() +// { +// @Override +// public AEADCipher createInstance() +// { +// return new RomulusEngine(RomulusEngine.RomulusParameters.RomulusM); +// } +// }); + CipherTest.implTestBufferingEngine(16, 16, 128, this, new CipherTest.Instance() + { + @Override + public AEADCipher createInstance() + { + return new RomulusEngine(RomulusEngine.RomulusParameters.RomulusT); + } + }); + CipherTest.implTestBufferingEngine(16, 16, 128, this, new CipherTest.Instance() + { + @Override + public AEADCipher createInstance() + { + return new RomulusEngine(RomulusEngine.RomulusParameters.RomulusN); + } + }); + //TODO: StreamDataOperator does not suit for implTestExceptionsEngine +// CipherTest.implTestExceptionsEngine(16, 16, this, new CipherTest.Instance() +// { +// @Override +// public AEADCipher createInstance() +// { +// return new RomulusEngine(RomulusEngine.RomulusParameters.RomulusM); +// } +// }); + CipherTest.implTestExceptionsEngine(16, 16, this, new CipherTest.Instance() + { + @Override + public AEADCipher createInstance() + { + return new RomulusEngine(RomulusEngine.RomulusParameters.RomulusT); + } + }); + CipherTest.implTestExceptionsEngine(16, 16, this, new CipherTest.Instance() + { + @Override + public AEADCipher createInstance() + { + return new RomulusEngine(RomulusEngine.RomulusParameters.RomulusN); + } + }); + implTestParametersEngine(new RomulusEngine(RomulusEngine.RomulusParameters.RomulusM), 16, 16, 16); + implTestParametersEngine(new RomulusEngine(RomulusEngine.RomulusParameters.RomulusT), 16, 16, 16); + implTestParametersEngine(new RomulusEngine(RomulusEngine.RomulusParameters.RomulusN), 16, 16, 16); + CipherTest.checkAEADParemeter(this, 16, 16, 16, 16, new RomulusEngine(RomulusEngine.RomulusParameters.RomulusM)); + CipherTest.checkAEADParemeter(this, 16, 16, 16, 16, new RomulusEngine(RomulusEngine.RomulusParameters.RomulusT)); + CipherTest.checkAEADParemeter(this, 16, 16, 16, 16, new RomulusEngine(RomulusEngine.RomulusParameters.RomulusN)); + CipherTest.testOverlapping(this, 16, 16, 16, 16, new RomulusEngine(RomulusEngine.RomulusParameters.RomulusM)); + CipherTest.testOverlapping(this, 16, 16, 16, 16, new RomulusEngine(RomulusEngine.RomulusParameters.RomulusT)); + CipherTest.testOverlapping(this, 16, 16, 16, 16, new RomulusEngine(RomulusEngine.RomulusParameters.RomulusN)); + CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 33, 16, 128, 16, new RomulusEngine(RomulusEngine.RomulusParameters.RomulusM)); + CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 33, 16, 128, 16, new RomulusEngine(RomulusEngine.RomulusParameters.RomulusT)); + CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 33, 16, 128, 16, new RomulusEngine(RomulusEngine.RomulusParameters.RomulusN)); + + CipherTest.checkCipher(16, 16, 40, 128, new CipherTest.Instance() + { + public AEADCipher createInstance() + { + return new RomulusEngine(RomulusEngine.RomulusParameters.RomulusM); + } + }); + CipherTest.checkCipher(16, 16, 40, 128, new CipherTest.Instance() + { + public AEADCipher createInstance() + { + return new RomulusEngine(RomulusEngine.RomulusParameters.RomulusT); + } + }); + + CipherTest.checkCipher(16, 16, 40, 128, new CipherTest.Instance() + { + public AEADCipher createInstance() + { + return new RomulusEngine(RomulusEngine.RomulusParameters.RomulusN); + } + }); + +// RomulusEngine romulus = new RomulusEngine(RomulusEngine.RomulusParameters.RomulusT); +// testExceptions(romulus, romulus.getKeyBytesSize(), romulus.getIVBytesSize(), romulus.getBlockSize()); +// romulus = new RomulusEngine(RomulusEngine.RomulusParameters.RomulusM); +// testExceptions(romulus, romulus.getKeyBytesSize(), romulus.getIVBytesSize(), romulus.getBlockSize()); +// romulus = new RomulusEngine(RomulusEngine.RomulusParameters.RomulusN); +// testExceptions(romulus, romulus.getKeyBytesSize(), romulus.getIVBytesSize(), romulus.getBlockSize()); +// testExceptions(new RomulusDigest(), 32); +// //testVectorsHash(); +// testVectors(RomulusEngine.RomulusParameters.RomulusT, "t"); +// testVectors(RomulusEngine.RomulusParameters.RomulusM, "m"); +// testVectors(RomulusEngine.RomulusParameters.RomulusN, "n"); + } + + private void implTestParametersEngine(RomulusEngine cipher, int keySize, int ivSize, + int macSize) + { + if (cipher.getKeyBytesSize() != keySize) + { + fail("key bytes of " + cipher.getAlgorithmName() + " is not correct"); + } + if (cipher.getIVBytesSize() != ivSize) + { + fail("iv bytes of " + cipher.getAlgorithmName() + " is not correct"); + } + + CipherParameters parameters = new ParametersWithIV(new KeyParameter(new byte[keySize]), new byte[ivSize]); + + cipher.init(true, parameters); + if (cipher.getOutputSize(0) != macSize) + { + fail("getOutputSize of " + cipher.getAlgorithmName() + " is incorrect for encryption"); + } + + cipher.init(false, parameters); + if (cipher.getOutputSize(macSize) != 0) + { + fail("getOutputSize of " + cipher.getAlgorithmName() + " is incorrect for decryption"); + } + } + +// public static void main(String[] args) +// { +// runTest(new RomulusTest()); +// } +} + + + diff --git a/core/src/test/java/org/bouncycastle/crypto/test/SAKKEKEMSTest.java b/core/src/test/java/org/bouncycastle/crypto/test/SAKKEKEMSTest.java new file mode 100644 index 0000000000..d21555274d --- /dev/null +++ b/core/src/test/java/org/bouncycastle/crypto/test/SAKKEKEMSTest.java @@ -0,0 +1,175 @@ +package org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.crypto.SecretWithEncapsulation; +import org.bouncycastle.crypto.kems.SAKKEKEMExtractor; +import org.bouncycastle.crypto.kems.SAKKEKEMSGenerator; +import org.bouncycastle.crypto.params.SAKKEPrivateKeyParameters; +import org.bouncycastle.crypto.params.SAKKEPublicKeyParameters; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.test.FixedSecureRandom; +import org.bouncycastle.util.test.SimpleTest; + +public class SAKKEKEMSTest + extends SimpleTest +{ + public static void main(String[] args) + throws Exception + { + SAKKEKEMSTest test = new SAKKEKEMSTest(); + test.performTest(); + } + + + @Override + public String getName() + { + return "SAKKE-KEMS Test"; + } + + @Override + public void performTest() + throws Exception + { + testTestVector(); + for (int i = 0; i < 1; ++i) + { + testRandom(); + } + } + + private void testTestVector() + { + final BigInteger Px = new BigInteger( + "53FC09EE332C29AD0A7990053ED9B52A2B1A2FD60AEC69C698B2F204B6FF7CBF" + + "B5EDB6C0F6CE2308AB10DB9030B09E1043D5F22CDB9DFA55718BD9E7406CE890" + + "9760AF765DD5BCCB337C86548B72F2E1A702C3397A60DE74A7C1514DBA66910D" + + "D5CFB4CC80728D87EE9163A5B63F73EC80EC46C4967E0979880DC8ABEAE63895", 16 + ); + + final BigInteger Py = new BigInteger( + "0A8249063F6009F1F9F1F0533634A135D3E82016029906963D778D821E141178" + + "F5EA69F4654EC2B9E7F7F5E5F0DE55F66B598CCF9A140B2E416CFF0CA9E032B9" + + "70DAE117AD547C6CCAD696B5B7652FE0AC6F1E80164AA989492D979FC5A4D5F2" + + "13515AD7E9CB99A980BDAD5AD5BB4636ADB9B5706A67DCDE75573FD71BEF16D7", 16 + ); + BigInteger g = new BigInteger(Hex.decode("66FC2A43 2B6EA392 148F1586 7D623068" + + " C6A87BD1 FB94C41E 27FABE65 8E015A87" + + " 371E9474 4C96FEDA 449AE956 3F8BC446" + + " CBFDA85D 5D00EF57 7072DA8F 541721BE" + + " EE0FAED1 828EAB90 B99DFB01 38C78433" + + " 55DF0460 B4A9FD74 B4F1A32B CAFA1FFA" + + " D682C033 A7942BCC E3720F20 B9B7B040" + + " 3C8CAE87 B7A0042A CDE0FAB3 6461EA46")); + BigInteger z = new BigInteger("AFF429D35F84B110D094803B3595A6E2998BC99F", 16); + BigInteger Zx = new BigInteger(Hex.decode("5958EF1B1679BF099B3A030DF255AA6A23C1D8F143D4D23F753E69BD27A832F38CB4AD53DDEF" + + "4260B0FE8BB45C4C1FF510EFFE300367A37B61F701D914AEF09724825FA0707D61A6DFF4FBD7273566CDDE352A0B04B7C16A78309BE" + + "640697DE747613A5FC195E8B9F328852A579DB8F99B1D0034479EA9C5595F47C4B2F54FF2")); + BigInteger Zy = new BigInteger(Hex.decode("1508D37514DCF7A8E143A6058C09A6BF2C9858CA37C258065AE6BF7532BC8B5B63383866E075" + + "3C5AC0E72709F8445F2E6178E065857E0EDA10F68206B63505ED87E534FB2831FF957FB7DC619DAE61301EEACC2FDA3680EA499925" + + "8A833CEA8FC67C6D19487FB449059F26CC8AAB655AB58B7CC796E24E9A394095754F5F8BAE")); + BigInteger q = new BigInteger(Hex.decode("265EAEC7 C2958FF6 99718466 36B4195E" + + " 905B0338 672D2098 6FA6B8D6 2CF8068B" + + " BD02AAC9 F8BF03C6 C8A1CC35 4C69672C" + + " 39E46CE7 FDF22286 4D5B49FD 2999A9B4" + + " 389B1921 CC9AD335 144AB173 595A0738" + + " 6DABFD2A 0C614AA0 A9F3CF14 870F026A" + + " A7E535AB D5A5C7C7 FF38FA08 E2615F6C" + + " 203177C4 2B1EB3A1 D99B601E BFAA17FB")); +// + byte[] b = Hex.decode("323031312D30320074656C3A2B34343737303039303031323300"); + + byte[] ssv = Hex.decode("123456789ABCDEF0123456789ABCDEF0"); + byte[] expectedR = Hex.decode("13EE3E1B8DAC5DB168B1CEB32F0566A4C273693F78BAFFA2A2EE6A686E6BD90F8206CCAB84E7F" + + "42ED39BD4FB131012ECCA2ECD2119414560C17CAB46B956A80F58A3302EB3E2C9A228FBA7ED34D8ACA2392DA1FFB0B17B2320AE09AAEDF" + + "D0235F6FE0EB65337A63F9CC97728B8E5AD0460FADE144369AA5B2166213247712096"); + + BigInteger kbx = new BigInteger("93AF67E5007BA6E6A80DA793DA300FA4" + + "B52D0A74E25E6E7B2B3D6EE9D18A9B5C" + + "5023597BD82D8062D34019563BA1D25C" + + "0DC56B7B979D74AA50F29FBF11CC2C93" + + "F5DFCA615E609279F6175CEADB00B58C" + + "6BEE1E7A2A47C4F0C456F05259A6FA94" + + "A634A40DAE1DF593D4FECF688D5FC678" + + "BE7EFC6DF3D6835325B83B2C6E69036B", 16); + + BigInteger kby = new BigInteger("155F0A27241094B04BFB0BDFAC6C670A" + + "65C325D39A069F03659D44CA27D3BE8D" + + "F311172B554160181CBE94A2A783320C" + + "ED590BC42644702CF371271E496BF20F" + + "588B78A1BC01ECBB6559934BDD2FB65D" + + "2884318A33D1A42ADF5E33CC5800280B" + + "28356497F87135BAB9612A1726042440" + + "9AC15FEE996B744C332151235DECB0F5", 16); +// BigInteger w = new BigInteger(Hex.decode("7D2A8438 E6291C64 9B6579EB 3B79EAE9" + +// "48B1DE9E 5F7D1F40 70A08F8D B6B3C515" + +// "6F2201AF FBB5CB9D 82AA3EC0 D0398B89" + +// "ABC78A13 A760C0BF 3F77E63D 0DF3F1A3" + +// "41A41B88 11DF197F D6CD0F00 3125606F" + +// "4F109F40 0F7292A1 0D255E3C 0EBCCB42" + +// "53FB182C 68F09CF6 CD9C4A53 DA6C74AD" + +// "007AF36B 8BCA979D 5895E282 F483FCD6")); +// BigInteger Rbx = new BigInteger(Hex.decode("44E8AD44 AB8592A6 A5A3DDCA 5CF896C7" + +// "18043606 A01D650D EF37A01F 37C228C3" + +// "32FC3173 54E2C274 D4DAF8AD 001054C7" + +// "6CE57971 C6F4486D 57230432 61C506EB" + +// "F5BE438F 53DE04F0 67C776E0 DD3B71A6" + +// "29013328 3725A532 F21AF145 126DC1D7" + +// "77ECC27B E50835BD 28098B8A 73D9F801" + +// "D893793A 41FF5C49 B87E79F2 BE4D56CE")); +// BigInteger Rby = new BigInteger(Hex.decode("557E134A D85BB1D4 B9CE4F8B E4B08A12" + +// "BABF55B1 D6F1D7A6 38019EA2 8E15AB1C" + +// "9F76375F DD1210D4 F4351B9A 009486B7" + +// "F3ED46C9 65DED2D8 0DADE4F3 8C6721D5" + +// "2C3AD103 A10EBD29 59248B4E F006836B" + +// "F097448E 6107C9ED EE9FB704 823DF199" + +// "F832C905 AE45F8A2 47A072D8 EF729EAB" + +// "C5E27574 B07739B3 4BE74A53 2F747B86")); + BigInteger p = new BigInteger( + "997ABB1F0A563FDA65C61198DAD0657A416C0CE19CB48261BE9AE358B3E01A2E" + + "F40AAB27E2FC0F1B228730D531A59CB0E791B39FF7C88A19356D27F4A666A6D0" + + "E26C6487326B4CD4512AC5CD65681CE1B6AFF4A831852A82A7CF3C521C3C09AA" + + "9F94D6AF56971F1FFCE3E82389857DB080C5DF10AC7ACE87666D807AFEA85FEB", 16 + ); + ECCurve.Fp curve = new ECCurve.Fp( + p, // Prime p + BigInteger.valueOf(-3).mod(p), // a = -3 + BigInteger.ZERO, // , + g,// Order of the subgroup (from RFC 6509) + BigInteger.ONE // Cofactor = 1 + ); + ECPoint P = curve.createPoint(Px, Py); + + ECPoint computed_Z = P.multiply(z).normalize(); + isTrue(computed_Z.equals(curve.createPoint(Zx, Zy))); + + SecureRandom random = new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(ssv)}); + SAKKEPublicKeyParameters b_publicKey = new SAKKEPublicKeyParameters(new BigInteger(b), curve.createPoint(Zx, Zy)); + SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(random); + SecretWithEncapsulation rlt = generator.generateEncapsulated(b_publicKey); + + + SAKKEKEMExtractor extractor = new SAKKEKEMExtractor(new SAKKEPrivateKeyParameters(z, b_publicKey)); + byte[] test = extractor.extractSecret(rlt.getEncapsulation()); + isTrue(Arrays.areEqual(test, ssv)); + } + + private void testRandom() + { + SecureRandom random = new SecureRandom(); + byte[] ssv = new byte[16]; + random.nextBytes(ssv); + SAKKEPrivateKeyParameters b_priv = new SAKKEPrivateKeyParameters(random); + SAKKEPublicKeyParameters b_pub = b_priv.getPublicParams(); + SAKKEKEMSGenerator generator = new SAKKEKEMSGenerator(new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(ssv)})); + SecretWithEncapsulation rlt = generator.generateEncapsulated(b_pub); + SAKKEKEMExtractor extractor = new SAKKEKEMExtractor(b_priv); + byte[] test = extractor.extractSecret(rlt.getEncapsulation()); + isTrue(Arrays.areEqual(test, ssv)); + } +} diff --git a/core/src/test/java/org/bouncycastle/crypto/test/SHA3DigestTest.java b/core/src/test/java/org/bouncycastle/crypto/test/SHA3DigestTest.java index be30e23830..60a57542d1 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/SHA3DigestTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/SHA3DigestTest.java @@ -7,18 +7,35 @@ import java.util.ArrayList; import java.util.List; +import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA3Digest; import org.bouncycastle.test.TestResourceFinder; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Exceptions; import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.test.SimpleTest; /** * SHA3 Digest Test */ public class SHA3DigestTest - extends SimpleTest + extends DigestTest { + private static String[] messages = + { + "", + "a", + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + }; + + private static String[] digests = + { + "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", + "80084bf2fba02475726feb2cab2d8215eab14bc6bdd8bfb2c8151257032ecd8b", + "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", + "41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376" + }; + static class MySHA3Digest extends SHA3Digest { MySHA3Digest(int bitLength) @@ -34,6 +51,7 @@ int myDoFinal(byte[] out, int outOff, byte partialByte, int partialBits) SHA3DigestTest() { + super(new SHA3Digest(), messages, digests); } public String getName() @@ -41,9 +59,28 @@ public String getName() return "SHA-3"; } - public void performTest() throws Exception + public void performTest() + { + super.performTest(); + + try + { + testVectors(); + } + catch (Exception e) + { + throw Exceptions.illegalStateException(e.toString(), e); + } + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA3Digest((SHA3Digest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) { - testVectors(); + return new SHA3Digest(encodedState); } public void testVectors() throws Exception diff --git a/core/src/test/java/org/bouncycastle/crypto/test/SHAKEDigestTest.java b/core/src/test/java/org/bouncycastle/crypto/test/SHAKEDigestTest.java index 9af19cf516..138921ecef 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/SHAKEDigestTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/SHAKEDigestTest.java @@ -7,18 +7,35 @@ import java.util.ArrayList; import java.util.List; +import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHAKEDigest; import org.bouncycastle.test.TestResourceFinder; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Exceptions; import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.test.SimpleTest; /** * SHAKE Digest Test */ public class SHAKEDigestTest - extends SimpleTest + extends DigestTest { + private static String[] messages = + { + "", + "a", + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + }; + + private static String[] digests = + { + "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26", + "85c8de88d28866bf0868090b3961162bf82392f690d9e4730910f4af7c6ab3ee", + "5881092dd818bf5cf8a3ddb793fbcba74097d5c526a6d35f97b83351940f2cc8", + "1a96182b50fb8c7e74e0a707788f55e98209b8d91fade8f32f8dd5cff7bf21f5" + }; + static class MySHAKEDigest extends SHAKEDigest { MySHAKEDigest(int bitLength) @@ -34,6 +51,7 @@ int myDoFinal(byte[] out, int outOff, int outLen, byte partialByte, int partialB SHAKEDigestTest() { + super(new SHAKEDigest(), messages, digests); } public String getName() @@ -41,9 +59,28 @@ public String getName() return "SHAKE"; } - public void performTest() throws Exception + public void performTest() + { + super.performTest(); + + try + { + testVectors(); + } + catch (Exception e) + { + throw Exceptions.illegalStateException(e.toString(), e); + } + } + + protected Digest cloneDigest(Digest digest) + { + return new SHAKEDigest((SHAKEDigest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) { - testVectors(); + return new SHAKEDigest(encodedState); } public void testVectors() throws Exception diff --git a/core/src/test/java/org/bouncycastle/crypto/test/SM4Test.java b/core/src/test/java/org/bouncycastle/crypto/test/SM4Test.java index 680f2ad80c..a297b6071a 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/SM4Test.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/SM4Test.java @@ -5,7 +5,9 @@ import org.bouncycastle.crypto.engines.SM4Engine; import org.bouncycastle.crypto.modes.AEADBlockCipher; import org.bouncycastle.crypto.modes.CCMBlockCipher; +import org.bouncycastle.crypto.modes.CCMModeCipher; import org.bouncycastle.crypto.modes.GCMBlockCipher; +import org.bouncycastle.crypto.modes.GCMModeCipher; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.util.encoders.Hex; @@ -91,8 +93,8 @@ private void gcmTest() + "A56834CBCF98C397B4024A2691233B8D"); byte[] tag = Hex.decode("83DE3541E4C2B58177E065A9BF7B62EC"); - GCMBlockCipher encCipher = new GCMBlockCipher(new SM4Engine()); - GCMBlockCipher decCipher = new GCMBlockCipher(new SM4Engine()); + GCMModeCipher encCipher = GCMBlockCipher.newInstance(new SM4Engine()); + GCMModeCipher decCipher = GCMBlockCipher.newInstance(new SM4Engine()); checkTestCase(encCipher, decCipher, "1", key, iv, aad, pt, ct, tag); } @@ -113,8 +115,8 @@ private void ccmTest() + "ED31A2F04476C18BB40C84A74B97DC5B"); byte[] tag = Hex.decode("fe26a58f94552a8d533b5b6b261c9cd8"); - CCMBlockCipher encCipher = new CCMBlockCipher(new SM4Engine()); - CCMBlockCipher decCipher = new CCMBlockCipher(new SM4Engine()); + CCMModeCipher encCipher = CCMBlockCipher.newInstance(new SM4Engine()); + CCMModeCipher decCipher = CCMBlockCipher.newInstance(new SM4Engine()); checkTestCase(encCipher, decCipher, "2", key, iv, aad, pt, ct, tag); } diff --git a/core/src/test/java/org/bouncycastle/crypto/test/SparkleTest.java b/core/src/test/java/org/bouncycastle/crypto/test/SparkleTest.java index 6dda9f40eb..ab76af8a2a 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/SparkleTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/SparkleTest.java @@ -49,7 +49,6 @@ public void performTest() testExceptionsDigest_ESCH256(); testExceptionsDigest_ESCH384(); ; - testExceptionsEngine_SCHWAEMM128_128(); testExceptionsEngine_SCHWAEMM192_192(); testExceptionsEngine_SCHWAEMM256_128(); @@ -71,6 +70,11 @@ public void performTest() CipherTest.checkAEADParemeter(this, 16, 32, 16, 16, new SparkleEngine(SparkleEngine.SparkleParameters.SCHWAEMM256_128)); CipherTest.checkAEADParemeter(this, 32, 32, 32, 32, new SparkleEngine(SparkleEngine.SparkleParameters.SCHWAEMM256_256)); + CipherTest.testOverlapping(this, 16, 16, 16, 16, new SparkleEngine(SparkleEngine.SparkleParameters.SCHWAEMM128_128)); + CipherTest.testOverlapping(this, 24, 24, 24, 24, new SparkleEngine(SparkleEngine.SparkleParameters.SCHWAEMM192_192)); + CipherTest.testOverlapping(this, 16, 32, 16, 16, new SparkleEngine(SparkleEngine.SparkleParameters.SCHWAEMM256_128)); + CipherTest.testOverlapping(this, 32, 32, 32, 32, new SparkleEngine(SparkleEngine.SparkleParameters.SCHWAEMM256_256)); + CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 33, 16, 128, 16, new SparkleEngine(SparkleEngine.SparkleParameters.SCHWAEMM128_128)); CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 33, 24, 192, 24, new SparkleEngine(SparkleEngine.SparkleParameters.SCHWAEMM192_192)); CipherTest.checkAEADCipherMultipleBlocks(this, 1025, 33, 16, 128, 32, new SparkleEngine(SparkleEngine.SparkleParameters.SCHWAEMM256_128)); diff --git a/core/src/test/java/org/bouncycastle/crypto/test/TupleHashTest.java b/core/src/test/java/org/bouncycastle/crypto/test/TupleHashTest.java index 0ed9d3d1c4..4cd6acaef0 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/TupleHashTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/TupleHashTest.java @@ -5,7 +5,6 @@ import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.test.SimpleTest; /** * TupleHash test vectors from: @@ -13,16 +12,38 @@ * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf */ public class TupleHashTest - extends SimpleTest + extends DigestTest { + private static String[] messages = + { + "", + "a", + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + }; + + private static String[] digests = + { + "549330469327c593eb95b1d467c48e5781939e135e10632c804ef8a69c73281c", + "98e1cb3104a046dcdc77a6acbee4177553ba15cb0235a3db99f506198dc9c8b5", + "873195cadfea6bc6a71cdd903da87afb49fd232d71db817c3abcad48ad8a7898", + "b9588fbf7302809815ebd989d00752f732a08dc9b1153b6f3a097f518cdc44ea" + }; + + public TupleHashTest() + { + super(new TupleHash(128, new byte[0]), messages, digests); + } + public String getName() { return "TupleHash"; } public void performTest() - throws Exception { + super.performTest(); + TupleHash tHash = new TupleHash(128, new byte[0]); tHash.update(Hex.decode("000102"), 0, 3); @@ -105,6 +126,16 @@ public void performTest() testClone(); } + protected Digest cloneDigest(Digest digest) + { + return new TupleHash((TupleHash)digest); + } + + protected Digest cloneDigest(byte[] state) + { + return new TupleHash(state); + } + private void testClone() { Digest digest = new TupleHash(256, Strings.toByteArray("My Tuple App")); diff --git a/core/src/test/java/org/bouncycastle/crypto/test/XoodyakTest.java b/core/src/test/java/org/bouncycastle/crypto/test/XoodyakTest.java index 1d19639d99..37bb098399 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/XoodyakTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/XoodyakTest.java @@ -33,6 +33,9 @@ public String getName() public void performTest() throws Exception { + DigestTest.implTestVectorsDigest(this, new XoodyakDigest(), "crypto/xoodyak", "LWC_HASH_KAT_256.txt"); + DigestTest.checkDigestReset(this, new XoodyakDigest()); + DigestTest.implTestExceptionsAndParametersDigest(this, new XoodyakDigest(), 32); CipherTest.checkAEADCipherMultipleBlocks(this, 1024, 18, 100, 128, 16, new XoodyakEngine()); testVectors(); CipherTest.checkCipher(32, 16, 100, 128, new CipherTest.Instance() @@ -43,8 +46,6 @@ public AEADCipher createInstance() return new XoodyakEngine(); } }); - DigestTest.checkDigestReset(this, new XoodyakDigest()); - testVectorsHash(); XoodyakEngine xoodyak = new XoodyakEngine(); testExceptions(xoodyak, xoodyak.getKeyBytesSize(), xoodyak.getIVBytesSize(), xoodyak.getBlockSize()); @@ -52,47 +53,7 @@ public AEADCipher createInstance() testExceptions(new XoodyakDigest(), 32); CipherTest.checkAEADCipherOutputSize(this, 16, 16, 24, 16, new XoodyakEngine()); CipherTest.checkAEADParemeter(this, 16, 16, 16, 24, new XoodyakEngine()); - } - - private void testVectorsHash() - throws Exception - { - XoodyakDigest xoodyak = new XoodyakDigest(); - InputStream src = TestResourceFinder.findTestResource("crypto/xoodyak", "LWC_HASH_KAT_256.txt"); - BufferedReader bin = new BufferedReader(new InputStreamReader(src)); - String line; - byte[] ptByte; - HashMap map = new HashMap(); - while ((line = bin.readLine()) != null) - { - int a = line.indexOf('='); - if (a < 0) - { -// if (!map.get("Count").equals("18")) -// { -// continue; -// } - xoodyak.reset(); - ptByte = Hex.decode((String)map.get("Msg")); - xoodyak.update(ptByte, 0, ptByte.length); - byte[] hash = new byte[32]; - xoodyak.doFinal(hash, 0); - if (!areEqual(hash, Hex.decode((String)map.get("MD")))) - { - mismatch("Keystream " + map.get("Count"), (String)map.get("MD"), hash); - } -// else -// { -// System.out.println("Keystream " + map.get("Count") + " pass"); -// } - map.clear(); - } - else - { - map.put(line.substring(0, a).trim(), line.substring(a + 1).trim()); - } - } -// System.out.println("Xoodyak Hash pass"); + CipherTest.testOverlapping(this, 16, 16, 16, 24, new XoodyakEngine()); } private void testVectors() @@ -187,7 +148,7 @@ private void testExceptions(AEADCipher aeadBlockCipher, int keysize, int ivsize, aeadBlockCipher.reset(); fail(aeadBlockCipher.getAlgorithmName() + " need to be initialed before reset"); } - catch (IllegalArgumentException e) + catch (IllegalStateException e) { //expected } @@ -301,6 +262,7 @@ private void testExceptions(AEADCipher aeadBlockCipher, int keysize, int ivsize, } aeadBlockCipher.reset(); + aeadBlockCipher.init(true, params); try { aeadBlockCipher.processAADBytes(new byte[]{0}, 1, 1); diff --git a/core/src/test/java/org/bouncycastle/crypto/test/speedy/MacThroughputTest.java b/core/src/test/java/org/bouncycastle/crypto/test/speedy/MacThroughputTest.java index 81401c3966..09df661763 100644 --- a/core/src/test/java/org/bouncycastle/crypto/test/speedy/MacThroughputTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/test/speedy/MacThroughputTest.java @@ -60,7 +60,7 @@ public static void main(String[] args) testMac(new SkeinMac(SkeinMac.SKEIN_512, 128), new KeyParameter(generateNonce(64)), 2); testMac(new SipHash(), new KeyParameter(generateNonce(16)), 1); testMac(new CMac(AESEngine.newInstance()), new KeyParameter(generateNonce(16)), 3); - testMac(new GMac(new GCMBlockCipher(AESEngine.newInstance())), new ParametersWithIV(new KeyParameter( + testMac(new GMac(GCMBlockCipher.newInstance(AESEngine.newInstance())), new ParametersWithIV(new KeyParameter( generateNonce(16)), generateNonce(16)), 5); testMac(new Poly1305(new NullEngine(16)), new ParametersWithIV(generatePoly1305Key(), generateNonce(16)), 1); testMac(new Poly1305(AESEngine.newInstance()), new ParametersWithIV(generatePoly1305Key(), generateNonce(16)), 1); diff --git a/core/src/test/java/org/bouncycastle/crypto/threshold/test/ShamirSecretSplitterTest.java b/core/src/test/java/org/bouncycastle/crypto/threshold/test/ShamirSecretSplitterTest.java index cd81bda2a4..ae13341922 100644 --- a/core/src/test/java/org/bouncycastle/crypto/threshold/test/ShamirSecretSplitterTest.java +++ b/core/src/test/java/org/bouncycastle/crypto/threshold/test/ShamirSecretSplitterTest.java @@ -19,7 +19,12 @@ public static void main(String[] args) throws IOException { ShamirSecretSplitterTest test = new ShamirSecretSplitterTest(); + for (int i = 0; i < 1000; ++i) + { + test.testShamirSecretMultipleDivide(); + } test.performTest(); + System.out.println("OK"); } public void performTest() @@ -77,7 +82,7 @@ public void testShamirSecretMultipleDivide() ShamirSplitSecret splitSecret1 = new ShamirSplitSecret(algorithm, mode, secretShares1); byte[] secret1 = splitSecret1.getSecret(); - int mul = random.nextInt(255); + int mul = random.nextInt(254) + 1; splitSecret.multiple(mul); secretShares = (ShamirSplitSecretShare[])splitSecret.getSecretShares(); ShamirSplitSecretShare[] secretShares4 = new ShamirSplitSecretShare[]{secretShares[1], secretShares[2], secretShares[5]}; @@ -89,7 +94,6 @@ public void testShamirSecretMultipleDivide() ShamirSplitSecretShare[] secretShares2 = new ShamirSplitSecretShare[]{secretShares[4], secretShares[7], secretShares[8]}; ShamirSplitSecret splitSecret2 = new ShamirSplitSecret(algorithm, mode, secretShares2); byte[] secret2 = splitSecret2.getSecret(); - assertTrue(Arrays.areEqual(secret1, secret2)); @@ -966,7 +970,7 @@ public ShamirSplitSecret newInstance(ShamirSplitSecretShare[] secretShares) @Override public ShamirSecretSplitter newInstance(int l, int m, int n, SecureRandom random) { - return new ShamirSecretSplitter(ShamirSecretSplitter.Algorithm.AES, ShamirSecretSplitter.Mode.Table, l, random); + return new ShamirSecretSplitter(ShamirSecretSplitter.Algorithm.AES, ShamirSecretSplitter.Mode.Table, l, random); } @Override @@ -996,7 +1000,7 @@ public ShamirSplitSecret newInstance(ShamirSplitSecretShare[] secretShares) @Override public ShamirSecretSplitter newInstance(int l, int m, int n, SecureRandom random) { - return new ShamirSecretSplitter(ShamirSecretSplitter.Algorithm.RSA, ShamirSecretSplitter.Mode.Table, l,random); + return new ShamirSecretSplitter(ShamirSecretSplitter.Algorithm.RSA, ShamirSecretSplitter.Mode.Table, l, random); } @Override diff --git a/core/src/test/java/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java b/core/src/test/java/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java index 9be8d3ea7b..2d9eaa4ded 100644 --- a/core/src/test/java/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java +++ b/core/src/test/java/org/bouncycastle/math/ec/test/ECPointPerformanceTest.java @@ -76,7 +76,7 @@ private void randMult(String label, X9ECParameters spec) throws Exception double avgRate = randMult(random, g, n); String coordName = COORD_NAMES[coord]; - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(" "); sb.append(defaultCoord ? '*' : ' '); sb.append(coordName); diff --git a/core/src/test/java/org/bouncycastle/math/ec/test/F2mProofer.java b/core/src/test/java/org/bouncycastle/math/ec/test/F2mProofer.java index b687520337..9dec0b2b51 100644 --- a/core/src/test/java/org/bouncycastle/math/ec/test/F2mProofer.java +++ b/core/src/test/java/org/bouncycastle/math/ec/test/F2mProofer.java @@ -40,7 +40,7 @@ private String pointToString(ECPoint.F2m p) int m = x.getM(); int len = m / 2 + 5; - StringBuffer sb = new StringBuffer(len); + StringBuilder sb = new StringBuilder(len); sb.append('('); sb.append(x.toBigInteger().toString(16)); sb.append(", "); diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/lms/HSSTests.java b/core/src/test/java/org/bouncycastle/pqc/crypto/lms/HSSTests.java index 2ececd90d2..20abf0cfa6 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/lms/HSSTests.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/lms/HSSTests.java @@ -115,7 +115,7 @@ private List loadVector(String vector) BufferedReader bin = new BufferedReader(new InputStreamReader(inputStream)); String line; List blocks = new ArrayList(); - StringBuffer sw = new StringBuffer(); + StringBuilder sw = new StringBuilder(); while ((line = bin.readLine()) != null) { if (line.startsWith("!")) diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/AllTests.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/AllTests.java index 08a3b0e5b4..221427954b 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/AllTests.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/AllTests.java @@ -4,6 +4,7 @@ import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; + import org.bouncycastle.test.PrintTestResult; import org.bouncycastle.util.test.SimpleTestResult; @@ -46,12 +47,11 @@ public static Test suite() suite.addTestSuite(SNTRUPrimeTest.class); suite.addTestSuite(BIKETest.class); suite.addTestSuite(HQCTest.class); - suite.addTestSuite(RainbowVectorTest.class); - suite.addTestSuite(GeMSSTest.class); suite.addTestSuite(XWingTest.class); suite.addTestSuite(AllTests.SimpleTestTest.class); suite.addTestSuite(SLHDSATest.class); - + suite.addTestSuite(MayoTest.class); + suite.addTestSuite(SnovaTest.class); return new BCTestSetup(suite); } diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/BIKETest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/BIKETest.java index f1ca00279a..f5f433eda6 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/BIKETest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/BIKETest.java @@ -4,7 +4,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; -import java.util.Random; import junit.framework.TestCase; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; @@ -52,7 +51,6 @@ public void testVectors() BIKEParameters.bike256 }; - TestSampler sampler = new TestSampler(); for (int fileIndex = 0; fileIndex < files.length; fileIndex++) { String name = files[fileIndex]; @@ -62,8 +60,7 @@ public void testVectors() String line = null; HashMap buf = new HashMap(); - Random rnd = new Random(System.currentTimeMillis()); - + TestSampler sampler = new TestSampler(); while ((line = bin.readLine()) != null) { line = line.trim(); diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/CMCEVectorTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/CMCEVectorTest.java index b5f4ef3480..92f6525b74 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/CMCEVectorTest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/CMCEVectorTest.java @@ -71,16 +71,16 @@ public void testVectors() CMCEParameters.mceliece8192128fr3 }; - TestSampler sampler = new TestSampler(); for (int fileIndex = 0; fileIndex != files.length; fileIndex++) { String name = files[fileIndex]; - // System.out.println("testing: " + name); + InputStream src = TestResourceFinder.findTestResource("pqc/crypto/cmce", name); BufferedReader bin = new BufferedReader(new InputStreamReader(src)); String line = null; HashMap buf = new HashMap(); + TestSampler sampler = new TestSampler(); while ((line = bin.readLine()) != null) { line = line.trim(); diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/CrystalsDilithiumTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/CrystalsDilithiumTest.java index ef8a6dd383..c50a69b206 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/CrystalsDilithiumTest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/CrystalsDilithiumTest.java @@ -42,16 +42,16 @@ public void testKeyGen() throws IOException DilithiumParameters.dilithium5, }; - TestSampler sampler = new TestSampler(); for (int fileIndex = 0; fileIndex != files.length; fileIndex++) { String name = files[fileIndex]; - // System.out.println("testing: " + name); + InputStream src = TestResourceFinder.findTestResource("pqc/crypto/dilithium/acvp", name); BufferedReader bin = new BufferedReader(new InputStreamReader(src)); String line = null; HashMap buf = new HashMap(); + TestSampler sampler = new TestSampler(); while ((line = bin.readLine()) != null) { line = line.trim(); @@ -115,16 +115,16 @@ public void testSigGen() throws IOException DilithiumParameters.dilithium5, }; - TestSampler sampler = new TestSampler(); for (int fileIndex = 0; fileIndex != files.length; fileIndex++) { String name = files[fileIndex]; - // System.out.println("testing: " + name); + InputStream src = TestResourceFinder.findTestResource("pqc/crypto/dilithium/acvp", name); BufferedReader bin = new BufferedReader(new InputStreamReader(src)); String line = null; HashMap buf = new HashMap(); + TestSampler sampler = new TestSampler(); while ((line = bin.readLine()) != null) { line = line.trim(); @@ -194,16 +194,16 @@ public void testSigVer() throws IOException DilithiumParameters.dilithium5, }; - TestSampler sampler = new TestSampler(); for (int fileIndex = 0; fileIndex != files.length; fileIndex++) { String name = files[fileIndex]; - // System.out.println("testing: " + name); + InputStream src = TestResourceFinder.findTestResource("pqc/crypto/dilithium/acvp", name); BufferedReader bin = new BufferedReader(new InputStreamReader(src)); String line = null; HashMap buf = new HashMap(); + TestSampler sampler = new TestSampler(); while ((line = bin.readLine()) != null) { line = line.trim(); diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/FalconTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/FalconTest.java index 5126132033..efc6335926 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/FalconTest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/FalconTest.java @@ -39,16 +39,16 @@ public void testVectors() FalconParameters.falcon_1024 }; - TestSampler sampler = new TestSampler(); - for (int fileindex = 0; fileindex < files.length; fileindex++) { String name = files[fileindex]; - // System.out.println("testing: " + name); + InputStream src = TestResourceFinder.findTestResource("pqc/crypto/falcon", name); BufferedReader bin = new BufferedReader(new InputStreamReader(src)); + String line = null; HashMap buf = new HashMap(); + TestSampler sampler = new TestSampler(); while ((line = bin.readLine()) != null) { line = line.trim(); @@ -141,34 +141,42 @@ public void testVectors() // System.out.println("testing successful!"); } } - - public void testFalconRandom() - { - byte[] msg = Strings.toByteArray("Hello World!"); - FalconKeyPairGenerator keyGen = new FalconKeyPairGenerator(); + public void testRandom() + throws Exception + { SecureRandom random = new SecureRandom(); + byte[] msg = Strings.toByteArray("Hello World!"); + FalconKeyPairGenerator keyGen = new FalconKeyPairGenerator(); keyGen.init(new FalconKeyGenerationParameters(random, FalconParameters.falcon_512)); - for (int i = 0; i != 100; i++) + for (int i = 0; i < 10; ++i) { AsymmetricCipherKeyPair keyPair = keyGen.generateKeyPair(); - // sign - FalconSigner signer = new FalconSigner(); - FalconPrivateKeyParameters skparam = (FalconPrivateKeyParameters)keyPair.getPrivate(); - ParametersWithRandom skwrand = new ParametersWithRandom(skparam, random); - signer.init(true, skwrand); - - byte[] sigGenerated = signer.generateSignature(msg); + FalconPrivateKeyParameters privParams = (FalconPrivateKeyParameters)keyPair.getPrivate(); + FalconPublicKeyParameters pubParams = (FalconPublicKeyParameters)keyPair.getPublic(); - // verify - FalconSigner verifier = new FalconSigner(); - FalconPublicKeyParameters pkparam = (FalconPublicKeyParameters)keyPair.getPublic(); - verifier.init(false, pkparam); + privParams = (FalconPrivateKeyParameters)PrivateKeyFactory.createKey( + PrivateKeyInfoFactory.createPrivateKeyInfo(privParams)); + pubParams = (FalconPublicKeyParameters)PublicKeyFactory.createKey( + SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(pubParams)); + + for (int j = 0; j < 10; ++j) + { + // sign + FalconSigner signer = new FalconSigner(); + signer.init(true, new ParametersWithRandom(privParams, random)); + byte[] signature = signer.generateSignature(msg); + + // verify + FalconSigner verifier = new FalconSigner(); + verifier.init(false, pubParams); + boolean verified = verifier.verifySignature(msg, signature); - assertTrue("count = " + i, verifier.verifySignature(msg, sigGenerated)); + assertTrue("count = " + i, verified); + } } } } diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/FrodoVectorTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/FrodoVectorTest.java index 1e6c6d7ef6..3d0b7031b6 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/FrodoVectorTest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/FrodoVectorTest.java @@ -58,16 +58,16 @@ public void testVectors() FrodoParameters.frodokem1344shake }; - TestSampler sampler = new TestSampler(); for (int fileIndex = 0; fileIndex != files.length; fileIndex++) { String name = files[fileIndex]; - // System.out.println("testing: " + name); + InputStream src = TestResourceFinder.findTestResource("pqc/crypto/frodo", name); BufferedReader bin = new BufferedReader(new InputStreamReader(src)); String line = null; HashMap buf = new HashMap(); + TestSampler sampler = new TestSampler(); while ((line = bin.readLine()) != null) { line = line.trim(); diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/GeMSSTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/GeMSSTest.java deleted file mode 100644 index ad405dca88..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/GeMSSTest.java +++ /dev/null @@ -1,180 +0,0 @@ -package org.bouncycastle.pqc.crypto.test; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Random; - -import junit.framework.TestCase; -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.gemss.GeMSSKeyGenerationParameters; -import org.bouncycastle.pqc.crypto.gemss.GeMSSKeyPairGenerator; -import org.bouncycastle.pqc.crypto.gemss.GeMSSParameters; -import org.bouncycastle.pqc.crypto.gemss.GeMSSPrivateKeyParameters; -import org.bouncycastle.pqc.crypto.gemss.GeMSSPublicKeyParameters; -import org.bouncycastle.pqc.crypto.gemss.GeMSSSigner; -import org.bouncycastle.test.TestResourceFinder; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.encoders.Hex; - -public class GeMSSTest - extends TestCase -{ - //TODO: MQSOFT_REF - public void testVectors() - throws Exception - { - - String files = "dualmodems256.rsp fgemss256.rsp dualmodems192.rsp fgemss192.rsp fgemss128.rsp dualmodems128.rsp " + - "redgemss128.rsp bluegemss128.rsp gemss128.rsp cyangemss128.rsp whitegemss128.rsp magentagemss128.rsp " + - "bluegemss192.rsp gemss192.rsp redgemss192.rsp whitegemss192.rsp cyangemss192.rsp magentagemss192.rsp " + - "cyangemss256.rsp bluegemss256.rsp whitegemss256.rsp redgemss256.rsp magentagemss256.rsp gemss256.rsp"; - - TestSampler sampler = new TestSampler(); - - Random rd = new Random(System.currentTimeMillis()); - - int offSet = rd.nextInt(10); - - String[] fileList = splitOn(files, ' '); - for (int i = 0; i < fileList.length; i++) - { - String name = fileList[i]; - InputStream src = TestResourceFinder.findTestResource("pqc/crypto/gemss", name); - BufferedReader bin = new BufferedReader(new InputStreamReader(src)); - String testcase = name.replace(".rsp", ""); - // System.out.println("Testing on " + testcase); - String line = null; - HashMap buf = new HashMap(); - while ((line = bin.readLine()) != null) - { - line = line.trim(); - - if (line.startsWith("#")) - { - continue; - } - if (line.length() == 0) - { - if (buf.size() > 0) - { - String count = (String)buf.get("count"); - byte[] sk = Hex.decode((String)buf.get("sk")); - byte[] pk = Hex.decode((String)buf.get("pk")); - byte[] msg = Hex.decode((String)buf.get("msg")); - byte[] sigExpected = Hex.decode((String)buf.get("sm")); - byte[] seed = Hex.decode((String)buf.get("seed")); - - if (Integer.parseInt(count) != offSet) - { - continue; - } -// if (sampler.skipTest(count)) -// { -// continue; -// } - - GeMSSKeyPairGenerator kpGen = new GeMSSKeyPairGenerator(); - SecureRandom random = new NISTSecureRandom(seed, null); - - GeMSSParameters parameters = (GeMSSParameters)GeMSSParameters.class.getField(testcase).get(null);// -// StringBuffer b = new StringBuffer(); -// b.append("_"); - //parameters = (GeMSSParameters)GeMSSParameters.class.getField(b.toString()).get(null); - // - // Generate keys and test. - // - kpGen.init(new GeMSSKeyGenerationParameters(random, parameters)); - AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); - //// System.out.println("Key generation complete for case " + buf.get("count")); - //GeMSSPublicKeyParameters pubParams =new GeMSSPublicKeyParameters(parameters, pk); - GeMSSPublicKeyParameters pubParams = (GeMSSPublicKeyParameters)kp.getPublic(); - GeMSSPrivateKeyParameters privParams = (GeMSSPrivateKeyParameters)kp.getPrivate(); - - byte[] PK = pubParams.getPK(); - byte[] SK = privParams.getEncoded(); -// for (i = 0; i < sk.length; ++i) -// { -// if (sk[i] != SK[i]) -// { -// // System.out.println(i + " " + sk[i] + " " + SK[i]); -// } -// } -// for (i = 0; i < pk.length; ++i) -// { -// if (pk[i] != PK[i]) -// { -// // System.out.println(i + " " + pk[i] + " " + PK[i]); -// } -// } - assertTrue(name + " " + count + ": public key", Arrays.areEqual(pk, pubParams.getEncoded())); - assertTrue(name + " " + count + ": secret key", Arrays.areEqual(sk, privParams.getEncoded())); -// assertTrue(name + " " + count + ": public key", Arrays.areEqual(Arrays.concatenate(pubParams.getParameters().getEncoded(), pk), pubParams.getEncoded())); -// assertTrue(name + " " + count + ": secret key", Arrays.areEqual(Arrays.concatenate(privParams.getParameters().getEncoded(), sk), privParams.getEncoded())); - // - // Signature test - // - GeMSSSigner signer = new GeMSSSigner(); - ParametersWithRandom skwrand = new ParametersWithRandom(kp.getPrivate(), random); - signer.init(true, skwrand); - byte[] sigGenerated = signer.generateSignature(msg); - //// System.out.println("Sig generation complete for case " + buf.get("count")); - signer.init(false, pubParams); -// for (i = 0; i < sigGenerated.length; ++i) -// { -// if (sigExpected[i] != sigGenerated[i]) -// { -// // System.out.println(i + " " + sigExpected[i] + " " + sigGenerated[i]); -// } -// } - assertTrue(name + " " + count + ": signature verify", signer.verifySignature(msg, Arrays.copyOfRange(sigExpected, 0, sigGenerated.length))); - //assertTrue(name + " " + count + ": signature verify", signer.verifySignature(msg, sigExpected)); - assertTrue(name + " " + count + ": signature gen match", Arrays.areEqual(sigExpected, sigGenerated)); - // System.out.println(testcase + " case " + buf.get("count") + " pass"); -// System.err.println(Hex.toHexString(sigExpected)); -// System.err.println(Hex.toHexString(attachedSig)); - //assertTrue(name + " " + count + ": signature gen match", Arrays.areEqual(sigExpected, attachedSig)); - - } - buf.clear(); - - continue; - } - - int a = line.indexOf("="); - if (a > -1) - { - buf.put(line.substring(0, a).trim(), line.substring(a + 1).trim()); - } - } - src.close(); - } - //System.err.println(System.currentTimeMillis() - startTime); - } - - private static String[] splitOn(String input, char c) - { - String s = input.trim(); - List l = new ArrayList(); - - int idx = s.indexOf(c); - while (idx > 0) - { - l.add(s.substring(0, idx)); - s = s.substring(idx + 1).trim(); - idx = s.indexOf(c); - } - - if (s.length() > 0) - { - l.add(s); - } - - return (String[])l.toArray(new String[0]); - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/HQCTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/HQCTest.java index e9cb95fe2b..963d14d39e 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/HQCTest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/HQCTest.java @@ -1,14 +1,13 @@ package org.bouncycastle.pqc.crypto.test; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.HashMap; -import java.util.Random; +import java.security.SecureRandom; import junit.framework.TestCase; -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.SecretWithEncapsulation; +import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import org.bouncycastle.crypto.EncapsulatedSecretExtractor; +import org.bouncycastle.crypto.EncapsulatedSecretGenerator; +import org.bouncycastle.crypto.digests.SHAKEDigest; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.pqc.crypto.hqc.HQCKEMExtractor; import org.bouncycastle.pqc.crypto.hqc.HQCKEMGenerator; import org.bouncycastle.pqc.crypto.hqc.HQCKeyGenerationParameters; @@ -16,18 +15,17 @@ import org.bouncycastle.pqc.crypto.hqc.HQCParameters; import org.bouncycastle.pqc.crypto.hqc.HQCPrivateKeyParameters; import org.bouncycastle.pqc.crypto.hqc.HQCPublicKeyParameters; -import org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; -import org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory; -import org.bouncycastle.pqc.crypto.util.PublicKeyFactory; -import org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory; -import org.bouncycastle.test.TestResourceFinder; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.encoders.Hex; -import org.bouncycastle.util.test.FixedSecureRandom; public class HQCTest extends TestCase { + public static void main(String[] args) + throws Exception + { + HQCTest test = new HQCTest(); + test.testVectors(); + } + @Override public String getName() { @@ -42,100 +40,84 @@ public void testVectors() String[] files; // test cases files = new String[]{ - "HQC-128.rsp", - "HQC-192.rsp", - "HQC-256.rsp", + "PQCkemKAT_2321.rsp", + "PQCkemKAT_4602.rsp", + "PQCkemKAT_7333.rsp", }; - HQCParameters[] listParams = new HQCParameters[]{ + final HQCParameters[] listParams = new HQCParameters[]{ HQCParameters.hqc128, HQCParameters.hqc192, HQCParameters.hqc256 }; - TestSampler sampler = new TestSampler(); - for (int fileIndex = 0; fileIndex < files.length; fileIndex++) + TestUtils.testTestVector(true, true, "pqc/crypto/hqc", files, new TestUtils.KeyEncapsulationOperation() { - // System.out.println("Working Directory = " + System.getProperty("user.dir")); - String name = files[fileIndex]; - // System.out.println("testing: " + name); - InputStream src = TestResourceFinder.findTestResource("pqc/crypto/hqc", name); - BufferedReader bin = new BufferedReader(new InputStreamReader(src)); + int sessionKeySize = 0; - String line = null; - HashMap buf = new HashMap(); - Random rnd = new Random(System.currentTimeMillis()); + @Override + public SecureRandom getSecureRandom(byte[] seed) + { + return new Shake256SecureRandom(seed); + } + + @Override + public AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int fileIndex, SecureRandom random) + { + HQCParameters parameters = listParams[fileIndex]; + sessionKeySize = parameters.getSessionKeySize(); + HQCKeyPairGenerator hqcKeyGen = new HQCKeyPairGenerator(); + HQCKeyGenerationParameters genParam = new HQCKeyGenerationParameters(random, parameters); + hqcKeyGen.init(genParam); + return hqcKeyGen; + } + + @Override + public byte[] getPublicKeyEncoded(AsymmetricKeyParameter pubParams) + { + return ((HQCPublicKeyParameters)pubParams).getPublicKey(); + } + + @Override + public byte[] getPrivateKeyEncoded(AsymmetricKeyParameter privParams) + { + return ((HQCPrivateKeyParameters)privParams).getPrivateKey(); + } - while ((line = bin.readLine()) != null) + @Override + public EncapsulatedSecretGenerator getKEMGenerator(SecureRandom random) { - line = line.trim(); - - if (line.startsWith("#")) - { - continue; - } - if (line.length() == 0) - { - if (buf.size() > 0) - { - String count = (String)buf.get("count"); - if (sampler.skipTest(count)) - { - continue; - } - // System.out.println("test case: " + count); - - byte[] seed = Hex.decode((String)buf.get("seed")); // seed for bike secure random - byte[] pk = Hex.decode((String)buf.get("pk")); // public key - byte[] sk = Hex.decode((String)buf.get("sk")); // private key - byte[] ct = Hex.decode((String)buf.get("ct")); // ciphertext - byte[] ss = Hex.decode((String)buf.get("ss")); // session key - - HQCParameters parameters = listParams[fileIndex]; - - HQCKeyPairGenerator hqcKeyGen = new HQCKeyPairGenerator(); - HQCKeyGenerationParameters genParam = new HQCKeyGenerationParameters(new FixedSecureRandom(seed), parameters); - - // - // Generate keys and test. - // - - // KEM Keypair - hqcKeyGen.init(genParam); - AsymmetricCipherKeyPair pair = hqcKeyGen.generateKeyPair(); - - HQCPublicKeyParameters generatedPk = (HQCPublicKeyParameters)PublicKeyFactory.createKey(SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo((HQCPublicKeyParameters)pair.getPublic())); - HQCPrivateKeyParameters generatedSk = (HQCPrivateKeyParameters)PrivateKeyFactory.createKey(PrivateKeyInfoFactory.createPrivateKeyInfo((HQCPrivateKeyParameters)pair.getPrivate())); - - assertTrue(name + " " + count + ": public key", Arrays.areEqual(pk, generatedPk.getPublicKey())); - assertTrue(name + " " + count + ": secret key", Arrays.areEqual(sk, generatedSk.getPrivateKey())); - - // KEM Encapsulation - HQCKEMGenerator hqcKemGenerator = new HQCKEMGenerator(new FixedSecureRandom(seed)); - SecretWithEncapsulation secretWithEnc = hqcKemGenerator.generateEncapsulated(generatedPk); - byte[] secret = secretWithEnc.getSecret(); - byte[] c = secretWithEnc.getEncapsulation(); - - assertTrue(name + " " + count + ": ciphertext", Arrays.areEqual(c, ct)); - assertTrue(name + " " + count + ": kem_dec ss", Arrays.areEqual(secret, 0, secret.length, ss, 0, secret.length)); - - // KEM Decapsulation - HQCKEMExtractor bikekemExtractor = new HQCKEMExtractor(generatedSk); - byte[] dec_key = bikekemExtractor.extractSecret(c); - - assertEquals(parameters.getSessionKeySize(), secret.length * 8); - assertTrue(name + " " + count + ": kem_dec key", Arrays.areEqual(dec_key, secret)); - } - buf.clear(); - continue; - } - int a = line.indexOf("="); - if (a > -1) - { - buf.put(line.substring(0, a).trim(), line.substring(a + 1).trim()); - } + return new HQCKEMGenerator(random); } - // System.out.println("Testing successful!"); + + @Override + public EncapsulatedSecretExtractor getKEMExtractor(AsymmetricKeyParameter privParams) + { + return new HQCKEMExtractor((HQCPrivateKeyParameters)privParams); + } + + @Override + public int getSessionKeySize() + { + return sessionKeySize; + } + }); + } + + private static class Shake256SecureRandom + extends SecureRandom + { + private final SHAKEDigest digest = new SHAKEDigest(256); + + Shake256SecureRandom(byte[] seed) + { + digest.update(seed, 0, seed.length); + digest.update((byte) 0); + } + + public void nextBytes(byte[] bytes) + { + digest.doOutput(bytes, 0, bytes.length); } } } diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/MLDSATest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/MLDSATest.java index f177d5b219..b8d6c0c540 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/MLDSATest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/MLDSATest.java @@ -5,12 +5,19 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.security.SecureRandom; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import junit.framework.TestCase; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.CryptoException; +import org.bouncycastle.crypto.Signer; import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.pqc.crypto.mldsa.HashMLDSASigner; import org.bouncycastle.pqc.crypto.mldsa.MLDSAKeyGenerationParameters; import org.bouncycastle.pqc.crypto.mldsa.MLDSAKeyPairGenerator; import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters; @@ -35,6 +42,9 @@ public class MLDSATest put("ML-DSA-44", MLDSAParameters.ml_dsa_44); put("ML-DSA-65", MLDSAParameters.ml_dsa_65); put("ML-DSA-87", MLDSAParameters.ml_dsa_87); + put("ML-DSA-44-WITH-SHA512", MLDSAParameters.ml_dsa_44_with_sha512); + put("ML-DSA-65-WITH-SHA512", MLDSAParameters.ml_dsa_65_with_sha512); + put("ML-DSA-87-WITH-SHA512", MLDSAParameters.ml_dsa_87_with_sha512); } }; @@ -43,9 +53,13 @@ public class MLDSATest MLDSAParameters.ml_dsa_44, MLDSAParameters.ml_dsa_65, MLDSAParameters.ml_dsa_87, + MLDSAParameters.ml_dsa_44_with_sha512, + MLDSAParameters.ml_dsa_65_with_sha512, + MLDSAParameters.ml_dsa_87_with_sha512, }; - public void testConsistency() throws Exception + public void testConsistency() + throws Exception { SecureRandom random = new SecureRandom(); @@ -65,7 +79,7 @@ public void testConsistency() throws Exception { AsymmetricCipherKeyPair kp = kpg.generateKeyPair(); - MLDSASigner signer = new MLDSASigner(); + Signer signer = parameters.isPreHash() ? (Signer)new HashMLDSASigner() : (Signer)new MLDSASigner(); for (int j = 0; j < 2; ++j) { @@ -462,7 +476,284 @@ public void testSigVerCombinedVectorSet() } } - private class InternalMLDSASigner + public void testMLDSARejection() + throws Exception + { + rejectionExternalMuTest(MLDSAParameters.ml_dsa_44, "dilithium_external_mu_rejection_vectors_44.h"); + rejectionExternalMuTest(MLDSAParameters.ml_dsa_65, "dilithium_external_mu_rejection_vectors_65.h"); + rejectionExternalMuTest(MLDSAParameters.ml_dsa_87, "dilithium_external_mu_rejection_vectors_87.h"); + // TODO: rejection vectors based on non-compliant hash - SHA-512 is currently the only one accepted +// rejectionPrehashTest(MLDSAParameters.ml_dsa_44, "dilithium_prehash_rejection_vectors_44.h"); +// rejectionPrehashTest(MLDSAParameters.ml_dsa_65, "dilithium_prehash_rejection_vectors_65.h"); +// rejectionPrehashTest(MLDSAParameters.ml_dsa_87, "dilithium_prehash_rejection_vectors_87.h"); + rejectionTest(MLDSAParameters.ml_dsa_44, "dilithium_pure_rejection_vectors_44.h"); + rejectionTest(MLDSAParameters.ml_dsa_65, "dilithium_pure_rejection_vectors_65.h"); + rejectionTest(MLDSAParameters.ml_dsa_87, "dilithium_pure_rejection_vectors_87.h"); + rejectionUpStreamTest(MLDSAParameters.ml_dsa_44, "dilithium_rejection_upstream_vectors_44.h"); + rejectionUpStreamTest(MLDSAParameters.ml_dsa_65, "dilithium_rejection_upstream_vectors_65.h"); + rejectionUpStreamTest(MLDSAParameters.ml_dsa_87, "dilithium_rejection_upstream_vectors_87.h"); + rejectionUpStreamTest(MLDSAParameters.ml_dsa_44, "dilithium_rejection_vectors_44.h"); + rejectionUpStreamTest(MLDSAParameters.ml_dsa_65, "dilithium_rejection_vectors_65.h"); + rejectionUpStreamTest(MLDSAParameters.ml_dsa_87, "dilithium_rejection_vectors_87.h"); + } + + private interface RejectionOperation + { + byte[] processSign(MLDSAPrivateKeyParameters privParams, byte[] msg) + throws CryptoException; + boolean processVerify(MLDSAPublicKeyParameters pubParams, byte[] msg, byte[] sig); + } + + private void rejectionTest(MLDSAParameters parameters, String filename, RejectionOperation operation) + throws Exception + { + List testVectors = parseTestVectors(TestResourceFinder.findTestResource("pqc/crypto/mldsa", filename)); + for (int i = 0; i < testVectors.size(); ++i) + { + TestVector t = (TestVector)testVectors.get(i); + FixedSecureRandom random = new FixedSecureRandom(t.seed); + + MLDSAKeyPairGenerator kpGen = new MLDSAKeyPairGenerator(); + kpGen.init(new MLDSAKeyGenerationParameters(random, parameters)); + + // + // Generate keys and test. + // + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); + + MLDSAPublicKeyParameters pubParams = (MLDSAPublicKeyParameters)PublicKeyFactory.createKey( + SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(kp.getPublic())); + MLDSAPrivateKeyParameters privParams = (MLDSAPrivateKeyParameters)PrivateKeyFactory.createKey( + PrivateKeyInfoFactory.createPrivateKeyInfo(kp.getPrivate())); + + if (t.pk.length != 0) + { + assertTrue(Arrays.areEqual(t.pk, pubParams.getEncoded())); + } + if (t.sk.length != 0) + { + assertTrue(Arrays.areEqual(t.sk, privParams.getEncoded())); + } + byte[] signature = operation.processSign(privParams, t.msg); + if (t.sig.length != 0) + { + assertTrue(Arrays.areEqual(t.sig, signature)); + } + boolean shouldVerify = operation.processVerify(pubParams, t.msg, signature); + assertTrue(shouldVerify); + } + } + + private void rejectionExternalMuTest(MLDSAParameters parameters, String filename) + throws Exception + { + rejectionTest(parameters, filename, new RejectionOperation() + { + public byte[] processSign(MLDSAPrivateKeyParameters privParams, byte[] msg) + throws CryptoException + { + InternalMLDSASigner signer = new InternalMLDSASigner(); + signer.init(true, privParams); + return signer.generateMuSignature(msg); + } + + public boolean processVerify(MLDSAPublicKeyParameters pubParams, byte[] msg, byte[] sig) + { + InternalMLDSASigner signer = new InternalMLDSASigner(); + signer.init(false, pubParams); + return signer.verifyMuSignature(msg, sig); + } + }); + } + + private void rejectionPrehashTest(MLDSAParameters parameters, String filename) + throws Exception + { + rejectionTest(parameters, filename, new RejectionOperation() + { + public byte[] processSign(MLDSAPrivateKeyParameters privParams, byte[] msg) + throws CryptoException + { + HashMLDSASigner signer = new HashMLDSASigner(); + signer.init(true, privParams); + signer.update(msg, 0, msg.length); + return signer.generateSignature(); + } + + public boolean processVerify(MLDSAPublicKeyParameters pubParams, byte[] msg, byte[] sig) + { + HashMLDSASigner signer = new HashMLDSASigner(); + signer.init(false, pubParams); + signer.update(msg, 0, msg.length); + return signer.verifySignature(sig); + } + }); + } + + private void rejectionTest(MLDSAParameters parameters, String filename) + throws Exception + { + rejectionTest(parameters, filename, new RejectionOperation() + { + public byte[] processSign(MLDSAPrivateKeyParameters privParams, byte[] msg) + throws CryptoException + { + InternalMLDSASigner signer = new InternalMLDSASigner(); + + signer.init(true, privParams); + signer.update(msg, 0, msg.length); + return signer.generateSignature(); + } + + public boolean processVerify(MLDSAPublicKeyParameters pubParams, byte[] msg, byte[] sig) + { + InternalMLDSASigner signer = new InternalMLDSASigner(); + signer.init(false, pubParams); + signer.update(msg, 0, msg.length); + return signer.verifySignature(sig); + } + }); + } + + private void rejectionUpStreamTest(MLDSAParameters parameters, String filename) + throws Exception + { + rejectionTest(parameters, filename, new RejectionOperation() + { + public byte[] processSign(MLDSAPrivateKeyParameters privParams, byte[] msg) + throws CryptoException + { + InternalMLDSASigner signer = new InternalMLDSASigner(); + signer.init(true, privParams); + return signer.internalGenerateSignature(msg, new byte[32]); + } + + public boolean processVerify(MLDSAPublicKeyParameters pubParams, byte[] msg, byte[] sig) + { + InternalMLDSASigner signer = new InternalMLDSASigner(); + signer.init(false, pubParams); + signer.update(msg, 0, msg.length); + return signer.internalVerifySignature(msg, sig); + } + }); + } + + private static List parseTestVectors(InputStream src) + throws IOException + { + List vectors = new ArrayList(); + BufferedReader bin = new BufferedReader(new InputStreamReader(src)); + + TestVector currentVector = null; + String currentField = null; + List currentBytes = null; + Pattern fieldPattern = Pattern.compile("\\.(seed|pk|sk|msg|sig|key_hash|sig_hash)\\s*=\\s*\\{"); + Pattern hexPattern = Pattern.compile("0x([0-9a-fA-F]{2})"); + + String line; + while ((line = bin.readLine()) != null) + { + // Skip comments and empty lines + line = line.split("//")[0].trim(); + if (line.length() == 0) + { + continue; + } + + // Look for test vector array start + if (line.indexOf("dilithium_rejection_testvectors[] = ") >= 0) + { + continue; + } + + // Start new test vector + if (line.startsWith("{") && currentVector == null) + { + currentVector = new TestVector(); + continue; + } + + // Detect field start + Matcher fieldMatcher = fieldPattern.matcher(line); + if (fieldMatcher.find()) + { + currentField = fieldMatcher.group(1); + currentBytes = new ArrayList(); + line = line.substring(fieldMatcher.end()).trim(); + } + + // Collect hex values if in field + if (currentField != null) + { + Matcher hexMatcher = hexPattern.matcher(line); + while (hexMatcher.find()) + { + String hex = hexMatcher.group(1); + currentBytes.add(new Byte((byte)Integer.parseInt(hex, 16))); + } + + // Check for field end + if (line.indexOf("},") >= 0) + { + setField(currentVector, currentField, currentBytes); + currentField = null; + currentBytes = null; + } + continue; + } + + // End of test vector + if (line.startsWith("},") && currentVector != null) + { + vectors.add(currentVector); + currentVector = null; + } + } + + return vectors; + } + + private static void setField(TestVector vector, String field, List bytes) + { + byte[] byteArray = new byte[bytes.size()]; + for (int i = 0; i < bytes.size(); i++) + { + byteArray[i] = ((Byte)bytes.get(i)).byteValue(); + } + + if ("seed".equals(field)) + { + vector.seed = byteArray; + } + else if ("pk".equals(field)) + { + vector.pk = byteArray; + } + else if ("sk".equals(field)) + { + vector.sk = byteArray; + } + else if ("msg".equals(field)) + { + vector.msg = byteArray; + } + else if ("sig".equals(field)) + { + vector.sig = byteArray; + } + // else ignore + } + + static class TestVector + { + byte[] seed = new byte[0]; + byte[] pk = new byte[0]; + byte[] sk = new byte[0]; + byte[] msg = new byte[0]; + byte[] sig = new byte[0]; + } + + private static class InternalMLDSASigner extends MLDSASigner { public byte[] internalGenerateSignature(byte[] message, byte[] rnd) diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/MLKEMTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/MLKEMTest.java index beb3537abf..c3f312a24a 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/MLKEMTest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/MLKEMTest.java @@ -8,6 +8,7 @@ import java.util.HashMap; import java.util.Map; +import junit.framework.Assert; import junit.framework.TestCase; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; @@ -29,10 +30,16 @@ import org.bouncycastle.test.TestResourceFinder; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.test.FixedSecureRandom; public class MLKEMTest extends TestCase { + private static byte[] okayKey = Hex.decode("29F853ECE08908E99D4B7195B89C296037B786E3000CA95607D80288A62EBDB53E5AD7A4BC716AE3BC0200788D7FBA9E49D5AAAA0A46E7A6C829A7B64869C458CACDB9043D350BC920D29E1D1B8E5ED57D83132AA6119C33770A56EB64511579FF2404F4CAA6CA8026BC647EA1692143139D4B5526006C38E87C1AC88CB615B87910E75371F97376938533B9720810B63D7354CE6B726184A392D90AF5F5821179C0ED4A519C4530818788CD877027369B5C8855486C2E8DE9BD7A2835A5D0248B772DFBE26BFA4049D0BC51EDCB9C51FAAFF638CB45399B8186C12E8119D5CBBCADE116FE1ACB097C8280343A3E666F6C5B89DB1070E698185D290429107712A46A3D057233B90FBC9A475CA73D3FF2743E54CEB255AF1809209D042E54D4C099D6C3B46868CBC64F00C5B352831C28C28260E40233CA62F5DC814C0809A9653D63CB756032BD9322544A199EF6E696AB026BA2701CE4D2A13850275BDA905A05130B2CB1E7410F46523DB54646E94C508CF548190A507174CA8B481BDC14C27B9267D8F428C0F73EBA769F35398824B2C4D6C171A1CA7A9DE0A315FA75ECD477B10969956B34F5188BA290390755066BFA8FB4E9BAE097A59243CE0DC57089E022C8D52A19D03F7EB23141B51A44BC1B1C0BA52A70AA1B8A61654CC54079A3AABC4D86E3C046880CDA9BCCE3A609E6A1149DFB6931E91D743BCBCDF6A963175FB48520FFD22885D0BCC59393F487133A5A0E115A02CD6049C06C8FF4D8A221E20D3F23C905501180F878C4D52C65C5A7FD745592CC38F5266918808B730138CEE47B0914544A653DDACB729581AC7296A7A5C90009DB63EDFAA45B6086BEA186983487A0E530D069AB99A10DC2F59894A77D15A7933AF23ECD283962E778BCAB985B2BA7DA84C0E10C165500A1A93427B976516E867A94095F30D406C209126789ADBE325D652ACD09B4B104A431ED4691F7A5CD15279A36E939A80C91C6468BF73811F103CA405C93CAC493245516ABCAC7B3F90CD2F030BE6461A18818C3983B03106D2D343D88877C41B9C329CB76B7DB2720D0157A04141459032AF4017D09D47B472F4CF643436ABF8D29AC9F7E27C7D9EB181F5AC93833D930C05D3E"); + private static byte[] tooLargeKey = Hex.decode("00615CA0D7AD5C0C84A7F77A9ACA3C32E17732C42EDC46249490021B9822D06361705ABFFC28730CE741B144A27A5748DE280CD253575EA6AF87C12E9ED6029825AB2F14C482E86DBB020257A25A33F38524858DBE4305A6B13859382615C6CCF7A997085384F8F0401F63127F5358D37236D978377365023FF659B3470195C43824441DA37641931041039093B185145C8644846B57EBF3862DC41AB7E54ABD0730BCC25B369C8B86E2165C73691F1863887071A77CAFFE39B537026991153A92D90E0568729F4C568895B965B8A1030A93DBA93672C2B9C5331491F442069550E4555F085B94F9F1611A028776361A6696671207B18803BE44395C7A560BD675B94ED0C0FFC97253E58FE2FBBBAACA802BB98F5E2B3DD810AE2CA91C00088B7D3175A2A65468A872917400163337BE503BEC2A24D798CF85A6653470AA5F0635447C94E73CA0FD09A2BD104432768F239B9633DC943BD052A8934D38D408BA38B57947699DF3783871CC23A46AA871BAA096A7DE77CF4320B2AF26A40F656351F90DFEB11088E85E6E181F42475324240288F13B5DE310E07C698914B8B9355416A69219D92315B9C3421205B0698D6AE3161AD18ECC325C3BC4BDE37002C4AA128C4C4FD4EAB040831264684ACA88A0D9C4616824085CE9A3A0C37C1148B41EA6C242B77E277C4A867113D9B3920354BE976C68ABD89E76819E7C3573F79A85D9A1778DA81D871838BBB43870CB786525267FF009B21A3275B7958936BABB7020D7F832362AA95E7761B9A82FD813266C709D4AC778632298F5800079D88A447C7A6B004843831775499C62A553BCF302FB0556CCA10577F24C81A651232BC9A5E97D37FC046498BCCFC69F7E4CBF890CC4DF5AA5E76C14371C38C5A348D1303C154C11899B7E9AA34D806275D6AB0E1E7B3A0BE6B48FC21475C4B5ED3B6AAFC23ADFBB7E33E501B7545B71446BABB6680A7316C39994DA351E36D228572080DFB47E0FBC12D24A842847109700309CF47B0F338389DAC6EFF534FA2251DA7773DD6845112843B95739D8F2109A91B078BAAC3612230D77569BA22138F9AB3FA02DFACA54C943920D254550C863261C771C32F6BC643A77D9C279F08AAC3E51F90DFEB11088E85E6E181F42475324240288F13B5DE310E07C698914B8B9355416A69219D92315B9C3421205B0698D6AE3161AD18ECC325C3BC4BDE37002C4AA128C4C4FD4EAB040831264684ACA88A0D9C4616824085CE9A3A0C37C1148B41EA6C242B77E277C4A867113D9B3920354BE976C68ABD89E76819E7C3573F79A85D9A1778DA81D871838BBB43870CB786525267FF009B21A3275B7958936BABB7020D7F832362AA95E7761B9A82FD813266C709D4AC778632298F5800079D88A447C7A6B004843831775499C62A553BCF302FB0556CCA10577F24C81A651232BC9A5E97D37FC046498BCCFC69F7E4CBF890CC4DF5AA5E76C14371C38C5A348D1303C154C11899B7E9AA34D806275D6AB0E1E7B3A0BE6B48FC21475C4B5ED3B6AAFC23ADFBB7E33E501B7545B71446BABB6680A7316C39994DA351E36D228572080DFB47E0FBC12D24A842847109700309CF47B0F338389DAC6EFF534FA2251DA7773DD6845112843B95739D8F2109A91B078BAAC3612230D77569BA22138F9AB3FA02DFACA54C943920D254550C863261C771C32F6BC643A77D9C279F08AAC3E"); + + private static byte[] faultyPrivateKey = Hex.decode("F57A2F125726FF2B75F19321D55A7AA33142A1BA9B8C1A1DDF9068D4759BFDFAB942A0AA90710033846B195BA44FC1762CA26C8AC0639BC1ADC2DC0E49CC6559830AF9463401EA181FEC83BD69594E3911108A929E1C2AD0F65AD60C5DE509BE8A966FE1F3452097C0BC186F6DA467F84A4A64A7B657D06D96E1A411611D39A3726752C30E48244CD675B7AC7F993C2EF5CCC5C598123024AFD3403DAA4A1541E1A8EE797B06BA5A9A01C0D2340B0122A379FB8F1EF73D2E46117F6B6FF23468C1D43413D4B0760A49B7D6BFE0784D1A646209C719C9E66147467E940163D03A0D4106C019E743F864A809F9BFD2E8C40AD185A428B1AAEC7510ECCC039A62E2E27472F77B451A8C5BFC1AF9D3C632B006CEE13A9B6B8F3280889A0515CC54BD2D676BB930B0C440771D965E4CA92942F9705D4BA535D43D18F94957BA285C0B5BF0F40080B1B42E82446A64C3B2707ADB41954F803B72884A13EBABC2801385928FF3890607B3C60FC16155A51C20BCB3BF3ACD07559F4BA67CE349AD5BD86106D01C19E222EFF33768782BBFF10D07D42045C69F68126241C985D1E3C1E39195DC133B8E6913E17359A331706C882D82527BDC90A0C7B223B4C30537CCC986E17C09513B1FF9A026A80A9358CAFA97A0C6D65BDAF471880C5B7A69882DAA2AE5C9223024AF3AA38FDFB1960F2527F7C03AAEB24E071BB4AE7CC170B4C9A302CF6ECA4FFBC96B3A801FE643CA65605A3CE5BC0944C1E234BA9EB9C7294543064309E266108E21110C5251648BB0AB449832115DF6D5538004581B371E6C779AD3949B2E4BA041E218EB853D172341C426B0DD1C3CB1B3283F27C716C288C1CA3C6C4BAE3C8B7AFC480565B13FA13A0CED8B2C0BBC83D26C0EC81C9EA25B9663710E51A811D8E398F4BB761DD862BF30502873C04A3B412BE20C8C2819312245288AC6DF74AE1B85BA217ABE08F465B12CAFF664B3693CAA5688C05F2A2070C307DAFA7F37BBAB87F11708F04E10175A74D6ABD7D09D8A0862AC487AED60BE508B28A52B1FC394A176C6A89F68BCC2217B4B463EF631C9821B3D71216CDE75A7D8763665956670ECBAE9B13A73899ED68264E65298B0B8256B713FE62470DDD3443E103AA679B8A6B3A8D690A9A655BFD0AA0A1030C5C57A1E6419114555605D1197F45C9258C617B28983C4257B67F688087A77A0990E6D11982589BF1FD424CDF73B156896FA534530416D1AB75915B3460AA295216C362C48A2B9944D94F4A00AEB5A9991979BD9B7859C881B5B3254F59079DC2DB209CE73AAC00D945713D46A62D9013F909A7E88B925704669B5356F851A99F77181215D0A73351871C853847B7BB3715E4892FDFC9466A4C7EAA83F0A9468FBCA6684786C61607A6FA1875C6043092B3DD6D5127C92559A9157F6DC1CD999B86A096A5D1524A578CA36C667C3F092DA3AA889319669469648C4BA920B53843686A18A8246B3B5A659C936EA0D0B01147B5832214488139224F9595FDB9151AE3621E1DCAAA03213B0C36CEF674FCF0517E313CF34E2A894FC063647408D239AF66C40ABF49E88268A1BBC2CC4CABF45C11A6379CEA9D326F685ADF021969942AD4A2A324B6C9033720A55F280A01648BA614C2DE6AB110AA71F56379910CEED337A64599222888E18598078E6A2B7D4497024A0CDD0B382C371592A65BA538DC025B82361C9AF7334A8D6C259A57F3EBC4B21F01F0BE6346B2CB25EB10A41D5AA2B28255DA750BAA89C2C0982A5C2B5C2292B98E91C922848DC2036D96001BE1208C7A1C8BCF29F4CA463DFB964D07443DBBA9CF4DC7A90342DAE70C2703A9FBE324C08AA2B7C86A94E6A3D7760BD40366E1336A56D57C29225363F6A5F8E91216ED2574037B028B3A69E3C0511B08DD6E07D0BEC5A6DF0A2111AAD9AA58EFAAB4596E25099930A56809CE31A987D2A9C52702437A5A929A44478172470F75DABDAB1C6B66772B0720E2B53CF0459384A6DB94A18B621AD271881B7DBAD8AE4C330965D6CD367B96B830256233113C03191186A05B3F4D90A349CC8816642A0A55DD3D95DF8CBC999C05A48E79282BC434C7AA7A08C3BAA8C4FA686C78F8A2F99D102F75023C3FA87188429817170348A40C1350EAC679BE5158B9CF5950D4871F9EC687621196D3B420F0B6360A3A721B2B29E4988F315A52253369340BF54CB70A6F569192FA55361EE3482F39F344B5E5217A624461B9B6FA830E17A7A45D0E59D2EECE64AADF692860235678DCC2B9818B3DF268AB12B07C94C627D2C5FB929D435CA2260A6AAED"); + private static final Map parametersMap = new HashMap() { { @@ -42,6 +49,68 @@ public class MLKEMTest } }; + private final SecureRandom RANDOM = new SecureRandom(); + + public void testKeys() + { + new MLKEMPublicKeyParameters(MLKEMParameters.ml_kem_512, okayKey); + + try + { + new MLKEMPublicKeyParameters(MLKEMParameters.ml_kem_512, tooLargeKey); + fail("no exception for invalid public key"); + } + catch (IllegalArgumentException e) + { + assertEquals("'encoding' has invalid length", e.getMessage()); + } + + try + { + new MLKEMPrivateKeyParameters(MLKEMParameters.ml_kem_512, faultyPrivateKey); + fail("no exception for invalid private key"); + } + catch (IllegalArgumentException e) + { + assertEquals("'encoding' fails hash check", e.getMessage()); + } + } + + public void testInputs() + throws Exception + { + MLKEMKeyPairGenerator kpGen = new MLKEMKeyPairGenerator(); + MLKEMKeyGenerationParameters genParam = new MLKEMKeyGenerationParameters(new SecureRandom(), MLKEMParameters.ml_kem_512); + + // + // Generate keys and test. + // + kpGen.init(genParam); + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); + + MLKEMExtractor kEx = new MLKEMExtractor((MLKEMPrivateKeyParameters)kp.getPrivate()); + + try + { + kEx.extractSecret(new byte[2000]); + Assert.fail(); + } + catch (IllegalArgumentException e) + { + assertEquals("encapsulation wrong length", e.getMessage()); + } + + try + { + kEx.extractSecret(new byte[600]); + Assert.fail(); + } + catch (IllegalArgumentException e) + { + assertEquals("encapsulation wrong length", e.getMessage()); + } + } + public void testKeyGen() throws IOException { MLKEMParameters[] params = new MLKEMParameters[]{ @@ -84,13 +153,13 @@ public void testKeyGen() throws IOException MLKEMParameters parameters = params[fileIndex]; MLKEMKeyPairGenerator kpGen = new MLKEMKeyPairGenerator(); - MLKEMKeyGenerationParameters genParam = new MLKEMKeyGenerationParameters(new SecureRandom(), parameters); + MLKEMKeyGenerationParameters genParam = new MLKEMKeyGenerationParameters(new FixedSecureRandom(Arrays.concatenate(d, z)), parameters); // // Generate keys and test. // kpGen.init(genParam); - AsymmetricCipherKeyPair kp = kpGen.internalGenerateKeyPair(d, z); + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); MLKEMPublicKeyParameters pubParams = (MLKEMPublicKeyParameters)PublicKeyFactory.createKey( SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo((MLKEMPublicKeyParameters)kp.getPublic())); @@ -142,13 +211,13 @@ public void testKeyGenCombinedVectorSet() throws IOException MLKEMParameters parameters = (MLKEMParameters)parametersMap.get((String)buf.get("parameterSet")); MLKEMKeyPairGenerator kpGen = new MLKEMKeyPairGenerator(); - MLKEMKeyGenerationParameters genParam = new MLKEMKeyGenerationParameters(new SecureRandom(), parameters); + MLKEMKeyGenerationParameters genParam = new MLKEMKeyGenerationParameters(new FixedSecureRandom(Arrays.concatenate(d, z)), parameters); // // Generate keys and test. // kpGen.init(genParam); - AsymmetricCipherKeyPair kp = kpGen.internalGenerateKeyPair(d, z); + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); MLKEMPublicKeyParameters pubParams = (MLKEMPublicKeyParameters)PublicKeyFactory.createKey( SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo((MLKEMPublicKeyParameters)kp.getPublic())); @@ -223,7 +292,7 @@ public void testEncapDecap_encapsulation() throws IOException // PrivateKeyInfoFactory.createPrivateKeyInfo((MLKEMPrivateKeyParameters)privKey)); // KEM Enc - MLKEMGenerator generator = new MLKEMGenerator(new SecureRandom()); + MLKEMGenerator generator = new MLKEMGenerator(RANDOM); SecretWithEncapsulation secWenc = generator.internalGenerateEncapsulated(pubParams, m); byte[] generated_cipher_text = secWenc.getEncapsulation(); @@ -351,7 +420,7 @@ public void testEncapDecapCombinedVectorSet() throws IOException MLKEMPublicKeyParameters pubParams = (MLKEMPublicKeyParameters)PublicKeyFactory.createKey( SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo((MLKEMPublicKeyParameters)pubKey)); - MLKEMGenerator generator = new MLKEMGenerator(new SecureRandom()); + MLKEMGenerator generator = new MLKEMGenerator(RANDOM); SecretWithEncapsulation secWenc = generator.internalGenerateEncapsulated(pubParams, m); byte[] generated_cipher_text = secWenc.getEncapsulation(); byte[] secret = secWenc.getSecret(); @@ -414,20 +483,14 @@ public void testModulus() throws IOException byte[] key = Hex.decode(line); MLKEMParameters parameters = params[fileIndex]; - MLKEMPublicKeyParameters pubParams = (MLKEMPublicKeyParameters) PublicKeyFactory.createKey( - SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(new MLKEMPublicKeyParameters(parameters, key))); - - // KEM Enc - SecureRandom random = new SecureRandom(); - MLKEMGenerator generator = new MLKEMGenerator(random); try { - SecretWithEncapsulation secWenc = generator.generateEncapsulated(pubParams); - byte[] generated_cipher_text = secWenc.getEncapsulation(); + new MLKEMPublicKeyParameters(parameters, key); fail(); } - catch (Exception ignored) + catch (IllegalArgumentException e) { + assertEquals("Modulus check failed for ML-KEM public key", e.getMessage()); } } } @@ -436,14 +499,13 @@ public void testModulus() throws IOException public void testPrivInfoGeneration() throws IOException { - SecureRandom random = new SecureRandom(); PQCOtherInfoGenerator.PartyU partyU = new PQCOtherInfoGenerator.PartyU(MLKEMParameters.ml_kem_512, - new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1), Hex.decode("beef"), Hex.decode("cafe"), random); + new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1), Hex.decode("beef"), Hex.decode("cafe"), RANDOM); byte[] partA = partyU.getSuppPrivInfoPartA(); PQCOtherInfoGenerator.PartyV partyV = new PQCOtherInfoGenerator.PartyV(MLKEMParameters.ml_kem_512, - new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1), Hex.decode("beef"), Hex.decode("cafe"), random); + new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1), Hex.decode("beef"), Hex.decode("cafe"), RANDOM); byte[] partB = partyV.getSuppPrivInfoPartB(partA); @@ -461,17 +523,16 @@ public void testMLKEM() String expectedPubKey = "A04184D4BC7B532A0F70A54D7757CDE6175A6843B861CB2BC4830C0012554CFC5D2C8A2027AA3CD967130E9B96241B11C4320C7649CC23A71BAFE691AFC08E680BCEF42907000718E4EACE8DA28214197BE1C269DA9CB541E1A3CE97CFADF9C6058780FE6793DBFA8218A2760B802B8DA2AA271A38772523A76736A7A31B9D3037AD21CEBB11A472B8792EB17558B940E70883F264592C689B240BB43D5408BF446432F412F4B9A5F6865CC252A43CF40A320391555591D67561FDD05353AB6B019B3A08A73353D51B6113AB2FA51D975648EE254AF89A230504A236A4658257740BDCBBE1708AB022C3C588A410DB3B9C308A06275BDF5B4859D3A2617A295E1A22F90198BAD0166F4A943417C5B831736CB2C8580ABFDE5714B586ABEEC0A175A08BC710C7A2895DE93AC438061BF7765D0D21CD418167CAF89D1EFC3448BCBB96D69B3E010C82D15CAB6CACC6799D3639669A5B21A633C865F8593B5B7BC800262BB837A924A6C5440E4FC73B41B23092C3912F4C6BEBB4C7B4C62908B03775666C22220DF9C88823E344C7308332345C8B795D34E8C051F21F5A21C214B69841358709B1C305B32CC2C3806AE9CCD3819FFF4507FE520FBFC27199BC23BE6B9B2D2AC1717579AC769279E2A7AAC68A371A47BA3A7DBE016F14E1A727333663C4A5CD1A0F8836CF7B5C49AC51485CA60345C990E06888720003731322C5B8CD5E6907FDA1157F468FD3FC20FA8175EEC95C291A262BA8C5BE990872418930852339D88A19B37FEFA3CFE82175C224407CA414BAEB37923B4D2D83134AE154E490A9B45A0563B06C953C3301450A2176A07C614A74E3478E48509F9A60AE945A8EBC7815121D90A3B0E07091A096CF02C57B25BCA58126AD0C629CE166A7EDB4B33221A0D3F72B85D562EC698B7D0A913D73806F1C5C87B38EC003CB303A3DC51B4B35356A67826D6EDAA8FEB93B98493B2D1C11B676A6AD9506A1AAAE13A824C7C08D1C6C2C4DBA9642C76EA7F6C8264B64A23CCCA9A74635FCBF03E00F1B5722B214376790793B2C4F0A13B5C40760B4218E1D2594DCB30A70D9C1782A5DD30576FA4144BFC8416EDA8118FC6472F56A979586F33BB070FB0F1B0B10BC4897EBE01BCA3893D4E16ADB25093A7417D0708C83A26322E22E6330091E30152BF823597C04CCF4CFC7331578F43A2726CCB428289A90C863259DD180C5FF142BEF41C7717094BE07856DA2B140FA67710967356AA47DFBC8D255B4722AB86D439B7E0A6090251D2D4C1ED5F20BBE6807BF65A90B7CB2EC0102AF02809DC9AC7D0A3ABC69C18365BCFF59185F33996887746185906C0191AED4407E139446459BE29C6822717644353D24AB6339156A9C424909F0A9025BB74720779BE43F16D81C8CC666E99710D8C68BB5CC4E12F314E925A551F09CC59003A1F88103C254BB978D75F394D3540E31E771CDA36E39EC54A62B5832664D821A72F1E6AFBBA27F84295B2694C498498E812BC8E9378FE541CEC5891B25062901CB7212E3CDC46179EC5BCEC10BC0B9311DE05074290687FD6A5392671654284CD9C8CC3EBA80EB3B662EB53EB75116704A1FEB5C2D056338532868DDF24EB8992AB8565D9E490CADF14804360DAA90718EAB616BAB0765D33987B47EFB6599C5563235E61E4BE670E97955AB292D9732CB8930948AC82DF230AC72297A23679D6B94C17F1359483254FEDC2F05819F0D069A443B78E3FC6C3EF4714B05A3FCA81CBBA60242A7060CD885D8F39981BB18092B23DAA59FD9578388688A09BBA079BC809A54843A60385E2310BBCBCC0213CE3DFAAB33B47F9D6305BC95C6107813C585C4B657BF30542833B14949F573C0612AD524BAAE69590C1277B86C286571BF66B3CFF46A3858C09906A794DF4A06E9D4B0A2E43F10F72A6C6C47E5646E2C799B71C33ED2F01EEB45938EB7A4E2E2908C53558A540D350369FA189C616943F7981D7618CF02A5B0A2BCC422E857D1A47871253D08293C1C179BCDC0437069107418205FDB9856623B8CA6B694C96C084B17F13BB6DF12B2CFBBC2B0E0C34B00D0FCD0AECFB27924F6984E747BE2A09D83A8664590A8077331491A4F7D720843F23E652C6FA840308DB4020337AAD37967034A9FB523B67CA70330F02D9EA20C1E84CB8E5757C9E1896B60581441ED618AA5B26DA56C0A5A73C4DCFD755E610B4FC81FF84E21"; String expectedPrivKey = "8C8B3722A82E550565521611EBBC63079944C9B1ABB3B0020FF12F631891A9C468D3A67BF6271280DA58D03CB042B3A461441637F929C273469AD15311E910DE18CB9537BA1BE42E98BB59E498A13FD440D0E69EE832B45CD95C382177D67096A18C07F1781663651BDCAC90DEDA3DDD143485864181C91FA2080F6DAB3F86204CEB64A7B4446895C03987A031CB4B6D9E0462FDA829172B6C012C638B29B5CD75A2C930A5596A3181C33A22D574D30261196BC350738D4FD9183A763336243ACED99B3221C71D8866895C4E52C119BF3280DAF80A95E15209A795C4435FBB3570FDB8AA9BF9AEFD43B094B781D5A81136DAB88B8799696556FEC6AE14B0BB8BE4695E9A124C2AB8FF4AB1229B8AAA8C6F41A60C34C7B56182C55C2C685E737C6CA00A23FB8A68C1CD61F30D3993A1653C1675AC5F0901A7160A73966408B8876B715396CFA4903FC69D60491F8146808C97CD5C533E71017909E97B835B86FF847B42A696375435E006061CF7A479463272114A89EB3EAF2246F0F8C104A14986828E0AD20420C9B37EA23F5C514949E77AD9E9AD12290DD1215E11DA274457AC86B1CE6864B122677F3718AA31B02580E64317178D38F25F609BC6C55BC374A1BF78EA8ECC219B30B74CBB3272A599238C93985170048F176775FB19962AC3B135AA59DB104F7114DBC2C2D42949ADECA6A85B323EE2B2B23A77D9DB235979A8E2D67CF7D2136BBBA71F269574B38888E1541340C19284074F9B7C8CF37EB01384E6E3822EC4882DFBBEC4E6098EF2B2FC177A1F0BCB65A57FDAA89315461BEB7885FB68B3CD096EDA596AC0E61DD7A9C507BC6345E0827DFCC8A3AC2DCE51AD731AA0EB932A6D0983992347CBEB3CD0D9C9719797CC21CF0062B0AD94CAD734C63E6B5D859CBE19F0368245351BF464D7505569790D2BB724D8659A9FEB1C7C473DC4D061E29863A2714BAC42ADCD1A8372776556F7928A7A44E94B6A25322D03C0A1622A7FD261522B7358F085BDFB60758762CB901031901B5EECF4920C81020A9B1781BCB9DD19A9DFB66458E7757C52CEC75B4BA740A24099CB56BB60A76B6901AA3E0169C9E83496D73C4C99435A28D613E97A1177F58B6CC595D3B2331E9CA7B57B74DC2C5277D26F2FE19240A55C35D6CFCA26C73E9A2D7C980D97960AE1A04698C16B398A5F20C35A0914145CE1674B71ABC6066A909A3E4B911E69D5A849430361F731B07246A6329B52361904225082D0AAC5B21D6B34862481A890C3C360766F04263603A6B73E802B1F70B2EB00046836B8F493BF10B90B8737C6C548449B294C47253BE26CA72336A632063AD3D0B48C8B0F4A34447EF13B764020DE739EB79ABA20E2BE1951825F293BEDD1089FCB0A91F560C8E17CDF52541DC2B81F972A7375B201F10C08D9B5BC8B95100054A3D0AAFF89BD08D6A0E7F2115A435231290460C9AD435A3B3CF35E52091EDD1890047BCC0AABB1ACEBC75F4A32BC1451ACC4969940788E89412188946C9143C5046BD1B458DF617C5DF533B052CD6038B7754034A23C2F7720134C7B4EACE01FAC0A2853A9285847ABBD06A3343A778AC6062E458BC5E61ECE1C0DE0206E6FE8A84034A7C5F1B005FB0A584051D3229B86C909AC5647B3D75569E05A88279D80E5C30F574DC327512C6BBE8101239EC62861F4BE67B05B9CDA9C545C13E7EB53CFF260AD9870199C21F8C63D64F0458A7141285023FEB829290872389644B0C3B73AC2C8E121A29BB1C43C19A233D56BED82740EB021C97B8EBBA40FF328B541760FCC372B52D3BC4FCBC06F424EAF253804D4CB46F41FF254C0C5BA483B44A87C219654555EC7C163C79B9CB760A2AD9BB722B93E0C28BD4B1685949C496EAB1AFF90919E3761B346838ABB2F01A91E554375AFDAAAF3826E6DB79FE7353A7A578A7C0598CE28B6D9915214236BBFFA6D45B6376A07924A39A7BE818286715C8A3C110CD76C02E0417AF138BDB95C3CCA798AC809ED69CFB672B6FDDC24D89C06A6558814AB0C21C62B2F84C0E3E0803DB337A4E0C7127A6B4C8C08B1D1A76BF07EB6E5B5BB47A16C74BC548375FB29CD789A5CFF91BDBD071859F4846E355BB0D29484E264DFF36C9177A7ACA78908879695CA87F25436BC12630724BB22F0CB64897FE5C41195280DA04184D4BC7B532A0F70A54D7757CDE6175A6843B861CB2BC4830C0012554CFC5D2C8A2027AA3CD967130E9B96241B11C4320C7649CC23A71BAFE691AFC08E680BCEF42907000718E4EACE8DA28214197BE1C269DA9CB541E1A3CE97CFADF9C6058780FE6793DBFA8218A2760B802B8DA2AA271A38772523A76736A7A31B9D3037AD21CEBB11A472B8792EB17558B940E70883F264592C689B240BB43D5408BF446432F412F4B9A5F6865CC252A43CF40A320391555591D67561FDD05353AB6B019B3A08A73353D51B6113AB2FA51D975648EE254AF89A230504A236A4658257740BDCBBE1708AB022C3C588A410DB3B9C308A06275BDF5B4859D3A2617A295E1A22F90198BAD0166F4A943417C5B831736CB2C8580ABFDE5714B586ABEEC0A175A08BC710C7A2895DE93AC438061BF7765D0D21CD418167CAF89D1EFC3448BCBB96D69B3E010C82D15CAB6CACC6799D3639669A5B21A633C865F8593B5B7BC800262BB837A924A6C5440E4FC73B41B23092C3912F4C6BEBB4C7B4C62908B03775666C22220DF9C88823E344C7308332345C8B795D34E8C051F21F5A21C214B69841358709B1C305B32CC2C3806AE9CCD3819FFF4507FE520FBFC27199BC23BE6B9B2D2AC1717579AC769279E2A7AAC68A371A47BA3A7DBE016F14E1A727333663C4A5CD1A0F8836CF7B5C49AC51485CA60345C990E06888720003731322C5B8CD5E6907FDA1157F468FD3FC20FA8175EEC95C291A262BA8C5BE990872418930852339D88A19B37FEFA3CFE82175C224407CA414BAEB37923B4D2D83134AE154E490A9B45A0563B06C953C3301450A2176A07C614A74E3478E48509F9A60AE945A8EBC7815121D90A3B0E07091A096CF02C57B25BCA58126AD0C629CE166A7EDB4B33221A0D3F72B85D562EC698B7D0A913D73806F1C5C87B38EC003CB303A3DC51B4B35356A67826D6EDAA8FEB93B98493B2D1C11B676A6AD9506A1AAAE13A824C7C08D1C6C2C4DBA9642C76EA7F6C8264B64A23CCCA9A74635FCBF03E00F1B5722B214376790793B2C4F0A13B5C40760B4218E1D2594DCB30A70D9C1782A5DD30576FA4144BFC8416EDA8118FC6472F56A979586F33BB070FB0F1B0B10BC4897EBE01BCA3893D4E16ADB25093A7417D0708C83A26322E22E6330091E30152BF823597C04CCF4CFC7331578F43A2726CCB428289A90C863259DD180C5FF142BEF41C7717094BE07856DA2B140FA67710967356AA47DFBC8D255B4722AB86D439B7E0A6090251D2D4C1ED5F20BBE6807BF65A90B7CB2EC0102AF02809DC9AC7D0A3ABC69C18365BCFF59185F33996887746185906C0191AED4407E139446459BE29C6822717644353D24AB6339156A9C424909F0A9025BB74720779BE43F16D81C8CC666E99710D8C68BB5CC4E12F314E925A551F09CC59003A1F88103C254BB978D75F394D3540E31E771CDA36E39EC54A62B5832664D821A72F1E6AFBBA27F84295B2694C498498E812BC8E9378FE541CEC5891B25062901CB7212E3CDC46179EC5BCEC10BC0B9311DE05074290687FD6A5392671654284CD9C8CC3EBA80EB3B662EB53EB75116704A1FEB5C2D056338532868DDF24EB8992AB8565D9E490CADF14804360DAA90718EAB616BAB0765D33987B47EFB6599C5563235E61E4BE670E97955AB292D9732CB8930948AC82DF230AC72297A23679D6B94C17F1359483254FEDC2F05819F0D069A443B78E3FC6C3EF4714B05A3FCA81CBBA60242A7060CD885D8F39981BB18092B23DAA59FD9578388688A09BBA079BC809A54843A60385E2310BBCBCC0213CE3DFAAB33B47F9D6305BC95C6107813C585C4B657BF30542833B14949F573C0612AD524BAAE69590C1277B86C286571BF66B3CFF46A3858C09906A794DF4A06E9D4B0A2E43F10F72A6C6C47E5646E2C799B71C33ED2F01EEB45938EB7A4E2E2908C53558A540D350369FA189C616943F7981D7618CF02A5B0A2BCC422E857D1A47871253D08293C1C179BCDC0437069107418205FDB9856623B8CA6B694C96C084B17F13BB6DF12B2CFBBC2B0E0C34B00D0FCD0AECFB27924F6984E747BE2A09D83A8664590A8077331491A4F7D720843F23E652C6FA840308DB4020337AAD37967034A9FB523B67CA70330F02D9EA20C1E84CB8E5757C9E1896B60581441ED618AA5B26DA56C0A5A73C4DCFD755E610B4FC81FF84E21D2E574DFD8CD0AE893AA7E125B44B924F45223EC09F2AD1141EA93A68050DBF699E3246884181F8E1DD44E0C7629093330221FD67D9B7D6E1510B2DBAD8762F7"; - SecureRandom random = new SecureRandom(); MLKEMKeyPairGenerator keyGen = new MLKEMKeyPairGenerator(); - keyGen.init(new MLKEMKeyGenerationParameters(random, MLKEMParameters.ml_kem_1024)); + keyGen.init(new MLKEMKeyGenerationParameters(new FixedSecureRandom(Arrays.concatenate(d, z)), MLKEMParameters.ml_kem_1024)); - AsymmetricCipherKeyPair keyPair = keyGen.internalGenerateKeyPair(d, z); + AsymmetricCipherKeyPair keyPair = keyGen.generateKeyPair(); assertTrue(Arrays.areEqual(Hex.decode(expectedPubKey), ((MLKEMPublicKeyParameters)keyPair.getPublic()).getEncoded())); assertTrue(Arrays.areEqual(Hex.decode(expectedPrivKey), ((MLKEMPrivateKeyParameters)keyPair.getPrivate()).getEncoded())); - MLKEMGenerator kemGen = new MLKEMGenerator(random); + MLKEMGenerator kemGen = new MLKEMGenerator(RANDOM); byte[] message = Hex.decode("59C5154C04AE43AAFF32700F081700389D54BEC4C37C088B1C53F66212B12C72"); @@ -516,16 +577,15 @@ public void testParameters() public void testMLKEMRandom() { - SecureRandom random = new SecureRandom(); MLKEMKeyPairGenerator keyGen = new MLKEMKeyPairGenerator(); - keyGen.init(new MLKEMKeyGenerationParameters(random, MLKEMParameters.ml_kem_1024)); + keyGen.init(new MLKEMKeyGenerationParameters(RANDOM, MLKEMParameters.ml_kem_1024)); for (int i = 0; i != 1000; i++) { AsymmetricCipherKeyPair keyPair = keyGen.generateKeyPair(); - MLKEMGenerator kemGen = new MLKEMGenerator(random); + MLKEMGenerator kemGen = new MLKEMGenerator(RANDOM); SecretWithEncapsulation secretEncap = kemGen.generateEncapsulated(keyPair.getPublic()); @@ -536,4 +596,48 @@ public void testMLKEMRandom() assertTrue(Arrays.areEqual(secretEncap.getSecret(), decryptedSharedSecret)); } } + + public void testWithPreferredFormat() + { + MLKEMParameters[] parameters = new MLKEMParameters[]{ + MLKEMParameters.ml_kem_512, + MLKEMParameters.ml_kem_768, + MLKEMParameters.ml_kem_1024, + }; + + for (int i = 0; i < parameters.length; ++i) + { + MLKEMKeyPairGenerator kpg = new MLKEMKeyPairGenerator(); + kpg.init(new MLKEMKeyGenerationParameters(RANDOM, parameters[i])); + + AsymmetricCipherKeyPair kp = kpg.generateKeyPair(); + MLKEMPrivateKeyParameters privateKey = (MLKEMPrivateKeyParameters)kp.getPrivate(); + + implWithPreferredFormat(privateKey, MLKEMPrivateKeyParameters.SEED_ONLY); + implWithPreferredFormat(privateKey, MLKEMPrivateKeyParameters.EXPANDED_KEY); + implWithPreferredFormat(privateKey, MLKEMPrivateKeyParameters.BOTH); + } + } + + private static void implWithPreferredFormat(MLKEMPrivateKeyParameters privateKey, int format) + { + int originalFormat = privateKey.getPreferredFormat(); + byte[] originalSeed = privateKey.getSeed(); + byte[] originalEncoding = privateKey.getEncoded(); + + MLKEMPrivateKeyParameters updatedPrivateKey = privateKey.withPreferredFormat(format); + + int updatedFormat = updatedPrivateKey.getPreferredFormat(); + byte[] updatedSeed = updatedPrivateKey.getSeed(); + byte[] updatedEncoding = updatedPrivateKey.getEncoded(); + + assertEquals(format, updatedFormat); + assertTrue(Arrays.areEqual(originalSeed, updatedSeed)); + assertTrue(Arrays.areEqual(originalEncoding, updatedEncoding)); + + if (format == originalFormat) + { + assertSame(privateKey, updatedPrivateKey); + } + } } diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java new file mode 100644 index 0000000000..5dee4da12a --- /dev/null +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/MayoTest.java @@ -0,0 +1,94 @@ +package org.bouncycastle.pqc.crypto.test; + +import java.security.SecureRandom; + +import junit.framework.TestCase; +import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.Signer; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.pqc.crypto.MessageSigner; +import org.bouncycastle.pqc.crypto.mayo.MayoKeyGenerationParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoKeyPairGenerator; +import org.bouncycastle.pqc.crypto.mayo.MayoParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoSigner; + +public class MayoTest + extends TestCase +{ + public static void main(String[] args) + throws Exception + { + MayoTest test = new MayoTest(); + test.testTestVectors(); + //test.testKeyGen(); + } + + private static final MayoParameters[] PARAMETER_SETS = new MayoParameters[] + { + MayoParameters.mayo1, + MayoParameters.mayo2, + MayoParameters.mayo3, + MayoParameters.mayo5 + }; + + private static final String[] files = new String[]{ + "PQCsignKAT_24_MAYO_1.rsp", + "PQCsignKAT_24_MAYO_2.rsp", + "PQCsignKAT_32_MAYO_3.rsp", + "PQCsignKAT_40_MAYO_5.rsp", + }; + + + public void testTestVectors() + throws Exception + { + long start = System.currentTimeMillis(); + TestUtils.testTestVector(false, true, false, "pqc/crypto/mayo", files, new TestUtils.SignerOperation() + { + @Override + public SecureRandom getSecureRandom(byte[] seed) + { + return new NISTSecureRandom(seed, null); + } + + @Override + public AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int fileIndex, SecureRandom random) + { + MayoParameters parameters = PARAMETER_SETS[fileIndex]; + + MayoKeyPairGenerator kpGen = new MayoKeyPairGenerator(); + kpGen.init(new MayoKeyGenerationParameters(random, parameters)); + return kpGen; + } + + @Override + public byte[] getPublicKeyEncoded(AsymmetricKeyParameter pubParams) + { + return ((MayoPublicKeyParameters)pubParams).getEncoded(); + } + + @Override + public byte[] getPrivateKeyEncoded(CipherParameters privParams) + { + return ((MayoPrivateKeyParameters)privParams).getEncoded(); + } + + @Override + public Signer getSigner() + { + return null; + } + + @Override + public MessageSigner getMessageSigner() + { + return new MayoSigner(); + } + }); + long end = System.currentTimeMillis(); + System.out.println("time cost: " + (end - start) +"\n"); + } +} diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUKAT.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUKAT.java index e6888c3951..f400db2f59 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUKAT.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUKAT.java @@ -31,13 +31,12 @@ public class NTRUKAT */ public byte[] ss; - private static final TestSampler sampler = new TestSampler(); - public static List getKAT(InputStream src) { List kats = new ArrayList(); BufferedReader bin = new BufferedReader(new InputStreamReader(src)); HashMap buf = new HashMap(); + TestSampler sampler = new TestSampler(); try { for (String line = bin.readLine(); line != null; line = bin.readLine()) diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRULPRimeTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRULPRimeTest.java index 774c6e59f1..13e2d4afd3 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRULPRimeTest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRULPRimeTest.java @@ -37,8 +37,6 @@ public void testKEM() NTRULPRimeParameters.ntrulpr1277 }; - TestSampler sampler = new TestSampler(); - for (int i = 0; i != paramList.length; i++) { NTRULPRimeParameters paramSpec = paramList[i]; @@ -47,6 +45,7 @@ public void testKEM() BufferedReader resourceReader = new BufferedReader(new InputStreamReader(resource)); String line; + TestSampler sampler = new TestSampler(); while ((line = resourceReader.readLine()) != null) { if (! line.startsWith("count")) diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUPlusTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUPlusTest.java new file mode 100644 index 0000000000..c2037f7665 --- /dev/null +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUPlusTest.java @@ -0,0 +1,101 @@ +package org.bouncycastle.pqc.crypto.test; + +import java.security.SecureRandom; + +import junit.framework.TestCase; +import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import org.bouncycastle.crypto.EncapsulatedSecretExtractor; +import org.bouncycastle.crypto.EncapsulatedSecretGenerator; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusKEMExtractor; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusKEMGenerator; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusKeyGenerationParameters; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusKeyPairGenerator; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusParameters; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusPublicKeyParameters; + +public class NTRUPlusTest + extends TestCase +{ + public static void main(String[] args) + throws Exception + { + NTRUPlusTest test = new NTRUPlusTest(); + test.testTestVectors(); + //test.testKeyGen(); + } + + private static final NTRUPlusParameters[] PARAMETER_SETS = new NTRUPlusParameters[] + { + NTRUPlusParameters.ntruplus_kem_768, + NTRUPlusParameters.ntruplus_kem_864, + NTRUPlusParameters.ntruplus_kem_1152, + }; + + private static final String[] files = new String[]{ + "PQCkemKAT_2336.rsp", + "PQCkemKAT_2624.rsp", + "PQCkemKAT_3488.rsp", + }; + + + public void testTestVectors() + throws Exception + { + long start = System.currentTimeMillis(); + TestUtils.testTestVector(false, true, "pqc/crypto/ntruplus", files, new TestUtils.KeyEncapsulationOperation() + { + int sessionKeySize = 0; + + @Override + public SecureRandom getSecureRandom(byte[] seed) + { + return new NISTSecureRandom(seed, null); + } + + @Override + public AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int fileIndex, SecureRandom random) + { + NTRUPlusParameters parameters = PARAMETER_SETS[fileIndex]; + sessionKeySize = parameters.getSsBytes() * 8; + NTRUPlusKeyPairGenerator kpGen = new NTRUPlusKeyPairGenerator(); + kpGen.init(new NTRUPlusKeyGenerationParameters(random, parameters)); + return kpGen; + } + + @Override + public byte[] getPublicKeyEncoded(AsymmetricKeyParameter pubParams) + { + return ((NTRUPlusPublicKeyParameters)pubParams).getEncoded(); + } + + @Override + public byte[] getPrivateKeyEncoded(AsymmetricKeyParameter privParams) + { + return ((NTRUPlusPrivateKeyParameters)privParams).getEncoded(); + } + + @Override + public EncapsulatedSecretGenerator getKEMGenerator(SecureRandom random) + { + return new NTRUPlusKEMGenerator(random); + } + + @Override + public EncapsulatedSecretExtractor getKEMExtractor(AsymmetricKeyParameter privParams) + { + return new NTRUPlusKEMExtractor((NTRUPlusPrivateKeyParameters)privParams); + } + + @Override + public int getSessionKeySize() + { + return 0; + } + + }); + long end = System.currentTimeMillis(); + System.out.println("time cost: " + (end - start) + "\n"); + } +} diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/PicnicVectorTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/PicnicVectorTest.java index 5d048aff09..765e592c0e 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/PicnicVectorTest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/PicnicVectorTest.java @@ -90,17 +90,16 @@ public void testVectors() }; } - TestSampler sampler = new TestSampler(); - for (int fileIndex = 0; fileIndex != files.length; fileIndex++) { String name = files[fileIndex]; - // System.out.println("testing: " + name); + InputStream src = TestResourceFinder.findTestResource("pqc/crypto/picnic", name); BufferedReader bin = new BufferedReader(new InputStreamReader(src)); String line = null; HashMap buf = new HashMap(); + TestSampler sampler = new TestSampler(); while ((line = bin.readLine()) != null) { line = line.trim(); diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/RainbowTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/RainbowTest.java deleted file mode 100644 index e3c6458c8f..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/RainbowTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.bouncycastle.pqc.crypto.test; - -import java.math.BigInteger; -import java.security.SecureRandom; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.MessageSigner; -import org.bouncycastle.pqc.crypto.rainbow.RainbowKeyGenerationParameters; -import org.bouncycastle.pqc.crypto.rainbow.RainbowKeyPairGenerator; -import org.bouncycastle.pqc.crypto.rainbow.RainbowParameters; -import org.bouncycastle.pqc.crypto.rainbow.RainbowSigner; -import org.bouncycastle.util.BigIntegers; -import org.bouncycastle.util.test.SimpleTest; - -public class RainbowTest - extends SimpleTest -{ - private RainbowParameters params; - - public RainbowTest(RainbowParameters params) - { - this.params = params; - } - - public String getName() - { - return params.getName(); - } - - public void performTest() - { - byte[] seed = new byte[64]; - SecureRandom sr = new SecureRandom(); - sr.nextBytes(seed); - NISTSecureRandom random = new NISTSecureRandom(seed, null); - - RainbowKeyPairGenerator rainbowKeyGen = new RainbowKeyPairGenerator(); - RainbowKeyGenerationParameters genParam = new RainbowKeyGenerationParameters(random, params); - - rainbowKeyGen.init(genParam); - - AsymmetricCipherKeyPair pair = rainbowKeyGen.generateKeyPair(); - - ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); - - MessageSigner rainbowSigner = new RainbowSigner(); - - rainbowSigner.init(true, param); - - byte[] message = BigIntegers.asUnsignedByteArray(new BigInteger("968236873715988614170569073515315707566766479517")); - - byte[] sig = rainbowSigner.generateSignature(message); - - rainbowSigner.init(false, pair.getPublic()); - - if (!rainbowSigner.verifySignature(message, sig)) - { - fail("verification fails"); - } - } - - public static void main(String[] args) - { - runTest(new RainbowTest(RainbowParameters.rainbowIIIclassic)); - runTest(new RainbowTest(RainbowParameters.rainbowIIIcircumzenithal)); - runTest(new RainbowTest(RainbowParameters.rainbowIIIcompressed)); - runTest(new RainbowTest(RainbowParameters.rainbowVclassic)); - runTest(new RainbowTest(RainbowParameters.rainbowVcircumzenithal)); - runTest(new RainbowTest(RainbowParameters.rainbowVcompressed)); - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/RainbowVectorTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/RainbowVectorTest.java deleted file mode 100644 index 34cf596015..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/RainbowVectorTest.java +++ /dev/null @@ -1,143 +0,0 @@ -package org.bouncycastle.pqc.crypto.test; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.HashMap; -import java.util.Random; - -import junit.framework.TestCase; -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.MessageSigner; -import org.bouncycastle.pqc.crypto.rainbow.RainbowKeyGenerationParameters; -import org.bouncycastle.pqc.crypto.rainbow.RainbowKeyPairGenerator; -import org.bouncycastle.pqc.crypto.rainbow.RainbowParameters; -import org.bouncycastle.pqc.crypto.rainbow.RainbowPrivateKeyParameters; -import org.bouncycastle.pqc.crypto.rainbow.RainbowPublicKeyParameters; -import org.bouncycastle.pqc.crypto.rainbow.RainbowSigner; -import org.bouncycastle.test.TestResourceFinder; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.encoders.Hex; - -public class RainbowVectorTest - extends TestCase -{ - public void testVectors() - throws Exception - { - String[] files = new String[]{ - "rainbowIIIclassic.rsp", - "rainbowIIIcircumzenithal.rsp", - "rainbowIIIcompressed.rsp", - "rainbowVclassic.rsp", - "rainbowVcircumzenithal.rsp", - "rainbowVcompressed.rsp" - }; - RainbowParameters[] params = new RainbowParameters[]{ - RainbowParameters.rainbowIIIclassic, - RainbowParameters.rainbowIIIcircumzenithal, - RainbowParameters.rainbowIIIcompressed, - RainbowParameters.rainbowVclassic, - RainbowParameters.rainbowVcircumzenithal, - RainbowParameters.rainbowVcompressed - }; - - TestSampler sampler = new TestSampler(); - Random rd = new Random(System.currentTimeMillis()); - - int offSet = rd.nextInt(10); - - for (int fileIndex = 0; fileIndex != files.length; fileIndex++) - { - String name = files[fileIndex]; - // System.out.println("testing: " + name); - InputStream src = TestResourceFinder.findTestResource("pqc/crypto/rainbow", name); - BufferedReader bin = new BufferedReader(new InputStreamReader(src)); - - String line = null; - HashMap buf = new HashMap(); - while ((line = bin.readLine()) != null) - { - line = line.trim(); - - if (line.startsWith("#")) - { - continue; - } - if (line.length() == 0) - { - if (buf.size() > 0) - { - String count = (String)buf.get("count"); -// if (sampler.skipTest(count)) -// { -// continue; -// } - - if (Integer.parseInt(count) != offSet) - { - continue; - } - // System.out.println("test case: " + count); - byte[] seed = Hex.decode((String)buf.get("seed")); // seed for Rainbow secure random - int mlen = Integer.parseInt((String)buf.get("mlen")); // message length - byte[] msg = Hex.decode((String)buf.get("msg")); // message - byte[] pk = Hex.decode((String)buf.get("pk")); // public key - byte[] sk = Hex.decode((String)buf.get("sk")); // private key - int smlen = Integer.parseInt((String)buf.get("smlen")); // signature length - byte[] sigExpected = Hex.decode((String)buf.get("sm")); // signature - - NISTSecureRandom random = new NISTSecureRandom(seed, null); - - RainbowParameters parameters = params[fileIndex]; - - RainbowKeyPairGenerator kpGen = new RainbowKeyPairGenerator(); - RainbowKeyGenerationParameters genParams = new RainbowKeyGenerationParameters(random, parameters); - // - // Generate keys and test. - // - kpGen.init(genParams); - AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); - - RainbowPublicKeyParameters pubParams = (RainbowPublicKeyParameters)kp.getPublic(); - RainbowPrivateKeyParameters privParams = (RainbowPrivateKeyParameters)kp.getPrivate(); - assertTrue(name + " " + count + ": public key", Arrays.areEqual(pk, pubParams.getEncoded())); - assertTrue(name + " " + count + ": secret key", Arrays.areEqual(sk, privParams.getPrivateKey())); - - // - // Signature test - // - ParametersWithRandom param = new ParametersWithRandom(kp.getPrivate(), random); - MessageSigner signer = new RainbowSigner(); - - signer.init(true, param); - - byte[] sigGenerated = signer.generateSignature(msg); - byte[] attachedSig = Arrays.concatenate(msg, sigGenerated); - - //// System.out.println("expected:\t" + Hex.toHexString(sigExpected).toUpperCase().substring(msg.length*2, sigExpected.length*2)); - //// System.out.println("generated:\t" + Hex.toHexString(sigGenerated).toUpperCase()); - //// System.out.println("attached:\t" + Hex.toHexString(attachedSig).toUpperCase()); - - signer.init(false, kp.getPublic()); - - assertTrue(name + " " + count + ": signature verify", signer.verifySignature(msg, sigGenerated)); - assertTrue(name + " " + count + ": signature gen match", Arrays.areEqual(sigExpected, attachedSig)); - } - buf.clear(); - - continue; - } - - int a = line.indexOf("="); - if (a > -1) - { - buf.put(line.substring(0, a).trim(), line.substring(a + 1).trim()); - } - } - // System.out.println("testing successful!"); - } - } - -} diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/SABERVectorTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/SABERVectorTest.java index ce5f0d1ea7..d63527e933 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/SABERVectorTest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/SABERVectorTest.java @@ -79,17 +79,16 @@ public void testVectors() "ufiresaber-90s.rsp", }; - TestSampler sampler = new TestSampler(); - for (int fileIndex = 0; fileIndex != files.length; fileIndex++) { String name = files[fileIndex]; - // System.out.println("testing: " + name); + InputStream src = TestResourceFinder.findTestResource("pqc/crypto/saber", name); BufferedReader bin = new BufferedReader(new InputStreamReader(src)); String line = null; HashMap buf = new HashMap(); + TestSampler sampler = new TestSampler(); while ((line = bin.readLine()) != null) { line = line.trim(); diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/SLHDSATest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/SLHDSATest.java index 99ba397db4..1a1430b089 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/SLHDSATest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/SLHDSATest.java @@ -739,7 +739,7 @@ public void testBasicKeyGenerationShake256128fSimpleSign() // return (String[]) l.toArray(new String[0]); // } - private class InternalSLHDSASigner + private static class InternalSLHDSASigner extends SLHDSASigner { public byte[] internalGenerateSignature(byte[] message, byte[] optRand) diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/SNTRUPrimeTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/SNTRUPrimeTest.java index f10d8dd235..865a5d460f 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/SNTRUPrimeTest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/SNTRUPrimeTest.java @@ -37,7 +37,6 @@ public void testKEM() SNTRUPrimeParameters.sntrup1277 }; - TestSampler sampler = new TestSampler(); for (int i = 0; i != paramList.length; i++) { SNTRUPrimeParameters paramSpec = paramList[i]; @@ -46,6 +45,7 @@ public void testKEM() BufferedReader resourceReader = new BufferedReader(new InputStreamReader(resource)); String line; + TestSampler sampler = new TestSampler(); while ((line = resourceReader.readLine()) != null) { if (! line.startsWith("count")) diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/SnovaTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/SnovaTest.java new file mode 100644 index 0000000000..54ccbe264f --- /dev/null +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/SnovaTest.java @@ -0,0 +1,175 @@ +package org.bouncycastle.pqc.crypto.test; + +import java.security.SecureRandom; + +import junit.framework.TestCase; +import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.Signer; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.pqc.crypto.MessageSigner; +import org.bouncycastle.pqc.crypto.snova.SnovaKeyGenerationParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaKeyPairGenerator; +import org.bouncycastle.pqc.crypto.snova.SnovaParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaPublicKeyParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaSigner; + + +public class SnovaTest + extends TestCase +{ + public static void main(String[] args) + throws Exception + { + SnovaTest test = new SnovaTest(); + test.testTestVectors(); + } + + private static final SnovaParameters[] PARAMETER_SETS = new SnovaParameters[] + { + SnovaParameters.SNOVA_24_5_4_ESK, + SnovaParameters.SNOVA_24_5_4_SHAKE_ESK, + SnovaParameters.SNOVA_24_5_4_SHAKE_SSK, + SnovaParameters.SNOVA_24_5_4_SSK, + SnovaParameters.SNOVA_24_5_5_ESK, + SnovaParameters.SNOVA_24_5_5_SHAKE_ESK, + SnovaParameters.SNOVA_24_5_5_SHAKE_SSK, + SnovaParameters.SNOVA_24_5_5_SSK, + SnovaParameters.SNOVA_25_8_3_ESK, + SnovaParameters.SNOVA_25_8_3_SHAKE_ESK, + SnovaParameters.SNOVA_25_8_3_SHAKE_SSK, + SnovaParameters.SNOVA_25_8_3_SSK, + SnovaParameters.SNOVA_29_6_5_ESK, + SnovaParameters.SNOVA_29_6_5_SHAKE_ESK, + SnovaParameters.SNOVA_29_6_5_SHAKE_SSK, + SnovaParameters.SNOVA_29_6_5_SSK, + SnovaParameters.SNOVA_37_8_4_ESK, + SnovaParameters.SNOVA_37_8_4_SHAKE_ESK, + SnovaParameters.SNOVA_37_8_4_SHAKE_SSK, + SnovaParameters.SNOVA_37_8_4_SSK, + SnovaParameters.SNOVA_37_17_2_ESK, + SnovaParameters.SNOVA_37_17_2_SHAKE_ESK, + SnovaParameters.SNOVA_37_17_2_SHAKE_SSK, + SnovaParameters.SNOVA_37_17_2_SSK, + SnovaParameters.SNOVA_49_11_3_ESK, + SnovaParameters.SNOVA_49_11_3_SHAKE_ESK, + SnovaParameters.SNOVA_49_11_3_SHAKE_SSK, + SnovaParameters.SNOVA_49_11_3_SSK, + SnovaParameters.SNOVA_56_25_2_ESK, + SnovaParameters.SNOVA_56_25_2_SHAKE_ESK, + SnovaParameters.SNOVA_56_25_2_SHAKE_SSK, + SnovaParameters.SNOVA_56_25_2_SSK, + SnovaParameters.SNOVA_60_10_4_ESK, + SnovaParameters.SNOVA_60_10_4_SHAKE_ESK, + SnovaParameters.SNOVA_60_10_4_SHAKE_SSK, + SnovaParameters.SNOVA_60_10_4_SSK, + SnovaParameters.SNOVA_66_15_3_ESK, + SnovaParameters.SNOVA_66_15_3_SHAKE_ESK, + SnovaParameters.SNOVA_66_15_3_SHAKE_SSK, + SnovaParameters.SNOVA_66_15_3_SSK, + SnovaParameters.SNOVA_75_33_2_ESK, + SnovaParameters.SNOVA_75_33_2_SHAKE_ESK, + SnovaParameters.SNOVA_75_33_2_SHAKE_SSK, + SnovaParameters.SNOVA_75_33_2_SSK, + }; + + private static final String[] files = new String[]{ + "PQCsignKAT_SNOVA_24_5_4_ESK.rsp", + "PQCsignKAT_SNOVA_24_5_4_SHAKE_ESK.rsp", + "PQCsignKAT_SNOVA_24_5_4_SHAKE_SSK.rsp", + "PQCsignKAT_SNOVA_24_5_4_SSK.rsp", + "PQCsignKAT_SNOVA_24_5_5_ESK.rsp", + "PQCsignKAT_SNOVA_24_5_5_SHAKE_ESK.rsp", + "PQCsignKAT_SNOVA_24_5_5_SHAKE_SSK.rsp", + "PQCsignKAT_SNOVA_24_5_5_SSK.rsp", + "PQCsignKAT_SNOVA_25_8_3_ESK.rsp", + "PQCsignKAT_SNOVA_25_8_3_SHAKE_ESK.rsp", + "PQCsignKAT_SNOVA_25_8_3_SHAKE_SSK.rsp", + "PQCsignKAT_SNOVA_25_8_3_SSK.rsp", + "PQCsignKAT_SNOVA_29_6_5_ESK.rsp", + "PQCsignKAT_SNOVA_29_6_5_SHAKE_ESK.rsp", + "PQCsignKAT_SNOVA_29_6_5_SHAKE_SSK.rsp", + "PQCsignKAT_SNOVA_29_6_5_SSK.rsp", + "PQCsignKAT_SNOVA_37_8_4_ESK.rsp", + "PQCsignKAT_SNOVA_37_8_4_SHAKE_ESK.rsp", + "PQCsignKAT_SNOVA_37_8_4_SHAKE_SSK.rsp", + "PQCsignKAT_SNOVA_37_8_4_SSK.rsp", + "PQCsignKAT_SNOVA_37_17_2_ESK.rsp", + "PQCsignKAT_SNOVA_37_17_2_SHAKE_ESK.rsp", + "PQCsignKAT_SNOVA_37_17_2_SHAKE_SSK.rsp", + "PQCsignKAT_SNOVA_37_17_2_SSK.rsp", + "PQCsignKAT_SNOVA_49_11_3_ESK.rsp", + "PQCsignKAT_SNOVA_49_11_3_SHAKE_ESK.rsp", + "PQCsignKAT_SNOVA_49_11_3_SHAKE_SSK.rsp", + "PQCsignKAT_SNOVA_49_11_3_SSK.rsp", + "PQCsignKAT_SNOVA_56_25_2_ESK.rsp", + "PQCsignKAT_SNOVA_56_25_2_SHAKE_ESK.rsp", + "PQCsignKAT_SNOVA_56_25_2_SHAKE_SSK.rsp", + "PQCsignKAT_SNOVA_56_25_2_SSK.rsp", + "PQCsignKAT_SNOVA_60_10_4_ESK.rsp", + "PQCsignKAT_SNOVA_60_10_4_SHAKE_ESK.rsp", + "PQCsignKAT_SNOVA_60_10_4_SHAKE_SSK.rsp", + "PQCsignKAT_SNOVA_60_10_4_SSK.rsp", + "PQCsignKAT_SNOVA_66_15_3_ESK.rsp", + "PQCsignKAT_SNOVA_66_15_3_SHAKE_ESK.rsp", + "PQCsignKAT_SNOVA_66_15_3_SHAKE_SSK.rsp", + "PQCsignKAT_SNOVA_66_15_3_SSK.rsp", + "PQCsignKAT_SNOVA_75_33_2_ESK.rsp", + "PQCsignKAT_SNOVA_75_33_2_SHAKE_ESK.rsp", + "PQCsignKAT_SNOVA_75_33_2_SHAKE_SSK.rsp", + "PQCsignKAT_SNOVA_75_33_2_SSK.rsp", + }; + + + public void testTestVectors() + throws Exception + { + long start = System.currentTimeMillis(); + TestUtils.testTestVector(true, true, false, "pqc/crypto/snova", files, new TestUtils.SignerOperation() + { + @Override + public SecureRandom getSecureRandom(byte[] seed) + { + return new NISTSecureRandom(seed, null); + } + + @Override + public AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int fileIndex, SecureRandom random) + { + SnovaParameters parameters = PARAMETER_SETS[fileIndex]; + + SnovaKeyPairGenerator kpGen = new SnovaKeyPairGenerator(); + kpGen.init(new SnovaKeyGenerationParameters(random, parameters)); + return kpGen; + } + + @Override + public byte[] getPublicKeyEncoded(AsymmetricKeyParameter pubParams) + { + return ((SnovaPublicKeyParameters)pubParams).getEncoded(); + } + + @Override + public byte[] getPrivateKeyEncoded(CipherParameters privParams) + { + return ((SnovaPrivateKeyParameters)privParams).getEncoded(); + } + + @Override + public Signer getSigner() + { + return null; + } + + @Override + public MessageSigner getMessageSigner() + { + return new SnovaSigner(); + } + }); + long end = System.currentTimeMillis(); + System.out.println("time cost: " + (end - start) + "\n"); + } +} + diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/SphincsPlusTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/SphincsPlusTest.java index 95856025a2..19692d1828 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/SphincsPlusTest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/SphincsPlusTest.java @@ -8,7 +8,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Random; import junit.framework.TestCase; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; @@ -45,22 +44,18 @@ public void testVectors() " haraka-128s-simple.rsp haraka-256f-simple.rsp" + " haraka-192f-simple.rsp haraka-256s-simple.rsp"; - TestSampler sampler = new TestSampler(); - - Random rd = new Random(System.currentTimeMillis()); - - int offSet = rd.nextInt(10); - String[] fileList = splitOn(files, ' '); - //long startTime = System.currentTimeMillis(); + for (int i = 0; i != fileList.length; i++) { String name = fileList[i]; + InputStream src = TestResourceFinder.findTestResource("pqc/crypto/sphincs_plus", "subset_" + name); BufferedReader bin = new BufferedReader(new InputStreamReader(src)); - // System.out.println(name); + String line = null; HashMap buf = new HashMap(); + TestSampler sampler = new TestSampler(); while ((line = bin.readLine()) != null) { line = line.trim(); @@ -80,14 +75,10 @@ public void testVectors() byte[] sigExpected = Hex.decode((String)buf.get("sm")); byte[] oprR = Hex.decode((String)buf.get("optrand")); - if (Integer.parseInt(count) != offSet) + if (sampler.skipTest(count)) { continue; } -// if (sampler.skipTest(count)) -// { -// continue; -// } SPHINCSPlusKeyPairGenerator kpGen = new SPHINCSPlusKeyPairGenerator(); SecureRandom random = new FixedSecureRandom(sk); @@ -104,7 +95,7 @@ public void testVectors() boolean simple = nameParts[2].equals("simple.rsp"); boolean robust = nameParts[2].equals("robust.rsp"); - StringBuffer b = new StringBuffer(); + StringBuilder b = new StringBuilder(); if (sha2) { b.append("sha2"); diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestSampler.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestSampler.java index 054663747f..75ff701b15 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestSampler.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestSampler.java @@ -20,12 +20,16 @@ class TestSampler boolean skipTest(String count) { - int c = Integer.parseInt(count); - return !isFull && c != 0 && ((c + offSet) % 9 != 0); + return !isFull && shouldSkip(Integer.parseInt(count)); } boolean skipTest(int count) { - return !isFull && count != 0 && ((count + offSet) % 9 != 0); + return !isFull && shouldSkip(count); + } + + private boolean shouldSkip(int count) + { + return count != 0 && ((count + offSet) % 9 != 0); } } diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java index 743f936caf..1fdcac3574 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/TestUtils.java @@ -1,9 +1,268 @@ package org.bouncycastle.pqc.crypto.test; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.security.SecureRandom; +import java.util.HashMap; + +import junit.framework.Assert; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.EncapsulatedSecretExtractor; +import org.bouncycastle.crypto.EncapsulatedSecretGenerator; +import org.bouncycastle.crypto.SecretWithEncapsulation; +import org.bouncycastle.crypto.Signer; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.pqc.crypto.MessageSigner; +import org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; +import org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory; +import org.bouncycastle.pqc.crypto.util.PublicKeyFactory; +import org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory; +import org.bouncycastle.test.TestResourceFinder; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; + class TestUtils { static boolean parseBoolean(String value) { return "true".equalsIgnoreCase(value); } + + public interface SignerOperation + { + SecureRandom getSecureRandom(byte[] seed); + + AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int fileIndex, SecureRandom random); + + byte[] getPublicKeyEncoded(AsymmetricKeyParameter pubParams); + + byte[] getPrivateKeyEncoded(CipherParameters privParams); + + Signer getSigner(); + + MessageSigner getMessageSigner(); + } + + public interface KeyEncapsulationOperation + { + SecureRandom getSecureRandom(byte[] seed); + + AsymmetricCipherKeyPairGenerator getAsymmetricCipherKeyPairGenerator(int fileIndex, SecureRandom random); + + byte[] getPublicKeyEncoded(AsymmetricKeyParameter pubParams); + + byte[] getPrivateKeyEncoded(AsymmetricKeyParameter privParams); + + EncapsulatedSecretGenerator getKEMGenerator(SecureRandom random); + + EncapsulatedSecretExtractor getKEMExtractor(AsymmetricKeyParameter privParams); + + int getSessionKeySize(); + } + + public static void testTestVector(boolean sampleOnly, boolean enableFactory, boolean isSigner, String homeDir, String[] files, SignerOperation operation) + throws Exception + { + for (int fileIndex = 0; fileIndex != files.length; fileIndex++) + { + String name = files[fileIndex]; + + InputStream src = TestResourceFinder.findTestResource(homeDir, name); + BufferedReader bin = new BufferedReader(new InputStreamReader(src)); + + String line; + HashMap buf = new HashMap(); + TestSampler sampler = sampleOnly ? new TestSampler() : null; + while ((line = bin.readLine()) != null) + { + line = line.trim(); + + if (line.startsWith("#")) + { + continue; + } + if (line.length() == 0) + { + if (buf.size() > 0) + { + String count = (String)buf.get("count"); + if (sampler != null && sampler.skipTest(count)) + { + continue; + } + + byte[] seed = Hex.decode((String)buf.get("seed")); + byte[] pk = Hex.decode((String)buf.get("pk")); + byte[] sk = Hex.decode((String)buf.get("sk")); + byte[] message = Hex.decode((String)buf.get("msg")); + byte[] signature = Hex.decode((String)buf.get("sm")); + + SecureRandom random = operation.getSecureRandom(seed); + + AsymmetricCipherKeyPairGenerator kpGen = operation.getAsymmetricCipherKeyPairGenerator(fileIndex, random); + + // + // Generate keys and test. + // + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); + AsymmetricKeyParameter pubParams; + CipherParameters privParams; + if (enableFactory) + { + pubParams = PublicKeyFactory.createKey( + SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(kp.getPublic())); + privParams = PrivateKeyFactory.createKey( + PrivateKeyInfoFactory.createPrivateKeyInfo(kp.getPrivate())); + } + else + { + pubParams = kp.getPublic(); + privParams = kp.getPrivate(); + } + + Assert.assertTrue(name + ": public key", Arrays.areEqual(pk, operation.getPublicKeyEncoded(pubParams))); + Assert.assertTrue(name + ": secret key", Arrays.areEqual(sk, operation.getPrivateKeyEncoded(privParams))); + + byte[] sigGenerated; + privParams = new ParametersWithRandom(privParams, random); + if (isSigner) + { + Signer signer = operation.getSigner(); + signer.init(true, privParams); + signer.update(message, 0, message.length); + sigGenerated = signer.generateSignature(); + } + else + { + MessageSigner signer = operation.getMessageSigner(); + signer.init(true, privParams); + sigGenerated = signer.generateSignature(message); + } + + Assert.assertTrue(Arrays.areEqual(sigGenerated, signature)); + + if (isSigner) + { + Signer signer = operation.getSigner(); + signer.init(false, pubParams); + signer.update(message, 0, message.length); + Assert.assertTrue(signer.verifySignature(sigGenerated)); + } + else + { + MessageSigner signer = operation.getMessageSigner(); + signer.init(false, pubParams); + Assert.assertTrue(signer.verifySignature(message, sigGenerated)); + } + System.out.println("Count " + count + " pass"); + } + buf.clear(); + continue; + } + + int a = line.indexOf("="); + if (a > -1) + { + buf.put(line.substring(0, a).trim(), line.substring(a + 1).trim()); + } + } + } + } + + public static void testTestVector(boolean sampleOnly, boolean enableFactory, String homeDir, String[] files, KeyEncapsulationOperation operation) + throws Exception + { + for (int fileIndex = 0; fileIndex < files.length; fileIndex++) + { + String name = files[fileIndex]; + //System.out.println(files[fileIndex]); + InputStream src = TestResourceFinder.findTestResource(homeDir, name); + BufferedReader bin = new BufferedReader(new InputStreamReader(src)); + + String line = null; + HashMap buf = new HashMap(); + TestSampler sampler = sampleOnly ? new TestSampler() : null; + while ((line = bin.readLine()) != null) + { + line = line.trim(); + + if (line.startsWith("#")) + { + continue; + } + if (line.isEmpty()) + { + if (!buf.isEmpty()) + { + String count = (String)buf.get("count"); + if (sampler != null && sampler.skipTest(count)) + { + continue; + } + System.out.println("test case: " + count); + + byte[] seed = Hex.decode((String)buf.get("seed")); // seed for bike secure random + byte[] pk = Hex.decode((String)buf.get("pk")); // public key + byte[] sk = Hex.decode((String)buf.get("sk")); // private key + byte[] ct = Hex.decode((String)buf.get("ct")); // ciphertext + byte[] ss = Hex.decode((String)buf.get("ss")); // session key + + SecureRandom random = operation.getSecureRandom(seed); + + AsymmetricCipherKeyPairGenerator kpGen = operation.getAsymmetricCipherKeyPairGenerator(fileIndex, random); + + // + // Generate keys and test. + // + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); + AsymmetricKeyParameter pubParams; + AsymmetricKeyParameter privParams; + if (enableFactory) + { + pubParams = PublicKeyFactory.createKey( + SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(kp.getPublic())); + privParams = PrivateKeyFactory.createKey( + PrivateKeyInfoFactory.createPrivateKeyInfo(kp.getPrivate())); + } + else + { + pubParams = kp.getPublic(); + privParams = kp.getPrivate(); + } + + Assert.assertTrue(name + " " + count + ": public key", Arrays.areEqual(pk, operation.getPublicKeyEncoded(pubParams))); + Assert.assertTrue(name + " " + count + ": secret key", Arrays.areEqual(sk, operation.getPrivateKeyEncoded(privParams))); + + // KEM Encapsulation + EncapsulatedSecretGenerator kemGenerator = operation.getKEMGenerator(random); + SecretWithEncapsulation secretWithEnc = kemGenerator.generateEncapsulated(pubParams); + byte[] secret = secretWithEnc.getSecret(); + byte[] c = secretWithEnc.getEncapsulation(); + + Assert.assertTrue(name + " " + count + ": ciphertext", Arrays.areEqual(c, ct)); + Assert.assertTrue(name + " " + count + ": kem_dec ss", Arrays.areEqual(secret, 0, secret.length, ss, 0, secret.length)); + + // KEM Decapsulation + EncapsulatedSecretExtractor kemExtractor = operation.getKEMExtractor(privParams); + byte[] dec_key = kemExtractor.extractSecret(c); + + //Assert.assertTrue(operation.getSessionKeySize() == secret.length * 8); + Assert.assertTrue(name + " " + count + ": kem_dec key", Arrays.areEqual(dec_key, secret)); + } + buf.clear(); + continue; + } + int a = line.indexOf("="); + if (a > -1) + { + buf.put(line.substring(0, a).trim(), line.substring(a + 1).trim()); + } + } + // System.out.println("Testing successful!"); + } + } } diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/XMSSPrivateKeyTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/XMSSPrivateKeyTest.java index 7118bada5e..a7ce2d30f3 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/XMSSPrivateKeyTest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/XMSSPrivateKeyTest.java @@ -4,7 +4,6 @@ import junit.framework.TestCase; import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.Xof; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.digests.SHAKEDigest; @@ -32,7 +31,8 @@ private void parsingTest(Digest digest) { XMSSParameters params = new XMSSParameters(10, digest); byte[] root = generateRoot(digest); - XMSSPrivateKeyParameters privateKey = new XMSSPrivateKeyParameters.Builder(params).withRoot(root).build(); + XMSSPrivateKeyParameters privateKey = new XMSSPrivateKeyParameters.Builder(params).withRoot(root) + .withPublicSeed(new byte[digest.getDigestSize()]).withSecretKeySeed(new byte[digest.getDigestSize()]).build(); byte[] export = privateKey.toByteArray(); diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/XWingTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/XWingTest.java index 8568691939..a65a316210 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/XWingTest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/XWingTest.java @@ -1,5 +1,7 @@ package org.bouncycastle.pqc.crypto.test; +import java.security.SecureRandom; + import junit.framework.TestCase; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.SecretWithEncapsulation; @@ -16,70 +18,261 @@ public class XWingTest extends TestCase { - public void testKEM() + public static void main(String[] args) throws Exception { - String temp = "061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"; - String expectedSecret = "81b50581e5f7390675d542802e84f717fa3b87b5391217869e00eb54ba679a00"; - - byte[] seed = Hex.decode(temp); - - NISTSecureRandom random = new NISTSecureRandom(seed, null); - - byte[] coins = new byte[96]; - random.nextBytes(coins); - - XWingKeyPairGenerator keyGen = new XWingKeyPairGenerator(); - - keyGen.init(new XWingKeyGenerationParameters(new FixedSecureRandom(coins))); - - AsymmetricCipherKeyPair keyPair = keyGen.generateKeyPair(); - - XWingKEMGenerator kemGen = new XWingKEMGenerator(random); - - SecretWithEncapsulation secretEncap = kemGen.generateEncapsulated(keyPair.getPublic()); - - byte[] sharedSecret = secretEncap.getSecret(); + XWingTest test = new XWingTest(); + test.testKEM(); + } - assertTrue(Arrays.areEqual(Hex.decode(expectedSecret), sharedSecret)); + static byte[] seed1 = Hex.decode("7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26"); + static byte[] eseed1 = Hex.decode("3cb1eea988004b93103cfb0aeefd2a686e01fa4a58e8a3639ca8a1e3f9ae57e235b8cc87\n" + + " 3c23dc62b8d260169afa2f75ab916a58d974918835d25e6a435085b2"); + static byte[] pubEnc1 = Hex.decode("e2236b35a8c24b39b10aa1323a96a919a2ced88400633a7b07131713fc14b2b5b19cfc3d\n" + + " a5fa1a92c49f25513e0fd30d6b1611c9ab9635d7086727a4b7d21d34244e66969cf15b3b\n" + + " 2a785329f61b096b277ea037383479a6b556de7231fe4b7fa9c9ac24c0699a0018a52534\n" + + " 01bacfa905ca816573e56a2d2e067e9b7287533ba13a937dedb31fa44baced4076992361\n" + + " 0034ae31e619a170245199b3c5c39864859fe1b4c9717a07c30495bdfb98a0a002ccf56c\n" + + " 1286cef5041dede3c44cf16bf562c7448518026b3d8b9940680abd38a1575fd27b58da06\n" + + " 3bfac32c39c30869374c05c1aeb1898b6b303cc68be455346ee0af699636224a148ca2ae\n" + + " a10463111c709f69b69c70ce8538746698c4c60a9aef0030c7924ceec42a5d36816f545e\n" + + " ae13293460b3acb37ea0e13d70e4aa78686da398a8397c08eaf96882113fe4f7bad4da40\n" + + " b0501e1c753efe73053c87014e8661c33099afe8bede414a5b1aa27d8392b3e131e9a70c\n" + + " 1055878240cad0f40d5fe3cdf85236ead97e2a97448363b2808caafd516cd25052c5c362\n" + + " 543c2517e4acd0e60ec07163009b6425fc32277acee71c24bab53ed9f29e74c66a0a3564\n" + + " 955998d76b96a9a8b50d1635a4d7a67eb42df5644d330457293a8042f53cc7a69288f17e\n" + + " d55827e82b28e82665a86a14fbd96645eca8172c044f83bc0d8c0b4c8626985631ca87af\n" + + " 829068f1358963cb333664ca482763ba3b3bb208577f9ba6ac62c25f76592743b64be519\n" + + " 317714cb4102cb7b2f9a25b2b4f0615de31decd9ca55026d6da0b65111b16fe52feed8a4\n" + + " 87e144462a6dba93728f500b6ffc49e515569ef25fed17aff520507368253525860f58be\n" + + " 3be61c964604a6ac814e6935596402a520a4670b3d284318866593d15a4bb01c35e3e587\n" + + " ee0c67d2880d6f2407fb7a70712b838deb96c5d7bf2b44bcf6038ccbe33fbcf51a54a584\n" + + " fe90083c91c7a6d43d4fb15f48c60c2fd66e0a8aad4ad64e5c42bb8877c0ebec2b5e387c\n" + + " 8a988fdc23beb9e16c8757781e0a1499c61e138c21f216c29d076979871caa6942bafc09\n" + + " 0544bee99b54b16cb9a9a364d6246d9f42cce53c66b59c45c8f9ae9299a75d15180c3c95\n" + + " 2151a91b7a10772429dc4cbae6fcc622fa8018c63439f890630b9928db6bb7f9438ae406\n" + + " 5ed34d73d486f3f52f90f0807dc88dfdd8c728e954f1ac35c06c000ce41a0582580e3bb5\n" + + " 7b672972890ac5e7988e7850657116f1b57d0809aaedec0bede1ae148148311c6f7e3173\n" + + " 46e5189fb8cd635b986f8c0bdd27641c584b778b3a911a80be1c9692ab8e1bbb12839573\n" + + " cce19df183b45835bbb55052f9fc66a1678ef2a36dea78411e6c8d60501b4e60592d1369\n" + + " 8a943b509185db912e2ea10be06171236b327c71716094c964a68b03377f513a05bcd99c\n" + + " 1f346583bb052977a10a12adfc758034e5617da4c1276585e5774e1f3b9978b09d0e9c44\n" + + " d3bc86151c43aad185712717340223ac381d21150a04294e97bb13bbda21b5a182b6da96\n" + + " 9e19a7fd072737fa8e880a53c2428e3d049b7d2197405296ddb361912a7bcf4827ced611\n" + + " d0c7a7da104dde4322095339f64a61d5bb108ff0bf4d780cae509fb22c256914193ff734\n" + + " 9042581237d522828824ee3bdfd07fb03f1f942d2ea179fe722f06cc03de5b69859edb06\n" + + " eff389b27dce59844570216223593d4ba32d9abac8cd049040ef6534"); + static byte[] privEnc1 = Hex.decode("7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26"); + static byte[] ss1 = Hex.decode("d2df0522128f09dd8e2c92b1e905c793d8f57a54c3da25861f10bf4ca613e384"); + static byte[] ct1 = Hex.decode("b83aa828d4d62b9a83ceffe1d3d3bb1ef31264643c070c5798927e41fb07914a273f8f96\n" + + " e7826cd5375a283d7da885304c5de0516a0f0654243dc5b97f8bfeb831f68251219aabdd\n" + + " 723bc6512041acbaef8af44265524942b902e68ffd23221cda70b1b55d776a92d1143ea3\n" + + " a0c475f63ee6890157c7116dae3f62bf72f60acd2bb8cc31ce2ba0de364f52b8ed38c79d\n" + + " 719715963a5dd3842d8e8b43ab704e4759b5327bf027c63c8fa857c4908d5a8a7b88ac7f\n" + + " 2be394d93c3706ddd4e698cc6ce370101f4d0213254238b4a2e8821b6e414a1cf20f6c12\n" + + " 44b699046f5a01caa0a1a55516300b40d2048c77cc73afba79afeea9d2c0118bdf2adb88\n" + + " 70dc328c5516cc45b1a2058141039e2c90a110a9e16b318dfb53bd49a126d6b73f215787\n" + + " 517b8917cc01cabd107d06859854ee8b4f9861c226d3764c87339ab16c3667d2f49384e5\n" + + " 5456dd40414b70a6af841585f4c90c68725d57704ee8ee7ce6e2f9be582dbee985e038ff\n" + + " c346ebfb4e22158b6c84374a9ab4a44e1f91de5aac5197f89bc5e5442f51f9a5937b102b\n" + + " a3beaebf6e1c58380a4a5fedce4a4e5026f88f528f59ffd2db41752b3a3d90efabe46389\n" + + " 9b7d40870c530c8841e8712b733668ed033adbfafb2d49d37a44d4064e5863eb0af0a08d\n" + + " 47b3cc888373bc05f7a33b841bc2587c57eb69554e8a3767b7506917b6b70498727f16ea\n" + + " c1a36ec8d8cfaf751549f2277db277e8a55a9a5106b23a0206b4721fa9b3048552c5bd5b\n" + + " 594d6e247f38c18c591aea7f56249c72ce7b117afcc3a8621582f9cf71787e183dee0936\n" + + " 7976e98409ad9217a497df888042384d7707a6b78f5f7fb8409e3b535175373461b77600\n" + + " 2d799cbad62860be70573ecbe13b246e0da7e93a52168e0fb6a9756b895ef7f0147a0dc8\n" + + " 1bfa644b088a9228160c0f9acf1379a2941cd28c06ebc80e44e17aa2f8177010afd78a97\n" + + " ce0868d1629ebb294c5151812c583daeb88685220f4da9118112e07041fcc24d5564a99f\n" + + " dbde28869fe0722387d7a9a4d16e1cc8555917e09944aa5ebaaaec2cf62693afad42a3f5\n" + + " 18fce67d273cc6c9fb5472b380e8573ec7de06a3ba2fd5f931d725b493026cb0acbd3fe6\n" + + " 2d00e4c790d965d7a03a3c0b4222ba8c2a9a16e2ac658f572ae0e746eafc4feba023576f\n" + + " 08942278a041fb82a70a595d5bacbf297ce2029898a71e5c3b0d1c6228b485b1ade509b3\n" + + " 5fbca7eca97b2132e7cb6bc465375146b7dceac969308ac0c2ac89e7863eb8943015b243\n" + + " 14cafb9c7c0e85fe543d56658c213632599efabfc1ec49dd8c88547bb2cc40c9d38cbd30\n" + + " 99b4547840560531d0188cd1e9c23a0ebee0a03d5577d66b1d2bcb4baaf21cc7fef1e038\n" + + " 06ca96299df0dfbc56e1b2b43e4fc20c37f834c4af62127e7dae86c3c25a2f696ac8b589\n" + + " dec71d595bfbe94b5ed4bc07d800b330796fda89edb77be0294136139354eb8cd3759157\n" + + " 8f9c600dd9be8ec6219fdd507adf3397ed4d68707b8d13b24ce4cd8fb22851bfe9d63240\n" + + " 7f31ed6f7cb1600de56f17576740ce2a32fc5145030145cfb97e63e0e41d354274a079d3\n" + + " e6fb2e15"); - XWingKEMExtractor kemExtract = new XWingKEMExtractor((XWingPrivateKeyParameters)keyPair.getPrivate()); + static byte[] seed2 = Hex.decode("badfd6dfaac359a5efbb7bcc4b59d538df9a04302e10c8bc1cbf1a0b3a5120ea"); + static byte[] eseed2 = Hex.decode("17cda7cfad765f5623474d368ccca8af0007cd9f5e4c849f167a580b14aabdefaee7eef4\n" + + " 7cb0fca9767be1fda69419dfb927e9df07348b196691abaeb580b32d"); + static byte[] pubEnc2 = Hex.decode("0333285fa253661508c9fb444852caa4061636cb060e69943b431400134ae1fbc0228724\n" + + " 7cb38068bbb89e6714af10a3fcda6613acc4b5e4b0d6eb960c302a0253b1f507b596f088\n" + + " 4d351da89b01c35543214c8e542390b2bc497967961ef10286879c34316e6483b644fc27\n" + + " e8019d73024ba1d1cc83650bb068a5431b33d1221b3d122dc1239010a55cb13782140893\n" + + " f30aca7c09380255a0c621602ffbb6a9db064c1406d12723ab3bbe2950a21fe521b160b3\n" + + " 0b16724cc359754b4c88342651333ea9412d5137791cf75558ebc5c54c520dd6c622a059\n" + + " f6b332ccebb9f24103e59a297cd69e4a48a3bfe53a5958559e840db5c023f66c10ce2308\n" + + " 1c2c8261d744799ba078285cfa71ac51f44708d0a6212c3993340724b3ac38f63e82a889\n" + + " a4fc581f6b8353cc6233ac8f5394b6cca292f892360570a3031c90c4da3f02a895677390\n" + + " e60c24684a405f69ccf1a7b95312a47c844a4f9c2c4a37696dc10072a87bf41a2717d45b\n" + + " 2a99ce09a4898d5a3f6b67085f9a626646bcf369982d483972b9cd7d244c4f49970f766a\n" + + " 22507925eca7df99a491d80c27723e84c7b49b633a46b46785a16a41e02c538251622117\n" + + " 364615d9c2cdaa1687a860c18bfc9ce8690efb2a524cb97cdfd1a4ea661fa7d08817998a\n" + + " f838679b07c9db8455e2167a67c14d6a347522e89e8971270bec858364b1c1023b82c483\n" + + " cf8a8b76f040fe41c24dec2d49f6376170660605b80383391c4abad1136d874a77ef73b4\n" + + " 40758b6e7059add20873192e6e372e069c22c5425188e5c240cb3a6e29197ad17e87ec41\n" + + " a813af68531f262a6db25bbdb8a15d2ed9c9f35b9f2063890bd26ef09426f225aa1e6008\n" + + " d31600a29bcdf3b10d0bc72788d35e25f4976b3ca6ac7cbf0b442ae399b225d9714d0638\n" + + " a864bda7018d3b7c793bd2ace6ac68f4284d10977cc029cf203c5698f15a06b162d6c8b4\n" + + " fd40c6af40824f9c6101bb94e9327869ab7efd835dfc805367160d6c8571e3643ac70cba\n" + + " d5b96a1ad99352793f5af71705f95126cb4787392e94d808491a2245064ba5a7a30c0663\n" + + " 01392a6c315336e10dbc9c2177c7af382765b6c88eeab51588d01d6a95747f3652dc5b5c\n" + + " 401a23863c7a0343737c737c99287a40a90896d4594730b552b910d23244684206f0eb84\n" + + " 2fb9aa316ab182282a75fb72b6806cea4774b822169c386a58773c3edc8229d85905abb8\n" + + " 7ac228f0f7a2ce9a497bb5325e17a6a82777a997c036c3b862d29c14682ad325a9600872\n" + + " f3913029a1588648ba590a7157809ff740b5138380015c40e9fb90f0311107946f28e596\n" + + " 2e21666ad65092a3a60480cd16e61ff7fb5b44b70cf12201878428ef8067fceb1e1dcb49\n" + + " d66c773d312c7e53238cb620e126187009472d41036b702032411dc96cb750631df9d994\n" + + " 52e495deb4300df660c8d35f32b424e98c7ed14b12d8ab11a289ac63c50a24d52925950e\n" + + " 49ba6bf4c2c38953c92d60b6cd034e575c711ac41bfa66951f62b9392828d7b45aed377a\n" + + " c69c35f1c6b80f388f34e0bb9ce8167eb2bc630382825c396a407e905108081b444ac8a0\n" + + " 7c2507376a750d18248ee0a81c4318d9a38fc44c3b41e8681f87c34138442659512c4127\n" + + " 6e1cc8fc4eb66e12727bcb5a9e0e405cdea21538d6ea885ab169050e6b91e1b69f7ed34b\n" + + " cbb48fd4c562a576549f85b528c953926d96ea8a160b8843f1c89c62"); + static byte[] privEnc2 = Hex.decode("badfd6dfaac359a5efbb7bcc4b59d538df9a04302e10c8bc1cbf1a0b3a5120ea"); + static byte[] ss2 = Hex.decode("f2e86241c64d60f6649fbc6c5b7d17180b780a3f34355e64a85749949c45f150"); + static byte[] ct2 = Hex.decode("c93beb22326705699bbc3d1d0aa6339be7a405debe61a7c337e1a91453c097a6f77c1306\n" + + " 39d1aaeb193175f1a987aa1fd789a63c9cd487ebd6965f5d8389c8d7c8cfacbba4b44d2f\n" + + " be0ae84de9e96fb11215d9b76acd51887b752329c1a3e0468ccc49392c1e0f1aad61a73c\n" + + " 10831e60a9798cb2e7ec07596b5803db3e243ecbb94166feade0c9197378700f8eb65a43\n" + + " 502bbac4605992e2de2b906ab30ba401d7e1ff3c98f42cfc4b30b974d3316f331461ac05\n" + + " f43e0db7b41d3da702a4f567b6ee7295199c7be92f6b4a47e7307d34278e03c872fb4864\n" + + " 7c446a64a3937dccd7c6d8de4d34b9dea45a0b065ef15b9e94d1b6df6dca7174d9bc9d14\n" + + " c6225e3a78a58785c3fe4e2fe6a0706f3365389e4258fbb61ecf1a1957715982b3f18444\n" + + " 24e03acd83da7eee50573f6cd3ff396841e9a00ad679da92274129da277833d0524674fe\n" + + " ea09a98d25b888616f338412d8e65e151e65736c8c6fb448c9260fa20e7b2712148bcd3a\n" + + " 0853865f50c1fc9e4f201aee3757120e034fd509d954b7a749ff776561382c4cb64cebcb\n" + + " b6aa82d04cd5c2b40395ecaf231bde8334ecfd955d09efa8c6e7935b1cb0298fb8b6740b\n" + + " e4593360eed5f129d59d98822a6cea37c57674e919e84d6b90f695fca58e7d29092bd70f\n" + + " 7c97c6dfb021b9f87216a6271d8b144a364d03b6bf084f972dc59800b14a2c008bbd0992\n" + + " b5b82801020978f2bdddb3ca3367d876cffb3548dab695a29882cae2eb5ba7c847c3c71b\n" + + " d0150fa9c33aac8e6240e0c269b8e295ddb7b77e9c17bd310be65e28c0802136d086777b\n" + + " e5652d6f1ac879d3263e9c712d1af736eac048fe848a577d6afaea1428dc71db8c430edd\n" + + " 7b584ae6e6aeaf7257aff0fd8fe25c30840e30ccfa1d95118ef0f6657367e9070f3d97a2\n" + + " e9a7bae19957bd707b00e31b6b0ebb9d7df4bd22e44c060830a194b5b8288353255b5295\n" + + " 4ff5905ab2b126d9aa049e44599368c27d6cb033eae5182c2e1504ee4e3745f51488997b\n" + + " 8f958f0209064f6f44a7e4de5226d5594d1ad9b42ac59a2d100a2f190df873a2e141552f\n" + + " 33c923b4c927e8747c6f830c441a8bd3c5b371f6b3ab8103ebcfb18543aefc1beb6f776b\n" + + " bfd5344779f4aa23daaf395f69ec31dc046b491f0e5cc9c651dfc306bd8f2105be7bc7a4\n" + + " f4e21957f87278c771528a8740a92e2daefa76a3525f1fae17ec4362a2700988001d8600\n" + + " 11d6ca3a95f79a0205bcf634cef373a8ea273ff0f4250eb8617d0fb92102a6aa09cf0c3e\n" + + " e2cad1ad96438c8e4dfd6ee0fcc85833c3103dd6c1600cd305bc2df4cda89b55ca237a3f\n" + + " 9c3f82390074ff30825fc750130ebaf13d0cf7556d2c52a98a4bad39ca5d44aaadeaef77\n" + + " 5c695e64d06e966acfcd552a14e2df6c63ae541f0fa88fc48263089685704506a21a0385\n" + + " 6ce65d4f06d54f3157eeabd62491cb4ac7bf029e79f9fbd4c77e2a3588790c710e611da8\n" + + " b2040c76a61507a8020758dcc30894ad018fef98e401cc54106e20d94bd544a8f0e1fd05\n" + + " 00342d123f618aa8c91bdf6e0e03200693c9651e469aee6f91c98bea4127ae66312f4ae3\n" + + " ea155b67"); - byte[] decryptedSharedSecret = kemExtract.extractSecret(secretEncap.getEncapsulation()); + static byte[] seed3 = Hex.decode("ef58538b8d23f87732ea63b02b4fa0f4873360e2841928cd60dd4cee8cc0d4c9"); + static byte[] eseed3 = Hex.decode("22a96188d032675c8ac850933c7aff1533b94c834adbb69c6115bad4692d8619f90b0cdf\n" + + " 8a7b9c264029ac185b70b83f2801f2f4b3f70c593ea3aeeb613a7f1b"); + static byte[] pubEnc3 = Hex.decode("36244278824f77c621c660892c1c3886a9560caa52a97c461fd3958a598e749bbc8c7798\n" + + " ac8870bac7318ac2b863000ca3b0bdcbbc1ccfcb1a30875df9a76976763247083e646ccb\n" + + " 2499a4e4f0c9f4125378ba3da1999538b86f99f2328332c177d1192b849413e655101289\n" + + " 73f679d23253850bb6c347ba7ca81b5e6ac4c574565c731740b3cd8c9756caac39fba7ac\n" + + " 422acc60c6c1a645b94e3b6d21485ebad9c4fe5bb4ea0853670c5246652bff65ce8381cb\n" + + " 473c40c1a0cd06b54dcec11872b351397c0eaf995bebdb6573000cbe2496600ba76c8cb0\n" + + " 23ec260f0571e3ec12a9c82d9db3c57b3a99e8701f78db4fabc1cc58b1bae02745073a81\n" + + " fc8045439ba3b885581a283a1ba64e103610aabb4ddfe9959e7241011b2638b56ba6a982\n" + + " ef610c514a57212555db9a98fb6bcf0e91660ec15dfa66a67408596e9ccb97489a09a073\n" + + " ffd1a0a7ebbe71aa5ff793cb91964160703b4b6c9c5390842c2c905d4a9f88111fed5787\n" + + " 4ba9b03cf611e70486edf539767c7485189d5f1b08e32a274dc24a39c918fd2a4dfa946a\n" + + " 8c897486f2c974031b2804aabc81749db430b85311372a3b8478868200b40e043f7bf4a1\n" + + " c3a08b0771b431e342ee277410bca034a0c77086c8f702b3aed2b4108bbd3af471633373\n" + + " a1ac74b128b148d1b9412aa66948cac6dc6614681fda02ca86675d2a756003c49c50f06e\n" + + " 13c63ce4bc9f321c860b202ee931834930011f485c9af86b9f642f0c353ad305c66996b9\n" + + " a136b753973929495f0d8048db75529edcb4935904797ac66605490f66329c3bb36b8573\n" + + " a3e00f817b3082162ff106674d11b261baae0506cde7e69fdce93c6c7b59b9d4c759758a\n" + + " cf287c2e4c4bfab5170a9236daf21bdb6005e92464ee8863f845cf37978ef19969264a51\n" + + " 6fe992c93b5f7ae7cb6718ac69257d630379e4aac6029cb906f98d91c92d118c36a6d161\n" + + " 15d4c8f16066078badd161a65ba51e0252bc358c67cd2c4beab2537e42956e08a39cfccf\n" + + " 0cd875b5499ee952c83a162c68084f6d35cf92f71ec66baec74ab87e2243160b64df54af\n" + + " b5a07f78ec0f5c5759e5a4322bca2643425748a1a97c62108510c44fd9089c5a7c14e57b\n" + + " 1b77532800013027cff91922d7c935b4202bb507aa47598a6a5a030117210d4c49c17470\n" + + " 0550ad6f82ad40e965598b86bc575448eb19d70380d465c1f870824c026d74a2522a799b\n" + + " 7b122d06c83aa64c0974635897261433914fdfb14106c230425a83dc8467ad8234f086c7\n" + + " 2a47418be9cfb582b1dcfa3d9aa45299b79fff265356d8286a1ca2f3c2184b2a70d15289\n" + + " e5b202d03b64c735a867b1154c55533ff61d6c296277011848143bc85a4b823040ae025a\n" + + " 29293ab77747d85310078682e0ba0ac236548d905a79494324574d417c7a3457bd5fb525\n" + + " 3c4876679034ae844d0d05010fec722db5621e3a67a2d58e2ff33b432269169b51f9dcc0\n" + + " 95b8406dc1864cf0aeb6a2132661a38d641877594b3c51892b9364d25c63d637140a2018\n" + + " d10931b0daa5a2f2a405017688c991e586b522f94b1132bc7e87a63246475816c8be9c62\n" + + " b731691ab912eb656ce2619225663364701a014b7d0337212caa2ecc731f34438289e0ca\n" + + " 4590a276802d980056b5d0d316cae2ecfea6d86696a9f161aa90ad47eaad8cadd31ae3cb\n" + + " c1c013747dfee80fb35b5299f555dcc2b787ea4f6f16ffdf66952461"); + static byte[] privEnc3 = Hex.decode("ef58538b8d23f87732ea63b02b4fa0f4873360e2841928cd60dd4cee8cc0d4c9"); + static byte[] ss3 = Hex.decode("953f7f4e8c5b5049bdc771d1dffada0dd961477d1a2ae0988baa7ea6898d893f"); + static byte[] ct3 = Hex.decode("0d2e38cbf17a2e2e4e0c87a94ca1e7701ae1552e02509b3b00f9c82c39e3fd435b05b912\n" + + " 75f47abc9f1021429a26a346598cd6cd9efdc8adc1dbc35036d0290bf89733c835309202\n" + + " 232f9bf652ea82f3d49280d6e8a3bd3135fb883445ab5b074d949c5350c7c7d6ac59905b\n" + + " dbfce6639da8a9d4b390ecc1dd05522d2956f2d37a05593996e5cb3fd8d5a9eb52417732\n" + + " e1ebf545588713b4760227115aab7ada178dadbca583b26cfedba2888a0c95b950bf07f7\n" + + " 50d7aa8103798aa3470a042c0105c6a037de2f9ebc396021b2ba2c16aba696fbac3454dc\n" + + " 8e053b8fa55edd45215eeb57a1eab9106fb426b375a9b9e5c3419efc7610977e72640f9f\n" + + " d1b2ec337de33c35e5a7581b2aae4d8ee86d2e0ebf82a1350714de50d2d788687878a196\n" + + " 44ae4e3175e8d59dc90171b3badeff65aeaf600e5e5483a3595fdeb40cbafcbd040c29a2\n" + + " f6900533ae999d24f54dfcef748c30313ca447cdddfa57ad78eaa890e90f3f7bf8d11696\n" + + " 8a5713cc75fd0408f36364fa265c5617039304eaeac4cbee6fc49b9fe2276768cdbec2d7\n" + + " 3a507b543cc028dc1b154b7c2b0412254c466a94a8d6ea3a47e1743469bd45c08f54cf96\n" + + " 5884be3696e961741ede16e3b1bc4feb93faaef31d911dc0cb3fa90bcda991959a9d2cbc\n" + + " 817a5564c5c01177a59e9577589ea344d60cf5b0aa39f31863febd54603ca87ad2363c76\n" + + " 6642a3f52557bcd9e4c05a87665842ba336b83156a677030f0bad531a8387a1486a599ca\n" + + " a748fcea7bdc1eb63f3cdb97173551ab7c1c36b69acbbdb2ff7a1e7bc70439632ddc67b9\n" + + " 7f3da1f59b3c1588515957cb8a2f86ab635ce0a78b7cdf24eac3445e8fc8b79ba04da9e9\n" + + " 03f49a7d912c197a84b4cfabc779b97d24788419bcf58035db99717edb9fd1c1df8c4005\n" + + " f700eabba528ddfcbaeda6dd30754f795948a34c9319ab653524b19931c7900c4167988a\n" + + " f52292fe902e746b524d20ceffb4339e8f5535f41cf35f0f8ea8b4a7b949c5d2381116b1\n" + + " 46e9b913a83a3fa1c65ff9468c835fe4114554a6c66a80e1c9a6bb064b380be3c95e5595\n" + + " ec979bf1c85aa938938e3f10e72b0c87811969e8ab0d83de0b0604c4016ac3a015e19514\n" + + " 089271bdc6ebf2ec56fab6018e44de749b4c36cc235e370da8466dbdc253542a2d704eb3\n" + + " 316fd70d5d238cb7eaaf05966d973f62c7ef43b9a806f4ed213ac8099ea15d61a9024441\n" + + " 60883f6bf441a3e1469945c9b79489ea18390f1ebc83caca10bdb8f2429877b52bd44c94\n" + + " a228ef91c392ef5398c5c83982701318ccedab92f7a279c4fddebaa7fe5e986c48b7d813\n" + + " 5b3fe4cd15be2004ce73ff86b1e55f8ecd6ba5b8114315f8e716ef3ab0a64564a4644651\n" + + " 166ebd68b1f783e2e443dbccadfe189368647629f1a12215840b7f1d026de2f665c2eb02\n" + + " 3ff51a6df160912811ee03444ae4227fb941dc9ec4f31b445006fd384de5e60e0a5061b5\n" + + " 0cb1202f863090fc05eb814e2d42a03586c0b56f533847ac7b8184ce9690bc8dece32a88\n" + + " ca934f541d4cc520fa64de6b6e1c3c8e03db5971a445992227c825590688d203523f5271\n" + + " 61137334"); - assertTrue(Arrays.areEqual(Hex.decode(expectedSecret), decryptedSharedSecret)); + public void testKEM() + { + kemTest(seed1, eseed1, pubEnc1, privEnc1, ss1, ct1); + kemTest(seed2, eseed2, pubEnc2, privEnc2, ss2, ct2); + kemTest(seed3, eseed3, pubEnc3, privEnc3, ss3, ct3); } - public void testKeyEncoding() - throws Exception + private void kemTest(byte[] seed, byte[] eseed, byte[] pubEnc, byte[] privEnc, byte[] ss, byte[] ct) { - byte[] pubEnc = Hex.decode("a72c2d9c843ee9f8313ecc7f86d6294d59159d9a879a542e260922adf999051cc45200c9ffdb60449c49465979272367c083a7d6267a3ed7a7fd47957c219327f7ca73a4007e1627f00b11cc80573c15aee6640fb8562dfa6b240ca0ad351ac4ac155b96c14c8ab13dd262cdfd51c4bb5572fd616553d17bdd430acbea3e95f0b698d66990ab51e5d03783a8b3d278a5720454cf9695cfdca08485ba099c51cd92a7ea7587c1d15c28e609a81852601b0604010679aa482d51261ec36e36b8719676217fd74c54786488f4b4969c05a8ba27ca3a77cce73b965923ca554e422b9b61f4754641608ac16c9b8587a32c1c5dd788f88b36b717a46965635deb67f45b129b99070909c93eb80b42c2b3f3f70343a7cf37e8520e7bcfc416aca4f18c7981262ba2bfc756ae03278f0ec66dc2057696824ba6769865a601d7148ef6f54e5af5686aa2906f994ce38a5e0b938f239007003022c03392df3401b1e4a3a7ebc6161449f73374c8b0140369343d9295fdf511845c4a46ebaab6ca5492f6800b98c0cc803653a4b1d6e6aaed1932bacc5fefaa818ba502859ba5494c5f5402c8536a9c4c1888150617f80098f6b2a99c39bc5dc7cf3b5900a21329ab59053abaa64ed163e859a8b3b3ca3359b750ccc3e710c7ac43c8191cb5d68870c06391c0cb8aec72b897ac6be7fbaacc676ed66314c83630e89448c88a1df04aceb23abf2e409ef333c622289c18a2134e650c45257e47475fa33aa537a5a8f7680214716c50d470e3284963ca64f54677aec54b5272162bf52bc8142e1d4183fc017454a6b5a496831759064024745978cbd51a6cedc8955de4cc6d363670a47466e82be5c23603a17bf22acdb7cc984af08c87e14e27753cf587a8ec3447e62c649e887a67c36c9ce98721b697213275646b194f36758673a8ed11284455afc7a8529f69c97a3c2d7b8c636c0ba55614b768e624e712930f776169b01715725351bc74b47395ed52b25a1313c95164814c34c979cbdfab85954662cab485e75087a98cc74bb82ca2d1b5bf2803238480638c40e90b43c7460e7aa917f010151fab1169987b372abb59271f7006c24e60236b84b9ddd600623704254617fb498d89e58b0368bcb2103e79353eb587860c1422e476162e425bc2381db82c6592737e1dd602864b0167a71ec1f223305c02fe25052af2b3b5a55a0d7a2022d9a798dc0c5874a98702aaf4054c5d80338a5248b5b7bd09c53b5e2a084b047d277a861b1a73bb51488de04ef573c85230a0470b73175c9fa50594f66a5f50b4150054c93b68186f8b5cbc49316c8548a642b2b36a1d454c7489ac33b2d2ce6668096782a2c1e0866d21a65e16b585e7af8618bdf3184c1986878508917277b93e10706b1614972b2a94c7310fe9c708c231a1a8ac8d9314a529a97f469bf64962d820648443099a076d55d4cea824a58304844f99497c10a25148618a315d72ca857d1b04d575b94f85c01d19bef211bf0aa3362e7041fd16596d808e867b44c4c00d1cda3418967717f147d0eb21b42aaee74ac35d0b92414b958531aadf463ec6305ae5ecaf79174002f26ddecc813bf32672e8529d95a4e730a7ab4a3e8f8a8af979a665eafd465fc64a0c5f8f3f9003489415899d59a543d8208c54a3166529b539227001e4f285d5113a537f141fa23cb2770845ac28fc9d70df557415f3bc00e735"); - byte[] privEnc = Hex.decode("07638fb69868f3d320e5862bd96933feb311b362093c9b5d50170bced43f1b536d9a204bb1f22695950ba1f2a9e8eb828b284488760b3fc84faba04275d5628e39c5b2471374283c503299c0ab49b66b8bbb56a4186624f919a2ba59bb08d8551880c2befc4f87f25f59ab587a79c327d792d54c974a69262ff8a78938289e9a87b688b083e0595fe218b6bb1505941ce2e81a5a64c5aac60417256985349ee47a52420a5f97477b7236ac76bc70e8288729287ee3e34a3dbc3683c0b7b10029fc203418537e7466ba6385a8ff301ee12708f82aaa1e380fc7a88f8f205ab7e88d7e95952a55ba20d09b79a47141d62bf6eb7dd307b08eca13a5bc5f6b68581c6865b27bbcddab142f4b2cbff488c8a22705faa98a2b9eea3530c76662335cc7ea3a00777725ebcccd2a4636b2d9122ff3ab77123ce0883c1911115e50c9e8a94194e48dd0d09cffb3adcd2c1e92430903d07adbf00532031575aa7f9e7b5a1f3362dec936d4043c05f2476c07578bc9cbaf2ab4e382727ad41686a96b2548820bb03b32f11b2811ad62f489e951632aba0d1df89680cc8a8b53b481d92a68d70b4ea1c3a6a561c0692882b5ca8cc942a8d495afcb06de89498fb935b775908fe7a03e324d54cc19d4e1aabd3593b38b19ee1388fe492b43127e5a504253786a0d69ad32601c28e2c88504a5ba599706023a61363e17c6b9bb59bdc697452cd059451983d738ca3fd034e3f5988854ca05031db09611498988197c6b30d258dfe26265541c89a4b31d6864e9389b03cb74f7ec4323fb9421a4b9790a26d17b0398a26767350909f84d57b6694df830664ca8b3c3c03ed2ae67b89006868a68527ccd666459ab7f056671000c6164d3a7f266a14d97cbd7004d6c92caca770b844a4fa9b182e7b18ca885082ac5646fcb4a14e1685feb0c9ce3372ab95365c04fd83084f80a23ff10a05bf15f7fa5acc6c0cb462c33ca524fa6b8bb359043ba68609eaa2536e81d08463b19653b5435ba946c9addeb202b04b031cc960dcc12e4518d428b32b257a4fc7313d3a7980d80082e934f9d95c32b0a0191a23604384dd9e079bbbaa266d14c3f756b9f2133107433a4e83fa7187282a809203a4faf841851833d121ac383843a5e55bc2381425e16c7db4cc9ab5c1b0d91a47e2b8de0e582c86b6b0d907bb360b97f40ab5d038f6b75c814b27d9b968d419832bc8c2bee605ef6e5059d33100d90485d378450014221736c07407cac260408aa64926619788b8601c2a752d1a6cbf820d7c7a04716203225b3895b9342d147a8185cfc1bb65ba06b4142339903c0ac4651385b45d98a8b19d28cd6bab088787f7ee1b12461766b43cbccb96434427d93c065550688f6948ed1b5475a425f1b85209d061c08b56c1cc069f6c0a7c6f29358cab911087732a649d27c9b98f9a48879387d9b00c25959a71654d6f6a946164513e47a75d005986c2363c09f6b537eca78b9303a5fa457608a586a653a347db04dfcc19175b3a301172536062a658a95277570c8852ca8973f4ae123a334047dd711c8927a634a03388a527b034bf7a8170fa702c1f7c23ec32d18a2374890be9c787a9409c82d192c4bb705a2f996ce405da72c2d9c843ee9f8313ecc7f86d6294d59159d9a879a542e260922adf999051cc45200c9ffdb60449c49465979272367c083a7d6267a3ed7a7fd47957c219327f7ca73a4007e1627f00b11cc80573c15aee6640fb8562dfa6b240ca0ad351ac4ac155b96c14c8ab13dd262cdfd51c4bb5572fd616553d17bdd430acbea3e95f0b698d66990ab51e5d03783a8b3d278a5720454cf9695cfdca08485ba099c51cd92a7ea7587c1d15c28e609a81852601b0604010679aa482d51261ec36e36b8719676217fd74c54786488f4b4969c05a8ba27ca3a77cce73b965923ca554e422b9b61f4754641608ac16c9b8587a32c1c5dd788f88b36b717a46965635deb67f45b129b99070909c93eb80b42c2b3f3f70343a7cf37e8520e7bcfc416aca4f18c7981262ba2bfc756ae03278f0ec66dc2057696824ba6769865a601d7148ef6f54e5af5686aa2906f994ce38a5e0b938f239007003022c03392df3401b1e4a3a7ebc6161449f73374c8b0140369343d9295fdf511845c4a46ebaab6ca5492f6800b98c0cc803653a4b1d6e6aaed1932bacc5fefaa818ba502859ba5494c5f5402c8536a9c4c1888150617f80098f6b2a99c39bc5dc7cf3b5900a21329ab59053abaa64ed163e859a8b3b3ca3359b750ccc3e710c7ac43c8191cb5d68870c06391c0cb8aec72b897ac6be7fbaacc676ed66314c83630e89448c88a1df04aceb23abf2e409ef333c622289c18a2134e650c45257e47475fa33aa537a5a8f7680214716c50d470e3284963ca64f54677aec54b5272162bf52bc8142e1d4183fc017454a6b5a496831759064024745978cbd51a6cedc8955de4cc6d363670a47466e82be5c23603a17bf22acdb7cc984af08c87e14e27753cf587a8ec3447e62c649e887a67c36c9ce98721b697213275646b194f36758673a8ed11284455afc7a8529f69c97a3c2d7b8c636c0ba55614b768e624e712930f776169b01715725351bc74b47395ed52b25a1313c95164814c34c979cbdfab85954662cab485e75087a98cc74bb82ca2d1b5bf2803238480638c40e90b43c7460e7aa917f010151fab1169987b372abb59271f7006c24e60236b84b9ddd600623704254617fb498d89e58b0368bcb2103e79353eb587860c1422e476162e425bc2381db82c6592737e1dd602864b0167a71ec1f223305c02fe25052af2b3b5a55a0d7a2022d9a798dc0c5874a98702aaf4054c5d80338a5248b5b7bd09c53b5e2a084b047d277a861b1a73bb51488de04ef573c85230a0470b73175c9fa50594f66a5f50b4150054c93b68186f8b5cbc49316c8548a642b2b36a1d454c7489ac33b2d2ce6668096782a2c1e0866d21a65e16b585e7af8618bdf3184c1986878508917277b93e10706b1614972b2a94c7310fe9c708c231a1a8ac8d9314a529a97f469bf64962d820648443099a076d55d4cea824a58304844f99497c10a25148618a315d72ca857d1b04d575b94f85c01d19bef211bf0aa3362e7041fd16596d808e867b44c4c00d1cda3418967717f147d0eb21b42aaee74ac35d0b92414b958531aadf463ec6305ae5ecaf79174002f26ddecc813bf32672e8529d95a4e730a7ab4a3e8f8a8af979a665eafd465fc64a0c5f8f3f9003489415899d59a543d8208c54a3166529b53922d4ec143b50f01423b177895edee22bb739f647ecf85f50bc25ef7b5a725dee86b505d7cfad1b497499323c8686325e4792f267aafa3f87ca60d01cb54f29202a38784ccb7ebcdcfd45542b7f6af778742e0f4479175084aa488b3b743406786a"); - String temp = "061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"; - String expectedSecret = "e5015e7e9b71e3a0436b159a042b14cb5b63435eee3b8db95f1e8fcce44632a8"; - - byte[] seed = Hex.decode(temp); - - NISTSecureRandom random = new NISTSecureRandom(seed, null); + SecureRandom random = new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(seed)}); + XWingKeyPairGenerator keyGen = new XWingKeyPairGenerator(); + keyGen.init(new XWingKeyGenerationParameters(random)); + AsymmetricCipherKeyPair keyPair = keyGen.generateKeyPair(); - byte[] coins = new byte[96]; - random.nextBytes(coins); XWingPublicKeyParameters publicKey = new XWingPublicKeyParameters(pubEnc); + assertTrue(Arrays.areEqual(((XWingPublicKeyParameters)keyPair.getPublic()).getEncoded(), pubEnc)); + assertTrue(Arrays.areEqual(((XWingPrivateKeyParameters)keyPair.getPrivate()).getEncoded(), privEnc)); XWingPrivateKeyParameters privKey = new XWingPrivateKeyParameters(privEnc); - + random = new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(eseed)}); XWingKEMGenerator kemGen = new XWingKEMGenerator(random); SecretWithEncapsulation secretEncap = kemGen.generateEncapsulated(publicKey); byte[] sharedSecret = secretEncap.getSecret(); - - assertTrue(Arrays.areEqual(Hex.decode(expectedSecret), sharedSecret)); - + byte[] encapsulation = secretEncap.getEncapsulation(); + assertTrue(Arrays.areEqual(ss, sharedSecret)); + assertTrue(Arrays.areEqual(encapsulation, ct)); XWingKEMExtractor kemExtract = new XWingKEMExtractor(privKey); - byte[] decryptedSharedSecret = kemExtract.extractSecret(secretEncap.getEncapsulation()); + byte[] decryptedSharedSecret = kemExtract.extractSecret(encapsulation); - assertTrue(Arrays.areEqual(Hex.decode(expectedSecret), decryptedSharedSecret)); + assertTrue(Arrays.areEqual(ss, decryptedSharedSecret)); } } diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTeslaKeyEncodingTests.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTeslaKeyEncodingTests.java deleted file mode 100644 index 73817df3d6..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/qtesla/QTeslaKeyEncodingTests.java +++ /dev/null @@ -1,849 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.qtesla; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.util.ArrayList; - -import junit.framework.TestCase; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Longs; -import org.bouncycastle.util.encoders.Hex; - -public class QTeslaKeyEncodingTests - extends TestCase -{ - /** - * QTesla 1p Private key encoding. - */ - public void testDecodeEncodePrivateKeyQT1P() - { - /* - * There is no directly specified (i.e. in pack.c) decoder for private keys for this type. - * The following values for the s and e polynomials were taken from the C reference - * implementation. - */ - - byte[] seed = Hex.decode("CFC6B92DF4B09954DD20371C1E88087D73F0C885A68327486A812A1C9C36DA7E4F5C254B6292FB5C3DB9561B8793D8AE3E1611423AC0A9F8CFC13E1C85FEC6B5"); - byte[] publicKey = Hex.decode("7561DAADC32E5C51E5C7AB83FB32FAA58E32A0D1E5134A07BBBC3AE889C85470D024D22EE8A269A9772C24B5971CEC2AD55A846C6D8DD917B76223B0799227F89FE8EB91020CA49BD528FF1915ED00D9F9709740A13110864F11C24CF0DD8DEA29BF288DCFE4B1CEB12A7135C5142D7F51376456892BEDF33A295D6D70AD058C51D565E8097D26440D57DDA86AD04C1E7ED45946654ADFE9F46A2D2CA0BEA6B2E57046D734A3989BD6B2C42B9413646C1A2F1B6C3E55502D8780681D1553601130BF98D26EA05C216E7C98FF0D5FC03D10384DC6E29316921F50AD19FF96772F998DA91AFC45CB3A00E67BAA713E2825C6DC2A0C0E8778444870A0483E588EDEC82199DA34B636966A85D9001C446C425415C8F8269697EAD5D69DBA92F77228808FE2AC5485612B0F28862D9EDA5D32D5CDD840BD45649C1D7C50044CC017D87E8D1012FE2EA0E26F2710467A13230C73F485F26154825038BEE477CE3154C36468B22124038C3C0A8E41C8681B20BFA3493CF88299E70D0D3FBCB5CF7EB82D39656A27FDA96E62CC84FE9A83DA858A9982F01803872833C48376E04C4E319744EA26EFD8FD4A1834B5058986DEF96CD22F4A30652A543D640C424AD107B54EC7D5E9244328BCBD166100969A54B003DB5F1D30B7D8462941A5C2E6E166563C1D7C7222D167E2627C98EB0F4274FB098C1BB288C8A12180E0A2F32596B54E3E68520B625B87B47F5E2FF64A1490CEC86E82E5E94359FDF6782E2138229D2C1EFF49B6BB6A722D033FF80BBA7A2CBC90D40E39E2E6777E062F4603BF87C407E2C20DD67E67DA5FB1AF696A05CB301B78A91A54F0881D5459E35E4070E0FA605C43E98C472C76DF9C31AAC8A7473DE2B989F297B230B751B4F32B61CF089F77317285D302011D7D6BABCF4C07C0C70AD4DE3E99C46EF595EA9A61A080DD48C74A0C961513C845DB6A5811750145D081B4D4E76DE5B15DBA5C1626289345049D5CB8771C7C129DA1C5DD8BEE596321647E853BCF8D661D194A1023845F420066244F6BB5A0D50533579AA0DB5A726DAB32EA2B35261AE5B6D0DEB12C31A79242E2D952AA1A1774CB90AE815BE9613A93B30AF30374F5C8181F54B4F5D56E07232F68C6D52B94BA64ED1B2B7CA37EE6C730E03816689853224242F0297A017DCE955C8B8D1B41BB3B12665759584D3373BC2C77999205ED56F6E8B6AAEC3346D1528C2AE938CE21C24400ECBC4BB520958E3303374C68A21D403A6E6F05DAB6A8C03FF07FF5B83A216B2EBBF8E357BCE51A52A56EAAF6B6F6D34B8BCE02E22BB67CAC6629A8E8C3F9F4E7A3AEE3B9AED01B2E3BCB3FE566E3DFFD8C4A9830AEF3D30DE63B5208A32433A4C42633C4840EC5493E891D22F409E35F02CFAE46A9D3DEED6C221916F9B27BD7EE3C1CC3C961E59B3DB42A59213FFB168DD170393832ACA8C79B52C194571681F0E8AAE2DB99C1201632659AE136E3B085985DC94981A5503D950E041763AD485E253DD8B329283929E2132EFA6B9EB08E79AF6027D6E2E7E30E3D6B785256BA2E012D003AB5C07FC4A0EAB484991B3CBC3B03346409491A876C82548E2BB253E344E80415E4625D3BF15975B59DC36FA00A7FD894D363172DB8C2ABE40364F549A00C5D5FA8B534E0CAE6A9AE83CB5E4BE6BAEE126B755C9CB8F76C1C8A6E6FE2567C1CBDA68370D4D8465D8B360880601206CAC0C9D0B67C0261A0E7D132CE9C4EBE21250F7F197480FD5E0D8DA83068EFA8B35475733FAB080BB888E1D1D89D124AEFD81BAB3D970FE059674B6E71455517B9BA322A236D272144963DA4A934A1D59D19F05FEECDF0F1E390376801E0454971E30C47109944BB4DF414E19326B8BA2013D5F6B3FA20188E5E9BCC63ED8BC55D8D7D3A086193F9E80DD32381B26BD534D34F298DC06378EDBA2E614E8C3D886297AD1B2B59FF78B8FEC0760336C5207082D82ADA01CAE49AE6500AD992B7FC0631491B909F449618E5F82B18995BC926F46BBEEE152AB2706521AEE3574295F26FC01A7AD154673B2D3B500E1043FF51340BAAA70CF8B3A65C65811318AC7B4A32A9519A00ACE331959AED26F86CACCD7A952F9D40E66FC31224AA1BD280F89A6B16F46AC39C5F6D709868F92D0FA519D39827D215D8BA7F2FA6B4DA67D5A791984E7A1BDB04A5A7B024762952121C109AA318FD2CE88EFAD90FFCC17419C2892C916BA7E7C482ACF41E5C386290F1174AE5C5BECC5A0D21E23B40FEAF220CB9A58AF8A5B5910DBE823359150388A4B0046090287B760B3978433317F4C2E1AF2A5BC87EFD2F59931F558ED226CEA7174B9BD4D1BBF6A10CE2C2D827DC4D36B2096B9309D42EA8D45B5AC2B1F7049CCA4078D4751B6B03DB06B8BEF3E119589CA61D7FE308AEF4561C4EE87DEAC2DB94C38C4760916D27E6BB2C169D1C88D35616F8C5EA6EDD4D48D6A5CFF409DD67D5BF704B832C3454A8BD14568B93F760EC179ECDED970C46BE39D5960352D2F5B3959758CA7A10C88E961D474449CCC21394D2099F6110BEE145E7005DA5501C0DFE3DF1094ACF99951A2974808A60108643E9F4177827A3F616009FA67E21F54C363BF8F162F33254D6CFED5E7C0D4AFCF9854620B9632FBE147284C6739F5FB4F211C20B1D9982215C2C4B1C02CFD041F8281E429940E8FCB66C32B694C2611D8D7F50A751D3969C2A3AB1FB2553CF0B26C0478C2988D9008EF4A1777E9F7F16122BDF208A5044BE728E9D928A52F133C1CC462984590D44E00FF7AE1254928A006054D008E780E5D10BA7E11E17E296D43D21F64544AAAF27E6AF9D4C7A381E4CC2873F358B3541454BA2D594602DA71273F50F99201CE60F93E1431D82D5402E8654206DFC651A3E36CA854A9B18E8DF0CE2809FA89BB465C68475020C51A773107D9B367E3C9A82370773A498FABAE4AE84D7685C9329FB226E0F5F6173C5107AF143BA84BB2CD9A9D2CEF930C5F8055A4E71C1CED7538F3D8FD194EDA2C98FFF3005BE8A73D09C7CBC8DDA07F4066BDCBFF23A1838520AEE0A28E69DE30019DA6AF61FE52A6FF10B4A9215F8F9ABBC9FB5081CA33463F891A53DC91E252E90EF4B0D72A35923208CA48C3793347F3D5FD28DE56538586D2C2C6C1FD50C4160D67DF11254BB36CB94B835734F5B831BF12845155B49FBE3B0F44CC5D6782983D9478C6B3A9F30626A797A2CDF8911F5BFA90E611B39B29314C9E4CB7F12A69D6DAA1916667AAC5AEA693B70BD741928014ACCD125137488BEE48BAABB02DA3C6A9604A16BF4D19F1C0D87FAC94840C721EDDF03CD8A841D2EFA5D52BAFB50726B45A476C47E251601B0127C092A4EB8A66A0CB7A2DB5503394AD36D54F37CC6EC73317E38AF9FB62BB758973971EE9E75E6D8AC67A0D44384439E7B11390E983975281A194F8173119905FE8FFD863D55CE7A6AD00683D4FF83263C81A447948DBF3F1EA2CA593B38E6719A8EECF654774599AB25D1EC9741AD3DE4DC23264C9700CDA27C463656E3A53C52B860B3264CD9FC0334D915E03EE74E54D4A2E2D795297FC748075A404A6C0AA6A22671A480AA3468B9FA9DA9A20DFDD8BB9100C8B6804DD6F16AB0C1B938FBEDC2F1A9DF43CC877B0F323042E9B1DFBB8A2BDA8986534D52B7EF06614DA22F63951716C2B04196567698552F3BA2067B2309AF06DB126727E1A82F731B0CC2904470429C1EC94456D1E66A0EA35A2A1C552CD3FA1A99AD3D748D563978800C32F5B6CA195938BA26CF721FFCDD9402EC4E37A9E1198D39516B4892919327592C67ED148672377A53C7AA9BD47D16282D977A40BB7E036A3FD11283DC2BD82EBA452474B827434014D0BF7C5483F28A432D378C6C78E6470F4026C27F531C367A2B950B0DD95114A106C72227CC33779C705B1C8926DFA2F996000535A0BB87BCFF4B9A12D829D04434AA579A11F6D15490A2C9FAF65042DB4CF88BE47368C589629703815FA6A2A1BD4A1447330E00CAE7645B2527FB82E864290C9574FCFD364F1A4FE3419642D24D98A6A33A0FC0E83505FD5151518555F9E03B2D5742630A119B2B32657AD6B2EE8B624508780F98B27E51BEFACBF3A7B920A282EA45358FA4145AA24E7CDCB3432C6F08D92421E2561EF811F1C60D7E51C840EFFD637D940F43D655FD1221F2A41027A71D90F978CB09E2264737053330E47E4C433F9B5AC94DB9B04EF7326410CC60DF7A220E1749A654FF6370D7C8197C808D35C2B6769E7CCD009BCA5835E4FDDA202D6C3DBE324AB97C879DA16184123CEEC3D5FDCC3CC71103E46E711CF8274D29B5CDF074BA889D6B0E51290428E0499022E634439804A488483D3927DDB78C248EBF9A6C9A678F4F482373580CB7FE2DAD993DAD34149F112D735C7E60DBA06BC44F0304551ABC09B9C91D4211FCD6025A865C90159CE3D842405A5143C46BE19DFDC64228A413D4225D7C94697C0F128B4336E9483192F3024014D2E9885447D0762F802087C7654786F76773DADA83CBC7396E5DDA29BEE95E93FD8C67D75C7D258765C7154DC822B925E8684DEB3443F85300C96E59192E8E99D2BCA21CB62713CC5EB23BF156FB3E97DAAA0695D84932FB9C9DB03E0BB13B103190246CD9AAF79C4B9C8916DB4B6BA02F5FA8B87B9E9B8D18DF6650E907E8A02BD67B4C00EBFE4E4C2CDA560D1874D7215CF0009DA57529EA831A8E71C88152849A8C2900134306C0C05A40BCE42A17CE9C025C100277D7F0CB35566BE5AC11B2466A2BB03B8DA8F10B7A30CA26FC4E0A3971E16DA0C5FCA52838361046549A77B9721027DF307AD3DC8B4EB3DC05BE4B0B0FB77482A794305BBE99499F6ADB05519D1D4A12740F91A363602232535458E94C7487DB90E777247864446B5A862164D9761DAAFEAE213440958E0C399B4DCC6C6BCCA44BF33512828B20402EB814384B9ECEC2B0C1316F3C545D4A65F31CC01B9E324F4468ED92896AD4572248E7298520FAAB161203A09D366EA8FB0041E8A79368822C557C67889DA58C63043C0B6E94B36C61CA41E5BB570448894EEE09F4F00A18A0164FE451B4D005AD5B9A1E3013C356652479D340594223238E068D9DC8C838902D72D97D35EA16E9B7A1852EF464E22D6CB4217BED00F1998134CC09098453C34CB9C0EA8ADD432E295A4B8DE30BDE1AB413F515153A75D02CE99B2EC8E45B3FBC1682973B769D688C8F6FA1AEBEE1795D1B9563AD1D462BAF1668D0426C457382E0EDA9A898FE694D319CCFFB53F378EBDF3AC7BBCDA8CB319470FDA31A1E4E920237A31A7F31392F54BD8991A0A98C65E8DCD9A9666B4403CF1C47B76D30391610161253A9057D23712ED9C71816D1C4B32A390AB6B4DE8F6D6032B8967B30471E80E2FF925DCA64887EA29FD14051BE7856B65B954A37F9577384245272B2098990F198EE1A9ACF1548299512F541E45922238F31115532A3AD6D744473F68DDCE411BEBFD933BE64AD1C7007258DEC9B112D4B9B5ED01FB4DE74E128C90BBAF64763A540E41B407151CFD8C2048A415304F05F7733238C6722AAB433ECE0CF900EEB02C24B20DEB96441E947ED1097A539C6A1B9E8B838E6CA2055ECC7064F43495815DCA3972B83401D5C8EC61708E692130512573672CCB5B9A56973E2EDDB1E3E1C965CBAD617D2590C277B91985007493DC9909BD6BF8578F2127141993ABF817B6DA2019DC6CF79207F96AB032B6D06C0512D049EA8663C46D5EDEB246F036C978496B1C1BC47E81CB63364F47B6913D0548EC13E1A37BCE62C68CE98BA1C29E71A3868491569B3093DAE40D42A5ED2972182CEBCE8F2589137699B142E3D3D7164939A081FDF237AA58ED794603943F2269A40B2967314C22E8668B15FCE244E145A3A49A3CE5BFC2C46ED93F40816A92DFB2880B5C4E755B2CC50914583D0FFAA28FD934E763118DA70C3D4137957333927FA4F0F637C4C52B9078E141089BCEDC7B4288019EDF92FD0ADED643C375E71C25ADBC8F94E04CA5A4E91C362D1C86BCAD31149636A895F443A491E6F558F9DC89ABA27967C7E66EF9C7302C100E4AD175021CFC295048BD5CADD8E86469EFA437034D7A01E38BDC64A6187F51F6D023CDB240F9FD0053FF7258D2C5802D1FA1C39DBC9D6D0E65026FCFEEC8205F77FBA1F64AA03B4D1C091AF43AB800839B4EBD378B28EA895111560183199390C3C6706EC35A05E4118A192E5A29C77CED86919C2A74A827913219B2C33E83249175B886B598CD25253A4B07D10C3AF92060C52FDA89B880923595865CA108EB0E78BA3F9E7B0465522CBA8DD6094131045E13A4C979B07BE8BD782AED050C3CF7C25ADE3C2A1CAE81738C55DC1ED0A33020EB6DC3464BDF6C16CC8223161991C62D149FCEA52140198B36B6379B47F5AA5EC066A5D5F561FDAC44EF3F967EE0E0A420AF89E22A053119DEF0D36FEAD69FF1B2C2476561DAF68D7682BD807CB4D2782C0B7FC39D7C6494BBE622352B534C21BFA25E6A37613CA73B85C98894EE1E588F20E73643F241F83003ECCD05B56255AA36782EB07283337E99144CD03B90680A048D4538D580728C0AD59C082104CD79099A08C193D40C3CAAFE3DBC968F9F8D9D0C74A7CA135F02C8F9C18380B00ECA21AE7E7A22133C1A65687C7F74CC5FB4BBD291183B803B1AF8441900134932217783D9EE86A565C8E9D316E0BC93E75941989C7E227D3170B0F78AF6F1D8FA70C697B4645A5F896B0C4971B6544D0C9786A774179E99EB4425C9838D57861C88E1DAE2E482D38BAE9D9C04DCC71D97449B13D3E9F6A52D81C91C0B02B581F4392C4EEE0514D4D39C84F323D7FE9A30FA87C5380913D3955C210B84444FE7CEDECF821D903E2102E8CAEF4020006F67B6D4B2146335AF10C6EA0A116A0110C5B9C935E349A6B29E8D609361B668E42BC0CD1E33D491D59FFD4A13E5B7742A8DBC918FE7F72BF18268121CE414D222C9AAA0522CE0487F2FB8545D19D7911BDCD4C81106EBA729FBD57365B1DE562A07660EDC92337C9A695F4DE495FFF27D63248BD4E4A96E405E39999A8AE35B6CF12AAB699FF741E298A3222D168EEE5ED1C0A372810A883BAF50E7DECA6F146F6DCFF1067EF4187AF79B70D8814CD50E39042417B4A1B7A230FE68504352093E91073307AD525F069F15DA88856C5140F8E89DFC8861E8678067FD054B163E02203E06AE92FA76FE2B68527737D99F2A13893699D7985F2F025DC3A430555FC23C9CE0C078E83CBCE363C5B5840FE09155F433178C46D257F5DBCEFC6AE9140F46A78872803B8FC6D0459C8A26279E1AC09711150E7F58F420A6AC2111647724DAED3867FAFAA58D4485F0265F0FF6A63C9F88CAB0FFBBB3579DC045903D682070C4DF15D3D02650213EA7A7D2FEE676BA92F923C1A0CBB2DADE5EA8F5623A548DC1060A2BFDE25AA6A09F80D8613D9673B66D2EBB124452921200BE54364DC705DC60BA75F2D0540C4168E6CDA16DA504D63068DE764E1823700BA4C97BF86058DDD2F5942DD5F4D3B19D6883412B6089FC6A6DAE5FAD95C3175AD53CBA016D59FED8107D0C64A1B50B1BC1380261A55D04998B99202078EAC318A36879D5C5AAD9299134EE66684179F8CACC52EE8106D23D0509D32E0459384B86CAE143B3E3C0EE95C8ACAE8D496E59131C80CDCA98B812E0452B8B9EFE94DE5424C50B935BCC927FF395D4D141DFC89A639703632E98451182D4D072A987A88B4409E0B5AD6F0CC62A5A10C3DC00B03597D1453B3257770E36949218F22D721302D3CE5DFC09D5604C943F73D75C996687931133DC4B6B061E5E74483FAD6EAA9E89D9467CE4C4FA061EAE71B02F3390DA9EE49D0EC92097321171D9771B1D65A4B54130345278FF8BD415FD5C9894B9F430E47F2967C650E376E614AF5F32A9456AB0C61A9278109404A484F28AC568922691C4C3965D465CD82FDFA330E3C9DD9E65687AD8827D18617C54EE0E3F6BF7E9FFABE7127AACD1B71573E2846AADBA44415407013EC01C5A7F70960870D1742DFD488B81A34DD7A286F4CC2C000E042352CE0120A637250B2A21AA998CFD1CA99BA21C321335F4A9222486AEF986FDA32C36F64172AFD225B5D358B59A06FBC1D388A99AD5780624E6A257A96910A4471C9ED1CDBF4AD41C74538A0933A460FFFA7B36C925E02D45D89A819725B8029742C189E561840F20EEB86252A6925116578A705FAC7B5B9A128E1B429E321C0B8EAC6B74C9590E6B02DEE15A0AEAB25B7D5533BB7B6D9299620BAA42C097304795B71A91DEC14A32B96438B0D4C313DD9A25A916554D2164D787E800B524D7E02215515244E7994C427574CA0E02FA18244A81E49C03C59E85524C8A76B77828A938A0BE90C77595567FD2619381FF0FD601777B7C226AEFF35E0B5BB7D6D88660027ED4E5E4265B2E0A775122A2E375F08DC24F4F327C9C2766F9CD8DF228AED7920250F1730A4A7D08531A26827EAD62E1BAA0A45EA9B8A26F5EB7CB6B36561F72FCFA31BD4509FAEC210D79E0E86B3048F8E629DABB24AF46C73547D40C0BFAB592078383832561F15DBD90E4073BE80079F3A489BCD51B98278337077F6791CAA0AC828A14865ADD78BBABF1113A171C06D10796415C7B0F4F3B732745BF9BEC82866D4508C1930B22E391FCB6D68AC89EE0D66A8B76BEAE525BC89AE9FC4C15A21169B7FE739DEAA80A7F19D5C669EBAC95A71EFE265A1570400315B8E853B7CB18E33E3ACCD4CF9E48546E36422E6E0ED282519DD5280FE5DB8B7877902188B17C4120444D729920963CA5AF34B94E365A8B0AF7947142C114C3F0A7FFF0714ACC3833CE4C0864185ECEFC7F36736F3E267DC956B0A1051ED765DF0BD12E1D25760A09EB05C16B327A30BAA1EA24552E15448BA1B3E1DF0E8550C7F4CB8240DD4146AB5FC002E33B4FAD65115439B10991417068B09AB2EE5B16D02C250A020B27580A9C1122604D1D69CA74CB478582614C56C4CEED92660B643C50712A132EF7D148BC27C4D1FA1E8680AE171CA8643EA4BE9EFD4F442B1BACB36221370D2DAAA509F78B76FA2611744D7617C12CE4B73914A26A0E64D15E8201C5BE8313FE0B0005102EDD25F95B440C96B90D9A92720AE271B542060B2EDB0245BCB3C83F901E2631B76C24768D28C18B01DA9C184DEF925D68C655E65A013B592D161841045F3EC54D0088449A64FFF0EA8E6AF632347BEAE431C5EF288A30AA74D95241EE7A6FF4E73DD22EAB04C6A6339CAA3A4E8C181E0751AEE8468771EECB0AAB3427493B0DCC2B19DD9A586DF437348C7CF9C5E3A8B1A630D5BBA6307CA395B4C797CEEBFAF5153258B325FAA9AAD673DE591DC8C0D589C61EB70CB7327B537AC1A31A6EA95C81C886CB3DE52427BBE10736E1BBDE9B8EA4AE6A2B44E7BC376B27C08E6FBB22A73B8D14CBB3BDA545B9430C30D6F3D67E0B42D7B122DCEC983B996188F79FE193F03CF1B446F166C5D8F2B1FBACD5C85678698EED8E5C76E2E0D55B955A2643FD1BBBC16D5F5BCA479AB5C1182FE2918BFD722DA84A010E60164C3ABF8137D293DC8719731F40ED404BCBF171E99F511F1E3CA723D59C34D78EFBBD463403F1E87337CA461447FE180EC53054A3F969218290042FF30D798B0C20A84C12A4D632CC9955FCE0D5DAB4AD68E71E5E4F5E446DA5FF1E2A5EF84BA2A3F222E4240355850B20CA5065330046E261E88156FC1A84442C60ECBF4C3D2242E27F8D806B022424D917CDA2830CC401C7AE9F1221FE533EABE3CD2B45E5DDC9379CEC4542B529977E18A8CCBD41B827CF900268CF7F6EB88C82415BA10930D1E157832F46E1B0F14E4944B720270C92509DC0DFC24F605A8AC015511B5554A4170F97064CFE6CF944D3B202A7C17DA356ECA45D92941C661B70B4AA679EC10DE7230C095F0590575FB28038E02A807ADD262BE38F3CA3F5A1D103EAF88EA59449AD040FEF17E702D2E46424A19216F2EA716B60070D5F8069215D580B296EDEA56FA3049972FA9A7CC947E1C56F669CD228B4C0446268BC47FB0D160EFDF7AD3218D3D57BC4B583319CA48A21D8D1BCCE5179421F776870F140CB9F18E2AA1DD2C5F877D91CBCCED0B4B8D84B111AA7160EE85B2C9B8AB69C1E3EE4431FFE4D3BD6A4DC6C8A800BD20CD8137AE1754BFC244CA7C5EC281381A237548A9D9AFFE7100B4254302EDD5461122D314B4938BA7B2A4423B40142E090E7AA3A6FD08578B40B17F189F9B16DABCB6DA64DA5470991398E9B3238DE4622FD2D12FCBA1928BC861ECC336BDE65A5BC43B6467CE293D37A1019EFBABA13ECE121B0ADE45AEB7C644C2D49C05B45F946DFB58E78B5373A4DB14884A241367672A563E3242D1856C8D1662D5F3691A6F5C769DCEF47778685BB448A8ECC5179EFE36CE6C7E5C04FB2644309018C064B2803CC1377D19F59D30B19E04D2981873CECC5C3E992C8889708B89E1990AFF746B340AF895962FADB2E2F926342137DAD8C1EBB09A616F658F40EBB28D3858D21B9F92A7FCE7FF2D421994CBE6072BCAC3E0DC3A030A212219D5DBDC906B07DBF29DB8EDCD213667F40CDE4AC7FB56E2A08A55EEAFDB4E71196FA642828D56983AAC268FFDD7E5BF02CEB2581B6DB158C91393A36C367F36AAAAFD2C40C2B4EB40963D1332155353412A2126C51BADEA6B842D2FE695B3CBA2E2584288304015905AFE6F808CF58A708290C4824CC484EED112384309A28E028D1E2EBD46CE419B5CEC1D9C9164C9A40218DCE50C9B466A8E3C357D3F86EE02A51F86FD361C000509AFB168275DDFE1F1BDCCBEB92CBB345E62CCD4F0328FB0A35FA8F28919927C1443D289AF808C8F034D28F79038DF670499E6521F080F0D365F2400D5D086CC7C0041D4DF80E4E4CE3906215D18EB720466CF8B43DE1C692BB71F63DF253EBD498A9020BA92517628263F65B8CC41A5D21BD76B6436029FED17639049766716B33F03E6F1786852AE47250BE2FDF8B6BC4F0084A823256B34A2C2FF4931119139FA60DFD0F376990DFCC08BA8A09B0EB3DC299CE091A1A15F1BF7C11FD35CC40BA9C2C624530441027ED45FF8C00EB0B2BDF7BCC18746DA7942C342D2A58A88EE549BD71915D1D907F0CF89C6E2CCF63025E0922E95E713AD78DDB8052E17007A83B966279E860A19F38FA484702A1229ED9BCE918B360B2C1EA70ABC182F62B2B6306802D70E4E2A83D46CAAAF950A1A20DBFBDA6ED1F21AF9C2AD2092875EB391A925951255D9FAE3292EC485B5C3CA16B003FEE565110E0A910A010C499AF322039140A83B28949AA8946FACC77ACC38CB4AE9E2AA250E34C0E63260BA989181C7470E0BD484C17704907A39EC96E2F4269CFFC95F311DBEE98360A999FFC28BEA9F9446A00758F83B5D492B602084DD47400864696BFB5119923EEC8D5CA82CF9F2BE623A7046A741A8F5A31259A37247F8EE9CF5EDA91B5BC5DE61AF067DAB0CE4C6C9881EFFB4E1D40C87184C38CEA0E07409AEBE92480294B852E21272AA71463C86354A37704B682825E1E7A1FB84A3329C376844286683055AAEC5C8BDD71BE9C88B3ABFA303E7885A0A027012B2B8EA8B83BFB1A8A8C4EC028DE82CC11CD18511E3F56137D84D326326AD2E0C479513F5F112E91454C6CA904010D328B94A26AFED5C8F14609037E17355E42B24222E7E5B1D84E61895C45090E769734E07AA03B00D08A0ECFE0967D7AE09D16843D54F6EEC12584F87EA7AD832B90DBBA8E39A0D21E867E3786D8FBAF19CDF7E56E9E9A44F421DD350D0D85AE095AE2F2BC0F9C7A8748279720BB0C0C6E7919CB83C40BDB3EAE1A6F87DFDAACCA342DF1C73AE02838ACCCAC609504A12F720356A57C4A3D21794A8106139C27503E6A6C47844962AC9FBBC0244601888B6F2CE6C41F8CB757F3E202F8B9A27D3057272745198A5CE7D2A4B227EA9CA6F0838B23EF2C66950F38693161AFBFD724EEA187F9D324C970B9F4BCD408161906A6648D18F4E6D52123F02694E39B6D8D1BE691C5AD20E793809F4D970893DAA133FB310146463EBF24617072871AEFC1CF9E885923416128479EDCCDB941FAFECE56906243A74FE19CAD9250141AE8B4CA6A343926D9076B964733D8978A109876475EC66691F659499CB552C28ADB0420E335F01DCC2BF041BD438E830FA09AE673C03930FF478300E5C1FCDFE6932AEBC289C3713A08B3136B37798527B2F67803C705107F985A1F4584AC2FEB24D195234DBFAF4097C1A1A6C50B6CBE1D31CEAE79299782B7A4482C21D1ED48EAD643681282282B1B0BF1150C20364431F62224FFD07EF87B9AA4CC4F73FD2284BE1064682DE6851DB21F786D1B6F73654DF04C06FB4F7E1CEF9480392AA851DB4308EFA35A16CF35B59DDE63F6208B90C776BE38CE0139E97C041D508DF432CA1D399910CD19A1A7C65C09A6CA89A5323D205ACC5BC75C312764B0B6599E10C2B8F4DAAAB9B298CC96CF3BADC21E4B797B52AE793B1BF08162DA0D4206FA64D703D100580435854460EE5085BFE241F8E149007EF2A373E2F48E55112AC1394721D0CC272C5C95D3EE9120A3F9F7758E5BBAC508FC5C20665132DEF552A7A65D122AFCFF8B1268ACB094DDB628D39ED6A5A0B86FDC96A7843C3043C083D8C06C8016AC05CC517BAFD15B6BC3EBCE8EE5F4C6D4A6B0722075586C66A769F714AEAEA49D6A0F5F330F8EF78EA55DB2FA5C4D057D3A1E17A92EE224745723BDD8FD7E6EAC10AFE9A0E22B702CA226F694FA079A95375E66B002F1E3C72C3CF63AF044C435A7EC2AB93570912535C40543A3B29AA9C8D07B0434443B32DE9C64B96385390FA0D6DFD80C2528697D253B9E7FD3AC3E5665E1FC0F707B7624FE526E5DF2242CB30740B6A965D82C4CC1F56468C8B43B4070C59F5F13A96E2D46ECCABDEC4702D1E8D57DE00F17200BF581760519FF2CA755AB85B1E6072000B0D7469B36C1D70290512A43F2B492C90C16AA08185C0920EB642054BD4D968396BA5393CA0364224CA7CE9EC77296E0E0108C691BFCE7B312524025B51F62C5A631440A21EAD737D224A9BEB8354C6F7293A710909A4C20E29F2DEFA90DC3AFCCA6608CBF4BD37800A4866A47DDDB7D6CB93E276CAD4C0BC6363B2204B8BDE55B1017181A57B3D8C21A452AC2E90329CF0A57734FD3D566CE07DAAA277390C0ED6A5F9E004F6A21AB57A29EAA2483421C06B7F26ED889E8FB5EDB83D7B323477C71CA2747065C8B6F25319E56CECC956A0F668EDC3667D16D2F511BCF247D1B0A0CB333741C2CDFBDF42E2397B92D582B2E2BAFBE4283F482460BC4EF92285A6C6901FCFD5A4207AB3ED31F0F96F887A9AA3106A11B8631DB062549A389BD938DAF7A78990698F57CD28BA283BD1627E33ADA7A5FED8F99D2916EC6369C3155969B420BD3226C7176EBADE1FDA729F841FDC40A4B71AD06CEE87D22CE513F044193ED05CCC89DA0B02BDCABA46B55077744E5CC67400CD2834299A5117C73ECC94BEC33014AC80A44B213E2454429E87186DE2AD19FCBB82717B410E17D53E0D3DC9E19549440B254C7476566B5FBEF170D9A72103FDECFA8C9734D1288524F5A14180BF729E56A3FAAD46EC1C565401646B60C319676274BCA3348D8ED8AD4CB033AD0E60F46E9326D7905EFD342FF4E62860140FE4EBB0B10A4A50BEAEEBC69454DCCA565480F0A343E69D82DC782356F4082E654245E50A9EB928B14A12C23554AC2BB690CDFF0A780F8B76450C894010C0AB69F32D1172F3A4093EE363285A1BCD8A28B652E02B0AC6AFDFEDC2FC544C70EE216805EE18F90FDB9629B315D2AB7DD2E4B07EEE3813802F131C9E9B1D28E566F9F92F0418B4D5D7C8F04A1B01FD4B311A2AB22B0663DAD07F993FA403F7752E9C4E8EF2E7D5B4015344E43914150AFA4C44E1761CAE104A9DE91BC81B6806264B4F888B7F24AB645F2F51D745C99FE1ABE1E733B8F9A54D6909E247E098D201293C3B70069D683DCE35AF0D91F490B1E439583129F45884ABEC6B25A5F59657C4F74846629746C48F25FBDDEEA64C931E3B07082204E35D3CE3DA543131FF6A284168D245EF1196B5138633030286F64B43B6BAEB12C266881E44F25B5A711553C8B30EB66070A12EE3B9DC78E9E91BCB1F5748F40DEA61B36711588A6A14060921D6776FA84BDA0B585A7CC1A855096763E91AAB01228F7EDD01C53C2EA0B5FB420CABCEC9A1EAB94EE0152A5D315AF370A1C192CC621FEF816C3CB4B9344DB176EB226138787C75280AA061D77ADF001267AD32C146C21CB02B7F0557624335E764B1BA948F81FBF69BD29641060EBB9AC541437900CBF32D8E206695E496E4747430243DD78D80CDD17320EADF225BD0CD0D158F95120AE130EFDF13441BF7578F4DCB3964DD9B507B95B1CBA60230D356C40C51A5D457F92BA19148D6A6E3F459A78A874921CCE17F654B72574398C481BA54976F940C1239CDC045F953EF5943BCBAADD35B9D3CAD3195337C4F28385D61282F97C8E1D63BFA91160F254EA157E7444E98DD5D871B839A9042E5E815BC681D6495EFD3A017806E8C28C4E0627DBF61D1240C12BBE5F08C3CEAD6A0635EF7CA2E816C56284BEE2E8ACEB4B4954B00B44DE006633AC5840A26D415C94A25A88F5B2B7B522669A9E9DD142CDC188B20A9D545E307081602646AFAB9A32B725D66EF158E98432BC2D889086DEC63D7C7B4BDDE13B3187FEECA3488AA1531E606839C04764902F0800955C6833C00FE3CCEDCDBF75F087227BF12F4603253F6177891F37D408D6D27EACCE1512ED2664BC87540510C43A1A89D8AA28C8DDBA97B1BC92DCBA9A68DFF3DC57338DC45F891BA704D17A18DE5E142B09ADD8F97A3A1266B251392C0449561E0D4EA4AD1B84D071D28038D5AAD50BC86CCC3569EDF18E5B24046668106D24767781EE56605BD41B1195D8470581517E3FD8109C0AC24448D57C146CC5D1335B140B9B4286AC0F6D2616030C0458BAD9310AB6EEE683489A1146F7A08E406F00A4CE8F514D4CDDECBD01EA05977F55C3871087B03777D0149BCB81E3A456510014E7AF448E03A36855777464E463261F419870C2E54A63B7E6D1BD9ABAE22855469FB9251394F58329F0225320C52A333CB228BFD6A0EF48420DD3C7C550C22459CFEB0073386DBE032D31C5B75ACD4F8C67AD82C71E7183969D20769A18318A725D1F22ED2BEDF1E9D72C4A8C240943370FED1DE7F23513AEA2AA1D5AEE27AFDAE647F03D98EA7121891227C9485A0A3EB5C72C263998B13CD68367AAC51CAB3CDE76674341A593B05546DE545DD0CEC049C4D445DFA36019F1448AA432ED1C0B70D11DCD69F188F10127FD96984DAEB3D2A7A3790196729BBA73443D109B38A96E394C3419F4E187EA26D474534588F2E9124E52E1001116886D350A2CB3C6CD3881FEBAEF336AC1162C84D0165F14DF8011AAF3587FCDE8D0A19FA260B652D682F57C65C3443AB602FBC27B8A0622C231880B1E62D095E1A4FCABFF880D86C3C4ACEA5946D981369678F4E34FD08A4625D9060363F22526D4D8DB175D6D854A9D15609F704322440AD183FE6FF3F4250213006D91FAC2985BCA13D4FEEA8020C8DC6770F517CDEC026E125C1AA3756A34C8CCCA219B0C214303637010586B8CD51DE2E9A29DD9675411C92540822514F10205820A2D6EA2EF3D742635D81A72AF24CE08C8FF0DC150219CBBC550AA20DD7797EA683ABF681C8042BF242C2799E55EE2C10577E3FDBB413B494447F121969AB56660700E260C31A01B88EDFFF3D8308940E295DC5AAC44CB9CDF672B3F7AD2AC7D7AC1CF668F913A64B8573A60947437E1270658919DAF571289CC5F2E0E7BDFE3E4911582B540B0B36732C5550358BD2738C70721D3C18A5BAE95A3A4DCC202C5634C390F1CB489CC907CB4DCAFE6FCAC299CAC3655BD7DB669DE2AE6AD77F3F78B4A6A154D7463944DA23515D1AB4C75456D601736BECB027B0D544062271A3345E0C9BF9333EB1B02D5038CF771C2EAA1FD6AAF8F40E9F077B907827A31193AEF045F4CB5C24A9F490819644834D01B57E09EC21038A2A701C7D21E0E92C67F3AC8151F9AB1442A9C122AD961DA84679584324F42308C384FE0A844714201EF64C0602EECC06C45FE04BFED8B664930A573B95FD7BDFDEAE6E6CB1ECC8EDA92939A92937C574CA50BFB8E6D4F92D713A4A0C3B9B098C2B45DCCD2544369A923C73DD95B6743D96549F9840781D6B0C1876B2A407640024C6A823292E4688D0A8F83EF689D7BA5A31F2D2A8039E355509F0C6A199D782346FEC75E9D9C4E5BCE1A1E668AB0F383E9B40545A36C4C90F92CCF6032DDFA51EFA03A1A026B53E092842AC49858E71322081457CC6006D81F0C3693F5892FEDBFB32290AA36B1F68199FE655E3BB57479012BC0090E58E4B9D6074A5665996666394ABC542B063174D67C7038172B85B646D330A152FF451DBAAFE2A215D1AFADD79CB9BB785E1B9F400C8DBC9F90E5E2BB54AE66760C0781C1233A33220521096AC8C5094FE49E8D631EA05188328C9732502ABD8A0EE35C8ABD039902A5C8A0C7BBFCB32508A2591731CFB1632F39DF33C2B6F36A6331E3DE35533A3CF7932D417E753ED68F1BEAF651465950B455F292A23F3675DF243043C727775C9BEED7E16789F048AB34A99E9F86DCE589211541DE582AC1B9139B25EA1F7862808DC97C598BBBAE330839320CC36DB8ABA774CADA3711DD41D44F9BD60918C2346704D0B591B76D8FE88C523155E3A7C24B388540C90B3097F4F39141CBDB541DE113F726C102B11A659E403C9AFF464A21AA4A5B3ED8132620623B48121C203B94A32DE0A42FFCB4EAC69FE2D7DE4E144C8C071DE51B1B11111E139AD656552A757DEF878844B97094A633EFE041288E275CE020A935D2F0110D09E7A9720E04FB3FDF8390B73CC92EF9378B802C2371A2FF1F396D95F587D362A615153AC8F687D84367B2C72F24C6A92C9B7119A92B95D69CF4BEE22A40CE1D0354551E2A867C78A71E38EF22F82240846DBC93EF1BA85D152752E9AF9A1ABF3896C1B36A082CF633645EECFE133E60354A05FE5BE0A16E843C8B9DD6A290F0FE1572614362B0E08C9569CCE55ABF8DC821356629F5313019D52496F7BC794BD2B1ED61260FFEA4D9BD07930EE2E66CAC9464710B87A318C6F66242C0764005DB8F9502046582F0A99B13B48A00F8796E846B2649E807D6E4B66A39BA514E07D53B0C5D85AB54BC30969E8CE0AEA37F5305F6F8312207B8505BFFB78DB0A29265D2DB06E0F617E626614371F8C49208B501ACAE806E3385458BCB52DB4D182B8F39ED5E4C2775D0E5882C189B38B4ABC1F49CE55688E6A044AC3717417D96053D0F22491BC3F5D93FA197FC246238864488B5C9A334773B11878AFB48D086CFFC5C8E389EC3AF54BC44F1C53B5273C8851F94D17F841F9D99F4EE8DC0A96640FDBA3B43F3B0174A44A2A8785CA45C1CC4462B4E201D21E3C749AD482B51079C76D44CD0264E074A10658AD6BC803314C0568A1B73699C5566DF80B5A6ADF40E80C5CA3EE7E4A989D4C40E6E043614F8829192308656EE7D81C7EBC53001640345FC9CA1D14CD3D2DBC4CA88E26224162918644A34EBA89408DB7B8B810476E33369014BE8195A7838BEE3BFCF49DE0CDFC19D50B57547879514D53B38CF19CA5456CE9DB44C08FA05E55A626984DAE33703DA1CDF56E277F20E3A9985423C9CCC85287D5BDBA4823CD95AB0D6334DB939FE601A8F1D18B60BE9D010B6D3DC14F6E2DF2524254EB0DF39895F498E4A9C46FE0BF5EE151CA3401D4DB116336F456C64E1B5349109341E94A852861D152FE10C400B98F98A7FE976852077D44765D191593723DED3E17A4DAF288BF54829DACCA038DB37070BE05B968849D8EF747A157AC51F33A31E1934574E6EA09220547E740D4472F70BA581E88D15C8C768F51FB6B006688F34BE85680AEF80B6FF74D1B84545EA641CEEC241110D4157E4BA521235529CED6A43F101D5CD9595E020E01019D819C214962576047D923CFE2EDA821DE59109C845DB58DDBBCDC2B0258CDD0D0B3D7833EF57CB9935F09044D50928B665E6460EA650634C55FE146F2B784331B815C36A9C966C9020C5A2FA9C351385ACE18405CB0EA0039F14F11EC1905D0D273C57E3F8FB218E5B3C5395BC8BECD356D513455FC70B9EC32598E677527F403F9D3A9F27FA14788D6D29F28019F44E80E2DA4787B13E60A43C8E66D81E53C3E42D02FA188C916B515D74C20724B2FBFDF902C720747481A4E268F13087900ACE6C33267CC83635E0B3ADB698D006801F967625E492B2066F6688857CBDF1452598F3319D9ECE68A85C1564A343B52913C8C09441E13C2D5F3BC59D61B624E9D671268708EAE80D74100446F8FE14A32E7DC41C4439793CFF61893B5A4D39883E99E0999541A82AF0DD8B93C07F07A07DA922217ABDDDD481EE8C5A2D6A6D0623AC3F2ED28116EA5C7ADCCC94FF0E201D1C989DC676D4043F33F37C442DD20C9AD459BCB89C2C50B453E6A91B087F3DFC72411C80E05B675A5E9A6129D0D145B3A119147FD00D37D92179B88E3AFE4E77F24A008A3D4B0DC86FBDD2773B53124E4DD5B30B08B048639A75C7094F966E81612D8C0AAF7E4B03E02E2930BD35F8506CED8B491C8038CE8C1160B5B4C11A2E57FDCA4F2B242C7F8B74E18C8C77801F09B277D4FF68FF40605A286801F24E50106005ECB27136EF343597CBDE60B132A57809D1F1FF82310E69BD5A8B851963486C73A681F04473A00E137737672B6E592572EB162422A17752CAD3E4D32076A49125B02B090731648762DD08362853C32A000167E8B32E35A372EA9D6686D82AB35656A4F4E00A6942CC4BA40E468A32C013C4BDFA76C73103E930BA5C75157B62DC3779E779ECC0956EC7758D83604D480590F88FE77B1FAD5AF7472B4905DDE62C59D14757ABD800EEE2D88E496BD3C544397A78A041E9161CB37E3F4E7B6E09C424EF12E9068B898944F53908FE800CAE8C10F625D800E0AFA6A53861E1A1F7C12E2ABA9E0D282EF848BD90C29A90A54AC5EC53BE5CAAD67C5D276E0C69C06862E1A79B9736E19C3AEA178BA8B0AE170BD304C4319DF261910B29B4B569D1B3507BF87468063AB4A53ED2D651DC7C47F6B42CCB57564E99DE5DD438A8069C8967E25DF402B8929EA8244AD67CA9B8818A03067B280A4DE2E1A1A22995BB778C40A704B0CE84A9248C7B6974970513B29AD3E58880E15054BF028AF26CFE30ADED531EAD501F5263F289E6FCCD67E978434296C52F42AA317E06C66DC4008564E971404E17AE00170211943105E89A8625B0B7D76E36768D00CCA75F68679938149075AEBCD04EEAF7C5C0BA4032C60B45515CEEBE0B57AD05C25B6A932ECB6F2ABFB088253039908315629AA975B8D2EA5CD5A1964C231934A310BD222C8896CB870A620293536A4D93E29538AE3EBF091B6EDC84083CD43DDE7DB84440C8DE69079EE11A1B7E354D2E02A326E0FA84821DB48C9B886C10D2EF5286F8DA7206C1CA5EA16852579B0201F8598446D4C0E66EE116507FA2E1F853C11890B32D419E093698B6B2EBAB9C4417178985B8DFE2767BD8624A2088E756EFAE37E98490982288094977A7A2538907653FA78952C133017BC129539300159E75E15C93807F8C8ADBC908C466D720E2A86D8BF9ACFC10263620B9B31DF7EEA587891D693154CF251AF35A2DC01B4A837FB8CA74F1AA744CC53AC3953B68D51F71D14CEFDAF91E3972B2993DE80F83C9E1E401128531A8C17462BA7892CB962BC084C91130CE933A36B2A74AEC1C5BFE498684351996E15CDAAA5C5AB9C767228397135845E82469085104AE5D97523C0C7634D0DDB2D7F49CA6822F6BDDD8AAFC7558A405D1BFC00DC8E80506B0B2A12767C0F905CD1F568991CF277EA51205F04354E80255FCE010B93E822CE08C30448C6F631E6D6339949E100F7AF00357E982378611BD2F17190CE6E2E71A43FB8E03ADAA98D54F78445B2C7C433409ED8CB75D2FC9344C7B2C24A5FC368D5D5C7CB9BEECE94647CC6B65C69DF829EA1EC6DA913052A534990D27756B2BC0AF7A533A945A49B4A3B20668D94254326E18226EC1605B63EF618C1259C81BA5342A20CF8DC64E39F4D7929694B516E64CD03614290D3C033B6B1C0B030171CE4EFA65491D1F376FD2469944524666EA0A28AAD35A48E15EE79E677FE2B38E9B11C1062731935F2513AAA3A5230A75A50AA446700B10C5A326776241100A2155BAE98E8CAB6843116B153E8BAF5D46399CF5F6EA67202B0144E34B0E1BAC6C1AA55FE7CA565E643BC1E15A1C09FC378CE37548D23BE3283A74D6B590CC8D25C64464B83A506D27AEC7F721A911F039AC4671A02564DC266A2EB78D6348A8D100E71F99FA861E499CEFBF200F8865D244BF30BA23EA4706290BD108EF82340B134F9E1ECE3C1226714C15BE72D5D33CB8DA2CF49181DED7BA3055E26D05DD8511D5ACA38192BD1AB7271B653005A6EBD06A3DE983CA28259478B4EAD1D66BA479A92F375E892075329BEA241C4897187F64C370F0171DC5D48CA543F3599FC8A87E7AD5C46306DE61518F471AE909B842601348CE0D92D657015772A7A59E957848263E359EB50DE8CCE2D2E37BC6DD42E4B880221F2B949BBE202A2648F42E9CD9E958D5481BFD186D444320FDB69B249C4EC2A11E4C6868D1E27E0F601163384AB8BA30B063B4D82C70CB26F061B2450AFA9C489A2FA3F11A09EA4CEF28B89DB6C5EF2A23CA9CBE1D980314807ADF85F64B3E627917AA0D05E35687BEE745FE67FB72842B1684587A9C41A8CB8D424E30BA1A7D0A17C6891738AD96B07C9881141FAC9B1C76AB47D0A1D32EE8B3D1B7F38003AB07C7CC89270E004942C3EEBA178E62D0F6EDA1C81B97E3EB2492AC594F710F2414119A481936A5E970F941C7BBD08DE49304D1E446CEF76E52713DD9485EA73CFC6B92DF4B09954DD20371C1E88087D73F0C885A68327486A812A1C9C36DA7E"); - byte[] sk = Hex.decode("FFFA0806FCF5F30D09FD0009F707FD010A0004FAFAF504F2F3FBF8FAFFF309FAFF1104FDF8010503F7FE0E08FAFF1806EFFEF2FEFCF1FD06050B07FA060C01FAF31300FDFD00070100F9F5110FF8FE0FF709F4FD0307FEFCF60800FF02F2FF0FF9EE07FF0703F002FD03FDF80902FC0B02F7F1F304010407FF0701FEFCFE15FC0503FE0804FE0704F202EF09FBF408070D07F206F307FFF502FDFD07F70404F5F8FB01F704E7F700F40501F7E00CFE080AFEFBFFFFF806FAF606F5FCFCFBFBFB00FD0AFBFFF5FC0B0EF411F4FEFC07020707F9F817FA0A0507FD0508EDF3FBF805FF00F1090607000508FB10EF0504FFFF0301FD0D09EFFE02FFFEF5FCFEF1FF0403F5F3FDFB0506F703FF09FDF3F9F5F7FFFE08110F0201F60701FAFFFA0A0404FE0809FF0AFEF20D09FF0A10F7FC020409F7F003FFFDFCF1F4F707F801F103FFF504090600F50301FA08FCF4F7F90C1310FCF20AF20E0CFA050103FCFA05FDEC0B08FE0502F8F9FD0C03F6FAFFFE01F8FB02FBEFF8FDFD0005030002F9FEF2000603FFFDF8F4F50206FAF9FC0BFE02FBF20BF400FFF90E0001F10FFC07FC12FBFDFEFB0702F8011008FDFF01FC06FF010501FE060A0201FF0302F116F4F8130008F60A100906F90309F7F605F4090C0510FEFAF8010609000A09020C1203F8FB02FFFC04FF0BF803050AFC06F1030808F6FB070000F80D0404FDEFF8F804FF090DF708FA050E02ED04FC0105FAFE080EFA06F706FA01FAF3F80404F905F3FFF0040406030505F808020B0803FF0FFDF8FB00F80102F7FAFDFEF3FAF9EDF0F704F302F10503FAF20302FBF306FAEC05F20A0400FE08F7F90506FBFEFCFFFA0E14080EF4041002F60702FAFCFD0F0B05F7FF080810FF030807FCF5FE020203FDFBFE021209FA05090205F800FB0011FC09FBFA14EC0610040C070A020C0CFE0006F900FFF8FBFE00FDFF0305F50B01FF02FCFE0708FDF7020006000011F800FEFBF7F6F6FBF4F50DFB09030D00060C030200F7FEF3F8070605FEF7FBE907F903010003FEF4F9F50FFBF0FD010810040502010AFDFCF00A0403FB030F0203F6FEFF060CFC010905040BEE0EFE01FFF6F6F508F90C0503050404FB090800FFFF110D0B0111FF0BF405FDF302FBFDFB00F603FD07F4F90102F5FF0908FBFEF901EF050DFB04010603120F05060B06FDF1FAFC0408FA07000E0DFAFDFD0AFCFCF9FBFA0AF201F904F9FAFAF80CF40003F6F9F8020805F709FD08F90BFCF7EFFE050AF901F4F9F4010704FEFA0CFF0506F103FA10FF09090109F90602F7EC03FE0107FF02FCF101FE05F9EEFDFAFC010301FE0202F80304050107F30107EF060100F9EEFCF60603FD02070CFDFCFE0AFDF90EFD03FF00FBF70308F50407F8090D010AEC0603030909FC020908FCFDF8140CFC1510F404FBF20AFCFE0FFB03FCFB0105F8070B00040AFAF6FFF8FB0C09FAFBF806000109FEFE0F050908FEFA02FF06FB03FF01EFF40AF9F502FE030DF4F6F9F4FCFCFBF9FC05FFF90A0204010901F903070C1007F70008EF03FF0DF705FCF8000F0A0312F204F810030D00F0F7F5050008FFF6F9070AF70600FCFDFE00FB03FDFCFC0302050506FDFE04FAFEFC0303F7EF05F3F70BFC06FE00F3FCF3F5F3000703FB07120604FFF9040A0406FBFAFAFB0309040C06000312F901F30200FA00F3F4FE030505FFFEFAF7030D1104FCFC02FCEEF116FD0B010B0EFDFBF904F3FAF3FDF90001030801FDFBF807030706F70304FF16FDF700FD010BFE090DFB0502FF0CFC00F5F00A09FBF604FF02050A04030AF3F505FAFCF809F900FDF00A06EC04F9FB0302FE02F6F60B0707F8F209FCEDFE08FBF709FC0805F904FDFE020AF4F2FD030303FFF8FAFB0CF60BFFFF07FC090613020502F7F2FD02FEF2F2F400020FFCFBF905F4FF03F706FAEEFA03FDFAF607030207F8040FF71101FEFFF50200F3FF02FBF901F50A0B0706FC050900FA000AFFF0F306F802FDF00BF910F202FEFC03070501EDFEFF06F805F7FE04ECE5FC0C00F50B0703000AFAF0FBFEF5070FFBF3F10600040AF3070704FA02FEF80703040107FDFD00100B04FF0402FD0419FDFBF5020901020B060BFEF5FCF207FD01F2F609FCFEFE14FC0D100900FAFBFD0AF802F80B01FD0008FDFB00FC0102F7E9F304FB04FEFCF60AFF0B07FB06FF0D020700EBFF040B00F5F8F0F905FD040807F3FE04FAF2F60AFAFFE70AF7FBF6030D0B01FC05F701FD0BFEFEFE02F70B0101F4FB08F1F600FC09F5FE03FBFD06FF0405FA03FEFCF7F601FD01060800040FF8F4F9FB070EFCF503FDF707F0EE0B05FFFC0703000201FBF9FB03F7FEFB06FFF200FB0004F704FB0904FFFE000603EE0A060BFF0AFBFF08F6FEFAF9F6FFFEFF0BFA0AFBFA08FFFFFDFF010BF60512F9FA01FDEB02FCF9050DFE01EDF5F3FA03041304FBFCFC01010CEB06011304FCFC04F7020BF6F10400FBF6F9FFF60FFEFFFBFF03FFFD03F108FFFCEDF501F5F8FA060305010501FCFE0DFD0600EF0304F907FF0000FB03FEFCFEFF0FFEF8000402FBFCF80D0709040B15FBFDF7050207FF01F8FFF7FA0608F8EFFB030AFC0DFA0DF8FC07F603FF07F408FD050EFBF9F5F5F60403F706FF030C1306FA0DFFFFFD090405020105F7020500FE07F701F608FEFD09F910ED0BF6FCFAEF0B01F4ED0708FB000213020700FAFBFFF9030AF6060A01070712FC0C03FCFFFC060407080104FFFC0904FCFAEFFE03F8FCFB01FBF0FE05FD06FD0F09FDFF03F40504FF00FEFBFDFD0EFBFFFE0B0AF4070C00F4FFF5FA05F10505FEEF00FD0303040103FC050407FC05F90104FD03F501FE07FD0BFBFE07FCF5F805020301000103060902041101FCF8FC00F301F503FD05020601FEFE070409090400030BF60B01F60DEB00FD1803FE0103F70AFFFBF90408F611F7FC0707FE080203F305F8FDFD04FAF5061005070301F607FAFFFD08020AFC02070BEE0907F9FB07FE02050F0AFE0FFCFE07F509FB0C01100306040E02070B0202FC010DFC09F801050102000CF5FDF9FFFB0004FDFB0A040506FAF00607FD0EF10DF5F8FB0408FEF3F4FE12FFF500FA02FFFCEFFDFDFF06FC09FF07051600F7050702F60608F102FBF60CF50400FB010401FE0A00FE0BF50CF809FEFF04EBFE11060501FEFC040B040605FF00000100FD0EFE00FE03F70DF4FAFF0400080AF80310F508EEFCF20AFA030C03000E0308050600F901EAFA0A05F800FAF6F808F803FAFEFF01FA010902F9FDF6F60A0CFEF702F408FAFEFD00F8F3FC05F9F60200FB05FDFEF50A01010D04F908E600050CF407FF0404F5FDFB06FFFEFC0006F604FFF707F809F900090E01FC0C040AFD0C0BFF05040AF30003090EFBFDF602F8F8FD0101060513FBF805FC0B00070AF500F803FDF50702F0FDF9FCFE01FD05F8010E04060000FAFC06FAFB16F6FBFFFF12090805F906FBF9FDF8FFFF1106FEF7100707FC0406FA11FE01FDF5110D0B0DFE01F807F6FF04F4EC00F50502FCE90AF9FC00FEFB150D0008F8F4140F010CFB00FB040F020207F209000BF8F409FFF704F3F7120511F90FF8030904FFFB020900F907F40BF605F607030BFEF301F207F1F801F9F705EEFD0FFE04F004FB0AFB0405FD0000FEF90DFF01FD060606F8F8F60D0AFA01F9FA051C00000B0FF9FE01FC00FD0E04070109FC0507E409F6F601080D02F302FCF702FC0BFEF302FFFF04090105FFF8F6F607FA0A00FFFDF5FC0AF3FAFF02ED09F2FBF7FBFF0CFEFD050D070505F8FBF700FEFEF80005FFFAFEEE0AFE0BFA000906020307F60607F80200FAFE0BF60604FF08F9FBF50606040802FD0004F4F8FCE9130911FE0305FEFEFDF905FFFF0D0B0EFA05000500000406ECFAF8FEF40AFA05F504F9F9010BFA0302FEFDFC07FB02FCF40D04FDFD0803EDFC0F00F7FE06FB090305FCF9FFFA130B0BFBFDF501F7FB03000D02FD0C0300FD0BFFFC13FC04F90E0804FCFBF803FDF7050907FB0702F8F9F8F2050102FC01F40A0614F6FDFDFCF00805FBF803FCF5090EF6FE0900FE04F8FAEE14EC000600FB0801F7FE0408FA0AFE05FDFDF907F5ED0A0C000409FCF305FF03090AFA0401F0FD0A000DFAFFFA02E9FBFE07070501F508FE03F50BF205FC05F50108F405F9FA02F101FAF50B06FC0AEDF4000DFB0D06FCFEFBFFFBF700FD0B07000703E70A0406FA050400080001F00E020D00FDFD0800FEFE04F90300050D05000D090700FC0E03F50304F90007F60D020002FFFE02FE0903010303040706F70800FA0706FEFDF10608FCFEF4F5F1F8F610FBFCF002020702070B0DF3F707FB07FEFB0F06FF0A07000C12EB0FF9FA09F6FDFB0B040AF7110302E9F6FDF0F90A04FF0AF3E6FF12FA010804030AFD1402FF05FA020E040201F502F908F00E030C02F8F9FFFB0201F903F3FFF6000606FBFBFB0204110CFAFCF40202FEECF3FE0003F007FF0AF90302FEF708F00DFD0B0AF906010206130809FB07FBFE0907FD080002F804F2FC0CFBF40301F40607F7FCFAF605FE06FD0DF4FCF60400F4FD0AFCFC0B0C01130807F502FE05F802FFFA0404F908F6FBF802FCFC060505FD00F604FE040802F20100FC070500F40305FE09FDFCF4F903010C010313FBFFFE06F005FB09F8F2F3FF0A05FC0AF6F7F506FA0409F9F900FFF7F307F602EC0CF8060EFB02FEFCF311F910FEF8F0F904090A0BFBFDFF03F8FA0E02F90D07FEFB02F9F206F40308030A00FAF704030204FA05FF0BF600FF0309FC05FEF9E8FEFA05F5F907051405FEF3F5F0FFF5010BFA06F6FD0D0504FEEF000CF7FF04F004050307FF0AFD00FA05FFFD05FC02000E060DFA0005040AFE0A01E1F2FA1508FD0804FFF900030906FCFAEB00FDFCF600010207FD05FB0005FF0206F8F900FEF902F903FC0BFD05F3F9F81306FBFEFFFF02F5F7EDF10FF50D03FFF6FD03FAFC0606F90B020B03FD07F90C0213F609FF07ED10F900F801F6F8FFFD05FD04061005F6090308FCFDF10400F9FE1702F811FDFE05130307FAFF0AFDF5F60907FEF5F9070709EF0009FEF8F8FFFE0A0CF6F30100040807F70D0D07FE0303F7F808F7060808000003F303F1FF01F700F7F70CF8FEFFFF01F70303F50600FFF800FF010AF3F4FAF001F105150C030803EFFDF6FAF3F6F900020C090A08FF0400050606040408030401120AF9F3F505F1020402050E010407FEFCF9FC010008FBFD09F7FCFC04F9F804F604FD0BFB02F407F8FB0702080404F5FE0A040B090305FCFE090C08F90705FEF8FEF8F1F501020DFA0D0504F8F900F9FFFB00010402F6FF0FFAF905EE09FF07FFFA180501F9FBF9FAFD040A0405FD11F00D11FFF900F2FE0406FD0BFDF8040DF2F80801041205FD06EAF8FA10F2FAF6FDF8030CF7F7FFF702E8F510FC070E0706FB04030D0C02F60C0904FC0AF5010700FBF703FAF708F501F7F9F80FFD050E0300F90D03FE1510F0F9F7F7FDFEEC101405020E14EE05F1F50C05FE09F5F602FA04FCFBFD01F003F6FBF6FE01030D05020310F6F8FAFF080906FDF6F6F604EFFA00020704FDF9FDFC07FA07FAFFFE05FFFAFD040C090E18FAF1F40400F3F40103FAF7040BFD1105FB05F7F505071006090BFEF7FBF90FFAF800FCEFFF07FAF8F905080B04F4F9F601F707FD0E01F5FFF3FF0700F4FA04FFFCFDF6FF0A0107FDFFF404F80AFF000402F20A06F90400FF13FFFF08060DF402040511FE05F7EF03FF0206F6FEFB0DFE08FAFA03F3F3FB0CFDF9F804FEFD0D03F9F8F2FDF7F8FD0B0BFAFDFCEDF3F60FF8F807FA01000203F9FF0C0AFF0D00EE07FC02F4FB050B03F608F9F4FC02F5FBF80200E905FBFEFE0BFC050904FEFD060006F7FB01FDFD010FFE04F6FC1207F511050CF8F6F900EBF7030CFA05ED090009030B02FBFC0608FDF60A01F608FC05FAF7F9FE0A040D010B0EFDF90402FBF702FE090FF5F7FD010301FA05FD0206F4FFF4030402FA0BFF1008FC03FE0A0607FCFD0108F60C010B080110110501080506F60708010BFFFA02060D100304FF03F8F503FC09FF08F00304FF01F1FC06010404F8FA0406FBF7000307020DF50C04F9F4FEF500F50105F70AFF100B0F00FC01FC03EB17F9F1F3F5FA080FFC0307FA0900FBFCF1FD0106FB0BFCFF0D0D1806FAF90EF7FDFDFE03FFF7080404FBFCF9FB0AFDFF13FB0502FD00E9F50CFB100800FDFD0FF4FF010307010AFAFC0DF906F4FC0514100B0A03010301F6FA0609010604F90009FA07FC05F7F2F601F3030DFE0A00FAF903F7F603FB05FAF8F9FE080F06F11604F3FCFFFEFE0200FCF8EEFB09030CFD0306F504FCFF070AFE030805080CF405F5F9070416FEF5FA0003F4070203061000FCFC05F9F809F9FFFDF908010BFD0602000D100BF8F8F9FEF6FEFB03FB01F6F70401FAFBFCFFFE0100F800FD0605FDFEF0FB0AFDFC080005FCFCFBFA08F7060205F1F60305020800FE0307FEFB00FA00100CFD060A02F70EFFFD060BFC03FCFA00F9030AFF03FAF7F414FC00FBF605FD03FFF0F802050BFA01F3FDF802FA010DF90107FA05010AF703FF050A0304FFF905F8FE05FDFBFA010302FD0E0800FCFCF8FF0401FEF30102FAF80D09FB0301ECFFF70301F3FC0513FF05F3010F04F70AFFFC060400F1F1F8F802FFF30FFEF8FF01F9F6050402FCFF01FCFBF80703F3100B05FC05FC06FD02FC18020B101102F40604FEF610F005F811FC04FAFBF50E02FFF713EF03F50700F3090301ED02F507FFFDFA0306FA030805FFFD0F0CFF00FAF0FB0609FFFC0C0307FFFD0F03FDF10606FAF900030C061705130C02F60AFF0DFA060304FA0106FDF7FCF404010AEF03F9ED06F7E8F9FDFF070901000105FBFC04FFF8F5FF0306F6F7050700F3FB0608FEF6FDFB0E04F804FEFDEDFC02FE0009FE0108F9F8070506EC1408EFFFFE0DF7F70DFEFDF8F80408F707F6FCF6F10105F80C0210FDF300F3FF0702F9F208FDFD0500FDEFFCFEFE0005000C05FBF90D0308F801F7F9F30302FBFBFC04FC09FB08FA0B00F0F5FD02F90C0506F80904F00B03FBF809FBF7F7FFF6F908060503F5FEFE07FB02F909FF0D0305060601FDFEF8F70007FAF30301F2FCF8EFF1F803F6F8F40D0603080100FDFE09F90002F71002FD01020DFE0105FDF0FF08020403060CEEFE0C06000001FC15FFEEF80FFA04F301FB09F1E90C0401031204F70EF4FE01FFFCF208F8030BFD1405FD05F205FEFA08FF1109ECF8FAF8F904090B0A01CFC6B92DF4B09954DD20371C1E88087D73F0C885A68327486A812A1C9C36DA7E4F5C254B6292FB5C3DB9561B8793D8AE3E1611423AC0A9F8CFC13E1C85FEC6B5" - + "3E8FE33CAE1CEEC574275C02B17AE78A0018BD4212E087C0901E518796AAA752B6282A7D0DB145AE"); - - int[] s_poly = new int[]{ - -1, -6, 8, 6, -4, -11, -13, 13, - 9, -3, 0, 9, -9, 7, -3, 1, - 10, 0, 4, -6, -6, -11, 4, -14, - -13, -5, -8, -6, -1, -13, 9, -6, - -1, 17, 4, -3, -8, 1, 5, 3, - -9, -2, 14, 8, -6, -1, 24, 6, - -17, -2, -14, -2, -4, -15, -3, 6, - 5, 11, 7, -6, 6, 12, 1, -6, - -13, 19, 0, -3, -3, 0, 7, 1, - 0, -7, -11, 17, 15, -8, -2, 15, - -9, 9, -12, -3, 3, 7, -2, -4, - -10, 8, 0, -1, 2, -14, -1, 15, - -7, -18, 7, -1, 7, 3, -16, 2, - -3, 3, -3, -8, 9, 2, -4, 11, - 2, -9, -15, -13, 4, 1, 4, 7, - -1, 7, 1, -2, -4, -2, 21, -4, - 5, 3, -2, 8, 4, -2, 7, 4, - -14, 2, -17, 9, -5, -12, 8, 7, - 13, 7, -14, 6, -13, 7, -1, -11, - 2, -3, -3, 7, -9, 4, 4, -11, - -8, -5, 1, -9, 4, -25, -9, 0, - -12, 5, 1, -9, -32, 12, -2, 8, - 10, -2, -5, -1, -1, -8, 6, -6, - -10, 6, -11, -4, -4, -5, -5, -5, - 0, -3, 10, -5, -1, -11, -4, 11, - 14, -12, 17, -12, -2, -4, 7, 2, - 7, 7, -7, -8, 23, -6, 10, 5, - 7, -3, 5, 8, -19, -13, -5, -8, - 5, -1, 0, -15, 9, 6, 7, 0, - 5, 8, -5, 16, -17, 5, 4, -1, - -1, 3, 1, -3, 13, 9, -17, -2, - 2, -1, -2, -11, -4, -2, -15, -1, - 4, 3, -11, -13, -3, -5, 5, 6, - -9, 3, -1, 9, -3, -13, -7, -11, - -9, -1, -2, 8, 17, 15, 2, 1, - -10, 7, 1, -6, -1, -6, 10, 4, - 4, -2, 8, 9, -1, 10, -2, -14, - 13, 9, -1, 10, 16, -9, -4, 2, - 4, 9, -9, -16, 3, -1, -3, -4, - -15, -12, -9, 7, -8, 1, -15, 3, - -1, -11, 4, 9, 6, 0, -11, 3, - 1, -6, 8, -4, -12, -9, -7, 12, - 19, 16, -4, -14, 10, -14, 14, 12, - -6, 5, 1, 3, -4, -6, 5, -3, - -20, 11, 8, -2, 5, 2, -8, -7, - -3, 12, 3, -10, -6, -1, -2, 1, - -8, -5, 2, -5, -17, -8, -3, -3, - 0, 5, 3, 0, 2, -7, -2, -14, - 0, 6, 3, -1, -3, -8, -12, -11, - 2, 6, -6, -7, -4, 11, -2, 2, - -5, -14, 11, -12, 0, -1, -7, 14, - 0, 1, -15, 15, -4, 7, -4, 18, - -5, -3, -2, -5, 7, 2, -8, 1, - 16, 8, -3, -1, 1, -4, 6, -1, - 1, 5, 1, -2, 6, 10, 2, 1, - -1, 3, 2, -15, 22, -12, -8, 19, - 0, 8, -10, 10, 16, 9, 6, -7, - 3, 9, -9, -10, 5, -12, 9, 12, - 5, 16, -2, -6, -8, 1, 6, 9, - 0, 10, 9, 2, 12, 18, 3, -8, - -5, 2, -1, -4, 4, -1, 11, -8, - 3, 5, 10, -4, 6, -15, 3, 8, - 8, -10, -5, 7, 0, 0, -8, 13, - 4, 4, -3, -17, -8, -8, 4, -1, - 9, 13, -9, 8, -6, 5, 14, 2, - -19, 4, -4, 1, 5, -6, -2, 8, - 14, -6, 6, -9, 6, -6, 1, -6, - -13, -8, 4, 4, -7, 5, -13, -1, - -16, 4, 4, 6, 3, 5, 5, -8, - 8, 2, 11, 8, 3, -1, 15, -3, - -8, -5, 0, -8, 1, 2, -9, -6, - -3, -2, -13, -6, -7, -19, -16, -9, - 4, -13, 2, -15, 5, 3, -6, -14, - 3, 2, -5, -13, 6, -6, -20, 5, - -14, 10, 4, 0, -2, 8, -9, -7, - 5, 6, -5, -2, -4, -1, -6, 14, - 20, 8, 14, -12, 4, 16, 2, -10, - 7, 2, -6, -4, -3, 15, 11, 5, - -9, -1, 8, 8, 16, -1, 3, 8, - 7, -4, -11, -2, 2, 2, 3, -3, - -5, -2, 2, 18, 9, -6, 5, 9, - 2, 5, -8, 0, -5, 0, 17, -4, - 9, -5, -6, 20, -20, 6, 16, 4, - 12, 7, 10, 2, 12, 12, -2, 0, - 6, -7, 0, -1, -8, -5, -2, 0, - -3, -1, 3, 5, -11, 11, 1, -1, - 2, -4, -2, 7, 8, -3, -9, 2, - 0, 6, 0, 0, 17, -8, 0, -2, - -5, -9, -10, -10, -5, -12, -11, 13, - -5, 9, 3, 13, 0, 6, 12, 3, - 2, 0, -9, -2, -13, -8, 7, 6, - 5, -2, -9, -5, -23, 7, -7, 3, - 1, 0, 3, -2, -12, -7, -11, 15, - -5, -16, -3, 1, 8, 16, 4, 5, - 2, 1, 10, -3, -4, -16, 10, 4, - 3, -5, 3, 15, 2, 3, -10, -2, - -1, 6, 12, -4, 1, 9, 5, 4, - 11, -18, 14, -2, 1, -1, -10, -10, - -11, 8, -7, 12, 5, 3, 5, 4, - 4, -5, 9, 8, 0, -1, -1, 17, - 13, 11, 1, 17, -1, 11, -12, 5, - -3, -13, 2, -5, -3, -5, 0, -10, - 3, -3, 7, -12, -7, 1, 2, -11, - -1, 9, 8, -5, -2, -7, 1, -17, - 5, 13, -5, 4, 1, 6, 3, 18, - 15, 5, 6, 11, 6, -3, -15, -6, - -4, 4, 8, -6, 7, 0, 14, 13, - -6, -3, -3, 10, -4, -4, -7, -5, - -6, 10, -14, 1, -7, 4, -7, -6, - -6, -8, 12, -12, 0, 3, -10, -7, - -8, 2, 8, 5, -9, 9, -3, 8, - -7, 11, -4, -9, -17, -2, 5, 10, - -7, 1, -12, -7, -12, 1, 7, 4, - -2, -6, 12, -1, 5, 6, -15, 3, - -6, 16, -1, 9, 9, 1, 9, -7, - 6, 2, -9, -20, 3, -2, 1, 7, - -1, 2, -4, -15, 1, -2, 5, -7, - -18, -3, -6, -4, 1, 3, 1, -2, - 2, 2, -8, 3, 4, 5, 1, 7, - -13, 1, 7, -17, 6, 1, 0, -7, - -18, -4, -10, 6, 3, -3, 2, 7, - 12, -3, -4, -2, 10, -3, -7, 14, - -3, 3, -1, 0, -5, -9, 3, 8, - -11, 4, 7, -8, 9, 13, 1, 10, - -20, 6, 3, 3, 9, 9, -4, 2, - 9, 8, -4, -3, -8, 20, 12, -4, - 21, 16, -12, 4, -5, -14, 10, -4, - -2, 15, -5, 3, -4, -5, 1, 5, - }; - int[] e_poly = new int[]{ - -8, 7, 11, 0, 4, 10, -6, -10, - -1, -8, -5, 12, 9, -6, -5, -8, - 6, 0, 1, 9, -2, -2, 15, 5, - 9, 8, -2, -6, 2, -1, 6, -5, - 3, -1, 1, -17, -12, 10, -7, -11, - 2, -2, 3, 13, -12, -10, -7, -12, - -4, -4, -5, -7, -4, 5, -1, -7, - 10, 2, 4, 1, 9, 1, -7, 3, - 7, 12, 16, 7, -9, 0, 8, -17, - 3, -1, 13, -9, 5, -4, -8, 0, - 15, 10, 3, 18, -14, 4, -8, 16, - 3, 13, 0, -16, -9, -11, 5, 0, - 8, -1, -10, -7, 7, 10, -9, 6, - 0, -4, -3, -2, 0, -5, 3, -3, - -4, -4, 3, 2, 5, 5, 6, -3, - -2, 4, -6, -2, -4, 3, 3, -9, - -17, 5, -13, -9, 11, -4, 6, -2, - 0, -13, -4, -13, -11, -13, 0, 7, - 3, -5, 7, 18, 6, 4, -1, -7, - 4, 10, 4, 6, -5, -6, -6, -5, - 3, 9, 4, 12, 6, 0, 3, 18, - -7, 1, -13, 2, 0, -6, 0, -13, - -12, -2, 3, 5, 5, -1, -2, -6, - -9, 3, 13, 17, 4, -4, -4, 2, - -4, -18, -15, 22, -3, 11, 1, 11, - 14, -3, -5, -7, 4, -13, -6, -13, - -3, -7, 0, 1, 3, 8, 1, -3, - -5, -8, 7, 3, 7, 6, -9, 3, - 4, -1, 22, -3, -9, 0, -3, 1, - 11, -2, 9, 13, -5, 5, 2, -1, - 12, -4, 0, -11, -16, 10, 9, -5, - -10, 4, -1, 2, 5, 10, 4, 3, - 10, -13, -11, 5, -6, -4, -8, 9, - -7, 0, -3, -16, 10, 6, -20, 4, - -7, -5, 3, 2, -2, 2, -10, -10, - 11, 7, 7, -8, -14, 9, -4, -19, - -2, 8, -5, -9, 9, -4, 8, 5, - -7, 4, -3, -2, 2, 10, -12, -14, - -3, 3, 3, 3, -1, -8, -6, -5, - 12, -10, 11, -1, -1, 7, -4, 9, - 6, 19, 2, 5, 2, -9, -14, -3, - 2, -2, -14, -14, -12, 0, 2, 15, - -4, -5, -7, 5, -12, -1, 3, -9, - 6, -6, -18, -6, 3, -3, -6, -10, - 7, 3, 2, 7, -8, 4, 15, -9, - 17, 1, -2, -1, -11, 2, 0, -13, - -1, 2, -5, -7, 1, -11, 10, 11, - 7, 6, -4, 5, 9, 0, -6, 0, - 10, -1, -16, -13, 6, -8, 2, -3, - -16, 11, -7, 16, -14, 2, -2, -4, - 3, 7, 5, 1, -19, -2, -1, 6, - -8, 5, -9, -2, 4, -20, -27, -4, - 12, 0, -11, 11, 7, 3, 0, 10, - -6, -16, -5, -2, -11, 7, 15, -5, - -13, -15, 6, 0, 4, 10, -13, 7, - 7, 4, -6, 2, -2, -8, 7, 3, - 4, 1, 7, -3, -3, 0, 16, 11, - 4, -1, 4, 2, -3, 4, 25, -3, - -5, -11, 2, 9, 1, 2, 11, 6, - 11, -2, -11, -4, -14, 7, -3, 1, - -14, -10, 9, -4, -2, -2, 20, -4, - 13, 16, 9, 0, -6, -5, -3, 10, - -8, 2, -8, 11, 1, -3, 0, 8, - -3, -5, 0, -4, 1, 2, -9, -23, - -13, 4, -5, 4, -2, -4, -10, 10, - -1, 11, 7, -5, 6, -1, 13, 2, - 7, 0, -21, -1, 4, 11, 0, -11, - -8, -16, -7, 5, -3, 4, 8, 7, - -13, -2, 4, -6, -14, -10, 10, -6, - -1, -25, 10, -9, -5, -10, 3, 13, - 11, 1, -4, 5, -9, 1, -3, 11, - -2, -2, -2, 2, -9, 11, 1, 1, - -12, -5, 8, -15, -10, 0, -4, 9, - -11, -2, 3, -5, -3, 6, -1, 4, - 5, -6, 3, -2, -4, -9, -10, 1, - -3, 1, 6, 8, 0, 4, 15, -8, - -12, -7, -5, 7, 14, -4, -11, 3, - -3, -9, 7, -16, -18, 11, 5, -1, - -4, 7, 3, 0, 2, 1, -5, -7, - -5, 3, -9, -2, -5, 6, -1, -14, - 0, -5, 0, 4, -9, 4, -5, 9, - 4, -1, -2, 0, 6, 3, -18, 10, - 6, 11, -1, 10, -5, -1, 8, -10, - -2, -6, -7, -10, -1, -2, -1, 11, - -6, 10, -5, -6, 8, -1, -1, -3, - -1, 1, 11, -10, 5, 18, -7, -6, - 1, -3, -21, 2, -4, -7, 5, 13, - -2, 1, -19, -11, -13, -6, 3, 4, - 19, 4, -5, -4, -4, 1, 1, 12, - -21, 6, 1, 19, 4, -4, -4, 4, - -9, 2, 11, -10, -15, 4, 0, -5, - -10, -7, -1, -10, 15, -2, -1, -5, - -1, 3, -1, -3, 3, -15, 8, -1, - -4, -19, -11, 1, -11, -8, -6, 6, - 3, 5, 1, 5, 1, -4, -2, 13, - -3, 6, 0, -17, 3, 4, -7, 7, - -1, 0, 0, -5, 3, -2, -4, -2, - -1, 15, -2, -8, 0, 4, 2, -5, - -4, -8, 13, 7, 9, 4, 11, 21, - -5, -3, -9, 5, 2, 7, -1, 1, - -8, -1, -9, -6, 6, 8, -8, -17, - -5, 3, 10, -4, 13, -6, 13, -8, - -4, 7, -10, 3, -1, 7, -12, 8, - -3, 5, 14, -5, -7, -11, -11, -10, - 4, 3, -9, 6, -1, 3, 12, 19, - 6, -6, 13, -1, -1, -3, 9, 4, - 5, 2, 1, 5, -9, 2, 5, 0, - -2, 7, -9, 1, -10, 8, -2, -3, - 9, -7, 16, -19, 11, -10, -4, -6, - -17, 11, 1, -12, -19, 7, 8, -5, - 0, 2, 19, 2, 7, 0, -6, -5, - -1, -7, 3, 10, -10, 6, 10, 1, - 7, 7, 18, -4, 12, 3, -4, -1, - -4, 6, 4, 7, 8, 1, 4, -1, - -4, 9, 4, -4, -6, -17, -2, 3, - -8, -4, -5, 1, -5, -16, -2, 5, - -3, 6, -3, 15, 9, -3, -1, 3, - -12, 5, 4, -1, 0, -2, -5, -3, - -3, 14, -5, -1, -2, 11, 10, -12, - 7, 12, 0, -12, -1, -11, -6, 5, - -15, 5, 5, -2, -17, 0, -3, 3, - 3, 4, 1, 3, -4, 5, 4, 7, - -4, 5, -7, 1, 4, -3, 3, -11, - 1, -2, 7, -3, 11, -5, -2, 7, - -4, -11, -8, 5, 2, 3, 1, 0, - 1, 3, 6, 9, 2, 4, 17, 1, - -4, -8, -4, 0, -13, 1, -11, 3, - -3, 5, 2, 6, 1, -2, -2, 7, - 4, 9, 9, 4, 0, 3, 11, -10, - 11, 1, -10, 13, -21, 0, -3, 24, - 3, -2, 1, 3, -9, 10, -1, -5, - -7, 4, 8, -10, 17, -9, -4, 7, - 7, -2, 8, 2, 3, -13, 5, -8, - -3, -3, 4, -6, -11, 6, 16, 5, - 7, 3, 1, -10, 7, -6, -1, -3, - 8, 2, 10, -4, 2, 7, 11, -18, - 9, 7, -7, -5, 7, -2, 2, 5, - 15, 10, -2, 15, -4, -2, 7, -11, - 9, -5, 12, 1, 16, 3, 6, 4, - 14, 2, 7, 11, 2, 2, -4, 1, - 13, -4, 9, -8, 1, 5, 1, 2, - 0, 12, -11, -3, -7, -1, -5, 0, - 4, -3, -5, 10, 4, 5, 6, -6, - -16, 6, 7, -3, 14, -15, 13, -11, - -8, -5, 4, 8, -2, -13, -12, -2, - 18, -1, -11, 0, -6, 2, -1, -4, - -17, -3, -3, -1, 6, -4, 9, -1, - 7, 5, 22, 0, -9, 5, 7, 2, - -10, 6, 8, -15, 2, -5, -10, 12, - -11, 4, 0, -5, 1, 4, 1, -2, - 10, 0, -2, 11, -11, 12, -8, 9, - -2, -1, 4, -21, -2, 17, 6, 5, - 1, -2, -4, 4, 11, 4, 6, 5, - -1, 0, 0, 1, 0, -3, 14, -2, - 0, -2, 3, -9, 13, -12, -6, -1, - 4, 0, 8, 10, -8, 3, 16, -11, - 8, -18, -4, -14, 10, -6, 3, 12, - 3, 0, 14, 3, 8, 5, 6, 0, - -7, 1, -22, -6, 10, 5, -8, 0, - -6, -10, -8, 8, -8, 3, -6, -2, - -1, 1, -6, 1, 9, 2, -7, -3, - -10, -10, 10, 12, -2, -9, 2, -12, - 8, -6, -2, -3, 0, -8, -13, -4, - 5, -7, -10, 2, 0, -5, 5, -3, - -2, -11, 10, 1, 1, 13, 4, -7, - 8, -26, 0, 5, 12, -12, 7, -1, - 4, 4, -11, -3, -5, 6, -1, -2, - -4, 0, 6, -10, 4, -1, -9, 7, - -8, 9, -7, 0, 9, 14, 1, -4, - 12, 4, 10, -3, 12, 11, -1, 5, - 4, 10, -13, 0, 3, 9, 14, -5, - -3, -10, 2, -8, -8, -3, 1, 1, - 6, 5, 19, -5, -8, 5, -4, 11, - 0, 7, 10, -11, 0, -8, 3, -3, - -11, 7, 2, -16, -3, -7, -4, -2, - 1, -3, 5, -8, 1, 14, 4, 6, - 0, 0, -6, -4, 6, -6, -5, 22, - -10, -5, -1, -1, 18, 9, 8, 5, - -7, 6, -5, -7, -3, -8, -1, -1, - 17, 6, -2, -9, 16, 7, 7, -4, - 4, 6, -6, 17, -2, 1, -3, -11, - 17, 13, 11, 13, -2, 1, -8, 7, - -10, -1, 4, -12, -20, 0, -11, 5, - 2, -4, -23, 10, -7, -4, 0, -2, - -5, 21, 13, 0, 8, -8, -12, 20, - 15, 1, 12, -5, 0, -5, 4, 15, - 2, 2, 7, -14, 9, 0, 11, -8, - -12, 9, -1, -9, 4, -13, -9, 18, - 5, 17, -7, 15, -8, 3, 9, 4, - -1, -5, 2, 9, 0, -7, 7, -12, - 11, -10, 5, -10, 7, 3, 11, -2, - -13, 1, -14, 7, -15, -8, 1, -7, - -9, 5, -18, -3, 15, -2, 4, -16, - 4, -5, 10, -5, 4, 5, -3, 0, - 0, -2, -7, 13, -1, 1, -3, 6, - 6, 6, -8, -8, -10, 13, 10, -6, - 1, -7, -6, 5, 28, 0, 0, 11, - 15, -7, -2, 1, -4, 0, -3, 14, - 4, 7, 1, 9, -4, 5, 7, -28, - 9, -10, -10, 1, 8, 13, 2, -13, - 2, -4, -9, 2, -4, 11, -2, -13, - 2, -1, -1, 4, 9, 1, 5, -1, - -8, -10, -10, 7, -6, 10, 0, -1, - -3, -11, -4, 10, -13, -6, -1, 2, - -19, 9, -14, -5, -9, -5, -1, 12, - -2, -3, 5, 13, 7, 5, 5, -8, - -5, -9, 0, -2, -2, -8, 0, 5, - -1, -6, -2, -18, 10, -2, 11, -6, - 0, 9, 6, 2, 3, 7, -10, 6, - 7, -8, 2, 0, -6, -2, 11, -10, - 6, 4, -1, 8, -7, -5, -11, 6, - 6, 4, 8, 2, -3, 0, 4, -12, - -8, -4, -23, 19, 9, 17, -2, 3, - 5, -2, -2, -3, -7, 5, -1, -1, - 13, 11, 14, -6, 5, 0, 5, 0, - 0, 4, 6, -20, -6, -8, -2, -12, - 10, -6, 5, -11, 4, -7, -7, 1, - 11, -6, 3, 2, -2, -3, -4, 7, - -5, 2, -4, -12, 13, 4, -3, -3, - 8, 3, -19, -4, 15, 0, -9, -2, - 6, -5, 9, 3, 5, -4, -7, -1, - -6, 19, 11, 11, -5, -3, -11, 1, - -9, -5, 3, 0, 13, 2, -3, 12, - 3, 0, -3, 11, -1, -4, 19, -4, - 4, -7, 14, 8, 4, -4, -5, -8, - 3, -3, -9, 5, 9, 7, -5, 7, - 2, -8, -7, -8, -14, 5, 1, 2, - -4, 1, -12, 10, 6, 20, -10, -3, - -3, -4, -16, 8, 5, -5, -8, 3, - -4, -11, 9, 14, -10, -2, 9, 0, - -2, 4, -8, -6, -18, 20, -20, 0, - 6, 0, -5, 8, 1, -9, -2, 4, - 8, -6, 10, -2, 5, -3, -3, -7, - 7, -11, -19, 10, 12, 0, 4, 9, - -4, -13, 5, -1, 3, 9, 10, -6, - 4, 1, -16, -3, 10, 0, 13, -6, - -1, -6, 2, -23, -5, -2, 7, 7, - 5, 1, -11, 8, -2, 3, -11, 11, - -14, 5, -4, 5, -11, 1, 8, -12, - 5, -7, -6, 2, -15, 1, -6, -11, - 11, 6, -4, 10, -19, -12, 0, 13, - -5, 13, 6, -4, -2, -5, -1, -5, - -9, 0, -3, 11, 7, 0, 7, 3, - -25, 10, 4, 6, -6, 5, 4, 0, - 8, 0, 1, -16, 14, 2, 13, 0, - -3, -3, 8, 0, -2, -2, 4, -7, - 3, 0, 5, 13, 5, 0, 13, 9, - 7, 0, -4, 14, 3, -11, 3, 4, - -7, 0, 7, -10, 13, 2, 0, 2, - -1, -2, 2, -2, 9, 3, 1, 3, - 3, 4, 7, 6, -9, 8, 0, -6, - 7, 6, -2, -3, -15, 6, 8, -4, - -2, -12, -11, -15, -8, -10, 16, -5, - -4, -16, 2, 2, 7, 2, 7, 11, - 13, -13, -9, 7, -5, 7, -2, -5, - 15, 6, -1, 10, 7, 0, 12, 18, - -21, 15, -7, -6, 9, -10, -3, -5, - 11, 4, 10, -9, 17, 3, 2, -23, - -10, -3, -16, -7, 10, 4, -1, 10, - -13, -26, -1, 18, -6, 1, 8, 4, - 3, 10, -3, 20, 2, -1, 5, -6, - 2, 14, 4, 2, 1, -11, 2, -7, - 8, -16, 14, 3, 12, 2, -8, -7, - -1, -5, 2, 1, -7, 3, -13, -1, - -10, 0, 6, 6, -5, -5, -5, 2, - 4, 17, 12, -6, -4, -12, 2, 2, - -2, -20, -13, -2, 0, 3, -16, 7, - -1, 10, -7, 3, 2, -2, -9, 8, - -16, 13, -3, 11, 10, -7, 6, 1, - 2, 6, 19, 8, 9, -5, 7, -5, - -2, 9, 7, -3, 8, 0, 2, -8, - 4, -14, -4, 12, -5, -12, 3, 1, - -12, 6, 7, -9, -4, -6, -10, 5, - -2, 6, -3, 13, -12, -4, -10, 4, - 0, -12, -3, 10, -4, -4, 11, 12, - 1, 19, 8, 7, -11, 2, -2, 5, - -8, 2, -1, -6, 4, 4, -7, 8, - -10, -5, -8, 2, -4, -4, 6, 5, - 5, -3, 0, -10, 4, -2, 4, 8, - 2, -14, 1, 0, -4, 7, 5, 0, - -12, 3, 5, -2, 9, -3, -4, -12, - -7, 3, 1, 12, 1, 3, 19, -5, - -1, -2, 6, -16, 5, -5, 9, -8, - -14, -13, -1, 10, 5, -4, 10, -10, - -9, -11, 6, -6, 4, 9, -7, -7, - 0, -1, -9, -13, 7, -10, 2, -20, - 12, -8, 6, 14, -5, 2, -2, -4, - -13, 17, -7, 16, -2, -8, -16, -7, - 4, 9, 10, 11, -5, -3, -1, 3, - -8, -6, 14, 2, -7, 13, 7, -2, - -5, 2, -7, -14, 6, -12, 3, 8, - 3, 10, 0, -6, -9, 4, 3, 2, - 4, -6, 5, -1, 11, -10, 0, -1, - 3, 9, -4, 5, -2, -7, -24, -2, - -6, 5, -11, -7, 7, 5, 20, 5, - -2, -13, -11, -16, -1, -11, 1, 11, - -6, 6, -10, -3, 13, 5, 4, -2, - -17, 0, 12, -9, -1, 4, -16, 4, - 5, 3, 7, -1, 10, -3, 0, -6, - 5, -1, -3, 5, -4, 2, 0, 14, - 6, 13, -6, 0, 5, 4, 10, -2, - 10, 1, -31, -14, -6, 21, 8, -3, - 8, 4, -1, -7, 0, 3, 9, 6, - -4, -6, -21, 0, -3, -4, -10, 0, - 1, 2, 7, -3, 5, -5, 0, 5, - -1, 2, 6, -8, -7, 0, -2, -7, - 2, -7, 3, -4, 11, -3, 5, -13, - -7, -8, 19, 6, -5, -2, -1, -1, - 2, -11, -9, -19, -15, 15, -11, 13, - 3, -1, -10, -3, 3, -6, -4, 6, - 6, -7, 11, 2, 11, 3, -3, 7, - -7, 12, 2, 19, -10, 9, -1, 7, - -19, 16, -7, 0, -8, 1, -10, -8, - -1, -3, 5, -3, 4, 6, 16, 5, - -10, 9, 3, 8, -4, -3, -15, 4, - 0, -7, -2, 23, 2, -8, 17, -3, - -2, 5, 19, 3, 7, -6, -1, 10, - -3, -11, -10, 9, 7, -2, -11, -7, - 7, 7, 9, -17, 0, 9, -2, -8, - -8, -1, -2, 10, 12, -10, -13, 1, - 0, 4, 8, 7, -9, 13, 13, 7, - -2, 3, 3, -9, -8, 8, -9, 6, - 8, 8, 0, 0, 3, -13, 3, -15, - -1, 1, -9, 0, -9, -9, 12, -8, - -2, -1, -1, 1, -9, 3, 3, -11, - 6, 0, -1, -8, 0, -1, 1, 10, - -13, -12, -6, -16, 1, -15, 5, 21, - 12, 3, 8, 3, -17, -3, -10, -6, - -13, -10, -7, 0, 2, 12, 9, 10, - 8, -1, 4, 0, 5, 6, 6, 4, - 4, 8, 3, 4, 1, 18, 10, -7, - -13, -11, 5, -15, 2, 4, 2, 5, - 14, 1, 4, 7, -2, -4, -7, -4, - 1, 0, 8, -5, -3, 9, -9, -4, - -4, 4, -7, -8, 4, -10, 4, -3, - 11, -5, 2, -12, 7, -8, -5, 7, - 2, 8, 4, 4, -11, -2, 10, 4, - 11, 9, 3, 5, -4, -2, 9, 12, - 8, -7, 7, 5, -2, -8, -2, -8, - -15, -11, 1, 2, 13, -6, 13, 5, - 4, -8, -7, 0, -7, -1, -5, 0, - 1, 4, 2, -10, -1, 15, -6, -7, - 5, -18, 9, -1, 7, -1, -6, 24, - 5, 1, -7, -5, -7, -6, -3, 4, - 10, 4, 5, -3, 17, -16, 13, 17, - -1, -7, 0, -14, -2, 4, 6, -3, - 11, -3, -8, 4, 13, -14, -8, 8, - 1, 4, 18, 5, -3, 6, -22, -8, - -6, 16, -14, -6, -10, -3, -8, 3, - 12, -9, -9, -1, -9, 2, -24, -11, - 16, -4, 7, 14, 7, 6, -5, 4, - 3, 13, 12, 2, -10, 12, 9, 4, - -4, 10, -11, 1, 7, 0, -5, -9, - 3, -6, -9, 8, -11, 1, -9, -7, - -8, 15, -3, 5, 14, 3, 0, -7, - 13, 3, -2, 21, 16, -16, -7, -9, - -9, -3, -2, -20, 16, 20, 5, 2, - 14, 20, -18, 5, -15, -11, 12, 5, - -2, 9, -11, -10, 2, -6, 4, -4, - -5, -3, 1, -16, 3, -10, -5, -10, - -2, 1, 3, 13, 5, 2, 3, 16, - -10, -8, -6, -1, 8, 9, 6, -3, - -10, -10, -10, 4, -17, -6, 0, 2, - 7, 4, -3, -7, -3, -4, 7, -6, - 7, -6, -1, -2, 5, -1, -6, -3, - 4, 12, 9, 14, 24, -6, -15, -12, - 4, 0, -13, -12, 1, 3, -6, -9, - 4, 11, -3, 17, 5, -5, 5, -9, - -11, 5, 7, 16, 6, 9, 11, -2, - -9, -5, -7, 15, -6, -8, 0, -4, - -17, -1, 7, -6, -8, -7, 5, 8, - 11, 4, -12, -7, -10, 1, -9, 7, - -3, 14, 1, -11, -1, -13, -1, 7, - 0, -12, -6, 4, -1, -4, -3, -10, - -1, 10, 1, 7, -3, -1, -12, 4, - -8, 10, -1, 0, 4, 2, -14, 10, - 6, -7, 4, 0, -1, 19, -1, -1, - 8, 6, 13, -12, 2, 4, 5, 17, - -2, 5, -9, -17, 3, -1, 2, 6, - -10, -2, -5, 13, -2, 8, -6, -6, - 3, -13, -13, -5, 12, -3, -7, -8, - 4, -2, -3, 13, 3, -7, -8, -14, - -3, -9, -8, -3, 11, 11, -6, -3, - -4, -19, -13, -10, 15, -8, -8, 7, - -6, 1, 0, 2, 3, -7, -1, 12, - 10, -1, 13, 0, -18, 7, -4, 2, - -12, -5, 5, 11, 3, -10, 8, -7, - -12, -4, 2, -11, -5, -8, 2, 0, - -23, 5, -5, -2, -2, 11, -4, 5, - 9, 4, -2, -3, 6, 0, 6, -9, - -5, 1, -3, -3, 1, 15, -2, 4, - -10, -4, 18, 7, -11, 17, 5, 12, - -8, -10, -7, 0, -21, -9, 3, 12, - -6, 5, -19, 9, 0, 9, 3, 11, - 2, -5, -4, 6, 8, -3, -10, 10, - 1, -10, 8, -4, 5, -6, -9, -7, - -2, 10, 4, 13, 1, 11, 14, -3, - -7, 4, 2, -5, -9, 2, -2, 9, - 15, -11, -9, -3, 1, 3, 1, -6, - 5, -3, 2, 6, -12, -1, -12, 3, - 4, 2, -6, 11, -1, 16, 8, -4, - 3, -2, 10, 6, 7, -4, -3, 1, - 8, -10, 12, 1, 11, 8, 1, 16, - 17, 5, 1, 8, 5, 6, -10, 7, - 8, 1, 11, -1, -6, 2, 6, 13, - 16, 3, 4, -1, 3, -8, -11, 3, - -4, 9, -1, 8, -16, 3, 4, -1, - 1, -15, -4, 6, 1, 4, 4, -8, - -6, 4, 6, -5, -9, 0, 3, 7, - 2, 13, -11, 12, 4, -7, -12, -2, - -11, 0, -11, 1, 5, -9, 10, -1, - 16, 11, 15, 0, -4, 1, -4, 3, - -21, 23, -7, -15, -13, -11, -6, 8, - 15, -4, 3, 7, -6, 9, 0, -5, - -4, -15, -3, 1, 6, -5, 11, -4, - -1, 13, 13, 24, 6, -6, -7, 14, - -9, -3, -3, -2, 3, -1, -9, 8, - 4, 4, -5, -4, -7, -5, 10, -3, - -1, 19, -5, 5, 2, -3, 0, -23, - -11, 12, -5, 16, 8, 0, -3, -3, - 15, -12, -1, 1, 3, 7, 1, 10, - -6, -4, 13, -7, 6, -12, -4, 5, - 20, 16, 11, 10, 3, 1, 3, 1, - -10, -6, 6, 9, 1, 6, 4, -7, - 0, 9, -6, 7, -4, 5, -9, -14, - -10, 1, -13, 3, 13, -2, 10, 0, - -6, -7, 3, -9, -10, 3, -5, 5, - -6, -8, -7, -2, 8, 15, 6, -15, - 22, 4, -13, -4, -1, -2, -2, 2, - 0, -4, -8, -18, -5, 9, 3, 12, - -3, 3, 6, -11, 4, -4, -1, 7, - 10, -2, 3, 8, 5, 8, 12, -12, - 5, -11, -7, 7, 4, 22, -2, -11, - -6, 0, 3, -12, 7, 2, 3, 6, - 16, 0, -4, -4, 5, -7, -8, 9, - -7, -1, -3, -7, 8, 1, 11, -3, - 6, 2, 0, 13, 16, 11, -8, -8, - -7, -2, -10, -2, -5, 3, -5, 1, - -10, -9, 4, 1, -6, -5, -4, -1, - -2, 1, 0, -8, 0, -3, 6, 5, - -3, -2, -16, -5, 10, -3, -4, 8, - 0, 5, -4, -4, -5, -6, 8, -9, - 6, 2, 5, -15, -10, 3, 5, 2, - 8, 0, -2, 3, 7, -2, -5, 0, - -6, 0, 16, 12, -3, 6, 10, 2, - -9, 14, -1, -3, 6, 11, -4, 3, - -4, -6, 0, -7, 3, 10, -1, 3, - -6, -9, -12, 20, -4, 0, -5, -10, - 5, -3, 3, -1, -16, -8, 2, 5, - 11, -6, 1, -13, -3, -8, 2, -6, - 1, 13, -7, 1, 7, -6, 5, 1, - 10, -9, 3, -1, 5, 10, 3, 4, - -1, -7, 5, -8, -2, 5, -3, -5, - -6, 1, 3, 2, -3, 14, 8, 0, - -4, -4, -8, -1, 4, 1, -2, -13, - 1, 2, -6, -8, 13, 9, -5, 3, - 1, -20, -1, -9, 3, 1, -13, -4, - 5, 19, -1, 5, -13, 1, 15, 4, - -9, 10, -1, -4, 6, 4, 0, -15, - -15, -8, -8, 2, -1, -13, 15, -2, - -8, -1, 1, -7, -10, 5, 4, 2, - -4, -1, 1, -4, -5, -8, 7, 3, - -13, 16, 11, 5, -4, 5, -4, 6, - -3, 2, -4, 24, 2, 11, 16, 17, - 2, -12, 6, 4, -2, -10, 16, -16, - 5, -8, 17, -4, 4, -6, -5, -11, - 14, 2, -1, -9, 19, -17, 3, -11, - 7, 0, -13, 9, 3, 1, -19, 2, - -11, 7, -1, -3, -6, 3, 6, -6, - 3, 8, 5, -1, -3, 15, 12, -1, - 0, -6, -16, -5, 6, 9, -1, -4, - 12, 3, 7, -1, -3, 15, 3, -3, - -15, 6, 6, -6, -7, 0, 3, 12, - 6, 23, 5, 19, 12, 2, -10, 10, - -1, 13, -6, 6, 3, 4, -6, 1, - 6, -3, -9, -4, -12, 4, 1, 10, - -17, 3, -7, -19, 6, -9, -24, -7, - -3, -1, 7, 9, 1, 0, 1, 5, - -5, -4, 4, -1, -8, -11, -1, 3, - 6, -10, -9, 5, 7, 0, -13, -5, - 6, 8, -2, -10, -3, -5, 14, 4, - -8, 4, -2, -3, -19, -4, 2, -2, - 0, 9, -2, 1, 8, -7, -8, 7, - 5, 6, -20, 20, 8, -17, -1, -2, - 13, -9, -9, 13, -2, -3, -8, -8, - 4, 8, -9, 7, -10, -4, -10, -15, - 1, 5, -8, 12, 2, 16, -3, -13, - 0, -13, -1, 7, 2, -7, -14, 8, - -3, -3, 5, 0, -3, -17, -4, -2, - -2, 0, 5, 0, 12, 5, -5, -7, - 13, 3, 8, -8, 1, -9, -7, -13, - 3, 2, -5, -5, -4, 4, -4, 9, - -5, 8, -6, 11, 0, -16, -11, -3, - 2, -7, 12, 5, 6, -8, 9, 4, - -16, 11, 3, -5, -8, 9, -5, -9, - -9, -1, -10, -7, 8, 6, 5, 3, - -11, -2, -2, 7, -5, 2, -7, 9, - -1, 13, 3, 5, 6, 6, 1, -3, - -2, -8, -9, 0, 7, -6, -13, 3, - 1, -14, -4, -8, -17, -15, -8, 3, - -10, -8, -12, 13, 6, 3, 8, 1, - 0, -3, -2, 9, -7, 0, 2, -9, - 16, 2, -3, 1, 2, 13, -2, 1, - 5, -3, -16, -1, 8, 2, 4, 3, - 6, 12, -18, -2, 12, 6, 0, 0, - 1, -4, 21, -1, -18, -8, 15, -6, - 4, -13, 1, -5, 9, -15, -23, 12, - 4, 1, 3, 18, 4, -9, 14, -12, - -2, 1, -1, -4, -14, 8, -8, 3, - 11, -3, 20, 5, -3, 5, -14, 5, - -2, -6, 8, -1, 17, 9, -20, -8, - -6, -8, -7, 4, 9, 11, 10, 1, - }; - - byte[] reEncodedSK = new byte[sk.length]; - QTesla1p.encodePrivateKey(reEncodedSK, s_poly, e_poly, seed, 0, publicKey); - assertTrue(Arrays.areEqual(sk, reEncodedSK)); - } - - /** - * qTesla 1p public key encoding / decoding. - */ - public void testDecodeEncodePublicKeyQT1P() - { - byte[] seed = Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"); - byte[] publicKey = Hex.decode("7561DAADC32E5C51E5C7AB83FB32FAA58E32A0D1E5134A07BBBC3AE889C85470D024D22EE8A269A9772C24B5971CEC2AD55A846C6D8DD917B76223B0799227F89FE8EB91020CA49BD528FF1915ED00D9F9709740A13110864F11C24CF0DD8DEA29BF288DCFE4B1CEB12A7135C5142D7F51376456892BEDF33A295D6D70AD058C51D565E8097D26440D57DDA86AD04C1E7ED45946654ADFE9F46A2D2CA0BEA6B2E57046D734A3989BD6B2C42B9413646C1A2F1B6C3E55502D8780681D1553601130BF98D26EA05C216E7C98FF0D5FC03D10384DC6E29316921F50AD19FF96772F998DA91AFC45CB3A00E67BAA713E2825C6DC2A0C0E8778444870A0483E588EDEC82199DA34B636966A85D9001C446C425415C8F8269697EAD5D69DBA92F77228808FE2AC5485612B0F28862D9EDA5D32D5CDD840BD45649C1D7C50044CC017D87E8D1012FE2EA0E26F2710467A13230C73F485F26154825038BEE477CE3154C36468B22124038C3C0A8E41C8681B20BFA3493CF88299E70D0D3FBCB5CF7EB82D39656A27FDA96E62CC84FE9A83DA858A9982F01803872833C48376E04C4E319744EA26EFD8FD4A1834B5058986DEF96CD22F4A30652A543D640C424AD107B54EC7D5E9244328BCBD166100969A54B003DB5F1D30B7D8462941A5C2E6E166563C1D7C7222D167E2627C98EB0F4274FB098C1BB288C8A12180E0A2F32596B54E3E68520B625B87B47F5E2FF64A1490CEC86E82E5E94359FDF6782E2138229D2C1EFF49B6BB6A722D033FF80BBA7A2CBC90D40E39E2E6777E062F4603BF87C407E2C20DD67E67DA5FB1AF696A05CB301B78A91A54F0881D5459E35E4070E0FA605C43E98C472C76DF9C31AAC8A7473DE2B989F297B230B751B4F32B61CF089F77317285D302011D7D6BABCF4C07C0C70AD4DE3E99C46EF595EA9A61A080DD48C74A0C961513C845DB6A5811750145D081B4D4E76DE5B15DBA5C1626289345049D5CB8771C7C129DA1C5DD8BEE596321647E853BCF8D661D194A1023845F420066244F6BB5A0D50533579AA0DB5A726DAB32EA2B35261AE5B6D0DEB12C31A79242E2D952AA1A1774CB90AE815BE9613A93B30AF30374F5C8181F54B4F5D56E07232F68C6D52B94BA64ED1B2B7CA37EE6C730E03816689853224242F0297A017DCE955C8B8D1B41BB3B12665759584D3373BC2C77999205ED56F6E8B6AAEC3346D1528C2AE938CE21C24400ECBC4BB520958E3303374C68A21D403A6E6F05DAB6A8C03FF07FF5B83A216B2EBBF8E357BCE51A52A56EAAF6B6F6D34B8BCE02E22BB67CAC6629A8E8C3F9F4E7A3AEE3B9AED01B2E3BCB3FE566E3DFFD8C4A9830AEF3D30DE63B5208A32433A4C42633C4840EC5493E891D22F409E35F02CFAE46A9D3DEED6C221916F9B27BD7EE3C1CC3C961E59B3DB42A59213FFB168DD170393832ACA8C79B52C194571681F0E8AAE2DB99C1201632659AE136E3B085985DC94981A5503D950E041763AD485E253DD8B329283929E2132EFA6B9EB08E79AF6027D6E2E7E30E3D6B785256BA2E012D003AB5C07FC4A0EAB484991B3CBC3B03346409491A876C82548E2BB253E344E80415E4625D3BF15975B59DC36FA00A7FD894D363172DB8C2ABE40364F549A00C5D5FA8B534E0CAE6A9AE83CB5E4BE6BAEE126B755C9CB8F76C1C8A6E6FE2567C1CBDA68370D4D8465D8B360880601206CAC0C9D0B67C0261A0E7D132CE9C4EBE21250F7F197480FD5E0D8DA83068EFA8B35475733FAB080BB888E1D1D89D124AEFD81BAB3D970FE059674B6E71455517B9BA322A236D272144963DA4A934A1D59D19F05FEECDF0F1E390376801E0454971E30C47109944BB4DF414E19326B8BA2013D5F6B3FA20188E5E9BCC63ED8BC55D8D7D3A086193F9E80DD32381B26BD534D34F298DC06378EDBA2E614E8C3D886297AD1B2B59FF78B8FEC0760336C5207082D82ADA01CAE49AE6500AD992B7FC0631491B909F449618E5F82B18995BC926F46BBEEE152AB2706521AEE3574295F26FC01A7AD154673B2D3B500E1043FF51340BAAA70CF8B3A65C65811318AC7B4A32A9519A00ACE331959AED26F86CACCD7A952F9D40E66FC31224AA1BD280F89A6B16F46AC39C5F6D709868F92D0FA519D39827D215D8BA7F2FA6B4DA67D5A791984E7A1BDB04A5A7B024762952121C109AA318FD2CE88EFAD90FFCC17419C2892C916BA7E7C482ACF41E5C386290F1174AE5C5BECC5A0D21E23B40FEAF220CB9A58AF8A5B5910DBE823359150388A4B0046090287B760B3978433317F4C2E1AF2A5BC87EFD2F59931F558ED226CEA7174B9BD4D1BBF6A10CE2C2D827DC4D36B2096B9309D42EA8D45B5AC2B1F7049CCA4078D4751B6B03DB06B8BEF3E119589CA61D7FE308AEF4561C4EE87DEAC2DB94C38C4760916D27E6BB2C169D1C88D35616F8C5EA6EDD4D48D6A5CFF409DD67D5BF704B832C3454A8BD14568B93F760EC179ECDED970C46BE39D5960352D2F5B3959758CA7A10C88E961D474449CCC21394D2099F6110BEE145E7005DA5501C0DFE3DF1094ACF99951A2974808A60108643E9F4177827A3F616009FA67E21F54C363BF8F162F33254D6CFED5E7C0D4AFCF9854620B9632FBE147284C6739F5FB4F211C20B1D9982215C2C4B1C02CFD041F8281E429940E8FCB66C32B694C2611D8D7F50A751D3969C2A3AB1FB2553CF0B26C0478C2988D9008EF4A1777E9F7F16122BDF208A5044BE728E9D928A52F133C1CC462984590D44E00FF7AE1254928A006054D008E780E5D10BA7E11E17E296D43D21F64544AAAF27E6AF9D4C7A381E4CC2873F358B3541454BA2D594602DA71273F50F99201CE60F93E1431D82D5402E8654206DFC651A3E36CA854A9B18E8DF0CE2809FA89BB465C68475020C51A773107D9B367E3C9A82370773A498FABAE4AE84D7685C9329FB226E0F5F6173C5107AF143BA84BB2CD9A9D2CEF930C5F8055A4E71C1CED7538F3D8FD194EDA2C98FFF3005BE8A73D09C7CBC8DDA07F4066BDCBFF23A1838520AEE0A28E69DE30019DA6AF61FE52A6FF10B4A9215F8F9ABBC9FB5081CA33463F891A53DC91E252E90EF4B0D72A35923208CA48C3793347F3D5FD28DE56538586D2C2C6C1FD50C4160D67DF11254BB36CB94B835734F5B831BF12845155B49FBE3B0F44CC5D6782983D9478C6B3A9F30626A797A2CDF8911F5BFA90E611B39B29314C9E4CB7F12A69D6DAA1916667AAC5AEA693B70BD741928014ACCD125137488BEE48BAABB02DA3C6A9604A16BF4D19F1C0D87FAC94840C721EDDF03CD8A841D2EFA5D52BAFB50726B45A476C47E251601B0127C092A4EB8A66A0CB7A2DB5503394AD36D54F37CC6EC73317E38AF9FB62BB758973971EE9E75E6D8AC67A0D44384439E7B11390E983975281A194F8173119905FE8FFD863D55CE7A6AD00683D4FF83263C81A447948DBF3F1EA2CA593B38E6719A8EECF654774599AB25D1EC9741AD3DE4DC23264C9700CDA27C463656E3A53C52B860B3264CD9FC0334D915E03EE74E54D4A2E2D795297FC748075A404A6C0AA6A22671A480AA3468B9FA9DA9A20DFDD8BB9100C8B6804DD6F16AB0C1B938FBEDC2F1A9DF43CC877B0F323042E9B1DFBB8A2BDA8986534D52B7EF06614DA22F63951716C2B04196567698552F3BA2067B2309AF06DB126727E1A82F731B0CC2904470429C1EC94456D1E66A0EA35A2A1C552CD3FA1A99AD3D748D563978800C32F5B6CA195938BA26CF721FFCDD9402EC4E37A9E1198D39516B4892919327592C67ED148672377A53C7AA9BD47D16282D977A40BB7E036A3FD11283DC2BD82EBA452474B827434014D0BF7C5483F28A432D378C6C78E6470F4026C27F531C367A2B950B0DD95114A106C72227CC33779C705B1C8926DFA2F996000535A0BB87BCFF4B9A12D829D04434AA579A11F6D15490A2C9FAF65042DB4CF88BE47368C589629703815FA6A2A1BD4A1447330E00CAE7645B2527FB82E864290C9574FCFD364F1A4FE3419642D24D98A6A33A0FC0E83505FD5151518555F9E03B2D5742630A119B2B32657AD6B2EE8B624508780F98B27E51BEFACBF3A7B920A282EA45358FA4145AA24E7CDCB3432C6F08D92421E2561EF811F1C60D7E51C840EFFD637D940F43D655FD1221F2A41027A71D90F978CB09E2264737053330E47E4C433F9B5AC94DB9B04EF7326410CC60DF7A220E1749A654FF6370D7C8197C808D35C2B6769E7CCD009BCA5835E4FDDA202D6C3DBE324AB97C879DA16184123CEEC3D5FDCC3CC71103E46E711CF8274D29B5CDF074BA889D6B0E51290428E0499022E634439804A488483D3927DDB78C248EBF9A6C9A678F4F482373580CB7FE2DAD993DAD34149F112D735C7E60DBA06BC44F0304551ABC09B9C91D4211FCD6025A865C90159CE3D842405A5143C46BE19DFDC64228A413D4225D7C94697C0F128B4336E9483192F3024014D2E9885447D0762F802087C7654786F76773DADA83CBC7396E5DDA29BEE95E93FD8C67D75C7D258765C7154DC822B925E8684DEB3443F85300C96E59192E8E99D2BCA21CB62713CC5EB23BF156FB3E97DAAA0695D84932FB9C9DB03E0BB13B103190246CD9AAF79C4B9C8916DB4B6BA02F5FA8B87B9E9B8D18DF6650E907E8A02BD67B4C00EBFE4E4C2CDA560D1874D7215CF0009DA57529EA831A8E71C88152849A8C2900134306C0C05A40BCE42A17CE9C025C100277D7F0CB35566BE5AC11B2466A2BB03B8DA8F10B7A30CA26FC4E0A3971E16DA0C5FCA52838361046549A77B9721027DF307AD3DC8B4EB3DC05BE4B0B0FB77482A794305BBE99499F6ADB05519D1D4A12740F91A363602232535458E94C7487DB90E777247864446B5A862164D9761DAAFEAE213440958E0C399B4DCC6C6BCCA44BF33512828B20402EB814384B9ECEC2B0C1316F3C545D4A65F31CC01B9E324F4468ED92896AD4572248E7298520FAAB161203A09D366EA8FB0041E8A79368822C557C67889DA58C63043C0B6E94B36C61CA41E5BB570448894EEE09F4F00A18A0164FE451B4D005AD5B9A1E3013C356652479D340594223238E068D9DC8C838902D72D97D35EA16E9B7A1852EF464E22D6CB4217BED00F1998134CC09098453C34CB9C0EA8ADD432E295A4B8DE30BDE1AB413F515153A75D02CE99B2EC8E45B3FBC1682973B769D688C8F6FA1AEBEE1795D1B9563AD1D462BAF1668D0426C457382E0EDA9A898FE694D319CCFFB53F378EBDF3AC7BBCDA8CB319470FDA31A1E4E920237A31A7F31392F54BD8991A0A98C65E8DCD9A9666B4403CF1C47B76D30391610161253A9057D23712ED9C71816D1C4B32A390AB6B4DE8F6D6032B8967B30471E80E2FF925DCA64887EA29FD14051BE7856B65B954A37F9577384245272B2098990F198EE1A9ACF1548299512F541E45922238F31115532A3AD6D744473F68DDCE411BEBFD933BE64AD1C7007258DEC9B112D4B9B5ED01FB4DE74E128C90BBAF64763A540E41B407151CFD8C2048A415304F05F7733238C6722AAB433ECE0CF900EEB02C24B20DEB96441E947ED1097A539C6A1B9E8B838E6CA2055ECC7064F43495815DCA3972B83401D5C8EC61708E692130512573672CCB5B9A56973E2EDDB1E3E1C965CBAD617D2590C277B91985007493DC9909BD6BF8578F2127141993ABF817B6DA2019DC6CF79207F96AB032B6D06C0512D049EA8663C46D5EDEB246F036C978496B1C1BC47E81CB63364F47B6913D0548EC13E1A37BCE62C68CE98BA1C29E71A3868491569B3093DAE40D42A5ED2972182CEBCE8F2589137699B142E3D3D7164939A081FDF237AA58ED794603943F2269A40B2967314C22E8668B15FCE244E145A3A49A3CE5BFC2C46ED93F40816A92DFB2880B5C4E755B2CC50914583D0FFAA28FD934E763118DA70C3D4137957333927FA4F0F637C4C52B9078E141089BCEDC7B4288019EDF92FD0ADED643C375E71C25ADBC8F94E04CA5A4E91C362D1C86BCAD31149636A895F443A491E6F558F9DC89ABA27967C7E66EF9C7302C100E4AD175021CFC295048BD5CADD8E86469EFA437034D7A01E38BDC64A6187F51F6D023CDB240F9FD0053FF7258D2C5802D1FA1C39DBC9D6D0E65026FCFEEC8205F77FBA1F64AA03B4D1C091AF43AB800839B4EBD378B28EA895111560183199390C3C6706EC35A05E4118A192E5A29C77CED86919C2A74A827913219B2C33E83249175B886B598CD25253A4B07D10C3AF92060C52FDA89B880923595865CA108EB0E78BA3F9E7B0465522CBA8DD6094131045E13A4C979B07BE8BD782AED050C3CF7C25ADE3C2A1CAE81738C55DC1ED0A33020EB6DC3464BDF6C16CC8223161991C62D149FCEA52140198B36B6379B47F5AA5EC066A5D5F561FDAC44EF3F967EE0E0A420AF89E22A053119DEF0D36FEAD69FF1B2C2476561DAF68D7682BD807CB4D2782C0B7FC39D7C6494BBE622352B534C21BFA25E6A37613CA73B85C98894EE1E588F20E73643F241F83003ECCD05B56255AA36782EB07283337E99144CD03B90680A048D4538D580728C0AD59C082104CD79099A08C193D40C3CAAFE3DBC968F9F8D9D0C74A7CA135F02C8F9C18380B00ECA21AE7E7A22133C1A65687C7F74CC5FB4BBD291183B803B1AF8441900134932217783D9EE86A565C8E9D316E0BC93E75941989C7E227D3170B0F78AF6F1D8FA70C697B4645A5F896B0C4971B6544D0C9786A774179E99EB4425C9838D57861C88E1DAE2E482D38BAE9D9C04DCC71D97449B13D3E9F6A52D81C91C0B02B581F4392C4EEE0514D4D39C84F323D7FE9A30FA87C5380913D3955C210B84444FE7CEDECF821D903E2102E8CAEF4020006F67B6D4B2146335AF10C6EA0A116A0110C5B9C935E349A6B29E8D609361B668E42BC0CD1E33D491D59FFD4A13E5B7742A8DBC918FE7F72BF18268121CE414D222C9AAA0522CE0487F2FB8545D19D7911BDCD4C81106EBA729FBD57365B1DE562A07660EDC92337C9A695F4DE495FFF27D63248BD4E4A96E405E39999A8AE35B6CF12AAB699FF741E298A3222D168EEE5ED1C0A372810A883BAF50E7DECA6F146F6DCFF1067EF4187AF79B70D8814CD50E39042417B4A1B7A230FE68504352093E91073307AD525F069F15DA88856C5140F8E89DFC8861E8678067FD054B163E02203E06AE92FA76FE2B68527737D99F2A13893699D7985F2F025DC3A430555FC23C9CE0C078E83CBCE363C5B5840FE09155F433178C46D257F5DBCEFC6AE9140F46A78872803B8FC6D0459C8A26279E1AC09711150E7F58F420A6AC2111647724DAED3867FAFAA58D4485F0265F0FF6A63C9F88CAB0FFBBB3579DC045903D682070C4DF15D3D02650213EA7A7D2FEE676BA92F923C1A0CBB2DADE5EA8F5623A548DC1060A2BFDE25AA6A09F80D8613D9673B66D2EBB124452921200BE54364DC705DC60BA75F2D0540C4168E6CDA16DA504D63068DE764E1823700BA4C97BF86058DDD2F5942DD5F4D3B19D6883412B6089FC6A6DAE5FAD95C3175AD53CBA016D59FED8107D0C64A1B50B1BC1380261A55D04998B99202078EAC318A36879D5C5AAD9299134EE66684179F8CACC52EE8106D23D0509D32E0459384B86CAE143B3E3C0EE95C8ACAE8D496E59131C80CDCA98B812E0452B8B9EFE94DE5424C50B935BCC927FF395D4D141DFC89A639703632E98451182D4D072A987A88B4409E0B5AD6F0CC62A5A10C3DC00B03597D1453B3257770E36949218F22D721302D3CE5DFC09D5604C943F73D75C996687931133DC4B6B061E5E74483FAD6EAA9E89D9467CE4C4FA061EAE71B02F3390DA9EE49D0EC92097321171D9771B1D65A4B54130345278FF8BD415FD5C9894B9F430E47F2967C650E376E614AF5F32A9456AB0C61A9278109404A484F28AC568922691C4C3965D465CD82FDFA330E3C9DD9E65687AD8827D18617C54EE0E3F6BF7E9FFABE7127AACD1B71573E2846AADBA44415407013EC01C5A7F70960870D1742DFD488B81A34DD7A286F4CC2C000E042352CE0120A637250B2A21AA998CFD1CA99BA21C321335F4A9222486AEF986FDA32C36F64172AFD225B5D358B59A06FBC1D388A99AD5780624E6A257A96910A4471C9ED1CDBF4AD41C74538A0933A460FFFA7B36C925E02D45D89A819725B8029742C189E561840F20EEB86252A6925116578A705FAC7B5B9A128E1B429E321C0B8EAC6B74C9590E6B02DEE15A0AEAB25B7D5533BB7B6D9299620BAA42C097304795B71A91DEC14A32B96438B0D4C313DD9A25A916554D2164D787E800B524D7E02215515244E7994C427574CA0E02FA18244A81E49C03C59E85524C8A76B77828A938A0BE90C77595567FD2619381FF0FD601777B7C226AEFF35E0B5BB7D6D88660027ED4E5E4265B2E0A775122A2E375F08DC24F4F327C9C2766F9CD8DF228AED7920250F1730A4A7D08531A26827EAD62E1BAA0A45EA9B8A26F5EB7CB6B36561F72FCFA31BD4509FAEC210D79E0E86B3048F8E629DABB24AF46C73547D40C0BFAB592078383832561F15DBD90E4073BE80079F3A489BCD51B98278337077F6791CAA0AC828A14865ADD78BBABF1113A171C06D10796415C7B0F4F3B732745BF9BEC82866D4508C1930B22E391FCB6D68AC89EE0D66A8B76BEAE525BC89AE9FC4C15A21169B7FE739DEAA80A7F19D5C669EBAC95A71EFE265A1570400315B8E853B7CB18E33E3ACCD4CF9E48546E36422E6E0ED282519DD5280FE5DB8B7877902188B17C4120444D729920963CA5AF34B94E365A8B0AF7947142C114C3F0A7FFF0714ACC3833CE4C0864185ECEFC7F36736F3E267DC956B0A1051ED765DF0BD12E1D25760A09EB05C16B327A30BAA1EA24552E15448BA1B3E1DF0E8550C7F4CB8240DD4146AB5FC002E33B4FAD65115439B10991417068B09AB2EE5B16D02C250A020B27580A9C1122604D1D69CA74CB478582614C56C4CEED92660B643C50712A132EF7D148BC27C4D1FA1E8680AE171CA8643EA4BE9EFD4F442B1BACB36221370D2DAAA509F78B76FA2611744D7617C12CE4B73914A26A0E64D15E8201C5BE8313FE0B0005102EDD25F95B440C96B90D9A92720AE271B542060B2EDB0245BCB3C83F901E2631B76C24768D28C18B01DA9C184DEF925D68C655E65A013B592D161841045F3EC54D0088449A64FFF0EA8E6AF632347BEAE431C5EF288A30AA74D95241EE7A6FF4E73DD22EAB04C6A6339CAA3A4E8C181E0751AEE8468771EECB0AAB3427493B0DCC2B19DD9A586DF437348C7CF9C5E3A8B1A630D5BBA6307CA395B4C797CEEBFAF5153258B325FAA9AAD673DE591DC8C0D589C61EB70CB7327B537AC1A31A6EA95C81C886CB3DE52427BBE10736E1BBDE9B8EA4AE6A2B44E7BC376B27C08E6FBB22A73B8D14CBB3BDA545B9430C30D6F3D67E0B42D7B122DCEC983B996188F79FE193F03CF1B446F166C5D8F2B1FBACD5C85678698EED8E5C76E2E0D55B955A2643FD1BBBC16D5F5BCA479AB5C1182FE2918BFD722DA84A010E60164C3ABF8137D293DC8719731F40ED404BCBF171E99F511F1E3CA723D59C34D78EFBBD463403F1E87337CA461447FE180EC53054A3F969218290042FF30D798B0C20A84C12A4D632CC9955FCE0D5DAB4AD68E71E5E4F5E446DA5FF1E2A5EF84BA2A3F222E4240355850B20CA5065330046E261E88156FC1A84442C60ECBF4C3D2242E27F8D806B022424D917CDA2830CC401C7AE9F1221FE533EABE3CD2B45E5DDC9379CEC4542B529977E18A8CCBD41B827CF900268CF7F6EB88C82415BA10930D1E157832F46E1B0F14E4944B720270C92509DC0DFC24F605A8AC015511B5554A4170F97064CFE6CF944D3B202A7C17DA356ECA45D92941C661B70B4AA679EC10DE7230C095F0590575FB28038E02A807ADD262BE38F3CA3F5A1D103EAF88EA59449AD040FEF17E702D2E46424A19216F2EA716B60070D5F8069215D580B296EDEA56FA3049972FA9A7CC947E1C56F669CD228B4C0446268BC47FB0D160EFDF7AD3218D3D57BC4B583319CA48A21D8D1BCCE5179421F776870F140CB9F18E2AA1DD2C5F877D91CBCCED0B4B8D84B111AA7160EE85B2C9B8AB69C1E3EE4431FFE4D3BD6A4DC6C8A800BD20CD8137AE1754BFC244CA7C5EC281381A237548A9D9AFFE7100B4254302EDD5461122D314B4938BA7B2A4423B40142E090E7AA3A6FD08578B40B17F189F9B16DABCB6DA64DA5470991398E9B3238DE4622FD2D12FCBA1928BC861ECC336BDE65A5BC43B6467CE293D37A1019EFBABA13ECE121B0ADE45AEB7C644C2D49C05B45F946DFB58E78B5373A4DB14884A241367672A563E3242D1856C8D1662D5F3691A6F5C769DCEF47778685BB448A8ECC5179EFE36CE6C7E5C04FB2644309018C064B2803CC1377D19F59D30B19E04D2981873CECC5C3E992C8889708B89E1990AFF746B340AF895962FADB2E2F926342137DAD8C1EBB09A616F658F40EBB28D3858D21B9F92A7FCE7FF2D421994CBE6072BCAC3E0DC3A030A212219D5DBDC906B07DBF29DB8EDCD213667F40CDE4AC7FB56E2A08A55EEAFDB4E71196FA642828D56983AAC268FFDD7E5BF02CEB2581B6DB158C91393A36C367F36AAAAFD2C40C2B4EB40963D1332155353412A2126C51BADEA6B842D2FE695B3CBA2E2584288304015905AFE6F808CF58A708290C4824CC484EED112384309A28E028D1E2EBD46CE419B5CEC1D9C9164C9A40218DCE50C9B466A8E3C357D3F86EE02A51F86FD361C000509AFB168275DDFE1F1BDCCBEB92CBB345E62CCD4F0328FB0A35FA8F28919927C1443D289AF808C8F034D28F79038DF670499E6521F080F0D365F2400D5D086CC7C0041D4DF80E4E4CE3906215D18EB720466CF8B43DE1C692BB71F63DF253EBD498A9020BA92517628263F65B8CC41A5D21BD76B6436029FED17639049766716B33F03E6F1786852AE47250BE2FDF8B6BC4F0084A823256B34A2C2FF4931119139FA60DFD0F376990DFCC08BA8A09B0EB3DC299CE091A1A15F1BF7C11FD35CC40BA9C2C624530441027ED45FF8C00EB0B2BDF7BCC18746DA7942C342D2A58A88EE549BD71915D1D907F0CF89C6E2CCF63025E0922E95E713AD78DDB8052E17007A83B966279E860A19F38FA484702A1229ED9BCE918B360B2C1EA70ABC182F62B2B6306802D70E4E2A83D46CAAAF950A1A20DBFBDA6ED1F21AF9C2AD2092875EB391A925951255D9FAE3292EC485B5C3CA16B003FEE565110E0A910A010C499AF322039140A83B28949AA8946FACC77ACC38CB4AE9E2AA250E34C0E63260BA989181C7470E0BD484C17704907A39EC96E2F4269CFFC95F311DBEE98360A999FFC28BEA9F9446A00758F83B5D492B602084DD47400864696BFB5119923EEC8D5CA82CF9F2BE623A7046A741A8F5A31259A37247F8EE9CF5EDA91B5BC5DE61AF067DAB0CE4C6C9881EFFB4E1D40C87184C38CEA0E07409AEBE92480294B852E21272AA71463C86354A37704B682825E1E7A1FB84A3329C376844286683055AAEC5C8BDD71BE9C88B3ABFA303E7885A0A027012B2B8EA8B83BFB1A8A8C4EC028DE82CC11CD18511E3F56137D84D326326AD2E0C479513F5F112E91454C6CA904010D328B94A26AFED5C8F14609037E17355E42B24222E7E5B1D84E61895C45090E769734E07AA03B00D08A0ECFE0967D7AE09D16843D54F6EEC12584F87EA7AD832B90DBBA8E39A0D21E867E3786D8FBAF19CDF7E56E9E9A44F421DD350D0D85AE095AE2F2BC0F9C7A8748279720BB0C0C6E7919CB83C40BDB3EAE1A6F87DFDAACCA342DF1C73AE02838ACCCAC609504A12F720356A57C4A3D21794A8106139C27503E6A6C47844962AC9FBBC0244601888B6F2CE6C41F8CB757F3E202F8B9A27D3057272745198A5CE7D2A4B227EA9CA6F0838B23EF2C66950F38693161AFBFD724EEA187F9D324C970B9F4BCD408161906A6648D18F4E6D52123F02694E39B6D8D1BE691C5AD20E793809F4D970893DAA133FB310146463EBF24617072871AEFC1CF9E885923416128479EDCCDB941FAFECE56906243A74FE19CAD9250141AE8B4CA6A343926D9076B964733D8978A109876475EC66691F659499CB552C28ADB0420E335F01DCC2BF041BD438E830FA09AE673C03930FF478300E5C1FCDFE6932AEBC289C3713A08B3136B37798527B2F67803C705107F985A1F4584AC2FEB24D195234DBFAF4097C1A1A6C50B6CBE1D31CEAE79299782B7A4482C21D1ED48EAD643681282282B1B0BF1150C20364431F62224FFD07EF87B9AA4CC4F73FD2284BE1064682DE6851DB21F786D1B6F73654DF04C06FB4F7E1CEF9480392AA851DB4308EFA35A16CF35B59DDE63F6208B90C776BE38CE0139E97C041D508DF432CA1D399910CD19A1A7C65C09A6CA89A5323D205ACC5BC75C312764B0B6599E10C2B8F4DAAAB9B298CC96CF3BADC21E4B797B52AE793B1BF08162DA0D4206FA64D703D100580435854460EE5085BFE241F8E149007EF2A373E2F48E55112AC1394721D0CC272C5C95D3EE9120A3F9F7758E5BBAC508FC5C20665132DEF552A7A65D122AFCFF8B1268ACB094DDB628D39ED6A5A0B86FDC96A7843C3043C083D8C06C8016AC05CC517BAFD15B6BC3EBCE8EE5F4C6D4A6B0722075586C66A769F714AEAEA49D6A0F5F330F8EF78EA55DB2FA5C4D057D3A1E17A92EE224745723BDD8FD7E6EAC10AFE9A0E22B702CA226F694FA079A95375E66B002F1E3C72C3CF63AF044C435A7EC2AB93570912535C40543A3B29AA9C8D07B0434443B32DE9C64B96385390FA0D6DFD80C2528697D253B9E7FD3AC3E5665E1FC0F707B7624FE526E5DF2242CB30740B6A965D82C4CC1F56468C8B43B4070C59F5F13A96E2D46ECCABDEC4702D1E8D57DE00F17200BF581760519FF2CA755AB85B1E6072000B0D7469B36C1D70290512A43F2B492C90C16AA08185C0920EB642054BD4D968396BA5393CA0364224CA7CE9EC77296E0E0108C691BFCE7B312524025B51F62C5A631440A21EAD737D224A9BEB8354C6F7293A710909A4C20E29F2DEFA90DC3AFCCA6608CBF4BD37800A4866A47DDDB7D6CB93E276CAD4C0BC6363B2204B8BDE55B1017181A57B3D8C21A452AC2E90329CF0A57734FD3D566CE07DAAA277390C0ED6A5F9E004F6A21AB57A29EAA2483421C06B7F26ED889E8FB5EDB83D7B323477C71CA2747065C8B6F25319E56CECC956A0F668EDC3667D16D2F511BCF247D1B0A0CB333741C2CDFBDF42E2397B92D582B2E2BAFBE4283F482460BC4EF92285A6C6901FCFD5A4207AB3ED31F0F96F887A9AA3106A11B8631DB062549A389BD938DAF7A78990698F57CD28BA283BD1627E33ADA7A5FED8F99D2916EC6369C3155969B420BD3226C7176EBADE1FDA729F841FDC40A4B71AD06CEE87D22CE513F044193ED05CCC89DA0B02BDCABA46B55077744E5CC67400CD2834299A5117C73ECC94BEC33014AC80A44B213E2454429E87186DE2AD19FCBB82717B410E17D53E0D3DC9E19549440B254C7476566B5FBEF170D9A72103FDECFA8C9734D1288524F5A14180BF729E56A3FAAD46EC1C565401646B60C319676274BCA3348D8ED8AD4CB033AD0E60F46E9326D7905EFD342FF4E62860140FE4EBB0B10A4A50BEAEEBC69454DCCA565480F0A343E69D82DC782356F4082E654245E50A9EB928B14A12C23554AC2BB690CDFF0A780F8B76450C894010C0AB69F32D1172F3A4093EE363285A1BCD8A28B652E02B0AC6AFDFEDC2FC544C70EE216805EE18F90FDB9629B315D2AB7DD2E4B07EEE3813802F131C9E9B1D28E566F9F92F0418B4D5D7C8F04A1B01FD4B311A2AB22B0663DAD07F993FA403F7752E9C4E8EF2E7D5B4015344E43914150AFA4C44E1761CAE104A9DE91BC81B6806264B4F888B7F24AB645F2F51D745C99FE1ABE1E733B8F9A54D6909E247E098D201293C3B70069D683DCE35AF0D91F490B1E439583129F45884ABEC6B25A5F59657C4F74846629746C48F25FBDDEEA64C931E3B07082204E35D3CE3DA543131FF6A284168D245EF1196B5138633030286F64B43B6BAEB12C266881E44F25B5A711553C8B30EB66070A12EE3B9DC78E9E91BCB1F5748F40DEA61B36711588A6A14060921D6776FA84BDA0B585A7CC1A855096763E91AAB01228F7EDD01C53C2EA0B5FB420CABCEC9A1EAB94EE0152A5D315AF370A1C192CC621FEF816C3CB4B9344DB176EB226138787C75280AA061D77ADF001267AD32C146C21CB02B7F0557624335E764B1BA948F81FBF69BD29641060EBB9AC541437900CBF32D8E206695E496E4747430243DD78D80CDD17320EADF225BD0CD0D158F95120AE130EFDF13441BF7578F4DCB3964DD9B507B95B1CBA60230D356C40C51A5D457F92BA19148D6A6E3F459A78A874921CCE17F654B72574398C481BA54976F940C1239CDC045F953EF5943BCBAADD35B9D3CAD3195337C4F28385D61282F97C8E1D63BFA91160F254EA157E7444E98DD5D871B839A9042E5E815BC681D6495EFD3A017806E8C28C4E0627DBF61D1240C12BBE5F08C3CEAD6A0635EF7CA2E816C56284BEE2E8ACEB4B4954B00B44DE006633AC5840A26D415C94A25A88F5B2B7B522669A9E9DD142CDC188B20A9D545E307081602646AFAB9A32B725D66EF158E98432BC2D889086DEC63D7C7B4BDDE13B3187FEECA3488AA1531E606839C04764902F0800955C6833C00FE3CCEDCDBF75F087227BF12F4603253F6177891F37D408D6D27EACCE1512ED2664BC87540510C43A1A89D8AA28C8DDBA97B1BC92DCBA9A68DFF3DC57338DC45F891BA704D17A18DE5E142B09ADD8F97A3A1266B251392C0449561E0D4EA4AD1B84D071D28038D5AAD50BC86CCC3569EDF18E5B24046668106D24767781EE56605BD41B1195D8470581517E3FD8109C0AC24448D57C146CC5D1335B140B9B4286AC0F6D2616030C0458BAD9310AB6EEE683489A1146F7A08E406F00A4CE8F514D4CDDECBD01EA05977F55C3871087B03777D0149BCB81E3A456510014E7AF448E03A36855777464E463261F419870C2E54A63B7E6D1BD9ABAE22855469FB9251394F58329F0225320C52A333CB228BFD6A0EF48420DD3C7C550C22459CFEB0073386DBE032D31C5B75ACD4F8C67AD82C71E7183969D20769A18318A725D1F22ED2BEDF1E9D72C4A8C240943370FED1DE7F23513AEA2AA1D5AEE27AFDAE647F03D98EA7121891227C9485A0A3EB5C72C263998B13CD68367AAC51CAB3CDE76674341A593B05546DE545DD0CEC049C4D445DFA36019F1448AA432ED1C0B70D11DCD69F188F10127FD96984DAEB3D2A7A3790196729BBA73443D109B38A96E394C3419F4E187EA26D474534588F2E9124E52E1001116886D350A2CB3C6CD3881FEBAEF336AC1162C84D0165F14DF8011AAF3587FCDE8D0A19FA260B652D682F57C65C3443AB602FBC27B8A0622C231880B1E62D095E1A4FCABFF880D86C3C4ACEA5946D981369678F4E34FD08A4625D9060363F22526D4D8DB175D6D854A9D15609F704322440AD183FE6FF3F4250213006D91FAC2985BCA13D4FEEA8020C8DC6770F517CDEC026E125C1AA3756A34C8CCCA219B0C214303637010586B8CD51DE2E9A29DD9675411C92540822514F10205820A2D6EA2EF3D742635D81A72AF24CE08C8FF0DC150219CBBC550AA20DD7797EA683ABF681C8042BF242C2799E55EE2C10577E3FDBB413B494447F121969AB56660700E260C31A01B88EDFFF3D8308940E295DC5AAC44CB9CDF672B3F7AD2AC7D7AC1CF668F913A64B8573A60947437E1270658919DAF571289CC5F2E0E7BDFE3E4911582B540B0B36732C5550358BD2738C70721D3C18A5BAE95A3A4DCC202C5634C390F1CB489CC907CB4DCAFE6FCAC299CAC3655BD7DB669DE2AE6AD77F3F78B4A6A154D7463944DA23515D1AB4C75456D601736BECB027B0D544062271A3345E0C9BF9333EB1B02D5038CF771C2EAA1FD6AAF8F40E9F077B907827A31193AEF045F4CB5C24A9F490819644834D01B57E09EC21038A2A701C7D21E0E92C67F3AC8151F9AB1442A9C122AD961DA84679584324F42308C384FE0A844714201EF64C0602EECC06C45FE04BFED8B664930A573B95FD7BDFDEAE6E6CB1ECC8EDA92939A92937C574CA50BFB8E6D4F92D713A4A0C3B9B098C2B45DCCD2544369A923C73DD95B6743D96549F9840781D6B0C1876B2A407640024C6A823292E4688D0A8F83EF689D7BA5A31F2D2A8039E355509F0C6A199D782346FEC75E9D9C4E5BCE1A1E668AB0F383E9B40545A36C4C90F92CCF6032DDFA51EFA03A1A026B53E092842AC49858E71322081457CC6006D81F0C3693F5892FEDBFB32290AA36B1F68199FE655E3BB57479012BC0090E58E4B9D6074A5665996666394ABC542B063174D67C7038172B85B646D330A152FF451DBAAFE2A215D1AFADD79CB9BB785E1B9F400C8DBC9F90E5E2BB54AE66760C0781C1233A33220521096AC8C5094FE49E8D631EA05188328C9732502ABD8A0EE35C8ABD039902A5C8A0C7BBFCB32508A2591731CFB1632F39DF33C2B6F36A6331E3DE35533A3CF7932D417E753ED68F1BEAF651465950B455F292A23F3675DF243043C727775C9BEED7E16789F048AB34A99E9F86DCE589211541DE582AC1B9139B25EA1F7862808DC97C598BBBAE330839320CC36DB8ABA774CADA3711DD41D44F9BD60918C2346704D0B591B76D8FE88C523155E3A7C24B388540C90B3097F4F39141CBDB541DE113F726C102B11A659E403C9AFF464A21AA4A5B3ED8132620623B48121C203B94A32DE0A42FFCB4EAC69FE2D7DE4E144C8C071DE51B1B11111E139AD656552A757DEF878844B97094A633EFE041288E275CE020A935D2F0110D09E7A9720E04FB3FDF8390B73CC92EF9378B802C2371A2FF1F396D95F587D362A615153AC8F687D84367B2C72F24C6A92C9B7119A92B95D69CF4BEE22A40CE1D0354551E2A867C78A71E38EF22F82240846DBC93EF1BA85D152752E9AF9A1ABF3896C1B36A082CF633645EECFE133E60354A05FE5BE0A16E843C8B9DD6A290F0FE1572614362B0E08C9569CCE55ABF8DC821356629F5313019D52496F7BC794BD2B1ED61260FFEA4D9BD07930EE2E66CAC9464710B87A318C6F66242C0764005DB8F9502046582F0A99B13B48A00F8796E846B2649E807D6E4B66A39BA514E07D53B0C5D85AB54BC30969E8CE0AEA37F5305F6F8312207B8505BFFB78DB0A29265D2DB06E0F617E626614371F8C49208B501ACAE806E3385458BCB52DB4D182B8F39ED5E4C2775D0E5882C189B38B4ABC1F49CE55688E6A044AC3717417D96053D0F22491BC3F5D93FA197FC246238864488B5C9A334773B11878AFB48D086CFFC5C8E389EC3AF54BC44F1C53B5273C8851F94D17F841F9D99F4EE8DC0A96640FDBA3B43F3B0174A44A2A8785CA45C1CC4462B4E201D21E3C749AD482B51079C76D44CD0264E074A10658AD6BC803314C0568A1B73699C5566DF80B5A6ADF40E80C5CA3EE7E4A989D4C40E6E043614F8829192308656EE7D81C7EBC53001640345FC9CA1D14CD3D2DBC4CA88E26224162918644A34EBA89408DB7B8B810476E33369014BE8195A7838BEE3BFCF49DE0CDFC19D50B57547879514D53B38CF19CA5456CE9DB44C08FA05E55A626984DAE33703DA1CDF56E277F20E3A9985423C9CCC85287D5BDBA4823CD95AB0D6334DB939FE601A8F1D18B60BE9D010B6D3DC14F6E2DF2524254EB0DF39895F498E4A9C46FE0BF5EE151CA3401D4DB116336F456C64E1B5349109341E94A852861D152FE10C400B98F98A7FE976852077D44765D191593723DED3E17A4DAF288BF54829DACCA038DB37070BE05B968849D8EF747A157AC51F33A31E1934574E6EA09220547E740D4472F70BA581E88D15C8C768F51FB6B006688F34BE85680AEF80B6FF74D1B84545EA641CEEC241110D4157E4BA521235529CED6A43F101D5CD9595E020E01019D819C214962576047D923CFE2EDA821DE59109C845DB58DDBBCDC2B0258CDD0D0B3D7833EF57CB9935F09044D50928B665E6460EA650634C55FE146F2B784331B815C36A9C966C9020C5A2FA9C351385ACE18405CB0EA0039F14F11EC1905D0D273C57E3F8FB218E5B3C5395BC8BECD356D513455FC70B9EC32598E677527F403F9D3A9F27FA14788D6D29F28019F44E80E2DA4787B13E60A43C8E66D81E53C3E42D02FA188C916B515D74C20724B2FBFDF902C720747481A4E268F13087900ACE6C33267CC83635E0B3ADB698D006801F967625E492B2066F6688857CBDF1452598F3319D9ECE68A85C1564A343B52913C8C09441E13C2D5F3BC59D61B624E9D671268708EAE80D74100446F8FE14A32E7DC41C4439793CFF61893B5A4D39883E99E0999541A82AF0DD8B93C07F07A07DA922217ABDDDD481EE8C5A2D6A6D0623AC3F2ED28116EA5C7ADCCC94FF0E201D1C989DC676D4043F33F37C442DD20C9AD459BCB89C2C50B453E6A91B087F3DFC72411C80E05B675A5E9A6129D0D145B3A119147FD00D37D92179B88E3AFE4E77F24A008A3D4B0DC86FBDD2773B53124E4DD5B30B08B048639A75C7094F966E81612D8C0AAF7E4B03E02E2930BD35F8506CED8B491C8038CE8C1160B5B4C11A2E57FDCA4F2B242C7F8B74E18C8C77801F09B277D4FF68FF40605A286801F24E50106005ECB27136EF343597CBDE60B132A57809D1F1FF82310E69BD5A8B851963486C73A681F04473A00E137737672B6E592572EB162422A17752CAD3E4D32076A49125B02B090731648762DD08362853C32A000167E8B32E35A372EA9D6686D82AB35656A4F4E00A6942CC4BA40E468A32C013C4BDFA76C73103E930BA5C75157B62DC3779E779ECC0956EC7758D83604D480590F88FE77B1FAD5AF7472B4905DDE62C59D14757ABD800EEE2D88E496BD3C544397A78A041E9161CB37E3F4E7B6E09C424EF12E9068B898944F53908FE800CAE8C10F625D800E0AFA6A53861E1A1F7C12E2ABA9E0D282EF848BD90C29A90A54AC5EC53BE5CAAD67C5D276E0C69C06862E1A79B9736E19C3AEA178BA8B0AE170BD304C4319DF261910B29B4B569D1B3507BF87468063AB4A53ED2D651DC7C47F6B42CCB57564E99DE5DD438A8069C8967E25DF402B8929EA8244AD67CA9B8818A03067B280A4DE2E1A1A22995BB778C40A704B0CE84A9248C7B6974970513B29AD3E58880E15054BF028AF26CFE30ADED531EAD501F5263F289E6FCCD67E978434296C52F42AA317E06C66DC4008564E971404E17AE00170211943105E89A8625B0B7D76E36768D00CCA75F68679938149075AEBCD04EEAF7C5C0BA4032C60B45515CEEBE0B57AD05C25B6A932ECB6F2ABFB088253039908315629AA975B8D2EA5CD5A1964C231934A310BD222C8896CB870A620293536A4D93E29538AE3EBF091B6EDC84083CD43DDE7DB84440C8DE69079EE11A1B7E354D2E02A326E0FA84821DB48C9B886C10D2EF5286F8DA7206C1CA5EA16852579B0201F8598446D4C0E66EE116507FA2E1F853C11890B32D419E093698B6B2EBAB9C4417178985B8DFE2767BD8624A2088E756EFAE37E98490982288094977A7A2538907653FA78952C133017BC129539300159E75E15C93807F8C8ADBC908C466D720E2A86D8BF9ACFC10263620B9B31DF7EEA587891D693154CF251AF35A2DC01B4A837FB8CA74F1AA744CC53AC3953B68D51F71D14CEFDAF91E3972B2993DE80F83C9E1E401128531A8C17462BA7892CB962BC084C91130CE933A36B2A74AEC1C5BFE498684351996E15CDAAA5C5AB9C767228397135845E82469085104AE5D97523C0C7634D0DDB2D7F49CA6822F6BDDD8AAFC7558A405D1BFC00DC8E80506B0B2A12767C0F905CD1F568991CF277EA51205F04354E80255FCE010B93E822CE08C30448C6F631E6D6339949E100F7AF00357E982378611BD2F17190CE6E2E71A43FB8E03ADAA98D54F78445B2C7C433409ED8CB75D2FC9344C7B2C24A5FC368D5D5C7CB9BEECE94647CC6B65C69DF829EA1EC6DA913052A534990D27756B2BC0AF7A533A945A49B4A3B20668D94254326E18226EC1605B63EF618C1259C81BA5342A20CF8DC64E39F4D7929694B516E64CD03614290D3C033B6B1C0B030171CE4EFA65491D1F376FD2469944524666EA0A28AAD35A48E15EE79E677FE2B38E9B11C1062731935F2513AAA3A5230A75A50AA446700B10C5A326776241100A2155BAE98E8CAB6843116B153E8BAF5D46399CF5F6EA67202B0144E34B0E1BAC6C1AA55FE7CA565E643BC1E15A1C09FC378CE37548D23BE3283A74D6B590CC8D25C64464B83A506D27AEC7F721A911F039AC4671A02564DC266A2EB78D6348A8D100E71F99FA861E499CEFBF200F8865D244BF30BA23EA4706290BD108EF82340B134F9E1ECE3C1226714C15BE72D5D33CB8DA2CF49181DED7BA3055E26D05DD8511D5ACA38192BD1AB7271B653005A6EBD06A3DE983CA28259478B4EAD1D66BA479A92F375E892075329BEA241C4897187F64C370F0171DC5D48CA543F3599FC8A87E7AD5C46306DE61518F471AE909B842601348CE0D92D657015772A7A59E957848263E359EB50DE8CCE2D2E37BC6DD42E4B880221F2B949BBE202A2648F42E9CD9E958D5481BFD186D444320FDB69B249C4EC2A11E4C6868D1E27E0F601163384AB8BA30B063B4D82C70CB26F061B2450AFA9C489A2FA3F11A09EA4CEF28B89DB6C5EF2A23CA9CBE1D980314807ADF85F64B3E627917AA0D05E35687BEE745FE67FB72842B1684587A9C41A8CB8D424E30BA1A7D0A17C6891738AD96B07C9881141FAC9B1C76AB47D0A1D32EE8B3D1B7F38003AB07C7CC89270E004942C3EEBA178E62D0F6EDA1C81B97E3EB2492AC594F710F2414119A481936A5E970F941C7BBD08DE49304D1E446CEF76E52713DD9485EA73CFC6B92DF4B09954DD20371C1E88087D73F0C885A68327486A812A1C9C36DA7E"); - - int pk[] = new int[1024 * 4]; // PARAM_N * PARAM_K - QTesla1p.decodePublicKey(pk, seed, 0, publicKey); - - byte[] recodedPk = new byte[publicKey.length]; - - QTesla1p.encodePublicKey(recodedPk, pk, seed, 0); - - assertTrue(Arrays.areEqual(publicKey, recodedPk)); - } - - /** - * qTesla 1p signature encoding / decoding. - */ - public void testDecodeEncodeSignatureQ1P() - throws Exception - { - byte[] sig = Hex.decode("6238CB4227F176C95E1661842CE9AABDC1BA0DF9801F74239152654841BFAA0EDF0294AA66D9BD9AFDE6F7F3627BB787B556493F32A81F94FF26193539BD9DB6D7B7DE91CB22BE2435BCFE3DD4509D8FC316CE42FB73E385DEB3E0CADFF8ADBD7EBBA602003FBC23F63D88A0BD31319A2BFF0721488191DCC13E529F9A6E3359AB22BBAAD3C85C755FA5649EC2BC84D7AD920DE7F9C6663B8BD56F53F6812B73571418922B710FB3BDB86ECF3BF1F7D12A5E32F39EB4FEC46534D940AF0B9F069C65CEA2152FABB44E870298BD07270E69E000342A1734E1CBEEC02E89FEF4036991460F4C6B71BC39DCB5DDD8FCBA78A264EA1BA64DE8D7C36D786C688E369EE15C55AD0F18443FF9565C57CC69CAC4EB5ECC49A77C799123F960FE7B185116BC6BC991903814F9C736815AFEF27A742A58A684D2AE284661AFDCBBCDD66B703010DBD2DB5AB56850F35E9F819CE240AEDE97EA43A483BD6AE1A9A8CB7FEE9B2B3398B63642EA5A7739BD793155B25D53F23BF08A89EA0A0B20829F40E83E7544BFB7FDCE3DC75189319D7C10E41395A40B64E909F2B7DDE0022C80E00C73661EDC01B18B5AB934D6D10201E5E11C84A90DDC9C41D98BBCEF8C575DDB3445474090E0EDF7AB340BA6256996B6ADF37A2A565BF81C31252C84F73CE4B30041FCCC674C44A439059704E944FB24767D52A6C72A41483B626D75D29F00CEE0CF53EF26C44BEF2E05105E64971D00D774747E0B590D3784146EED28C5059EE3203E5C668AB3878874F7B2B6ACFF34B6531952496624D49F7CDD3A2C4041D9296C59E36DF4C5AC471AA470FC37EE2E15ECA7891287D60EAC457D275138EAB20F55D2A93BBD2D1EF87517AB1F43ED1E6174F169AF0FAC48BA8FCD090753844E35F87B4DBD8351DD539B57E9F2418F23416294E026F2CA9A7D6D43596ACD6A684A4C96BDE527A6A3736D59E210527A180E632B33F43AEAB4113288CBBDCBA92E39378EF25FE70F3EA29C41E04E4474BAF79D5D0E78F57197495994F2EF770FB6856C25560F5E78ADD985AA1D2B8035B9459202F376B0E735BE3907E2E73BA6BC6F6D7583A137F910F41F3C21D817269E5C13012AE16E0A5AEA1B6545487BFE563C3CD2032ECA29DD90F0FF448ABFF7530C79F7E038C3CF8FC068250A8D1AA438EB98DB977F0FDE98EFDA31E18A8B82E33FC471ADA95BAA027909BE282EE4CA2DF6BE4477CBC23E599B8AB0E8715EC423F171FB04BAEA8B6DEA751C3DCFDB91B6DB6887E49DE3E0B199D8EAA27B40C16F41A881B2923B32EB44FBD4AC0C33AF5F7B62D04A1284E33290DE7F2283562D427E119FDFCA3D73B588CEDC11E855D88FF44D94970B629F66C6C03EF548E384B3A62C2E124B236D1705F9DB3B7197AA7BF8E6CBF731B000C56E4934F6D931947FCC35DEB4FF3A07D8A3DDAA30C3E88981561FEBDA0FEAB8EA2FE9E7C0A3DA496320F0FDDBCB9A9F6BB442F246A7FFDFB4A301456EFF8D67B6AE2BEC958BED930D6C73BD24ECCBFB58C293186DB871A40966CC6D5ED1780C076A8AA54B4B0471E1FE202DD02A59D3187D4007A8940B67A4D3FD1A8FD6AC77D48EB0646A30625BB2E261937422B0885180CCC7CC89CC9D14A00004E6D5E9F1EE25A94790ADA993904025ACB1EDF36E100CB8C3CB5AFF7E5FF36B7ACD94F865452FFBB2F180C4F7094574DD3A48E275E89A3D4E7D6635D7D5A95A11907CA974329290CC170908176E6C990E10BB8CB79051D690C5B71316BE43C384FEB0BD9DEE36A1D1ADE7B024B006DEB4A7E165A9A87095AB59DA160CEAF0ADC90331720D99FFADF0C04B22FB30E7F3D91790B508651FC368B545C728FFD1585FBC174A66554F5BF578CC6D3A903DBD188EF2E08A7D8A4B359F848B651DCE24B7F7F26C4042AE110A4048F84E61188CA6B59F2871990584ECBB3639C160B49B5539C3B6B969055490572CE5DBE5E27DC5F2FEEE41D081FA4F2CD660F3916CAB71C1582A80C34683844552DA13DA923791D274E33D02BF1ED1AD5D63C7A51232711A2A650A7D141AAD346672BA714711F70D0786DB17E0B4D2D30358D1F3BFBD0FB6C239730E6E03788E6915ABA1B7494D71D8A265A4BED8E477CF8885A2F405EE4911653A45D2F9AF62AA25B1B2BB7A369F766256124F20ABD9A0166C4B89DC1646AED2E818B7A33C44E58948BDA30098624ADE2B9BC19D186F43D33FC53962AD7555C153F7BFC80933B5262B7F626E4C4A429F9166AD15BF377C3D829500B91E716EDA05A4B099452A1C8DF4F7F2E6B182FF7FACBA7C12D6302D5B0160645BCAB4ECB45D1D6F8BF53EF0BD3B9A391B400D96C38C886D7DF32F0158271C3EB9259D070EEEF7B6A01D25BA33FFF465408E41BBF1BBF4B881BD1463CF326D3C932D131CB9EFA64A6933B5D8A0E06D4C6C0E9467EE6BEE70DD78BCFA2A5D96642719508DD2FF8F710353E8A1D6695F7DC9CF2FEC592B3581D3995154DFE2F5C0DDCF11FF49D1560D804686EEB4D9538D281CE524B382218B390DA7D34D29583D082880492175A3A348541E8B971F6F39921ECEEBEE775738C015D2DD07A8B1E325E3E640E13B97F9E54A58D99E249C45704370CF4CCD938E5552FC51D3EA76F1ECE57FE6415D751267547BE9B8D68C494898D610008C10070BE6D446FB3A107D961A2395F664D01171B871B1310A03BB8BA672DF01103345F25D484EF87AE99DA56FCCB0C97E7121FA07ED74C17CEDDEAEC7ABC18E14B2376E6E11805214F7473BB4514CFBA0A54BCB855395CCF7EBCEBD170776D7E78DA4FFC9F08A7D33A1042AE86DA1EECB44452E96CAE5EB874E78B69177B6E7EC75DF6CDC9662C1B7444E659BA4662C0445A5D729D2F2A5AB36ECDE30C28699ADC14EE7305F6E7810AD277E979199005DBACDD41521ABFA6AF26A991BF130C3277A810831696D11125976FA7B96CCEC7C429DCE00AD8D892E9F60A6D0BDC82F53CA0667503416C5C1B1D86DD14501811B9C7CA109C912C822E0FE1588404D92117F249405224CEC625291983F77439A05D1404692A8D10658F3BDFADF5593F89F60E34A04ED83E45CC61BB44D43B3331BA1999229EE2CAB3DFD2797C44B4DDDF6740EEF186EC98E9FB9BAE3155FE1E97DFF8B59E10EDABD282B539161F3EA597B5B8E33306578D7F6BCF1B1CDA1F72237FDDAC7BCAF15D112E6CAB50E38E57140CC9DF9BF8C1EAC4A44CC507D2E3B256934C6F8BAD57B9CA1B24562F3EDD7BD1ABE110AA52FC71E4FDB4B4EA7EB3113E69620AEF2C1F0CDD03CB2910FD61E98923B430BE4B5BEC6A7AE517F2AEFD746E0269D168D543CCFEFB1A36FFD17A8B208B2358EE40ABB64F0A887A27C3DE64B32FC78BDA1BFF932668A230A1AE8BAC4A64DB572400D28F4E53ABECF0EA12C64910E59B0C5B979A71A609B85A059C7052D6E077953E6402D84C5047F0D4F45B7D53B36CB0C3FFEFE1DE6C2DF0B9E5C5C5F927580B8FB67D698ABFBD095198777AE89AD25B79A5CA3CB64EED3EF6A566B222070877DB78DA2AE44976BA3DB7EA0D7D8066E4358807AEBC84105DF99A25E7E99553E8657B4DF176FF9A0B7B61EAAFCE6F196310173DA2465E73D40C66C4956A95C6AF143B24990451799249CE76E3A49B0D4C11A97FBA5413B0A99D5EB8D8B8DCB21845CB1B2AA6014F2B3D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - - int[] z = new int[1024]; - byte[] c = new byte[64]; - - QTesla1p.decodeSignature(c, z, sig, 0); - - byte[] sigPart = new byte[sig.length - msg.length]; - - QTesla1p.encodeSignature(sigPart, 0, c, 0, z); - - // - // Vector has message tacked onto end of signature hence the concat. - // - byte[] recodedSig = Arrays.concatenate(sigPart, msg); - - assertTrue(Arrays.areEqual(sig, recodedSig)); - } - - /** - * qTesla 3p Private key encodding decoding. - */ - public void testDecodeEncodePrivateKeyQT3P() - throws Exception - { - // - // Vector data had to be put in file, string constants were too long. - // - - BufferedReader bin = new BufferedReader(new InputStreamReader(this.getClass().getResourceAsStream("/org/bouncycastle/pqc/crypto/test/q3pIII.txt"))); - - byte[] seed = Hex.decode(bin.readLine()); - byte[] msg = Hex.decode(bin.readLine()); - byte[] pk = Hex.decode(bin.readLine()); - byte[] sk = Hex.decode(bin.readLine()); - byte[] sm = Hex.decode(bin.readLine()); - - bin.close(); - - // - // Replace seed with expanded seed, this is generated within the key generator function normally. - // It is required to verify the encoding.. - // - byte[] expandedSeed = Hex.decode("F8BC708C44E3D8A298F708196BC66F75F91732E5AF062775A9ACA36CE2DA64BCF62CAA4F63293C7A8F894856E9F263EB9CA4A0648141B4B0EA3A2D3364C36A83"); - - long[] s_poly = readLongs("/org/bouncycastle/pqc/crypto/test/3P_s.long"); - long[] e_poly = readLongs("/org/bouncycastle/pqc/crypto/test/3P_e.long"); - - // - // There is no explicit decode of private keys into polynomials defined in the C library. - // So this test used two polynomials and seed value extracted from the C version. - // - - byte[] reEncodedSK = new byte[sk.length]; - QTesla3p.encodePrivateKey(reEncodedSK, s_poly, e_poly, expandedSeed, 0, pk); - assertTrue(Arrays.areEqual(sk, reEncodedSK)); - } - - /** - * QTesla 3p public key encoding / decoding. - */ - public void testDecodeEncodePublicKeyQT3P() - throws Exception - { - BufferedReader bin = new BufferedReader(new InputStreamReader(this.getClass().getResourceAsStream("/org/bouncycastle/pqc/crypto/test/q3pIII.txt"))); - - byte[] seed = Hex.decode(bin.readLine()); - byte[] msg = Hex.decode(bin.readLine()); - byte[] publicKey = Hex.decode(bin.readLine()); - byte[] sk = Hex.decode(bin.readLine()); - byte[] sm = Hex.decode(bin.readLine()); - - bin.close(); - - int pk[] = new int[2048 * 5]; // PARAM_N * PARAM_K - QTesla3p.decodePublicKey(pk, seed, 0, publicKey); - - byte[] recodedPk = new byte[publicKey.length]; - - long pk_l[] = new long[pk.length]; - for (int i = 0; i != pk.length; i++) - { - pk_l[i] = pk[i]; - } - - QTesla3p.encodePublicKey(recodedPk, pk_l, seed, 0); - - assertTrue(Arrays.areEqual(publicKey, recodedPk)); - } - - /** - * qTesla 3p signature encoding / decoding. - */ - public void testDecodeEncodeSignatureQ3P() - throws Exception - { - byte[] sig = Hex.decode("3BF4765B50CA214DE3F97965AA87D047EB1537549361E5AFBC4D68DC753A147D3385FDAFDCEBC93399640146AA51DC61E5A5CB41BA2AC8A8547B8BADAA90F2FC7B844600CC5B002D8BE3EB1B0E705692350D2711EE5CB39AC5108FA8A4A3152B9CB0FB6246CBC8A490D73F29535991C2D3C657D4AD5C71914CCB766F3C307887356E07FF8D0495EDE24A0FFF21EEF1B847E6B12C7BEE874698D0DC59557BAB0CDFD1675780968D363D3FD4336AE375016E8359B726105FB20154FDABBAF43314E10AC93FD4F2E2EE624B83B45C4228814F381875D813D7C78D25BDBB1343638CD3BDEF781C69BD3DA50B6E70D30DDE41DF64E2A3CDA12133F075F5632612CCA3C2F5AD10A647F5046310A1DA8CFE6E5E5316C1EC85EF459093CAE6E35DB464EC0AAAD991F45661C9B41B47E33CB0E91D30FD75BC68FC147025B727A373DDA7ABE7D98CC99F24FBB57933E4B2C0E59D19F00DBA7F285A3ACE50F6ADB34EF3E18E46F543188F933C7E3682630F2C9603C41E1E319718F181AC84C11AA42CE47C718B41FFD2053356CA09B9887823D27E3DFF9D9538F79E480D57BBCF7300ED9BAA300B4C1A7A0B86E07B26B39B0CC1BC951D92C068494EA20CDE55F55A0E8D11B7B9C47501AB3DBE0D9B2467A7DCF3BED75AA574758A7F46ABA9AA8C14A498E4F9D9337786E3F1F1F2534E0F8D74B88E474696C608660688064A4398F40433B9BBDF24F1D3BDB5B31090A741530458FC7128889099C94AF3C1E40CD0C2EA8BC7ACE64DF364C02EBA8DE4A63257CB0952BFF0F4AD4556932D080AEB3B96C783F5D087C7DECA2D23C0E5F3A68E2E898B59518F731BE21ABDF1AB7CFEBCB52719A72B68846994AB0928304EB8E1DD94CA9C8E0A07886A97F018ACD714B346D933303C1D8EE551ED6658C13E3D819A2D626A4AFB8F059B3D81D20114542437CD3BE428A092B6D29A14CEAC841919D4A2D42D6D0357450A52740F359F5AB50903D51BB43D7D53E1B7BE04C753B3746A7D8D9883751F11BFB75F89D045F62B48B0CC900A7F41F6BA25F4A50B24A624D50DD973E939D96C4C02B84426A0ED1A9CCDD7D81381A231D47529852C8F5EEAD2D8825EAD5FEBCAA4700D2E1B68335012F122D3F534549E32B76AC388169729B7787FB92FDDFA5150C0F0E385C41256CC9C7788C40E96CC64856C6EFBA384B678F0167DB050C56155B2477E2949C0855DF8BE1BE759812125D88E90C432B88D0856ADEDFEBAEA433F79ABDD41BA2EEB1C94AEED32760B6523923F2CC2A6A5736224A63F13AFA307B4A6ADB2A0A868A880F8C1B4DC55B7C5FC70001606C6C3A310BDE7AD0759FA7A774114285C726F188A7A369CF1050D9BEB5B305720D6E841F4949DAE6FE83655CDCD98136ABF800146066E943AD84B571C23AADBD44FEF8FAE27560F630A42D14A67D763C2CD95F9AC993BD6C3EE89D5312D2017F0A9889D4ED15DA0E4AC8378739281A8ACAF17BE18D59E2A0AAEBF64645D0463A73C0872CCB65B7C83DA8DC4954C613DB680E0FD51684A1C4F71EEBBA6C27D9AAFB0409AB757909B963A1F6338F391410204D765228A73B05C12F4AF0571BEAE9F97509A97FEF1C4C36682E6C2F2042401DB24140FE2D7D1DE8328E788EA228A8F142A2331EB651FFC06B6D112A985DC6F43DA0841D61D81EA6AFFFD9C531E520DCD0C40EEFCB40648DECE13E25BF0608720234BDF0C07E11649C34E6FCBFE751A900FAD30F771EA1DB0C3A0BC55F84F756FB53D202D0C851C55AA62E123754E7FBA2BB708C47D01DF00695D78E974AA4D4BF6A5D30E0C111B8A444A650A910503D42277915DB1EE9074805C39FC2CE4A090BD9F347B4D57E752D4A03E30FAB89569D711D8C6C6A6FFEF7D47F06468D92E9D3909C7CCF3B30E51238C328DD921834A646BF14D84FF59A37D653943C84D1BD5AC401E6842114D63B11E92D7D6A2154100CCE1E9805A048E7DEE23EFCC895A21BC1382F23AD3E277F1F8E4D17C1D0E7B123C2A9B4E3B1F797F3DABFF0C9D425E405D9DCDA79C7B7B0BF7C4EC60F267B4A8AF7AEDF88580D3618EBC8A5CD5733619823B401868148F1D87919F30F67DA04981EA4FCEDDDE34439994AC590CE7AF2CED26500EFB3F06FC1EE68A973411A66DE8D40AE5E1E2E665C1F8C577950BAC7324979A62DB9415A09BA5A097B9541776944CC247724A4F41427D0D131C52D840515783F0708538462EAEAE6C2FA4F524B9FCBAAFCD29DD381DC593E443B255B9D41542092A1EEE4A2E44A73DC742FDE6456B3A893FF0CBDA6EF4DCA53FEE6344EAB0627F8696FC18D0B6F459E2B69A5139139C9080ECD5F86E4B1232FC61B4442315F5F5F6B536BD050D66C8052FDC3B4BA4AF9063C9C03078020B4753853A0D92401A277DD90313A6AF244BD9524CCA33D4DC5AAAA0D8EDA869A411E1BD4EF93591A12BFB6AAA5C7B43EFAB4914DD06C6C33FAC683BEA99163725729ED7C7A25B55C98271209E1905ADC937E17F48DA2C574A4216DD5ABA0225C71BE98573ECD4542AF7EC5AA77158E7B0D4368272E0103B4A3D344BF13A507F7FB07B2D6B2FB65BC01FD664C0FD165A65808FFEBD5B36DFBD1CFAD9525113840BDAE05A3F987F0D6CBB0EFC6F917FAC1A48C822D23C31840253821B91DB8DDF23455BF97A7A178F393952C74A010B5781901AE0807E78B9D9D84CE78F9DC90B1289E59061F22EC3BCFD2F79F265DF18C8C3A7B7180698372418F8EBA6C66F6E9AEADEF65B827D857375D186A3D74DBEB36527C56DFC194128C6944C2F303B1FFB5D1A5FA9F236C41499D8C0572C99E3D45DDA296357120B58A5393FA27F55FA3CA26AE4CD0D3F02268C52AA7BF3904B9FC378568ACC5F401CC5F399BC58A6ACBF191DD4BCC5C1EBB5389E3AF956BD48B07EC1899A6D94AB49A5EA4853F84B889BF74808CC3E605B985797AEA5CD9CF6C5402C8A731CC68FA106626DE36A34F701E5848350B6E7A0CFB8C74E916AE4B68FAB219635C28D55C4F5769D2669186E8B2C56DD5B60981D96F131B64C581ED9F5533143C6396C5485D22C3191AD46897EF8A32ECCD580D448A8BF800486C9799E6FCDC328A5245A894CF13E3C627188D1324591965BEA25A30422884B23BD3DA844C661B104EC9644795E3AB365B948403651B147A04E104836190267101FCE446AFABDF561B1966E813F4CC6AC6C7A50773CD7A6EF64ED346B34E8D9204F60A409E7C3F5A42AB3C1C992300442AC88B4A62AEAEA0AD368D2CE7A9287F449DA71748A2140A6FC44443E4AAF1E30EE9D8CDD390A9833E4FCA7D6BE5522FE57A9F0FD6530327883D5BD84DAB9E678AAC80B057F8AB7FFBE7EB59B5D6D5CC1E3EDBA8EAB0D9663675732F67E02990EE04A5571600CF8AA3AA34CAC33CD17181CF7594D8052EDE72FCDD52FB6F03E49734646E62CC603F097005498496005FCA6035831429BB0CE4EA13616D323E3381E23C72DAFA5C2F79A915FFA52B3B038E291D3F4003DD0D00F6398D4582EFB4FF85FA2A940FC75B177C51BCCBE7DBEF12CD14FD01ECBDCB00C89A40CEAF2E4C4CA14E4B56DD6EA223346677F9A77A09A0E0DC037177A3E02803EC180C03FB3FC22E30A63F735861CE874324E40846B6C707A8ED3B59F648CD6F48880556DED403EABE84BA7AA93333590A5A6C98447CE65D13E27D401DEE845E8D559E686D9C80DAB8A7AA4DB74DDEDA8872FC80B444DF28286508949528490EFEA857EFA4F8522DBA129323EBCBC65C798F1C7E171257E3BC6777AFCD1220D44CB861F7566A0E184E58DC83BD7322F9054E264F1E4F161F00CEF568CA263F933BC37A876DF187733E12C45FC1FB9821F828EFCD3CE69BA977CEBAA4DFD8ECEDA7023B934A76A555E82C35458B0A87266CE88D61C6848022FD8FC8BBB17391B970B8BDD1CF4D48794E14407F9719008E3AD5EE799EEE2A74075A83EDB64DFCC8CB3CA099CBC9BD4FD1FB79510608007328A96219F815314EA525E59D8F5C6879C2C357D106DD36FA8BC682E2C15EC26BBEE8A8AA1DB7CF221B31C2926D68923C86099510FFD51C42988F246CD4C788D84DDB658AC7FA7B38568373598293C34DE84B6B373064F20976C239507C40AB4F167FFFB72AE183BB3E9B1616220139AAAA2CF4B118EE395C141B2BF33E20CBA856FB87D71D40F1C45FA1B20FFDF06087E558DBF315D18A804DB05EFEABC18D0A486442289DB5C228BF5857E4398FC7D784A189E41C3C37BF134B93AD09289FC5EFDF1E2FE6D02B79F028871D085B5E290979175E5C2DB75D74066B5B1CFAA48ACDA258F44D620FDCB8B1CAE66FD3D7E2BE71D2F3C561B72A32A739B42A9C7699E5E6DECE1D8CFE7CC5A1334F5FA026B8C442280FEB17B52D4E1953CB11F702D7BC700D77A753442E65CAD320552AA2C72344AAFEE2B2E6F5EDB65CC64FDAA3458865F08ACF66A614AB871822FABE9B2CF88A348B3E7FAC1BF132E0594CBD63DF8BC01D70122C0C01F8E497B5A7A08AA9823938A96858DCF06CC638AE790488BC851C91B8754E5E7E576919625A387B5624BE9A1991EC2CE62E6C7DD207CB5DFF0418C27499AC13D809793C260C99D1C50F23199A6906275A29AABD3A78D79AD588779F061C14D1A18B2C6DD4FA573C0DEBD105FE970A97D3EA582B09E5FEB5CCDDAC617150482173566E9A1C016DCCB6B83508FCDF424F8F4DBD9A5452123F7ED645056848CC86D124011932E4B735B86F807B36ACAE45E8B777116ACD7729E63F6AE92FA91BA9B9ABB6DE4546C74693391261FCA5C14F48CC3124EADF6F963CDEB6647F0066A1EDFDCA46BCCC764B44D279E97A6397B986687539F555A68C2416A8B8B395D73B691E40E5965ACACEF1847C28BD92B59A9E704976372E48AF049CDCAA7844A389A8E606CA9755B3F726B4C6739760764219BBF523918D41B57EF9C911DAB066BC305B2CC97B0B2265F7EDB89997D2AC61947D9E33D67139CF384785A06D605BF82CED7F903480820576079593CBA07CA9B6CB507507B10C080A5F9D98463F92E1006E1564415350A52A0C512F5B657DC217670C957C725F63827B2A6ECF835781CC520AE7888BD213CC6F9D3974C540492BDC2370D9B54388E301CDD0A73D99E658BC20DE7EE474ACAC12A47C538C45A9C01F5FC9C5578932A21CB4D671B8969BF208A3F7ABBCA517FAAF090E778D6D1F54F76AD1F5772A037FEE7623A88EFDD7CBFD093AFF20F44271BD4EE1AC5ED70F26D1B966E4A78B0E47AE557FB4897524EF9D92AEA663A276E4A6592ADF7570630F3FA2143FDFAC7A74C3EC28AE9A9A402595FB7F4D01D4E6A2AC7ABE3BF8A52A4240046E43036A2F18644A70C02268B2848E30145E21A732DA0EBDD3250B2C8B2B97EAD2DCFE86650707BEBE6700AB347A63644DBB3F9B8411519D6DB6DE9CD7D6088EBB5A563391217EB7E6D911CCCBFF23FB4715ED471373BFFDD122E114D12E1276971948EC10CC4594DB44EF5C8E92C01E9B0238660D06DCA691420FDC5EAC9B09EAC7BE9DC1B2B9899BEF773934CA34A947E027A37DB0E39F00FBFD2E01F70DB1B10962512E9704BBE3BBA94AAE5A13D34F580CD31C1EF015E1475CAC4525AB40B3523727B449F94ED877E46F22DEE6F2B2DE38A8AD8686BEF2279D36166D0C0707DA77ADCE213E339AA0C8891ECCD4C8A8858FA8B80A7FC9B07CA5AB6D1B7AD83CF8CE9177A9BB624087CE258398A3030AE92527897BBD0B923D69903E7FA9AAFE0E351191BE54231CF4FF26E9902E2CA5C6C43D2DAD8FB115FC8B2F2E270185976C3F8AEC8D5B1BFC637B8013FBBC0C6E43930420E2EC9BCBA560B623184997CBBBAE66780FC518504C5465E7E9FC5153B0C3944C8469FD4DD74265C64BC91F31D949381C17409E154995B229382F5BFE27B0B869359FCAF0A8E59CA5BF18D916F2A51C0B3C33C5038E54AA356B684438D7B5206AC0D97A5B6784BFBF70E0916C71CF6098ED1F34824945CC6931469726BE9E5DDFCFB581CB0C994C4534C19BAECE844AA31DB44D8933F8EA4FF8F2301A2E205895EB7DDC1083A8B948B1CDB3CB7150636AD5F2CE5184FA9065E05C5F37DEF8A96FD56DCFC18B1E5B0E4CECBAFEA8CDB17E9FA2C7E82B66503BC5910A49E3661CDB06819466B1293604533583F11B6E59143915E906AEF3D2182620A2750AD9B32ADA19404429D4E680B415F86B01B6CEC7A7F93BF64B098B7465D1B209CBDDD94ACED3949769D0D4DE011A785AB7C0D52D3C16FC6731D22F0DA5893AAAE63F44E23524A35E56B34FF10E31C1C93D605AFB15238D9F6E983FDD4ABF943CF1581B8666C7A6F7A3F68C0A3D93ECAAED2F2F65A7BB3542E960D60CE1DE2D14E1FE2A8D74CE3E5DDD1977C2FA9D75805669F7C64EB933C5126FFE8AD85BA0C87D49BB781D8741AA3BD7019C3E3013FE9D636E4893611295DE036DF08253901171BA5B3D746D84756E84A1ABC8D5436C1631FE058984D173E07D4AAC0DE23E95F5BCF1C8617527FD326FB502626E26FD9B2424AAC6DDAD4CA1742BA05BB110F18815F8D648E463FAE2B7788C204C2B36346CE23C98BF729EFABC1EF77304A4E5068E2D7B97F68543FD4DBFA7F08988B68BFD789D9FF08E87F98CD24259E57B8C981D233342A9F6B042386D8F78E567C3E8ACE6DB7B9D82908E77B74C8B79914AF144B4BBB26C02C640195842E95A3E2703650322AF7678665C8EA2A5CB6D57D1F3378E54F027E3040A225DE70E5179C9D0DC22EC9BEBCD0DFBE82DDDA7DA082409BDEFD0F2058CF941C1EE593A6824A1A9BB5F4A8D33F010B9495DD5214B08D2F0D06C7F5CA9BD9A23FFED5D7E18F0D4A1EA76A05E90FE1FE741DDA24ADC2FCFFEF491D615D8E340F0CC2D8EFC082192C58CCE492D911EE3927C9B87E81B8C6E2F107E18554C80C1D68EA26D050EC0B799C75FC9EA403693358BCA09126922F7CA6B9EB71D7B48195BBC1126D3C6452AB2815A04418DDA2A6D026C1BA8D776E65035415303FC9CE24A669EA42EC234B6D2D975DBC626CC983BA87A231DAB0E67DD97E33DAF582A9CD33F9CFAA4676BA22A0B28F8341521EED0C2668AD13D0D8B3F797468F91EBEA010862EBC5A7E92058A6774DE2A4D02FD215F79E83BF50B6C9F4FFA5909A4EBE327DDBB70FFE84E230DE62EB6FF13E8D20E5601F3833155BFD193A7D3C51DB2125C7802445C90E758F412473A7DEEC35B93DF629F21EF9722B43E290D984843E50A2375C6BFDCD24E41BB11A01B46DFB90FEFAFA085012BA00201A06E1E513895029E361AA741AF824B04DC77CB34AB79191BD05659C43BD04FD67183A30027342962E1AA8CDA718AEFED0150D15921A5D58C029AC1B4718A0E5DBDC6298882E72CCA163E2F01B4DCD5BAE8DB979E8864966A72645ABEFD6E3B6E22AEBC6284106B1EE0B023AD91443A6589F06EABBE05317E667015884D1DC00E5E96106F52F6BF47E971EFC5C58D64BC86DF06339EC3C8B318A2D65B53A18192192D10F54CBFA6A6954EB16D1F99D6FB383F71324770386FA9D52E1A7919009A3939E38552A49271546BE4E06CA31E1A90AB4356DDCB17A77C98A186C21BCFC1E04C79FBE0CAFC6DD180A81219DB7FF65371C5593DCF82AF0806787436A187A21FE9D91F8CD71A8CD28BDC670942B9D8852ABCE4A1DF50FBC1574CD8C5186D188583895073F86A6BCF9BE1D868B25844ED706090C637FB86D458CF400B604CE46289A51B70D5CAEE82DE77799476FC935018FA48E6A6358710FB12CB3E505A910BBFEBA2AEA0F14E4DCF75090425DAAB73AEE95BFBDE27CF07834CF74F94047CED52AEDFDF208621EFD1D6F73A732984B6C5B1F6B8D941EA5380F29DC14CA31411159CCD1D44842347ECE07AAEFE1C4752432901FBCDB173DCB36A9EA615DEA2A6946276AEADD8133A10C932DB70C0872AF3D3905F9E7F51FBB6C0C22DD2D2D45D3A993F28979AD816FC4F4A37C2BD8894C3ADBFCCBD802B5C43DC2A655A8D6286BA4848E5D6102BEA9378B55F990C3A573CE8CE0722D46D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - - long[] z = new long[2048]; - byte[] c = new byte[64]; - - QTesla3p.decodeSignature(c, z, sig, 0); - - byte[] sigPart = new byte[sig.length - msg.length]; - - QTesla3p.encodeSignature(sigPart, 0, c, 0, z); - - // - // Vector has message tacked onto end of signature hence the concat. - // - byte[] recodedSig = Arrays.concatenate(sigPart, msg); - - assertTrue(Arrays.areEqual(sig, recodedSig)); - } - - private static long[] readLongs(String classpath) - throws Exception - { - BufferedReader bin = new BufferedReader(new InputStreamReader(QTeslaKeyEncodingTests.class.getResourceAsStream(classpath))); - String line; - ArrayList longs = new ArrayList(); - - while ((line = bin.readLine()) != null) - { - line = line.trim(); - if (line.length() > 0) - { - longs.add(Longs.valueOf(Long.parseLong(line))); - } - } - - bin.close(); - - long[] l = new long[longs.size()]; - - for (int i = 0; i != l.length; i++) - { - l[i] = ((Long)longs.get(i)).longValue(); - } - - return l; - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/AllTests.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/AllTests.java deleted file mode 100644 index f85072288a..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/AllTests.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import junit.extensions.TestSetup; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; -import org.bouncycastle.pqc.crypto.test.RegressionTest; -import org.bouncycastle.test.PrintTestResult; -import org.bouncycastle.util.test.SimpleTestResult; - -public class AllTests - extends TestCase -{ - public static void main(String[] args) - { - PrintTestResult.printResult(junit.textui.TestRunner.run(suite())); - } - - public static Test suite() - { - TestSuite suite = new TestSuite("Lightweight PQ Crypto Tests"); - - suite.addTestSuite(BitStringTest.class); - suite.addTestSuite(EncryptionKeyTest.class); - suite.addTestSuite(NTRUEncryptionParametersTest.class); - suite.addTestSuite(NTRUEncryptTest.class); - suite.addTestSuite(NTRUSignatureParametersTest.class); - suite.addTestSuite(NTRUSignatureKeyTest.class); - suite.addTestSuite(NTRUSignerTest.class); - suite.addTestSuite(NTRUSigningParametersTest.class); - suite.addTestSuite(QTESLATest.class); - suite.addTestSuite(SimpleTestTest.class); - - return new BCTestSetup(suite); - } - - public static class SimpleTestTest - extends TestCase - { - public void testPQC() - { - org.bouncycastle.util.test.Test[] tests = RegressionTest.tests; - - for (int i = 0; i != tests.length; i++) - { - SimpleTestResult result = (SimpleTestResult)tests[i].perform(); - - if (!result.isSuccessful()) - { - if (result.getException() != null) - { - result.getException().printStackTrace(); - } - fail(result.toString()); - } - } - } - } - - static class BCTestSetup - extends TestSetup - { - public BCTestSetup(Test test) - { - super(test); - } - - protected void setUp() - { - - } - - protected void tearDown() - { - - } - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/BitStringTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/BitStringTest.java deleted file mode 100644 index 37751d9c93..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/BitStringTest.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import junit.framework.TestCase; -import org.bouncycastle.pqc.legacy.crypto.ntru.IndexGenerator.BitString; -import org.bouncycastle.util.Arrays; - -public class BitStringTest - extends TestCase -{ - public void testAppendBitsByteArray() - { - BitString bs = new BitString(); - bs.appendBits((byte)78); - assertBitStringEquals(bs, new byte[]{78}); - bs.appendBits((byte)-5); - assertBitStringEquals(bs, new byte[]{78, -5}); - bs.appendBits((byte)127); - assertBitStringEquals(bs, new byte[]{78, -5, 127}); - bs.appendBits((byte)0); - assertBitStringEquals(bs, new byte[]{78, -5, 127, 0}); - bs.appendBits((byte)100); - assertBitStringEquals(bs, new byte[]{78, -5, 127, 0, 100}); - } - - private void assertBitStringEquals(BitString bs, byte[] arr) - { - byte[] bsBytes = bs.getBytes(); - - assertTrue(bsBytes.length >= arr.length); - arr = copyOf(arr, bsBytes.length); - assertTrue(Arrays.areEqual(arr, bsBytes)); - } - - public void testGetTrailing() - { - BitString bs = new BitString(); - bs.appendBits((byte)78); - BitString bs2 = bs.getTrailing(3); - assertBitStringEquals(bs2, new byte[]{6}); - - bs = new BitString(); - bs.appendBits((byte)78); - bs.appendBits((byte)-5); - bs2 = bs.getTrailing(9); - assertBitStringEquals(bs2, new byte[]{78, 1}); - - bs2.appendBits((byte)100); - assertBitStringEquals(bs2, new byte[]{78, -55}); - bs = bs2.getTrailing(13); - assertBitStringEquals(bs, new byte[]{78, 9}); - bs2 = bs2.getTrailing(11); - assertBitStringEquals(bs2, new byte[]{78, 1}); - - bs2.appendBits((byte)100); - assertBitStringEquals(bs2, new byte[]{78, 33, 3}); - bs2 = bs2.getTrailing(16); - assertBitStringEquals(bs2, new byte[]{78, 33}); - } - - public void testGetLeadingAsInt() - { - BitString bs = new BitString(); - bs.appendBits((byte)78); - bs.appendBits((byte)42); - assertEquals(1, bs.getLeadingAsInt(3)); - assertEquals(84, bs.getLeadingAsInt(9)); - assertEquals(338, bs.getLeadingAsInt(11)); - - BitString bs2 = bs.getTrailing(11); - assertBitStringEquals(bs2, new byte[]{78, 2}); - assertEquals(590, bs2.getLeadingAsInt(11)); - assertEquals(9, bs2.getLeadingAsInt(5)); - - bs2.appendBits((byte)115); - assertEquals(230, bs2.getLeadingAsInt(9)); - assertEquals(922, bs2.getLeadingAsInt(11)); - - bs2.appendBits((byte)-36); - assertEquals(55, bs2.getLeadingAsInt(6)); - } - - private byte[] copyOf(byte[] src, int length) - { - byte[] tmp = new byte[length]; - System.arraycopy(src, 0, tmp, 0, tmp.length > src.length ? src.length : tmp.length); - return tmp; - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/EncryptionKeyTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/EncryptionKeyTest.java deleted file mode 100644 index 554b404588..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/EncryptionKeyTest.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -import junit.framework.TestCase; -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUEncryptionKeyGenerationParameters; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUEncryptionKeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUEncryptionPrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUEncryptionPublicKeyParameters; - -public class EncryptionKeyTest - extends TestCase -{ - public void testEncode() - throws IOException - { - for (NTRUEncryptionKeyGenerationParameters params : new NTRUEncryptionKeyGenerationParameters[]{NTRUEncryptionKeyGenerationParameters.APR2011_743, NTRUEncryptionKeyGenerationParameters.APR2011_743_FAST, NTRUEncryptionKeyGenerationParameters.EES1499EP1}) - { - testEncode(params); - } - } - - private void testEncode(NTRUEncryptionKeyGenerationParameters params) - throws IOException - { - NTRUEncryptionKeyPairGenerator kpGen = new NTRUEncryptionKeyPairGenerator(); - - kpGen.init(params); - - AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); - byte[] priv = ((NTRUEncryptionPrivateKeyParameters)kp.getPrivate()).getEncoded(); - byte[] pub = ((NTRUEncryptionPublicKeyParameters)kp.getPublic()).getEncoded(); - - AsymmetricCipherKeyPair kp2 = new AsymmetricCipherKeyPair(new NTRUEncryptionPublicKeyParameters(pub, params.getEncryptionParameters()), new NTRUEncryptionPrivateKeyParameters(priv, params.getEncryptionParameters())); - assertEquals(kp.getPublic(), kp2.getPublic()); - assertEquals(kp.getPrivate(), kp2.getPrivate()); - - ByteArrayOutputStream bos1 = new ByteArrayOutputStream(); - ByteArrayOutputStream bos2 = new ByteArrayOutputStream(); - ((NTRUEncryptionPrivateKeyParameters)kp.getPrivate()).writeTo(bos1); - ((NTRUEncryptionPublicKeyParameters)kp.getPublic()).writeTo(bos2); - ByteArrayInputStream bis1 = new ByteArrayInputStream(bos1.toByteArray()); - ByteArrayInputStream bis2 = new ByteArrayInputStream(bos2.toByteArray()); - AsymmetricCipherKeyPair kp3 = new AsymmetricCipherKeyPair(new NTRUEncryptionPublicKeyParameters(bis2, params.getEncryptionParameters()), new NTRUEncryptionPrivateKeyParameters(bis1, params.getEncryptionParameters())); - assertEquals(kp.getPublic(), kp3.getPublic()); - assertEquals(kp.getPrivate(), kp3.getPrivate()); - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/GMSSSignerTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/GMSSSignerTest.java deleted file mode 100644 index bcc7989b7d..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/GMSSSignerTest.java +++ /dev/null @@ -1,130 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import java.math.BigInteger; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.CryptoServicesRegistrar; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.Signer; -import org.bouncycastle.crypto.digests.SHA224Digest; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.DigestingMessageSigner; -import org.bouncycastle.pqc.crypto.DigestingStateAwareMessageSigner; -import org.bouncycastle.pqc.legacy.crypto.gmss.GMSSDigestProvider; -import org.bouncycastle.pqc.legacy.crypto.gmss.GMSSKeyGenerationParameters; -import org.bouncycastle.pqc.legacy.crypto.gmss.GMSSKeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.gmss.GMSSParameters; -import org.bouncycastle.pqc.legacy.crypto.gmss.GMSSPrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.gmss.GMSSSigner; -import org.bouncycastle.pqc.legacy.crypto.gmss.GMSSStateAwareSigner; -import org.bouncycastle.util.BigIntegers; -import org.bouncycastle.util.Strings; -import org.bouncycastle.util.test.SimpleTest; - -public class GMSSSignerTest - extends SimpleTest -{ - public String getName() - { - return "GMSS"; - } - - public void performTest() - throws Exception - { - GMSSParameters params = new GMSSParameters(3, - new int[]{15, 15, 10}, new int[]{5, 5, 4}, new int[]{3, 3, 2}); - - GMSSDigestProvider digProvider = new GMSSDigestProvider() - { - public Digest get() - { - return new SHA224Digest(); - } - }; - - GMSSKeyPairGenerator gmssKeyGen = new GMSSKeyPairGenerator(digProvider); - - GMSSKeyGenerationParameters genParam = new GMSSKeyGenerationParameters(null, params); - - gmssKeyGen.init(genParam); - - AsymmetricCipherKeyPair pair = gmssKeyGen.generateKeyPair(); - - GMSSPrivateKeyParameters privKey = (GMSSPrivateKeyParameters)pair.getPrivate(); - - ParametersWithRandom param = new ParametersWithRandom(privKey, null); - - // TODO - Signer gmssSigner = new DigestingMessageSigner(new GMSSSigner(digProvider), new SHA224Digest()); - gmssSigner.init(true, param); - - byte[] message = BigIntegers.asUnsignedByteArray(new BigInteger("968236873715988614170569073515315707566766479517")); - gmssSigner.update(message, 0, message.length); - byte[] sig = gmssSigner.generateSignature(); - - - gmssSigner.init(false, pair.getPublic()); - gmssSigner.update(message, 0, message.length); - if (!gmssSigner.verifySignature(sig)) - { - fail("verification fails"); - } - - if (!((GMSSPrivateKeyParameters)pair.getPrivate()).isUsed()) - { - fail("private key not marked as used"); - } - - stateAwareTest(privKey.nextKey(), pair.getPublic()); - } - - private void stateAwareTest(GMSSPrivateKeyParameters privKey, AsymmetricKeyParameter pub) - { - DigestingStateAwareMessageSigner statefulSigner = new DigestingStateAwareMessageSigner(new GMSSStateAwareSigner(new SHA224Digest()), new SHA224Digest()); - statefulSigner.init(true, new ParametersWithRandom(privKey, CryptoServicesRegistrar.getSecureRandom())); - - byte[] mes1 = Strings.toByteArray("Message One"); - statefulSigner.update(mes1, 0, mes1.length); - byte[] sig1 = statefulSigner.generateSignature(); - - isTrue(privKey.isUsed()); - - byte[] mes2 = Strings.toByteArray("Message Two"); - statefulSigner.update(mes2, 0, mes2.length); - byte[] sig2 = statefulSigner.generateSignature(); - - GMSSPrivateKeyParameters recoveredKey = (GMSSPrivateKeyParameters)statefulSigner.getUpdatedPrivateKey(); - - isTrue(recoveredKey.isUsed() == false); - - try - { - statefulSigner.generateSignature(); - } - catch (IllegalStateException e) - { - isEquals("signing key no longer usable", e.getMessage()); - } - - statefulSigner.init(false, pub); - statefulSigner.update(mes2, 0, mes2.length); - if (!statefulSigner.verifySignature(sig2)) - { - fail("verification two fails"); - } - - statefulSigner.update(mes1, 0, mes1.length); - if (!statefulSigner.verifySignature(sig1)) - { - fail("verification one fails"); - } - } - - public static void main( - String[] args) - { - runTest(new GMSSSignerTest()); - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/McElieceCipherTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/McElieceCipherTest.java deleted file mode 100644 index d86e9ce266..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/McElieceCipherTest.java +++ /dev/null @@ -1,130 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import java.security.SecureRandom; -import java.util.Random; - -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCipher; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceKeyGenerationParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceKeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceKobaraImaiCipher; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceParameters; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.encoders.Base64; -import org.bouncycastle.util.test.SimpleTest; - -public class McElieceCipherTest - extends SimpleTest -{ - - SecureRandom keyRandom = new SecureRandom(); - - public String getName() - { - return "McEliecePKCS"; - } - - public void performTest() - throws Exception - { - leadingZeroTest(); - - int numPassesKPG = 1; - int numPassesEncDec = 10; - Random rand = new Random(); - byte[] mBytes; - for (int j = 0; j < numPassesKPG; j++) - { - - McElieceParameters params = new McElieceParameters(); - McElieceKeyPairGenerator mcElieceKeyGen = new McElieceKeyPairGenerator(); - McElieceKeyGenerationParameters genParam = new McElieceKeyGenerationParameters(keyRandom, params); - - mcElieceKeyGen.init(genParam); - AsymmetricCipherKeyPair pair = mcElieceKeyGen.generateKeyPair(); - - ParametersWithRandom param = new ParametersWithRandom(pair.getPublic(), keyRandom); - Digest msgDigest = new SHA256Digest(); - McElieceCipher mcEliecePKCSDigestCipher = new McElieceCipher(); - - - for (int k = 1; k <= numPassesEncDec; k++) - { - // System.out.println("############### test: " + k); - // initialize for encryption - mcEliecePKCSDigestCipher.init(true, param); - - // generate random message - int mLength = (rand.nextInt() & 0x1f) + 1; - mBytes = new byte[mLength]; - rand.nextBytes(mBytes); - - // encrypt - 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); - - boolean verified = true; - for (int i = 0; i < hash.length; i++) - { - verified = verified && hash[i] == constructedmessage[i]; - } - - if (!verified) - { - fail("en/decryption fails"); - } - else - { - // System.out.println("test okay"); - // System.out.println(); - } - - } - } - - } - - public void leadingZeroTest() - throws Exception - { - /* - MIIQpgIBADAOBgwrBgEEAcBtAwEDBAIEghCPMIIQiwICCAACAgXaBAQFCAAABGaJAgAEmAUuBp8D/gbaA2AChwKKApsCCAQbBTcGAAa2BtMDXAPJBvAFzAQ9B1wFKQIUANUA6wT4A1cBEQVlA+oEXQM0AwUCDgf4BCUG0QfnAnIHugctB9wAIgIEAFcDBQEfAtEGAQAEghAEAAgAAMUE8wHQBC8AVAVOBekH/wPvBxcHjwdvA0wFxgIzAMoFpAYjBn0GfQLSAXoAXQZLAIQEigEXAy4BKATyAyUFOwXQAUoAcwT+BjkD7QJjAewBBwQKBuQCuwSLAaoEuQMyAXkEEQUHAb0B6QAfARUDBwPOAroDxwUEBI4BygMwB/4E5gSmBYAAmwcZAg8HfAF0AdcHuAUrAA0BXgRtB1cBlgOWAl8DrgEMALkAYQJxArYD4wECAk0BLQD/AjIFwwFYAGAGaAPTAAMDJgXXBf8BJQbBBB8DwgZiA38HAwfhAC0GZgWHAIECDwWXA/MFvwScAkwCZwcZBk4BtQcEBSgGSwJnAgMFywd1APEEIwR7AKsF9AWSAFwBcgJDB48DNQPKAqcHfgO/Bm0AmgNoBdoDzgEyAs0DxQclBzcDuAdhBgUF6gGsB7gCHARLBKoF/ABLAzEGxwRVBIoAogI0Al0BfwYQAJQDawZjAFQEDgQuBSAC7wV0B80HgQeoBbICvAdRAg0AkQT0BOgHTAeqB1YGOQcvBo8FqwN+BEABEwS2BdUFWgB8BZMD6wc3AuAFlQXPAxsG+wAGAwAGtgBsBMUCxgOoAzoD0gZ2BE4E6wTPB54EZwOSBZ0CtAWRA1AHvQbEAxMF0wb1AYUDEwBlBKwA+wbVA2AH4AA9B30B3QZqBMcGJwVABBAEQQalBdMELwNgApECrQCOBDQHCAVoAtMDmwJhAPwGAAJ/ARQF8AV1BccCdwCtBgYHugbxB3oFIANNAG4CBgJNB4MAxwNBALQEQANNAgMEGwBwAV8GLgIMBx0ArwaBAB8FEQJhB9QEoQSxBEoDrgf1BLkCqQGvAhICLQVmB2sEZgM5AIgEYgYQBsABJgSGBsEDJga5BdUG/gOsA/AGfQT6AogFHAcnBN0AqQMwBMoB1gTcBE0E4AM/BvACKgHBB14CCQLPAs0EeAM7BxoEUgNpA/wC6ATLBcwENgP5BtYG3gMpA2kELwQJB0UDBgawAKkCgQYCAxQENAMAATMG5AbdBLEHfgDYAyIAoAGjBH4HtwXiBAAAmALvBBIBlgV2B2UGiwbOBooHiwPVB1cEIQFEABEAaQAqBLsAnAbjB60HEALUA4QHJATJAncEXwfbBRoDHQSdBRwD5gJZBgwGbwexBg4AHgSPAQ0HsgA9BkUFsQXfA0YGbAZCB7MBDgf2BdYBvASTBM8A5wObBOgBBQePBIUBoQfEBSgFBgWRB1sG3ge2AUAG0wHvAncFLwdfBeUERwM4BYMD7gQfB+UCfAC+BX8EtgSmBLgAHwaYACMBwwM+AkkBDgFeA2sBxgenAWUDaQG7A9oFCwUtBxgHCgDCBFAG9QXcAkkERAQnBzgDyQQoAfUAoAerAFYF3QNqAYsClQb6AzMFJgd2BtkALQFDBRgF0QQ+BvwFJQOPBv8FeQY2AGYAOgKfBNUECAGaArMCswQWAqcGSQWCA3gF3wKjA7UCEQGNA8sC2QPNBR8AOwOuBRcGwAa5BzUFwwQ1BP4B3QG3BJ4BdwaHBkcE1wAnACIEDgPnB3AGqQAKAmIB4AZWApAAmAaSBGwFPgQbA2QE5QApAmUAjAYMARcAUwNHApQHWAH/ALIHfwO9A+UFFgH1ByYBhAP9BVYAnQFiADEEbwD4BpABCAZ3Av4HCgULAHkC3wWkAnQFkARFAlAASQMxAroEXgUTB4ADrwCUAf0HmwBJBw8AtABxBIAGoQDhB4EBdAY9BDMCvQIVBp8BYwWCBhAFpAXCAgIEuwJ5AfsHMAL1A/kDbQFWA5UHzgSOAjQEhQfDAggAUwQqB/wDWweyBMgHZAFcAH0FowIFAPkClASFBFUAJAH5BTkCgwKEBlMAKAeGAnMD4gMiBc4ATgdlAZwBtgfoAOIGHQW/A0sHDAW1AesFnQSGAM8FpAGQA/oB0AeYB4wFNwYpAWEEMgOXBR4AAASXABAB6QS2BtwGJwb/B0gFUwecBUIDbADMAp4HdAKgBlQAyAFPBWYE3QdrA+YGyQDGBGYBIQX9A2YGKAJzAE8HYwdyA3wD1QCeALUGyAO8AQ8DVgRuAJcCowFHAMAHKwLlAf4AbgfRB2oCxwAZBX4C5AVABbgBgAH7A5MAVQNkAHsH/AEZAR0BNgW7Bc0B1gU2B1UGBwWpBjoGSATbAbQC8gI4AnoEOwIWB/IAiAKnAlMCqAJoBCoCpgDgBIMFpATGBm8CeAFIArEAqQVpBwUBWQHNAtgH6wASBxcFYwSzBz8AUQSABe4HGAOKAiAEzgUOBnEDkAZPAkQHwgA9AnoDKwbwAdwHiQJzBd4EcADnBjkBeAccANQBWgMJBaAFHQKVAX0DDwTLASwFpQZ/AkYAcwfaAQ0E5AQmAJMFawfZAgoE2wcmAiQDZwDEAtwDBgEXBKQH9gLqA+4DOQXoBdgEugfHB1IFRQe0B1ICtwFXAgsGnwAtA9YCYACHBDoADgJWAewCXQd7BIQAUQB2AJoBMADBBv0AVwWKBhkHBAb+AkAHQwOdBrcGqAbhBTUC8ACwA9MHiwQJAE0DLwVcAoIAggV8BjwCeAA7BGAD0QPABEYFPAYJBLwGYQWPABQGlwbZAfsCHAGSB6YCgARoAKQDXQVyAWwDAQPpAYgAIgJsAa8HtwPnAukCNAEhBl0DiQfqBAoH0ACoAUwGiQMIA4wBCAKOBkgGQgbIBqkElgRkBgsCEgM4BoYFkgHDBdgAXAYUB60BuwbzA78CnwNVB80AbQMcAtoAkgOOA+sB9ABRA7AHawKTBi4ERAKpBwIF4AfxA6cFIgYXASkErwEFBD4FaAEqA4wERQZZBaIBvAJiBY8CLABEBtECVQUgAUwBKQCbBZYG9gDdAkkG1AAkADYBlgGHB3kHqwJTBe4BwAMQA64DKwU+B/IHPAXjAFcGcAeJBu0FrwQSBZkCRAFlB7MAZAWNB9UCjQIyB/YEsAbqBgMAlAaiB20GOAAVAJkF9wNDBiYDcgVFAOgChAHZBvQGAgCqBpkHaAbwA/cCywMtBJcBwQFYB6wF4AHuADEB7QNBBHcDGgYhA9EB+gX3AEMCwQXcAUoC+AVfAscBlgfEBLYCyAX5AAAFFQIpBiIBDQKLBRQCvQAWANgF7AWLADUG8QJZBAMB+AJQAl4GGgC/AAwEkgZ7BTADvwfiAOkGCwRGA3YDSQB1A9kEEwYeBcMHEwHXApsBPwVHB7UDbwUXAg0F1Ae9BCUC/wTKBJEBzAYjAgwCyQU4B/MA6wNpBksGLQKTAcEA5QdhAbsBigSFBiwCXgehAu0GAQKjBxoHFgX0BxQB0AUoAz4DiAe/BVcAjAIzAfsEhQAEBzcH8gQ0APEARwFGB4wAWQAWBpIC5wHKBooDFQS+BFsDdQIHBwQDHgMPAdsDUgcwBdYD+QEgBVkCMQCdA6gE9AEJBp8CvADbALMGGwfAAnQA9gffBIMGYwNUA3UBHwL5BygAqgC+B0EC3wAIBDUAxgHFBp4G0AJaAtoE8gZvAaMAYAVbAaIDzwTXAyAGAQVyAIgGTgI0BgMGRQSiBHQE7AeGB/cGmQZPA0MEiQW1BJwDPwcZBBsChgOmBiEC4QRyBBgAPAc9A0EHQwHiAQcCFgQ4BLIFGARfBAQCMwN7A2cBoAC5BhMDKwFwAsMAuQQwBpoEHQcCAY4AogWYBOUG4gd4BpcEegYuA/AHrQUyAMMGjAecAPYBaQW1BcIDTwEFBr0FVQHXBAgHmwZaBK4EtAbCB5MHxAbmAxgBZwRIASEH0wK1AHcH5wRYBfcHPQWzBbkBUwHEAWIEWgGnAEQD/AdoB04AKwOyAVwHZgLrAnUGQgIJAdIDEgQLA+ME2gINA0YEcQchBPoAOwH0A1IA3gFuBL4GUAEJAxQAVgexAwMC7ATBAnMCbgE5BuwGgAf9AhUFqwSaB7sH3wbpA3QDRwV+Ba0C7wFkB6UArARcBR8EGwVfAVwEfASTAj8C5gV9AGcGcwZ6AVQGRgK9B+UDVAehA5oAzwYjAPsFOgfJATkEoQUVB7ACeQO6AgEGvgPqAioGJAXRAOMDUgRQA6UB/QGOB20EewaUAkgAYAHMByIDvgECB40GLAdMA0oFqwcnAtgCkAfRBYkBcQH+BSQHNwSBBVAFIADeBqYD/wbvBuEDgwfEAEAAbAIMA1oFlAUKAYQC/QRxBtIEzwHzBOgDKgWYAQEBogaiAPoEAQT4BAoDjQCJAA0GXQThAboALwIaApkD7gZuAwsBXwCuAuICwgXOA6UDggESAAEA8QF4AsYFagV/BVgDgAJ5AEgDsgbqB3MBPwE6AZACuAbwBGoGQgTJByMDIAenBNUBnAelB1IBqAfxBb8BPAFUAgUCWQcsAzEFtAMcBawB6wZIB64AvgDABTYCIwW8A3AFcATMBX4B0gIbBCUAEQMeBvwEMgQyBikFPAQqAIwDBwAOBb4CSgb4A9cGMweJBBAHtwdiAgQAWATcBW4FZQVBA6cDoAN2BW8EWgaXB+QD5geaBhwGnQebA3EARwY+AOYBbgb2A30HZwX4AewDQgCIAycBXgGWAMwDcgaZBFAEnweZAREE2wbOBywG5AfiBREHTAA/BLAEAAMCBuEC+wGYBToETQYbASQCawVvBtMF6gWBBB4CZQLJBssAewIeAcwBQwCrAYYEiwfnAJEGawAlBKACTwByB+wAxQHZBx0GNgZTBlUCHgeGAe8AJwOtAy8B4wIuBncBGAJhA98H9AJMBBkAkAVBBXwCrwM6BbEC7wMwARMCqgGNBdYH7QSmAU8G1Ab3BI4F2AFCAasGTQWFBU4GhAXtAIUC8QazAzsG5wXLBCEArAalAjMEFANKBykHWALYBt4C0QaDAS4HPwN6B1EG3gU3AUYBWwJaB7oBYASIAUoEQAJ2AiwBtwI3BQAH1gBOA1EFCweeA5QA9QJUARUBKwRPBGMCmANRB7ID5ABsB/IFpgcxB8UDwABXBwUD2gYaASIHZAISBjcAWwQrB4ICjQFjBjwAhwWHAocBxgCVAGkC3QWwBQYAWwVSBqMGvAXKB3ADLgB4BF0A+gbbBPoH0gfUBe0BIwffAZ4FlQLjBpUDRAUYBtQCrgaqA20CgQMZA9IAcQXLBswAxQWgBAEHtAEHBtkF0AODBFcDOAEaBZ8GOwCRAOoANQc+AcoAXAP3BZoFPQFiByUBxAfIAu4FzQZCBckDUQGKBf0GrwXFABYDSQKqAvgHdQfmAB0DeQX4AA8GuAOCB1gGugWCBJ0A7QdKAZkA3gBBAeMFnARZA7EBPQCjBYcD8wdtBbgE9wEkBu4CSwFeAPMGNAUxA5UEsAE1AWoDagDhBgYEEQb1BvkEdgHoBlsAwgE8A0sFdQRqB/MC5AF6AtoHrAKkAH4GpQQ2BMgEnwV7AfIBXQKhBuACBAEPAo0EyADbAtIFfwDcAJ4CfAfQBpEFrQS3AGQD9gahAdcB6QVFAagALAQwCwYJYIZIAWUDBAIB - JPRvWBk1htKrDwB/tcjmdg02SxHNKyHwZqJ5EWxoFBpcCuthOyezRfBOKTAd7Py0pEYeq1POQqyWuhoIH7bLtdWK3WtUootS31fY2RGJ6h14Lyw80GmmawHFWbXwxirn3SkuWlF9DEs8fLa6SToRvR6JLJXYrM9I1U120z63xhRt0NyvYG/n/0H7IGpTD2gHjoK+AxpcyIV0pgRV69du6XX754P3JhH3WtUhDLo0pyeGI07di3aXxmLWoz8iAU1N3enwxDksZxT51hPkZERlcZ4l8p2B3rjE+JnQkaa0gWkE7WP+aoxcax6OXN00MgbX9yteJy/cRKdw+A== - 5Btx1aKTMktU9pwKG9U1KZp9OTag90msKyZhaqzWnXrDwJpPfbWZHt7VGOvbkKxQ8O6VdqDqyRMcAJPARZzjbYCTwug5jsUsEL2FQfaEpSw3bV8NYHcVPe9nz5a92cOjkSku9+GhTtAv1X/4UkIjgTdYeLEHoNmAmhfh3wrB9yWbOm7NujYa2T84w+9CxOBTfuPnKlay4O6vMRSpZGNG+BNMAkeDVGcQKqEofk80yDqW1GAbRY/kD7tqh0IXo6ARlGlumy/Zgmbb+1J4zo4obtB5s4JdrWo2d3JMK9vviQz9R2jOQme65prfp8pAM9OG3zNwqkFO8YdKjNMHUOZ+vEpwbzdzDhqOJprSWfAWL+PHk8xHevMKrCaqHLRp5Xk+rSkGAEaa9GuoNmQkO9Cx5qfvfpfzB+Md2YjmpeofOzL7QQRvE6yPRPANJys0pi7gGd2DHiw= - - */ - PrivateKeyInfo cca2PrivKey = PrivateKeyInfo.getInstance( - Base64.decode( - "MIIQpgIBADAOBgwrBgEEAcBtAwEDBAIEghCPMIIQiwICCAACAgXaBAQFCAAABGaJAgAEmAUuBp8D/gbaA2AChwKKApsCCAQbBTcGAAa2BtMDXAPJBvAFzAQ9B1wFKQIUANUA6wT4A1cBEQVlA+oEXQM0AwUCDgf4BCUG0QfnAnIHugctB9wAIgIEAFcDBQEfAtEGAQAEghAEAAgAAMUE8wHQBC8AVAVOBekH/wPvBxcHjwdvA0wFxgIzAMoFpAYjBn0GfQLSAXoAXQZLAIQEigEXAy4BKATyAyUFOwXQAUoAcwT+BjkD7QJjAewBBwQKBuQCuwSLAaoEuQMyAXkEEQUHAb0B6QAfARUDBwPOAroDxwUEBI4BygMwB/4E5gSmBYAAmwcZAg8HfAF0AdcHuAUrAA0BXgRtB1cBlgOWAl8DrgEMALkAYQJxArYD4wECAk0BLQD/AjIFwwFYAGAGaAPTAAMDJgXXBf8BJQbBBB8DwgZiA38HAwfhAC0GZgWHAIECDwWXA/MFvwScAkwCZwcZBk4BtQcEBSgGSwJnAgMFywd1APEEIwR7AKsF9AWSAFwBcgJDB48DNQPKAqcHfgO/Bm0AmgNoBdoDzgEyAs0DxQclBzcDuAdhBgUF6gGsB7gCHARLBKoF/ABLAzEGxwRVBIoAogI0Al0BfwYQAJQDawZjAFQEDgQuBSAC7wV0B80HgQeoBbICvAdRAg0AkQT0BOgHTAeqB1YGOQcvBo8FqwN+BEABEwS2BdUFWgB8BZMD6wc3AuAFlQXPAxsG+wAGAwAGtgBsBMUCxgOoAzoD0gZ2BE4E6wTPB54EZwOSBZ0CtAWRA1AHvQbEAxMF0wb1AYUDEwBlBKwA+wbVA2AH4AA9B30B3QZqBMcGJwVABBAEQQalBdMELwNgApECrQCOBDQHCAVoAtMDmwJhAPwGAAJ/ARQF8AV1BccCdwCtBgYHugbxB3oFIANNAG4CBgJNB4MAxwNBALQEQANNAgMEGwBwAV8GLgIMBx0ArwaBAB8FEQJhB9QEoQSxBEoDrgf1BLkCqQGvAhICLQVmB2sEZgM5AIgEYgYQBsABJgSGBsEDJga5BdUG/gOsA/AGfQT6AogFHAcnBN0AqQMwBMoB1gTcBE0E4AM/BvACKgHBB14CCQLPAs0EeAM7BxoEUgNpA/wC6ATLBcwENgP5BtYG3gMpA2kELwQJB0UDBgawAKkCgQYCAxQENAMAATMG5AbdBLEHfgDYAyIAoAGjBH4HtwXiBAAAmALvBBIBlgV2B2UGiwbOBooHiwPVB1cEIQFEABEAaQAqBLsAnAbjB60HEALUA4QHJATJAncEXwfbBRoDHQSdBRwD5gJZBgwGbwexBg4AHgSPAQ0HsgA9BkUFsQXfA0YGbAZCB7MBDgf2BdYBvASTBM8A5wObBOgBBQePBIUBoQfEBSgFBgWRB1sG3ge2AUAG0wHvAncFLwdfBeUERwM4BYMD7gQfB+UCfAC+BX8EtgSmBLgAHwaYACMBwwM+AkkBDgFeA2sBxgenAWUDaQG7A9oFCwUtBxgHCgDCBFAG9QXcAkkERAQnBzgDyQQoAfUAoAerAFYF3QNqAYsClQb6AzMFJgd2BtkALQFDBRgF0QQ+BvwFJQOPBv8FeQY2AGYAOgKfBNUECAGaArMCswQWAqcGSQWCA3gF3wKjA7UCEQGNA8sC2QPNBR8AOwOuBRcGwAa5BzUFwwQ1BP4B3QG3BJ4BdwaHBkcE1wAnACIEDgPnB3AGqQAKAmIB4AZWApAAmAaSBGwFPgQbA2QE5QApAmUAjAYMARcAUwNHApQHWAH/ALIHfwO9A+UFFgH1ByYBhAP9BVYAnQFiADEEbwD4BpABCAZ3Av4HCgULAHkC3wWkAnQFkARFAlAASQMxAroEXgUTB4ADrwCUAf0HmwBJBw8AtABxBIAGoQDhB4EBdAY9BDMCvQIVBp8BYwWCBhAFpAXCAgIEuwJ5AfsHMAL1A/kDbQFWA5UHzgSOAjQEhQfDAggAUwQqB/wDWweyBMgHZAFcAH0FowIFAPkClASFBFUAJAH5BTkCgwKEBlMAKAeGAnMD4gMiBc4ATgdlAZwBtgfoAOIGHQW/A0sHDAW1AesFnQSGAM8FpAGQA/oB0AeYB4wFNwYpAWEEMgOXBR4AAASXABAB6QS2BtwGJwb/B0gFUwecBUIDbADMAp4HdAKgBlQAyAFPBWYE3QdrA+YGyQDGBGYBIQX9A2YGKAJzAE8HYwdyA3wD1QCeALUGyAO8AQ8DVgRuAJcCowFHAMAHKwLlAf4AbgfRB2oCxwAZBX4C5AVABbgBgAH7A5MAVQNkAHsH/AEZAR0BNgW7Bc0B1gU2B1UGBwWpBjoGSATbAbQC8gI4AnoEOwIWB/IAiAKnAlMCqAJoBCoCpgDgBIMFpATGBm8CeAFIArEAqQVpBwUBWQHNAtgH6wASBxcFYwSzBz8AUQSABe4HGAOKAiAEzgUOBnEDkAZPAkQHwgA9AnoDKwbwAdwHiQJzBd4EcADnBjkBeAccANQBWgMJBaAFHQKVAX0DDwTLASwFpQZ/AkYAcwfaAQ0E5AQmAJMFawfZAgoE2wcmAiQDZwDEAtwDBgEXBKQH9gLqA+4DOQXoBdgEugfHB1IFRQe0B1ICtwFXAgsGnwAtA9YCYACHBDoADgJWAewCXQd7BIQAUQB2AJoBMADBBv0AVwWKBhkHBAb+AkAHQwOdBrcGqAbhBTUC8ACwA9MHiwQJAE0DLwVcAoIAggV8BjwCeAA7BGAD0QPABEYFPAYJBLwGYQWPABQGlwbZAfsCHAGSB6YCgARoAKQDXQVyAWwDAQPpAYgAIgJsAa8HtwPnAukCNAEhBl0DiQfqBAoH0ACoAUwGiQMIA4wBCAKOBkgGQgbIBqkElgRkBgsCEgM4BoYFkgHDBdgAXAYUB60BuwbzA78CnwNVB80AbQMcAtoAkgOOA+sB9ABRA7AHawKTBi4ERAKpBwIF4AfxA6cFIgYXASkErwEFBD4FaAEqA4wERQZZBaIBvAJiBY8CLABEBtECVQUgAUwBKQCbBZYG9gDdAkkG1AAkADYBlgGHB3kHqwJTBe4BwAMQA64DKwU+B/IHPAXjAFcGcAeJBu0FrwQSBZkCRAFlB7MAZAWNB9UCjQIyB/YEsAbqBgMAlAaiB20GOAAVAJkF9wNDBiYDcgVFAOgChAHZBvQGAgCqBpkHaAbwA/cCywMtBJcBwQFYB6wF4AHuADEB7QNBBHcDGgYhA9EB+gX3AEMCwQXcAUoC+AVfAscBlgfEBLYCyAX5AAAFFQIpBiIBDQKLBRQCvQAWANgF7AWLADUG8QJZBAMB+AJQAl4GGgC/AAwEkgZ7BTADvwfiAOkGCwRGA3YDSQB1A9kEEwYeBcMHEwHXApsBPwVHB7UDbwUXAg0F1Ae9BCUC/wTKBJEBzAYjAgwCyQU4B/MA6wNpBksGLQKTAcEA5QdhAbsBigSFBiwCXgehAu0GAQKjBxoHFgX0BxQB0AUoAz4DiAe/BVcAjAIzAfsEhQAEBzcH8gQ0APEARwFGB4wAWQAWBpIC5wHKBooDFQS+BFsDdQIHBwQDHgMPAdsDUgcwBdYD+QEgBVkCMQCdA6gE9AEJBp8CvADbALMGGwfAAnQA9gffBIMGYwNUA3UBHwL5BygAqgC+B0EC3wAIBDUAxgHFBp4G0AJaAtoE8gZvAaMAYAVbAaIDzwTXAyAGAQVyAIgGTgI0BgMGRQSiBHQE7AeGB/cGmQZPA0MEiQW1BJwDPwcZBBsChgOmBiEC4QRyBBgAPAc9A0EHQwHiAQcCFgQ4BLIFGARfBAQCMwN7A2cBoAC5BhMDKwFwAsMAuQQwBpoEHQcCAY4AogWYBOUG4gd4BpcEegYuA/AHrQUyAMMGjAecAPYBaQW1BcIDTwEFBr0FVQHXBAgHmwZaBK4EtAbCB5MHxAbmAxgBZwRIASEH0wK1AHcH5wRYBfcHPQWzBbkBUwHEAWIEWgGnAEQD/AdoB04AKwOyAVwHZgLrAnUGQgIJAdIDEgQLA+ME2gINA0YEcQchBPoAOwH0A1IA3gFuBL4GUAEJAxQAVgexAwMC7ATBAnMCbgE5BuwGgAf9AhUFqwSaB7sH3wbpA3QDRwV+Ba0C7wFkB6UArARcBR8EGwVfAVwEfASTAj8C5gV9AGcGcwZ6AVQGRgK9B+UDVAehA5oAzwYjAPsFOgfJATkEoQUVB7ACeQO6AgEGvgPqAioGJAXRAOMDUgRQA6UB/QGOB20EewaUAkgAYAHMByIDvgECB40GLAdMA0oFqwcnAtgCkAfRBYkBcQH+BSQHNwSBBVAFIADeBqYD/wbvBuEDgwfEAEAAbAIMA1oFlAUKAYQC/QRxBtIEzwHzBOgDKgWYAQEBogaiAPoEAQT4BAoDjQCJAA0GXQThAboALwIaApkD7gZuAwsBXwCuAuICwgXOA6UDggESAAEA8QF4AsYFagV/BVgDgAJ5AEgDsgbqB3MBPwE6AZACuAbwBGoGQgTJByMDIAenBNUBnAelB1IBqAfxBb8BPAFUAgUCWQcsAzEFtAMcBawB6wZIB64AvgDABTYCIwW8A3AFcATMBX4B0gIbBCUAEQMeBvwEMgQyBikFPAQqAIwDBwAOBb4CSgb4A9cGMweJBBAHtwdiAgQAWATcBW4FZQVBA6cDoAN2BW8EWgaXB+QD5geaBhwGnQebA3EARwY+AOYBbgb2A30HZwX4AewDQgCIAycBXgGWAMwDcgaZBFAEnweZAREE2wbOBywG5AfiBREHTAA/BLAEAAMCBuEC+wGYBToETQYbASQCawVvBtMF6gWBBB4CZQLJBssAewIeAcwBQwCrAYYEiwfnAJEGawAlBKACTwByB+wAxQHZBx0GNgZTBlUCHgeGAe8AJwOtAy8B4wIuBncBGAJhA98H9AJMBBkAkAVBBXwCrwM6BbEC7wMwARMCqgGNBdYH7QSmAU8G1Ab3BI4F2AFCAasGTQWFBU4GhAXtAIUC8QazAzsG5wXLBCEArAalAjMEFANKBykHWALYBt4C0QaDAS4HPwN6B1EG3gU3AUYBWwJaB7oBYASIAUoEQAJ2AiwBtwI3BQAH1gBOA1EFCweeA5QA9QJUARUBKwRPBGMCmANRB7ID5ABsB/IFpgcxB8UDwABXBwUD2gYaASIHZAISBjcAWwQrB4ICjQFjBjwAhwWHAocBxgCVAGkC3QWwBQYAWwVSBqMGvAXKB3ADLgB4BF0A+gbbBPoH0gfUBe0BIwffAZ4FlQLjBpUDRAUYBtQCrgaqA20CgQMZA9IAcQXLBswAxQWgBAEHtAEHBtkF0AODBFcDOAEaBZ8GOwCRAOoANQc+AcoAXAP3BZoFPQFiByUBxAfIAu4FzQZCBckDUQGKBf0GrwXFABYDSQKqAvgHdQfmAB0DeQX4AA8GuAOCB1gGugWCBJ0A7QdKAZkA3gBBAeMFnARZA7EBPQCjBYcD8wdtBbgE9wEkBu4CSwFeAPMGNAUxA5UEsAE1AWoDagDhBgYEEQb1BvkEdgHoBlsAwgE8A0sFdQRqB/MC5AF6AtoHrAKkAH4GpQQ2BMgEnwV7AfIBXQKhBuACBAEPAo0EyADbAtIFfwDcAJ4CfAfQBpEFrQS3AGQD9gahAdcB6QVFAagALAQwCwYJYIZIAWUDBAIB")); - byte[] plainText = Base64.decode( - "JPRvWBk1htKrDwB/tcjmdg02SxHNKyHwZqJ5EWxoFBpcCuthOyezRfBOKTAd7Py0pEYeq1POQqyWuhoIH7bLtdWK3WtUootS31fY2RGJ6h14Lyw80GmmawHFWbXwxirn3SkuWlF9DEs8fLa6SToRvR6JLJXYrM9I1U120z63xhRt0NyvYG/n/0H7IGpTD2gHjoK+AxpcyIV0pgRV69du6XX754P3JhH3WtUhDLo0pyeGI07di3aXxmLWoz8iAU1N3enwxDksZxT51hPkZERlcZ4l8p2B3rjE+JnQkaa0gWkE7WP+aoxcax6OXN00MgbX9yteJy/cRKdw+A=="); - byte[] cipherText = Base64.decode( - "5Btx1aKTMktU9pwKG9U1KZp9OTag90msKyZhaqzWnXrDwJpPfbWZHt7VGOvbkKxQ8O6VdqDqyRMcAJPARZzjbYCTwug5jsUsEL2FQfaEpSw3bV8NYHcVPe9nz5a92cOjkSku9+GhTtAv1X/4UkIjgTdYeLEHoNmAmhfh3wrB9yWbOm7NujYa2T84w+9CxOBTfuPnKlay4O6vMRSpZGNG+BNMAkeDVGcQKqEofk80yDqW1GAbRY/kD7tqh0IXo6ARlGlumy/Zgmbb+1J4zo4obtB5s4JdrWo2d3JMK9vviQz9R2jOQme65prfp8pAM9OG3zNwqkFO8YdKjNMHUOZ+vEpwbzdzDhqOJprSWfAWL+PHk8xHevMKrCaqHLRp5Xk+rSkGAEaa9GuoNmQkO9Cx5qfvfpfzB+Md2YjmpeofOzL7QQRvE6yPRPANJys0pi7gGd2DHiw="); - - McElieceKobaraImaiCipher cipher = new McElieceKobaraImaiCipher(); - - cipher.init(false, PrivateKeyFactory.createKey(cca2PrivKey)); - - isTrue(Arrays.areEqual(plainText, cipher.messageDecrypt(cipherText))); - } - - public static void main( - String[] args) - { - runTest(new McElieceCipherTest()); - } - -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/McElieceFujisakiCipherTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/McElieceFujisakiCipherTest.java deleted file mode 100644 index b2ad2f8e7d..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/McElieceFujisakiCipherTest.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import java.security.SecureRandom; -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.legacy.crypto.mceliece.McElieceCCA2KeyGenerationParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2KeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2Parameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceFujisakiCipher; -import org.bouncycastle.util.test.SimpleTest; - -public class McElieceFujisakiCipherTest - extends SimpleTest -{ - - SecureRandom keyRandom = new SecureRandom(); - - public String getName() - { - return "McElieceFujisaki"; - - } - - - public void performTest() - throws InvalidCipherTextException - { - int numPassesKPG = 1; - int numPassesEncDec = 10; - Random rand = new Random(); - byte[] mBytes; - for (int j = 0; j < numPassesKPG; j++) - { - McElieceCCA2Parameters params = new McElieceCCA2Parameters(); - McElieceCCA2KeyPairGenerator mcElieceCCA2KeyGen = new McElieceCCA2KeyPairGenerator(); - McElieceCCA2KeyGenerationParameters genParam = new McElieceCCA2KeyGenerationParameters(keyRandom, params); - - mcElieceCCA2KeyGen.init(genParam); - AsymmetricCipherKeyPair pair = mcElieceCCA2KeyGen.generateKeyPair(); - - ParametersWithRandom param = new ParametersWithRandom(pair.getPublic(), keyRandom); - Digest msgDigest = new SHA256Digest(); - McElieceFujisakiCipher mcElieceFujisakiDigestCipher = new McElieceFujisakiCipher(); - - - for (int k = 1; k <= numPassesEncDec; k++) - { - // System.out.println("############### test: " + k); - // initialize for encryption - mcElieceFujisakiDigestCipher.init(true, param); - - // generate random message - int mLength = (rand.nextInt() & 0x1f) + 1;; - mBytes = new byte[mLength]; - rand.nextBytes(mBytes); - - msgDigest.update(mBytes, 0, mBytes.length); - byte[] hash = new byte[msgDigest.getDigestSize()]; - msgDigest.doFinal(hash, 0); - - // encrypt - byte[] enc = mcElieceFujisakiDigestCipher.messageEncrypt(hash); - - // initialize for decryption - mcElieceFujisakiDigestCipher.init(false, pair.getPrivate()); - byte[] constructedmessage = mcElieceFujisakiDigestCipher.messageDecrypt(enc); - - // XXX write in McElieceFujisakiDigestCipher? - - - boolean verified = true; - for (int i = 0; i < hash.length; i++) - { - verified = verified && hash[i] == constructedmessage[i]; - } - - if (!verified) - { - fail("en/decryption fails"); - } - else - { - // System.out.println("test okay"); - // System.out.println(); - } - - } - } - - } - - public static void main( - String[] args) - { - runTest(new McElieceFujisakiCipherTest()); - } - -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/McElieceKobaraImaiCipherTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/McElieceKobaraImaiCipherTest.java deleted file mode 100644 index 35ffc0ecf2..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/McElieceKobaraImaiCipherTest.java +++ /dev/null @@ -1,159 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import java.security.SecureRandom; -import java.util.Random; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; -import org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory; -import org.bouncycastle.pqc.crypto.util.PublicKeyFactory; -import org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2KeyGenerationParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2KeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2Parameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PublicKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceKobaraImaiCipher; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Strings; -import org.bouncycastle.util.test.SimpleTest; - -public class McElieceKobaraImaiCipherTest - extends SimpleTest -{ - - SecureRandom keyRandom = new SecureRandom(); - - public String getName() - { - return "McElieceKobaraImai"; - - } - - private void checkEncoding() - throws Exception - { - checkEncoding(new McElieceCCA2Parameters("SHA-1")); - checkEncoding(new McElieceCCA2Parameters("SHA-224")); - checkEncoding(new McElieceCCA2Parameters("SHA-256")); - checkEncoding(new McElieceCCA2Parameters("SHA-384")); - checkEncoding(new McElieceCCA2Parameters("SHA-512")); - } - - private void checkEncoding(McElieceCCA2Parameters params) - throws Exception - { - McElieceCCA2KeyPairGenerator mcElieceCCA2KeyGen = new McElieceCCA2KeyPairGenerator(); - McElieceCCA2KeyGenerationParameters genParam = new McElieceCCA2KeyGenerationParameters(keyRandom, params); - - mcElieceCCA2KeyGen.init(genParam); - AsymmetricCipherKeyPair pair = mcElieceCCA2KeyGen.generateKeyPair(); - - McElieceCCA2PrivateKeyParameters priv1 = (McElieceCCA2PrivateKeyParameters)pair.getPrivate(); - McElieceCCA2PublicKeyParameters pub1 = (McElieceCCA2PublicKeyParameters)pair.getPublic(); - - McElieceCCA2PrivateKeyParameters priv2 = (McElieceCCA2PrivateKeyParameters)PrivateKeyFactory.createKey(PrivateKeyInfoFactory.createPrivateKeyInfo(priv1)); - McElieceCCA2PublicKeyParameters pub2 = (McElieceCCA2PublicKeyParameters)PublicKeyFactory.createKey(SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(pub1)); - - isEquals(PrivateKeyInfoFactory.createPrivateKeyInfo(priv1), PrivateKeyInfoFactory.createPrivateKeyInfo(priv2)); - isEquals(SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(pub1), SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(pub2)); - - byte[] msg = Arrays.concatenate(Strings.toByteArray("A not so random string"), new byte[155]); - - McElieceKobaraImaiCipher cipher = new McElieceKobaraImaiCipher(); - cipher.init(true, pub1); - byte[] enc1 = cipher.messageEncrypt(msg); - - cipher.init(false, priv2); - byte[] dec1 = cipher.messageDecrypt(enc1); - - isTrue(Arrays.areEqual(msg, dec1)); - - cipher.init(true, pub2); - byte[] enc2 = cipher.messageEncrypt(msg); - - cipher.init(false, priv1); - byte[] dec2 = cipher.messageDecrypt(enc2); - - isTrue(Arrays.areEqual(msg, dec2)); - } - - public void performTest() - throws Exception - { - checkEncoding(); - - int numPassesKPG = 0; // TODO: this algorithm is broken - int numPassesEncDec = 10; - Random rand = new Random(); - byte[] mBytes; - for (int j = 0; j < numPassesKPG; j++) - { - - McElieceCCA2Parameters params = new McElieceCCA2Parameters("SHA-256"); - McElieceCCA2KeyPairGenerator mcElieceCCA2KeyGen = new McElieceCCA2KeyPairGenerator(); - McElieceCCA2KeyGenerationParameters genParam = new McElieceCCA2KeyGenerationParameters(keyRandom, params); - - mcElieceCCA2KeyGen.init(genParam); - AsymmetricCipherKeyPair pair = mcElieceCCA2KeyGen.generateKeyPair(); - - ParametersWithRandom param = new ParametersWithRandom(pair.getPublic(), keyRandom); - Digest msgDigest = new SHA256Digest(); - McElieceKobaraImaiCipher mcElieceKobaraImaiDigestCipher = new McElieceKobaraImaiCipher(); - - - for (int k = 1; k <= numPassesEncDec; k++) - { - // System.out.println("############### test: " + k); - // initialize for encryption - mcElieceKobaraImaiDigestCipher.init(true, param); - - // generate random message - int mLength = (rand.nextInt() & 0x1f) + 1; - mBytes = new byte[mLength]; - rand.nextBytes(mBytes); - - msgDigest.update(mBytes, 0, mBytes.length); - byte[] hash = new byte[msgDigest.getDigestSize()]; - msgDigest.doFinal(hash, 0); - - // encrypt - byte[] enc = mcElieceKobaraImaiDigestCipher.messageEncrypt(hash); - - // initialize for decryption - mcElieceKobaraImaiDigestCipher.init(false, pair.getPrivate()); - byte[] constructedmessage = mcElieceKobaraImaiDigestCipher.messageDecrypt(enc); - - // XXX write in McElieceFujisakiDigestCipher? - - boolean verified = true; - for (int i = 0; i < hash.length; i++) - { - verified = verified && hash[i] == constructedmessage[i]; - } - - if (!verified) - { - fail("en/decryption fails"); - } - else - { - // System.out.println("test okay"); - // System.out.println(); - } - - } - } - - } - - public static void main( - String[] args) - { - runTest(new McElieceKobaraImaiCipherTest()); - } - -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/McEliecePointchevalCipherTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/McEliecePointchevalCipherTest.java deleted file mode 100644 index fd4c2a4956..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/McEliecePointchevalCipherTest.java +++ /dev/null @@ -1,100 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import java.security.SecureRandom; -import java.util.Random; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2KeyGenerationParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2KeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2Parameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McEliecePointchevalCipher; -import org.bouncycastle.util.test.SimpleTest; - -public class McEliecePointchevalCipherTest - extends SimpleTest -{ - SecureRandom keyRandom = new SecureRandom(); - - public String getName() - { - return "McElieceFujisaki"; - - } - - public void performTest() - throws Exception - { - int numPassesKPG = 1; - int numPassesEncDec = 10; - Random rand = new Random(); - byte[] mBytes; - for (int j = 0; j < numPassesKPG; j++) - { - - McElieceCCA2Parameters params = new McElieceCCA2Parameters("SHA-256"); - McElieceCCA2KeyPairGenerator mcElieceCCA2KeyGen = new McElieceCCA2KeyPairGenerator(); - McElieceCCA2KeyGenerationParameters genParam = new McElieceCCA2KeyGenerationParameters(keyRandom, params); - - mcElieceCCA2KeyGen.init(genParam); - AsymmetricCipherKeyPair pair = mcElieceCCA2KeyGen.generateKeyPair(); - - ParametersWithRandom param = new ParametersWithRandom(pair.getPublic(), keyRandom); - Digest msgDigest = new SHA256Digest(); - McEliecePointchevalCipher mcEliecePointchevalDigestCipher = new McEliecePointchevalCipher(); - - - for (int k = 1; k <= numPassesEncDec; k++) - { - // System.out.println("############### test: " + k); - // initialize for encryption - mcEliecePointchevalDigestCipher.init(true, param); - - // generate random message - int mLength = (rand.nextInt() & 0x1f) + 1; - mBytes = new byte[mLength]; - rand.nextBytes(mBytes); - - msgDigest.update(mBytes, 0, mBytes.length); - byte[] hash = new byte[msgDigest.getDigestSize()]; - msgDigest.doFinal(hash, 0); - - // encrypt - byte[] enc = mcEliecePointchevalDigestCipher.messageEncrypt(hash); - - // initialize for decryption - mcEliecePointchevalDigestCipher.init(false, pair.getPrivate()); - byte[] constructedmessage = mcEliecePointchevalDigestCipher.messageDecrypt(enc); - - // XXX write in McElieceFujisakiDigestCipher? - - boolean verified = true; - for (int i = 0; i < hash.length; i++) - { - verified = verified && hash[i] == constructedmessage[i]; - } - - if (!verified) - { - fail("en/decryption fails"); - } - else - { - // System.out.println("test okay"); - // System.out.println(); - } - - } - } - - } - - public static void main( - String[] args) - { - runTest(new McEliecePointchevalCipherTest()); - } - -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUEncryptTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUEncryptTest.java deleted file mode 100644 index a6b580dbe8..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUEncryptTest.java +++ /dev/null @@ -1,298 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import java.io.IOException; -import java.security.SecureRandom; - -import junit.framework.TestCase; -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUEncryptionKeyGenerationParameters; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUEncryptionKeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUEncryptionPrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUEncryptionPublicKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUEngine; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUParameters; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.Polynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.SparseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.TernaryPolynomial; -import org.bouncycastle.util.Arrays; - -public class NTRUEncryptTest - extends TestCase -{ - public void testEncryptDecrypt() - throws InvalidCipherTextException - { - NTRUEncryptionKeyGenerationParameters params = NTRUEncryptionKeyGenerationParameters.APR2011_743.clone(); - // set df1..df3 and dr1..dr3 so params can be used for SIMPLE as well as PRODUCT - params.df1 = NTRUEncryptionKeyGenerationParameters.APR2011_743_FAST.df1; - params.df2 = NTRUEncryptionKeyGenerationParameters.APR2011_743_FAST.df2; - params.df3 = NTRUEncryptionKeyGenerationParameters.APR2011_743_FAST.df3; - params.dr1 = NTRUEncryptionKeyGenerationParameters.APR2011_743_FAST.dr1; - params.dr2 = NTRUEncryptionKeyGenerationParameters.APR2011_743_FAST.dr2; - params.dr3 = NTRUEncryptionKeyGenerationParameters.APR2011_743_FAST.dr3; - - int[] values = new int[] { NTRUParameters.TERNARY_POLYNOMIAL_TYPE_SIMPLE, NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT }; - - for (int i = 0; i != values.length; i++) - { - int polyType = values[i]; - - boolean[] booleans = {true, false}; - for (int j = 0; j != booleans.length; j++) - { - params.polyType = polyType; - params.fastFp = booleans[j]; - - VisibleNTRUEngine ntru = new VisibleNTRUEngine(); - NTRUEncryptionKeyPairGenerator ntruGen = new NTRUEncryptionKeyPairGenerator(); - - ntruGen.init(params); - - AsymmetricCipherKeyPair kp = ntruGen.generateKeyPair(); - - testPolynomial(ntru, kp, params); - - testText(ntru, kp, params); - // sparse/dense - params.sparse = !params.sparse; - testText(ntru, kp, params); - params.sparse = !params.sparse; - - testEmpty(ntru, kp, params); - testMaxLength(ntru, kp, params); - testTooLong(ntru, kp, params); - testInvalidEncoding(ntru, kp, params); - } - } - } - - // encrypts and decrypts a polynomial - private void testPolynomial(VisibleNTRUEngine ntru, AsymmetricCipherKeyPair kp, NTRUEncryptionKeyGenerationParameters params) - { - SecureRandom random = new SecureRandom(); - IntegerPolynomial m = DenseTernaryPolynomial.generateRandom(params.N, random); - SparseTernaryPolynomial r = SparseTernaryPolynomial.generateRandom(params.N, params.dr, params.dr, random); - - ntru.init(true, kp.getPublic()); // just to set params - - IntegerPolynomial e = ntru.encrypt(m, r, ((NTRUEncryptionPublicKeyParameters)kp.getPublic()).h); - IntegerPolynomial c = ntru.decrypt(e, ((NTRUEncryptionPrivateKeyParameters)kp.getPrivate()).t, ((NTRUEncryptionPrivateKeyParameters)kp.getPrivate()).fp); - - assertTrue(Arrays.areEqual(m.coeffs, c.coeffs)); - } - - // encrypts and decrypts text - private void testText(NTRUEngine ntru, AsymmetricCipherKeyPair kp, NTRUEncryptionKeyGenerationParameters params) - throws InvalidCipherTextException - { - byte[] plainText = "text to encrypt".getBytes(); - - ntru.init(true, kp.getPublic()); - - byte[] encrypted = ntru.processBlock(plainText, 0, plainText.length); - - ntru.init(false, kp.getPrivate()); - - byte[] decrypted = ntru.processBlock(encrypted, 0, encrypted.length); - - assertTrue(Arrays.areEqual(plainText, decrypted)); - } - - // tests an empty message - private void testEmpty(NTRUEngine ntru, AsymmetricCipherKeyPair kp, NTRUEncryptionKeyGenerationParameters params) - throws InvalidCipherTextException - { - byte[] plainText = "".getBytes(); - - ntru.init(true, kp.getPublic()); - - byte[] encrypted = ntru.processBlock(plainText, 0, plainText.length); - - ntru.init(false, kp.getPrivate()); - - byte[] decrypted = ntru.processBlock(encrypted, 0, encrypted.length); - - assertTrue(Arrays.areEqual(plainText, decrypted)); - } - - // tests a message of the maximum allowed length - private void testMaxLength(NTRUEngine ntru, AsymmetricCipherKeyPair kp, NTRUEncryptionKeyGenerationParameters params) - throws InvalidCipherTextException - { - byte[] plainText = new byte[params.maxMsgLenBytes]; - System.arraycopy("secret encrypted text".getBytes(), 0, plainText, 0, 21); - ntru.init(true, kp.getPublic()); - - byte[] encrypted = ntru.processBlock(plainText, 0, plainText.length); - - ntru.init(false, kp.getPrivate()); - - byte[] decrypted = ntru.processBlock(encrypted, 0, encrypted.length); - - assertTrue(Arrays.areEqual(plainText, decrypted)); - } - - // tests a message that is too long - private void testTooLong(NTRUEngine ntru, AsymmetricCipherKeyPair kp, NTRUEncryptionKeyGenerationParameters params) - { - byte[] plainText = new byte[params.maxMsgLenBytes + 1]; - try - { - System.arraycopy("secret encrypted text".getBytes(), 0, plainText, 0, 21); - - ntru.init(true, kp.getPublic()); - - byte[] encrypted = ntru.processBlock(plainText, 0, plainText.length); - - ntru.init(false, kp.getPrivate()); - - byte[] decrypted = ntru.processBlock(encrypted, 0, encrypted.length); - - assertTrue(Arrays.areEqual(plainText, decrypted)); - fail("An exception should have been thrown!"); - } - catch (DataLengthException ex) - { - assertEquals("Message too long: " + plainText.length + ">" + params.maxMsgLenBytes, ex.getMessage()); - } - catch (InvalidCipherTextException e) - { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } - } - - // tests that altering the public key *AFTER* encryption causes the decrypted message to be rejected - private void testInvalidEncoding(NTRUEngine ntru, AsymmetricCipherKeyPair kp, NTRUEncryptionKeyGenerationParameters params) - { - try - { - byte[] plainText = "secret encrypted text".getBytes(); - ntru.init(true, kp.getPublic()); - - byte[] encrypted = ntru.processBlock(plainText, 0, plainText.length); - - NTRUEncryptionPrivateKeyParameters orig = (NTRUEncryptionPrivateKeyParameters)kp.getPrivate(); - IntegerPolynomial h = (IntegerPolynomial)((NTRUEncryptionPublicKeyParameters)kp.getPublic()).h.clone(); - h.coeffs[0] = (h.coeffs[0] + 111) % params.q; // alter h - NTRUEncryptionPrivateKeyParameters privKey = new NTRUEncryptionPrivateKeyParameters(h, orig.t, orig.fp, params.getEncryptionParameters()); - - ntru.init(false, privKey); - - ntru.processBlock(encrypted, 0, encrypted.length); - - fail("An exception should have been thrown!"); - } - catch (InvalidCipherTextException ex) - { - assertEquals("Invalid message encoding", ex.getMessage()); - } - } - - // encrypts and decrypts text using an encoded key pair (fastFp=false, simple ternary polynomials) - public void testEncodedKeysSlow() - throws IOException, InvalidCipherTextException - { - byte[] plainText = "secret encrypted text".getBytes(); - - // dense polynomials - NTRUEncryptionKeyGenerationParameters params = NTRUEncryptionKeyGenerationParameters.APR2011_743; - NTRUEngine ntru = new NTRUEngine(); - - byte[] privBytes = {2, -94, 95, 65, -107, 27, 98, 62, -15, -62, 21, -4, 119, -117, 7, 68, 100, 113, -36, -82, 87, -87, -82, 24, -45, -75, -74, -108, 105, 24, 123, 117, 124, 74, -27, 42, -106, -78, 114, 27, 18, 77, -41, 105, -113, 39, 49, 46, 109, -69, 61, 77, 49, 117, 14, -29, 42, 3, 120, -121, -120, -37, 95, 84, 60, -9, -31, -64, 31, 72, 115, -15, 21, -6, 27, -60, -73, -29, -33, -81, -43, 106, 65, 114, 102, -14, -115, -96, 9, 54, 23, -18, -24, -76, 84, -41, -79, 35, 88, 11, 41, 67, 44, -63, -28, 76, 84, -41, -103, 106, -22, 35, -2, -40, -48, -121, -128, 76, 63, 123, -11, 103, -35, -32, 21, -51, -99, -40, -103, -12, 64, -80, 57, -56, 1, -51, 103, 83, 50, 111, -87, -98, 7, -109, 25, -51, 23, -92}; - byte[] pubBytes = {91, -66, -25, -81, -66, -33, 25, -31, 48, 23, -38, 20, -30, -120, -17, 1, 21, 51, -11, 102, -50, 62, 71, 79, 32, -49, -57, 105, 21, -34, -45, -67, 113, -46, -103, 57, 28, -54, -21, 94, -112, -63, 105, -100, -95, 21, -52, 50, 11, -22, -63, -35, -42, 50, 93, -40, 23, 0, 121, 23, -93, 111, -98, -14, 92, -24, -117, -8, -109, -118, -4, -107, -60, 100, -128, -47, -92, -117, -108, 39, -113, 43, 48, 68, 95, 123, -112, 41, -27, -99, 59, 33, -57, -120, -44, 72, -98, -105, -91, -52, -89, 107, 119, 87, -36, -102, -83, 67, -8, 30, -54, 74, 93, 119, -3, 126, 69, -104, -44, -24, 124, 108, -125, 73, 98, 121, -49, -37, -24, 87, -71, 91, 8, -31, -50, 95, 112, 27, 97, -93, 3, -73, -54, -16, -92, -108, -74, 88, -5, 23, 70, 69, -49, -46, -50, 65, 69, -54, -41, 109, 8, -80, -23, -84, 120, -77, 26, 99, -104, -33, 82, 91, 22, -17, 113, -29, 66, -7, -114, -101, -111, -47, -1, -3, -57, 62, 79, -70, -58, 45, 76, 28, -117, 59, -117, 113, 84, -55, 48, 119, 58, -105, -20, 80, 102, 14, -69, -69, 5, 11, -87, 107, 15, 105, -69, -27, -24, 47, -18, -54, -45, -67, 27, -52, -20, -94, 64, -26, -58, 98, 33, -61, 71, -101, 120, 28, 113, 72, 127, 50, 123, 36, -97, 78, 32, -74, 105, 62, 92, 84, -17, 21, -75, 24, -90, -78, -4, -121, 47, -82, 119, 27, -61, 17, -66, 43, 96, -49, -6, 66, -13, -75, -95, 64, -12, -39, 111, 46, -3, -123, 82, 12, -26, -30, -29, 71, -108, -79, -112, 13, 16, -70, 7, 100, 84, 89, -100, 114, 47, 56, 71, 83, 63, -61, -39, -53, -100, 23, -31, -52, -46, 36, -13, 62, 107, 28, -28, 92, 116, -59, 28, -111, -23, -44, 21, -2, 127, -112, 54, -126, 13, -104, 47, -43, -109, -19, 107, -94, -126, 50, 92, -69, 1, 115, -121, -52, -100, 25, 126, -7, 86, 77, 72, -2, -104, -42, 98, -16, 54, -67, 117, 14, -73, 4, 58, 121, 35, 1, 99, -127, -9, -60, 32, -37, -106, 6, -108, -13, -62, 23, -20, -9, 21, 15, 4, 126, -112, 123, 34, -67, -51, 43, -30, -75, 119, -112, -58, -55, -90, 2, -5, -46, -12, 119, 87, 24, -52, 2, -29, 113, 61, -82, -101, 57, -11, -107, -11, 67, -42, -43, -13, 112, -49, 82, 60, 13, -50, 108, 64, -64, 53, -107, -9, 102, -33, 75, -100, -115, 102, -113, -48, 19, -119, -72, -65, 22, -65, -93, 34, -71, 75, 101, 54, 126, 75, 34, -21, -53, -36, 127, -21, 70, 24, 89, -88, 63, -43, -4, 68, 97, -45, -101, -125, -38, 98, -118, -34, -63, 23, 78, 15, 17, 101, -107, 119, -41, 107, 117, 17, 108, 43, -93, -6, -23, -30, 49, -61, 27, 61, -125, -68, 51, 40, -106, -61, 51, 127, 2, 123, 7, -50, -115, -32, -95, -96, 67, 4, 5, 59, -45, 61, 95, 14, 2, -76, -121, 8, 125, 16, -126, 58, 118, -32, 19, -113, -113, 120, -101, 86, 76, -90, 50, -92, 51, -92, 1, 121, -74, -101, -33, 53, -53, -83, 46, 20, -87, -112, -61, -87, 106, -126, 64, 99, -60, 70, 120, 47, -53, 36, 20, -90, 110, 61, -93, 55, -10, 85, 45, 52, 79, 87, 100, -81, -85, 34, 55, -91, 27, 116, -18, -71, -11, 87, -11, 76, 48, 97, -78, 64, -100, -59, -12, 19, -90, 121, 48, -19, 64, 113, -70, -14, -70, 92, 124, 42, 95, 7, -115, 36, 127, 73, 33, 30, 121, 88, 16, -90, 99, 120, -68, 64, -125, -78, 76, 112, 68, 8, 105, 10, -47, -124, 39, -107, -101, 46, -61, 118, -74, 102, -62, -6, -128, 17, -45, 61, 76, 63, -10, -41, 50, -113, 75, -83, -59, -51, -23, -61, 47, 7, -80, 126, -2, 79, -53, 110, -93, -38, -91, -22, 20, -84, -113, -124, -73, 124, 0, 33, -58, 63, -26, 52, 7, 74, 65, 38, -33, 21, -9, -1, 120, -16, 47, -96, 59, -64, 74, 6, 48, -67, -32, -26, 35, 68, 47, 82, 36, 52, 41, 112, -28, -22, -51, -6, -49, 105, 16, -34, 99, -41, 75, 7, 79, -22, -125, -30, -126, 35, 119, -43, -30, 32, 8, 44, -42, -98, 78, -92, -95, -10, -94, -1, -91, -122, 77, 0, 40, -23, 36, 85, 123, -57, -74, -69, -90, 89, 111, -120, 22, 5, -48, 114, 59, 31, 31, -25, -3, 24, 110, -110, 73, -40, 92, -26, -12, 52, 83, -98, -119, -6, -117, -89, 95, 83, -25, 122, -26, 114, 81, 25, 110, 79, -49, -39, 10, -78, -65, 57, -90, -46, -126, 15, -124, -104, -89, -66, -87, 24, -45, 39, -34, -40, -13, 106, 12, -25, -116, -47, 79, -81, 64, -17, -31, -70, 87, 36, 46, 102, 107, 48, 88, 34, 46, 24, 63, -100, 106, 27, 58, -71, 38, 60, -66, 45, -89, 39, -60, -116, -14, -119, 118, 0, -24, -9, 38, -71, -79, 124, -119, -64, -9, 71, -56, -82, -73, -69, 127, -1, -20, 123, 32, -43, 49, 5, 49, 105, -5, -2, 5, -105, -111, 89, -30, -41, -49, 61, 80, 69, 44, -33, -116, -45, -96, 63, 28, -17, -106, -94, 90, -40, -88, 122, 116, 116, 113, -65, 104, 119, -3, 96, -45, 18, -120, -111, 83, 43, -5, 101, 71, 48, 104, -112, -95, -46, 53, -96, -93, -126, 96, 56, 104, -111, 114, -1, -44, -120, -112, -19, 100, 41, -122, 23, -78, 33, -35, 11, 57, -18, 106, -40, 74, 61, 66, 54, -77, 96, 70, 108, -128, 91, -97, -36, -23, -86, -91, 44, 58, 117, 2, 26, 44, 95, 79, -101, -81, -92, 110, -81, -12, -88, -21, -83, 60, 93, -121, -114, -48, -34, -119, -1, 127, -121, 54, -128, -106, -39, -108, 81, 17, -3, -13, -57, 74, 41, -122, -65, -107, -118, -65, -61, 103, -69, 19}; - - byte[] fullBytes = new byte[pubBytes.length + privBytes.length]; - - System.arraycopy(pubBytes, 0, fullBytes, 0, pubBytes.length); - System.arraycopy(privBytes, 0, fullBytes, pubBytes.length, privBytes.length); - - NTRUEncryptionPrivateKeyParameters priv = new NTRUEncryptionPrivateKeyParameters(fullBytes, params.getEncryptionParameters()); - NTRUEncryptionPublicKeyParameters pub = new NTRUEncryptionPublicKeyParameters(pubBytes, params.getEncryptionParameters()); - AsymmetricCipherKeyPair kp = new AsymmetricCipherKeyPair(pub, priv); - - ntru.init(true, kp.getPublic()); - - byte[] encrypted = ntru.processBlock(plainText, 0, plainText.length); - - ntru.init(false, kp.getPrivate()); - - byte[] decrypted = ntru.processBlock(encrypted, 0, encrypted.length); - assertTrue(Arrays.areEqual(plainText, decrypted)); - - // sparse polynomials - params = NTRUEncryptionKeyGenerationParameters.EES1499EP1; - ntru = new NTRUEngine(); - privBytes = new byte[] {116, 7, 118, 121, 6, 77, -36, 60, 65, 108, 10, -106, 12, 9, -22, -113, 122, -31, -31, 18, 120, 81, -33, 5, 122, -76, 109, -30, -101, -45, 21, 13, -11, -49, -111, 46, 91, 4, -28, -109, 121, -119, -121, -58, -113, -9, -10, -25, -53, 40, -86, -22, -50, 42, 52, 107, 119, 17, 33, 125, -26, 33, 55, 25, -77, -65, -106, 116, -67, 91, 105, -7, 42, -107, -54, 101, 12, -12, 57, -116, 45, -107, -17, 110, 35, -64, 19, -38, -122, 115, -93, 53, 69, 66, -106, 17, 20, -71, 121, 23, -21, -45, 108, 97, 23, -98, -12, -41, -31, -53, 30, -42, 15, 85, -21, -89, 118, 42, -117, -39, 69, 0, -63, 83, 48, -80, -14, -123, -4, -116, -90, -107, -89, 119, 29, -30, 69, 22, -84, 47, 117, -123, 102, -116, 35, 93, -13, 84, -9, -122, 58, 101, 93, -106, -119, -35, -75, 76, 27, -125, -22, 68, 101, 49, 103, -13, -98, 93, -56, -110, -19, -12, 74, 104, 7, 6, -11, 47, 57, 90, 75, -30, 47, 66, -58, 14, 14, 70, 11, -119, -36, -118, -55, -53, 101, -73, -77, 33, -29, 96, -86, 38, 47, 103, 19, -37, -17, -50, -82, -87, -119, 37, -54, 77, -69, -16, -48, -52, 110, -26, 111, 35, 26, -53, -10, 9, -108, -34, 102, 7, -18, -72, -26, 24, -50, -43, 92, 56, -94, 23, -36, 60, 28, -121, 27, 127, -93, -79, -45, -60, 105, -6, -88, 72, -41, 47, -51, 3, 91, 116, 75, 122, -94, -113, 28, -96, -62, -29, -74, -85, -93, 51, 58, 72, 44, 9, 18, -48, -24, 73, 122, 60, -23, 83, -110, -7, -111, -69, 106, 51, 118, -83, -18, 109, -32, 40, 22}; - - pubBytes = new byte[] {-62, 56, 59, -46, 30, -19, 22, -115, -20, 117, -14, 3, 2, -57, 85, -24, 27, 57, 49, -93, -52, 87, 49, 96, 15, 95, -95, -86, -61, 50, -18, 3, 109, -55, -110, -57, 82, 124, -5, -57, 68, -18, 126, 114, 6, -22, 8, 121, 125, 29, -16, 112, -81, 27, -7, 109, -44, -123, -15, -14, 74, -126, 95, -94, -91, 119, 80, -48, 41, 49, 6, 104, 93, -97, -108, -82, 93, 70, -127, -113, -22, -103, 35, -115, 20, -115, 63, 57, -84, -18, -107, 81, 44, -16, 83, 71, -27, -2, -125, 87, 26, 100, -116, 110, 94, -46, -56, -82, 119, -110, -127, -99, -8, -118, 90, 64, -29, 102, 99, 92, 86, -117, 26, -89, 32, 17, 55, -65, -10, -5, -74, 19, 13, 113, -15, -103, 17, 10, -127, -95, -79, 19, 11, -24, 59, 28, -70, -55, -69, -105, -20, -117, 66, 4, 77, 116, -124, -62, 19, 109, 49, -120, 10, -15, 108, 84, 126, 122, -46, -37, 114, -78, -72, 34, -12, 25, -104, -3, 114, -94, 16, 31, 31, -124, -109, -64, 57, -47, -113, -26, 97, -58, 112, -40, 49, 80, -54, -115, -98, -60, -123, 91, 14, 75, -86, 77, -93, 68, 112, 82, 79, 28, -25, 49, -27, -112, 103, 60, -128, 95, -63, 2, -51, 2, -107, 80, 113, 18, 123, 24, 70, 77, -56, -48, 33, 89, 88, 29, 112, -102, -15, 52, -96, 17, -9, 6, -11, -119, 29, -107, -84, -19, 84, 124, 19, 90, -60, -41, 123, -81, 96, -119, 17, -61, 62, 55, 95, -73, -13, -60, 56, 77, 24, -39, -107, -78, 47, -91, 88, 90, 34, 112, -80, 83, -58, 127, 76, -97, -40, 78, -20, -1, -62, 19, 6, -43, -46, -36, -53, -22, -28, -119, 8, 19, 79, -9, -54, -126, -3, -20, -110, -82, 51, 3, 1, -123, -41, -40, -11, 91, -52, 48, 104, -11, -2, 49, 45, 52, -33, 109, -44, -30, -44, -83, -108, -10, 77, 106, 82, 3, 14, -48, -18, -79, -64, -34, -63, -18, 122, 33, 25, 44, 82, -112, 111, 68, 97, -58, -38, 25, 62, 78, 97, -36, 57, -19, 122, -18, -74, 67, -127, -24, 32, -45, 67, -106, 90, 0, 1, 91, 30, -80, 95, 9, 78, -4, -14, 16, 111, -56, -102, -90, 52, -1, 116, 19, -127, -23, -87, 103, -94, -111, 118, 53, -69, 77, 17, -3, 31, -53, -21, -78, 124, -88, 52, 117, 34, -52, -77, -107, -38, -102, 23, 73, -76, -88, 95, 64, -85, 12, 36, -86, 86, -17, 77, 121, 90, 24, -49, -107, 33, -116, 65, 13, 91, 118, -107, -21, 65, -59, 18, 125, 61, -65, -68, -19, 23, 88, 60, -6, 78, -8, 69, -62, -118, -93, 97, -64, -67, 28, 28, -87, -97, 72, -125, -119, 4, -43, 7, 22, -15, 52, 52, -82, -5, -51, 99, 20, -59, -2, -54, -67, 40, -128, -20, -37, 50, 123, 32, 8, -39, -105, 93, 73, 77, 84, 43, 89, 88, -6, 7, -108, 81, 27, 1, 50, 16, -101, 67, 95, 119, 105, 70, 99, -127, 22, 127, -33, -19, -113, -55, -100, 122, -86, 98, 53, 27, -95, 4, -121, -96, 87, 67, -98, -37, -10, 92, 29, -3, -115, -23, 37, 8, -30, 99, -117, 62, 101, 83, 49, 60, -83, -47, -33, 41, -118, 76, -7, 111, -15, 123, -59, 53, 2, -20, -57, 24, 57, 62, 84, -26, -11, 93, -118, 54, -13, 56, 77, -66, 18, -62, -76, 80, 98, 26, 120, -93, 55, 103, -1, 78, -92, 120, -23, -60, -75, 11, 53, -62, -94, -80, 120, 113, 33, -24, -64, -5, 23, 120, -14, 61, 26, -1, 56, 79, 34, 116, -16, -95, -71, 40, -89, -50, 71, -117, -109, 2, -2, -34, 94, -78, -88, -27, 70, 94, -86, 123, -49, 107, -65, -67, 84, 90, 123, -61, -2, 43, -119, -93, 75, -4, -81, 98, -36, 125, -23, -37, 81, 104, 90, -63, -52, 88, -96, -44, 25, 3, -37, -123, -48, 113, -76, -94, -109, -115, 37, -39, 104, -124, 82, -73, 100, 48, -54, -40, -65, 81, 16, -85, -41, 60, 42, 117, 65, 77, 14, -8, -56, 52, -118, -109, 125, 13, 64, -20, 125, -37, -74, -28, 118, 112, -126, 18, -101, 11, 75, 30, -4, -121, -13, -65, -13, -122, -53, -52, 20, -2, 67, 18, -106, 67, 83, -111, 15, 106, 10, 113, 53, -112, -3, 118, 8, -56, 40, 53, 23, -123, 96, 87, -118, -97, -116, -47, 85, -73, -85, -82, 124, -55, 55, 61, 46, 12, -6, 34, 22, -22, 3, 115, -49, 102, 23, 46, 39, 0, 118, 3, -45, 48, -73, -38, 29, -36, 11, -127, -86, 30, 29, -2, -108, -114, 64, 110, 86, -46, -91, -64, 95, -40, -65, 49, -79, -126, -37, -103, -71, 53, -85, 45, -51, 33, -28, -126, 36, -77, -120, 55, -54, 72, -21, 58, -87, -73, 18, -12, 20, -100, 30, 118, -83, -22, -90, 71, -64, 108, 101, -46, 36, 105, -46, -91, 60, -113, 72, 100, 82, -90, 106, -127, 65, -94, 17, 77, -10, -112, 46, 118, 72, -84, 57, -86, -114, 88, 91, 79, 30, 107, -35, 61, 81, 71, 40, -29, -6, -107, 61, -62, -6, 65, -68, 118, 61, 110, -115, -119, -73, 104, 59, -66, -89, -127, -8, -67, 122, -38, 79, -13, 93, 1, -32, -47, -3, 62, 88, -112, 105, 73, 96, 73, -104, -126, -69, 21, -22, 16, -85, 116, 9, 82, 54, -15, -55, -67, 68, -23, 16, -89, 48, -17, -107, 60, -43, -34, 66, -114, 63, -3, -26, 68, 68, -86, 120, -111, 99, 61, 101, 27, 93, 31, 90, -33, -94, 29, -89, 41, -80, 26, -23, -80, 27, 107, 69, -45, -123, 62, 63, 80, 1, -28, 52, -8, 35, -86, -127, 76, 102, 83, -104, -79, -98, 77, -28, 118, 18, -15, -98, -39, 2, -58, 95, 64, 105, -82, -7, 96, 110, 104, 127, 126, -124, 26, 36, 33, -42, 59, 82, 127, 42, -24, -61, -50, -18, -87, 22, -32, -125, -70, 103, -121, -112, -94, 58, -95, -97, 53, 95, -61, -83, 42, 37, 80, 51, -118, 125, 15, 67, 41, -97, 41, -121, 29, -88, 100, -113, 39, 101, 47, 91, -36, 48, -56, -13, 12, 37, 0, 81, 3, -40, 8, 36, -65, -11, -32, 108, 62, 79, 70, 91, -83, 2, -47, 0, 91, 10, 87, -19, -40, 96, 106, 41, 120, -53, 40, -114, 90, 64, 59, -115, 39, 2, 53, -49, -72, -114, 94, 5, 49, 74, 13, 50, -14, 76, -123, -11, -81, 100, 120, 16, -41, -72, -118, 28, 41, 98, 122, 27, 18, -108, -43, 51, -71, 93, -13, -42, -64, -118, -106, 45, 108, 72, -128, 58, -123, -29, -114, 15, 52, -72, 108, -62, 75, -15, 105, -89, 25, 37, 13, -21, -109, 68, 5, -89, 69, 10, -46, 18, -57, 77, -103, -74, 57, -43, -110, 1, -80, 82, 5, -9, -49, -53, 83, 4, 44, 64, -117, -67, -11, 1, -65, -81, 34, -23, -71, 14, 105, -93, 2, -120, 90, 92, -6, -128, -16, -51, 27, 123, 71, -117, -72, -81, 26, 28, 5, -117, -30, 22, -72, -76, -32, -14, 82, 90, 69, 74, -94, -72, -30, -17, 12, -37, -3, -80, 72, 2, -40, 41, 0, -53, 48, -37, -117, -128, -120, -80, 28, 49, -52, 114, -119, 92, -42, -105, 125, -95, 78, 76, 123, -56, 32, -66, 69, -58, 57, -77, -100, -70, 125, 53, -115, 8, 116, 88, -34, 86, -75, 55, 64, 79, -113, -124, -91, 50, -82, -119, 50, 11, 87, -14, -25, 15, -1, -49, -127, -5, -50, 72, -29, -78, 101, -119, -21, -15, 97, -63, 57, -123, -94, -24, -8, 104, 86, 79, 49, 102, -8, -76, 8, 69, 99, -64, -108, 70, 36, 71, -127, 56, 39, 78, 109, 42, -42, -2, 126, 17, -88, -65, -23, -64, 78, 87, 7, 6, -82, -98, 41, -46, -10, -25, 90, -73, 24, 127, -27, 118, -9, 81, -3, 115, -4, 47, 86, -30, -9, -50, 32, 86, 114, 58, -5, 78, 74, 36, 29, -126, 116, 117, -114, -92, -121, -36, -86, -18, 55, 49, 112, 43, 111, -99, -116, 70, 60, -63, 87, -4, -35, 15, 28, -27, -65, 66, 115, -33, 112, 94, 74, -22, 104, -56, -27, 39, -8, -53, -120, 8, -109, 73, -68, 67, 40, -59, 59, 121, -76, -41, -80, -54, -88, -120, -121, -118, -58, 74, -120, 82, -88, -113, 30, -8, 54, -126, -106, 37, -43, -74, -56, 40, -76, 93, 91, 28, -59, -30, -2, 107, 6, -89, -69, -121, -125, -109, 5, -94, -7, -2, -5, -67, 54, -90, 39, 5, -80, 93, -99, 82, -100, -128, -8, -39, -109, 66, -11, 99, -41, 18, -32, -122, 69, 6, -95, -21, 9, 19, -117, -34, -42, 11, 20, 84, 89, 91, -61, -13, -7, 55, 90, -15, 62, 59, -4, 125, -127, -24, -124, -99, -63, -23, 52, 111, -52, -60, -113, -65, -26, 127, 57, 21, 102, 101, -77, 66, -116, 117, 80, 7, 1, -96, -29, -99, 75, -73, 44, -99, 61, -73, 15, -18, 89, 95, 104, -12, 94, 33, 13, -49, 118, -84, -122, -2, -121, 62, -32, -80, 11, -10, 102, -67, 20, -3, 25, -6, 51, -17, -123, -76, 103, 3, 127, -107, -5, 122, 65, 22, 113, 120, 6, -19, -110, 86, 55, -88, -124, 0, -54, 17, 112, 15, 105, -28, 111, -93, 85, -59, -88, 28, 123, 55, 117, 10, 76, 54, -98, 116, 40, -65, -53, -80, 46, 66, -8, -114, 102, 66, 67, -117, 46, 21, -116, -38, 58, -105, 101, 37, -16, 5, 55, -33, -87, 72, 122, -114, -91, 41, -114, 77, 50, 109, 35, -61, 9, -55, -118, 126, -35, -108, 5, 62, 125, -109, -115, -55, 32, -71, 69, 110, 87, -82, 119, 26, 103, -77, -38, -13, 113, 74, 69, 116, 94, -21, 5, 35, 73, -80, -87, 80, 13, 108, 1, 82, -56, -35, -21, -78, -98, 121, 112, -117, 72, 47, 76, -97, -84, -110, -35, -19, -120, -13, 127, 5, 56, 72, -22, 110, -8, -71, 0, -57, -125, -101, 60, -64, -32, 1, 126, -109, 9, 84, 117, 62, -68, -106, 28, -118, -52, -81, 112, 11, 55, 68, -86, -65, 123, 83, 55, -72, 110, 63, -90, 31, 11, 90, -60, 20, 14, -36, 5, -92, 11, -100, 64, -57, -72, -105, 7, 103, 125, 99, -88, 32, -5, 41, -115, -11, 89, 81, 77, -33, -7, -123, -17, 109, 59, 40, -12, -61, 98, -91, 19, -36, 108, 118, -124, -82, -40, -124, -66, 19, 127, -73, -39, 99, 43, -16, -44, -83, -77, -34, 68, -118, -71, -116, 114, 120, -34, -105, -32, -46, 102, 73, -79, 7, 42, 35, -66, 125, 34, 113, 66, 78, 71, 6, 44, -17, 4, -80, 38, -59, 12, -8, -78, 103, 8, 80, 18, -74, 20, 3, 56, -20, 106, -1, -12, 83, 4, 68, -119, 84, -87, 97, -53, 102, 119, 34, -85, 22, -26, 55, -107, 96, -70, 77, -68, -96, -15, -22, -77, -55, 5, 103, -42, -87, 122, -80, -103, -37, -120, -56, -16, -51, -7, -19, -104, 120, 9, 54, -85, 48, -76, -38, 58, -68, 116, -20, -44, 22, -32, 75, -46, -41, 13, -100, 16, -59, -93, -115, 54, 22, -110, -46, -119, 44, -98, -48, 4, -58, -115, -57, 103, -56, 36, -63, 104, -114, -125, 92, 65, 117, -21, -59, -31, 56, -98, -126, 56, 47, -116, 100, 122, -98, 4, 26, -29, -127, -113, 73, 48, 106, 125, -69, -127, 62, 56, -79, 76, 84, -46, -31, -17, 94, -98, 62, 63, 118, -24, 63, 123, -93, -46, 103, 117, -120, -35, 19, 25, 15, -110, -125, 12, -75, -50, 103, 49, 47, 98, 92, 10, -88, 54, -53, 19, 25, -90, 93, -49, 64, 126, -106, -30, -52, 58, 37, 68, -18, -60, 15, -27, 93, -124, 88, 110, -80, -106, 88, 55, 108, -58, -43, -70, 76, 85, 98, 27, -66, 18, 75, 69, 114, 90, -26, -10, -12, -126, 84, -109, 108, 15, -115, 90, 11, -127, 63, -7, 47, 92, -72, 38, -58, -35, 18, 25, 12, -103, 0}; - - fullBytes = new byte[pubBytes.length + privBytes.length]; - - System.arraycopy(pubBytes, 0, fullBytes, 0, pubBytes.length); - System.arraycopy(privBytes, 0, fullBytes, pubBytes.length, privBytes.length); - - priv = new NTRUEncryptionPrivateKeyParameters(fullBytes, params.getEncryptionParameters()); - pub = new NTRUEncryptionPublicKeyParameters(pubBytes, params.getEncryptionParameters()); - kp = new AsymmetricCipherKeyPair(pub, priv); - ntru.init(true, kp.getPublic()); - - encrypted = ntru.processBlock(plainText, 0, plainText.length); - - ntru.init(false, kp.getPrivate()); - - decrypted = ntru.processBlock(encrypted, 0, encrypted.length); - - assertTrue(Arrays.areEqual(plainText, decrypted)); - } - - // encrypts and decrypts text using an encoded key pair (fastFp=true) - public void testEncodedKeysFast() - throws IOException, InvalidCipherTextException - { - byte[] plainText = "secret encrypted text".getBytes(); - - NTRUEncryptionKeyGenerationParameters params = NTRUEncryptionKeyGenerationParameters.APR2011_743_FAST; - NTRUEngine ntru = new NTRUEngine(); - byte[] privBytes = {10, 16, 2, 30, -40, -63, -109, -77, -72, -122, 66, 23, -30, -44, -82, 0, 95, 64, 68, 48, -62, -14, 26, -19, -72, -25, 72, 123, 98, 84, -83, 0, 7, 40, 65, 35, 68, 113, 12, -112, 32, -123, 58, 85, -30, -109, -74, 0, 34, -8, -126, 57, 30, 98, -107, -45, -88, 102, 68, 42, -30, -108, -89, 0, 38, -40, -61, 37, 82, 113, -115, 123, -100, 5, 46, 125, -23, 78, -111, -76, 36, -90, 67, -31, 10, 2, 96, -127, 21, 50, -79, 13, -125, -124, 38, 55, -67, -95, 81, -107, 12, 117, -86, 99, -127, 11}; - byte[] pubBytes = {108, -76, -104, -75, -87, -65, -18, -5, 45, -57, -100, -83, 51, 99, 94, 15, -73, 89, -100, 40, -114, 91, -107, 104, 127, 22, 13, 5, -16, 69, -104, -126, -44, 119, 47, -48, 75, 66, 83, -37, -66, -84, 73, 52, 23, -27, 53, 63, 56, 14, -2, 43, -59, -85, -80, 46, 38, -126, 75, -8, -63, 88, 104, 13, 72, -25, -10, -58, -51, 117, -84, 115, -24, -53, 83, -103, -97, 46, 90, -82, -61, 113, -49, -24, -72, 24, -124, -42, -36, 7, 41, 8, 14, -71, -75, -84, -24, -39, 56, 67, 88, 67, 66, -13, 70, -119, -64, 74, -100, -58, 35, 105, -20, 93, 80, -116, -55, 37, -52, 64, 0, -36, -71, 8, 77, -10, -41, -22, -73, 4, -115, -74, -74, -73, 23, -10, -26, 48, 125, -114, -32, -116, 74, 19, -104, 59, 43, 4, 97, -84, 112, 45, 16, 3, -110, -13, 119, -6, 29, -80, 109, 82, -31, 82, 30, 76, -111, -122, -50, -69, -41, -123, 107, 78, -35, 24, -121, -87, -108, 13, 70, 32, -74, 112, 104, -40, -61, 86, -125, 60, -94, -5, -18, 55, 54, -128, 83, -88, 71, 71, -66, 29, -113, 120, 30, 16, -38, 37, 96, -90, 38, -85, 88, 59, 15, -69, 6, -8, 1, 1, 71, 12, 60, -26, -110, 97, 77, 33, 58, 63, 104, 108, 83, 72, -21, -99, 115, -125, -16, 12, 99, 68, 39, -97, -6, 17, 26, -59, 123, -110, -37, -71, 47, 50, 5, 110, -34, 89, -74, 20, 79, -108, -7, 42, 106, -112, 44, 107, 106, -50, 55, 127, -124, 53, 123, -119, -46, -114, -52, -85, 75, 34, -39, -125, 58, -5, -31, -81, -37, -94, -123, 113, 11, -104, -124, 96, -103, 9, 108, 115, 97, -6, 98, -43, 26, -89, -23, 83, 60, 34, -86, -54, 107, 78, -48, 118, -31, -19, 29, -106, 108, 117, 83, 119, 51, -45, 115, 108, -13, -89, -29, 29, -120, 108, 20, 22, -3, 22, 78, -109, 95, 3, -68, -10, -53, -117, -96, -49, 9, 7, 38, 116, 33, -65, 31, 9, -5, -73, 127, 52, 113, 87, -39, 119, -96, 74, -105, 75, -89, 63, 69, -109, -127, 92, -54, 17, -98, -23, -69, 123, -125, 23, -93, 44, -11, -25, -101, 120, -29, 113, -33, 0, -117, -100, -114, 22, 41, -46, 29, -109, 107, 37, -94, 125, 46, 17, 16, -65, -14, 105, -118, 51, -21, 121, -5, 56, 29, 30, -69, -38, -10, -77, -74, 6, -105, 83, 110, 23, 114, -11, -123, -14, 30, -11, -9, 84, -90, -20, -29, 72, -85, 97, -74, -59, -112, -15, -51, -105, 117, 123, -17, -64, -127, 127, -33, -102, 88, 77, 122, -127, -15, 121, -125, -32, 53, 113, 45, -22, 84, -87, 20, 36, 65, 83, -84, -66, -22, 4, 15, -108, -92, 109, -128, -48, 4, -27, -13, 25, 51, -10, 34, 87, 88, 38, -87, 89, -64, -62, 20, 78, 35, -26, -2, 55, 3, -72, -64, 30, 28, -105, 6, -37, -38, -8, 26, -118, 105, -37, -30, 85, -66, 105, -46, -37, -11, -72, 71, 43, -65, -44, 17, -79, 98, 79, -77, -111, 95, 74, 101, -40, -106, 14, -108, -112, 86, 108, 49, 72, -38, -103, -31, 65, -119, 8, 78, -89, 100, -28, 116, 94, 15, -18, 108, 101, 85, 8, -6, 111, -82, -49, -66, -89, 28, -84, -85, -119, 111, 45, 83, -60, -40, -45, -101, -105, -35, 123, -1, 13, -112, 79, -80, -85, -109, -71, 69, 104, 95, -93, 121, -17, 83, 117, -73, -63, -65, -107, -72, 118, -102, -56, 38, 79, 121, -25, -86, -81, -38, 8, 122, 97, 37, 82, -40, 53, 11, 124, -94, -76, -107, -125, -9, -119, 63, 52, -34, -72, -21, 59, 3, -100, -127, 47, -102, 19, -37, -45, -114, -65, 39, -106, 6, -127, -110, -38, 96, -38, -51, 110, -3, 28, 8, 102, -102, 96, -127, 109, -56, -53, -13, 59, -98, 92, 80, 1, 55, -91, -122, -105, 28, 69, -85, 109, -38, 105, 87, -5, 3, -102, 62, -92, 60, 43, -20, -7, -23, -84, 106, 121, -48, 123, -112, 56, -17, -52, 14, -123, -122, 64, 14, -23, -71, 60, 70, -121, 6, 37, -15, 77, 96, 104, -34, 58, -125, -61, 1, -26, 118, -78, -35, -1, 0, 5, 33, -98, -86, -127, 25, 56, -91, 82, -33, 60, -64, -86, 27, 31, -80, -79, 118, -12, -18, 40, -72, 32, 119, -28, -62, 100, -121, -71, -79, -9, 38, -37, 25, 65, -46, 8, -112, 37, 9, -56, 123, -40, -44, -90, -21, -54, -2, -7, 107, -93, 24, -126, 69, 42, -111, -84, 57, 69, -119, 21, 60, 57, -122, 111, -99, 49, -46, -119, 100, 98, 24, -62, 112, 122, 46, 18, -35, -67, 89, 104, 82, 12, 125, 57, -70, -112, -109, 96, 51, -68, 1, -101, -59, -92, 54, 85, -41, 17, 31, 94, 75, -128, 53, 84, 0, -83, -94, -123, 49, -30, -24, 18, 46, 48, -33, 120, 66, -69, 70, 23, -124, -117, 81, 96, 46, 47, -33, 83, -13, -14, -94, 49, 66, -46, 84, -27, -77, 6, 0, -75, -18, 86, -119, -88, 82, -50, 55, -20, 63, 55, -57, 22, -108, -103, -17, -22, 64, 65, 90, -34, -96, -117, 51, 119, -103, -35, 95, -15, -118, 2, -31, 31, -9, -58, 84, -75, 80, 39, -101, -56, 16, -75, 59, 48, -63, -24, -95, 119, 73, -110, -115, 49, -18, 54, -124, 112, -61, -40, -105, -118, -66, 15, -107, 75, 82, -70, -87, -11, -11, 48, 41, 119, -42, -34, -33, 57, 23, -14, -45, -125, -108, -75, 3, 44, 44, 58, 126, -126, -20, -123, 58, 114, 79, -102, -115, 115, 12, 66, 108, 84, 43, -46, -80, -41, -70, 111, -114, 123, 21, 1, 34, -72, 23, 105, -52, -39, -54, -119, 45, 77, -16, -66, -105, -11, 91, -46, 77, -104, -93, 52, -3, 17, 55, -10, 67, -33, 43, 75, -103, 106, 7, -35, -65, -21, 68, 118, -38, 59, -115, 31}; - - byte[] fullBytes = new byte[pubBytes.length + privBytes.length]; - - System.arraycopy(pubBytes, 0, fullBytes, 0, pubBytes.length); - System.arraycopy(privBytes, 0, fullBytes, pubBytes.length, privBytes.length); - - NTRUEncryptionPrivateKeyParameters priv = new NTRUEncryptionPrivateKeyParameters(fullBytes, params.getEncryptionParameters()); - NTRUEncryptionPublicKeyParameters pub = new NTRUEncryptionPublicKeyParameters(pubBytes, params.getEncryptionParameters()); - AsymmetricCipherKeyPair kp = new AsymmetricCipherKeyPair(pub, priv); - - ntru.init(true, kp.getPublic()); - - byte[] encrypted = ntru.processBlock(plainText, 0, plainText.length); - - assertEquals(encrypted.length, ntru.getOutputBlockSize()); - - ntru.init(false, kp.getPrivate()); - - byte[] decrypted = ntru.processBlock(encrypted, 0, encrypted.length); - - assertTrue(Arrays.areEqual(plainText, decrypted)); - } - - private static class VisibleNTRUEngine - extends NTRUEngine - { - public IntegerPolynomial encrypt(IntegerPolynomial m, TernaryPolynomial r, IntegerPolynomial pubKey) - { - return super.encrypt(m, r, pubKey); - } - - public IntegerPolynomial decrypt(IntegerPolynomial e, Polynomial priv_t, IntegerPolynomial priv_fp) - { - return super.decrypt(e, priv_t, priv_fp); - } - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUEncryptionParametersTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUEncryptionParametersTest.java deleted file mode 100644 index e3acc517c6..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUEncryptionParametersTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -import junit.framework.TestCase; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUEncryptionKeyGenerationParameters; - -public class NTRUEncryptionParametersTest - extends TestCase -{ - public void testLoadSave() - throws IOException - { - NTRUEncryptionKeyGenerationParameters params = NTRUEncryptionKeyGenerationParameters.EES1499EP1; - ByteArrayOutputStream os = new ByteArrayOutputStream(); - params.writeTo(os); - ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); - assertEquals(params, new NTRUEncryptionKeyGenerationParameters(is)); - } - - public void testEqualsHashCode() - throws IOException - { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - NTRUEncryptionKeyGenerationParameters.EES1499EP1.writeTo(os); - ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); - NTRUEncryptionKeyGenerationParameters params = new NTRUEncryptionKeyGenerationParameters(is); - - assertEquals(params, NTRUEncryptionKeyGenerationParameters.EES1499EP1); - assertEquals(params.hashCode(), NTRUEncryptionKeyGenerationParameters.EES1499EP1.hashCode()); - - params.N += 1; - assertFalse(params.equals(NTRUEncryptionKeyGenerationParameters.EES1499EP1)); - assertFalse(NTRUEncryptionKeyGenerationParameters.EES1499EP1.equals(params)); - assertFalse(params.hashCode() == NTRUEncryptionKeyGenerationParameters.EES1499EP1.hashCode()); - } - - public void testClone() - { - NTRUEncryptionKeyGenerationParameters params = NTRUEncryptionKeyGenerationParameters.APR2011_439; - assertEquals(params, params.clone()); - - params = NTRUEncryptionKeyGenerationParameters.APR2011_439_FAST; - assertEquals(params, params.clone()); - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUSignatureKeyTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUSignatureKeyTest.java deleted file mode 100644 index cf5865a8a6..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUSignatureKeyTest.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -import junit.framework.TestCase; -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUSigner; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUSigningKeyGenerationParameters; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUSigningKeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUSigningPrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUSigningPublicKeyParameters; - -public class NTRUSignatureKeyTest - extends TestCase -{ - public void testEncode() - throws IOException - { - for (NTRUSigningKeyGenerationParameters params : new NTRUSigningKeyGenerationParameters[]{NTRUSigningKeyGenerationParameters.TEST157, NTRUSigningKeyGenerationParameters.TEST157_PROD}) - { - testEncode(params); - } - } - - private void testEncode(NTRUSigningKeyGenerationParameters params) - throws IOException - { - NTRUSigner ntru = new NTRUSigner(params.getSigningParameters()); - NTRUSigningKeyPairGenerator kGen = new NTRUSigningKeyPairGenerator(); - - kGen.init(params); - - AsymmetricCipherKeyPair kp = kGen.generateKeyPair(); - - NTRUSigningPrivateKeyParameters kPriv = (NTRUSigningPrivateKeyParameters)kp.getPrivate(); - NTRUSigningPublicKeyParameters kPub = (NTRUSigningPublicKeyParameters)kp.getPublic(); - - // encode to byte[] and reconstruct - byte[] priv = kPriv.getEncoded(); - byte[] pub = kPub.getEncoded(); - AsymmetricCipherKeyPair kp2 = new AsymmetricCipherKeyPair(new NTRUSigningPublicKeyParameters(pub, params.getSigningParameters()), new NTRUSigningPrivateKeyParameters(priv, params)); - assertEquals(kPub, kp2.getPublic()); - assertEquals(kPriv, kp2.getPrivate()); - - // encode to OutputStream and reconstruct - ByteArrayOutputStream bos1 = new ByteArrayOutputStream(); - ByteArrayOutputStream bos2 = new ByteArrayOutputStream(); - kPriv.writeTo(bos1); - kPub.writeTo(bos2); - ByteArrayInputStream bis1 = new ByteArrayInputStream(bos1.toByteArray()); - ByteArrayInputStream bis2 = new ByteArrayInputStream(bos2.toByteArray()); - AsymmetricCipherKeyPair kp3 = new AsymmetricCipherKeyPair(new NTRUSigningPublicKeyParameters(bis2, params.getSigningParameters()), new NTRUSigningPrivateKeyParameters(bis1, params)); - assertEquals(kPub, kp3.getPublic()); - assertEquals(kPriv, kp3.getPrivate()); - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUSignatureParametersTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUSignatureParametersTest.java deleted file mode 100644 index 28c8cbd596..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUSignatureParametersTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -import junit.framework.TestCase; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUSigningKeyGenerationParameters; - -public class NTRUSignatureParametersTest - extends TestCase -{ - public void testLoadSave() - throws IOException - { - for (NTRUSigningKeyGenerationParameters params : new NTRUSigningKeyGenerationParameters[]{NTRUSigningKeyGenerationParameters.TEST157, NTRUSigningKeyGenerationParameters.TEST157_PROD, NTRUSigningKeyGenerationParameters.APR2011_743, NTRUSigningKeyGenerationParameters.APR2011_743_PROD}) - { - testLoadSave(params); - } - } - - private void testLoadSave(NTRUSigningKeyGenerationParameters params) - throws IOException - { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - params.writeTo(os); - ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); - assertEquals(params, new NTRUSigningKeyGenerationParameters(is)); - } - - public void testEqualsHashCode() - throws IOException - { - for (NTRUSigningKeyGenerationParameters params : new NTRUSigningKeyGenerationParameters[]{NTRUSigningKeyGenerationParameters.TEST157, NTRUSigningKeyGenerationParameters.TEST157_PROD, NTRUSigningKeyGenerationParameters.APR2011_743, NTRUSigningKeyGenerationParameters.APR2011_743_PROD}) - { - testEqualsHashCode(params); - } - } - - private void testEqualsHashCode(NTRUSigningKeyGenerationParameters params) - throws IOException - { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - params.writeTo(os); - ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); - NTRUSigningKeyGenerationParameters params2 = new NTRUSigningKeyGenerationParameters(is); - - assertEquals(params, params2); - assertEquals(params.hashCode(), params2.hashCode()); - - params.N += 1; - assertFalse(params.equals(params2)); - assertFalse(params.equals(params2)); - assertFalse(params.hashCode() == params2.hashCode()); - } - - public void testClone() - { - for (NTRUSigningKeyGenerationParameters params : new NTRUSigningKeyGenerationParameters[]{NTRUSigningKeyGenerationParameters.TEST157, NTRUSigningKeyGenerationParameters.TEST157_PROD, NTRUSigningKeyGenerationParameters.APR2011_743, NTRUSigningKeyGenerationParameters.APR2011_743_PROD}) - { - assertEquals(params, params.clone()); - } - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUSignerTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUSignerTest.java deleted file mode 100644 index f298914517..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUSignerTest.java +++ /dev/null @@ -1,317 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - - -import junit.framework.TestCase; - -/** - * @deprecated algorithm no longer safe. - */ -public class NTRUSignerTest - extends TestCase -{ - public void testStub() - { - - } - /* - public void testCreateBasis() - { - for (NTRUSigningKeyGenerationParameters params : new NTRUSigningKeyGenerationParameters[]{NTRUSigningKeyGenerationParameters.TEST157.clone(), NTRUSigningKeyGenerationParameters.TEST157_PROD.clone()}) - { - testCreateBasis(params); - } - } - - private void testCreateBasis(NTRUSigningKeyGenerationParameters params) - { - NTRUSigningKeyPairGenerator ntru = new NTRUSigningKeyPairGenerator(); - - ntru.init(params); - - NTRUSigningKeyPairGenerator.FGBasis basis = (NTRUSigningKeyPairGenerator.FGBasis)ntru.generateBoundedBasis(); - assertTrue(equalsQ(basis.f, basis.fPrime, basis.F, basis.G, params.q, params.N)); - - // test KeyGenAlg.FLOAT (default=RESULTANT) - params.keyGenAlg = NTRUSigningKeyGenerationParameters.KEY_GEN_ALG_FLOAT; - ntru.init(params); - basis = (NTRUSigningKeyPairGenerator.FGBasis)ntru.generateBoundedBasis(); - assertTrue(equalsQ(basis.f, basis.fPrime, basis.F, basis.G, params.q, params.N)); - } - - // verifies that f*G-g*F=q - private boolean equalsQ(Polynomial f, Polynomial g, IntegerPolynomial F, IntegerPolynomial G, int q, int N) - { - IntegerPolynomial x = f.mult(G); - x.sub(g.mult(F)); - boolean equalsQ = true; - for (int i = 1; i < x.coeffs.length; i++) - { - equalsQ &= x.coeffs[i] == 0; - } - equalsQ &= x.coeffs[0] == q; - return equalsQ; - } - - /** - * a test for the one-method-call variants: sign(byte, SignatureKeyPair) and verify(byte[], byte[], SignatureKeyPair) - * - public void testSignVerify157() - throws IOException - { - for (NTRUSigningKeyGenerationParameters params : new NTRUSigningKeyGenerationParameters[]{NTRUSigningKeyGenerationParameters.TEST157.clone(), NTRUSigningKeyGenerationParameters.TEST157_PROD.clone(), NTRUSigningKeyGenerationParameters.APR2011_439.clone(), NTRUSigningKeyGenerationParameters.APR2011_439_PROD.clone(), NTRUSigningKeyGenerationParameters.APR2011_743.clone(), NTRUSigningKeyGenerationParameters.APR2011_743_PROD.clone()}) - { - testSignVerify(params); - } - } - - public void testSignVerify439() - throws IOException - { - for (NTRUSigningKeyGenerationParameters params : new NTRUSigningKeyGenerationParameters[]{NTRUSigningKeyGenerationParameters.APR2011_439.clone(), NTRUSigningKeyGenerationParameters.APR2011_439_PROD.clone()}) - { - testSignVerify(params); - } - } -// -// public void testSignVerify743() -// throws IOException -// { -// for (NTRUSigningKeyGenerationParameters params : new NTRUSigningKeyGenerationParameters[]{NTRUSigningKeyGenerationParameters.APR2011_743.clone(), NTRUSigningKeyGenerationParameters.APR2011_743_PROD.clone()}) -// { -// testSignVerify(params); -// } -// } - - private void testSignVerify(NTRUSigningKeyGenerationParameters params) - throws IOException - { - NTRUSigner ntru = new NTRUSigner(params.getSigningParameters()); - NTRUSigningKeyPairGenerator kGen = new NTRUSigningKeyPairGenerator(); - - kGen.init(params); - - AsymmetricCipherKeyPair kp = kGen.generateKeyPair(); - - Random rng = new Random(); - byte[] msg = new byte[10 + rng.nextInt(1000)]; - rng.nextBytes(msg); - - // sign and verify - ntru.init(true, kp.getPrivate()); - - ntru.update(msg, 0, msg.length); - - byte[] s = ntru.generateSignature(); - - ntru.init(false, kp.getPublic()); - - ntru.update(msg, 0, msg.length); - - boolean valid = ntru.verifySignature(s); - - assertTrue(valid); - - // altering the signature should make it invalid - s[rng.nextInt(params.N)] += 1; - ntru.init(false, kp.getPublic()); - - ntru.update(msg, 0, msg.length); - - valid = ntru.verifySignature(s); - assertFalse(valid); - - // test that a random signature fails - rng.nextBytes(s); - - ntru.init(false, kp.getPublic()); - - ntru.update(msg, 0, msg.length); - - valid = ntru.verifySignature(s); - assertFalse(valid); - - // encode, decode keypair, test - NTRUSigningPrivateKeyParameters priv = new NTRUSigningPrivateKeyParameters(((NTRUSigningPrivateKeyParameters)kp.getPrivate()).getEncoded(), params); - NTRUSigningPublicKeyParameters pub = new NTRUSigningPublicKeyParameters(((NTRUSigningPublicKeyParameters)kp.getPublic()).getEncoded(), params.getSigningParameters()); - kp = new AsymmetricCipherKeyPair(pub, priv); - - ntru.init(true, kp.getPrivate()); - ntru.update(msg, 0, msg.length); - - s = ntru.generateSignature(); - - ntru.init(false, kp.getPublic()); - ntru.update(msg, 0, msg.length); - - valid = ntru.verifySignature(s); - assertTrue(valid); - - // altering the signature should make it invalid - s[rng.nextInt(s.length)] += 1; - ntru.init(false, kp.getPublic()); - ntru.update(msg, 0, msg.length); - valid = ntru.verifySignature(s); - assertFalse(valid); - - // sparse/dense - params.sparse = !params.sparse; - - ntru.init(true, kp.getPrivate()); - ntru.update(msg, 0, msg.length); - - s = ntru.generateSignature(); - - ntru.init(false, kp.getPublic()); - ntru.update(msg, 0, msg.length); - valid = ntru.verifySignature(s); - assertTrue(valid); - - s[rng.nextInt(s.length)] += 1; - ntru.init(false, kp.getPublic()); - ntru.update(msg, 0, msg.length); - valid = ntru.verifySignature(s); - assertFalse(valid); - params.sparse = !params.sparse; - - // decrease NormBound to force multiple signing attempts - NTRUSigningKeyGenerationParameters params2 = params.clone(); - params2.normBoundSq *= 4.0 / 9; - params2.signFailTolerance = 10000; - ntru = new NTRUSigner(params2.getSigningParameters()); - - ntru.init(true, kp.getPrivate()); - ntru.update(msg, 0, msg.length); - - s = ntru.generateSignature(); - - ntru.init(false, kp.getPublic()); - ntru.update(msg, 0, msg.length); - valid = ntru.verifySignature(s); - - assertTrue(valid); - - // test KeyGenAlg.FLOAT (default=RESULTANT) - params2 = params.clone(); - params.keyGenAlg = NTRUSigningKeyGenerationParameters.KEY_GEN_ALG_FLOAT; - ntru = new NTRUSigner(params.getSigningParameters()); - - kGen.init(params); - - kp = kGen.generateKeyPair(); - ntru.init(true, kp.getPrivate()); - ntru.update(msg, 0, msg.length); - - s = ntru.generateSignature(); - ntru.init(false, kp.getPublic()); - ntru.update(msg, 0, msg.length); - valid = ntru.verifySignature(s); - assertTrue(valid); - s[rng.nextInt(s.length)] += 1; - ntru.init(false, kp.getPublic()); - ntru.update(msg, 0, msg.length); - valid = ntru.verifySignature(s); - assertFalse(valid); - } - - /** - * test for the initSign/update/sign and initVerify/update/verify variant - * - public void testInitUpdateSign() - { - for (NTRUSigningKeyGenerationParameters params : new NTRUSigningKeyGenerationParameters[]{NTRUSigningKeyGenerationParameters.TEST157.clone(), NTRUSigningKeyGenerationParameters.TEST157_PROD.clone()}) - { - testInitUpdateSign(params); - } - } - - private void testInitUpdateSign(NTRUSigningKeyGenerationParameters params) - { - NTRUSigner ntru = new NTRUSigner(params.getSigningParameters()); - NTRUSigningKeyPairGenerator kGen = new NTRUSigningKeyPairGenerator(); - - kGen.init(params); - - AsymmetricCipherKeyPair kp = kGen.generateKeyPair(); - - Random rng = new Random(); - byte[] msg = new byte[10 + rng.nextInt(1000)]; - rng.nextBytes(msg); - - // sign and verify a message in two pieces each - ntru.init(true, kp.getPrivate()); - int splitIdx = rng.nextInt(msg.length); - ntru.update(msg[0]); // first byte - ntru.update(msg, 1, splitIdx - 1); // part 1 of msg - ntru.update(msg, splitIdx, msg.length - splitIdx); - byte[] s = ntru.generateSignature(); // part 2 of msg - ntru.init(false, kp.getPublic()); - splitIdx = rng.nextInt(msg.length); - ntru.update(msg, 0, splitIdx); // part 1 of msg - ntru.update(msg, splitIdx, msg.length - splitIdx); // part 2 of msg - boolean valid = ntru.verifySignature(s); - assertTrue(valid); - // verify the same signature with the one-step method - ntru.init(false, (NTRUSigningPublicKeyParameters)kp.getPublic()); - ntru.update(msg, 0, msg.length); // part 1 of msg - valid = ntru.verifySignature(s); - assertTrue(valid); - - // sign using the one-step method and verify using the multi-step method - ntru.init(true, kp.getPrivate()); - ntru.update(msg, 0, msg.length); - s = ntru.generateSignature(); - ntru.init(false, (NTRUSigningPublicKeyParameters)kp.getPublic()); - splitIdx = rng.nextInt(msg.length); - ntru.update(msg, 0, splitIdx); // part 1 of msg - ntru.update(msg, splitIdx, msg.length - splitIdx); // part 2 of msg - valid = ntru.verifySignature(s); - assertTrue(valid); - } - - public void testCreateMsgRep() - { - for (NTRUSigningKeyGenerationParameters params : new NTRUSigningKeyGenerationParameters[]{NTRUSigningKeyGenerationParameters.TEST157.clone(), NTRUSigningKeyGenerationParameters.TEST157_PROD.clone()}) - { - testCreateMsgRep(params); - } - } - - private void testCreateMsgRep(NTRUSigningKeyGenerationParameters params) - { - VisibleNTRUSigner ntru = new VisibleNTRUSigner(params.getSigningParameters()); - byte[] msgHash = "adfsadfsdfs23234234".getBytes(); - - // verify that the message representative is reproducible - IntegerPolynomial i1 = ntru.createMsgRep(msgHash, 1); - IntegerPolynomial i2 = ntru.createMsgRep(msgHash, 1); - assertTrue(Arrays.areEqual(i1.coeffs, i2.coeffs)); - i1 = ntru.createMsgRep(msgHash, 5); - i2 = ntru.createMsgRep(msgHash, 5); - assertTrue(Arrays.areEqual(i1.coeffs, i2.coeffs)); - - i1 = ntru.createMsgRep(msgHash, 2); - i2 = ntru.createMsgRep(msgHash, 3); - assertFalse(Arrays.areEqual(i1.coeffs, i2.coeffs)); - } - - private class VisibleNTRUSigner - extends NTRUSigner - { - - /** - * Constructs a new instance with a set of signature parameters. - * - * @param params signature parameters - * - public VisibleNTRUSigner(NTRUSigningParameters params) - { - super(params); - } - - public IntegerPolynomial createMsgRep(byte[] hash, int i) - { - return super.createMsgRep(hash, i); - } - } - */ -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUSigningParametersTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUSigningParametersTest.java deleted file mode 100644 index 194efa7d3d..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/NTRUSigningParametersTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -import junit.framework.TestCase; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUSigningKeyGenerationParameters; - -public class NTRUSigningParametersTest - extends TestCase -{ - - public void testLoadSave() - throws IOException - { - for (NTRUSigningKeyGenerationParameters params : new NTRUSigningKeyGenerationParameters[]{NTRUSigningKeyGenerationParameters.TEST157, NTRUSigningKeyGenerationParameters.TEST157_PROD}) - { - testLoadSave(params); - } - } - - private void testLoadSave(NTRUSigningKeyGenerationParameters params) - throws IOException - { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - params.writeTo(os); - ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); - assertEquals(params, new NTRUSigningKeyGenerationParameters(is)); - } - - public void testEqualsHashCode() - throws IOException - { - for (NTRUSigningKeyGenerationParameters params : new NTRUSigningKeyGenerationParameters[]{NTRUSigningKeyGenerationParameters.TEST157, NTRUSigningKeyGenerationParameters.TEST157_PROD}) - { - testEqualsHashCode(params); - } - } - - private void testEqualsHashCode(NTRUSigningKeyGenerationParameters params) - throws IOException - { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - params.writeTo(os); - ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); - NTRUSigningKeyGenerationParameters params2 = new NTRUSigningKeyGenerationParameters(is); - - assertEquals(params, params2); - assertEquals(params.hashCode(), params2.hashCode()); - - params.N += 1; - assertFalse(params.equals(params2)); - assertFalse(params.equals(params2)); - assertFalse(params.hashCode() == params2.hashCode()); - } - - public void testClone() - { - for (NTRUSigningKeyGenerationParameters params : new NTRUSigningKeyGenerationParameters[]{NTRUSigningKeyGenerationParameters.TEST157, NTRUSigningKeyGenerationParameters.TEST157_PROD}) - { - assertEquals(params, params.clone()); - } - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/QTESLASecureRandomFactory.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/QTESLASecureRandomFactory.java deleted file mode 100644 index 02db7b3ca6..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/QTESLASecureRandomFactory.java +++ /dev/null @@ -1,193 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import org.bouncycastle.crypto.BufferedBlockCipher; -import org.bouncycastle.crypto.DefaultBufferedBlockCipher; -import org.bouncycastle.crypto.engines.AESEngine; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.util.test.FixedSecureRandom; - -/** - * Factory for producing FixedSecureRandom objects for use with testsing - */ -class QTESLASecureRandomFactory -{ - private byte[] seed; - private byte[] personalization; - private byte[] key; - private byte[] v; - int reseed_counuter = 1; - - - /** - * Return a seeded FixedSecureRandom representing the result of processing a - * qTESLA test seed with the qTESLA RandomNumberGenerator. - * - * @param seed original qTESLA seed - * @param strength bit-strength of the RNG required. - * @return a FixedSecureRandom containing the correct amount of seed material for use with Java. - */ - public static FixedSecureRandom getFixed(byte[] seed, int strength) - { - return getFixed(seed,null, strength, strength / 8, strength / 8); - } - - public static FixedSecureRandom getFixed(byte[] seed, byte[] personalization, int strength, int discard, int size) - { - QTESLASecureRandomFactory teslaRNG = new QTESLASecureRandomFactory(seed, personalization); - teslaRNG.init(strength); - byte[] burn = new byte[discard]; - teslaRNG.nextBytes(burn); - if (discard != size) - { - burn = new byte[size]; - } - teslaRNG.nextBytes(burn); - return new FixedSecureRandom(burn); - } - - - public static FixedSecureRandom getFixedNoDiscard(byte[] seed, int strength) - { - QTESLASecureRandomFactory teslaRNG = new QTESLASecureRandomFactory(seed, null); - teslaRNG.init(strength); - byte[] burn = new byte[strength / 8]; - teslaRNG.nextBytes(burn); - return new FixedSecureRandom(burn); - } - - private QTESLASecureRandomFactory(byte[] seed, byte[] personalization) - { - this.seed = seed; - this.personalization = personalization; - } - - - private void init(int strength) - { - randombytes_init(seed, personalization, strength); - reseed_counuter = 1; - } - - private void nextBytes(byte[] x) - { - byte[] block = new byte[16]; - int i = 0; - - int xlen = x.length; - - while (xlen > 0) - { - for (int j = 15; j >= 0; j--) - { - if ((v[j] & 0xFF) == 0xff) - { - v[j] = 0x00; - } - else - { - v[j]++; - break; - } - } - - AES256_ECB(key, v, block, 0); - - if (xlen > 15) - { - System.arraycopy(block, 0, x, i, block.length); - i += 16; - xlen -= 16; - } - else - { - System.arraycopy(block, 0, x, i, xlen); - xlen = 0; - } - } - - AES256_CTR_DRBG_Update(null, key, v); - reseed_counuter++; - } - - - private void AES256_ECB(byte[] key, byte[] ctr, byte[] buffer, int startPosition) - { - try - { - BufferedBlockCipher bufferedBlockCipher = new DefaultBufferedBlockCipher(AESEngine.newInstance()); - - bufferedBlockCipher.init(true, new KeyParameter(key)); - - int len = bufferedBlockCipher.processBytes(ctr, 0, ctr.length, buffer, startPosition); - - bufferedBlockCipher.doFinal(buffer, len); - } - catch (Throwable ex) - { - ex.printStackTrace(); - } - } - - - private void AES256_CTR_DRBG_Update(byte[] entropy_input, byte[] key, byte[] v) - { - - byte[] tmp = new byte[48]; - - for (int i = 0; i < 3; i++) - { - //increment V - for (int j = 15; j >= 0; j--) - { - if ((v[j] & 0xFF) == 0xff) - { - v[j] = 0x00; - } - else - { - v[j]++; - break; - } - } - - AES256_ECB(key, v, tmp, 16 * i); - } - - if (entropy_input != null) - { - for (int i = 0; i < 48; i++) - { - tmp[i] ^= entropy_input[i]; - } - } - - System.arraycopy(tmp, 0, key, 0, key.length); - System.arraycopy(tmp, 32, v, 0, v.length); - - - } - - - private void randombytes_init(byte[] entropyInput, byte[] personalization, int strength) - { - byte[] seedMaterial = new byte[48]; - - System.arraycopy(entropyInput, 0, seedMaterial, 0, seedMaterial.length); - if (personalization != null) - { - for (int i = 0; i < 48; i++) - { - seedMaterial[i] ^= personalization[i]; - } - } - - key = new byte[32]; - v = new byte[16]; - - - AES256_CTR_DRBG_Update(seedMaterial, key, v); - - reseed_counuter = 1; - - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/QTESLATest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/QTESLATest.java deleted file mode 100644 index 17ba694816..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/QTESLATest.java +++ /dev/null @@ -1,471 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import junit.framework.TestCase; -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.legacy.crypto.qtesla.QTESLAKeyGenerationParameters; -import org.bouncycastle.pqc.legacy.crypto.qtesla.QTESLAKeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.qtesla.QTESLAPrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.qtesla.QTESLAPublicKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.qtesla.QTESLASecurityCategory; -import org.bouncycastle.pqc.legacy.crypto.qtesla.QTESLASigner; -import org.bouncycastle.test.TestResourceFinder; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Integers; -import org.bouncycastle.util.encoders.Hex; - -public class QTESLATest - extends TestCase -{ - static SecureRandom secureRandom = new SecureRandom(); - - private static String asString(Map values, String key) - { - if (values.containsKey(key)) - { - return (String)values.get(key); - } - return null; - } - - private static Integer asInt(Map values, String key, int def) - throws Exception - { - String value = asString(values, key); - if (value != null) - { - return Integers.valueOf(Integer.parseInt(value)); - } - return Integers.valueOf(def); - } - - private static byte[] asByteArray(Map values, String key) - { - String value = asString(values, key); - if (value != null) - { - return Hex.decode(value); - } - return null; - } - - - private void doTestKAT(int securityCategory, byte[] pubKey, byte[] privKey, byte[] seed, byte[] msg, byte[] expected) - { - // - // Validate Key Generation. - // - // Invoke the key generator with the Fixed Random that uses the seed from the vector. - // This ensures we can generate the same keys as the vector. - // USE A REAL RANDOM NUMBER GENERATOR IN PRODUCTION. - // - QTESLAKeyGenerationParameters keyGenerationParameters = new QTESLAKeyGenerationParameters(securityCategory, QTESLASecureRandomFactory.getFixedNoDiscard(seed, 256)); - QTESLAKeyPairGenerator keyGen = new QTESLAKeyPairGenerator(); - keyGen.init(keyGenerationParameters); - AsymmetricCipherKeyPair acp = keyGen.generateKeyPair(); - - // - // Test generated keys from seed match supplied keys in vector. - // - assertTrue(Arrays.areEqual(pubKey, ((QTESLAPublicKeyParameters)acp.getPublic()).getPublicData())); - assertTrue(Arrays.areEqual(privKey, ((QTESLAPrivateKeyParameters)acp.getPrivate()).getSecret())); - - // - // Set up for sign / verify testing. - // - QTESLAPublicKeyParameters qPub = new QTESLAPublicKeyParameters(securityCategory, pubKey); - QTESLAPrivateKeyParameters qPriv = new QTESLAPrivateKeyParameters(securityCategory, privKey); - - // For signing.. - QTESLASigner signer = new QTESLASigner(); - signer.init(true, new ParametersWithRandom(qPriv, QTESLASecureRandomFactory.getFixed(seed, 256))); - byte[] sig = signer.generateSignature(msg); - - - // - // Verify signature matches vector, NB signatures in the vector are [sig][msg] hence the concatenation. - // - assertTrue(Arrays.areEqual(expected, Arrays.concatenate(sig, msg))); - - // - // Set up for verification. - // - signer = new QTESLASigner(); - signer.init(false, qPub); - - // Verify verification. - assertTrue(signer.verifySignature(msg, sig)); - - - // - // Damage signature, expect failure. - // - { - byte[] damagedSig = Arrays.copyOf(sig, sig.length); - damagedSig[0] ^= 1; - assertFalse(signer.verifySignature(msg, damagedSig)); - } - - // - // Damage Message, expect failure. - // - { - byte[] damagedMsg = Arrays.copyOf(msg, msg.length); - damagedMsg[0] ^= 1; - assertFalse(signer.verifySignature(damagedMsg, sig)); - } - } - - public void testSignQ1p() - throws Exception - { - byte[] seed = Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"); - byte[] publicKey = Hex.decode("7561DAADC32E5C51E5C7AB83FB32FAA58E32A0D1E5134A07BBBC3AE889C85470D024D22EE8A269A9772C24B5971CEC2AD55A846C6D8DD917B76223B0799227F89FE8EB91020CA49BD528FF1915ED00D9F9709740A13110864F11C24CF0DD8DEA29BF288DCFE4B1CEB12A7135C5142D7F51376456892BEDF33A295D6D70AD058C51D565E8097D26440D57DDA86AD04C1E7ED45946654ADFE9F46A2D2CA0BEA6B2E57046D734A3989BD6B2C42B9413646C1A2F1B6C3E55502D8780681D1553601130BF98D26EA05C216E7C98FF0D5FC03D10384DC6E29316921F50AD19FF96772F998DA91AFC45CB3A00E67BAA713E2825C6DC2A0C0E8778444870A0483E588EDEC82199DA34B636966A85D9001C446C425415C8F8269697EAD5D69DBA92F77228808FE2AC5485612B0F28862D9EDA5D32D5CDD840BD45649C1D7C50044CC017D87E8D1012FE2EA0E26F2710467A13230C73F485F26154825038BEE477CE3154C36468B22124038C3C0A8E41C8681B20BFA3493CF88299E70D0D3FBCB5CF7EB82D39656A27FDA96E62CC84FE9A83DA858A9982F01803872833C48376E04C4E319744EA26EFD8FD4A1834B5058986DEF96CD22F4A30652A543D640C424AD107B54EC7D5E9244328BCBD166100969A54B003DB5F1D30B7D8462941A5C2E6E166563C1D7C7222D167E2627C98EB0F4274FB098C1BB288C8A12180E0A2F32596B54E3E68520B625B87B47F5E2FF64A1490CEC86E82E5E94359FDF6782E2138229D2C1EFF49B6BB6A722D033FF80BBA7A2CBC90D40E39E2E6777E062F4603BF87C407E2C20DD67E67DA5FB1AF696A05CB301B78A91A54F0881D5459E35E4070E0FA605C43E98C472C76DF9C31AAC8A7473DE2B989F297B230B751B4F32B61CF089F77317285D302011D7D6BABCF4C07C0C70AD4DE3E99C46EF595EA9A61A080DD48C74A0C961513C845DB6A5811750145D081B4D4E76DE5B15DBA5C1626289345049D5CB8771C7C129DA1C5DD8BEE596321647E853BCF8D661D194A1023845F420066244F6BB5A0D50533579AA0DB5A726DAB32EA2B35261AE5B6D0DEB12C31A79242E2D952AA1A1774CB90AE815BE9613A93B30AF30374F5C8181F54B4F5D56E07232F68C6D52B94BA64ED1B2B7CA37EE6C730E03816689853224242F0297A017DCE955C8B8D1B41BB3B12665759584D3373BC2C77999205ED56F6E8B6AAEC3346D1528C2AE938CE21C24400ECBC4BB520958E3303374C68A21D403A6E6F05DAB6A8C03FF07FF5B83A216B2EBBF8E357BCE51A52A56EAAF6B6F6D34B8BCE02E22BB67CAC6629A8E8C3F9F4E7A3AEE3B9AED01B2E3BCB3FE566E3DFFD8C4A9830AEF3D30DE63B5208A32433A4C42633C4840EC5493E891D22F409E35F02CFAE46A9D3DEED6C221916F9B27BD7EE3C1CC3C961E59B3DB42A59213FFB168DD170393832ACA8C79B52C194571681F0E8AAE2DB99C1201632659AE136E3B085985DC94981A5503D950E041763AD485E253DD8B329283929E2132EFA6B9EB08E79AF6027D6E2E7E30E3D6B785256BA2E012D003AB5C07FC4A0EAB484991B3CBC3B03346409491A876C82548E2BB253E344E80415E4625D3BF15975B59DC36FA00A7FD894D363172DB8C2ABE40364F549A00C5D5FA8B534E0CAE6A9AE83CB5E4BE6BAEE126B755C9CB8F76C1C8A6E6FE2567C1CBDA68370D4D8465D8B360880601206CAC0C9D0B67C0261A0E7D132CE9C4EBE21250F7F197480FD5E0D8DA83068EFA8B35475733FAB080BB888E1D1D89D124AEFD81BAB3D970FE059674B6E71455517B9BA322A236D272144963DA4A934A1D59D19F05FEECDF0F1E390376801E0454971E30C47109944BB4DF414E19326B8BA2013D5F6B3FA20188E5E9BCC63ED8BC55D8D7D3A086193F9E80DD32381B26BD534D34F298DC06378EDBA2E614E8C3D886297AD1B2B59FF78B8FEC0760336C5207082D82ADA01CAE49AE6500AD992B7FC0631491B909F449618E5F82B18995BC926F46BBEEE152AB2706521AEE3574295F26FC01A7AD154673B2D3B500E1043FF51340BAAA70CF8B3A65C65811318AC7B4A32A9519A00ACE331959AED26F86CACCD7A952F9D40E66FC31224AA1BD280F89A6B16F46AC39C5F6D709868F92D0FA519D39827D215D8BA7F2FA6B4DA67D5A791984E7A1BDB04A5A7B024762952121C109AA318FD2CE88EFAD90FFCC17419C2892C916BA7E7C482ACF41E5C386290F1174AE5C5BECC5A0D21E23B40FEAF220CB9A58AF8A5B5910DBE823359150388A4B0046090287B760B3978433317F4C2E1AF2A5BC87EFD2F59931F558ED226CEA7174B9BD4D1BBF6A10CE2C2D827DC4D36B2096B9309D42EA8D45B5AC2B1F7049CCA4078D4751B6B03DB06B8BEF3E119589CA61D7FE308AEF4561C4EE87DEAC2DB94C38C4760916D27E6BB2C169D1C88D35616F8C5EA6EDD4D48D6A5CFF409DD67D5BF704B832C3454A8BD14568B93F760EC179ECDED970C46BE39D5960352D2F5B3959758CA7A10C88E961D474449CCC21394D2099F6110BEE145E7005DA5501C0DFE3DF1094ACF99951A2974808A60108643E9F4177827A3F616009FA67E21F54C363BF8F162F33254D6CFED5E7C0D4AFCF9854620B9632FBE147284C6739F5FB4F211C20B1D9982215C2C4B1C02CFD041F8281E429940E8FCB66C32B694C2611D8D7F50A751D3969C2A3AB1FB2553CF0B26C0478C2988D9008EF4A1777E9F7F16122BDF208A5044BE728E9D928A52F133C1CC462984590D44E00FF7AE1254928A006054D008E780E5D10BA7E11E17E296D43D21F64544AAAF27E6AF9D4C7A381E4CC2873F358B3541454BA2D594602DA71273F50F99201CE60F93E1431D82D5402E8654206DFC651A3E36CA854A9B18E8DF0CE2809FA89BB465C68475020C51A773107D9B367E3C9A82370773A498FABAE4AE84D7685C9329FB226E0F5F6173C5107AF143BA84BB2CD9A9D2CEF930C5F8055A4E71C1CED7538F3D8FD194EDA2C98FFF3005BE8A73D09C7CBC8DDA07F4066BDCBFF23A1838520AEE0A28E69DE30019DA6AF61FE52A6FF10B4A9215F8F9ABBC9FB5081CA33463F891A53DC91E252E90EF4B0D72A35923208CA48C3793347F3D5FD28DE56538586D2C2C6C1FD50C4160D67DF11254BB36CB94B835734F5B831BF12845155B49FBE3B0F44CC5D6782983D9478C6B3A9F30626A797A2CDF8911F5BFA90E611B39B29314C9E4CB7F12A69D6DAA1916667AAC5AEA693B70BD741928014ACCD125137488BEE48BAABB02DA3C6A9604A16BF4D19F1C0D87FAC94840C721EDDF03CD8A841D2EFA5D52BAFB50726B45A476C47E251601B0127C092A4EB8A66A0CB7A2DB5503394AD36D54F37CC6EC73317E38AF9FB62BB758973971EE9E75E6D8AC67A0D44384439E7B11390E983975281A194F8173119905FE8FFD863D55CE7A6AD00683D4FF83263C81A447948DBF3F1EA2CA593B38E6719A8EECF654774599AB25D1EC9741AD3DE4DC23264C9700CDA27C463656E3A53C52B860B3264CD9FC0334D915E03EE74E54D4A2E2D795297FC748075A404A6C0AA6A22671A480AA3468B9FA9DA9A20DFDD8BB9100C8B6804DD6F16AB0C1B938FBEDC2F1A9DF43CC877B0F323042E9B1DFBB8A2BDA8986534D52B7EF06614DA22F63951716C2B04196567698552F3BA2067B2309AF06DB126727E1A82F731B0CC2904470429C1EC94456D1E66A0EA35A2A1C552CD3FA1A99AD3D748D563978800C32F5B6CA195938BA26CF721FFCDD9402EC4E37A9E1198D39516B4892919327592C67ED148672377A53C7AA9BD47D16282D977A40BB7E036A3FD11283DC2BD82EBA452474B827434014D0BF7C5483F28A432D378C6C78E6470F4026C27F531C367A2B950B0DD95114A106C72227CC33779C705B1C8926DFA2F996000535A0BB87BCFF4B9A12D829D04434AA579A11F6D15490A2C9FAF65042DB4CF88BE47368C589629703815FA6A2A1BD4A1447330E00CAE7645B2527FB82E864290C9574FCFD364F1A4FE3419642D24D98A6A33A0FC0E83505FD5151518555F9E03B2D5742630A119B2B32657AD6B2EE8B624508780F98B27E51BEFACBF3A7B920A282EA45358FA4145AA24E7CDCB3432C6F08D92421E2561EF811F1C60D7E51C840EFFD637D940F43D655FD1221F2A41027A71D90F978CB09E2264737053330E47E4C433F9B5AC94DB9B04EF7326410CC60DF7A220E1749A654FF6370D7C8197C808D35C2B6769E7CCD009BCA5835E4FDDA202D6C3DBE324AB97C879DA16184123CEEC3D5FDCC3CC71103E46E711CF8274D29B5CDF074BA889D6B0E51290428E0499022E634439804A488483D3927DDB78C248EBF9A6C9A678F4F482373580CB7FE2DAD993DAD34149F112D735C7E60DBA06BC44F0304551ABC09B9C91D4211FCD6025A865C90159CE3D842405A5143C46BE19DFDC64228A413D4225D7C94697C0F128B4336E9483192F3024014D2E9885447D0762F802087C7654786F76773DADA83CBC7396E5DDA29BEE95E93FD8C67D75C7D258765C7154DC822B925E8684DEB3443F85300C96E59192E8E99D2BCA21CB62713CC5EB23BF156FB3E97DAAA0695D84932FB9C9DB03E0BB13B103190246CD9AAF79C4B9C8916DB4B6BA02F5FA8B87B9E9B8D18DF6650E907E8A02BD67B4C00EBFE4E4C2CDA560D1874D7215CF0009DA57529EA831A8E71C88152849A8C2900134306C0C05A40BCE42A17CE9C025C100277D7F0CB35566BE5AC11B2466A2BB03B8DA8F10B7A30CA26FC4E0A3971E16DA0C5FCA52838361046549A77B9721027DF307AD3DC8B4EB3DC05BE4B0B0FB77482A794305BBE99499F6ADB05519D1D4A12740F91A363602232535458E94C7487DB90E777247864446B5A862164D9761DAAFEAE213440958E0C399B4DCC6C6BCCA44BF33512828B20402EB814384B9ECEC2B0C1316F3C545D4A65F31CC01B9E324F4468ED92896AD4572248E7298520FAAB161203A09D366EA8FB0041E8A79368822C557C67889DA58C63043C0B6E94B36C61CA41E5BB570448894EEE09F4F00A18A0164FE451B4D005AD5B9A1E3013C356652479D340594223238E068D9DC8C838902D72D97D35EA16E9B7A1852EF464E22D6CB4217BED00F1998134CC09098453C34CB9C0EA8ADD432E295A4B8DE30BDE1AB413F515153A75D02CE99B2EC8E45B3FBC1682973B769D688C8F6FA1AEBEE1795D1B9563AD1D462BAF1668D0426C457382E0EDA9A898FE694D319CCFFB53F378EBDF3AC7BBCDA8CB319470FDA31A1E4E920237A31A7F31392F54BD8991A0A98C65E8DCD9A9666B4403CF1C47B76D30391610161253A9057D23712ED9C71816D1C4B32A390AB6B4DE8F6D6032B8967B30471E80E2FF925DCA64887EA29FD14051BE7856B65B954A37F9577384245272B2098990F198EE1A9ACF1548299512F541E45922238F31115532A3AD6D744473F68DDCE411BEBFD933BE64AD1C7007258DEC9B112D4B9B5ED01FB4DE74E128C90BBAF64763A540E41B407151CFD8C2048A415304F05F7733238C6722AAB433ECE0CF900EEB02C24B20DEB96441E947ED1097A539C6A1B9E8B838E6CA2055ECC7064F43495815DCA3972B83401D5C8EC61708E692130512573672CCB5B9A56973E2EDDB1E3E1C965CBAD617D2590C277B91985007493DC9909BD6BF8578F2127141993ABF817B6DA2019DC6CF79207F96AB032B6D06C0512D049EA8663C46D5EDEB246F036C978496B1C1BC47E81CB63364F47B6913D0548EC13E1A37BCE62C68CE98BA1C29E71A3868491569B3093DAE40D42A5ED2972182CEBCE8F2589137699B142E3D3D7164939A081FDF237AA58ED794603943F2269A40B2967314C22E8668B15FCE244E145A3A49A3CE5BFC2C46ED93F40816A92DFB2880B5C4E755B2CC50914583D0FFAA28FD934E763118DA70C3D4137957333927FA4F0F637C4C52B9078E141089BCEDC7B4288019EDF92FD0ADED643C375E71C25ADBC8F94E04CA5A4E91C362D1C86BCAD31149636A895F443A491E6F558F9DC89ABA27967C7E66EF9C7302C100E4AD175021CFC295048BD5CADD8E86469EFA437034D7A01E38BDC64A6187F51F6D023CDB240F9FD0053FF7258D2C5802D1FA1C39DBC9D6D0E65026FCFEEC8205F77FBA1F64AA03B4D1C091AF43AB800839B4EBD378B28EA895111560183199390C3C6706EC35A05E4118A192E5A29C77CED86919C2A74A827913219B2C33E83249175B886B598CD25253A4B07D10C3AF92060C52FDA89B880923595865CA108EB0E78BA3F9E7B0465522CBA8DD6094131045E13A4C979B07BE8BD782AED050C3CF7C25ADE3C2A1CAE81738C55DC1ED0A33020EB6DC3464BDF6C16CC8223161991C62D149FCEA52140198B36B6379B47F5AA5EC066A5D5F561FDAC44EF3F967EE0E0A420AF89E22A053119DEF0D36FEAD69FF1B2C2476561DAF68D7682BD807CB4D2782C0B7FC39D7C6494BBE622352B534C21BFA25E6A37613CA73B85C98894EE1E588F20E73643F241F83003ECCD05B56255AA36782EB07283337E99144CD03B90680A048D4538D580728C0AD59C082104CD79099A08C193D40C3CAAFE3DBC968F9F8D9D0C74A7CA135F02C8F9C18380B00ECA21AE7E7A22133C1A65687C7F74CC5FB4BBD291183B803B1AF8441900134932217783D9EE86A565C8E9D316E0BC93E75941989C7E227D3170B0F78AF6F1D8FA70C697B4645A5F896B0C4971B6544D0C9786A774179E99EB4425C9838D57861C88E1DAE2E482D38BAE9D9C04DCC71D97449B13D3E9F6A52D81C91C0B02B581F4392C4EEE0514D4D39C84F323D7FE9A30FA87C5380913D3955C210B84444FE7CEDECF821D903E2102E8CAEF4020006F67B6D4B2146335AF10C6EA0A116A0110C5B9C935E349A6B29E8D609361B668E42BC0CD1E33D491D59FFD4A13E5B7742A8DBC918FE7F72BF18268121CE414D222C9AAA0522CE0487F2FB8545D19D7911BDCD4C81106EBA729FBD57365B1DE562A07660EDC92337C9A695F4DE495FFF27D63248BD4E4A96E405E39999A8AE35B6CF12AAB699FF741E298A3222D168EEE5ED1C0A372810A883BAF50E7DECA6F146F6DCFF1067EF4187AF79B70D8814CD50E39042417B4A1B7A230FE68504352093E91073307AD525F069F15DA88856C5140F8E89DFC8861E8678067FD054B163E02203E06AE92FA76FE2B68527737D99F2A13893699D7985F2F025DC3A430555FC23C9CE0C078E83CBCE363C5B5840FE09155F433178C46D257F5DBCEFC6AE9140F46A78872803B8FC6D0459C8A26279E1AC09711150E7F58F420A6AC2111647724DAED3867FAFAA58D4485F0265F0FF6A63C9F88CAB0FFBBB3579DC045903D682070C4DF15D3D02650213EA7A7D2FEE676BA92F923C1A0CBB2DADE5EA8F5623A548DC1060A2BFDE25AA6A09F80D8613D9673B66D2EBB124452921200BE54364DC705DC60BA75F2D0540C4168E6CDA16DA504D63068DE764E1823700BA4C97BF86058DDD2F5942DD5F4D3B19D6883412B6089FC6A6DAE5FAD95C3175AD53CBA016D59FED8107D0C64A1B50B1BC1380261A55D04998B99202078EAC318A36879D5C5AAD9299134EE66684179F8CACC52EE8106D23D0509D32E0459384B86CAE143B3E3C0EE95C8ACAE8D496E59131C80CDCA98B812E0452B8B9EFE94DE5424C50B935BCC927FF395D4D141DFC89A639703632E98451182D4D072A987A88B4409E0B5AD6F0CC62A5A10C3DC00B03597D1453B3257770E36949218F22D721302D3CE5DFC09D5604C943F73D75C996687931133DC4B6B061E5E74483FAD6EAA9E89D9467CE4C4FA061EAE71B02F3390DA9EE49D0EC92097321171D9771B1D65A4B54130345278FF8BD415FD5C9894B9F430E47F2967C650E376E614AF5F32A9456AB0C61A9278109404A484F28AC568922691C4C3965D465CD82FDFA330E3C9DD9E65687AD8827D18617C54EE0E3F6BF7E9FFABE7127AACD1B71573E2846AADBA44415407013EC01C5A7F70960870D1742DFD488B81A34DD7A286F4CC2C000E042352CE0120A637250B2A21AA998CFD1CA99BA21C321335F4A9222486AEF986FDA32C36F64172AFD225B5D358B59A06FBC1D388A99AD5780624E6A257A96910A4471C9ED1CDBF4AD41C74538A0933A460FFFA7B36C925E02D45D89A819725B8029742C189E561840F20EEB86252A6925116578A705FAC7B5B9A128E1B429E321C0B8EAC6B74C9590E6B02DEE15A0AEAB25B7D5533BB7B6D9299620BAA42C097304795B71A91DEC14A32B96438B0D4C313DD9A25A916554D2164D787E800B524D7E02215515244E7994C427574CA0E02FA18244A81E49C03C59E85524C8A76B77828A938A0BE90C77595567FD2619381FF0FD601777B7C226AEFF35E0B5BB7D6D88660027ED4E5E4265B2E0A775122A2E375F08DC24F4F327C9C2766F9CD8DF228AED7920250F1730A4A7D08531A26827EAD62E1BAA0A45EA9B8A26F5EB7CB6B36561F72FCFA31BD4509FAEC210D79E0E86B3048F8E629DABB24AF46C73547D40C0BFAB592078383832561F15DBD90E4073BE80079F3A489BCD51B98278337077F6791CAA0AC828A14865ADD78BBABF1113A171C06D10796415C7B0F4F3B732745BF9BEC82866D4508C1930B22E391FCB6D68AC89EE0D66A8B76BEAE525BC89AE9FC4C15A21169B7FE739DEAA80A7F19D5C669EBAC95A71EFE265A1570400315B8E853B7CB18E33E3ACCD4CF9E48546E36422E6E0ED282519DD5280FE5DB8B7877902188B17C4120444D729920963CA5AF34B94E365A8B0AF7947142C114C3F0A7FFF0714ACC3833CE4C0864185ECEFC7F36736F3E267DC956B0A1051ED765DF0BD12E1D25760A09EB05C16B327A30BAA1EA24552E15448BA1B3E1DF0E8550C7F4CB8240DD4146AB5FC002E33B4FAD65115439B10991417068B09AB2EE5B16D02C250A020B27580A9C1122604D1D69CA74CB478582614C56C4CEED92660B643C50712A132EF7D148BC27C4D1FA1E8680AE171CA8643EA4BE9EFD4F442B1BACB36221370D2DAAA509F78B76FA2611744D7617C12CE4B73914A26A0E64D15E8201C5BE8313FE0B0005102EDD25F95B440C96B90D9A92720AE271B542060B2EDB0245BCB3C83F901E2631B76C24768D28C18B01DA9C184DEF925D68C655E65A013B592D161841045F3EC54D0088449A64FFF0EA8E6AF632347BEAE431C5EF288A30AA74D95241EE7A6FF4E73DD22EAB04C6A6339CAA3A4E8C181E0751AEE8468771EECB0AAB3427493B0DCC2B19DD9A586DF437348C7CF9C5E3A8B1A630D5BBA6307CA395B4C797CEEBFAF5153258B325FAA9AAD673DE591DC8C0D589C61EB70CB7327B537AC1A31A6EA95C81C886CB3DE52427BBE10736E1BBDE9B8EA4AE6A2B44E7BC376B27C08E6FBB22A73B8D14CBB3BDA545B9430C30D6F3D67E0B42D7B122DCEC983B996188F79FE193F03CF1B446F166C5D8F2B1FBACD5C85678698EED8E5C76E2E0D55B955A2643FD1BBBC16D5F5BCA479AB5C1182FE2918BFD722DA84A010E60164C3ABF8137D293DC8719731F40ED404BCBF171E99F511F1E3CA723D59C34D78EFBBD463403F1E87337CA461447FE180EC53054A3F969218290042FF30D798B0C20A84C12A4D632CC9955FCE0D5DAB4AD68E71E5E4F5E446DA5FF1E2A5EF84BA2A3F222E4240355850B20CA5065330046E261E88156FC1A84442C60ECBF4C3D2242E27F8D806B022424D917CDA2830CC401C7AE9F1221FE533EABE3CD2B45E5DDC9379CEC4542B529977E18A8CCBD41B827CF900268CF7F6EB88C82415BA10930D1E157832F46E1B0F14E4944B720270C92509DC0DFC24F605A8AC015511B5554A4170F97064CFE6CF944D3B202A7C17DA356ECA45D92941C661B70B4AA679EC10DE7230C095F0590575FB28038E02A807ADD262BE38F3CA3F5A1D103EAF88EA59449AD040FEF17E702D2E46424A19216F2EA716B60070D5F8069215D580B296EDEA56FA3049972FA9A7CC947E1C56F669CD228B4C0446268BC47FB0D160EFDF7AD3218D3D57BC4B583319CA48A21D8D1BCCE5179421F776870F140CB9F18E2AA1DD2C5F877D91CBCCED0B4B8D84B111AA7160EE85B2C9B8AB69C1E3EE4431FFE4D3BD6A4DC6C8A800BD20CD8137AE1754BFC244CA7C5EC281381A237548A9D9AFFE7100B4254302EDD5461122D314B4938BA7B2A4423B40142E090E7AA3A6FD08578B40B17F189F9B16DABCB6DA64DA5470991398E9B3238DE4622FD2D12FCBA1928BC861ECC336BDE65A5BC43B6467CE293D37A1019EFBABA13ECE121B0ADE45AEB7C644C2D49C05B45F946DFB58E78B5373A4DB14884A241367672A563E3242D1856C8D1662D5F3691A6F5C769DCEF47778685BB448A8ECC5179EFE36CE6C7E5C04FB2644309018C064B2803CC1377D19F59D30B19E04D2981873CECC5C3E992C8889708B89E1990AFF746B340AF895962FADB2E2F926342137DAD8C1EBB09A616F658F40EBB28D3858D21B9F92A7FCE7FF2D421994CBE6072BCAC3E0DC3A030A212219D5DBDC906B07DBF29DB8EDCD213667F40CDE4AC7FB56E2A08A55EEAFDB4E71196FA642828D56983AAC268FFDD7E5BF02CEB2581B6DB158C91393A36C367F36AAAAFD2C40C2B4EB40963D1332155353412A2126C51BADEA6B842D2FE695B3CBA2E2584288304015905AFE6F808CF58A708290C4824CC484EED112384309A28E028D1E2EBD46CE419B5CEC1D9C9164C9A40218DCE50C9B466A8E3C357D3F86EE02A51F86FD361C000509AFB168275DDFE1F1BDCCBEB92CBB345E62CCD4F0328FB0A35FA8F28919927C1443D289AF808C8F034D28F79038DF670499E6521F080F0D365F2400D5D086CC7C0041D4DF80E4E4CE3906215D18EB720466CF8B43DE1C692BB71F63DF253EBD498A9020BA92517628263F65B8CC41A5D21BD76B6436029FED17639049766716B33F03E6F1786852AE47250BE2FDF8B6BC4F0084A823256B34A2C2FF4931119139FA60DFD0F376990DFCC08BA8A09B0EB3DC299CE091A1A15F1BF7C11FD35CC40BA9C2C624530441027ED45FF8C00EB0B2BDF7BCC18746DA7942C342D2A58A88EE549BD71915D1D907F0CF89C6E2CCF63025E0922E95E713AD78DDB8052E17007A83B966279E860A19F38FA484702A1229ED9BCE918B360B2C1EA70ABC182F62B2B6306802D70E4E2A83D46CAAAF950A1A20DBFBDA6ED1F21AF9C2AD2092875EB391A925951255D9FAE3292EC485B5C3CA16B003FEE565110E0A910A010C499AF322039140A83B28949AA8946FACC77ACC38CB4AE9E2AA250E34C0E63260BA989181C7470E0BD484C17704907A39EC96E2F4269CFFC95F311DBEE98360A999FFC28BEA9F9446A00758F83B5D492B602084DD47400864696BFB5119923EEC8D5CA82CF9F2BE623A7046A741A8F5A31259A37247F8EE9CF5EDA91B5BC5DE61AF067DAB0CE4C6C9881EFFB4E1D40C87184C38CEA0E07409AEBE92480294B852E21272AA71463C86354A37704B682825E1E7A1FB84A3329C376844286683055AAEC5C8BDD71BE9C88B3ABFA303E7885A0A027012B2B8EA8B83BFB1A8A8C4EC028DE82CC11CD18511E3F56137D84D326326AD2E0C479513F5F112E91454C6CA904010D328B94A26AFED5C8F14609037E17355E42B24222E7E5B1D84E61895C45090E769734E07AA03B00D08A0ECFE0967D7AE09D16843D54F6EEC12584F87EA7AD832B90DBBA8E39A0D21E867E3786D8FBAF19CDF7E56E9E9A44F421DD350D0D85AE095AE2F2BC0F9C7A8748279720BB0C0C6E7919CB83C40BDB3EAE1A6F87DFDAACCA342DF1C73AE02838ACCCAC609504A12F720356A57C4A3D21794A8106139C27503E6A6C47844962AC9FBBC0244601888B6F2CE6C41F8CB757F3E202F8B9A27D3057272745198A5CE7D2A4B227EA9CA6F0838B23EF2C66950F38693161AFBFD724EEA187F9D324C970B9F4BCD408161906A6648D18F4E6D52123F02694E39B6D8D1BE691C5AD20E793809F4D970893DAA133FB310146463EBF24617072871AEFC1CF9E885923416128479EDCCDB941FAFECE56906243A74FE19CAD9250141AE8B4CA6A343926D9076B964733D8978A109876475EC66691F659499CB552C28ADB0420E335F01DCC2BF041BD438E830FA09AE673C03930FF478300E5C1FCDFE6932AEBC289C3713A08B3136B37798527B2F67803C705107F985A1F4584AC2FEB24D195234DBFAF4097C1A1A6C50B6CBE1D31CEAE79299782B7A4482C21D1ED48EAD643681282282B1B0BF1150C20364431F62224FFD07EF87B9AA4CC4F73FD2284BE1064682DE6851DB21F786D1B6F73654DF04C06FB4F7E1CEF9480392AA851DB4308EFA35A16CF35B59DDE63F6208B90C776BE38CE0139E97C041D508DF432CA1D399910CD19A1A7C65C09A6CA89A5323D205ACC5BC75C312764B0B6599E10C2B8F4DAAAB9B298CC96CF3BADC21E4B797B52AE793B1BF08162DA0D4206FA64D703D100580435854460EE5085BFE241F8E149007EF2A373E2F48E55112AC1394721D0CC272C5C95D3EE9120A3F9F7758E5BBAC508FC5C20665132DEF552A7A65D122AFCFF8B1268ACB094DDB628D39ED6A5A0B86FDC96A7843C3043C083D8C06C8016AC05CC517BAFD15B6BC3EBCE8EE5F4C6D4A6B0722075586C66A769F714AEAEA49D6A0F5F330F8EF78EA55DB2FA5C4D057D3A1E17A92EE224745723BDD8FD7E6EAC10AFE9A0E22B702CA226F694FA079A95375E66B002F1E3C72C3CF63AF044C435A7EC2AB93570912535C40543A3B29AA9C8D07B0434443B32DE9C64B96385390FA0D6DFD80C2528697D253B9E7FD3AC3E5665E1FC0F707B7624FE526E5DF2242CB30740B6A965D82C4CC1F56468C8B43B4070C59F5F13A96E2D46ECCABDEC4702D1E8D57DE00F17200BF581760519FF2CA755AB85B1E6072000B0D7469B36C1D70290512A43F2B492C90C16AA08185C0920EB642054BD4D968396BA5393CA0364224CA7CE9EC77296E0E0108C691BFCE7B312524025B51F62C5A631440A21EAD737D224A9BEB8354C6F7293A710909A4C20E29F2DEFA90DC3AFCCA6608CBF4BD37800A4866A47DDDB7D6CB93E276CAD4C0BC6363B2204B8BDE55B1017181A57B3D8C21A452AC2E90329CF0A57734FD3D566CE07DAAA277390C0ED6A5F9E004F6A21AB57A29EAA2483421C06B7F26ED889E8FB5EDB83D7B323477C71CA2747065C8B6F25319E56CECC956A0F668EDC3667D16D2F511BCF247D1B0A0CB333741C2CDFBDF42E2397B92D582B2E2BAFBE4283F482460BC4EF92285A6C6901FCFD5A4207AB3ED31F0F96F887A9AA3106A11B8631DB062549A389BD938DAF7A78990698F57CD28BA283BD1627E33ADA7A5FED8F99D2916EC6369C3155969B420BD3226C7176EBADE1FDA729F841FDC40A4B71AD06CEE87D22CE513F044193ED05CCC89DA0B02BDCABA46B55077744E5CC67400CD2834299A5117C73ECC94BEC33014AC80A44B213E2454429E87186DE2AD19FCBB82717B410E17D53E0D3DC9E19549440B254C7476566B5FBEF170D9A72103FDECFA8C9734D1288524F5A14180BF729E56A3FAAD46EC1C565401646B60C319676274BCA3348D8ED8AD4CB033AD0E60F46E9326D7905EFD342FF4E62860140FE4EBB0B10A4A50BEAEEBC69454DCCA565480F0A343E69D82DC782356F4082E654245E50A9EB928B14A12C23554AC2BB690CDFF0A780F8B76450C894010C0AB69F32D1172F3A4093EE363285A1BCD8A28B652E02B0AC6AFDFEDC2FC544C70EE216805EE18F90FDB9629B315D2AB7DD2E4B07EEE3813802F131C9E9B1D28E566F9F92F0418B4D5D7C8F04A1B01FD4B311A2AB22B0663DAD07F993FA403F7752E9C4E8EF2E7D5B4015344E43914150AFA4C44E1761CAE104A9DE91BC81B6806264B4F888B7F24AB645F2F51D745C99FE1ABE1E733B8F9A54D6909E247E098D201293C3B70069D683DCE35AF0D91F490B1E439583129F45884ABEC6B25A5F59657C4F74846629746C48F25FBDDEEA64C931E3B07082204E35D3CE3DA543131FF6A284168D245EF1196B5138633030286F64B43B6BAEB12C266881E44F25B5A711553C8B30EB66070A12EE3B9DC78E9E91BCB1F5748F40DEA61B36711588A6A14060921D6776FA84BDA0B585A7CC1A855096763E91AAB01228F7EDD01C53C2EA0B5FB420CABCEC9A1EAB94EE0152A5D315AF370A1C192CC621FEF816C3CB4B9344DB176EB226138787C75280AA061D77ADF001267AD32C146C21CB02B7F0557624335E764B1BA948F81FBF69BD29641060EBB9AC541437900CBF32D8E206695E496E4747430243DD78D80CDD17320EADF225BD0CD0D158F95120AE130EFDF13441BF7578F4DCB3964DD9B507B95B1CBA60230D356C40C51A5D457F92BA19148D6A6E3F459A78A874921CCE17F654B72574398C481BA54976F940C1239CDC045F953EF5943BCBAADD35B9D3CAD3195337C4F28385D61282F97C8E1D63BFA91160F254EA157E7444E98DD5D871B839A9042E5E815BC681D6495EFD3A017806E8C28C4E0627DBF61D1240C12BBE5F08C3CEAD6A0635EF7CA2E816C56284BEE2E8ACEB4B4954B00B44DE006633AC5840A26D415C94A25A88F5B2B7B522669A9E9DD142CDC188B20A9D545E307081602646AFAB9A32B725D66EF158E98432BC2D889086DEC63D7C7B4BDDE13B3187FEECA3488AA1531E606839C04764902F0800955C6833C00FE3CCEDCDBF75F087227BF12F4603253F6177891F37D408D6D27EACCE1512ED2664BC87540510C43A1A89D8AA28C8DDBA97B1BC92DCBA9A68DFF3DC57338DC45F891BA704D17A18DE5E142B09ADD8F97A3A1266B251392C0449561E0D4EA4AD1B84D071D28038D5AAD50BC86CCC3569EDF18E5B24046668106D24767781EE56605BD41B1195D8470581517E3FD8109C0AC24448D57C146CC5D1335B140B9B4286AC0F6D2616030C0458BAD9310AB6EEE683489A1146F7A08E406F00A4CE8F514D4CDDECBD01EA05977F55C3871087B03777D0149BCB81E3A456510014E7AF448E03A36855777464E463261F419870C2E54A63B7E6D1BD9ABAE22855469FB9251394F58329F0225320C52A333CB228BFD6A0EF48420DD3C7C550C22459CFEB0073386DBE032D31C5B75ACD4F8C67AD82C71E7183969D20769A18318A725D1F22ED2BEDF1E9D72C4A8C240943370FED1DE7F23513AEA2AA1D5AEE27AFDAE647F03D98EA7121891227C9485A0A3EB5C72C263998B13CD68367AAC51CAB3CDE76674341A593B05546DE545DD0CEC049C4D445DFA36019F1448AA432ED1C0B70D11DCD69F188F10127FD96984DAEB3D2A7A3790196729BBA73443D109B38A96E394C3419F4E187EA26D474534588F2E9124E52E1001116886D350A2CB3C6CD3881FEBAEF336AC1162C84D0165F14DF8011AAF3587FCDE8D0A19FA260B652D682F57C65C3443AB602FBC27B8A0622C231880B1E62D095E1A4FCABFF880D86C3C4ACEA5946D981369678F4E34FD08A4625D9060363F22526D4D8DB175D6D854A9D15609F704322440AD183FE6FF3F4250213006D91FAC2985BCA13D4FEEA8020C8DC6770F517CDEC026E125C1AA3756A34C8CCCA219B0C214303637010586B8CD51DE2E9A29DD9675411C92540822514F10205820A2D6EA2EF3D742635D81A72AF24CE08C8FF0DC150219CBBC550AA20DD7797EA683ABF681C8042BF242C2799E55EE2C10577E3FDBB413B494447F121969AB56660700E260C31A01B88EDFFF3D8308940E295DC5AAC44CB9CDF672B3F7AD2AC7D7AC1CF668F913A64B8573A60947437E1270658919DAF571289CC5F2E0E7BDFE3E4911582B540B0B36732C5550358BD2738C70721D3C18A5BAE95A3A4DCC202C5634C390F1CB489CC907CB4DCAFE6FCAC299CAC3655BD7DB669DE2AE6AD77F3F78B4A6A154D7463944DA23515D1AB4C75456D601736BECB027B0D544062271A3345E0C9BF9333EB1B02D5038CF771C2EAA1FD6AAF8F40E9F077B907827A31193AEF045F4CB5C24A9F490819644834D01B57E09EC21038A2A701C7D21E0E92C67F3AC8151F9AB1442A9C122AD961DA84679584324F42308C384FE0A844714201EF64C0602EECC06C45FE04BFED8B664930A573B95FD7BDFDEAE6E6CB1ECC8EDA92939A92937C574CA50BFB8E6D4F92D713A4A0C3B9B098C2B45DCCD2544369A923C73DD95B6743D96549F9840781D6B0C1876B2A407640024C6A823292E4688D0A8F83EF689D7BA5A31F2D2A8039E355509F0C6A199D782346FEC75E9D9C4E5BCE1A1E668AB0F383E9B40545A36C4C90F92CCF6032DDFA51EFA03A1A026B53E092842AC49858E71322081457CC6006D81F0C3693F5892FEDBFB32290AA36B1F68199FE655E3BB57479012BC0090E58E4B9D6074A5665996666394ABC542B063174D67C7038172B85B646D330A152FF451DBAAFE2A215D1AFADD79CB9BB785E1B9F400C8DBC9F90E5E2BB54AE66760C0781C1233A33220521096AC8C5094FE49E8D631EA05188328C9732502ABD8A0EE35C8ABD039902A5C8A0C7BBFCB32508A2591731CFB1632F39DF33C2B6F36A6331E3DE35533A3CF7932D417E753ED68F1BEAF651465950B455F292A23F3675DF243043C727775C9BEED7E16789F048AB34A99E9F86DCE589211541DE582AC1B9139B25EA1F7862808DC97C598BBBAE330839320CC36DB8ABA774CADA3711DD41D44F9BD60918C2346704D0B591B76D8FE88C523155E3A7C24B388540C90B3097F4F39141CBDB541DE113F726C102B11A659E403C9AFF464A21AA4A5B3ED8132620623B48121C203B94A32DE0A42FFCB4EAC69FE2D7DE4E144C8C071DE51B1B11111E139AD656552A757DEF878844B97094A633EFE041288E275CE020A935D2F0110D09E7A9720E04FB3FDF8390B73CC92EF9378B802C2371A2FF1F396D95F587D362A615153AC8F687D84367B2C72F24C6A92C9B7119A92B95D69CF4BEE22A40CE1D0354551E2A867C78A71E38EF22F82240846DBC93EF1BA85D152752E9AF9A1ABF3896C1B36A082CF633645EECFE133E60354A05FE5BE0A16E843C8B9DD6A290F0FE1572614362B0E08C9569CCE55ABF8DC821356629F5313019D52496F7BC794BD2B1ED61260FFEA4D9BD07930EE2E66CAC9464710B87A318C6F66242C0764005DB8F9502046582F0A99B13B48A00F8796E846B2649E807D6E4B66A39BA514E07D53B0C5D85AB54BC30969E8CE0AEA37F5305F6F8312207B8505BFFB78DB0A29265D2DB06E0F617E626614371F8C49208B501ACAE806E3385458BCB52DB4D182B8F39ED5E4C2775D0E5882C189B38B4ABC1F49CE55688E6A044AC3717417D96053D0F22491BC3F5D93FA197FC246238864488B5C9A334773B11878AFB48D086CFFC5C8E389EC3AF54BC44F1C53B5273C8851F94D17F841F9D99F4EE8DC0A96640FDBA3B43F3B0174A44A2A8785CA45C1CC4462B4E201D21E3C749AD482B51079C76D44CD0264E074A10658AD6BC803314C0568A1B73699C5566DF80B5A6ADF40E80C5CA3EE7E4A989D4C40E6E043614F8829192308656EE7D81C7EBC53001640345FC9CA1D14CD3D2DBC4CA88E26224162918644A34EBA89408DB7B8B810476E33369014BE8195A7838BEE3BFCF49DE0CDFC19D50B57547879514D53B38CF19CA5456CE9DB44C08FA05E55A626984DAE33703DA1CDF56E277F20E3A9985423C9CCC85287D5BDBA4823CD95AB0D6334DB939FE601A8F1D18B60BE9D010B6D3DC14F6E2DF2524254EB0DF39895F498E4A9C46FE0BF5EE151CA3401D4DB116336F456C64E1B5349109341E94A852861D152FE10C400B98F98A7FE976852077D44765D191593723DED3E17A4DAF288BF54829DACCA038DB37070BE05B968849D8EF747A157AC51F33A31E1934574E6EA09220547E740D4472F70BA581E88D15C8C768F51FB6B006688F34BE85680AEF80B6FF74D1B84545EA641CEEC241110D4157E4BA521235529CED6A43F101D5CD9595E020E01019D819C214962576047D923CFE2EDA821DE59109C845DB58DDBBCDC2B0258CDD0D0B3D7833EF57CB9935F09044D50928B665E6460EA650634C55FE146F2B784331B815C36A9C966C9020C5A2FA9C351385ACE18405CB0EA0039F14F11EC1905D0D273C57E3F8FB218E5B3C5395BC8BECD356D513455FC70B9EC32598E677527F403F9D3A9F27FA14788D6D29F28019F44E80E2DA4787B13E60A43C8E66D81E53C3E42D02FA188C916B515D74C20724B2FBFDF902C720747481A4E268F13087900ACE6C33267CC83635E0B3ADB698D006801F967625E492B2066F6688857CBDF1452598F3319D9ECE68A85C1564A343B52913C8C09441E13C2D5F3BC59D61B624E9D671268708EAE80D74100446F8FE14A32E7DC41C4439793CFF61893B5A4D39883E99E0999541A82AF0DD8B93C07F07A07DA922217ABDDDD481EE8C5A2D6A6D0623AC3F2ED28116EA5C7ADCCC94FF0E201D1C989DC676D4043F33F37C442DD20C9AD459BCB89C2C50B453E6A91B087F3DFC72411C80E05B675A5E9A6129D0D145B3A119147FD00D37D92179B88E3AFE4E77F24A008A3D4B0DC86FBDD2773B53124E4DD5B30B08B048639A75C7094F966E81612D8C0AAF7E4B03E02E2930BD35F8506CED8B491C8038CE8C1160B5B4C11A2E57FDCA4F2B242C7F8B74E18C8C77801F09B277D4FF68FF40605A286801F24E50106005ECB27136EF343597CBDE60B132A57809D1F1FF82310E69BD5A8B851963486C73A681F04473A00E137737672B6E592572EB162422A17752CAD3E4D32076A49125B02B090731648762DD08362853C32A000167E8B32E35A372EA9D6686D82AB35656A4F4E00A6942CC4BA40E468A32C013C4BDFA76C73103E930BA5C75157B62DC3779E779ECC0956EC7758D83604D480590F88FE77B1FAD5AF7472B4905DDE62C59D14757ABD800EEE2D88E496BD3C544397A78A041E9161CB37E3F4E7B6E09C424EF12E9068B898944F53908FE800CAE8C10F625D800E0AFA6A53861E1A1F7C12E2ABA9E0D282EF848BD90C29A90A54AC5EC53BE5CAAD67C5D276E0C69C06862E1A79B9736E19C3AEA178BA8B0AE170BD304C4319DF261910B29B4B569D1B3507BF87468063AB4A53ED2D651DC7C47F6B42CCB57564E99DE5DD438A8069C8967E25DF402B8929EA8244AD67CA9B8818A03067B280A4DE2E1A1A22995BB778C40A704B0CE84A9248C7B6974970513B29AD3E58880E15054BF028AF26CFE30ADED531EAD501F5263F289E6FCCD67E978434296C52F42AA317E06C66DC4008564E971404E17AE00170211943105E89A8625B0B7D76E36768D00CCA75F68679938149075AEBCD04EEAF7C5C0BA4032C60B45515CEEBE0B57AD05C25B6A932ECB6F2ABFB088253039908315629AA975B8D2EA5CD5A1964C231934A310BD222C8896CB870A620293536A4D93E29538AE3EBF091B6EDC84083CD43DDE7DB84440C8DE69079EE11A1B7E354D2E02A326E0FA84821DB48C9B886C10D2EF5286F8DA7206C1CA5EA16852579B0201F8598446D4C0E66EE116507FA2E1F853C11890B32D419E093698B6B2EBAB9C4417178985B8DFE2767BD8624A2088E756EFAE37E98490982288094977A7A2538907653FA78952C133017BC129539300159E75E15C93807F8C8ADBC908C466D720E2A86D8BF9ACFC10263620B9B31DF7EEA587891D693154CF251AF35A2DC01B4A837FB8CA74F1AA744CC53AC3953B68D51F71D14CEFDAF91E3972B2993DE80F83C9E1E401128531A8C17462BA7892CB962BC084C91130CE933A36B2A74AEC1C5BFE498684351996E15CDAAA5C5AB9C767228397135845E82469085104AE5D97523C0C7634D0DDB2D7F49CA6822F6BDDD8AAFC7558A405D1BFC00DC8E80506B0B2A12767C0F905CD1F568991CF277EA51205F04354E80255FCE010B93E822CE08C30448C6F631E6D6339949E100F7AF00357E982378611BD2F17190CE6E2E71A43FB8E03ADAA98D54F78445B2C7C433409ED8CB75D2FC9344C7B2C24A5FC368D5D5C7CB9BEECE94647CC6B65C69DF829EA1EC6DA913052A534990D27756B2BC0AF7A533A945A49B4A3B20668D94254326E18226EC1605B63EF618C1259C81BA5342A20CF8DC64E39F4D7929694B516E64CD03614290D3C033B6B1C0B030171CE4EFA65491D1F376FD2469944524666EA0A28AAD35A48E15EE79E677FE2B38E9B11C1062731935F2513AAA3A5230A75A50AA446700B10C5A326776241100A2155BAE98E8CAB6843116B153E8BAF5D46399CF5F6EA67202B0144E34B0E1BAC6C1AA55FE7CA565E643BC1E15A1C09FC378CE37548D23BE3283A74D6B590CC8D25C64464B83A506D27AEC7F721A911F039AC4671A02564DC266A2EB78D6348A8D100E71F99FA861E499CEFBF200F8865D244BF30BA23EA4706290BD108EF82340B134F9E1ECE3C1226714C15BE72D5D33CB8DA2CF49181DED7BA3055E26D05DD8511D5ACA38192BD1AB7271B653005A6EBD06A3DE983CA28259478B4EAD1D66BA479A92F375E892075329BEA241C4897187F64C370F0171DC5D48CA543F3599FC8A87E7AD5C46306DE61518F471AE909B842601348CE0D92D657015772A7A59E957848263E359EB50DE8CCE2D2E37BC6DD42E4B880221F2B949BBE202A2648F42E9CD9E958D5481BFD186D444320FDB69B249C4EC2A11E4C6868D1E27E0F601163384AB8BA30B063B4D82C70CB26F061B2450AFA9C489A2FA3F11A09EA4CEF28B89DB6C5EF2A23CA9CBE1D980314807ADF85F64B3E627917AA0D05E35687BEE745FE67FB72842B1684587A9C41A8CB8D424E30BA1A7D0A17C6891738AD96B07C9881141FAC9B1C76AB47D0A1D32EE8B3D1B7F38003AB07C7CC89270E004942C3EEBA178E62D0F6EDA1C81B97E3EB2492AC594F710F2414119A481936A5E970F941C7BBD08DE49304D1E446CEF76E52713DD9485EA73CFC6B92DF4B09954DD20371C1E88087D73F0C885A68327486A812A1C9C36DA7E"); - byte[] sk = Hex.decode("FFFA0806FCF5F30D09FD0009F707FD010A0004FAFAF504F2F3FBF8FAFFF309FAFF1104FDF8010503F7FE0E08FAFF1806EFFEF2FEFCF1FD06050B07FA060C01FAF31300FDFD00070100F9F5110FF8FE0FF709F4FD0307FEFCF60800FF02F2FF0FF9EE07FF0703F002FD03FDF80902FC0B02F7F1F304010407FF0701FEFCFE15FC0503FE0804FE0704F202EF09FBF408070D07F206F307FFF502FDFD07F70404F5F8FB01F704E7F700F40501F7E00CFE080AFEFBFFFFF806FAF606F5FCFCFBFBFB00FD0AFBFFF5FC0B0EF411F4FEFC07020707F9F817FA0A0507FD0508EDF3FBF805FF00F1090607000508FB10EF0504FFFF0301FD0D09EFFE02FFFEF5FCFEF1FF0403F5F3FDFB0506F703FF09FDF3F9F5F7FFFE08110F0201F60701FAFFFA0A0404FE0809FF0AFEF20D09FF0A10F7FC020409F7F003FFFDFCF1F4F707F801F103FFF504090600F50301FA08FCF4F7F90C1310FCF20AF20E0CFA050103FCFA05FDEC0B08FE0502F8F9FD0C03F6FAFFFE01F8FB02FBEFF8FDFD0005030002F9FEF2000603FFFDF8F4F50206FAF9FC0BFE02FBF20BF400FFF90E0001F10FFC07FC12FBFDFEFB0702F8011008FDFF01FC06FF010501FE060A0201FF0302F116F4F8130008F60A100906F90309F7F605F4090C0510FEFAF8010609000A09020C1203F8FB02FFFC04FF0BF803050AFC06F1030808F6FB070000F80D0404FDEFF8F804FF090DF708FA050E02ED04FC0105FAFE080EFA06F706FA01FAF3F80404F905F3FFF0040406030505F808020B0803FF0FFDF8FB00F80102F7FAFDFEF3FAF9EDF0F704F302F10503FAF20302FBF306FAEC05F20A0400FE08F7F90506FBFEFCFFFA0E14080EF4041002F60702FAFCFD0F0B05F7FF080810FF030807FCF5FE020203FDFBFE021209FA05090205F800FB0011FC09FBFA14EC0610040C070A020C0CFE0006F900FFF8FBFE00FDFF0305F50B01FF02FCFE0708FDF7020006000011F800FEFBF7F6F6FBF4F50DFB09030D00060C030200F7FEF3F8070605FEF7FBE907F903010003FEF4F9F50FFBF0FD010810040502010AFDFCF00A0403FB030F0203F6FEFF060CFC010905040BEE0EFE01FFF6F6F508F90C0503050404FB090800FFFF110D0B0111FF0BF405FDF302FBFDFB00F603FD07F4F90102F5FF0908FBFEF901EF050DFB04010603120F05060B06FDF1FAFC0408FA07000E0DFAFDFD0AFCFCF9FBFA0AF201F904F9FAFAF80CF40003F6F9F8020805F709FD08F90BFCF7EFFE050AF901F4F9F4010704FEFA0CFF0506F103FA10FF09090109F90602F7EC03FE0107FF02FCF101FE05F9EEFDFAFC010301FE0202F80304050107F30107EF060100F9EEFCF60603FD02070CFDFCFE0AFDF90EFD03FF00FBF70308F50407F8090D010AEC0603030909FC020908FCFDF8140CFC1510F404FBF20AFCFE0FFB03FCFB0105F8070B00040AFAF6FFF8FB0C09FAFBF806000109FEFE0F050908FEFA02FF06FB03FF01EFF40AF9F502FE030DF4F6F9F4FCFCFBF9FC05FFF90A0204010901F903070C1007F70008EF03FF0DF705FCF8000F0A0312F204F810030D00F0F7F5050008FFF6F9070AF70600FCFDFE00FB03FDFCFC0302050506FDFE04FAFEFC0303F7EF05F3F70BFC06FE00F3FCF3F5F3000703FB07120604FFF9040A0406FBFAFAFB0309040C06000312F901F30200FA00F3F4FE030505FFFEFAF7030D1104FCFC02FCEEF116FD0B010B0EFDFBF904F3FAF3FDF90001030801FDFBF807030706F70304FF16FDF700FD010BFE090DFB0502FF0CFC00F5F00A09FBF604FF02050A04030AF3F505FAFCF809F900FDF00A06EC04F9FB0302FE02F6F60B0707F8F209FCEDFE08FBF709FC0805F904FDFE020AF4F2FD030303FFF8FAFB0CF60BFFFF07FC090613020502F7F2FD02FEF2F2F400020FFCFBF905F4FF03F706FAEEFA03FDFAF607030207F8040FF71101FEFFF50200F3FF02FBF901F50A0B0706FC050900FA000AFFF0F306F802FDF00BF910F202FEFC03070501EDFEFF06F805F7FE04ECE5FC0C00F50B0703000AFAF0FBFEF5070FFBF3F10600040AF3070704FA02FEF80703040107FDFD00100B04FF0402FD0419FDFBF5020901020B060BFEF5FCF207FD01F2F609FCFEFE14FC0D100900FAFBFD0AF802F80B01FD0008FDFB00FC0102F7E9F304FB04FEFCF60AFF0B07FB06FF0D020700EBFF040B00F5F8F0F905FD040807F3FE04FAF2F60AFAFFE70AF7FBF6030D0B01FC05F701FD0BFEFEFE02F70B0101F4FB08F1F600FC09F5FE03FBFD06FF0405FA03FEFCF7F601FD01060800040FF8F4F9FB070EFCF503FDF707F0EE0B05FFFC0703000201FBF9FB03F7FEFB06FFF200FB0004F704FB0904FFFE000603EE0A060BFF0AFBFF08F6FEFAF9F6FFFEFF0BFA0AFBFA08FFFFFDFF010BF60512F9FA01FDEB02FCF9050DFE01EDF5F3FA03041304FBFCFC01010CEB06011304FCFC04F7020BF6F10400FBF6F9FFF60FFEFFFBFF03FFFD03F108FFFCEDF501F5F8FA060305010501FCFE0DFD0600EF0304F907FF0000FB03FEFCFEFF0FFEF8000402FBFCF80D0709040B15FBFDF7050207FF01F8FFF7FA0608F8EFFB030AFC0DFA0DF8FC07F603FF07F408FD050EFBF9F5F5F60403F706FF030C1306FA0DFFFFFD090405020105F7020500FE07F701F608FEFD09F910ED0BF6FCFAEF0B01F4ED0708FB000213020700FAFBFFF9030AF6060A01070712FC0C03FCFFFC060407080104FFFC0904FCFAEFFE03F8FCFB01FBF0FE05FD06FD0F09FDFF03F40504FF00FEFBFDFD0EFBFFFE0B0AF4070C00F4FFF5FA05F10505FEEF00FD0303040103FC050407FC05F90104FD03F501FE07FD0BFBFE07FCF5F805020301000103060902041101FCF8FC00F301F503FD05020601FEFE070409090400030BF60B01F60DEB00FD1803FE0103F70AFFFBF90408F611F7FC0707FE080203F305F8FDFD04FAF5061005070301F607FAFFFD08020AFC02070BEE0907F9FB07FE02050F0AFE0FFCFE07F509FB0C01100306040E02070B0202FC010DFC09F801050102000CF5FDF9FFFB0004FDFB0A040506FAF00607FD0EF10DF5F8FB0408FEF3F4FE12FFF500FA02FFFCEFFDFDFF06FC09FF07051600F7050702F60608F102FBF60CF50400FB010401FE0A00FE0BF50CF809FEFF04EBFE11060501FEFC040B040605FF00000100FD0EFE00FE03F70DF4FAFF0400080AF80310F508EEFCF20AFA030C03000E0308050600F901EAFA0A05F800FAF6F808F803FAFEFF01FA010902F9FDF6F60A0CFEF702F408FAFEFD00F8F3FC05F9F60200FB05FDFEF50A01010D04F908E600050CF407FF0404F5FDFB06FFFEFC0006F604FFF707F809F900090E01FC0C040AFD0C0BFF05040AF30003090EFBFDF602F8F8FD0101060513FBF805FC0B00070AF500F803FDF50702F0FDF9FCFE01FD05F8010E04060000FAFC06FAFB16F6FBFFFF12090805F906FBF9FDF8FFFF1106FEF7100707FC0406FA11FE01FDF5110D0B0DFE01F807F6FF04F4EC00F50502FCE90AF9FC00FEFB150D0008F8F4140F010CFB00FB040F020207F209000BF8F409FFF704F3F7120511F90FF8030904FFFB020900F907F40BF605F607030BFEF301F207F1F801F9F705EEFD0FFE04F004FB0AFB0405FD0000FEF90DFF01FD060606F8F8F60D0AFA01F9FA051C00000B0FF9FE01FC00FD0E04070109FC0507E409F6F601080D02F302FCF702FC0BFEF302FFFF04090105FFF8F6F607FA0A00FFFDF5FC0AF3FAFF02ED09F2FBF7FBFF0CFEFD050D070505F8FBF700FEFEF80005FFFAFEEE0AFE0BFA000906020307F60607F80200FAFE0BF60604FF08F9FBF50606040802FD0004F4F8FCE9130911FE0305FEFEFDF905FFFF0D0B0EFA05000500000406ECFAF8FEF40AFA05F504F9F9010BFA0302FEFDFC07FB02FCF40D04FDFD0803EDFC0F00F7FE06FB090305FCF9FFFA130B0BFBFDF501F7FB03000D02FD0C0300FD0BFFFC13FC04F90E0804FCFBF803FDF7050907FB0702F8F9F8F2050102FC01F40A0614F6FDFDFCF00805FBF803FCF5090EF6FE0900FE04F8FAEE14EC000600FB0801F7FE0408FA0AFE05FDFDF907F5ED0A0C000409FCF305FF03090AFA0401F0FD0A000DFAFFFA02E9FBFE07070501F508FE03F50BF205FC05F50108F405F9FA02F101FAF50B06FC0AEDF4000DFB0D06FCFEFBFFFBF700FD0B07000703E70A0406FA050400080001F00E020D00FDFD0800FEFE04F90300050D05000D090700FC0E03F50304F90007F60D020002FFFE02FE0903010303040706F70800FA0706FEFDF10608FCFEF4F5F1F8F610FBFCF002020702070B0DF3F707FB07FEFB0F06FF0A07000C12EB0FF9FA09F6FDFB0B040AF7110302E9F6FDF0F90A04FF0AF3E6FF12FA010804030AFD1402FF05FA020E040201F502F908F00E030C02F8F9FFFB0201F903F3FFF6000606FBFBFB0204110CFAFCF40202FEECF3FE0003F007FF0AF90302FEF708F00DFD0B0AF906010206130809FB07FBFE0907FD080002F804F2FC0CFBF40301F40607F7FCFAF605FE06FD0DF4FCF60400F4FD0AFCFC0B0C01130807F502FE05F802FFFA0404F908F6FBF802FCFC060505FD00F604FE040802F20100FC070500F40305FE09FDFCF4F903010C010313FBFFFE06F005FB09F8F2F3FF0A05FC0AF6F7F506FA0409F9F900FFF7F307F602EC0CF8060EFB02FEFCF311F910FEF8F0F904090A0BFBFDFF03F8FA0E02F90D07FEFB02F9F206F40308030A00FAF704030204FA05FF0BF600FF0309FC05FEF9E8FEFA05F5F907051405FEF3F5F0FFF5010BFA06F6FD0D0504FEEF000CF7FF04F004050307FF0AFD00FA05FFFD05FC02000E060DFA0005040AFE0A01E1F2FA1508FD0804FFF900030906FCFAEB00FDFCF600010207FD05FB0005FF0206F8F900FEF902F903FC0BFD05F3F9F81306FBFEFFFF02F5F7EDF10FF50D03FFF6FD03FAFC0606F90B020B03FD07F90C0213F609FF07ED10F900F801F6F8FFFD05FD04061005F6090308FCFDF10400F9FE1702F811FDFE05130307FAFF0AFDF5F60907FEF5F9070709EF0009FEF8F8FFFE0A0CF6F30100040807F70D0D07FE0303F7F808F7060808000003F303F1FF01F700F7F70CF8FEFFFF01F70303F50600FFF800FF010AF3F4FAF001F105150C030803EFFDF6FAF3F6F900020C090A08FF0400050606040408030401120AF9F3F505F1020402050E010407FEFCF9FC010008FBFD09F7FCFC04F9F804F604FD0BFB02F407F8FB0702080404F5FE0A040B090305FCFE090C08F90705FEF8FEF8F1F501020DFA0D0504F8F900F9FFFB00010402F6FF0FFAF905EE09FF07FFFA180501F9FBF9FAFD040A0405FD11F00D11FFF900F2FE0406FD0BFDF8040DF2F80801041205FD06EAF8FA10F2FAF6FDF8030CF7F7FFF702E8F510FC070E0706FB04030D0C02F60C0904FC0AF5010700FBF703FAF708F501F7F9F80FFD050E0300F90D03FE1510F0F9F7F7FDFEEC101405020E14EE05F1F50C05FE09F5F602FA04FCFBFD01F003F6FBF6FE01030D05020310F6F8FAFF080906FDF6F6F604EFFA00020704FDF9FDFC07FA07FAFFFE05FFFAFD040C090E18FAF1F40400F3F40103FAF7040BFD1105FB05F7F505071006090BFEF7FBF90FFAF800FCEFFF07FAF8F905080B04F4F9F601F707FD0E01F5FFF3FF0700F4FA04FFFCFDF6FF0A0107FDFFF404F80AFF000402F20A06F90400FF13FFFF08060DF402040511FE05F7EF03FF0206F6FEFB0DFE08FAFA03F3F3FB0CFDF9F804FEFD0D03F9F8F2FDF7F8FD0B0BFAFDFCEDF3F60FF8F807FA01000203F9FF0C0AFF0D00EE07FC02F4FB050B03F608F9F4FC02F5FBF80200E905FBFEFE0BFC050904FEFD060006F7FB01FDFD010FFE04F6FC1207F511050CF8F6F900EBF7030CFA05ED090009030B02FBFC0608FDF60A01F608FC05FAF7F9FE0A040D010B0EFDF90402FBF702FE090FF5F7FD010301FA05FD0206F4FFF4030402FA0BFF1008FC03FE0A0607FCFD0108F60C010B080110110501080506F60708010BFFFA02060D100304FF03F8F503FC09FF08F00304FF01F1FC06010404F8FA0406FBF7000307020DF50C04F9F4FEF500F50105F70AFF100B0F00FC01FC03EB17F9F1F3F5FA080FFC0307FA0900FBFCF1FD0106FB0BFCFF0D0D1806FAF90EF7FDFDFE03FFF7080404FBFCF9FB0AFDFF13FB0502FD00E9F50CFB100800FDFD0FF4FF010307010AFAFC0DF906F4FC0514100B0A03010301F6FA0609010604F90009FA07FC05F7F2F601F3030DFE0A00FAF903F7F603FB05FAF8F9FE080F06F11604F3FCFFFEFE0200FCF8EEFB09030CFD0306F504FCFF070AFE030805080CF405F5F9070416FEF5FA0003F4070203061000FCFC05F9F809F9FFFDF908010BFD0602000D100BF8F8F9FEF6FEFB03FB01F6F70401FAFBFCFFFE0100F800FD0605FDFEF0FB0AFDFC080005FCFCFBFA08F7060205F1F60305020800FE0307FEFB00FA00100CFD060A02F70EFFFD060BFC03FCFA00F9030AFF03FAF7F414FC00FBF605FD03FFF0F802050BFA01F3FDF802FA010DF90107FA05010AF703FF050A0304FFF905F8FE05FDFBFA010302FD0E0800FCFCF8FF0401FEF30102FAF80D09FB0301ECFFF70301F3FC0513FF05F3010F04F70AFFFC060400F1F1F8F802FFF30FFEF8FF01F9F6050402FCFF01FCFBF80703F3100B05FC05FC06FD02FC18020B101102F40604FEF610F005F811FC04FAFBF50E02FFF713EF03F50700F3090301ED02F507FFFDFA0306FA030805FFFD0F0CFF00FAF0FB0609FFFC0C0307FFFD0F03FDF10606FAF900030C061705130C02F60AFF0DFA060304FA0106FDF7FCF404010AEF03F9ED06F7E8F9FDFF070901000105FBFC04FFF8F5FF0306F6F7050700F3FB0608FEF6FDFB0E04F804FEFDEDFC02FE0009FE0108F9F8070506EC1408EFFFFE0DF7F70DFEFDF8F80408F707F6FCF6F10105F80C0210FDF300F3FF0702F9F208FDFD0500FDEFFCFEFE0005000C05FBF90D0308F801F7F9F30302FBFBFC04FC09FB08FA0B00F0F5FD02F90C0506F80904F00B03FBF809FBF7F7FFF6F908060503F5FEFE07FB02F909FF0D0305060601FDFEF8F70007FAF30301F2FCF8EFF1F803F6F8F40D0603080100FDFE09F90002F71002FD01020DFE0105FDF0FF08020403060CEEFE0C06000001FC15FFEEF80FFA04F301FB09F1E90C0401031204F70EF4FE01FFFCF208F8030BFD1405FD05F205FEFA08FF1109ECF8FAF8F904090B0A01CFC6B92DF4B09954DD20371C1E88087D73F0C885A68327486A812A1C9C36DA7E4F5C254B6292FB5C3DB9561B8793D8AE3E1611423AC0A9F8CFC13E1C85FEC6B5" - + "3E8FE33CAE1CEEC574275C02B17AE78A0018BD4212E087C0901E518796AAA752B6282A7D0DB145AE"); - - - // - // Key generation. - // - - // - // The QTESLASecureRandomFactory.getFixedNoDiscard(...) is used so the same key values can be generated for a given seed - // for testing purposes. You MUST use a real SecureRandom instance in reality. - // - QTESLAKeyGenerationParameters keyGenerationParameters = new QTESLAKeyGenerationParameters(QTESLASecurityCategory.PROVABLY_SECURE_I, QTESLASecureRandomFactory.getFixedNoDiscard(seed, 256)); - QTESLAKeyPairGenerator keyGen = new QTESLAKeyPairGenerator(); - keyGen.init(keyGenerationParameters); - AsymmetricCipherKeyPair acp = keyGen.generateKeyPair(); - assertTrue(Arrays.areEqual(publicKey, ((QTESLAPublicKeyParameters)acp.getPublic()).getPublicData())); - assertTrue(Arrays.areEqual(sk, ((QTESLAPrivateKeyParameters)acp.getPrivate()).getSecret())); - - - byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - - - QTESLAPrivateKeyParameters qPriv = new QTESLAPrivateKeyParameters(QTESLASecurityCategory.PROVABLY_SECURE_I, sk); - QTESLASigner signer = new QTESLASigner(); - - signer.init(true, new ParametersWithRandom(qPriv, QTESLASecureRandomFactory.getFixed(seed, 256))); - - byte[] sig = signer.generateSignature(msg); - - // - // The expect sig from the C version is [sig][message] so to validate we need to append the message to our generated signature. - // - byte[] expectedSig = Hex.decode("77CA5E0F6AB8586FAE62A68BD7A97DDA9435AF9335EF76BEF113A56D64420A8FDC2669E234AAD20193D2085F9E4B9DFFADA03E33DB4119FABBBCD91B19530793E0BAB71ED5CD61A607055E93FB56F66E8EBEBC6B63020E75579ACF8E2F16E5F6179AFD9E7B20DF0C010C1554791E6D41C224639B9D070AB04F6914E74644B14AEE4C7731675DB2B94237FFF00BFDAD7A070D73BD1DBACEC15094D091A0563F6ECC749FA57AFC4BF8B3009836DC5ED692DEC837953D776076F1D9A0AE98D812758A08F184751D33D29EEFB8868B97E21E115C568BEA8521B60E7D9ECD30CA5DD48EE82FEE169A2A3A1F9EC1366203FF1B1732C1598906F6715B88576EDA2C29FE0D0B4006B03E1B21171E923B5C3775ABBCCD2313186793CA98BA96B932D2561DD915E4B7BBB08B6946C37D71A4077CE9E3868148C33377068A70F1B21C13CDBBBF200F39F52E7A4C2B094F8EFE208CACDA1F7789A4FC471574ABA28BF06CB8940207E06A5B2A0B3CFD2BCBF6421A85D32F5831084A78C914FEDA6D7F1D6977397202CD24A4260B90C11077CA337F10A852A34FBAB455F2B7530E336AF3F2C6AE04B652D7E05FC02264E5C81E0E09FACD01A70F4F66F368D7F308284988BC3E6B4C026F97A65C0B31C1187CD05409C5BA4C22317C3A1CE08EAC8FC25A4D3644B610481E07FE372D19FA622365394E37A6BB61EE38E309736A807A2DD85AC76F88451354FB12AA778E3F05EC69D83AC8EED551070DA0ADC0222E7839D79E2847037A2DB1B2E0F15C376451CE38A11E57896F67D804DA2A4F84BA51308ED69F161A9E08207DA401D9F5EAABDC4F50B4D96357929126A208B0DB29D03CD71A2F203309E41DA4661162A48944F463AA642D67AE9C36FCDCA4F14AF4B136A943B74AD5B8CE6ED6BFDC3755B1750B901584B2C1614A2634D0DAD3F2D54BBE3BFBEE7C07E4D7AE64430364A5A0EE4E4A0D436D569B2DD6C8A121FB33329FD25E2FE7297E939736721E6A2BC37398DD16C7E2CA087182C5958A4D9A21EA3E2BA3754B630BDB7F146F090649ED7A4B1ABB64D58BF1CC54E3FCC8358EA6AF1B2C7622B633AEE12C6664A51F1437368E8D9EC67AB6C2939749A671465EE7A77F9368E145047072664084EAE6233F91010DD5148E2F7A66F69BC5849F80186CE26C0D927BCA38E5BB8A28302946A43CE57872FE5D735793337127E41EAAD931AD96FED22862FC0AEA72569E9B56596B8BC36A186D4D03C87D484111F18A6187CD7522EC926153488DB161D8ED5CB05F144C01ED77C7614FB42FCE566898BC9F5AA9FEF0F7093818A390A22EBA9404EBC3A79FB3543640DF29D2B5B9A601E916DB36CFD66A5067E7FA379A640D12B99D75B67F8ED059B761D3FBBDAC235024D071EAB9A2C6F13D5C6DAE1BF952EEA902A5A25F1FCFFCF8B0ABAFF0B242B48EBFFA6CBA9CE3654673F3AD4CD5E2ADD2F3E630B7FD48B1F7578CEE7D1ADC54360952ED1F1951F3F4ED531BA57BADDBFB7EC437E42A429DEC044EDBA509E5C18BCF8DE6118D6935EE38B3F94C12300D49E9F434F227407F3C7FA1ECED88D08DF04B4A518C508A3B93A3A8C60ADBB8C0B5F3923213CA531007E0CAA77E5361CBBA1CA6E49E81BA87ABE3C07E9E4590635486B44212298CBF9EC48920C0A899CF257421B734377B18141550B3954E23EEF90D6E20FEF7BF04C17DFE8083C0116786DC771DD802A69B2516396A45F6C755E05F228B4C31835F8E46591C80CD10250470B4421FD5C86B97B48C35CFE22721C3A9BA3DB8BCC739AC0CE5D2BE05B8569C0E3AB51CD112E4BF0137D6902E08E5636861E00EF3D58F3B05C63A5ED8286EE075B46EFBF2CE806301C059602FFEACD4CA5E25FC72424D4A982FE4AA6A6B7821AEEA4A4C209E78034CD69E5AEB14D57E5685E0F90BCA8507FF339CC084889541BACDC155FF24CEFBB79FB2496224A06517CD7A5B3B0C829A6ADE5FFDF70BF197E1927D080C20EFADA5BF44764D7062609F62B8C878C9A66063C957837DEF9065E571E12F44AE02E0A023F1DF37E0F5AE70C5F2699654450C112AE96927D2E46AD1F2116885D40D0373BF5B9AC1B07D99B3EBB739EE4B9F9E369F83F5806AE6A528E8E373B512A83E2DE089F3C52C155C282A78D3D8F1BD9EDA5399D48476DE5F2074F4122504E003072BABEC347678E91B921D5B583DB4B4030BDC547E948CDFA07019B180823AF3C88AFB4954F239662614826C26E3D68B12270D0426418D0DD2815F8AA43E6DBC95CAD2B55E0F5438AD46806B3CD319430550317B7C80BC8DECCBCBC651C6AA00EAC9E514FB92188F49E48C74CF2A595D42BDEC4AC6A5229179C16760885168B18D5C5F86CD500BED77F5D4041C4AA244A1679682E9A62BBD5303A9811DA40AB7D5233B13F19A6C30F700C7D5C670CE4C14B7F7CBB6BD593029B4E55D4FC010171FAE640FF6D6FDDDFEA1E1A197B41369580A38FA6979EBA701F4BB00D8F6D4B24E180A532FB235F12003EBA74BBB329D68488BE399EC1066F768204388CAB27D2766E1E5502E3F690DEE57273951BB799F237FC0F1CE7AC404F64DF1238F352D70658755184E027D0BAD33616A821E1C8CA4F281D14A531D34113AD17D971A3D5E6B022725D395AD3F594277690C96877CD96FD1761E226E5D3A98F16F33E590EEF6CFDDF7A9E5D2A2288F4B5195BF3CF923229D617D4D594D5A76BB74E2A5558DEB44CDBAEF71ADDC3A4AF7D1570347FE0F7C715656061D0B8967D5B8147D13AF1A515C1E07EDE157BEBF8F73FD0AAF94B7F3695BADC3D5D81454BA9A19DED20969CB1EA356DAEA186D25EE563CED503EE3B0F4ACC8B59C2071F4D7454ED60083BEB7F33DD9E4975E85AA49A17ADD101DA612EC0D74CFF4B1E6616A8B7A7F7771AB0BFC956152F4679F3864BA08000F232F62F33D3328443505B5CB6F15EF4CDB365B1CBDF0D750DB39F49EF9BF31484CB79CA5F5AD334E7CAFFE7D7AFEC3E821DFEF387AA0677085941522EBF93D2414E9C1365B534555895B635F731E44480556ECD61DF5DD27794209066C7BB7814170E12C6E3EE938B3FF0984F1BACBCAB09DA34D015721B55E156A9276E2AB76C9B80886CA04B825BD140D1AC4C6CE873A4D38AD274F007E989FCA8BC3D05B19475B414A9C093ECA93BBBB45F8A4DD0360807ECFAE3A7DFD1B0AE736B7C17755A404E5FF6DB6B9A61B16A66A08BCE6D6C6AB31917A9EAA5E4715387A634F232CF90CC9AA9E1609F0E567516567EE1FDDC535FC5E5628E811B43C9993FCA6E4241913C2665E4E7A09AF46FF90659CDF0D022A30D253FCCDA2EE8F18714E1869DA71730AF568161AA0417E7A7B338D94BD85F5D6C30A5D0E6C38F5EFAAEC68D7D383D2529F7F696A3A061BE6FAB1EF8F2D7F91C6F10A7898C87BE2679F0CB3EFE5883AE4D954C5913FDED07FDF70A8AE16B2D11E8B0D8A73904388071E49997FF18766592B59EC2443B3C7C5B465508A40559D764CD499D8574992FC571F483B0A3BC8B28BEC0D042585435CA275875E0ED0E9E00BF401D0071769EF7345FF3F7A87DD10204D154422C7F182754DC9AA3CB764EA920329199FDEF60D8D85F5ABA944050A3A4824EC5032B67FFC7C56A591B2A2C3843617AF31B1C1C75E029093BBEC7374C98E79C21A0EFF8DBD15298173D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - byte[] generatedSig = Arrays.concatenate(sig, msg); - - assertTrue(Arrays.areEqual(expectedSig, generatedSig)); - - - // - // Round trip against the public key generated by the C version. - // - - QTESLAPublicKeyParameters qPub = new QTESLAPublicKeyParameters(QTESLASecurityCategory.PROVABLY_SECURE_I, publicKey); - - QTESLASigner verifier = new QTESLASigner(); - - verifier.init(false, qPub); - - assertTrue(verifier.verifySignature(msg, sig)); - assertFalse(verifier.verifySignature(Arrays.append(msg, (byte)0x00), sig)); - assertFalse(verifier.verifySignature(msg, Arrays.append(sig, (byte)0x00))); - } - - public void testSignQ3p() - throws Exception - { - // - // Values put in file because vectors exceeded length of string constant. - // - BufferedReader bin = new BufferedReader(new InputStreamReader(TestResourceFinder.findTestResource("pqc/crypto", "q3pIII.txt"))); - - byte[] seed = Hex.decode(bin.readLine()); - byte[] msg = Hex.decode(bin.readLine()); - byte[] publicKey = Hex.decode(bin.readLine()); - byte[] sk = Hex.decode(bin.readLine()); - byte[] sm = Hex.decode(bin.readLine()); - - bin.close(); - - - // - // Key generation. - // - - // - // The QTESLASecureRandomFactory.getFixedNoDiscard(...) is used so the same key values can be generated for a given seed - // for testing purposes. You MUST use a real SecureRandom instance in reality. - // - QTESLAKeyGenerationParameters keyGenerationParameters = new QTESLAKeyGenerationParameters(QTESLASecurityCategory.PROVABLY_SECURE_III, QTESLASecureRandomFactory.getFixedNoDiscard(seed, 256)); - QTESLAKeyPairGenerator keyGen = new QTESLAKeyPairGenerator(); - keyGen.init(keyGenerationParameters); - AsymmetricCipherKeyPair acp = keyGen.generateKeyPair(); - assertTrue(Arrays.areEqual(publicKey, ((QTESLAPublicKeyParameters)acp.getPublic()).getPublicData())); - assertTrue(Arrays.areEqual(sk, ((QTESLAPrivateKeyParameters)acp.getPrivate()).getSecret())); - - - QTESLAPrivateKeyParameters qPriv = new QTESLAPrivateKeyParameters(QTESLASecurityCategory.PROVABLY_SECURE_III, sk); - QTESLASigner signer = new QTESLASigner(); - - signer.init(true, new ParametersWithRandom(qPriv, QTESLASecureRandomFactory.getFixed(seed, 256))); - - byte[] sig = signer.generateSignature(msg); - - - // - // The expected sig from the C version is [sig][message] so to validate we need to append the message to our generated signature. - // - byte[] expectedSig = sm; - byte[] generatedSig = Arrays.concatenate(sig, msg); - - assertTrue(Arrays.areEqual(expectedSig, generatedSig)); - - - // - // Round trip against the public key generated by the C version. - // - - QTESLAPublicKeyParameters qPub = new QTESLAPublicKeyParameters(QTESLASecurityCategory.PROVABLY_SECURE_III, publicKey); - - QTESLASigner verifier = new QTESLASigner(); - - verifier.init(false, qPub); - - assertTrue(verifier.verifySignature(msg, sig)); - assertFalse(verifier.verifySignature(Arrays.append(msg, (byte)0x00), sig)); - assertFalse(verifier.verifySignature(msg, Arrays.append(sig, (byte)0x00))); - } - - public void testKATVectors() - throws Exception - { - String[] files = new String[]{ - "PQCsignKAT_qTesla-p-I.rsp", - "PQCsignKAT_qTesla-p-III.rsp", - }; - - for (int f = 0; f != files.length; f++) - { - String file = files[f]; - - List vectors = - new QTeslaKatParser(file, TestResourceFinder.findTestResource("pqc/crypto/qTeslaR2/KAT/ref", file)) - .parse("count"); - - TestCase.assertEquals(100, vectors.size()); - - int type; - - if (file.endsWith("qTesla-p-I.rsp")) - { - type = QTESLASecurityCategory.PROVABLY_SECURE_I; - } - else if (file.endsWith("qTesla-p-III.rsp")) - { - type = QTESLASecurityCategory.PROVABLY_SECURE_III; - } - else - { - throw new Exception("unable to determine file type for. " + file); - } - - for (int i = 0; i != vectors.size(); i++) - { - QTeslaKatVector vector = (QTeslaKatVector)vectors.get(i); - try - { - doTestKAT(type, vector.pk, vector.sk, vector.seed, vector.msg, vector.sm); - } - catch (Exception ex) - { - throw new Exception(file + " count =" + vector.count + " failed", ex); - } - } - } - } - - public static class QTeslaKatVector - { - final int count; - final byte[] seed; - final int mlen; - final byte[] msg; - final byte[] pk; - final byte[] sk; - final int smlen; - final byte[] sm; - - - QTeslaKatVector(Map parameters) - throws Exception - { - count = asInt(parameters, "count", -1).intValue(); - seed = asByteArray(parameters, "seed"); - mlen = asInt(parameters, "mlen", -1).intValue(); - msg = asByteArray(parameters, "msg"); - pk = asByteArray(parameters, "pk"); - sk = asByteArray(parameters, "sk"); - smlen = asInt(parameters, "smlen", -1).intValue(); - sm = asByteArray(parameters, "sm"); - } - - public boolean equals(Object o) - { - if (this == o) - { - return true; - } - if (o == null || getClass() != o.getClass()) - { - return false; - } - - QTeslaKatVector that = (QTeslaKatVector)o; - -// if (count != that.count) -// { -// return false; -// } - if (mlen != that.mlen) - { - return false; - } - if (smlen != that.smlen) - { - return false; - } - if (!Arrays.areEqual(seed, that.seed)) - { - return false; - } - if (!Arrays.areEqual(msg, that.msg)) - { - return false; - } - if (!Arrays.areEqual(pk, that.pk)) - { - return false; - } - if (!Arrays.areEqual(sk, that.sk)) - { - return false; - } - return Arrays.areEqual(sm, that.sm); - } - - public int hashCode() - { - int result;// = count; - result = Arrays.hashCode(seed);// 31 * result + java.util.Arrays.hashCode(seed); - result = 31 * result + mlen; - result = 31 * result + Arrays.hashCode(msg); - result = 31 * result + Arrays.hashCode(pk); - result = 31 * result + Arrays.hashCode(sk); - result = 31 * result + smlen; - result = 31 * result + Arrays.hashCode(sm); - return result; - } - } - - public static class QTeslaKatParser - { - - private final InputStream src; - private final String srcLabel; - - public QTeslaKatParser(String label, InputStream src) - { - this.src = src; - this.srcLabel = label; - } - - - public List parse(String blockDelimField) - throws Exception - { - - List vectors = new ArrayList(); - Map extractedParameters = new HashMap(); - BufferedReader bin = new BufferedReader(new InputStreamReader(src)); - Set duplicateTrap = new HashSet(); - - - String line = null; - - while ((line = bin.readLine()) != null) - { - line = line.trim(); - if (line.length() == 0 || line.startsWith("#")) - { - continue; - } - - - // - // Vector parameter. - // - if (line.indexOf('=') >= 0) - { - String[] kv = line.split("="); - - for (int t = 0; t < kv.length; t++) - { - kv[t] = kv[t].trim(); - } - - if (kv.length > 0) - { - if (!extractedParameters.isEmpty() && kv[0].equals(blockDelimField)) - { - QTeslaKatVector vector = new QTeslaKatVector(extractedParameters); - vectors.add(vector); - - if (duplicateTrap.contains(vector)) - { - throw new Exception("Duplicate Vector encountered, set : " + vector.count + " in " + srcLabel); - } - - duplicateTrap.add(vector); - - extractedParameters.clear(); - } - - if (kv.length > 1) - { - extractedParameters.put(kv[0], kv[1]); - } - else - { - extractedParameters.put(kv[0], null); - } - } - } - } - - // - // Trailing block. - // - if (!extractedParameters.isEmpty()) - { - vectors.add(new QTeslaKatVector(extractedParameters)); - } - - return vectors; - } - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/RainbowSignerTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/RainbowSignerTest.java deleted file mode 100644 index 00eed90fc2..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/RainbowSignerTest.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - - -import java.math.BigInteger; -import java.security.SecureRandom; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.digests.SHA224Digest; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.DigestingMessageSigner; -import org.bouncycastle.pqc.legacy.crypto.rainbow.RainbowKeyGenerationParameters; -import org.bouncycastle.pqc.legacy.crypto.rainbow.RainbowKeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.rainbow.RainbowParameters; -import org.bouncycastle.pqc.legacy.crypto.rainbow.RainbowSigner; -import org.bouncycastle.util.BigIntegers; -import org.bouncycastle.util.test.SimpleTest; - - -public class RainbowSignerTest -extends SimpleTest -{ - public String getName() - { - return "Rainbow"; - } - - public void performTest() - { - RainbowParameters params = new RainbowParameters(); - - RainbowKeyPairGenerator rainbowKeyGen = new RainbowKeyPairGenerator(); - RainbowKeyGenerationParameters genParam = new RainbowKeyGenerationParameters(new SecureRandom(), params); - - rainbowKeyGen.init(genParam); - - AsymmetricCipherKeyPair pair = rainbowKeyGen.generateKeyPair(); - - ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), new SecureRandom()); - - DigestingMessageSigner rainbowSigner = new DigestingMessageSigner(new RainbowSigner() , new SHA224Digest()); - - rainbowSigner.init(true, param); - - byte[] message = BigIntegers.asUnsignedByteArray(new BigInteger("968236873715988614170569073515315707566766479517")); - rainbowSigner.update(message, 0, message.length); - byte[] sig = rainbowSigner.generateSignature(); - - rainbowSigner.init(false, pair.getPublic()); - rainbowSigner.update(message, 0, message.length); - - if (!rainbowSigner.verifySignature(sig)) - { - fail("verification fails"); - } - } - - public static void main( - String[] args) - { - runTest(new RainbowSignerTest()); - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/RegressionTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/RegressionTest.java deleted file mode 100644 index d60a243c62..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/crypto/test/RegressionTest.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.bouncycastle.pqc.legacy.crypto.test; - -import org.bouncycastle.util.test.SimpleTest; -import org.bouncycastle.util.test.Test; - -public class RegressionTest -{ - public static Test[] tests = { - new GMSSSignerTest(), - new McElieceFujisakiCipherTest(), - new McElieceKobaraImaiCipherTest(), - new McElieceCipherTest(), - new McEliecePointchevalCipherTest(), - new RainbowSignerTest() , - }; - - public static void main(String[] args) - { - SimpleTest.runTests(tests); - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/test/AllTests.java b/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/test/AllTests.java deleted file mode 100644 index 4d303aa0bd..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/test/AllTests.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.euclid.test; - -import junit.extensions.TestSetup; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; -import org.bouncycastle.test.PrintTestResult; - -public class AllTests - extends TestCase -{ - public static void main (String[] args) - { - PrintTestResult.printResult(junit.textui.TestRunner.run(suite())); - } - - public static Test suite() - { - TestSuite suite = new TestSuite("NTRU Euclid Tests"); - - suite.addTestSuite(BigIntEuclideanTest.class); - suite.addTestSuite(IntEuclideanTest.class); - - return new BCTestSetup(suite); - } - - static class BCTestSetup - extends TestSetup - { - public BCTestSetup(Test test) - { - super(test); - } - - protected void setUp() - { - - } - - protected void tearDown() - { - - } - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/test/BigIntEuclideanTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/test/BigIntEuclideanTest.java deleted file mode 100644 index dc082a452b..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/test/BigIntEuclideanTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.euclid.test; - -import java.math.BigInteger; - -import junit.framework.TestCase; -import org.bouncycastle.pqc.legacy.math.ntru.euclid.BigIntEuclidean; - -public class BigIntEuclideanTest - extends TestCase -{ - public void testCalculate() - { - BigIntEuclidean r = BigIntEuclidean.calculate(BigInteger.valueOf(120), BigInteger.valueOf(23)); - assertEquals(BigInteger.valueOf(-9), r.x); - assertEquals(BigInteger.valueOf(47), r.y); - assertEquals(BigInteger.valueOf(1), r.gcd); - - r = BigIntEuclidean.calculate(BigInteger.valueOf(126), BigInteger.valueOf(231)); - assertEquals(BigInteger.valueOf(2), r.x); - assertEquals(BigInteger.valueOf(-1), r.y); - assertEquals(BigInteger.valueOf(21), r.gcd); - } -} \ No newline at end of file diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/test/IntEuclideanTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/test/IntEuclideanTest.java deleted file mode 100644 index 46d31a25fa..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/euclid/test/IntEuclideanTest.java +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2011 Tim Buktu (tbuktu@hotmail.com) - * - * 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, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - */ - -package org.bouncycastle.pqc.legacy.math.ntru.euclid.test; - -import junit.framework.TestCase; -import org.bouncycastle.pqc.legacy.math.ntru.euclid.IntEuclidean; - -public class IntEuclideanTest - extends TestCase -{ - public void testCalculate() - { - IntEuclidean r = IntEuclidean.calculate(120, 23); - assertEquals(-9, r.x); - assertEquals(47, r.y); - assertEquals(1, r.gcd); - - r = IntEuclidean.calculate(126, 231); - assertEquals(2, r.x); - assertEquals(-1, r.y); - assertEquals(21, r.gcd); - } -} \ No newline at end of file diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/AllTests.java b/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/AllTests.java deleted file mode 100644 index 197578615d..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/AllTests.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial.test; - -import junit.extensions.TestSetup; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; -import org.bouncycastle.test.PrintTestResult; - -public class AllTests - extends TestCase -{ - public static void main (String[] args) - { - PrintTestResult.printResult(junit.textui.TestRunner.run(suite())); - } - - public static Test suite() - { - TestSuite suite = new TestSuite("NTRU Polynomial Tests"); - - suite.addTestSuite(BigDecimalPolynomialTest.class); - suite.addTestSuite(BigIntPolynomialTest.class); - suite.addTestSuite(IntegerPolynomialTest.class); - suite.addTestSuite(LongPolynomial2Test.class); - suite.addTestSuite(LongPolynomial5Test.class); - suite.addTestSuite(ProductFormPolynomialTest.class); - suite.addTestSuite(SparseTernaryPolynomialTest.class); - - return new BCTestSetup(suite); - } - - static class BCTestSetup - extends TestSetup - { - public BCTestSetup(Test test) - { - super(test); - } - - protected void setUp() - { - - } - - protected void tearDown() - { - - } - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/BigDecimalPolynomialTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/BigDecimalPolynomialTest.java deleted file mode 100644 index e288306b79..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/BigDecimalPolynomialTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial.test; - -import java.math.BigDecimal; -import java.security.SecureRandom; - -import junit.framework.TestCase; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.BigDecimalPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.BigIntPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; - -public class BigDecimalPolynomialTest - extends TestCase -{ - public void testMult() - { - BigDecimalPolynomial a = new BigDecimalPolynomial(new BigIntPolynomial(new IntegerPolynomial(new int[]{4, -1, 9, 2, 1, -5, 12, -7, 0, -9, 5}))); - BigDecimalPolynomial b = new BigDecimalPolynomial(new BigIntPolynomial(new IntegerPolynomial(new int[]{-6, 0, 0, 13, 3, -2, -4, 10, 11, 2, -1}))); - BigDecimalPolynomial c = a.mult(b); - BigDecimal[] expectedCoeffs = new BigDecimalPolynomial(new BigIntPolynomial(new IntegerPolynomial(new int[]{2, -189, 77, 124, -29, 0, -75, 124, -49, 267, 34}))).getCoeffs(); - - BigDecimal[] cCoeffs = c.getCoeffs(); - - assertEquals(expectedCoeffs.length, cCoeffs.length); - for (int i = 0; i != cCoeffs.length; i++) - { - assertEquals(expectedCoeffs[i], cCoeffs[i]); - } - - // multiply a polynomial by its inverse modulo 2048 and check that the result is 1 - SecureRandom random = new SecureRandom(); - IntegerPolynomial d, dInv; - do - { - d = DenseTernaryPolynomial.generateRandom(1001, 333, 334, random); - dInv = d.invertFq(2048); - } - while (dInv == null); - - d.mod(2048); - BigDecimalPolynomial e = new BigDecimalPolynomial(new BigIntPolynomial(d)); - BigIntPolynomial f = new BigIntPolynomial(dInv); - IntegerPolynomial g = new IntegerPolynomial(e.mult(f).round()); - g.modPositive(2048); - assertTrue(g.equalsOne()); - } -} \ No newline at end of file diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/BigIntPolynomialTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/BigIntPolynomialTest.java deleted file mode 100644 index 83067d1543..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/BigIntPolynomialTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial.test; - -import java.math.BigInteger; - -import junit.framework.TestCase; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.BigIntPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; - -public class BigIntPolynomialTest - extends TestCase -{ - public void testMult() - { - BigIntPolynomial a = new BigIntPolynomial(new IntegerPolynomial(new int[]{4, -1, 9, 2, 1, -5, 12, -7, 0, -9, 5})); - BigIntPolynomial b = new BigIntPolynomial(new IntegerPolynomial(new int[]{-6, 0, 0, 13, 3, -2, -4, 10, 11, 2, -1})); - BigIntPolynomial c = a.mult(b); - BigInteger[] expectedCoeffs = new BigIntPolynomial(new IntegerPolynomial(new int[]{2, -189, 77, 124, -29, 0, -75, 124, -49, 267, 34})).getCoeffs(); - BigInteger[] cCoeffs = c.getCoeffs(); - - assertEquals(expectedCoeffs.length, cCoeffs.length); - for (int i = 0; i != cCoeffs.length; i++) - { - assertEquals(expectedCoeffs[i], cCoeffs[i]); - } - } -} \ No newline at end of file diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/IntegerPolynomialTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/IntegerPolynomialTest.java deleted file mode 100644 index 19cd065e47..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/IntegerPolynomialTest.java +++ /dev/null @@ -1,230 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial.test; - -import java.math.BigInteger; -import java.security.SecureRandom; - -import junit.framework.TestCase; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUSigningKeyGenerationParameters; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.BigIntPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.Resultant; -import org.bouncycastle.util.Arrays; - - -public class IntegerPolynomialTest - extends TestCase -{ - public void testMult() - { - // multiplication modulo q - IntegerPolynomial a = new IntegerPolynomial(new int[]{-1, 1, 1, 0, -1, 0, 1, 0, 0, 1, -1}); - IntegerPolynomial b = new IntegerPolynomial(new int[]{14, 11, 26, 24, 14, 16, 30, 7, 25, 6, 19}); - IntegerPolynomial c = a.mult(b, 32); - assertEqualsMod(new int[]{3, -7, -10, -11, 10, 7, 6, 7, 5, -3, -7}, c.coeffs, 32); - - a = new IntegerPolynomial(new int[]{15, 27, 18, 16, 12, 13, 16, 2, 28, 22, 26}); - b = new IntegerPolynomial(new int[]{-1, 0, 1, 1, 0, 1, 0, 0, -1, 0, -1}); - c = a.mult(b, 32); - assertEqualsMod(new int[]{8, 25, 22, 20, 12, 24, 15, 19, 12, 19, 16}, c.coeffs, 32); - - // multiplication without a modulus - a = new IntegerPolynomial(new int[]{1, 1, 0, 0, -1, -1, 0, 0, -1, 0, 1}); - b = new IntegerPolynomial(new int[]{704, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); - c = a.mult(b); - - // mult(p, modulus) should give the same result as mult(p) followed by modulus - a = new IntegerPolynomial(new int[]{1, 0, -1, 1, 0, 1, 1, 1, -1, 1, -1}); - b = new IntegerPolynomial(new int[]{0, 1, 1, 0, 0, -1, -1, 1, 1, -1, 1}); - c = a.mult(b); - c.modPositive(20); - IntegerPolynomial d = a.mult(b, 20); - d.modPositive(20); - assertTrue(Arrays.areEqual(c.coeffs, d.coeffs)); - } - - void assertEqualsMod(int[] arr1, int[] arr2, int m) - { - assertEquals(arr1.length, arr2.length); - for (int i = 0; i < arr1.length; i++) - { - assertEquals((arr1[i] + m) % m, (arr2[i] + m) % m); - } - } - - public void testInvertFq() - { - SecureRandom random = new SecureRandom(); - // Verify an example from the NTRU tutorial - IntegerPolynomial a = new IntegerPolynomial(new int[]{-1, 1, 1, 0, -1, 0, 1, 0, 0, 1, -1}); - IntegerPolynomial b = a.invertFq(32); - assertEqualsMod(new int[]{5, 9, 6, 16, 4, 15, 16, 22, 20, 18, 30}, b.coeffs, 32); - verifyInverse(a, b, 32); - - // test 3 random polynomials - int numInvertible = 0; - while (numInvertible < 3) - { - a = DenseTernaryPolynomial.generateRandom(853, random); - b = a.invertFq(2048); - if (b != null) - { - numInvertible++; - verifyInverse(a, b, 2048); - } - } - - // test a non-invertible polynomial - a = new IntegerPolynomial(new int[]{-1, 0, 1, 1, 0, 0, -1, 0, -1, 0, 1}); - b = a.invertFq(32); - assertNull(b); - } - - public void testInvertF3() - { - IntegerPolynomial a = new IntegerPolynomial(new int[]{-1, 1, 1, 0, -1, 0, 1, 0, 0, 1, -1}); - IntegerPolynomial b = a.invertF3(); - assertEqualsMod(new int[]{1, 2, 0, 2, 2, 1, 0, 2, 1, 2, 0}, b.coeffs, 3); - verifyInverse(a, b, 3); - - // test a non-invertible polynomial - a = new IntegerPolynomial(new int[]{0, 1, -1, 1, 0, 0, 0, 0, -1, 0, 0}); - b = a.invertF3(); - assertNull(b); - } - - // tests if a*b=1 (mod modulus) - private void verifyInverse(IntegerPolynomial a, IntegerPolynomial b, int modulus) - { - IntegerPolynomial c = a.mult(b, modulus); - for (int i = 1; i < c.coeffs.length; i++) - { - c.coeffs[i] %= modulus; - } - c.ensurePositive(modulus); - assertTrue(c.equalsOne()); - } - - public void testFromToBinary() - { - byte[] a = new byte[]{-44, -33, 30, -109, 101, -28, -6, -105, -45, 113, -72, 99, 101, 15, 9, 49, -80, -76, 58, 42, -57, -113, -89, -14, -125, 24, 125, -16, 37, -58, 10, -49, -77, -31, 120, 103, -29, 105, -56, -126, -92, 36, 125, 127, -90, 38, 9, 4, 104, 10, -78, -106, -88, -1, -1, -43, -19, 90, 41, 0, -43, 102, 118, -72, -122, 19, -76, 57, -59, -2, 35, 47, 83, 114, 86, -115, -125, 58, 75, 115, -29, -6, 108, 6, -77, -51, 127, -8, -8, -58, -30, -126, 110, -5, -35, -41, -37, 69, 22, -48, 26, 4, -120, -19, -32, -81, -77, 124, -7, -2, -46, -96, 38, -35, 88, 4, -5, 16, 101, 29, 7, 2, 88, 35, -64, 31, -66, -70, 120, -97, 76, -74, -97, -61, 52, -56, 87, -35, 5, 95, -93, -30, 10, 38, 17, -102, -25, 86, 7, -43, 44, -52, -108, 33, -18, -110, -9, -115, 66, -71, 66, 1, -90, -72, 90, -88, -38, 75, 47, -124, -120, -15, -49, -8, 85, 5, 17, -88, 76, 99, -4, 83, 16, -91, 82, 116, 112, -83, 56, -45, -26, 125, 13, -75, -115, 92, -12, -59, 3, -12, 14, -6, 43, -17, 121, 122, 22, 92, -74, 99, -59, -103, 113, 8, -103, 114, 99, -48, 92, -88, 77, 81, 5, 31, -4, -69, -24, 23, 94, 126, 71, 93, 20, 77, 82, -54, -14, 86, 45, -81, 0, 52, -63, -66, 48, 104, -54, 15, -73, -2, -52, 115, 76, 28, -5, -94, -63, 117, -69, 0, 61, 22, -1, 71, -115, 9, -73, -100, -128, -31, 106, -74, -61, -37, 98, -6, 11, -5, 6, -18, -53, -6, 11, -49, 62, 23, 6, -128, 38, -91, 89, -34, 18, -38, -110, -101, 43, 36, 62, 101, 112, 59, -91, 78, -81, 61, 126, -21, -42, -110, -38, -27, 69, 57, 9, 24, -50, -118, 31, -17, 42, 87, -54, 122, -16, 42, -47, -19, -80, 16, 54, -97, -89, 81, -22, -35, 45, 54, -46, 22, -122, -95, -17, 7, -127, 105, -100, -56, -98, -105, 101, -81, 104, 121, -7, 33, 126, 110, -125, -85, 111, -52, 123, -98, 41, -42, 88, -68, -17, 39, -19, -96, -10, -117, 13, -88, -75, -101, -16, -7, 73, 23, -12, 41, -116, -105, -64, -4, 103, 49, -15, -49, 60, 88, -25, -21, 42, 26, 95, -90, -83, -69, 64, -2, 50, -116, -64, 26, -29, -93, -120, -70, 32, -38, 39, -126, -19, 103, 127, 65, 54, 110, 94, 126, -82, -80, -18, 43, 45, 56, -118, 109, 36, -8, 10, 113, 69, 53, -122, -127, 92, -127, -73, 70, -19, -105, -80, -15, -5, 99, -109, -27, 119, -76, -57, -48, 42, -35, 23, 39, -126, 44, -107, -100, -125, 117, -50, 115, -79, -16, 104, 8, -102, 83, -73, 21, -85, 113, -87, -54, 93, 63, -108, -64, 109, -74, 15, 14, -119, -6, -68, 45, 37, -15, -97, -95, -55, 89, 25, -63, -92, -80, -27, -8, 55, 50, 96, -91, 40, -74, 110, -96, 94, 6, 85, 92, 0, 34, -122, 5, -126, 123, 37, -90, -94, 60, 14, 36, 49, -98, -23, 57, 75, 63, 106, -7, -36, -89, 84, 71, 60, -21, 104, -47, 90, -52, -66, 88, -91, -81, -3, 116, 23, 62, -47, -84, -118, 65, 31, 7, -103, 37, -29, 115, -114, 73, 12, -121, 96, -91, -7, 56, 10, -72, 27, -45, 122, -27, -38, 74, 64, 30, -60, 64, -21, 48, 101, 113, 126, -60, -103, 71, 100, -117, 124, -125, 116, 78, 114, -74, 42, -81, -54, 34, 33, -10, 19, 23, 24, 40, 0, -8, 78, 100, 73, -88, -95, -62, -115, -18, 47, 10, -14, -39, 82, 27, -9, -115, -70, 92, -6, 39, 45, -71, -109, -41, 94, -88, -63, 19, -58, -37, -31, 1, 127, -42, 125, -120, -57, 120, -86, -6, 17, -27, -37, 47, 55, -22, -11, -31, 38, -1, 29, 56, -34, -104, -66, -62, 72, -11, -30, -30, 61, -31, 10, -63, 116, -84, 118, -127, 6, 17, -36, 91, 123, 77, 35, 22, 110, 114, 107, -3, 52, 11, 86, 68, -56, 0, 119, -43, -73, 112, 89, -4, -122, -71, -26, 103, -118, -61, -112, -108, -44, -25, -22, 4, 24, 53, -5, -71, 9, -41, 84, -28, 22, 99, 39, -26, -2, -51, 68, 63, -15, 99, 66, -78, 46, -89, 21, -38, -114, -51, 100, -59, 84, -76, -105, 51, 28, 19, 74, 42, 91, -73, 12, -89, -128, 34, 38, -100, 121, -78, 114, -28, 127, -29, 50, 105, -6, 36, 98, -35, 79, -58, 5, -13, -86, -101, -108, -99, -70, 25, 103, 63, 57, 79, -12, -63, 125, -54, 61, 15, 6, -79, 90, 76, 103, -45, 7, 39, 93, 107, 58, 76, 80, 56, -108, 55, -22, 36, 125, -91, -65, 11, 69, 10, -19, -14, -4, -26, -36, 114, 124, 63, -31, 88, 92, 108, 33, -52, -22, 80, -65, 57, 126, 43, -13, 122, -8, 68, 72, 92, -50, 100, -91, 1, -81, 75, 95, -11, -99, 38, 121, -20, -70, 82, -125, -94, -18, 16, 59, 89, 18, -96, 91, -97, 62, -96, 127, 45, 70, 16, 84, -43, -75, -118, 81, 58, 84, -115, -120, -3, 41, -103, -70, 123, 26, 101, 33, 58, 13, -11, -73, -84, -47, -7, 81, -63, 60, -45, 30, 100, -51, -15, 73, 58, -119, -3, 62, -63, -17, -69, -44, 60, -54, -115, -59, 23, -59, 98, -89, -72, 20, -96, 27, 53, -89, 59, -85, -29, 120, 23, 62, 8, -86, 113, 87, -15, 102, 106, -104, 57, -57, 37, 110, 118, 109, 25, 64, 26, -20, -86, -2, 60, -70, -33, 67, 13, -28, -29, -63, -37, 67, 99, 84, 121, -126, -38, 45, 24, 122, 51, 11, -19, -80, 26, -106, -95, 82, 69, -2, -75, 62, 106, -120, 87, -107, 87, 17, 102, -52, -16, 22, 12, -86, -48, -95, -61, 109, 64, -29, 111, 40, -90, -35, 49, 88, -15, 122, 127, 87, 113, 116, 93, 100, 28, -70, -87, -40, -1, -126, -114, 7, 79, 16, 2, -47, -98, -102, 49, 58, 61, -32, 44, 18, -26, 37, 27, -123, -76, 56, 91, 51, -21, -48, -122, -33, 40, -8, -62, -56, -126, 91, -51, 76, -29, 127, -22, -18, -110, 27, 13, -111, 81, 51, -104, 70, 98, 12, 120, -7, 15, 104, -43, -104, 124, 46, 116, 7, -26, 21, 33, 105, 17, -99, -42, -106, 8, -85, 39, 8, 79, -54, -81, 109, 40, 25, 29, -18, -90, 22, 85, -12, -16, 61, 49, -31, 127, 64, 5, 25, 39, -65, -42, 13, -97, -92, 36, -126, -18, -4, -22, -14, 109, -93, -76, -5, 13, 74, 44, 103, 79, 110, 85, 58, 39, -24, 119, 120, 122, 120, 43, 110, 67, 21, 47, 39, -48, 7, 91, -51, 126, 100, -38, -124, 0, -97, 99, -123, 118, -27, 8, 102, -106, -23, -53, -4, -56, -9, -126, -85, 93, -4, -5, 4, 49, 29, 2, 63, 78, -32, -106, 118, 111, 52, 54, 74, 53, 106, 39, -95, -38, -18, 118, -5, 94, -83, -97, -27, 62, -56, -90, -36, 43, 43, -113, 119, -89, 44, -108, -46, 66, 28, 66, -38, 3, -62, -83, -35, -127, -2, 51, 104, 105, 40, 76, -10, -124, -95, 52, 11, 101, -32, -122, -73, -17, 37, -126, 68, -126, 55, 112, -126, 38, 99, -63, 123, -74, -31, 58, 8, 93, -68, 111, -22, -24, -23, 9, -87, -25, -115, 81, -116, -91, 60, 96, -102, -1, -7, 73, 99, 46, -78, 62, 48, -116, -52, -44, -5, 82, -45, 5, -55, -101, 101, 65, -109, -108, 26, 98, -55, 11, -86, 57, 30, 92, -58, 20, 82, 65, 103, 27, -64, 76, 123, -56, -16, -111, -83, 125, 65, 111, 9, 123, 14, 119, 126, -80, 79, 94, -19, 66, -25, 35, 112, -64, 10, -66, -86, 51, 56, -78, 103, 92, -116, 8, 75, 41, -49, -79, -53, 125, -32, -76, -27, 59, -8, -4, -94, -104, -15, 79, -7, -124, 32, -87, -104, 85, -118, -36, 125, 65, 111, -105, 5, -105, 40, -50, 2, 118, 123, -54, 59, -22, 94, 20, 99, -87, -27, 28, -30, -109, 72, -19, 92, 60, 19, 115, 47, 96, -96, 10, -74, 60, 96, -86, 101, 101, 68, -44, -72, 9, -36, 126, 96, -45, -12, 9, 14, -15, 79, -79, -48, 8, -107, -81, 47, 35, -36, -107, -120, -36, -124, 37, 103, -60, -35, -74, 100, -38, -88, -99, -99, -94, -107, 79, 115, 108, 54, 119, 73, 84, 110, -74, 92, 57, 108, 80, 47, -36, -119, -115, 58, -62, -4, -97, 43, -98, 5, 112, 47, 59, -89, 82, -69, -103, 39, -29, 75, -9, -94, -72, 99, -64, 22, -10, 21, 89, 101, 21, 94, -30, -17, 73, -36, -68, -89, -91, -94, 99, -106, 119, -116, 123, -19, 54, -99, 64, -119, 82, 120, -106, -99, 80, 69, 29, -48, 77, 28, 13, 92, -107, -77, 94, -116, 108, 89, -115, 96, -41, 25, 99, -65, 118, -5, -16, 48, -122, 5, 50, -123, -115, 13, 24, 7, 15, -103, -62, -71, 92, -82, -5, -70, 49, -6, -51, -17, -47, 12, 46, -86, 30, 93, 84, -101, 43, -92, -87, -118, -110, -32, 52, 115, -4, 36, -2, -79, -69, -46, -110, 70, -82, 6, 21, -27, -11, 94, 42, -81, -96, 116, -102, -38, 36, 32, 91, 28, 80, -45, 116, -94, -33, -5, -102, 64, -96, 27, -2, 100, -126, 59, -71, 33, -36, -124, 123, 99, -76, 108, 127, -11, -24, -19, 84, -6, 19, 105, -19, -18, 120, -14, 23, 39, 54, 87, 105, 58, -95, -15, 127, -65, 114, 49, 4, -66, 32, -7, 84, 43, -103, 76, 11, 36, -68, -3, -98, -5, -43, 35, -48, 20, -40, -33, -123, 1, -54, -44, 99, -68, 8, -100, 97, -49, -10, 110, 49, 84, 46, -85, 98, -103, -58, -4, 104, -100, -40, -79, 67, -20, -95, 85, 51, 73, 10, -25, 102, 68, -97, -83, -39, 35, 2, -111, 71, 62, -89, 20, 25, -126, 17, -81, -29, 39, -27, -55, 55, -122, 97, 23, -99, 55, 86, 33, -9, 8, 55, -40, -84, 39, 38, 37, -29, 87, 113, -118, -26, 123, -95, 24, -126, 119, -94, 17, 83, -43, 10, 63, -98, 72, 8, 16, -95, -96, 119, -91, 6, 71, -60, 1, -77, 4, 53, -121, 55, 7, 36, -86, -49, -118, -121, 56, 84, -49, -57, -99, 3, -68, 37, -108, -72, 114, -74, 120, 3, 121, -28, -106, 54, -20, 63, -121, -85, -59, -111, 32, 13, -69, 122, 90, 5, 40, 88, 15, -90, 125, -28, 89, 95, 73, 96, 60, -60, -51, 102, 7, 57, 91, 59, 15, 92, -76, -34, -23, -77, 90, 45, 91, 77, -63, 94, -127, 74, -97, -44, 50, -87, -94, -25, -71, 112, 127, -117, 6, 32, -113, 54, 83, -31, 111, -73, 53, 34, -32, -98, 125, -39, 63, 15, 72, -69, 87, -118, 108, 17, 84, 15, 61, -47, 54, -24, -79, 91, 28, -28, 66, 53, 22, 9, -28, -12, 38, 64, 75, -122, 96, -59, -45, 4, -19, 47, -30, 75, -94, 62, -64, 76, -49, 19, -66, -34, 3, 84, -2, -54, 13, -84, 86, -117, 94, -27, 89, 16, 96, 52, -77, -36, -116, 27, -52, -33, -50, 14, -59, 77, 93, -109, 8, -89, 81, -114, -29, -94, 73, -119, -56, -19, 88, -17, -33, 125, -18, -68, 113, 40, -128, -112, -119, -106, -106, -30, 23, -77, 49, 3, 98, -101, 99, -107, -121, -12, -112, 24, -74, -74, 79, -17, 96, 65, -52, 86, -63, 45, 84, 119, -42, 61, -91, 29, -87, 65, -85, 99, -14, 71, 33, -41, -48, -2, -121, 78, -38, 41, -7, -37, 48, 122, 61, -124, 42, -22, 24, 2, -49, 74, -81, -88, -89, -107, 109, 53, -68, 90, -117, 123, -109, -28, 12, 80, 120, 26, -104, 73, 70, -36, 34, -80, -104, 23, 16, 14, -96, -5, 27, 71, 25, -8, -125, 58, 88, -52, -97, -97, -93, 11, -44, 116, 42, -102, -100, -31, -86, 71, 84, 70, 27, 117, -67, 92, -84, -13, 54, -102, 34, 5, 19, -76, 71, 89, 22, -49, -34, -29}; - IntegerPolynomial poly = IntegerPolynomial.fromBinary(a, 1499, 2048); - byte[] b = poly.toBinary(2048); - // verify that bytes 0..2047 match, ignore non-relevant bits of byte 2048 - assertTrue(Arrays.areEqual(copyOf(a, 2047), copyOf(b, 2047))); - assertEquals((a[a.length - 1] & 1) >> (7 - (1499 * 11) % 8), (b[b.length - 1] & 1) >> (7 - (1499 * 11) % 8)); - } - - public void testFromToBinary3Sves() - { - byte[] a = new byte[]{-112, -78, 19, 15, 99, -65, -56, -90, 44, -93, -109, 104, 40, 90, -84, -21, -124, 51, -33, 4, -51, -106, 33, 86, -76, 42, 41, -17, 47, 79, 81, -29, 15, 116, 101, 120, 116, 32, 116, 111, 32, 101, 110, 99, 114, 121, 112, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - IntegerPolynomial poly = IntegerPolynomial.fromBinary3Sves(a, 1499); - byte[] b = poly.toBinary3Sves(); - assertTrue(Arrays.areEqual(a, b)); - } - - public void testFromToBinary3Tight() - { - int[] c = new int[]{0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 1, 0, 1, 0, -1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0}; - IntegerPolynomial poly1 = new IntegerPolynomial(c); - IntegerPolynomial poly2 = IntegerPolynomial.fromBinary3Tight(poly1.toBinary3Tight(), c.length); - assertTrue(Arrays.areEqual(poly1.coeffs, poly2.coeffs)); - - IntegerPolynomial poly3 = new IntegerPolynomial(new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0}); - byte[] arr = poly3.toBinary3Tight(); - IntegerPolynomial poly4 = IntegerPolynomial.fromBinary3Tight(arr, 1499); - assertTrue(Arrays.areEqual(poly3.coeffs, poly4.coeffs)); - - IntegerPolynomial poly5 = new IntegerPolynomial(new int[]{0, 0, 0, 1, -1, -1, -1}); - arr = poly5.toBinary3Tight(); - IntegerPolynomial poly6 = IntegerPolynomial.fromBinary3Tight(arr, 7); - assertTrue(Arrays.areEqual(poly5.coeffs, poly6.coeffs)); - - SecureRandom random = new SecureRandom(); - - for (int i = 0; i < 100; i++) - { - IntegerPolynomial poly7 = DenseTernaryPolynomial.generateRandom(157, random); - arr = poly7.toBinary3Tight(); - IntegerPolynomial poly8 = IntegerPolynomial.fromBinary3Tight(arr, 157); - assertTrue(Arrays.areEqual(poly7.coeffs, poly8.coeffs)); - } - } - - public void testResultant() - { - SecureRandom random = new SecureRandom(); - NTRUSigningKeyGenerationParameters params = NTRUSigningKeyGenerationParameters.APR2011_439; - IntegerPolynomial a = DenseTernaryPolynomial.generateRandom(params.N, params.d, params.d, random); - verifyResultant(a, a.resultant()); - - a = new IntegerPolynomial(new int[]{0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 1, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, -1, -1, 0, -1, 1, -1, 0, -1, 0, -1, -1, -1, 0, 0, 0, 1, 1, -1, -1, -1, 0, -1, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 1, 1, -1, 0, 1, -1, 0, 1, 0, 1, 0, -1, -1, 0, 1, 0, -1, 1, 1, 1, 1, 0, 0, -1, -1, 1, 0, 0, -1, -1, 0, -1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 1, 0, 1, -1, 0, 0, 1, 1, 1, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0, -1, -1, 0, -1, -1, -1, 0, -1, -1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, -1, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, -1, -1, 0, -1, -1, 1, 1, 0, 0, -1, 1, 0, 0, 0, -1, 1, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, 1, 1, 0, 0, -1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, -1, 0, 1, 0, -1, -1, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 1, -1, 1, -1, -1, 1, -1, 0, 1, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, -1, 0, 1, -1, 0, 0, 1, 1, 0, 0, 1, 1, 0, -1, 0, -1, 1, -1, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, 1, -1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, -1, -1, 0, 0, -1, 0, 1, 1, -1, 1, -1, 0, 0, 0, 1}); - verifyResultant(a, a.resultant()); - } - - // verifies that res=rho*a mod x^n-1 - private void verifyResultant(IntegerPolynomial a, Resultant r) - { - BigIntPolynomial b = new BigIntPolynomial(a).mult(r.rho); - BigInteger[] bCoeffs = b.getCoeffs(); - - for (int j = 1; j < bCoeffs.length - 1; j++) - { - assertEquals(BigInteger.ZERO, bCoeffs[j]); - } - if (r.res.equals(BigInteger.ZERO)) - { - assertEquals(BigInteger.ZERO, bCoeffs[0].subtract(bCoeffs[bCoeffs.length - 1])); - } - else - { - assertEquals(BigInteger.ZERO, (bCoeffs[0].subtract(bCoeffs[bCoeffs.length - 1]).mod(r.res))); - } - assertEquals(bCoeffs[0].subtract(r.res), bCoeffs[bCoeffs.length - 1].negate()); - } - - public void testResultantMod() - { - int p = 46337; // prime; must be less than sqrt(2^31) or integer overflows will occur - - IntegerPolynomial a = new IntegerPolynomial(new int[]{0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 1, -1, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, -1, -1, 0, -1, 1, -1, 0, -1, 0, -1, -1, -1, 0, 0, 0, 1, 1, -1, -1, -1, 0, -1, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 0, 0, 1, 1, -1, 0, 1, -1, 0, 1, 0, 1, 0, -1, -1, 0, 1, 0, -1, 1, 1, 1, 1, 0, 0, -1, -1, 1, 0, 0, -1, -1, 0, -1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 1, 0, 1, -1, 0, 0, 1, 1, 1, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0, -1, -1, 0, -1, -1, -1, 0, -1, -1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, -1, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, -1, -1, 0, -1, -1, 1, 1, 0, 0, -1, 1, 0, 0, 0, -1, 1, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, 1, 1, 0, 0, -1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, -1, 0, 1, 0, -1, -1, 0, 0, 0, 0, 0, 1, -1, 0, 0, 0, 1, -1, 1, -1, -1, 1, -1, 0, 1, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, -1, 0, 1, -1, 0, 0, 1, 1, 0, 0, 1, 1, 0, -1, 0, -1, 1, -1, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, -1, 0, 0, 1, -1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 1, 0, -1, -1, 0, 0, -1, 0, 1, 1, -1, 1, -1, 0, 0, 0, 1}); - verifyResultant(a, a.resultant(p), p); - - SecureRandom random = new SecureRandom(); - - for (int i = 0; i < 10; i++) - { - a = DenseTernaryPolynomial.generateRandom(853, random); - verifyResultant(a, a.resultant(p), p); - } - } - - // verifies that res=rho*a mod x^n-1 mod p - private void verifyResultant(IntegerPolynomial a, Resultant r, int p) - { - BigIntPolynomial b = new BigIntPolynomial(a).mult(r.rho); - b.mod(BigInteger.valueOf(p)); - BigInteger[] bCoeffs = b.getCoeffs(); - - for (int j = 1; j < bCoeffs.length - 1; j++) - { - assertEquals(BigInteger.ZERO, bCoeffs[j]); - } - if (r.res.equals(BigInteger.ZERO)) - { - assertEquals(BigInteger.ZERO, bCoeffs[0].subtract(bCoeffs[bCoeffs.length - 1])); - } - else - { - assertEquals(BigInteger.ZERO, (bCoeffs[0].subtract(bCoeffs[bCoeffs.length - 1]).subtract(r.res).mod(BigInteger.valueOf(p)))); - } - assertEquals(BigInteger.ZERO, bCoeffs[0].subtract(r.res).subtract(bCoeffs[bCoeffs.length - 1].negate()).mod(BigInteger.valueOf(p))); - } - - private byte[] copyOf(byte[] src, int length) - { - byte[] tmp = new byte[length]; - System.arraycopy(src, 0, tmp, 0, tmp.length); - return tmp; - } -} \ No newline at end of file diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/LongPolynomial2Test.java b/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/LongPolynomial2Test.java deleted file mode 100644 index b31d38a082..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/LongPolynomial2Test.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial.test; - -import java.util.Random; - -import junit.framework.TestCase; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.LongPolynomial2; -import org.bouncycastle.util.Arrays; - -public class LongPolynomial2Test - extends TestCase -{ - public void testMult() - { - IntegerPolynomial i1 = new IntegerPolynomial(new int[]{1368, 2047, 672, 871, 1662, 1352, 1099, 1608}); - IntegerPolynomial i2 = new IntegerPolynomial(new int[]{1729, 1924, 806, 179, 1530, 1381, 1695, 60}); - LongPolynomial2 a = new LongPolynomial2(i1); - LongPolynomial2 b = new LongPolynomial2(i2); - IntegerPolynomial c1 = i1.mult(i2, 2048); - IntegerPolynomial c2 = a.mult(b).toIntegerPolynomial(); - assertTrue(Arrays.areEqual(c1.coeffs, c2.coeffs)); - - // test 10 random polynomials - Random rng = new Random(); - for (int i = 0; i < 10; i++) - { - int N = 2 + rng.nextInt(2000); - i1 = PolynomialGenerator.generateRandom(N, 2048); - i2 = PolynomialGenerator.generateRandom(N, 2048); - a = new LongPolynomial2(i1); - b = new LongPolynomial2(i2); - c1 = i1.mult(i2); - c1.modPositive(2048); - c2 = a.mult(b).toIntegerPolynomial(); - assertTrue(Arrays.areEqual(c1.coeffs, c2.coeffs)); - } - } - - public void testSubAnd() - { - IntegerPolynomial i1 = new IntegerPolynomial(new int[]{1368, 2047, 672, 871, 1662, 1352, 1099, 1608}); - IntegerPolynomial i2 = new IntegerPolynomial(new int[]{1729, 1924, 806, 179, 1530, 1381, 1695, 60}); - LongPolynomial2 a = new LongPolynomial2(i1); - LongPolynomial2 b = new LongPolynomial2(i2); - a.subAnd(b, 2047); - i1.sub(i2); - i1.modPositive(2048); - assertTrue(Arrays.areEqual(a.toIntegerPolynomial().coeffs, i1.coeffs)); - } - - public void testMult2And() - { - IntegerPolynomial i1 = new IntegerPolynomial(new int[]{1368, 2047, 672, 871, 1662, 1352, 1099, 1608}); - LongPolynomial2 i2 = new LongPolynomial2(i1); - i2.mult2And(2047); - i1.mult(2); - i1.modPositive(2048); - assertTrue(Arrays.areEqual(i1.coeffs, i2.toIntegerPolynomial().coeffs)); - } -} \ No newline at end of file diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/LongPolynomial5Test.java b/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/LongPolynomial5Test.java deleted file mode 100644 index 4a77d0263b..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/LongPolynomial5Test.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial.test; - -import java.security.SecureRandom; - -import junit.framework.TestCase; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.LongPolynomial5; -import org.bouncycastle.util.Arrays; - -public class LongPolynomial5Test - extends TestCase -{ - public void testMult() - { - testMult(new int[]{2}, new int[]{-1}); - testMult(new int[]{2, 0}, new int[]{-1, 0}); - testMult(new int[]{2, 0, 3}, new int[]{-1, 0, 1}); - testMult(new int[]{2, 0, 3, 1}, new int[]{-1, 0, 1, 1}); - testMult(new int[]{2, 0, 3, 1, 2}, new int[]{-1, 0, 1, 1, 0}); - testMult(new int[]{2, 0, 3, 1, 1, 5}, new int[]{1, -1, 1, 1, 0, 1}); - testMult(new int[]{2, 0, 3, 1, 1, 5, 1, 4}, new int[]{1, 0, 1, 1, -1, 1, 0, -1}); - testMult(new int[]{1368, 2047, 672, 871, 1662, 1352, 1099, 1608}, new int[]{1, 0, 1, 1, -1, 1, 0, -1}); - - // test random polynomials - SecureRandom rng = new SecureRandom(); - for (int i = 0; i < 10; i++) - { - int[] coeffs1 = new int[rng.nextInt(2000) + 1]; - int[] coeffs2 = DenseTernaryPolynomial.generateRandom(coeffs1.length, rng).coeffs; - testMult(coeffs1, coeffs2); - } - } - - private void testMult(int[] coeffs1, int[] coeffs2) - { - IntegerPolynomial i1 = new IntegerPolynomial(coeffs1); - IntegerPolynomial i2 = new IntegerPolynomial(coeffs2); - - LongPolynomial5 a = new LongPolynomial5(i1); - DenseTernaryPolynomial b = new DenseTernaryPolynomial(i2); - IntegerPolynomial c1 = i1.mult(i2, 2048); - IntegerPolynomial c2 = a.mult(b).toIntegerPolynomial(); - assertEqualsMod(c1.coeffs, c2.coeffs, 2048); - } - - private void assertEqualsMod(int[] arr1, int[] arr2, int m) - { - assertEquals(arr1.length, arr2.length); - for (int i = 0; i < arr1.length; i++) - { - assertEquals((arr1[i] + m) % m, (arr2[i] + m) % m); - } - } - - public void testToIntegerPolynomial() - { - int[] coeffs = new int[]{2, 0, 3, 1, 1, 5, 1, 4}; - LongPolynomial5 p = new LongPolynomial5(new IntegerPolynomial(coeffs)); - assertTrue(Arrays.areEqual(coeffs, p.toIntegerPolynomial().coeffs)); - } -} \ No newline at end of file diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/PolynomialGenerator.java b/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/PolynomialGenerator.java deleted file mode 100644 index 4131d75337..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/PolynomialGenerator.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial.test; - -import java.util.Random; - -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; - -public class PolynomialGenerator -{ - /** - * Creates a random polynomial with N coefficients - * between 0 and q-1. - * - * @param N length of the polynomial - * @param q coefficients will all be below this number - * @return a random polynomial - */ - public static IntegerPolynomial generateRandom(int N, int q) - { - Random rng = new Random(); - int[] coeffs = new int[N]; - for (int i = 0; i < N; i++) - { - coeffs[i] = rng.nextInt(q); - } - return new IntegerPolynomial(coeffs); - } -} \ No newline at end of file diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/ProductFormPolynomialTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/ProductFormPolynomialTest.java deleted file mode 100644 index 1e1394a867..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/ProductFormPolynomialTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial.test; - -import java.security.SecureRandom; - -import junit.framework.TestCase; -import org.bouncycastle.pqc.legacy.crypto.ntru.NTRUEncryptionKeyGenerationParameters; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.ProductFormPolynomial; - -public class ProductFormPolynomialTest - extends TestCase -{ - private NTRUEncryptionKeyGenerationParameters params; - private int N; - private int df1; - private int df2; - private int df3; - private int q; - - public void setUp() - { - params = NTRUEncryptionKeyGenerationParameters.APR2011_439_FAST; - N = params.N; - df1 = params.df1; - df2 = params.df2; - df3 = params.df3; - q = params.q; - } - - public void testFromToBinary() - throws Exception - { - ProductFormPolynomial p1 = ProductFormPolynomial.generateRandom(N, df1, df2, df3, df3 - 1, new SecureRandom()); - byte[] bin1 = p1.toBinary(); - ProductFormPolynomial p2 = ProductFormPolynomial.fromBinary(bin1, N, df1, df2, df3, df3 - 1); - assertEquals(p1, p2); - } - - public void testMult() - { - ProductFormPolynomial p1 = ProductFormPolynomial.generateRandom(N, df1, df2, df3, df3 - 1, new SecureRandom()); - IntegerPolynomial p2 = PolynomialGenerator.generateRandom(N, q); - IntegerPolynomial p3 = p1.mult(p2); - IntegerPolynomial p4 = p1.toIntegerPolynomial().mult(p2); - assertEquals(p3, p4); - } -} \ No newline at end of file diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/SparseTernaryPolynomialTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/SparseTernaryPolynomialTest.java deleted file mode 100644 index fb9cf7f868..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/polynomial/test/SparseTernaryPolynomialTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.polynomial.test; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.security.SecureRandom; - -import junit.framework.TestCase; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.BigIntPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.IntegerPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.SparseTernaryPolynomial; - -public class SparseTernaryPolynomialTest - extends TestCase -{ - - /** - * tests mult(IntegerPolynomial) and mult(BigIntPolynomial) - */ - public void testMult() - { - SecureRandom random = new SecureRandom(); - SparseTernaryPolynomial p1 = SparseTernaryPolynomial.generateRandom(1000, 500, 500, random); - IntegerPolynomial p2 = DenseTernaryPolynomial.generateRandom(1000, random); - - IntegerPolynomial prod1 = p1.mult(p2); - IntegerPolynomial prod2 = p1.mult(p2); - assertEquals(prod1, prod2); - - BigIntPolynomial p3 = new BigIntPolynomial(p2); - BigIntPolynomial prod3 = p1.mult(p3); - - assertEquals(new BigIntPolynomial(prod1), prod3); - } - - public void testFromToBinary() - throws IOException - { - SecureRandom random = new SecureRandom(); - SparseTernaryPolynomial poly1 = SparseTernaryPolynomial.generateRandom(1000, 100, 101, random); - ByteArrayInputStream poly1Stream = new ByteArrayInputStream(poly1.toBinary()); - SparseTernaryPolynomial poly2 = SparseTernaryPolynomial.fromBinary(poly1Stream, 1000, 100, 101); - assertEquals(poly1, poly2); - } -} \ No newline at end of file diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/util/test/AllTests.java b/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/util/test/AllTests.java deleted file mode 100644 index 0676c97f1f..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/util/test/AllTests.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.util.test; - -import junit.extensions.TestSetup; -import junit.framework.Test; -import junit.framework.TestCase; -import junit.framework.TestSuite; -import org.bouncycastle.test.PrintTestResult; - -public class AllTests - extends TestCase -{ - public static void main (String[] args) - { - PrintTestResult.printResult(junit.textui.TestRunner.run(suite())); - } - - public static Test suite() - { - TestSuite suite = new TestSuite("NTRU ArrayEncoder Tests"); - - suite.addTestSuite(ArrayEncoderTest.class); - - return new BCTestSetup(suite); - } - - static class BCTestSetup - extends TestSetup - { - public BCTestSetup(Test test) - { - super(test); - } - - protected void setUp() - { - - } - - protected void tearDown() - { - - } - } -} diff --git a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/util/test/ArrayEncoderTest.java b/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/util/test/ArrayEncoderTest.java deleted file mode 100644 index 5ca1812c86..0000000000 --- a/core/src/test/java/org/bouncycastle/pqc/legacy/math/ntru/util/test/ArrayEncoderTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.bouncycastle.pqc.legacy.math.ntru.util.test; - -import java.security.SecureRandom; -import java.util.Random; - -import junit.framework.TestCase; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.DenseTernaryPolynomial; -import org.bouncycastle.pqc.legacy.math.ntru.polynomial.test.PolynomialGenerator; -import org.bouncycastle.pqc.legacy.math.ntru.util.ArrayEncoder; -import org.bouncycastle.util.Arrays; - -public class ArrayEncoderTest - extends TestCase -{ - public void testEncodeDecodeModQ() - { - int[] coeffs = PolynomialGenerator.generateRandom(1000, 2048).coeffs; - byte[] data = ArrayEncoder.encodeModQ(coeffs, 2048); - int[] coeffs2 = ArrayEncoder.decodeModQ(data, 1000, 2048); - assertTrue(Arrays.areEqual(coeffs, coeffs2)); - } - - public void testEncodeDecodeMod3Sves() - { - Random rng = new Random(); - byte[] data = new byte[180]; - rng.nextBytes(data); - int[] coeffs = ArrayEncoder.decodeMod3Sves(data, 960); - byte[] data2 = ArrayEncoder.encodeMod3Sves(coeffs); - assertTrue(Arrays.areEqual(data, data2)); - } - - public void testEncodeDecodeMod3Tight() - { - SecureRandom random = new SecureRandom(); - - int[] coeffs = DenseTernaryPolynomial.generateRandom(1000, random).coeffs; - byte[] data = ArrayEncoder.encodeMod3Tight(coeffs); - int[] coeffs2 = ArrayEncoder.decodeMod3Tight(data, 1000); - assertTrue(Arrays.areEqual(coeffs, coeffs2)); - } -} \ No newline at end of file diff --git a/core/src/test/java/org/bouncycastle/util/encoders/test/AbstractCoderTest.java b/core/src/test/java/org/bouncycastle/util/encoders/test/AbstractCoderTest.java index 0da54d9b78..abf268a640 100644 --- a/core/src/test/java/org/bouncycastle/util/encoders/test/AbstractCoderTest.java +++ b/core/src/test/java/org/bouncycastle/util/encoders/test/AbstractCoderTest.java @@ -202,8 +202,8 @@ private void addSpace(ByteArrayOutputStream out) private String convertBytesToString(byte[] encoded) { - StringBuffer b = new StringBuffer(); - + StringBuilder b = new StringBuilder(); + for (int i = 0; i != encoded.length; i++) { b.append((char)(encoded[i] & 0xff)); diff --git a/core/src/test/java/org/bouncycastle/util/utiltest/AllTests.java b/core/src/test/java/org/bouncycastle/util/utiltest/AllTests.java index f4d21358c2..19ff5734fc 100644 --- a/core/src/test/java/org/bouncycastle/util/utiltest/AllTests.java +++ b/core/src/test/java/org/bouncycastle/util/utiltest/AllTests.java @@ -19,6 +19,7 @@ public static Test suite() suite.addTestSuite(IPTest.class); suite.addTestSuite(BigIntegersTest.class); suite.addTestSuite(ArraysTest.class); + suite.addTestSuite(StringsTest.class); return new BCTestSetup(suite); } diff --git a/core/src/test/java/org/bouncycastle/util/utiltest/StringsTest.java b/core/src/test/java/org/bouncycastle/util/utiltest/StringsTest.java new file mode 100644 index 0000000000..4e1ba3f7b8 --- /dev/null +++ b/core/src/test/java/org/bouncycastle/util/utiltest/StringsTest.java @@ -0,0 +1,67 @@ +package org.bouncycastle.util.utiltest; + +import junit.framework.TestCase; +import org.bouncycastle.util.Strings; + +public class StringsTest + extends TestCase +{ + public void testSplitWithLeadingDelimiter() + { + String[] parts = Strings.split(".permitted", '.'); + assertEquals(2, parts.length); + assertEquals("", parts[0]); + assertEquals("permitted", parts[1]); + } + + public void testSplitDomainWithLeadingDot() + { + String[] parts = Strings.split(".example.domain.com", '.'); + assertEquals(4, parts.length); + assertEquals("", parts[0]); + assertEquals("example", parts[1]); + assertEquals("domain", parts[2]); + assertEquals("com", parts[3]); + } + + public void testSplitNormalDomain() + { + String[] parts = Strings.split("example.domain.com", '.'); + assertEquals(3, parts.length); + assertEquals("example", parts[0]); + assertEquals("domain", parts[1]); + assertEquals("com", parts[2]); + } + + public void testSplitNoDelimiter() + { + String[] parts = Strings.split("nodots", '.'); + assertEquals(1, parts.length); + assertEquals("nodots", parts[0]); + } + + public void testSplitTrailingDelimiter() + { + String[] parts = Strings.split("trailing.", '.'); + assertEquals(2, parts.length); + assertEquals("trailing", parts[0]); + assertEquals("", parts[1]); + } + + public void testSplitOnlyDelimiter() + { + String[] parts = Strings.split(".", '.'); + assertEquals(2, parts.length); + assertEquals("", parts[0]); + assertEquals("", parts[1]); + } + + public void testSplitConsecutiveDelimiters() + { + String[] parts = Strings.split("a..b", '.'); + assertEquals(3, parts.length); + assertEquals("a", parts[0]); + assertEquals("", parts[1]); + assertEquals("b", parts[2]); + } +} diff --git a/docs/releasenotes.html b/docs/releasenotes.html index 1e6f20d7cb..f749606926 100644 --- a/docs/releasenotes.html +++ b/docs/releasenotes.html @@ -18,10 +18,126 @@

    1.0 Introduction

    2.0 Release History

    -

    2.1.1 Version

    +

    2.1.1 Version

    +Release: 1.84
    +Date:      TBD +

    2.1.2 Defects Fixed

    +
      +
    • Random numbers being generated for DSTU4145 signature calculations were 1 bit shorter than they could be. The code has been corrected to allow the generated numbers to occupy the full numeric range available.
    • +
    • CompositePublic/PrivateKey builders had an issue identifying brainpool and EdDSA curves from the algorithm names due to an error in the OID mapping table. This has been fixed.
    • +
    +

    2.1.3 Additional Features and Functionality

    +
      +
    +

    2.1.4 Additional Notes

    +
      +
    • DSA was recently deprecated by NIST and several users have requested that we move to an RSA signing certificate for provider signing instead of our current DSA one. We are grateful to report that Oracle have been very supportive of this and issued us a second RSA certificate based on a new RSA key for signing providers. Providers signed with the previous DSA key will continue to work as before.
    • +
    + +

    2.2.1 Version

    +Release: 1.83
    +Date:      2025, November 27th. +

    2.2.2 Defects Fixed

    +
      +
    • Attempting to check a password on a stripped PGP key would throw an exception. Checking the password on such a key will now always return false.
    • +
    • Fixed an issue in KangarooTwelve where premature absorption caused erroneous 168-byte padding; absorption is now delayed so correct final-byte padding is applied.
    • +
    • BCJSSE: Fix supported_versions creation for renegotiation handshake.
    • +
    • (D)TLS: Reneg info now only offered with pre-1.3.
    • +
    +

    2.2.3 Additional Features and Functionality

    +
      +
    • A generic "COMPOSITE" algorithm name has been added as a JCA Signature algorithm. The algorithm will identify the composite signature to use from the composite key passed in.
    • +
    • The composite signatures implementation has been updated to the final draft and now follows the submitted standard.
    • +
    • Support for the generation and use as trust anchors has been added for certificate signatures with id-alg-unsigned as the signature type.
    • +
    • Support for CMP direct POP for encryption keys using challenge/response has been added to the CMP/CRMF APIs.
    • +
    • Support for SupportedCurves attribute added to the BC provider
    • +
    • BCJSSE: Added support for SLH-DSA signature schemes in TLS 1.3 per draft-reddy-tls-slhdsa-01.
    • +
    • Support has been added for the Java 25 KDF API (current algorithms, PBKDF2, SCRYPT, and HKDF).
    • +
    • Support for composite signatures is now included in CMS and timestamping.
    • +
    • It is now possible to disable the Lenstra check in RSA where the public key is not available via the system/security property "org.bouncycastle.rsa.no_lenstra_check".
    • +
    + +

    2.3.1 Version

    +Release: 1.82
    +Date:      2025, 17th September. +

    2.3.2 Defects Fixed

    +
      +
    • SNOVA and MAYO are now correctly added to the JCA provider module-info file.
    • +
    • TLS: Avoid nonce reuse error in JCE AEAD workaround for pre-Java7.
    • +
    • BCJSSE: Session binding map is now shared across all stages of the session lifecycle (SunJSSE compatibility).
    • +
    • The CMCEPrivateKeyParameters#reconstructPublicKey method was returning an empty byte array. It now returns an encoding of the public key.
    • +
    • CBZip2InputStream no longer auto-closes at end-of-contents.
    • +
    • The BC CertPath implementation was eliminating certificates on the bases of the Key-ID. This is not in accordance with RFC 4158 and has been fixed.
    • +
    • Support for the previous set of libOQS Falcon OIDs has been restored.
    • +
    • The BC CipherInputStream could throw an exception if asked to handle an AEAD stream consisting of the MAC only. This has been fixed.
    • +
    • Some KeyAgreement classes were missing in the Java 11 class hierarchy. This has been fixed.
    • +
    • A typo in a constant name in the HPKE class has been fixed and the old constant deprecated.
    • +
    • Fuzzing analysis has been done on the OpenPGP API and additional code has been added to prevent escaping exceptions.
    • +
    +

    2.3.3 Additional Features and Functionality

    +
      +
    • SHA3Digest, CSHAKE, TupleHash, KMAC now provide support for Memoable and EncodableService.
    • +
    • BCJSSE: Added support for integrity-only cipher suites in TLS 1.3 per RFC 9150.
    • +
    • BCJSSE: Added support for system properties "jdk.tls.client.maxInboundCertificateChainLength" and "jdk.tls.server.maxInboundCertificateChainLength".
    • +
    • BCJSSE: Added support for ML-DSA signature schemes in TLS 1.3 per draft-ietf-tls-mldsa-00.
    • +
    • The Composite post-quantum signatures implementation has been updated to the latest draft (07) draft-ietf-lamps-pq-composite-sigs.
    • +
    • "_PREHASH" implementations are now provided for all composite signatures to allow the hash of the data to be used instead of the actual data in signature calculation.
    • +
    • The gradle build can now be used to generate an Bill of Materials (BOM) file.
    • +
    • It is now possible to configure the SignerInfoVerifierBuilder used by the SignedMailValidator class.
    • +
    • The Ascon family of algorithms has been updated with the latest published changes.
    • +
    • Composite signature keys can now be constructed from the individual keys of the algorithms composing the composite.
    • +
    • PGPSecretKey, PGPSignatureGenerator now support version 6.
    • +
    • Further optimisation work has been done on ML-KEM public key validation.
    • +
    • Zeroization of passwords in the JCA PKCS12 key store has been improved.
    • +
    • The "org.bouncycastle.drbg.effective_256bits_entropy" property has been added for platforms where the entropy source is not producing 1 full bit of entropy per bit and additional bits are required (default value 282).
    • +
    • Support has been added to the CMS content encryptors to allow a generated key to be passed in, rather than always having them generate their own.
    • +
    • OpenPGPKeyGenerator now allows for the use of empty UserIDs (version 4 compatibility).
    • +
    • The HQC KEM has been updated with the latest draft updates.
    • +
    +

    2.3.4 Additional Notes

    +
      +
    • The legacy post-quantum package has now been removed.
    • +
    + +

    2.4.1 Version

    +Release: 1.81
    +Date:      2025, 4th June. +

    2.4.2 Defects Fixed

    +
      +
    • A potention NullPointerException in the KEM KDF KemUtil class has been removed.
    • +
    • Overlapping input/output buffers in doFinal could result in data corruption. This has been fixed.
    • +
    • Fixed Grain-128AEAD decryption incorrectly handle MAC verification.
    • +
    • Add configurable header validation to prevent malicious header injection in PGP cleartext signed messages; Fix signature packet encoding issues in PGPSignature.join() and embedded signatures while phasing out legacy format.
    • +
    • Fixed ParallelHash initialization stall when using block size B=0.
    • +
    • The PRF from the PBKDF2 function was been lost when PBMAC1 was initialized from protectionAlgorithm. This has been fixed.
    • +
    • The lowlevel DigestFactory was cloning MD5 when being asked to clone SHA1. This has been fixed.
    • +
    +

    2.4.3 Additional Features and Functionality

    +
      +
    • XWing implementation updated to draft-connolly-cfrg-xwing-kem/07/
    • +
    • Further support has been added for generation and use of PGP V6 keys
    • +
    • Additional validation has been added for armored headers in Cleartext Signed Messages.
    • +
    • The PQC signature algorithm proposal Mayo has been added to the low-level API and the BCPQC provider.
    • +
    • The PQC signature algorithm proposal Snova has been added to the low-level API and the BCPQC provider.
    • +
    • Support for ChaCha20-Poly1305 has been added to the CMS/SMIME APIs.
    • +
    • The Falcon implementation has been updated to the latest draft.
    • +
    • Support has been added for generating keys which encode as seed-only and expanded-key-only for ML-KEM and ML-DSA private keys.
    • +
    • Private key encoding of ML-DSA and ML-KEM private keys now follows the latest IETF draft.
    • +
    • The Ascon family of algorithms has been updated to the initial draft of SP 800-232. Some additional optimisation work has been done.
    • +
    • Support for ML-DSA's external-mu calculation and signing has been added to the BC provider.
    • +
    • CMS now supports ML-DSA for SignedData generation.
    • +
    • Introduce high-level OpenPGP API for message creation/consumption and certificate evaluation.
    • +
    • Added JDK21 KEM API implementation for HQC algorithm.
    • +
    • BCJSSE: Strip trailing dot from hostname for SNI, endpointID checks.
    • +
    • BCJSSE: Draft support for ML-KEM updated (draft-connolly-tls-mlkem-key-agreement-05).
    • +
    • BCJSSE: Draft support for hybrid ECDHE-MLKEM (draft-ietf-tls-ecdhe-mlkem-00).
    • +
    • BCJSSE: Optionally prefer TLS 1.3 server's supported_groups order (BCSSLParameters.useNamedGroupsOrder).
    • +
    + +

    2.5.1 Version

    Release: 1.80
    Date:      2025, 14th January. -

    2.1.2 Defects Fixed

    +

    2.5.2 Defects Fixed

    • A splitting issue for ML-KEM lead to an incorrect size for kemct in KEMRecipientInfos. This has been fixed.
    • The PKCS12 KeyStore has been adjusted to prevent accidental doubling of the Oracle trusted certificate attribute (results in an IOException when used with the JVM PKCS12 implementation).
    • @@ -36,7 +152,7 @@

      2.1.2 Defects Fixed

    • EtsiTs1029411TypesAuthorization was missing an extension field. This has been added.
    • Interoperability issues with single depth LMS keys have been addressed.
    -

    2.2.3 Additional Features and Functionality

    +

    2.5.3 Additional Features and Functionality

    • CompositeSignatures now updated to draft-ietf-lamps-pq-composite-sigs-03.
    • ML-KEM, ML-DSA, SLH-DSA, and Composite private keys now use raw encodings as per the latest drafts from IETF 121: draft-ietf-lamps-kyber-certificates-06, draft-ietf-lamps-dilithium-certificates-05, and draft-ietf-lamps-x509-slhdsa.
    • @@ -54,10 +170,10 @@

      2.2.3 Additional Features and Functionality

    • The ASCON family of algorithms have been updated in accordance with the published FIPS SP 800-232 draft.
    -

    2.2.1 Version

    +

    2.6.1 Version

    Release: 1.79
    Date:      2024, 30th October. -

    2.2.2 Defects Fixed

    +

    2.6.2 Defects Fixed

    • Leading zeroes were sometimes dropped from Ed25519 signatures leading to verification errors in the PGP API. This has been fixed.
    • Default version string for Armored Output is now set correctly in 18on build.
    • @@ -74,7 +190,7 @@

      2.2.2 Defects Fixed

    • The default version header for PGP armored output did not carry the correct version string. This has been fixed.
    • In some situations the algorithm lookup for creating PGPDigestCalculators would fail due to truncation of the algorithm name. This has been fixed.
    -

    2.2.3 Additional Features and Functionality

    +

    2.6.3 Additional Features and Functionality

    • Object Identifiers have been added for ML-KEM, ML-DSA, and SLH-DSA.
    • The PQC algorithms, ML-KEM, ML-DSA (including pre-hash), and SLH-DSA (including pre-hash) have been added to the BC provider and the lightweight API.
    • @@ -95,10 +211,10 @@

      2.2.3 Additional Features and Functionality

    • The system property "org.bouncycastle.ec.disable_f2m" has been introduced to allow F2m EC support to be disabled.
    -

    2.3.1 Version

    +

    2.7.1 Version

    Release: 1.78.1
    Date:      2024, 18th April. -

    2.3.2 Defects Fixed

    +

    2.7.2 Defects Fixed

    • The new dependency of the the PGP API on the bcutil jar was missing from the module jar, the OSGi manifest, and the Maven POM. This has been fixed.
    • Missing exports and duplicate imports have been added/removed from the OSGi manifests.
    • @@ -106,10 +222,10 @@

      2.3.2 Defects Fixed

    • A check in the X.509 Extensions class preventing the parsing of empty extensions has been removed.
    -

    2.4.1 Version

    +

    2.8.1 Version

    Release: 1.78
    Date:      2024, 7th April. -

    2.4.2 Defects Fixed

    +

    2.8.2 Defects Fixed

    • Issues with a dangling weak reference causing intermittent NullPointerExceptions in the OcspCache have been fixed.
    • Issues with non-constant time RSA operations in TLS handshakes have been fixed.
    • @@ -127,7 +243,7 @@

      2.4.2 Defects Fixed

    • An off-by-one error in the encoding for EccP256CurvePoint for ITS has been fixed.
    • PEM Parser now enforces PEM headers to start at the beginning of the line to be meaningful.
    -

    2.4.3 Additional Features and Functionality

    +

    2.8.3 Additional Features and Functionality

    • An implementation of MLS (RFC 9420 - The Messaging Layer Security Protocol) has been added as a new module.
    • NTRU now supports NTRU-HPS4096-1229 and NTRU-HRSS-1373.
    • @@ -145,7 +261,7 @@

      2.4.3 Additional Features and Functionality

    • CertPathValidationContext and CertificatePoliciesValidation now include implementations of Memoable.
    • The Composite post-quantum signatures implementation has been updated to the latest draft draft-ounsworth-pq-composite-sigs.
    -

    2.4.4 Notes.

    +

    2.8.4 Notes.

    • Both versions of NTRUPrime have been updated to produce 256 bit secrets in line with Kyber. This should also bring them into line with other implementations such as those used in OpenSSH now.
    • BCJSSE: The boolean system property 'org.bouncycastle.jsse.fips.allowRSAKeyExchange" now defaults to false. All RSA @@ -156,7 +272,7 @@

      2.4.4 Notes.

    • The PKCS12 store using GCM does not include the PKCS#12 MAC so no longer includes use of the PKCS#12 PBE scheme and only uses PBKDF2.
    • In keeping with the current set of experimental OIDs for PQC algorithms, OIDs may have changed to reflect updated versions of the algorithms.
    -

    2.4.5 Security Advisories.

    +

    2.8.5 Security Advisories.

    Release 1.78 deals with the following CVEs:

    @@ -167,10 +283,10 @@

    2.4.5 Security Advisories.

  • CVE-2024-34447 - When endpoint identification is enabled in the BCJSSE and an SSL socket is not created with an explicit hostname (as happens with HttpsURLConnection), hostname verification could be performed against a DNS-resolved IP address. This has been fixed.
  • -

    2.5.1 Version

    +

    2.9.1 Version

    Release: 1.77
    Date:      2023, November 13th -

    2.5.2 Defects Fixed

    +

    2.9.2 Defects Fixed

    • Using an unescaped '=' in an X.500 RDN would result in the RDN being truncated silently. The issue is now detected and an exception is thrown.
    • asn1.eac.CertificateBody was returning certificateEffectiveDate from getCertificateExpirationDate(). This has been fixed to return certificateExpirationDate.
    • @@ -186,7 +302,7 @@

      2.5.2 Defects Fixed

    • An internal method in Arrays was failing to construct its failure message correctly on an error. This has been fixed.
    • HSSKeyPublicParameters.generateLMSContext() would fail for a unit depth key. This has been fixed.
    -

    2.5.3 Additional Features and Functionality

    +

    2.9.3 Additional Features and Functionality

    • BCJSSE: Added org.bouncycastle.jsse.client.omitSigAlgsCertExtension and org.bouncycastle.jsse.server.omitSigAlgsCertExtension boolean system properties to control (for client and server resp.) whether the signature_algorithms_cert extension should be omitted if it would be identical to signature_algorithms. @@ -198,7 +314,7 @@

      2.5.3 Additional Features and Functionality

    • TLS: RSA key exchange cipher suites are now disabled by default.
    • Support has been added for PKCS#10 requests to allow certificates using the altSignature/altPublicKey extensions.
    -

    2.5.4 Notes.

    +

    2.9.4 Notes.

    • Kyber and Dilithium have been updated according to the latest draft of the standard. Dilithium-AES and Kyber-AES have now been removed. Kyber now produces 256 bit secrets for all parameter sets (in line with the draft standard).
    • NTRU has been updated to produce 256 bit secrets in line with Kyber.
    • @@ -207,10 +323,10 @@

      2.5.4 Notes.

    • PQC CMS SignedData now defaults to SHA-256 for signed attributes rather than SHAKE-256. This is also a compatibility change, but may change further again as the IETF standard for CMS is updated.
    -

    2.6.1 Version

    +

    2.10.1 Version

    Release: 1.76
    Date:      2023, July 29th -

    2.6.2 Defects Fixed

    +

    2.10.2 Defects Fixed

    • Service allocation in the provider could fail due to the lack of a permission block. This has been fixed.
    • JceKeyFingerPrintCalculator has been generalised for different providers by using "SHA-256" for the algorithm string.
    • @@ -219,7 +335,7 @@

      2.6.2 Defects Fixed

    • Cipher.unwrap() for HQC could fail due to a miscalculation of the length of the KEM packet. This has been fixed.
    • There was exposure to a Java 7 method in the Java 5 to Java 8 BCTLS jar which could cause issues with some TLS 1.2 cipher suites running on older JVMs. This is now fixed.
    -

    2.6.3 Additional Features and Functionality

    +

    2.10.3 Additional Features and Functionality

    • BCJSSE: Following OpenJDK, finalizers have been removed from SSLSocket subclasses. Applications should close sockets and not rely on garbage collection.
    • BCJSSE: Added support for boolean system property "jdk.tls.client.useCompatibilityMode" (default "true").
    • @@ -232,30 +348,30 @@

      2.6.3 Additional Features and Functionality

    • An UnknownPacket type has been added to the PGP APIs to allow for forwards compatibility with upcoming revisions to the standard.
    -

    2.7.1 Version

    +

    2.11.1 Version

    Release: 1.75
    Date:      2023, June 21st -

    2.7.2 Defects Fixed

    +

    2.11.2 Defects Fixed

    • Several Java 8 method calls were accidentally introduced in the Java 5 to Java 8 build. The affected classes have been refactored to remove this.
    • (D)TLS: renegotiation after resumption now fixed to avoid breaking connection.
    -

    2.7.3 Notes.

    +

    2.11.3 Notes.

    • The ASN.1 core package has had some dead and retired methods cleaned up and removed.
    -

    2.8.1 Version

    +

    2.12.1 Version

    Release: 1.74
    Date:      2023, June 12th -

    2.8.2 Defects Fixed

    +

    2.12.2 Defects Fixed

    • AsconEngine: Fixed a buffering bug when decrypting across multiple processBytes calls (ascon128a unaffected).
    • Context based sanity checking on PGP signatures has been added.
    • The ParallelHash clone constructor was not copying all fields. This is now fixed.
    • The maximimum number of blocks for CTR/SIC modes was 1 block less than it should have been. This is now fixed.
    -

    2.8.3 Additional Features and Functionality

    +

    2.12.3 Additional Features and Functionality

    • The PGP API now supports wildcard key IDs for public key based data encryption.
    • LMS now supports SHA256/192, SHAKE256/192, and SHAKE256/256 (the additional SP 8000-208 parameter sets).
    • @@ -274,22 +390,22 @@

      2.8.3 Additional Features and Functionality

    • The number of keys/sub-keys in a PGPKeyRing can now be found by calling PGPKeyRing.size().
    • The PQC algorithms LMS/HSS, SPHINCS+, Dilithium, Falcon, and NTRU are now supported directly by the BC provider.
    -

    2.8.4 Notes.

    +

    2.12.4 Notes.

    • The now defunct PQC SIKE algorithm has been removed, this has also meant the removal of its resource files so the provider is now quite a bit smaller.
    • As a precaution, HC128 now enforces a 128 bit IV, previous behaviour for shorter IVs can be supported where required by padding the IV to the 128 bits with zero.
    • PGP encrypted data generation now uses integrity protection by default. Previous behaviour for encrypted data can be supported where required by calling PGPDataEncryptorBuilder.setWithIntegrityPacket(false) when data encryption is set up.
    • There are now additional sanity checks in place to prevent accidental mis-use of PGPSignature objects. If this change causes any issues, you might want to check what your code is up to as there is probably a bug.
    -

    2.8.5 Security Advisories.

    +

    2.12.5 Security Advisories.

    • CVE-2023-33201 - this release fixes an issue with the X509LDAPCertStoreSpi where a specially crafted certificate subject could be used to try and extract extra information out of an LDAP server with wild-card matching enabled.
    -

    2.9.1 Version

    +

    2.13.1 Version

    Release: 1.73
    Date:      2023, April 8th -

    2.9.2 Defects Fixed

    +

    2.13.2 Defects Fixed

    • BCJSSE: Instantiating a JSSE provider in some contexts could cause an AccessControl exception. This has been fixed.
    • The EC key pair generator can generate out of range private keys when used with SM2. A specific SM2KeyPairGenerator has been added to the low-level API and is used by KeyPairGenerator.getInstance("SM2", "BC"). The SM2 signer has been updated to check for out of range keys as well..
    • @@ -310,7 +426,7 @@

      2.9.2 Defects Fixed

    • IPAddress has been written to provide stricter checking and avoid the use of Integer.parseInt().
    • A Java 7 class snuck into the Java 5 to Java 8 build. This has been addressed.
    -

    2.9.3 Additional Features and Functionality

    +

    2.13.3 Additional Features and Functionality

    • The Rainbow NIST Post Quantum Round-3 Candidate has been added to the low-level API and the BCPQC provider (level 3 and level 5 parameter sets only).
    • The GeMSS NIST Post Quantum Round-3 Candidate has been added to the low-level API.
    • @@ -337,38 +453,38 @@

      2.9.3 Additional Features and Functionality

    • A general purpose PQCOtherInfoGenerator has been added which supports all Kyber and NTRU.
    • An implementation of HPKE (RFC 9180 - Hybrid Public Key Encryption) has been added to the light-weight cryptography API.
    -

    2.9.4 Security Advisories.

    +

    2.13.4 Security Advisories.

    • The PQC implementations have now been subject to formal review for secret leakage and side channels, there were issues in BIKE, Falcon, Frodo, HQC which have now been fixed. Some weak positives also showed up in Rainbow, Picnic, SIKE, and GeMSS - for now this last set has been ignored as the algorithms will either be updated if they reappear in the Signature Round, or deleted, as is already the case for SIKE (it is now in the legacy package). Details on the group responsible for the testing can be found in the CONTRIBUTORS file.
    • For at least some ECIES variants (e.g. when using CBC) there is an issue with potential malleability of a nonce (implying silent malleability of the plaintext) that must be sent alongside the ciphertext but is outside the IES integrity check. For this reason the automatic generation of nonces with IED is now disabled and they have to be passed in using an IESParameterSpec. The current advice is to agree on a nonce between parties and then rely on the use of the ephemeral key component to allow the nonce (rather the so called nonce) usage to be extended.
    -

    2.9.5 Notes.

    +

    2.13.5 Notes.

    • Most test data files have now been migrated to a separate project bc-test-data which is also available on github. If you clone bc-test-data at the same level as the bc-java project the tests will find the test data they require.
    • There has been further work to make entropy collection more friendly in container environments. See DRBG.java for details. We would welcome any further feedback on this as we clearly cannot try all situations first hand.
    -

    2.10.1 Version

    +

    2.14.1 Version

    Release: 1.72.2, 1.72.3
    Date:      2022, November 20th -

    2.10.2 Defects Fixed

    +

    2.14.2 Defects Fixed

    • PGP patch release - fix for OSGI and version header in 1.72.1 jar file.
    -

    2.11.1 Version

    +

    2.15.1 Version

    Release: 1.72.1
    Date:      2022, October 25th -

    2.11.2 Defects Fixed

    +

    2.15.2 Defects Fixed

    • PGP patch release - fix for regression in OpenPGP PGPEncryptedData.java which could result in checksum failures on correct files.
    -

    2.12.1 Version

    +

    2.16.1 Version

    Release: 1.72
    Date:      2022, September 25th -

    2.12.2 Defects Fixed

    +

    2.16.2 Defects Fixed

    • There were parameter errors in XMSS^MT OIDs for XMSSMT_SHA2_40/4_256 and XMSSMT_SHA2_60/3_256. These have been fixed.
    • There was an error in Merkle tree construction for the Evidence Records (ERS) implementation which could result in invalid roots been timestamped. ERS now produces an ArchiveTimeStamp for each data object/group with an associated reduced hash tree. The reduced hash tree is now calculated as a simple path to the root of the tree for each record.
    • @@ -376,7 +492,7 @@

      2.12.2 Defects Fixed

    • A tagging calculation error in GCMSIV which could result in incorrect tags has been fixed.
    • Issues around Java 17 which could result in failing tests have been addressed.
    -

    2.12.3 Additional Features and Functionality

    +

    2.16.3 Additional Features and Functionality

    • BCJSSE: TLS 1.3 is now enabled by default where no explicit protocols are supplied (e.g. "TLS" or "Default" SSLContext algorithms, or SSLContext.getDefault() method).
    • BCJSSE: Rewrite SSLEngine implementation to improve compatibility with SunJSSE.
    • @@ -406,22 +522,22 @@

      2.12.3 Additional Features and Functionality

    • Support has been added to the PKCS#12 implementation for the Oracle trusted certificate attribute.
    • Performance of our BZIP2 classes has been improved.
    -

    2.12.4 Notes

    +

    2.16.4 Notes

    Keep in mind the PQC algorithms are still under development and we are still at least a year and a half away from published standards. This means the algorithms may still change so by all means experiment, but do not use the PQC algoritms for anything long term.

    The legacy "Rainbow" and "McEliece" implementations have been removed from the BCPQC provider. The underlying classes are still present if required. Other legacy algorithm implementations can be found under the org.bouncycastle.pqc.legacy package.

    -

    2.12.5 Security Notes

    +

    2.16.5 Security Notes

    The PQC SIKE algorithm is provided for research purposes only. It should now be regarded as broken. The SIKE implementation will be withdrawn in BC 1.73.

    -

    2.13.1 Version

    +

    2.17.1 Version

    Release: 1.71
    Date:      2022, March 31st. -

    2.13.2 Defects Fixed

    +

    2.17.2 Defects Fixed

    • In line with GPG the PGP API now attempts to preserve comments containing non-ascii UTF-8 characters.
    • An accidental partial dependency on Java 1.7 has been removed from the TLS API.
    • @@ -435,7 +551,7 @@

      2.13.2 Defects Fixed

    • An accidental regression introduced by a fix for another issue in PKIXCertPathReviewer around use of the AuthorityKeyIdentifier extension and it failing to match a certificate uniquely when the serial number field is missing has been fixed.
    • An error was found in the creation of TLS 1.3 Export Keying Material which could cause compatibility issues. This has been fixed.
    -

    2.13.3 Additional Features and Functionality

    +

    2.17.3 Additional Features and Functionality

    • Support has been added for OpenPGP regular expression signature packets.
    • Support has been added for OpenPGP PolicyURI signature packets.
    • @@ -465,16 +581,16 @@

      2.13.3 Additional Features and Functionality

    • ASN.1 object support has been added for the Lightweight Certificate Management Protocol (CMP), currently in draft.
    • A HybridValueParamterSpec class has been added for use with KeyAgreement to support SP 800-56C hybrid (so classical/post-quantum) key agreement.
    -

    2.13.4 Notes

    +

    2.17.4 Notes

    • The deprecated QTESLA implementation has been removed from the BCPQC provider.
    • The submission update to SPHINCS+ has been added. This changes the generation of signatures - particularly deterministic ones.
    -

    2.14.1 Version

    +

    2.18.1 Version

    Release: 1.70
    Date:      2021, November 29th. -

    2.14.2 Defects Fixed

    +

    2.18.2 Defects Fixed

    • Blake 3 output limit is enforced.
    • The PKCS12 KeyStore was relying on default precedence for its key Cipher implementation so was sometimes failing if used from the keytool. The KeyStore class now makes sure it uses the correct Cipher implementation.
    • @@ -488,7 +604,7 @@

      2.14.2 Defects Fixed

    • The lack of close() in the ASN.1 Dump command line utility was triggering false positives in some code analysis tools. A close() call has been added.
    • PGPPublicKey.getBitStrength() now properly recognises EdDSA keys.
    -

    2.14.3 Additional Features and Functionality

    +

    2.18.3 Additional Features and Functionality

    • Missing PGP CRC checksums can now be optionally ignored using setDetectMissingCRC() (default false) on ArmoredInputStream.
    • PGPSecretKey.copyWithNewPassword() now has a variant which uses USAGE_SHA1 for key protection if a PGPDigestCalculator is passed in.
    • @@ -527,15 +643,15 @@

      2.14.3 Additional Features and Functionality

    • The JcePKCSPBEOutputEncryptorBuilder now supports SCRYPT with ciphers that do not have algorithm parameters (e.g. AESKWP).
    • Support is now added for certificates using ETSI TS 103 097, "Intelligent Transport Systems (ITS)" in the bcpkix package.
    -

    2.14.4 Notes.

    +

    2.18.4 Notes.

    • While this release should maintain source code compatibility, developers making use of some parts of the ASN.1 library will find that some classes need recompiling. Apologies for the inconvenience.
    -

    2.15.1 Version

    +

    2.19.1 Version

    Release: 1.69
    Date:      2021, June 7th. -

    2.15.2 Defects Fixed

    +

    2.19.2 Defects Fixed

    • Lightweight and JCA conversion of Ed25519 keys in the PGP API could drop the leading byte as it was zero. This has been fixed.
    • Marker packets appearing at the start of PGP public key rings could cause parsing failure. This has been fixed.
    • @@ -555,7 +671,7 @@

      2.15.2 Defects Fixed

    • Fix various conversions and interoperability for XDH and EdDSA between BC and SunEC providers.
    • TLS: Prevent attempts to use KeyUpdate mechanism in versions before TLS 1.3.
    -

    2.15.3 Additional Features and Functionality

    +

    2.19.3 Additional Features and Functionality

    • GCM-SIV has been added to the lightweight API and the provider.
    • Blake3 has been added to the lightweight API.
    • @@ -596,24 +712,24 @@

      2.15.3 Additional Features and Functionality

    • BCJSSE: Key managers now support EC credentials for use with TLS 1.3 ECDSA signature schemes (including brainpool).
    • TLS: Add TLS 1.3 support for brainpool curves per RFC 8734.
    -

    2.15.4 Notes

    +

    2.19.4 Notes

    • There is a small API change in the PKIX package to the DigestAlgorithmIdentifierFinder interface as a find() method that takes an ASN1ObjectIdentifier has been added to it. For people wishing to extend their own implementations, see DefaultDigestAlgorithmIdentifierFinder for a sample implementation.
    • A version of the bcmail API supporting Jakarta Mail has now been added (see bcjmail jar).
    • Some work has been done on moving out code that does not need to be in the provider jar. This has reduced the size of the provider jar and should also make it easier for developers to patch the classes involved as they no longer need to be signed. bcpkix and bctls are both dependent on the new bcutil jar.
    -

    2.16.1 Version

    +

    2.20.1 Version

    Release: 1.68
    Date:      2020, December 21st. -

    2.16.2 Defects Fixed

    +

    2.20.2 Defects Fixed

    • Some BigIntegers utility methods would fail for BigInteger.ZERO. This has been fixed.
    • PGPUtil.isKeyRing() was not detecting secret sub-keys in its input. This has been fixed.
    • The ASN.1 class, ArchiveTimeStamp was insisting on a value for the optional reducedHashTree field. This has been fixed.
    • BCJSSE: Lock against multiple writers - a possible synchronization issue has been removed.
    -

    2.16.3 Additional Features and Functionality

    +

    2.20.3 Additional Features and Functionality

    • BCJSSE: Added support for system property com.sun.net.ssl.requireCloseNotify. Note that we are using a default value of 'true'.
    • BCJSSE: 'TLSv1.3' is now a supported protocol for both client and server. For this release it is only enabled by default for the 'TLSv1.3' SSLContext, but can be explicitly enabled using 'setEnabledProtocols' on an SSLSocket or SSLEngine, or via SSLParameters.
    • @@ -624,10 +740,10 @@

      2.16.3 Additional Features and Functionality

    -

    2.17.1 Version

    +

    2.21.1 Version

    Release: 1.67
    Date:      2020, November 1st. -

    2.17.2 Defects Fixed

    +

    2.21.2 Defects Fixed

    • BCJSSE: SunJSSE compatibility fix - override of getChannel() removed and 'urgent data' behaviour should now conform to what the SunJSSE expects.
    • Nested BER data could sometimes cause issues in octet strings. This has been fixed.
    • @@ -639,7 +755,7 @@

      2.17.2 Defects Fixed

    • Zero length data would cause an unexpected exception from RFC5649WrapEngine. This has been fixed.
    • OpenBSDBcrypt was failing to handle some valid prefixes. This has been fixed.
    -

    2.17.3 Additional Features and Functionality

    +

    2.21.3 Additional Features and Functionality

    • Performance of Argon2 has been improved.
    • Performance of Noekeon has been improved.
    • @@ -657,15 +773,15 @@

      2.17.3 Additional Features and Functionality

    • Mode name checks in Cipher strings should now make sure an improper mode name always results in a NoSuchAlgorithmException.
    • In line with changes in OpenSSL, the OpenSSLPBKDF now uses UTF-8 encoding.
    -

    2.17.4 Security Advisory

    +

    2.21.4 Security Advisory

    • As described in CVE-2020-28052, the OpenBSDBCrypt.checkPassword() method had a flaw in it due to a change for BC 1.65. BC 1.66 is also affected. The issue is fixed in BC 1.67. If you are using OpenBSDBCrypt.checkPassword() and you are using BC 1.65 or BC 1.66 we strongly advise moving to BC 1.67 or later.
    -

    2.18.1 Version

    +

    2.22.1 Version

    Release: 1.66
    Date:      2020, July 4th. -

    2.18.2 Defects Fixed

    +

    2.22.2 Defects Fixed

    • EdDSA verifiers now reset correctly after rejecting overly long signatures.
    • BCJSSE: SSLSession.getPeerCertificateChain could throw NullPointerException. This has been fixed.
    • @@ -682,7 +798,7 @@

      2.18.2 Defects Fixed

    • For a few values the cSHAKE implementation would add unnecessary pad bytes where the N and S strings produced encoded data that was block aligned. This has been fixed.
    • There were a few circumstances where Argon2BytesGenerator might hit an unexpected null. These have been removed.
    -

    2.18.3 Additional Features and Functionality

    +

    2.22.3 Additional Features and Functionality

    • The qTESLA signature algorithm has been updated to v2.8 (20191108).
    • BCJSSE: Client-side OCSP stapling now supports status_request_v2 extension.
    • @@ -701,15 +817,15 @@

      2.18.3 Additional Features and Functionality

    • Performance of the Base64 encoder has been improved.
    • The PGPPublicKey class will now include direct key sigantures when checking for key expiry times.
    -

    2.18.4 Notes

    +

    2.22.4 Notes

    The qTESLA update breaks compatibility with previous versions. Private keys now include a hash of the public key at the end, and signatures are no longer interoperable with previous versions.

    -

    2.19.1 Version

    +

    2.23.1 Version

    Release: 1.65
    Date:      2020, March 31st. -

    2.19.2 Defects Fixed

    +

    2.23.2 Defects Fixed

    • DLExternal would encode using DER encoding for tagged SETs. This has been fixed.
    • ChaCha20Poly1305 could fail for large (>~2GB) files. This has been fixed.
    • @@ -721,7 +837,7 @@

      2.19.2 Defects Fixed

    • BCJSSE: Choice of credentials and signing algorithm now respect the peer's signature_algorithms extension properly.
    • BCJSSE: KeyManager for KeyStoreBuilderParameters no longer leaks memory.
    -

    2.19.3 Additional Features and Functionality

    +

    2.23.3 Additional Features and Functionality

    • LMS and HSS (RFC 8554) support has been added to the low level library and the PQC provider.
    • SipHash128 support has been added to the low level library and the JCE provider.
    • @@ -735,10 +851,10 @@

      2.19.3 Additional Features and Functionality

    • TLS: DSA in JcaTlsCrypto now falls back to stream signing to work around NoneWithDSA limitations in default provider.
    -

    2.20.1 Version

    +

    2.24.1 Version

    Release: 1.64
    Date:      2019, October 7th. -

    2.20.2 Defects Fixed

    +

    2.24.2 Defects Fixed

    • OpenSSH: Fixed padding in generated Ed25519 private keys.
    • Validation of headers in PemReader now looks for tailing dashes in header.
    • @@ -746,7 +862,7 @@

      2.20.2 Defects Fixed

    • Some compatibility issues around the signature encryption algorithm field in CMS SignedData and the GOST algorithms have been addressed.
    • GOST3410-2012-512 now uses the GOST3411-2012-256 as its KDF digest.
    -

    2.20.3 Additional Features and Functionality

    +

    2.24.3 Additional Features and Functionality

    • PKCS12: key stores containing only certificates can now be created without the need to provide passwords.
    • BCJSSE: Initial support for AlgorithmConstraints; protocol versions and cipher suites.
    • @@ -759,20 +875,20 @@

      2.20.3 Additional Features and Functionality

    • Support for Java 11's NamedParameterSpec class has been added (using reflection) to the EC and EdEC KeyPairGenerator implementations.
    -

    2.20.4 Removed Features and Functionality

    +

    2.24.4 Removed Features and Functionality

    • Deprecated ECPoint 'withCompression' tracking has been removed.
    -

    2.20.5 Security Advisory

    +

    2.24.5 Security Advisory

    • A change to the ASN.1 parser in 1.63 introduced a regression that can cause an OutOfMemoryError to occur on parsing ASN.1 data. We recommend upgrading to 1.64, particularly where an application might be parsing untrusted ASN.1 data from third parties.
    -

    2.21.1 Version

    +

    2.25.1 Version

    Release: 1.63
    Date:      2019, September 10th. -

    2.21.2 Defects Fixed

    +

    2.25.2 Defects Fixed

    • The ASN.1 parser would throw a large object exception for some objects which could be safely parsed. This has been fixed.
    • GOST3412-2015 CTR mode was unusable at the JCE level. This has been fixed.
    • @@ -791,7 +907,7 @@

      2.21.2 Defects Fixed

    • It is now possible to specify different S-Box parameters for the GOST 28147-89 MAC.
    -

    2.21.3 Additional Features and Functionality

    +

    2.25.3 Additional Features and Functionality

    • QTESLA is now updated with the round 2 changes. Note: the security catergories, and in some cases key generation and signatures, have changed. For people interested in comparison, the round 1 version is now moved to org.bouncycastle.pqc.crypto.qteslarnd1 - this package will be deleted in 1.64. Please keep in mind that QTESLA may continue to evolve.
    • Support has been added for generating Ed25519/Ed448 signed certificates.
    • @@ -804,10 +920,10 @@

      2.21.3 Additional Features and Functionality

    • The valid path for EST services has been updated to cope with the characters used in the Aruba clearpass EST implementation.
    -

    2.22.1 Version

    +

    2.26.1 Version

    Release: 1.62
    Date:      2019, June 3rd. -

    2.22.2 Defects Fixed

    +

    2.26.2 Defects Fixed

    • DTLS: Fixed infinite loop on IO exceptions.
    • DTLS: Retransmission timers now properly apply to flights monolithically.
    • @@ -824,7 +940,7 @@

      2.22.2 Defects Fixed

    • CertificateFactory now enforces presence of PEM headers when required.
    • A performance issue with RSA key pair generation that was introduced in 1.61 has been mostly eliminated.
    -

    2.22.3 Additional Features and Functionality

    +

    2.26.3 Additional Features and Functionality

    • Builders for X509 certificates and CRLs now support replace and remove extension methods.
    • DTLS: Added server-side support for HelloVerifyRequest.
    • @@ -845,10 +961,10 @@

      2.22.3 Additional Features and Functionality

    • Support for the Ethereum flavor of IES has been added to the lightweight API.
    -

    2.23.1 Version

    +

    2.27.1 Version

    Release: 1.61
    Date:      2019, February 4th. -

    2.23.2 Defects Fixed

    +

    2.27.2 Defects Fixed

    • Use of EC named curves could be lost if keys were constructed via a key factory and algorithm parameters. This has been fixed.
    • RFC3211WrapEngine would not properly handle messages longer than 127 bytes. This has been fixed.
    • @@ -869,7 +985,7 @@

      2.23.2 Defects Fixed

    • Several parsing issues related to the processing of CMP PKIPublicationInfo have been fixed.
    • The ECGOST curves for id-tc26-gost-3410-12-256-paramSetA and id-tc26-gost-3410-12-512-paramSetC had incorrect co-factors. These have been fixed.
    -

    2.23.3 Additional Features and Functionality

    +

    2.27.3 Additional Features and Functionality

    • The qTESLA signature algorithm has been added to PQC light-weight API and the PQC provider.
    • The password hashing function, Argon2 has been added to the lightweight API.
    • @@ -893,15 +1009,15 @@

      2.23.3 Additional Features and Functionality

    • SM2 in public key cipher mode has been added to the provider API.
    • The BCFKSLoadStoreParameter has been extended to allow the use of certificates and digital signatures for verifying the integrity of BCFKS key stores.
    -

    2.23.4 Removed Features and Functionality

    +

    2.27.4 Removed Features and Functionality

    • Deprecated methods for EC point construction independent of curves have been removed.
    -

    2.24.1 Version

    +

    2.28.1 Version

    Release: 1.60
    Date:      2018, June 30 -

    2.24.2 Defects Fixed

    +

    2.28.2 Defects Fixed

    • Base64/UrlBase64 would throw an exception on a zero length string. This has been fixed.
    • Base64/UrlBase64 would throw an exception if there was whitespace in the last 4 characters. This has been fixed.
    • @@ -922,7 +1038,7 @@

      2.24.2 Defects Fixed

    • In some situations the use of sm2p256v1 would result in "unknown curve name". This has been fixed.
    • CMP PollReqContent now supports multiple certificate request IDs.
    -

    2.24.3 Additional Features and Functionality

    +

    2.28.3 Additional Features and Functionality

    • TLS: Extended CBC padding is now optional (and disabled by default).
    • TLS: Now supports channel binding 'tls-server-end-point'.
    • @@ -950,16 +1066,16 @@

      2.24.3 Additional Features and Functionality

    • Support has been added for the German BSI KAEG Elliptic Curve key agreement algorithm with X9.63 as the KDF to the JCE.
    • Support has been added for the German BSI KAEG Elliptic Curve session key KDF to the lightweight API.
    -

    2.24.4 Security Related Changes and CVE's Addressed by this Release

    +

    2.28.4 Security Related Changes and CVE's Addressed by this Release

    • CVE-2018-1000180: issue around primality tests for RSA key pair generation if done using only the low-level API.
    • CVE-2018-1000613: lack of class checking in deserialization of XMSS/XMSS^MT private keys with BDS state information.
    -

    2.25.1 Version

    +

    2.29.1 Version

    Release: 1.59
    Date:      2017, December 28 -

    2.25.2 Defects Fixed

    +

    2.29.2 Defects Fixed

    • Issues with using PQC based keys with the provided BC KeyStores have now been fixed.
    • ECGOST-2012 public keys were being encoded with the wrong OID for the digest parameter in the algorithm parameter set. This has been fixed.
    • @@ -973,7 +1089,7 @@

      2.25.2 Defects Fixed

    • An off-by-one error for the max N check for SCRYPT has been fixed. SCRYPT should now be compliant with RFC 7914.
    • ASN1GeneralizedTime will now accept a broader range of input strings.
    -

    2.25.3 Additional Features and Functionality

    +

    2.29.3 Additional Features and Functionality

    • GOST3410-94 private keys encoded using ASN.1 INTEGER are now accepted in private key info objects.
    • SCRYPT is now supported as a SecretKeyFactory in the provider and in the PKCS8 APIs
    • @@ -992,15 +1108,15 @@

      2.25.3 Additional Features and Functionality

    • A DEROtherInfo generator for key agreement using NewHope as the source of the shared private info has been added that can be used in conjunction with regular key agreement algorithms.
    • RFC 7748: Added low-level implementations of X25519 and X448.
    -

    2.25.4 Security Related Changes and CVE's Addressed by this Release

    +

    2.29.4 Security Related Changes and CVE's Addressed by this Release

    • CVE-2017-13098 ("ROBOT"), a Bleichenbacher oracle in TLS when RSA key exchange is negotiated. This potentially affected BCJSSE servers and any other TLS servers configured to use JCE for the underlying crypto - note the two TLS implementations using the BC lightweight APIs are not affected by this.
    -

    2.26.1 Version

    +

    2.30.1 Version

    Release: 1.58
    Date:      2017, August 18 -

    2.26.2 Defects Fixed

    +

    2.30.2 Defects Fixed

    • NewHope and SPHINCS keys are now correctly created off certificates by the BC provider.
    • Use of the seeded constructor with SecureRandom() and the BC provider in first position could cause a stack overflow error. This has been fixed.
    • @@ -1014,7 +1130,7 @@

      2.26.2 Defects Fixed

    • A race condition that could occur inside the HybridSecureRandom on reseed and result in an exception has been fixed.
    • DTLS now supports records containing multiple handshake messages.
    -

    2.26.3 Additional Features and Functionality

    +

    2.30.3 Additional Features and Functionality

    • An implementation of GOST3410-2012 has been added to light weight API and the JCA provider.
    • Support for ECDH GOST3410-2012 and GOST3410-2001 have been added. The CMS API can also handle reading ECDH GOST3410 key transport messages.
    • @@ -1034,16 +1150,16 @@

      2.26.3 Additional Features and Functionality

    • The new TLS API now supports RFC 7633 - X.509v3 TLS Feature Extension (e.g. "must staple"), enabled in default clients.
    • TLS exceptions have been made more directly informative.
    -

    2.26.4 Removed Features and Functionality

    +

    2.30.4 Removed Features and Functionality

    • Per RFC 7465, removed support for RC4 in the new TLS API.
    • Per RFC 7568, removed support for SSLv3 in the new TLS API.
    -

    2.27.1 Version

    +

    2.31.1 Version

    Release: 1.57
    Date:      2017, May 11 -

    2.27.2 Defects Fixed

    +

    2.31.2 Defects Fixed

    • A class cast exception for master certification removal in PGPPublicKey.removeCertification() by certification has been fixed.
    • GOST GOFB 28147-89 mode had an edge condition concerning the incorrect calculation of N4 (see section 6.1 of RFC 5830) affecting about 1% of IVs. This has been fixed.
    • @@ -1060,7 +1176,7 @@

      2.27.2 Defects Fixed

    • EC FixedPointCombMultiplier avoids 'infinity' point in lookup tables, reducing timing side-channels.
    • Reuse of a Blake2b digest with a call to reset() rather than doFinal() could result in incorrect padding being introduced and the wrong digest result produced. This has been fixed.
    -

    2.27.3 Additional Features and Functionality

    +

    2.31.3 Additional Features and Functionality

    • ARIA (RFC 5794) is now supported by the provider and the lightweight API.
    • ARIA Key Wrapping (RFC 5649 style) is now supported by the provider and the lightweight API.
    • @@ -1070,23 +1186,23 @@

      2.27.3 Additional Features and Functionality

    • A test client for EST which will interop with the 7030 test server at http://testrfc7030.com/ has been added to the general test module in the current source tree.
    • The BCJSSE provider now supports SSLContext.getDefault(), with very similar behaviour to the SunJSSE provider, including checks of the relevant javax.net.ssl.* system properties and auto-loading of jssecacerts or cacerts as the default trust store.
    -

    2.27.4 Security Related Changes

    +

    2.31.4 Security Related Changes

    • The default parameter sizes for DH and DSA are now 2048. If you have been relying on key pair generation without passing in parameters generated keys will now be larger.
    • Further work has been done on preventing accidental re-use of a GCM cipher without first changing its key or iv.
    -

    2.28.1 Version

    +

    2.32.1 Version

    Release: 1.56
    Date:      2016, December 23 -

    2.28.2 Defects Fixed

    +

    2.32.2 Defects Fixed

    • See section 2.15.4 for Security Defects.
    • Using unknown status with the ASN.1 CertStatus primitive could result in an IllegalArgumentException on construction. This has been fixed.
    • A potentional NullPointerException in a precomputation in WNafUtil has been removed.
    • PGPUtil.getDecoderStream() would throw something other than an IOException for empty and very small data. This has been fixed.
    -

    2.28.3 Additional Features and Functionality

    +

    2.32.3 Additional Features and Functionality

    • Support for the explicit setting of AlgorithmParameters has been added to the JceCMSContentEncryptorBuilder and the JceCMSMacCaculatorBuilder classes to allow configuration of the session cipher/MAC used.
    • EC, ECGOST3410, and DSTU4145 Public keys are now validated on construction in the JCA/JCE and the light weight API.
    • @@ -1102,7 +1218,7 @@

      2.28.3 Additional Features and Functionality

    • SHA-3 support has been added to BcDefaultDigestProvider.
    • A higher level TLS API and JSSE provider have been added to the project.
    -

    2.28.4 Security Related Changes and CVE's Addressed by this Release

    +

    2.32.4 Security Related Changes and CVE's Addressed by this Release

    • It is now possible to configure the provider to only import keys for specific named curves.
    • Work has been done to improve the "constant time" behaviour of the RSA padding mechanisms.
    • @@ -1121,15 +1237,15 @@

      2.28.3 Additional Features and Functionality

    • CVE-2016-1000346: Other party DH public key not fully validated. This can cause issues as invalid keys can be used to reveal details about the other party's private key where static Diffie-Hellman is in use. As of this release the key parameters are checked on agreement calculation.
    • CVE-2016-1000352: ECIES allows the use of unsafe ECB mode. This algorithm is now removed from the provider.
    -

    2.28.5 Security Advisory

    +

    2.32.5 Security Advisory

    • We consider the carry propagation bugs fixed in this release to have been exploitable in previous releases (1.51-1.55), for static ECDH, to reveal the long-term key, per "Practical realisation and elimination of an ECC-related software bug attack", Brumley et.al.. The most common case of this would be the non-ephemeral ECDH ciphersuites in TLS. These are not enabled by default in our TLS implementations, but they can be enabled explicitly by users. We recommend that users DO NOT enable static ECDH ciphersuites for TLS.
    -

    2.29.1 Version

    +

    2.33.1 Version

    Release: 1.55
    Date:      2016, August 18 -

    2.29.2 Defects Fixed

    +

    2.33.2 Defects Fixed

    • Issues with cloning of blake digests with salts and personalisation strings have been fixed.
    • The JceAsymmetricValueDecryptor in the CRMF package now attempts to recognise a wider range of parameters for the key wrapping algorithm, rather than relying on a default.
    • @@ -1150,7 +1266,7 @@

      2.29.2 Defects Fixed

    • Trying to use of non-default parameters for OAEP in CRMF would resort to the default parameter set. This has been fixed.
    • If the BC provider was not registered, creating a CertificateFactory would cause a new provider object to be created. This has been fixed.
    -

    2.29.3 Additional Features and Functionality

    +

    2.33.3 Additional Features and Functionality

    • The DANE API has been updated to reflect the latest standard changes.
    • The signature algorithm SPHINCS-256 has been added to the post-quantum provider (BCPQC). Support is in place for SHA-512 and SHA3-512 (using trees based around SHA512_256 and SHA3_256 respectively).
    • @@ -1168,10 +1284,10 @@

      2.29.3 Additional Features and Functionality

    • Additional search methods have been added to PGP public and secret key rings.
    -

    2.30.1 Version

    +

    2.34.1 Version

    Release: 1.54
    Date:      2015, December 29 -

    2.30.2 Defects Fixed

    +

    2.34.2 Defects Fixed

    • Blake2b-160, Blake2b-256, Blake2b-384, and Blake2b-512 are now actually in the provider and an issue with cloning Blake2b digests has been fixed.
    • PKCS#5 Scheme 2 using DESede CBC is now supported by the PKCS#12 implementation.
    • @@ -1180,7 +1296,7 @@

      2.30.2 Defects Fixed

    • It turns out, after advice one way and another that the NESSIE test vectors for Serpent are now what should be followed and that the vectors in the AES submission are regarded as an algorithm called Tnepres. The Serpent version now follows the NESSIE vectors, and the Tnepres cipher has been added to the provider and the lightweight API for compatibility.
    • Problems with DTLS record-layer version handling were resolved, making version negotiation work properly.
    -

    2.30.3 Additional Features and Functionality

    +

    2.34.3 Additional Features and Functionality

    • Camellia and SEED key wrapping are now supported for CMS key agreement
    • The BC TLS/DTLS code now includes a non-blocking API.
    • @@ -1190,19 +1306,19 @@

      2.30.3 Additional Features and Functionality

    • Support has been added to the CMS API for PKCS#7 ANY type encapsulated content where the encapsulated content is not an OCTET STRING.
    • PSSSigner in the lightweight API now supports fixed salts.
    -

    2.30.4 Security Advisory

    +

    2.34.4 Security Advisory

    • (D)TLS 1.2: Motivated by CVE-2015-7575, we have added validation that the signature algorithm received in DigitallySigned structures is actually one of those offered (in signature_algorithms extension or CertificateRequest). With our default TLS configuration, we do not believe there is an exploitable vulnerability in any earlier releases. Users that are customizing the signature_algorithms extension, or running a server supporting client authentication, are advised to double-check that they are not offering any signature algorithms involving MD5.
    -

    2.30.5 Notes

    +

    2.34.5 Notes

    If you have been using Serpent, you will need to either change to Tnepres, or take into account the fact that Serpent is now byte-swapped compared to what it was before.

    -

    2.31.1 Version

    +

    2.35.1 Version

    Release: 1.53
    Date:      2015, October 10 -

    2.31.2 Defects Fixed

    +

    2.35.2 Defects Fixed

    • The BC JCE cipher implementations could sometimes fail when used in conjunction with the JSSE and NIO. This has been fixed.
    • PGPPublicKey.getBitStrength() always returned 0 for EC keys. This has been fixed.
    • @@ -1227,7 +1343,7 @@

      2.31.2 Defects Fixed

    • Some decidedly odd argument casting in the PKIXCertPathValidator has been fixed to throw an InvalidAlgorithmParameterException.
    • Presenting an empty array of certificates to the PKIXCertPathValidator would cause an IndexOutOfRangeException instead of a CertPathValidatorException. This has been fixed.
    -

    2.31.3 Additional Features and Functionality

    +

    2.35.3 Additional Features and Functionality

    • It is now possible to specify that an unwrapped key must be usable by a software provider in the asymmetric unwrappers for CMS.
    • A Blake2b implementation has been added to the provider and lightweight API.
    • @@ -1243,15 +1359,15 @@

      2.31.3 Additional Features and Functionality

    • The PKCS#12 key store will now garbage collect orphaned certificates on saving.
    • Caching for ASN.1 ObjectIdentifiers has been rewritten to make use of an intern method. The "usual suspects" are now interned automatically, and the cache is used by the parser. Other OIDs can be added to the cache by calling ASN1ObjectIdentifier.intern().
    -

    2.31.4 Notes

    +

    2.35.4 Notes

    It turns out there was a similar, but different, issue in Crypto++ to the BC issue with ECIES. Crypto++ 6.0 now offers a corrected version of ECIES which is compatible with that which is now in BC.

    -

    2.32.1 Version

    +

    2.36.1 Version

    Release: 1.52
    Date:      2015, March 2 -

    2.32.2 Defects Fixed

    +

    2.36.2 Defects Fixed

    • GenericSigner in the lightweight API would fail if the digest started with a zero byte, occasionally causing a TLS negotiation to fail. This has been fixed.
    • Some BC internal classes expected the BC provider to be accessible within the provider. This has been fixed.
    • @@ -1268,7 +1384,7 @@

      2.32.2 Defects Fixed

    • A badly formed issuer in a X.509 certificate could cause a null pointer exception in X509CertificateHolder.toString(). This has been fixed.
    • CMSSignedData.verifySignatures() could fail on a correct counter signature due to a mismatch of the SID. This has been fixed.
    -

    2.32.3 Additional Features and Functionality

    +

    2.36.3 Additional Features and Functionality

    • The CMP support class CMPCertificate restricted the types of certificates that could be added. A more flexible method has been introduced to allow for other certificate types.
    • Support classes have be added for DNS-based Authentication of Named Entities (DANE) to the PKIX distribution.
    • @@ -1296,15 +1412,15 @@

      2.32.3 Additional Features and Functionality

    • Support for some JDK1.5+ language features has finally made its way into the repository.
    • A load store parameter, PKCS12StoreParameter, has been added to support DER only encoding of PKCS12 key stores.
    -

    2.32.4 Security Advisory

    +

    2.36.4 Security Advisory

    • The CTR DRBGs would not populate some bytes in the requested block of random bytes if the size of the block requested was not an exact multiple of the block size of the underlying cipher being used in the DRBG. If you are using the CTR DRBGs with "odd" keysizes, we strongly advise upgrading to this release, or contacting us for a work around.
    -

    2.33.1 Version

    +

    2.37.1 Version

    Release: 1.51
    Date:      2014, July 28 -

    2.33.2 Defects Fixed

    +

    2.37.2 Defects Fixed

    • The AEAD GCM AlgorithmParameters object was unable to return a GCMParameterSpec object. This has been fixed.
    • Cipher.getIV() was returning null for AEAD mode ciphers. This has been fixed.
    • @@ -1319,7 +1435,7 @@

      2.33.2 Defects Fixed

    • PKCS#12 files containing keys/certificates with empty attribute sets attached to them no longer cause an ArrayIndexOutOfBoundsException to be thrown.
    • Issues with certificate verification and server side DTLS/TLS 1.2 have now been fixed.
    -

    2.33.3 Additional Features and Functionality

    +

    2.37.3 Additional Features and Functionality

    • The range of key algorithm names that will be interpreted by KeyAgreement.generateSecret() has been expanded for ECDH derived algorithms in the provider. A KeyAgreement of ECDHwithSHA1KDF can now be explicitly created.
    • ECIES now supports the use of IVs with the underlying block cipher and CBC mode in both the lightweight and the JCE APIs.
    • @@ -1346,17 +1462,17 @@

      2.33.3 Additional Features and Functionality

    • Full support is now provided for client-side auth in the D/TLS server code.
    • Compatibility issues with some OSGI containers have been addressed.
    -

    2.33.4 Notes

    +

    2.37.4 Notes

    • Support for NTRUSigner has been deprecated as the algorithm has been withdrawn.
    • Some changes have affected the return values of some methods. If you are migrating from an earlier release, it is recommended to recompile before using this release.
    • There has been further clean out of deprecated methods in this release. If your code has previously been flagged as using a deprecated method you may need to change it. The OpenPGP API is the most heavily affected.
    -

    2.34.1 Version

    +

    2.38.1 Version

    Release: 1.50
    Date:      2013, December 3 -

    2.34.2 Defects Fixed

    +

    2.38.2 Defects Fixed

    • The DualECSP800DRBG sometimes truncated the last block in the generated stream incorrectly. This has been fixed.
    • Keys produced from RSA certificates with specialised parameters would lose the parameter settings. This has been fixed.
    • @@ -1370,7 +1486,7 @@

      2.34.2 Defects Fixed

    • Default RC2 parameters for 40 bit RC2 keys in CMSEnvelopedData were encoding incorrectly. This has been fixed.
    • In case of a long hash the DSTU4145 implementation would sometimes remove one bit too much during truncation. This has been fixed.
    -

    2.34.3 Additional Features and Functionality

    +

    2.38.3 Additional Features and Functionality

    • Additional work has been done on CMS recipient generation to simplify the generation of OAEP encrypted messages and allow for non-default parameters.
    • OCB implementation updated to account for changes in draft-irtf-cfrg-ocb-03.
    • @@ -1390,7 +1506,7 @@

      2.34.3 Additional Features and Functionality

    • The JDK 1.5+ provider will now recognise and use GCMParameterSpec if it is run in a 1.7 JVM.
    • Client side support and some server side support has been added for TLS/DTLS 1.2.
    -

    2.34.4 Notes

    +

    2.38.4 Notes

    • org.bouncycastle.crypto.DerivationFunction is now a base interface, the getDigest() method appears on DigestDerivationFunction.
    • Recent developments at NIST indicate the SHA-3 may be changed before final standardisation. Please bare this in mind if you are using it.
    • @@ -1400,10 +1516,10 @@

      2.34.4 Notes

    • ECDH support for OpenPGP should still be regarded as experimental. It is still possible there will be compliance issues with other implementations.
    -

    2.35.1 Version

    +

    2.39.1 Version

    Release: 1.49
    Date:      2013, May 31 -

    2.35.2 Defects Fixed

    +

    2.39.2 Defects Fixed

    • Occasional ArrayOutOfBounds exception in DSTU-4145 signature generation has been fixed.
    • The handling of escaped characters in X500 names is much improved.
    • @@ -1414,7 +1530,7 @@

      2.35.2 Defects Fixed

    • PEMParser would throw a NullPointerException if it ran into explicit EC curve parameters, it would also throw an Exception if the named curve was not already defined. The parser now returns X9ECParmameters for explicit parameters and returns an ASN1ObjectIdentifier for a named curve.
    • The V2TBSCertListGenerator was adding the wrong date type for CRL invalidity date extensions. This has been fixed.
    -

    2.35.3 Additional Features and Functionality

    +

    2.39.3 Additional Features and Functionality

    • A SecretKeyFactory has been added that enables use of PBKDF2WithHmacSHA.
    • Support has been added to PKCS12 KeyStores and PfxPdu to handle PKCS#5 encrypted private keys.
    • @@ -1443,16 +1559,16 @@

      2.35.3 Additional Features and Functionality

    • A basic commitment package has been introduced into the lightweight API containing a digest based commitment scheme.
    • It is now possible to set the NotAfter and NotBefore date in the CRMF CertificateRequestMessageBuilder class.
    -

    2.35.4 Notes

    +

    2.39.4 Notes

    • The NTRU implementation has been moved into the org.bouncycastle.pqc package hierarchy.
    • The change to PEMParser to support explicit EC curves is not backward compatible. If you run into a named curve you need to use org.bouncycastle.asn1.x9.ECNamedCurveTable.getByOID() to look the curve up if required.
    -

    2.36.1 Version

    +

    2.40.1 Version

    Release: 1.48
    Date:      2013, February 10 -

    2.36.2 Defects Fixed

    +

    2.40.2 Defects Fixed

    • Occasional key compatibility issues in IES due to variable length keys have been fixed.
    • PEMWriter now recognises the new PKCS10CertificationRequest object.
    • @@ -1463,7 +1579,7 @@

      2.36.2 Defects Fixed

    • The BC SSL implementation has been modified to deal with the "Lucky Thirteen" attack.
    • A regression in 1.47 which prevented key wrapping with regular symmetric PBE algorihtms has been fixed.
    -

    2.36.3 Additional Features and Functionality

    +

    2.40.3 Additional Features and Functionality

    • IES now supports auto generation of ephemeral keys in both the JCE and the lightweight APIs.
    • A new class PEMParser has been added to return the new CertificateHolder and Request objects introduced recently.
    • @@ -1478,10 +1594,10 @@

      2.36.3 Additional Features and Functionality

    • T61String now uses UTF-8 encoding by default rather than a simple 8 bit transform.
    -

    2.37.1 Version

    +

    2.41.1 Version

    Release: 1.47
    Date:      2012, March 30 -

    2.37.2 Defects Fixed

    +

    2.41.2 Defects Fixed

    • OpenPGP ID based certifications now support UTF-8. Note: this may mean that some old certifications no longer validate - if this happens a retry can be added using by converting the ID using Strings.fromByteArray(Strings.toByteArray(id)) - this will strip out the top byte in each character.
    • IPv4/IPv6 parsing in CIDR no longer assumes octet boundaries on a mask.
    • @@ -1498,7 +1614,7 @@

      2.37.2 Defects Fixed

    • Check of DH parameter L could reject some valid keys. This is now fixed.
    -

    2.37.3 Additional Features and Functionality

    +

    2.41.3 Additional Features and Functionality

    • Support is now provided via the RepeatedKey class to enable IV only re-initialisation in the JCE layer. The same effect can be acheived in the light weight API by using null as the key parameter when creating a ParametersWithIV object.
    • CRMF now supports empty poposkInput.
    • @@ -1518,15 +1634,15 @@

      2.37.3 Additional Features and Functionality

    • The J2ME lcrypto release now includes higher level classes for handling PKCS, CMS, CRMF, CMP, EAC, OpenPGP, and certificate generation.
    -

    2.37.4 Other notes

    +

    2.41.4 Other notes

    Okay, so we have had to do another release. The issue we have run into is that we probably didn't go far enough in 1.46, but we are now confident that moving from this release to 2.0 should be largely just getting rid of deprecated methods. While this release does change a lot it is relatively straight forward to do a port and we have a porting guide which explains the important ones. The area there has been the most change in is the ASN.1 library which was in bad need of a rewrite after 10 years of patching. On the bright side the rewrite did allow us to eliminate a few problems and bugs in the ASN.1 library, so we have some hope anyone porting to it will also have similar benefits. As with 1.46 the other point of emphasis has been making sure interface support is available for operations across the major APIs, so the lightweight API or some local role your own methods can be used instead for doing encryption and signing.

    -

    2.38.1 Version

    +

    2.42.1 Version

    Release: 1.46
    Date:      2011, February 23 -

    2.38.2 Defects Fixed

    +

    2.42.2 Defects Fixed

    • An edge condition in ECDSA which could result in an invalid signature has been fixed.
    • Exhaustive testing has been performed on the ASN.1 parser, eliminating another potential OutOfMemoryException and several escaping run time exceptions.
    • @@ -1535,7 +1651,7 @@

      2.38.2 Defects Fixed

    • DERGeneralizedTime.getDate() would produce incorrect results for fractional seconds. This has been fixed.
    • PSSSigner would produce incorrect results if the MGF digest and content digest were not the same. This has been fixed.
    -

    2.38.3 Additional Features and Functionality

    +

    2.42.3 Additional Features and Functionality

    • A null genTime can be passed to TimeStampResponseGenerator.generate() to generate timeNotAvailable error responses.
    • Support has been added for reading and writing of openssl PKCS#8 encrypted keys.
    • @@ -1552,7 +1668,7 @@

      2.38.3 Additional Features and Functionality

    • PGP public subkeys can now be separately decoded and encoded.
    • An IV can now be passed to an ISO9797Alg3Mac.
    -

    2.38.4 Other notes

    +

    2.42.4 Other notes

    Baring security patches we expect 1.46 will be the last of the 1.* releases. The next release of BC will be version 2.0. For this reason a lot of things in 1.46 that relate to CMS have been deprecated and @@ -1569,29 +1685,29 @@

    2.38.4 Other notes

  • The X509Name class will utlimately be replacde with the X500Name class, the getInstance() methods on both these classes allow conversion from one type to another.
  • The org.bouncycastle.cms.RecipientId class now has a collection of subclasses to allow for more specific recipient matching. If you are creating your own recipient ids you should use the constructors for the subclasses rather than relying on the set methods inherited from X509CertSelector. The dependencies on X509CertSelector and CertStore will be removed from the version 2 CMS API.
  • -

    2.39.1 Version

    +

    2.43.1 Version

    Release: 1.45
    Date:      2010, January 12 -

    2.39.2 Defects Fixed

    +

    2.43.2 Defects Fixed

    • OpenPGP now supports UTF-8 in file names for literal data.
    • The ASN.1 library was losing track of the stream limit in a couple of places, leading to the potential of an OutOfMemoryError on a badly corrupted stream. This has been fixed.
    • The provider now uses a privileged block for initialisation.
    • JCE/JCA EC keys are now serialisable.
    -

    2.39.3 Additional Features and Functionality

    +

    2.43.3 Additional Features and Functionality

    • Support for EC MQV has been added to the light weight API, provider, and the CMS/SMIME library.
    -

    2.39.4 Security Advisory

    +

    2.43.4 Security Advisory

    • This version of the provider has been specifically reviewed to eliminate possible timing attacks on algorithms such as GCM and CCM mode.
    -

    2.40.1 Version

    +

    2.44.1 Version

    Release: 1.44
    Date:      2009, October 9 -

    2.40.2 Defects Fixed

    +

    2.44.2 Defects Fixed

    • The reset() method in BufferedAsymmetricBlockCipher is now fully clearing the buffer.
    • Use of ImplicitlyCA with KeyFactory and Sun keyspec no longer causes NullPointerException.
    • @@ -1607,7 +1723,7 @@

      2.40.2 Defects Fixed

    • PKIXCertPathReviewer.getTrustAnchor() could occasionally cause a null pointer exception or an exception due to conflicting trust anchors. This has been fixed.
    • Handling of explicit CommandMap objects with the generation of S/MIME messages has been improved.
    -

    2.40.3 Additional Features and Functionality

    +

    2.44.3 Additional Features and Functionality

    • PEMReader/PEMWriter now support encrypted EC keys.
    • BC generated EC private keys now include optional fields required by OpenSSL.
    • @@ -1623,24 +1739,24 @@

      2.40.3 Additional Features and Functionality

    • Support for raw signatures has been extended to RSA and RSA-PSS in the provider. RSA support can be used in CMSSignedDataStreamGenerator to support signatures without signed attributes.
    -

    2.41.1 Version

    +

    2.45.1 Version

    Release: 1.43
    Date:      2009, April 13 -

    2.41.2 Defects Fixed

    +

    2.45.2 Defects Fixed

    • Multiple countersignature attributes are now correctly collected.
    • Two bugs in HC-128 and HC-256 related to sign extension and byte swapping have been fixed. The implementations now pass the latest ecrypt vector tests.
    • X509Name.hashCode() is now consistent with equals.
    -

    2.41.3 Security Advisory

    +

    2.45.3 Security Advisory

    • The effect of the sign extension bug was to decrease the key space the HC-128 and HC-256 ciphers were operating in and the byte swapping inverted every 32 bits of the generated stream. If you are using either HC-128 or HC-256 you must upgrade to this release.
    -

    2.42.1 Version

    +

    2.46.1 Version

    Release: 1.42
    Date:      2009, March 16 -

    2.42.2 Defects Fixed

    +

    2.46.2 Defects Fixed

    • A NullPointer exception which could be result from generating a diffie-hellman key has been fixed.
    • CertPath validation could occasionally mistakenly identify a delta CRL. This has been fixed.
    • @@ -1653,7 +1769,7 @@

      2.42.2 Defects Fixed

    • Multiplication by negative powers of two is fixed in BigInteger.
    • OptionalValidity now encodes correctly.
    -

    2.42.3 Additional Features and Functionality

    +

    2.46.3 Additional Features and Functionality

    • Support for NONEwithECDSA has been added.
    • Support for Grainv1 and Grain128 has been added.
    • @@ -1664,10 +1780,10 @@

      2.42.3 Additional Features and Functionality

    • Support for the SRP-6a protocol has been added to the lightweight API.
    -

    2.43.1 Version

    +

    2.47.1 Version

    Release: 1.41
    Date:      2008, October 1 -

    2.43.2 Defects Fixed

    +

    2.47.2 Defects Fixed

    • The GeneralName String constructor now supports IPv4 and IPv6 address parsing.
    • An issue with nested-multiparts with postamble for S/MIME that was causing signatures to fail verification has been fixed.
    • @@ -1678,7 +1794,7 @@

      2.43.2 Defects Fixed

    • Standard name "DiffieHellman" is now supported in the provider.
    • Better support for equality tests for '#' encoded entries has been added to X509Name.
    -

    2.43.3 Additional Features and Functionality

    +

    2.47.3 Additional Features and Functionality

    • Camellia is now 12.5% faster than previously.
    • A smaller version (around 8k compiled) of Camellia, CamelliaLightEngine has also been added.
    • @@ -1689,10 +1805,10 @@

      2.43.3 Additional Features and Functionality

    • Support for reading and extracting personalised certificates in PGP Secret Key rings has been added.
    -

    2.44.1 Version

    +

    2.48.1 Version

    Release: 1.40
    Date:      2008, July 12 -

    2.44.2 Defects Fixed

    +

    2.48.2 Defects Fixed

    • EAX mode ciphers were not resetting correctly after a doFinal/reset. This has been fixed.
    • The SMIME API was failing to verify doubly nested multipart objects in signatures correctly. This has been fixed.
    • @@ -1708,7 +1824,7 @@

      2.44.2 Defects Fixed

    • The '+' character can now be escaped or quoted in the constructor for X509Name, X509Prinicipal.
    • Fix to regression from 1.38: PKIXCertPathValidatorResult.getPublicKey was returning the wrong public key when the BC certificate path validator was used.
    -

    2.44.3 Additional Features and Functionality

    +

    2.48.3 Additional Features and Functionality

    • Galois/Counter Mode (GCM) has been added to the lightweight API and the JCE provider.
    • SignedPublicKeyAndChallenge and PKCS10CertificationRequest can now take null providers if you need to fall back to the default provider mechanism.
    • @@ -1716,15 +1832,15 @@

      2.44.3 Additional Features and Functionality

    • Unnecessary local ID attributes on certificates in PKCS12 files are now automatically removed.
    • The PKCS12 store types PKCS12-3DES-3DES and PKCS12-DEF-3DES-3DES have been added to support generation of PKCS12 files with both certificates and keys protected by 3DES.
    -

    2.44.4 Additional Notes

    +

    2.48.4 Additional Notes

    • Due to problems for some users caused by the presence of the IDEA algorithm, an implementation is no longer included in the default signed jars. Only the providers of the form bcprov-ext-*-*.jar now include IDEA.
    -

    2.45.1 Version

    +

    2.49.1 Version

    Release: 1.39
    Date:      2008, March 29 -

    2.45.2 Defects Fixed

    +

    2.49.2 Defects Fixed

    • A bug causing the odd NullPointerException has been removed from the LocalizedMessage class.
    • IV handling in CMS for the SEED and Camellia was incorrect. This has been fixed.
    • @@ -1738,7 +1854,7 @@

      2.45.2 Defects Fixed

    • A decoding issue with a mis-identified tagged object in CertRepMessage has been fixed.
    • \# is now properly recognised in the X509Name class.
    -

    2.45.3 Additional Features and Functionality

    +

    2.49.3 Additional Features and Functionality

    • Certifications associated with user attributes can now be created, verified and removed in OpenPGP.
    • API support now exists for CMS countersignature reading and production.
    • @@ -1753,10 +1869,10 @@

      2.45.3 Additional Features and Functionality

    • Support has been added to the provider for the VMPC MAC.
    -

    2.46.1 Version

    +

    2.50.1 Version

    Release: 1.38
    Date:      2007, November 7 -

    2.46.2 Defects Fixed

    +

    2.50.2 Defects Fixed

    • SMIME signatures containing non-standard quote-printable data could be altered by SMIME encryption. This has been fixed.
    • CMS signatures that do not use signed attributes were vulnerable to one of Bleichenbacher's RSA signature forgery attacks. This has been fixed.
    • @@ -1770,7 +1886,7 @@

      2.46.2 Defects Fixed

    • Overwriting entities in a PKCS#12 file was not fully compliant with the JavaDoc for KeyStore. This has been fixed.
    • TlsInputStream.read() could appear to return end of file when end of file had not been reached. This has been fixed.
    -

    2.46.3 Additional Features and Functionality

    +

    2.50.3 Additional Features and Functionality

    • Buffering in the streaming CMS has been reworked. Throughput is now usually higher and the behaviour is more predictable.
    • It's now possible to pass a table of hashes to a CMS detached signature rather than having to always pass the data.
    • @@ -1781,10 +1897,10 @@

      2.46.3 Additional Features and Functionality

    • CertPathReviewer has better handling for problem trust anchors.
    • Base64 encoder now does initial size calculations to try to improve resource usage.
    -

    2.47.1 Version

    +

    2.51.1 Version

    Release: 1.37
    Date:      2007, June 15 -

    2.47.2 Defects Fixed

    +

    2.51.2 Defects Fixed

    • The ClearSignedFileProcessor example for OpenPGP did not take into account trailing white space in the file to be signed. This has been fixed.
    • @@ -1798,7 +1914,7 @@

      2.47.2 Defects Fixed

    • The default private key length in the lightweght API for generated DiffieHellman parameters was absurdly small, this has been fixed.
    • Cipher.getParameters() for PBEwithSHAAndTwofish-CBC was returning null after intialisation. This has been fixed.
    -

    2.47.3 Additional Features and Functionality

    +

    2.51.3 Additional Features and Functionality

    • The block cipher mode CCM has been added to the provider and light weight API.
    • The block cipher mode EAX has been added to the provider and light weight API.
    • @@ -1817,10 +1933,10 @@

      2.47.3 Additional Features and Functionality

    • The JCE provider now supports RIPEMD160withECDSA.
    -

    2.48.1 Version

    +

    2.52.1 Version

    Release: 1.36
    Date:      2007, March 16 -

    2.48.2 Defects Fixed

    +

    2.52.2 Defects Fixed

    • DSA key generator now checks range and keysize.
    • Class loader issues with i18n classes should now be fixed.
    • @@ -1834,7 +1950,7 @@

      2.48.2 Defects Fixed

    • Some surrogate pairs were not assembled correctly by the UTF-8 decoder. This has been fixed.
    • Alias resolution in PKCS#12 is now case insensitive.
    -

    2.48.3 Additional Features and Functionality

    +

    2.52.3 Additional Features and Functionality

    • CMS/SMIME now supports basic EC KeyAgreement with X9.63.
    • CMS/SMIME now supports RFC 3211 password based encryption.
    • @@ -1850,10 +1966,10 @@

      2.48.3 Additional Features and Functionality

    • DSASigner now handles long messages. SHA2 family digest support for DSA has been added to the provider.
    -

    2.49.1 Version

    +

    2.53.1 Version

    Release: 1.35
    Date:      2006, December 16 -

    2.49.2 Defects Fixed

    +

    2.53.2 Defects Fixed

    • Test data files are no longer in the provider jars.
    • SMIMESignedParser now handles indefinite length data in SignerInfos.
    • @@ -1868,7 +1984,7 @@

      2.49.2 Defects Fixed

    • The IESEngine could incorrectly encrypt data when used in block cipher mode. This has been fixed.
    • An error in the encoding of the KEKRecipientInfo has been fixed. Compatability warning: this may mean that versions of BC mail prior to 1.35 will have trouble processing KEK messages produced by 1.35 or later.
    -

    2.49.3 Additional Features and Functionality

    +

    2.53.3 Additional Features and Functionality

    • Further optimisations to elliptic curve math libraries.
    • API now incorporates a CertStore which should be suitable for use with LDAP.
    • @@ -1890,10 +2006,10 @@

      2.49.3 Additional Features and Functionality

    • PGP packet streams can now be closed off using close() on the returned stream as well as closing the generator.
    -

    2.50.1 Version

    +

    2.54.1 Version

    Release: 1.34
    Date:      2006, October 2 -

    2.50.2 Defects Fixed

    +

    2.54.2 Defects Fixed

    • Endianess of integer conversion in KDF2BytesGenerator was incorrect. This has been fixed.
    • Generating critical signature subpackets in OpenPGP would result in a zero packet tag. This has been fixed. @@ -1905,7 +2021,7 @@

      2.50.2 Defects Fixed

    • PGP Identity strings were only being interpreted as ASCII rather than UTF-8. This has been fixed.
    • CertificateFactory.generateCRLs now returns a Collection rather than null.
    -

    2.50.3 Additional Features and Functionality

    +

    2.54.3 Additional Features and Functionality

    • An ISO18033KDFParameters class had been added to support ISO18033 KDF generators.
    • An implemention of the KDF1 bytes generator algorithm has been added. @@ -1925,16 +2041,16 @@

      2.50.3 Additional Features and Functionality

    • Performance of the prime number generation in the BigInteger library has been further improved.
    • In line with RFC 3280 section 4.1.2.4 DN's are now encoded using UTF8String by default rather than PrintableString.
    -

    2.50.4 Security Advisory

    +

    2.54.4 Security Advisory

    • If you are using public exponents with the value three you *must* upgrade to this release, otherwise it will be possible for attackers to exploit some of Bleichenbacher's RSA signature forgery attacks on your applications.
    -

    2.51.1 Version

    +

    2.55.1 Version

    Release: 1.33
    Date:      2006, May 3 -

    2.51.2 Defects Fixed

    +

    2.55.2 Defects Fixed

    • OCSPResponseData was including the default version in its encoding. This has been fixed.
    • BasicOCSPResp.getVersion() would throw a NullPointer exception if called on a default version response. This has been fixed. @@ -1943,7 +2059,7 @@

      2.51.2 Defects Fixed

    • ArmoredInputStream was not closing the underlying stream on close. This has been fixed.
    • Small base64 encoded strings with embedded white space could decode incorrectly using the Base64 class. This has been fixed.
    -

    2.51.3 Additional Features and Functionality

    +

    2.55.3 Additional Features and Functionality

    • The X509V2CRLGenerator now supports adding general extensions to CRL entries.
    • A RoleSyntax implementation has been added to the x509 ASN.1 package, and the AttributeCertificateHolder class now support the IssuerSerial option. @@ -1951,10 +2067,10 @@

      2.51.3 Additional Features and Functionality

    • DERUTF8String now supports surrogate pairs.
    -

    2.52.1 Version

    +

    2.56.1 Version

    Release: 1.32
    Date:      2006, March 27 -

    2.52.2 Defects Fixed

    +

    2.56.2 Defects Fixed

    • Further work has been done on RFC 3280 compliance.
    • The ASN1Sequence constructor for SemanticsInformation would sometimes throw a ClassCastException on reconstruction an object from a byte stream. This has been fixed. @@ -1971,7 +2087,7 @@

      2.52.2 Defects Fixed

    • OpenPGP clear text signatures containing '\r' as line separators were not being correctly canonicalized. This has been fixed.
    -

    2.52.3 Additional Features and Functionality

    +

    2.56.3 Additional Features and Functionality

    • The ASN.1 library now includes classes for the ICAO Electronic Passport.
    • Support has been added to CMS and S/MIME for ECDSA. @@ -1980,16 +2096,16 @@

      2.52.3 Additional Features and Functionality

    • Support has been added for repeated attributes in CMS and S/MIME messages.
    • A wider range of RSA-PSS signature types is now supported for CRL and Certificate verification.
    -

    2.52.4 Possible compatibility issue

    +

    2.56.4 Possible compatibility issue

    • Previously elliptic curve keys and points were generated with point compression enabled by default. Owing to patent issues in some jurisdictions, they are now generated with point compression disabled by default.
    -

    2.53.1 Version

    +

    2.57.1 Version

    Release: 1.31
    Date:      2005, December 29 -

    2.53.2 Defects Fixed

    +

    2.57.2 Defects Fixed

    • getCriticalExtensionOIDs on an X.509 attribute certificate was returning the non-critical set. This has been fixed.
    • Encoding uncompressed ECDSA keys could occasionally introduce an extra leading zero byte. This has been fixed. @@ -2002,7 +2118,7 @@

      2.53.2 Defects Fixed

      This has been fixed.
    • OIDs with extremely large components would sometimes reencode with unnecessary bytes in their encoding. The optimal DER encoding will now be produced instead.
    -

    2.53.3 Additional Features and Functionality

    +

    2.57.3 Additional Features and Functionality

    • The SMIME package now supports the large file streaming model as well.
    • Additional ASN.1 message support has been added for RFC 3739 in the org.bouncycastle.x509.qualified package. @@ -2011,10 +2127,10 @@

      2.53.3 Additional Features and Functionality

    • CertPathValidator has been updated to better support path validation as defined in RFC 3280.
    -

    2.54.1 Version

    +

    2.58.1 Version

    Release: 1.30
    Date:      2005, September 18 -

    2.54.2 Defects Fixed

    +

    2.58.2 Defects Fixed

    • Whirlpool was calculating the wrong digest for 31 byte data and could throw an exception for some other data lengths. This has been fixed.
    • AlgorithmParameters for IVs were returning a default of RAW encoding of the parameters when they should have been returning an @@ -2026,7 +2142,7 @@

      2.54.2 Defects Fixed

    • KEKIdentifier would not handle OtherKeyAttribute objects correctly. This has been fixed.
    • GetCertificateChain on a PKCS12 keystore would return a single certificate chain rather than null if the alias passed in represented a certificate not a key. This has been fixed.
    -

    2.54.3 Additional Features and Functionality

    +

    2.58.3 Additional Features and Functionality

    • RSAEngine no longer assumes keys are byte aligned when checking for out of range input.
    • PGPSecretKeyRing.removeSecretKey and PGPSecretKeyRing.insertSecretKey have been added. @@ -2037,10 +2153,10 @@

      2.54.3 Additional Features and Functionality

    • Both the lightweight API and the provider now support the Camellia encryption algorithm.
    -

    2.55.1 Version

    +

    2.59.1 Version

    Release: 1.29
    Date:      2005, June 27 -

    2.55.2 Defects Fixed

    +

    2.59.2 Defects Fixed

    • HMac-SHA384 and HMac-SHA512 were not IETF compliant. This has been fixed.
    • The equals() method on ElGamalKeyParameters and DHKeyParameters in the lightweight API would sometimes @@ -2051,7 +2167,7 @@

      2.55.2 Defects Fixed

    • ISO9796 signatures for full recovered messsages could incorrectly verify for similar messages in some circumstances. This has been fixed.
    • The occasional problem with decrypting PGP messages containing compressed streams now appears to be fixed.
    -

    2.55.3 Additional Features and Functionality

    +

    2.59.3 Additional Features and Functionality

    • Support has been added for the OIDs and key generation required for HMac-SHA224, HMac-SHA256, HMac-SHA384, and HMac-SHA512. @@ -2059,16 +2175,16 @@

      2.55.3 Additional Features and Functionality

    • The provider and the lightweight API now support the GOST-28147-94 MAC algorithm.
    • Headers are now settable for PGP armored output streams.
    -

    2.55.4 Notes

    +

    2.59.4 Notes

    • The old versions of HMac-SHA384 and HMac-SHA512 can be invoked as OldHMacSHA384 and OldHMacSHA512, or by using the OldHMac class in the lightweight API.
    -

    2.56.1 Version

    +

    2.60.1 Version

    Release: 1.28
    Date:      2005, April 20 -

    2.56.2 Defects Fixed

    +

    2.60.2 Defects Fixed

    • Signatures on binary encoded S/MIME messages could fail to validate when correct. This has been fixed.
    • getExtensionValue() on CRL Entries were returning the encoding of the inner object, rather than the octet string. This has been fixed. @@ -2082,7 +2198,7 @@

      2.56.2 Defects Fixed

    • Filetype for S/MIME compressed messages was incorrect. This has been fixed.
    • BigInteger class can now create negative numbers from byte arrays.
    -

    2.56.3 Additional Features and Functionality

    +

    2.60.3 Additional Features and Functionality

    • S/MIME now does canonicalization on non-binary input for signatures.
    • Micalgs for the new SHA schemes are now supported. @@ -2093,7 +2209,7 @@

      2.56.3 Additional Features and Functionality

    • Support has been added for the creation of ECDSA certificate requests.
    • The provider and the light weight API now support the WHIRLPOOL message digest.
    -

    2.56.4 Notes

    +

    2.60.4 Notes

    • Patches for S/MIME binary signatures and canonicalization were actually applied in 1.27, but a couple of days after the release - if the class CMSProcessableBodyPartOutbound is present in the package org.bouncycastle.mail.smime you have the patched 1.27. We would recommend upgrading to 1.28 in any case @@ -2101,10 +2217,10 @@

      2.56.4 Notes

    • GOST private keys are probably not encoding correctly and can be expected to change.
    -

    2.57.1 Version

    +

    2.61.1 Version

    Release: 1.27
    Date:      2005, February 20 -

    2.57.2 Defects Fixed

    +

    2.61.2 Defects Fixed

    • Typos in the provider which pointed Signature algorithms SHA256WithRSA, SHA256WithRSAEncryption, SHA384WithRSA, SHA384WithRSAEncryption, SHA512WithRSA, and SHA512WithRSAEncryption at the PSS versions of the algorithms have been fixed. The correct names for the PSS algorithms are SHA256withRSAandMGF1, SHA384withRSAandMGF1, and SHA512withRSAandMGF1.
    • X509CertificateFactory failed under some circumstances to reset properly if the input stream being passed @@ -2118,7 +2234,7 @@

      2.57.2 Defects Fixed

    • TSP TimeStampToken was failing to validate time stamp tokens with the issuerSerial field set in the ESSCertID structure. This has been fixed.
    • Path validation in environments with frequently updated CRLs could occasionally reject a valid path. This has been fixed.
    -

    2.57.3 Additional Features and Functionality

    +

    2.61.3 Additional Features and Functionality

    • Full support has been added for the OAEPParameterSpec class to the JDK 1.5 povider.
    • Full support has been added for the PSSParameterSpec class to the JDK 1.4 and JDK 1.5 providers. @@ -2129,7 +2245,7 @@

      2.57.3 Additional Features and Functionality

    • The CertPath support classes now support PKCS #7 encoding.
    • Point compression can now be turned off when encoding elliptic curve keys.
    -

    2.57.4 Changes that may affect compatibility

    +

    2.61.4 Changes that may affect compatibility

    • org.bouncycastle.jce.interfaces.ElGamalKey.getParams() has been changed to getParameters() to avoid clashes with a JCE interface with the same method signature. @@ -2139,10 +2255,10 @@

      2.57.4 Changes that may affect compatibility

      were using these previously you should use SHA256WithRSAAndMGF1, SHA384WithRSAAndMGF1, or SHA512WithRSAAndMGF1.
    -

    2.58.1 Version

    +

    2.62.1 Version

    Release: 1.26
    Date:      2005, January 15 -

    2.58.2 Defects Fixed

    +

    2.62.2 Defects Fixed

    • The X.509 class UserNotice assumed some of the optional fields were not optional. This has been fixed.
    • BCPGInputStream would break on input packets of 8274 bytes in length. This has been fixed. @@ -2151,7 +2267,7 @@

      2.58.2 Defects Fixed

    • ASN1Sets now properly sort their contents when created from scratch.
    • A bug introduced in the CertPath validation in the last release which meant some certificate paths would validate if they were invalid has been fixed.
    -

    2.58.3 Additional Features and Functionality

    +

    2.62.3 Additional Features and Functionality

    • Support for JDK 1.5 naming conventions for OAEP encryption and PSS signing has been added.
    • Support for Time Stamp Protocol (RFC 3161) has been added. @@ -2161,15 +2277,15 @@

      2.58.3 Additional Features and Functionality

    • PBEWithMD5AndRC2, PBEWithSHA1AndRC2 now generate keys rather than exceptions.
    • The BigInteger implementation has been further optimised to take more advantage of the Montgomery number capabilities.
    -

    2.58.4 JDK 1.5 Changes

    +

    2.62.4 JDK 1.5 Changes

    • The JDK 1.5 version of the provider now supports the new Elliptic Curve classes found in the java.security packages. Note: while we have tried to preserve some backwards compatibility people using Elliptic curve are likely to find some minor code changes are required when moving code from JDK 1.4 to JDK 1.5 as the java.security APIs have changed.
    -

    2.59.1 Version

    +

    2.63.1 Version

    Release: 1.25
    Date:      2004, October 1 -

    2.59.2 Defects Fixed

    +

    2.63.2 Defects Fixed

    • In some situations OpenPGP would overread when a stream had been broken up into partial blocks. This has been fixed. @@ -2191,7 +2307,7 @@

      2.59.2 Defects Fixed

    • Parsing a message with a zero length body with SMIMESigned would cause an exception. This has been fixed.
    • Some versions of PGP use zeros in the data stream rather than a replication of the last two bytes of the iv as specified in the RFC to determine if the correct decryption key has been found. The decryption classes will now cope with both.
    -

    2.59.3 Additional Features and Functionality

    +

    2.63.3 Additional Features and Functionality

    • Support for extracting signatures based on PGP user attributes has been added to PGPPublicKey. @@ -2211,10 +2327,10 @@

      2.59.3 Additional Features and Functionality

    • OID components of up to 2^63 bits are now supported.
    -

    2.60.1 Version

    +

    2.64.1 Version

    Release: 1.24
    Date:      2004, June 12 -

    2.60.2 Defects Fixed

    +

    2.64.2 Defects Fixed

    • OpenPGP Secret key rings now parse key rings with user attribute packets in them correctly.
    • OpenPGP Secret key rings now parse key rings with GPG comment packets in them. @@ -2231,17 +2347,17 @@

      2.60.2 Defects Fixed

    • An encoding error introduced in 1.23 which affected generation of the KeyUsage extension has been fixed.
    -

    2.60.3 Additional Features and Functionality

    +

    2.64.3 Additional Features and Functionality

    • PKCS12 keystore now handles single key/certificate files without any attributes present.
    • Support for creation of PGPKeyRings incorporating sub keys has been added.
    • ZeroPadding for encrypting ASCII data has been added.
    -

    2.61.1 Version

    +

    2.65.1 Version

    Release: 1.23
    Date:      2004, April 10 -

    2.61.2 Defects Fixed

    +

    2.65.2 Defects Fixed

    • Reading a PGP Secret key file would sometimes cause a class cast exception. This has been fixed.
    • PGP will now read SecretKeys which are encrypted with the null algorithm. @@ -2256,7 +2372,7 @@

      2.61.2 Defects Fixed

    • X509Name class will now print names with nested pairs in component sets correctly.
    • RC4 now resets correctly on doFinal.
    -

    2.61.3 Additional Features and Functionality

    +

    2.65.3 Additional Features and Functionality

    • PGP V3 keys and V3 signature generation is now supported.
    • Collection classes have been added for representing files of PGP public and secret keys. @@ -2275,10 +2391,10 @@

      2.61.3 Additional Features and Functionality

    • DERGeneralizedTime getTime() method now handles a broader range of input strings.
    -

    2.62.1 Version

    +

    2.66.1 Version

    Release: 1.22
    Date:      2004, February 7 -

    2.62.2 Defects Fixed

    +

    2.66.2 Defects Fixed

    • Generating DSA signatures with PGP would cause a class cast exception, this has been fixed.
    • PGP Data in the 192 to 8383 byte length would sometimes be written with the wrong length header. This has been fixed. @@ -2288,7 +2404,7 @@

      2.62.2 Defects Fixed

    • PSS signature verification would fail approximately 0.5 % of the time on correct signatures. This has been fixed.
    • Encoding of CRL Distribution Points now always works.
    -

    2.62.3 Additional Features and Functionality

    +

    2.66.3 Additional Features and Functionality

    • Additional methods for getting public key information have been added to the PGP package.
    • Some support for user attributes and the image attribute tag has been added. @@ -2296,10 +2412,10 @@

      2.62.3 Additional Features and Functionality

    • Support for ElGamal encryption/decryption has been added to the PGP package.
    -

    2.63.1 Version

    +

    2.67.1 Version

    Release: 1.21
    Date:      2003, December 6 -

    2.63.2 Defects Fixed

    +

    2.67.2 Defects Fixed

    • The CertPath validator would fail for some valid CRLs. This has been fixed.
    • AES OIDS for S/MIME were still incorrect, this has been fixed. @@ -2307,17 +2423,17 @@

      2.63.2 Defects Fixed

    • The J2ME BigInteger class would sometimes go into an infinite loop generating prime numbers. This has been fixed.
    • DERBMPString.equals() would throw a class cast exception. This has been fixed.
    -

    2.63.3 Additional Features and Functionality

    +

    2.67.3 Additional Features and Functionality

    • PEMReader now handles public keys.
    • OpenPGP/BCPG should now handle partial input streams. Additional methods for reading subpackets off signatures.
    • The ASN.1 library now supports policy qualifiers and policy info objects.
    -

    2.64.1 Version

    +

    2.68.1 Version

    Release: 1.20
    Date:      2003, October 8 -

    2.64.2 Defects Fixed

    +

    2.68.2 Defects Fixed

    • BigInteger toString() in J2ME/JDK1.0 now produces same output as the Sun one.
    • RSA would throw a NullPointer exception with doFinal without arguments. This has been fixed. @@ -2327,7 +2443,7 @@

      2.64.2 Defects Fixed

    • AES OIDS were incorrect, this has been fixed.
    • In some cases BC generated private keys would not work with the JSSE. This has been fixed.
    -

    2.64.3 Additional Features and Functionality

    +

    2.68.3 Additional Features and Functionality

    • Support for reading/writing OpenPGP public/private keys and OpenPGP signatures has been added.
    • Support for generating OpenPGP PBE messages and public key encrypted messages has been added. @@ -2335,10 +2451,10 @@

      2.64.3 Additional Features and Functionality

    • Addition of a Null block cipher to the light weight API.
    -

    2.65.1 Version

    +

    2.69.1 Version

    Release: 1.19
    Date:      2003, June 7 -

    2.65.2 Defects Fixed

    +

    2.69.2 Defects Fixed

    • The PKCS12 store would throw an exception reading PFX files that had attributes with no values. This has been fixed.
    • RSA Private Keys would not serialise if they had PKCS12 bag attributes attached to them, this has been fixed. @@ -2346,7 +2462,7 @@

      2.65.2 Defects Fixed

    • ASN1 parser would sometimes mistake an implicit null for an implicit empty sequence. This has been fixed.
    -

    2.65.3 Additional Features and Functionality

    +

    2.69.3 Additional Features and Functionality

    • S/MIME and CMS now support the draft standard for AES encryption.
    • S/MIME and CMS now support setable key sizes for the standard algorithms. @@ -2358,10 +2474,10 @@

      2.65.3 Additional Features and Functionality

      in order to find algorithms.
    -

    2.66.1 Version

    +

    2.70.1 Version

    Release: 1.18
    Date:      2003, February 8 -

    2.66.2 Defects Fixed

    +

    2.70.2 Defects Fixed

    • DESKeySpec.isParityAdjusted in the clean room JCE could go into an infinite loop. This has been fixed. @@ -2372,7 +2488,7 @@

      2.66.2 Defects Fixed

    • Seeding with longs in the SecureRandom for the J2ME and JDK 1.0, only used 4 bytes of the seed value. This has been fixed.
    -

    2.66.3 Additional Features and Functionality

    +

    2.70.3 Additional Features and Functionality

    • The X.509 OID for RSA is now recognised by the provider as is the OID for RSA/OAEP.
    • Default iv's for DES are now handled correctly in CMS. @@ -2384,10 +2500,10 @@

      2.66.3 Additional Features and Functionality

      Sun BigInteger library.
    -

    2.67.1 Version

    +

    2.71.1 Version

    Release: 1.17
    Date:      2003, January 8 -

    2.67.2 Defects Fixed

    +

    2.71.2 Defects Fixed

    • Reuse of an CMSSignedObject could occasionally result in a class cast exception. This has been fixed. @@ -2398,7 +2514,7 @@

      2.67.2 Defects Fixed

    • The DERObject constructor in OriginatorIdentifierOrKey was leaving the id field as null. This has been fixed.
    -

    2.67.3 Additional Functionality and Features

    +

    2.71.3 Additional Functionality and Features

    • RC2 now supports the full range of parameter versions and effective key sizes. @@ -2418,10 +2534,10 @@

      2.67.3 Additional Functionality and Features

      string to OID conversion.
    -

    2.68.1 Version

    +

    2.72.1 Version

    Release: 1.16
    Date:      2002, November 30 -

    2.68.2 Defects Fixed

    +

    2.72.2 Defects Fixed

    • CRLS were only working for UTC time constructed Time objects, this has been fixed. @@ -2435,7 +2551,7 @@

      2.68.2 Defects Fixed

      to throw a NullPointerException at the wrong time.
    • Macs now clone correctly in the clean room JCE.
    -

    2.68.3 Additional Functionality and Features

    +

    2.72.3 Additional Functionality and Features

    • PGPCFB support has been added to the provider and the lightweight API.
    • There are now three versions of the AESEngine, all faster than before, @@ -2453,10 +2569,10 @@

      2.68.3 Additional Functionality and Features

      and to support multiple recipients/signers.
    -

    2.69.1 Version

    +

    2.73.1 Version

    Release: 1.15
    Date:      2002, September 6 -

    2.69.2 Defects Fixed

    +

    2.73.2 Defects Fixed

    • The base string for the oids in asn1.x509.KeyPurposeId was incorrect. This has been fixed. @@ -2479,7 +2595,7 @@

      2.69.2 Defects Fixed

      The local name now takes precedence.
    • ReasonFlags now correctly encodes.
    -

    2.69.3 Additional Functionality and Features

    +

    2.73.3 Additional Functionality and Features

    • The PKCS12 key store now handles key bags in encryptedData bags.
    • The X509NameTokenizer now handles for '\' and '"' characters. @@ -2488,10 +2604,10 @@

      2.69.3 Additional Functionality and Features

    • Both the provider and the lightweight library now support a basic SIC mode for block ciphers.
    -

    2.70.1 Version

    +

    2.74.1 Version

    Release: 1.14
    Date:      2002, June 17 -

    2.70.2 Defects Fixed

    +

    2.74.2 Defects Fixed

    • there was a bug in the BigInteger right shifting for > 31 bit shifts. This has been fixed. @@ -2512,7 +2628,7 @@

      2.70.2 Defects Fixed

    • asn1.x509.ExtendedKeyUsage used to throw a null pointer exception on construction. This has been fixed.
    -

    2.70.3 Additional Functionality and Features

    +

    2.74.3 Additional Functionality and Features

    • The BigInteger library now uses Montgomery numbers for modPow and is substantially faster. @@ -2526,10 +2642,10 @@

      2.70.3 Additional Functionality and Features

      object identifiers.
    -

    2.71.1 Version

    +

    2.75.1 Version

    Release: 1.13
    Date:      2002, April 19 -

    2.71.2 Defects Fixed

    +

    2.75.2 Defects Fixed

    • The TBSCertificate object in the ASN.1 library now properly implements the Time object, rather returning UTC time. @@ -2538,7 +2654,7 @@

      2.71.2 Defects Fixed

    • toByteArray in the big integer class was not always producing correct results for negative numbers. This has been Fixed.
    -

    2.71.3 Additional Functionality and Features

    +

    2.75.3 Additional Functionality and Features

    • The key to keySpec handling of the secret key factories has been improved.
    • There is now a SMIME implementation and a more complete CMS @@ -2553,10 +2669,10 @@

      2.71.3 Additional Functionality and Features

      length certificate chains for signing keys.
    -

    2.72.1 Version

    +

    2.76.1 Version

    Release: 1.12
    Date:      2002, February 8 -

    2.72.2 Defects Fixed

    +

    2.76.2 Defects Fixed

    • The ASN.1 library was unable to read an empty set object. This has been fixed.
    • Returning sets of critical and non-critical extensions on X.509 certificates could result in a null pointer exception if the certificate had no extensions. This has been fixed. @@ -2575,7 +2691,7 @@

      2.72.2 Defects Fixed

    • the IV algorithm parameters class would improperly throw an exception on initialisation. This has been fixed.
    -

    2.72.3 Additional Functionality and Features

    +

    2.76.3 Additional Functionality and Features

    • The AESWrap ciphers will now take IV's.
    • The DES-EDEWrap algorithm described in https://www.ietf.org/internet-drafts/draft-ietf-smime-key-wrap-01.txt is now supported. @@ -2589,10 +2705,10 @@

      2.72.3 Additional Functionality and Features

      for details).
    -

    2.73.1 Version

    +

    2.77.1 Version

    Release: 1.11
    Date:      2001, December 10 -

    2.73.2 Defects Fixed

    +

    2.77.2 Defects Fixed

    • X9.23 padding of MACs now works correctly with block size aligned data.
    • Loading a corrupted "UBER" key store would occasionally cause the @@ -2618,7 +2734,7 @@

      2.73.2 Defects Fixed

      extensions. This has been fixed.
    • The NetscapeCert type bits were reversed! This has been fixed.
    -

    2.73.3 Additional Functionality and Features

    +

    2.77.3 Additional Functionality and Features

    • The lightweight API and the JCE provider now support ElGamal.
    • X509Principal, and X509Name now supports the "DC" attribute and the @@ -2632,7 +2748,7 @@

      2.73.3 Additional Functionality and Features

    • Elliptic curve routines now handle uncompressed points as well as the compressed ones.
    -

    2.73.4 Other changes

    +

    2.77.4 Other changes

    • As the range of public key types supported has expanded the getPublicKey method on the SubjectPublicKeyInfo class is not always going to work. The @@ -2640,10 +2756,10 @@

      2.73.4 Other changes

      throws an IOException if there is a problem.
    -

    2.74.1 Version

    +

    2.78.1 Version

    Release: 1.10
    Date:      2001, October 20 -

    2.74.2 Defects Fixed

    +

    2.78.2 Defects Fixed

    • The PKCS12 Key Store now interoperates with the JDK key tool. Note: this does mean the the key name passed to the setKeyEntry calls has become significant. @@ -2651,7 +2767,7 @@

      2.74.2 Defects Fixed

      has been fixed.
    • The ASN.1 input streams now handle zero-tagged zero length objects correctly.
    -

    2.74.3 Additional Functionality and Features

    +

    2.78.3 Additional Functionality and Features

    • The JCE Provider and the lightweight API now support Serpent, CAST5, and CAST6.
    • The JCE provider and the lightweight API now has an implementation of ECIES. @@ -2661,10 +2777,10 @@

      2.74.3 Additional Functionality and Features

    • Support for the generation of PKCS10 certification requests has been added.
    -

    2.75.1 Version

    +

    2.79.1 Version

    Release: 1.09
    Date:      2001, October 6 -

    2.75.2 Defects Fixed

    +

    2.79.2 Defects Fixed

    • failure to pass in an RC5 parameters object now results in an exception at the upper level of the JCE, rather than falling over in the lightweight @@ -2677,7 +2793,7 @@

      2.75.2 Defects Fixed

    • In some cases the ASN.1 library wouldn't handle implicit tagging properly. This has been fixed.
    -

    2.75.3 Additional Functionality and Features

    +

    2.79.3 Additional Functionality and Features

    • Support for RC5-64 has been added to the JCE.
    • ISO9796-2 signatures have been added to the JCE and lightweight API. @@ -2701,10 +2817,10 @@

      2.75.3 Additional Functionality and Features

      resource hungry and faster - whether it's fast enough remains to be seen!
    -

    2.76.1 Version

    +

    2.80.1 Version

    Release: 1.08
    Date:      2001, September 9 -

    2.76.2 Defects Fixed

    +

    2.80.2 Defects Fixed

    • It wasn't possible to specify an ordering for distinguished names in X509 certificates. This is now supported. @@ -2715,7 +2831,7 @@

      2.76.2 Defects Fixed

    • The netscape certificate request class wouldn't compile under JDK 1.1. This has been fixed.
    -

    2.76.3 Additional Functionality and Features

    +

    2.80.3 Additional Functionality and Features

    • ISO 9796-1 padding is now supported with RSA in the lightweight API and the JCE. @@ -2729,10 +2845,10 @@

      2.76.3 Additional Functionality and Features

      this is fixed.
    -

    2.77.1 Version

    +

    2.81.1 Version

    Release: 1.07
    Date:      2001, July 9 -

    2.77.2 Defects Fixed

    +

    2.81.2 Defects Fixed

    • It turned out that the setOddParity method in the DESParameter class was indeed doing something odd but not what was intended. This is now @@ -2743,10 +2859,10 @@

      2.77.2 Defects Fixed

      have a look in org.bouncycastle.jce.provider.JDKKeyStore lines 201-291.
    -

    2.78.1 Version

    +

    2.82.1 Version

    Release: 1.06
    Date:      2001, July 2 -

    2.78.2 Defects Fixed

    +

    2.82.2 Defects Fixed

    • Diffie-Hellman keys are now properly serialisable as well as encodable. @@ -2768,17 +2884,17 @@

      2.78.2 Defects Fixed

    • Resetting and resusing HMacs in the lightweight and heavyweight libraries caused a NullPointer exception. This has been fixed.
    -

    2.78.3 Additional Functionality

    +

    2.82.3 Additional Functionality

    • ISO10126Padding is now recognised explicitly for block ciphers as well.
    • The Blowfish implementation is now somewhat faster.
    -

    2.79.1 Version

    +

    2.83.1 Version

    Release: 1.05
    Date:      2001, April 17 -

    2.79.2 Defects Fixed

    +

    2.83.2 Defects Fixed

    • The DESEDE key generator can now be used to generate 2-Key-DESEDE keys as well as 3-Key-DESEDE keys. @@ -2789,22 +2905,22 @@

      2.79.2 Defects Fixed

    • The ASN.1 library was skipping explicitly tagged objects of zero length. This has been fixed.
    -

    2.79.3 Additional Functionality

    +

    2.83.3 Additional Functionality

    • There is now an org.bouncycastle.jce.netscape package which has a class in for dealing with Netscape Certificate Request objects.
    -

    2.79.4 Additional Notes

    +

    2.83.4 Additional Notes

    Concerning the PKCS12 fix: in a few cases this may cause some backward compatibility issues - if this happens to you, drop us a line at feedback-crypto@bouncycastle.org and we will help you get it sorted out.

    -

    2.80.1 Version

    +

    2.84.1 Version

    Release: 1.04
    Date:      2001, March 11 -

    2.80.2 Defects Fixed

    +

    2.84.2 Defects Fixed

    • Signatures generated by other providers that include optional null parameters in the AlgorithmIdentifier are now handled correctly by the @@ -2833,7 +2949,7 @@

      2.80.2 Defects Fixed

      hash table when the hash table constructor was called. This has been fixed.
    -

    2.80.3 Additional Functionality

    +

    2.84.3 Additional Functionality

    • Added Elliptic Curve DSA (X9.62) - ECDSA - to provider and lightweight library. @@ -2845,10 +2961,10 @@

      2.80.3 Additional Functionality

    • The certificate generators now support ECDSA and DSA certs as well.
    -

    2.81.1 Version

    +

    2.85.1 Version

    Release: 1.03
    Date:      2001, January 7 -

    2.81.2 Defects Fixed

    +

    2.85.2 Defects Fixed

    • CFB and OFB modes when specified without padding would insist on input being block aligned. When specified without padding CFB and OFB now behave in a compatible @@ -2858,29 +2974,29 @@

      2.81.2 Defects Fixed

      length as the plain text.
    -

    2.82.1 Version

    +

    2.86.1 Version

    Release: 1.02
    Date:      2000, November 7 -

    2.82.2 Defects Fixed

    +

    2.86.2 Defects Fixed

    • The RSA key pair generator occasionally produced keys 1 bit under the requested size. This is now fixed.
    -

    2.83.1 Version

    +

    2.87.1 Version

    Release: 1.01
    Date:      2000, October 15 -

    2.83.2 Defects Fixed

    +

    2.87.2 Defects Fixed

    • Buffered ciphers in lightweight library were not resetting correctly on a doFinal. This has been fixed.
    -

    2.84.1 Version

    +

    2.88.1 Version

    Release: 1.00
    Date:      2000, October 13 -

    2.84.2 Defects Fixed

    +

    2.88.2 Defects Fixed

    • JDK1.2 version now works with keytool for certificate generation. @@ -2895,7 +3011,7 @@

      2.84.2 Defects Fixed

    • Some DES PBE algorithms did not set the parity correctly in generated keys, this has been fixed.
    -

    2.84.3 Additional functionality

    +

    2.88.3 Additional functionality

    • Argument validation is much improved. diff --git a/docs/specifications.html b/docs/specifications.html index 6b7c989165..ebc8d12582 100644 --- a/docs/specifications.html +++ b/docs/specifications.html @@ -1028,6 +1028,51 @@

      Signature Algorithms

    • SHA512withXMSSMT-SHA512
    • SHAKE128withXMSSMT-SHAKE128
    • SHAKE256withXMSSMT-SHAKE256
    • +
    • MLDSA44
    • +
    • MLDSA65
    • +
    • MLDSA87
    • +
    • MLDSA44-ECDSA-P256-SHA256
    • +
    • MLDSA44-Ed25519-SHA512
    • +
    • MLDSA44-RSA2048-PKCS15-SHA256
    • +
    • MLDSA44-RSA2048-PSS-SHA256
    • +
    • MLDSA65-ECDSA-P256-SHA512
    • +
    • MLDSA65-ECDSA-brainpoolP256r1-SHA512
    • +
    • MLDSA65-ECDSA-P384-SHA512
    • +
    • MLDSA65-Ed25519-SHA512
    • +
    • MLDSA65-RSA3072-PKCS15-SHA512
    • +
    • MLDSA65-RSA3072-PSS-SHA512
    • +
    • MLDSA65-RSA4096-PKCS15-SHA512
    • +
    • MLDSA65-RSA4096-PSS-SHA512
    • +
    • MLDSA87-ECDSA-P384-SHA512
    • +
    • MLDSA87-ECDSA-brainpoolP384r1-SHA512
    • +
    • MLDSA87-ECDSA-P521-SHA512
    • +
    • MLDSA87-Ed448-SHAKE256
    • +
    • MLDSA87-RSA3072-PSS-SHA512
    • +
    • MLDSA87-RSA4096-PSS-SHA512
    • +
    • SLH-DSA-SHA2-128F
    • +
    • SLH-DSA-SHA2-128S
    • +
    • SLH-DSA-SHA2-192F
    • +
    • SLH-DSA-SHA2-192S
    • +
    • SLH-DSA-SHA2-256F
    • +
    • SLH-DSA-SHA2-256S
    • +
    • SLH-DSA-SHAKE-128F
    • +
    • SLH-DSA-SHAKE-128S
    • +
    • SLH-DSA-SHAKE-192F
    • +
    • SLH-DSA-SHAKE-192S
    • +
    • SLH-DSA-SHAKE-256F
    • +
    • SLH-DSA-SHAKE-256S
    • +
    • SLH-DSA-SHA2-128F-WITH-SHA256
    • +
    • SLH-DSA-SHA2-128S-WITH-SHA256
    • +
    • SLH-DSA-SHA2-192F-WITH-SHA512
    • +
    • SLH-DSA-SHA2-192S-WITH-SHA512
    • +
    • SLH-DSA-SHA2-256F-WITH-SHA512
    • +
    • SLH-DSA-SHA2-256S-WITH-SHA512
    • +
    • SLH-DSA-SHAKE-128F-WITH-SHAKE128
    • +
    • SLH-DSA-SHAKE-128S-WITH-SHAKE128
    • +
    • SLH-DSA-SHAKE-192F-WITH-SHAKE256
    • +
    • SLH-DSA-SHAKE-192S-WITH-SHAKE256
    • +
    • SLH-DSA-SHAKE-256F-WITH-SHAKE256
    • +
    • SLH-DSA-SHAKE-256S-WITH-SHAKE256

    Password Hashing and PBE

    diff --git a/gradle.properties b/gradle.properties index 88edbf693d..455d1be300 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ org.gradle.jvmargs=-Xmx2g -version=1.80-SNAPSHOT -maxVersion=1.81 +version=1.84-SNAPSHOT +maxVersion=1.85 org.gradle.java.installations.auto-detect=false org.gradle.java.installations.auto-download=false -org.gradle.java.installations.fromEnv=BC_JDK8,BC_JDK11,BC_JDK17 +org.gradle.java.installations.fromEnv=BC_JDK8,BC_JDK11,BC_JDK17,BC_JDK21,BC_JDK25 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd49177..8bdaf60c75 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a4413138c9..2e1113280e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a4269..ef07e0162b 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -112,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -203,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. @@ -211,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 93e3f59f13..db3a6ac207 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,22 +59,22 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/jmail/build.gradle b/jmail/build.gradle index 5a3bc6ef26..4be328057c 100644 --- a/jmail/build.gradle +++ b/jmail/build.gradle @@ -1,6 +1,6 @@ plugins { - id "biz.aQute.bnd.builder" version "7.0.0" + id "biz.aQute.bnd.builder" version "7.1.0" } jar.archiveBaseName = "bcjmail-$vmrange" @@ -83,6 +83,11 @@ jar { manifest.attributes('Export-Package': "org.bouncycastle.mail.*;version=${v}") manifest.attributes('Import-Package': "java.*;resolution:=optional,javax.*;resolution:=optional,jakarta.*;resolution:=optional,!org.bouncycastle.mail.*,org.bouncycastle.*;version=\"[${v},${maxVersion})\"") manifest.attributes('Bundle-Version': "${v}") + manifest.attributes('Permissions': 'all-permissions') + manifest.attributes('Codebase': '*') + manifest.attributes('Application-Library-Allowable-Codebase': '*') + manifest.attributes('Caller-Allowable-Codebase': '*') + manifest.attributes('Trusted-Library': 'true') } task sourcesJar(type: Jar) { diff --git a/mail/build.gradle b/mail/build.gradle index 0c3be2b56f..90ed0f8fb9 100644 --- a/mail/build.gradle +++ b/mail/build.gradle @@ -1,5 +1,5 @@ plugins { - id "biz.aQute.bnd.builder" version "7.0.0" + id "biz.aQute.bnd.builder" version "7.1.0" } jar.archiveBaseName = "bcmail-$vmrange" @@ -62,6 +62,11 @@ jar { manifest.attributes('Export-Package': "org.bouncycastle.mail.*;version=${v}") manifest.attributes('Import-Package': "java.*;resolution:=optional,javax.*;resolution:=optional,!org.bouncycastle.mail.*,org.bouncycastle.*;version=\"[${v},${maxVersion})\"") manifest.attributes('Bundle-Version': "${v}") + manifest.attributes('Permissions': 'all-permissions') + manifest.attributes('Codebase': '*') + manifest.attributes('Application-Library-Allowable-Codebase': '*') + manifest.attributes('Caller-Allowable-Codebase': '*') + manifest.attributes('Trusted-Library': 'true') } task sourcesJar(type: Jar) { @@ -108,4 +113,4 @@ publishing { } -} \ No newline at end of file +} diff --git a/mail/src/main/java/org/bouncycastle/mail/smime/SMIMEAuthEnvelopedGenerator.java b/mail/src/main/java/org/bouncycastle/mail/smime/SMIMEAuthEnvelopedGenerator.java index 99d2ab17bd..c8d1235492 100644 --- a/mail/src/main/java/org/bouncycastle/mail/smime/SMIMEAuthEnvelopedGenerator.java +++ b/mail/src/main/java/org/bouncycastle/mail/smime/SMIMEAuthEnvelopedGenerator.java @@ -12,8 +12,8 @@ import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.cms.CMSAuthEnvelopedDataGenerator; import org.bouncycastle.cms.CMSAuthEnvelopedDataStreamGenerator; +import org.bouncycastle.cms.CMSAuthEnvelopedGenerator; import org.bouncycastle.cms.CMSException; import org.bouncycastle.cms.RecipientInfoGenerator; import org.bouncycastle.operator.OutputAEADEncryptor; @@ -38,9 +38,9 @@ public class SMIMEAuthEnvelopedGenerator extends SMIMEEnvelopedGenerator { - public static final String AES128_GCM = CMSAuthEnvelopedDataGenerator.AES128_GCM; - public static final String AES192_GCM = CMSAuthEnvelopedDataGenerator.AES192_GCM; - public static final String AES256_GCM = CMSAuthEnvelopedDataGenerator.AES256_GCM; + public static final String AES128_GCM = CMSAuthEnvelopedGenerator.AES128_GCM; + public static final String AES192_GCM = CMSAuthEnvelopedGenerator.AES192_GCM; + public static final String AES256_GCM = CMSAuthEnvelopedGenerator.AES256_GCM; static final String AUTH_ENVELOPED_DATA_CONTENT_TYPE = "application/pkcs7-mime; name=\"smime.p7m\"; smime-type=authEnveloped-data"; diff --git a/mail/src/main/java/org/bouncycastle/mail/smime/SMIMEEnvelopedUtil.java b/mail/src/main/java/org/bouncycastle/mail/smime/SMIMEEnvelopedUtil.java index fe4dae9089..ed7ee3e591 100644 --- a/mail/src/main/java/org/bouncycastle/mail/smime/SMIMEEnvelopedUtil.java +++ b/mail/src/main/java/org/bouncycastle/mail/smime/SMIMEEnvelopedUtil.java @@ -1,7 +1,6 @@ package org.bouncycastle.mail.smime; import java.util.HashSet; -import java.util.Set; import javax.mail.MessagingException; import javax.mail.internet.MimeBodyPart; @@ -13,13 +12,13 @@ public class SMIMEEnvelopedUtil { - private static Set authOIDs = new HashSet(); + private static final HashSet AUTH_OIDS = new HashSet(); static { - authOIDs.add(NISTObjectIdentifiers.id_aes128_GCM); - authOIDs.add(NISTObjectIdentifiers.id_aes128_GCM); - authOIDs.add(NISTObjectIdentifiers.id_aes128_GCM); + AUTH_OIDS.add(NISTObjectIdentifiers.id_aes128_GCM); + AUTH_OIDS.add(NISTObjectIdentifiers.id_aes192_GCM); + AUTH_OIDS.add(NISTObjectIdentifiers.id_aes256_GCM); } /** @@ -32,7 +31,7 @@ public class SMIMEEnvelopedUtil */ public static RecipientInformationStore getRecipientInfos(MimeBodyPart message) throws MessagingException, CMSException { - if(message.getContentType().equals(SMIMEAuthEnvelopedGenerator.AUTH_ENVELOPED_DATA_CONTENT_TYPE)) + if (message.getContentType().equals(SMIMEAuthEnvelopedGenerator.AUTH_ENVELOPED_DATA_CONTENT_TYPE)) { return new SMIMEAuthEnveloped(message).getRecipientInfos(); } @@ -48,7 +47,7 @@ public static RecipientInformationStore getRecipientInfos(MimeBodyPart message) */ public static SMIMEEnvelopedGenerator createGenerator(ASN1ObjectIdentifier algorithm) { - if (authOIDs.contains(algorithm)) + if (AUTH_OIDS.contains(algorithm)) { return new SMIMEAuthEnvelopedGenerator(); } diff --git a/mail/src/main/java/org/bouncycastle/mail/smime/SMIMESigned.java b/mail/src/main/java/org/bouncycastle/mail/smime/SMIMESigned.java index fd8698cc04..2a080a76dd 100644 --- a/mail/src/main/java/org/bouncycastle/mail/smime/SMIMESigned.java +++ b/mail/src/main/java/org/bouncycastle/mail/smime/SMIMESigned.java @@ -23,6 +23,8 @@ /** * general class for handling a pkcs7-signature message. *

    + * (SMIMESignedParser may be preferred e.g. for large files, since it avoids loading all the data at once). + *

    * A simple example of usage - note, in the example below the validity of * the certificate isn't verified, just the fact that one of the certs * matches the given signer... diff --git a/mail/src/main/java/org/bouncycastle/mail/smime/SMIMESignedGenerator.java b/mail/src/main/java/org/bouncycastle/mail/smime/SMIMESignedGenerator.java index 3d359848eb..acbf65892d 100644 --- a/mail/src/main/java/org/bouncycastle/mail/smime/SMIMESignedGenerator.java +++ b/mail/src/main/java/org/bouncycastle/mail/smime/SMIMESignedGenerator.java @@ -253,7 +253,7 @@ public void addAttributeCertificates( } private void addHashHeader( - StringBuffer header, + StringBuilder header, List signers) { int count = 0; @@ -343,7 +343,7 @@ private MimeMultipart make( // // build the multipart header // - StringBuffer header = new StringBuffer( + StringBuilder header = new StringBuilder( "signed; protocol=\"application/pkcs7-signature\""); List allSigners = new ArrayList(_signers); diff --git a/mail/src/main/java/org/bouncycastle/mail/smime/SMIMESignedParser.java b/mail/src/main/java/org/bouncycastle/mail/smime/SMIMESignedParser.java index 964aa5c270..00172b74ac 100644 --- a/mail/src/main/java/org/bouncycastle/mail/smime/SMIMESignedParser.java +++ b/mail/src/main/java/org/bouncycastle/mail/smime/SMIMESignedParser.java @@ -64,8 +64,8 @@ public class SMIMESignedParser extends CMSSignedDataParser { - Object message; - MimeBodyPart content; + protected Object message; + protected MimeBodyPart content; private static File getTmpFile() throws MessagingException diff --git a/mail/src/main/java/org/bouncycastle/mail/smime/SMIMEUtil.java b/mail/src/main/java/org/bouncycastle/mail/smime/SMIMEUtil.java index e52697204f..030ddd9622 100644 --- a/mail/src/main/java/org/bouncycastle/mail/smime/SMIMEUtil.java +++ b/mail/src/main/java/org/bouncycastle/mail/smime/SMIMEUtil.java @@ -237,7 +237,7 @@ static void outputPostamble(LineOutputStream lOut, BodyPart parent, String paren private static String readLine(InputStream in) throws IOException { - StringBuffer b = new StringBuffer(); + StringBuilder b = new StringBuilder(); int ch; while ((ch = in.read()) >= 0 && ch != '\n') diff --git a/mail/src/main/java/org/bouncycastle/mail/smime/examples/ValidateSignedMail.java b/mail/src/main/java/org/bouncycastle/mail/smime/examples/ValidateSignedMail.java index 79b4b80f2c..b820f6400c 100644 --- a/mail/src/main/java/org/bouncycastle/mail/smime/examples/ValidateSignedMail.java +++ b/mail/src/main/java/org/bouncycastle/mail/smime/examples/ValidateSignedMail.java @@ -26,9 +26,9 @@ import javax.mail.internet.MimeMessage; import javax.security.auth.x500.X500Principal; -import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.NameConstraints; import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; import org.bouncycastle.cms.SignerInformation; import org.bouncycastle.jce.provider.BouncyCastleProvider; @@ -42,7 +42,6 @@ */ public class ValidateSignedMail { - /* * Use trusted certificates from $JAVA_HOME/lib/security/cacerts as * trustanchors @@ -51,7 +50,6 @@ public class ValidateSignedMail public static void main(String[] args) throws Exception { - Security.addProvider(new BouncyCastleProvider()); // @@ -62,8 +60,7 @@ public static void main(String[] args) throws Exception Session session = Session.getDefaultInstance(props, null); // read message - MimeMessage msg = new MimeMessage(session, new FileInputStream( - "signed.message")); + MimeMessage msg = new MimeMessage(session, new FileInputStream("signed.message")); // create PKIXparameters PKIXParameters param; @@ -137,8 +134,7 @@ public static void verifySignedMail(MimeMessage msg, PKIXParameters param) SignedMailValidator validator = new SignedMailValidator(msg, param); // iterate over all signatures and print results - Iterator it = validator.getSignerInformationStore().getSigners() - .iterator(); + Iterator it = validator.getSignerInformationStore().getSigners().iterator(); while (it.hasNext()) { SignerInformation signer = (SignerInformation) it.next(); @@ -279,27 +275,26 @@ public static void verifySignedMail(MimeMessage msg, PKIXParameters param) } } } - } - protected static TrustAnchor getTrustAnchor(String trustcert) - throws Exception + protected static TrustAnchor getTrustAnchor(String trustcert) throws Exception { X509Certificate cert = loadCert(trustcert); - if (cert != null) + if (cert == null) { - byte[] ncBytes = cert - .getExtensionValue(Extension.nameConstraints.getId()); + return null; + } - if (ncBytes != null) - { - ASN1Encodable extValue = JcaX509ExtensionUtils - .parseExtensionValue(ncBytes); - return new TrustAnchor(cert, extValue.toASN1Primitive().getEncoded(ASN1Encoding.DER)); - } - return new TrustAnchor(cert, null); + byte[] nameConstraints = null; + + byte[] ncExtValue = cert.getExtensionValue(Extension.nameConstraints.getId()); + if (ncExtValue != null) + { + NameConstraints nc = NameConstraints.getInstance(JcaX509ExtensionUtils.parseExtensionValue(ncExtValue)); + nameConstraints = nc.getEncoded(ASN1Encoding.DER); } - return null; + + return new TrustAnchor(cert, nameConstraints); } protected static X509Certificate loadCert(String certfile) @@ -350,5 +345,4 @@ private static TrustAnchor getDummyTrustAnchor() throws Exception PublicKey trustPubKey = kpg.generateKeyPair().getPublic(); return new TrustAnchor(principal, trustPubKey, null); } - } diff --git a/mail/src/main/java/org/bouncycastle/mail/smime/validator/SignedMailValidator.java b/mail/src/main/java/org/bouncycastle/mail/smime/validator/SignedMailValidator.java index a6c99488de..f63b62075d 100644 --- a/mail/src/main/java/org/bouncycastle/mail/smime/validator/SignedMailValidator.java +++ b/mail/src/main/java/org/bouncycastle/mail/smime/validator/SignedMailValidator.java @@ -24,6 +24,7 @@ import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -32,16 +33,12 @@ import javax.mail.internet.InternetAddress; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; +import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1IA5String; -import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1String; -import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.cms.Attribute; import org.bouncycastle.asn1.cms.AttributeTable; import org.bouncycastle.asn1.cms.CMSAttributes; @@ -52,11 +49,15 @@ import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; import org.bouncycastle.asn1.x509.ExtendedKeyUsage; import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.KeyPurposeId; -import org.bouncycastle.asn1.x509.TBSCertificate; import org.bouncycastle.cert.jcajce.JcaCertStoreBuilder; +import org.bouncycastle.cert.jcajce.JcaX500NameUtil; +import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; import org.bouncycastle.cms.SignerInformation; import org.bouncycastle.cms.SignerInformationStore; +import org.bouncycastle.cms.SignerInformationVerifier; import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; import org.bouncycastle.cms.jcajce.JcaX509CertSelectorConverter; import org.bouncycastle.mail.smime.SMIMESigned; @@ -73,18 +74,17 @@ public class SignedMailValidator private static final Class DEFAULT_CERT_PATH_REVIEWER = PKIXCertPathReviewer.class; - private static final String EXT_KEY_USAGE = Extension.extendedKeyUsage - .getId(); - - private static final String SUBJECT_ALTERNATIVE_NAME = Extension.subjectAlternativeName - .getId(); - private static final int shortKeyLength = 512; // (365.25*30)*24*3600*1000 private static final long THIRTY_YEARS_IN_MILLI_SEC = 21915l * 12l * 3600l * 1000l; - private static final JcaX509CertSelectorConverter selectorConverter = new JcaX509CertSelectorConverter(); + private static final JcaX509CertSelectorConverter SELECTOR_CONVERTER = new JcaX509CertSelectorConverter(); + + private static final int KU_DIGITAL_SIGNATURE = 0; + private static final int KU_NON_REPUDIATION = 1; + + private static final Locale locale = Locale.getDefault(); private CertStore certs; @@ -97,50 +97,46 @@ public class SignedMailValidator private Class certPathReviewerClass; /** - * Validates the signed {@link MimeMessage} message. The - * {@link PKIXParameters} from param are used for the certificate path - * validation. The actual PKIXParameters used for the certificate path - * validation is a copy of param with the followin changes:
    - The - * validation date is changed to the signature time
    - A CertStore with - * certificates and crls from the mail message is added to the CertStores.
    + * Validates the signed {@link MimeMessage} message. The {@link PKIXParameters} from + * param are used for the certificate path validation. The actual + * {@link PKIXParameters} used for the certificate path validation are a copy of param + * with the following changes:
    + * - The validation date is changed to the signature time.
    + * - A CertStore with certificates and CRLs from the mail message is added to the CertStores.
    *
    - * In param it's also possible to add additional CertStores - * with intermediate Certificates and/or CRLs which then are also used for - * the validation. + * In param it's also possible to add additional CertStores with intermediate + * certificates and/or CRLs which then are also used for the validation. * - * @param message the signed MimeMessage - * @param param the parameters for the certificate path validation - * @throws SignedMailValidatorException if the message is no signed message or if an exception occurs - * reading the message + * @param message the signed {@link MimeMessage}. + * @param param the parameters for the certificate path validation. + * @throws SignedMailValidatorException if the message is not a signed message or if an + * exception occurs reading the message. */ - public SignedMailValidator(MimeMessage message, PKIXParameters param) - throws SignedMailValidatorException + public SignedMailValidator(MimeMessage message, PKIXParameters param) throws SignedMailValidatorException { this(message, param, DEFAULT_CERT_PATH_REVIEWER); } /** - * Validates the signed {@link MimeMessage} message. The - * {@link PKIXParameters} from param are used for the certificate path - * validation. The actual PKIXParameters used for the certificate path - * validation is a copy of param with the followin changes:
    - The - * validation date is changed to the signature time
    - A CertStore with - * certificates and crls from the mail message is added to the CertStores.
    + * Validates the signed {@link MimeMessage} message. The {@link PKIXParameters} from + * param are used for the certificate path validation. The actual + * {@link PKIXParameters} used for the certificate path validation are a copy of param + * with the following changes:
    + * - The validation date is changed to the signature time.
    + * - A CertStore with certificates and CRLs from the mail message is added to the CertStores.
    *
    - * In param it's also possible to add additional CertStores - * with intermediate Certificates and/or CRLs which then are also used for - * the validation. + * In param it's also possible to add additional CertStores with intermediate + * certificates and/or CRLs which then are also used for the validation. * - * @param message the signed MimeMessage - * @param param the parameters for the certificate path validation + * @param message the signed {@link MimeMessage}. + * @param param the parameters for the certificate path validation. * @param certPathReviewerClass a subclass of {@link PKIXCertPathReviewer}. The SignedMailValidator - * uses objects of this type for the cert path vailidation. The class must - * have an empty constructor. - * @throws SignedMailValidatorException if the message is no signed message or if an exception occurs - * reading the message - * @throws IllegalArgumentException if the certPathReviewerClass is not a - * subclass of {@link PKIXCertPathReviewer} or objects of - * certPathReviewerClass can not be instantiated + * uses objects of this type for the cert path vailidation. The class must have an empty + * constructor. + * @throws SignedMailValidatorException if the message is not a signed message or if an exception + * occurs reading the message. + * @throws IllegalArgumentException if the certPathReviewerClass is not a subclass of + * {@link PKIXCertPathReviewer} or objects of certPathReviewerClass can not be instantiated. */ public SignedMailValidator(MimeMessage message, PKIXParameters param, Class certPathReviewerClass) throws SignedMailValidatorException @@ -149,33 +145,35 @@ public SignedMailValidator(MimeMessage message, PKIXParameters param, Class cert boolean isSubclass = DEFAULT_CERT_PATH_REVIEWER.isAssignableFrom(certPathReviewerClass); if (!isSubclass) { - throw new IllegalArgumentException("certPathReviewerClass is not a subclass of " + DEFAULT_CERT_PATH_REVIEWER.getName()); + throw new IllegalArgumentException( + "certPathReviewerClass is not a subclass of " + DEFAULT_CERT_PATH_REVIEWER.getName()); } - SMIMESigned s; - try { // check if message is multipart signed + SMIMESigned s; if (message.isMimeType("multipart/signed")) { - MimeMultipart mimemp = (MimeMultipart)message.getContent(); + MimeMultipart mimemp = (MimeMultipart) message.getContent(); s = new SMIMESigned(mimemp); } - else if (message.isMimeType("application/pkcs7-mime") - || message.isMimeType("application/x-pkcs7-mime")) + else if (message.isMimeType("application/pkcs7-mime") || message.isMimeType("application/x-pkcs7-mime")) { s = new SMIMESigned(message); } else { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.noSignedMessage"); + ErrorBundle msg = createErrorBundle("SignedMailValidator.noSignedMessage"); throw new SignedMailValidatorException(msg); } // save certstore and signerInformationStore - certs = new JcaCertStoreBuilder().addCertificates(s.getCertificates()).addCRLs(s.getCRLs()).setProvider("BC").build(); + certs = new JcaCertStoreBuilder() + .addCertificates(s.getCertificates()) + .addCRLs(s.getCRLs()) + .setProvider("BC") + .build(); signers = s.getSignerInfos(); // save "from" addresses from message @@ -190,14 +188,14 @@ else if (message.isMimeType("application/pkcs7-mime") } catch (MessagingException ex) { - //ignore garbage in Sender: header + // ignore garbage in Sender: header } int fromsLength = (froms != null) ? froms.length : 0; fromAddresses = new String[fromsLength + ((sender != null) ? 1 : 0)]; for (int i = 0; i < fromsLength; i++) { - InternetAddress inetAddr = (InternetAddress)froms[i]; + InternetAddress inetAddr = (InternetAddress) froms[i]; fromAddresses[i] = inetAddr.getAddress(); } if (sender != null) @@ -212,24 +210,29 @@ else if (message.isMimeType("application/pkcs7-mime") { if (e instanceof SignedMailValidatorException) { - throw (SignedMailValidatorException)e; + throw (SignedMailValidatorException) e; } // exception reading message - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.exceptionReadingMessage", - new Object[]{e.getMessage(), e, e.getClass().getName()}); + ErrorBundle msg = createErrorBundle("SignedMailValidator.exceptionReadingMessage", e); throw new SignedMailValidatorException(msg, e); } - // validate signatues + // validate signatures validateSignatures(param); } protected void validateSignatures(PKIXParameters pkixParam) + { + JcaSimpleSignerInfoVerifierBuilder signerInfoVerifierBuilder = new JcaSimpleSignerInfoVerifierBuilder() + .setProvider("BC"); + validateSignatures(signerInfoVerifierBuilder, pkixParam); + } + + protected void validateSignatures(JcaSimpleSignerInfoVerifierBuilder signerInfoVerifierBuilder, PKIXParameters pkixParam) { PKIXParameters usedParameters = (PKIXParameters)pkixParam.clone(); - // add crls and certs from mail + // add CRLs and certs from mail usedParameters.addCertStore(certs); Collection c = signers.getSigners(); @@ -243,208 +246,178 @@ protected void validateSignatures(PKIXParameters pkixParam) SignerInformation signer = (SignerInformation)it.next(); // signer certificate - X509Certificate cert = null; + X509Certificate signerCert = null; try { - Collection certCollection = findCerts(usedParameters - .getCertStores(), selectorConverter.getCertSelector(signer.getSID())); - - Iterator certIt = certCollection.iterator(); - if (certIt.hasNext()) - { - cert = (X509Certificate)certIt.next(); - } + X509CertSelector selector = SELECTOR_CONVERTER.getCertSelector(signer.getSID()); + signerCert = findFirstCert(usedParameters.getCertStores(), selector, null); } catch (CertStoreException cse) { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.exceptionRetrievingSignerCert", - new Object[]{cse.getMessage(), cse, cse.getClass().getName()}); + ErrorBundle msg = createErrorBundle("SignedMailValidator.exceptionRetrievingSignerCert", cse); errors.add(msg); } - if (cert != null) + if (signerCert == null) { + // no signer certificate found + ErrorBundle msg = createErrorBundle("SignedMailValidator.noSignerCert"); + errors.add(msg); + results.put(signer, new ValidationResult(null, false, errors, notifications, null)); + continue; + } + + boolean validSignature; + try + { + SignerInformationVerifier verifier = signerInfoVerifierBuilder + .build(signerCert.getPublicKey()); + // check signature - boolean validSignature = false; + validSignature = isValidSignature(verifier, signer, errors); + } + catch (Exception e) + { + validSignature = false; + ErrorBundle msg = createErrorBundle("SignedMailValidator.exceptionVerifyingSignature", e); + errors.add(msg); + } + + // check signer certificate (mail address, key usage, etc) + checkSignerCert(signerCert, errors, notifications); + + // notify if a signed receipt request is in the message + AttributeTable atab = signer.getSignedAttributes(); + if (atab != null) + { + Attribute attr = atab.get(PKCSObjectIdentifiers.id_aa_receiptRequest); + if (attr != null) + { + ErrorBundle msg = createErrorBundle("SignedMailValidator.signedReceiptRequest"); + notifications.add(msg); + } + } + + // check certificate path + + // get signing time if possible, otherwise use current time as signing time + Date signTime = getSignatureTime(signer); + if (signTime == null) // no signing time was found + { + ErrorBundle msg = createErrorBundle("SignedMailValidator.noSigningTime"); + notifications.add(msg); + signTime = pkixParam.getDate(); + if (signTime == null) + { + signTime = new Date(); + } + } + else + { + // check if certificate was valid at signing time try { - validSignature = signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert.getPublicKey())); - if (!validSignature) - { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.signatureNotVerified"); - errors.add(msg); - } + signerCert.checkValidity(signTime); } - catch (Exception e) + catch (CertificateExpiredException e) { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.exceptionVerifyingSignature", - new Object[]{e.getMessage(), e, e.getClass().getName()}); + ErrorBundle msg = createErrorBundle("SignedMailValidator.certExpired", + new Object[]{ new TrustedInput(signTime), new TrustedInput(signerCert.getNotAfter()) }); errors.add(msg); } - - // check signer certificate (mail address, key usage, etc) - checkSignerCert(cert, errors, notifications); - - // notify if a signed receip request is in the message - AttributeTable atab = signer.getSignedAttributes(); - if (atab != null) + catch (CertificateNotYetValidException e) { - Attribute attr = atab.get(PKCSObjectIdentifiers.id_aa_receiptRequest); - if (attr != null) - { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.signedReceiptRequest"); - notifications.add(msg); - } + ErrorBundle msg = createErrorBundle("SignedMailValidator.certNotYetValid", + new Object[]{ new TrustedInput(signTime), new TrustedInput(signerCert.getNotBefore()) }); + errors.add(msg); } + } + usedParameters.setDate(signTime); + + try + { + // construct cert chain + ArrayList userCertStores = new ArrayList(); + userCertStores.add(certs); - // check certificate path + Object[] cpres = createCertPath(signerCert, usedParameters.getTrustAnchors(), pkixParam.getCertStores(), + userCertStores); + CertPath certPath = (CertPath)cpres[0]; + List userProvidedList = (List)cpres[1]; - // get signing time if possible, otherwise use current time as - // signing time - Date signTime = getSignatureTime(signer); - if (signTime == null) // no signing time was found + // validate cert chain + PKIXCertPathReviewer review; + try { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.noSigningTime"); - notifications.add(msg); - signTime = pkixParam.getDate(); - if (signTime == null) - { - signTime = new Date(); - } + review = (PKIXCertPathReviewer)certPathReviewerClass.newInstance(); } - else + catch (IllegalAccessException e) { - // check if certificate was valid at signing time - try - { - cert.checkValidity(signTime); - } - catch (CertificateExpiredException e) - { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.certExpired", - new Object[]{new TrustedInput(signTime), new TrustedInput(cert.getNotAfter())}); - errors.add(msg); - } - catch (CertificateNotYetValidException e) - { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.certNotYetValid", - new Object[]{new TrustedInput(signTime), new TrustedInput(cert.getNotBefore())}); - errors.add(msg); - } + throw new IllegalArgumentException("Cannot instantiate object of type " + + certPathReviewerClass.getName() + ": " + e.getMessage()); } - usedParameters.setDate(signTime); - - try + catch (InstantiationException e) { - // construct cert chain - CertPath certPath; - List userProvidedList; - - List userCertStores = new ArrayList(); - userCertStores.add(certs); - Object[] cpres = createCertPath(cert, usedParameters.getTrustAnchors(), pkixParam.getCertStores(), userCertStores); - certPath = (CertPath)cpres[0]; - userProvidedList = (List)cpres[1]; - - // validate cert chain - PKIXCertPathReviewer review; - try - { - review = (PKIXCertPathReviewer)certPathReviewerClass.newInstance(); - } - catch (IllegalAccessException e) - { - throw new IllegalArgumentException("Cannot instantiate object of type " + - certPathReviewerClass.getName() + ": " + e.getMessage()); - } - catch (InstantiationException e) - { - throw new IllegalArgumentException("Cannot instantiate object of type " + - certPathReviewerClass.getName() + ": " + e.getMessage()); - } - review.init(certPath, usedParameters); - if (!review.isValidCertPath()) - { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.certPathInvalid"); - errors.add(msg); - } - results.put(signer, new ValidationResult(review, - validSignature, errors, notifications, userProvidedList)); + throw new IllegalArgumentException("Cannot instantiate object of type " + + certPathReviewerClass.getName() + ": " + e.getMessage()); } - catch (GeneralSecurityException gse) + review.init(certPath, usedParameters); + if (!review.isValidCertPath()) { - // cannot create cert path - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.exceptionCreateCertPath", - new Object[]{gse.getMessage(), gse, gse.getClass().getName()}); + ErrorBundle msg = createErrorBundle("SignedMailValidator.certPathInvalid"); errors.add(msg); - results.put(signer, new ValidationResult(null, - validSignature, errors, notifications, null)); - } - catch (CertPathReviewerException cpre) - { - // cannot initialize certpathreviewer - wrong parameters - errors.add(cpre.getErrorMessage()); - results.put(signer, new ValidationResult(null, - validSignature, errors, notifications, null)); } + results.put(signer, + new ValidationResult(review, validSignature, errors, notifications, userProvidedList)); } - else - // no signer certificate found + catch (GeneralSecurityException gse) { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.noSignerCert"); + // cannot create cert path + ErrorBundle msg = createErrorBundle("SignedMailValidator.exceptionCreateCertPath", gse); errors.add(msg); - results.put(signer, new ValidationResult(null, false, errors, - notifications, null)); + results.put(signer, new ValidationResult(null, validSignature, errors, notifications, null)); + } + catch (CertPathReviewerException cpre) + { + // cannot initialize certpathreviewer - wrong parameters + errors.add(cpre.getErrorMessage()); + results.put(signer, new ValidationResult(null, validSignature, errors, notifications, null)); } } } - public static Set getEmailAddresses(X509Certificate cert) - throws IOException, CertificateEncodingException + public static Set getEmailAddresses(X509Certificate cert) throws IOException, CertificateEncodingException { - Set addresses = new HashSet(); - - TBSCertificate tbsCertificate = getTBSCert(cert); + HashSet addresses = new HashSet(); - RDN[] rdns = tbsCertificate.getSubject().getRDNs(PKCSObjectIdentifiers.pkcs_9_at_emailAddress); + RDN[] rdns = JcaX500NameUtil.getSubject(cert).getRDNs(PKCSObjectIdentifiers.pkcs_9_at_emailAddress); for (int i = 0; i < rdns.length; i++) { AttributeTypeAndValue[] atVs = rdns[i].getTypesAndValues(); for (int j = 0; j != atVs.length; j++) { - if (atVs[j].getType().equals(PKCSObjectIdentifiers.pkcs_9_at_emailAddress)) + if (PKCSObjectIdentifiers.pkcs_9_at_emailAddress.equals(atVs[j].getType())) { - String email = ((ASN1String)atVs[j].getValue()).getString().toLowerCase(); + String email = ((ASN1String)atVs[j].getValue()).getString().toLowerCase(locale); addresses.add(email); } } } - byte[] ext = cert.getExtensionValue(SUBJECT_ALTERNATIVE_NAME); - if (ext != null) + byte[] sanExtValue = cert.getExtensionValue(Extension.subjectAlternativeName.getId()); + if (sanExtValue != null) { - ASN1Sequence altNames = ASN1Sequence.getInstance(getObject(ext)); - for (int j = 0; j < altNames.size(); j++) - { - ASN1TaggedObject o = (ASN1TaggedObject)altNames - .getObjectAt(j); + GeneralNames san = GeneralNames.getInstance(JcaX509ExtensionUtils.parseExtensionValue(sanExtValue)); - if (o.getTagNo() == 1) + GeneralName[] names = san.getNames(); + for (int i = 0; i < names.length; ++i) + { + GeneralName name = names[i]; + if (name.getTagNo() == GeneralName.rfc822Name) { - String email = ASN1IA5String.getInstance(o, false) - .getString().toLowerCase(); + String email = ASN1IA5String.getInstance(name.getName()).getString().toLowerCase(locale); addresses.add(email); } } @@ -453,34 +426,24 @@ public static Set getEmailAddresses(X509Certificate cert) return addresses; } - private static ASN1Primitive getObject(byte[] ext) - throws IOException - { - ASN1InputStream aIn = new ASN1InputStream(ext); - ASN1OctetString octs = ASN1OctetString.getInstance(aIn.readObject()); - - return ASN1Primitive.fromByteArray(octs.getOctets()); - } - - protected void checkSignerCert(X509Certificate cert, List errors, - List notifications) + protected void checkSignerCert(X509Certificate cert, List errors, List notifications) { // get key length PublicKey key = cert.getPublicKey(); int keyLength = -1; if (key instanceof RSAPublicKey) { - keyLength = ((RSAPublicKey)key).getModulus().bitLength(); + keyLength = ((RSAPublicKey) key).getModulus().bitLength(); } else if (key instanceof DSAPublicKey) { - keyLength = ((DSAPublicKey)key).getParams().getP().bitLength(); + keyLength = ((DSAPublicKey) key).getParams().getP().bitLength(); } if (keyLength != -1 && keyLength <= shortKeyLength) { ErrorBundle msg = createErrorBundle( "SignedMailValidator.shortSigningKey", - new Object[]{Integers.valueOf(keyLength)}); + new Object[]{ Integers.valueOf(keyLength) }); notifications.add(msg); } @@ -490,44 +453,39 @@ else if (key instanceof DSAPublicKey) { ErrorBundle msg = createErrorBundle( "SignedMailValidator.longValidity", - new Object[]{new TrustedInput(cert.getNotBefore()), new TrustedInput(cert.getNotAfter())}); + new Object[]{ new TrustedInput(cert.getNotBefore()), new TrustedInput(cert.getNotAfter()) }); notifications.add(msg); } // check key usage if digitalSignature or nonRepudiation is set boolean[] keyUsage = cert.getKeyUsage(); - if (keyUsage != null && !keyUsage[0] && !keyUsage[1]) + if (!supportsKeyUsage(keyUsage, KU_DIGITAL_SIGNATURE) && + !supportsKeyUsage(keyUsage, KU_NON_REPUDIATION)) { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.signingNotPermitted"); + ErrorBundle msg = createErrorBundle("SignedMailValidator.signingNotPermitted"); errors.add(msg); } // check extended key usage try { - byte[] ext = cert.getExtensionValue(EXT_KEY_USAGE); - if (ext != null) + byte[] ekuExtValue = cert.getExtensionValue(Extension.extendedKeyUsage.getId()); + if (ekuExtValue != null) { - ExtendedKeyUsage extKeyUsage = ExtendedKeyUsage - .getInstance(getObject(ext)); - if (!extKeyUsage - .hasKeyPurposeId(KeyPurposeId.anyExtendedKeyUsage) - && !extKeyUsage - .hasKeyPurposeId(KeyPurposeId.id_kp_emailProtection)) + ExtendedKeyUsage eku = ExtendedKeyUsage.getInstance( + JcaX509ExtensionUtils.parseExtensionValue(ekuExtValue)); + + if (!eku.hasKeyPurposeId(KeyPurposeId.anyExtendedKeyUsage) && + !eku.hasKeyPurposeId(KeyPurposeId.id_kp_emailProtection)) { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.extKeyUsageNotPermitted"); + ErrorBundle msg = createErrorBundle("SignedMailValidator.extKeyUsageNotPermitted"); errors.add(msg); } } } catch (Exception e) { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.extKeyUsageError", new Object[]{ - e.getMessage(), e, e.getClass().getName()} - ); + ErrorBundle msg = createErrorBundle("SignedMailValidator.extKeyUsageError", e); errors.add(msg); } @@ -538,46 +496,37 @@ else if (key instanceof DSAPublicKey) if (certEmails.isEmpty()) { // error no email address in signing certificate - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.noEmailInCert"); + ErrorBundle msg = createErrorBundle("SignedMailValidator.noEmailInCert"); errors.add(msg); } - else + else if (!hasAnyFromAddress(certEmails, fromAddresses)) { - // check if email in cert is equal to the from address in the - // message - boolean equalsFrom = false; - for (int i = 0; i < fromAddresses.length; i++) - { - if (certEmails.contains(fromAddresses[i].toLowerCase())) - { - equalsFrom = true; - break; - } - } - if (!equalsFrom) - { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.emailFromCertMismatch", - new Object[]{ - new UntrustedInput( - addressesToString(fromAddresses)), - new UntrustedInput(certEmails)} - ); - errors.add(msg); - } + ErrorBundle msg = createErrorBundle( + "SignedMailValidator.emailFromCertMismatch", + new Object[]{ new UntrustedInput(addressesToString(fromAddresses)), new UntrustedInput(certEmails) }); + errors.add(msg); } } catch (Exception e) { - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.certGetEmailError", new Object[]{ - e.getMessage(), e, e.getClass().getName()} - ); + ErrorBundle msg = createErrorBundle("SignedMailValidator.certGetEmailError", e); errors.add(msg); } } + static boolean hasAnyFromAddress(Set certEmails, String[] fromAddresses) + { + // check if email in cert is equal to the from address in the message + for (int i = 0; i < fromAddresses.length; ++i) + { + if (certEmails.contains(fromAddresses[i].toLowerCase(locale))) + { + return true; + } + } + return false; + } + static String addressesToString(Object[] a) { if (a == null) @@ -585,7 +534,7 @@ static String addressesToString(Object[] a) return "null"; } - StringBuffer b = new StringBuffer(); + StringBuilder b = new StringBuilder(); b.append('['); for (int i = 0; i != a.length; i++) @@ -603,71 +552,26 @@ static String addressesToString(Object[] a) public static Date getSignatureTime(SignerInformation signer) { AttributeTable atab = signer.getSignedAttributes(); - Date result = null; if (atab != null) { Attribute attr = atab.get(CMSAttributes.signingTime); if (attr != null) { - Time t = Time.getInstance(attr.getAttrValues().getObjectAt(0) - .toASN1Primitive()); - result = t.getDate(); - } - } - return result; - } - - private static List findCerts(List certStores, X509CertSelector selector) - throws CertStoreException - { - List result = new ArrayList(); - Iterator it = certStores.iterator(); - while (it.hasNext()) - { - CertStore store = (CertStore)it.next(); - Collection coll = store.getCertificates(selector); - // sometimes the subjectKeyIdentifier in a TA certificate, even when the authorityKeyIdentifier is set. - // where this happens we role back to a simpler match to make sure we've got all the possibilities. - if (coll.isEmpty() && selector.getSubjectKeyIdentifier() != null) - { - X509CertSelector certSelector = (X509CertSelector)selector.clone(); - certSelector.setSubjectKeyIdentifier(null); - coll = store.getCertificates(certSelector); + Time t = Time.getInstance(attr.getAttrValues().getObjectAt(0)); + return t.getDate(); } - result.addAll(coll); } - return result; - } - - private static X509Certificate findNextCert(List certStores, X509CertSelector selector, Set certSet) - throws CertStoreException - { - Iterator certIt = findCerts(certStores, selector).iterator(); - - boolean certFound = false; - X509Certificate nextCert = null; - while (certIt.hasNext()) - { - nextCert = (X509Certificate)certIt.next(); - if (!certSet.contains(nextCert)) - { - certFound = true; - break; - } - } - - return certFound ? nextCert : null; + return null; } /** - * @param signerCert the end of the path + * @param signerCert the end of the path * @param trustanchors trust anchors for the path * @param certStores * @return the resulting certificate path. * @throws GeneralSecurityException */ - public static CertPath createCertPath(X509Certificate signerCert, - Set trustanchors, List certStores) + public static CertPath createCertPath(X509Certificate signerCert, Set trustanchors, List certStores) throws GeneralSecurityException { Object[] results = createCertPath(signerCert, trustanchors, certStores, null); @@ -675,163 +579,111 @@ public static CertPath createCertPath(X509Certificate signerCert, } /** - * Returns an Object array containing a CertPath and a List of Booleans. The list contains the value true - * if the corresponding certificate in the CertPath was taken from the user provided CertStores. + * Returns an Object array containing a CertPath and a List of Booleans. The list contains the value + * true if the corresponding certificate in the CertPath was taken from the user + * provided CertStores. * - * @param signerCert the end of the path - * @param trustanchors trust anchors for the path + * @param signerCert the end of the path + * @param trustAnchors trust anchors for the path * @param systemCertStores list of {@link CertStore} provided by the system - * @param userCertStores list of {@link CertStore} provided by the user + * @param userCertStores list of {@link CertStore} provided by the user * @return a CertPath and a List of booleans. * @throws GeneralSecurityException */ - public static Object[] createCertPath(X509Certificate signerCert, - Set trustanchors, List systemCertStores, List userCertStores) - throws GeneralSecurityException + public static Object[] createCertPath(X509Certificate signerCert, Set trustAnchors, List systemCertStores, + List userCertStores) throws GeneralSecurityException { - Set certSet = new LinkedHashSet(); - List userProvidedList = new ArrayList(); + if (signerCert == null) + { + throw new NullPointerException("'signerCert' cannot be null"); + } - // add signer certificate + LinkedHashSet certSet = new LinkedHashSet(); + ArrayList userProvidedList = new ArrayList(); X509Certificate cert = signerCert; - certSet.add(cert); - userProvidedList.add(new Boolean(true)); + boolean certIsSystemProvided = false; - boolean trustAnchorFound = false; + X509Certificate providedCert = getProvidedCert(trustAnchors, systemCertStores, signerCert); + if (providedCert != null) + { + cert = providedCert; + certIsSystemProvided = true; + } - X509Certificate taCert = null; + TrustAnchor trustAnchor = null; // add other certs to the cert path - while (cert != null && !trustAnchorFound) + do { - // check if cert Issuer is Trustanchor - Iterator trustIt = trustanchors.iterator(); - while (trustIt.hasNext()) + certSet.add(cert); + userProvidedList.add(Boolean.valueOf(!certIsSystemProvided)); + + // check if cert issuer is Trustanchor + trustAnchor = findTrustAnchorForCert(cert, trustAnchors); + if (trustAnchor != null) { - TrustAnchor anchor = (TrustAnchor)trustIt.next(); - X509Certificate anchorCert = anchor.getTrustedCert(); - if (anchorCert != null) - { - if (anchorCert.getSubjectX500Principal().equals( - cert.getIssuerX500Principal())) - { - try - { - cert.verify(anchorCert.getPublicKey(), "BC"); - trustAnchorFound = true; - taCert = anchorCert; - break; - } - catch (Exception e) - { - // trustanchor not found - } - } - } - else - { - if (anchor.getCAName().equals( - cert.getIssuerX500Principal().getName())) - { - try - { - cert.verify(anchor.getCAPublicKey(), "BC"); - trustAnchorFound = true; - break; - } - catch (Exception e) - { - // trustanchor not found - } - } - } + break; } - if (!trustAnchorFound) - { - // add next cert to path - X509CertSelector select = new X509CertSelector(); - try - { - select.setSubject(cert.getIssuerX500Principal().getEncoded()); - } - catch (IOException e) - { - throw new IllegalStateException(e.toString()); - } - byte[] authKeyIdentBytes = cert.getExtensionValue(Extension.authorityKeyIdentifier.getId()); - if (authKeyIdentBytes != null) - { - try - { - AuthorityKeyIdentifier kid = AuthorityKeyIdentifier.getInstance(getObject(authKeyIdentBytes)); - if (kid.getKeyIdentifier() != null) - { - select.setSubjectKeyIdentifier(new DEROctetString(kid.getKeyIdentifier()).getEncoded(ASN1Encoding.DER)); - } - } - catch (IOException ioe) - { - // ignore - } - } - boolean userProvided = false; + // add next cert to path - cert = findNextCert(systemCertStores, select, certSet); - if (cert == null && userCertStores != null) - { - userProvided = true; - cert = findNextCert(userCertStores, select, certSet); - } + X509CertSelector issuerSelector = createIssuerSelector(cert); - if (cert != null) - { - // cert found - certSet.add(cert); - userProvidedList.add(new Boolean(userProvided)); - } + cert = findFirstCert(systemCertStores, issuerSelector, certSet); + certIsSystemProvided = (cert != null); + + if (cert == null && userCertStores != null) + { + cert = findFirstCert(userCertStores, issuerSelector, certSet); } } + while (cert != null); - // if a trustanchor was found - try to find a selfsigned certificate of - // the trustanchor - if (trustAnchorFound) + // if a trust anchor was found - try to find a self-signed certificate of the trust anchor + if (trustAnchor != null) { - if (taCert != null && taCert.getSubjectX500Principal().equals(taCert.getIssuerX500Principal())) + X509Certificate trustedCert = trustAnchor.getTrustedCert(); // Can be null + + if (trustedCert != null && + trustedCert.getSubjectX500Principal().equals(trustedCert.getIssuerX500Principal())) { - certSet.add(taCert); - userProvidedList.add(new Boolean(false)); + if (certSet.add(trustedCert)) + { + userProvidedList.add(Boolean.FALSE); + } } else { - X509CertSelector select = new X509CertSelector(); + X509CertSelector taSelector = new X509CertSelector(); + byte[] certIssuerEncoding = cert.getIssuerX500Principal().getEncoded(); try { - select.setSubject(cert.getIssuerX500Principal().getEncoded()); - select.setIssuer(cert.getIssuerX500Principal().getEncoded()); + taSelector.setSubject(certIssuerEncoding); + taSelector.setIssuer(certIssuerEncoding); } catch (IOException e) { throw new IllegalStateException(e.toString()); } - boolean userProvided = false; + cert = findFirstCert(systemCertStores, taSelector, certSet); + certIsSystemProvided = (cert != null); - taCert = findNextCert(systemCertStores, select, certSet); - if (taCert == null && userCertStores != null) + if (cert == null && userCertStores != null) { - userProvided = true; - taCert = findNextCert(userCertStores, select, certSet); + cert = findFirstCert(userCertStores, taSelector, certSet); } - if (taCert != null) + + if (cert != null) { try { - cert.verify(taCert.getPublicKey(), "BC"); - certSet.add(taCert); - userProvidedList.add(new Boolean(userProvided)); + cert.verify(cert.getPublicKey(), "BC"); + + certSet.add(cert); + userProvidedList.add(Boolean.valueOf(!certIsSystemProvided)); } catch (GeneralSecurityException gse) { @@ -842,7 +694,7 @@ public static Object[] createCertPath(X509Certificate signerCert, } CertPath certPath = CertificateFactory.getInstance("X.509", "BC").generateCertPath(new ArrayList(certSet)); - return new Object[]{certPath, userProvidedList}; + return new Object[]{ certPath, userProvidedList }; } public CertStore getCertsAndCRLs() @@ -855,38 +707,29 @@ public SignerInformationStore getSignerInformationStore() return signers; } - public ValidationResult getValidationResult(SignerInformation signer) - throws SignedMailValidatorException + public ValidationResult getValidationResult(SignerInformation signer) throws SignedMailValidatorException { if (signers.getSigners(signer.getSID()).isEmpty()) { // the signer is not part of the SignerInformationStore // he has not signed the message - ErrorBundle msg = createErrorBundle( - "SignedMailValidator.wrongSigner"); + ErrorBundle msg = createErrorBundle("SignedMailValidator.wrongSigner"); throw new SignedMailValidatorException(msg); } - else - { - return (ValidationResult)results.get(signer); - } + + return (ValidationResult)results.get(signer); } public static class ValidationResult { - private PKIXCertPathReviewer review; - private List errors; - private List notifications; - private List userProvidedCerts; - private boolean signVerified; - ValidationResult(PKIXCertPathReviewer review, boolean verified, - List errors, List notifications, List userProvidedCerts) + ValidationResult(PKIXCertPathReviewer review, boolean verified, List errors, List notifications, + List userProvidedCerts) { this.review = review; this.errors = errors; @@ -916,8 +759,8 @@ public List getNotifications() } /** - * @return the PKIXCertPathReviewer for the CertPath of this signature - * or null if an Exception occurred. + * @return the PKIXCertPathReviewer for the CertPath of this signature or null if an Exception + * occurred. */ public PKIXCertPathReviewer getCertPathReview() { @@ -925,8 +768,7 @@ public PKIXCertPathReviewer getCertPathReview() } /** - * @return the CertPath for this signature - * or null if an Exception occurred. + * @return the CertPath for this signature or null if an Exception occurred. */ public CertPath getCertPath() { @@ -934,8 +776,8 @@ public CertPath getCertPath() } /** - * @return a List of Booleans that are true if the corresponding certificate in the CertPath was taken from - * the CertStore of the SMIME message + * @return a List of Booleans that are true if the corresponding certificate in the CertPath was + * taken from the CertStore of the SMIME message */ public List getUserProvidedCerts() { @@ -943,8 +785,7 @@ public List getUserProvidedCerts() } /** - * @return true if the signature corresponds to the public key of the - * signer + * @return true if the signature corresponds to the public key of the signer */ public boolean isVerifiedSignature() { @@ -952,42 +793,191 @@ public boolean isVerifiedSignature() } /** - * @return true if the signature is valid (ie. if it corresponds to the - * public key of the signer and the cert path for the signers - * certificate is also valid) + * @return true if the signature is valid (ie. if it corresponds to the public key of the signer and + * the cert path for the signers certificate is also valid) */ public boolean isValidSignature() { - if (review != null) - { - return signVerified && review.isValidCertPath() && errors.isEmpty(); - } - else - { - return false; - } + return review != null && signVerified && review.isValidCertPath() && errors.isEmpty(); } } - private static TBSCertificate getTBSCert(X509Certificate cert) - throws CertificateEncodingException - { - return TBSCertificate.getInstance(cert.getTBSCertificate()); - } - private static ErrorBundle createErrorBundle(String id) { ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, id); msg.setClassLoader(SignedMailValidator.class.getClassLoader()); - + return msg; } - + private static ErrorBundle createErrorBundle(String id, Object[] arguments) { ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, id, arguments); msg.setClassLoader(SignedMailValidator.class.getClassLoader()); - + return msg; } + + private static ErrorBundle createErrorBundle(String id, Exception e) + { + return createErrorBundle(id, new Object[]{ e.getMessage(), e, e.getClass().getName() }); + } + + private static X509CertSelector createIssuerSelector(X509Certificate cert) + { + // add next cert to path + X509CertSelector selector = new X509CertSelector(); + try + { + selector.setSubject(cert.getIssuerX500Principal().getEncoded()); + } + catch (IOException e) + { + throw new IllegalStateException(e.toString()); + } + + byte[] akiExtValue = cert.getExtensionValue(Extension.authorityKeyIdentifier.getId()); + if (akiExtValue != null) + { + try + { + AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance( + JcaX509ExtensionUtils.parseExtensionValue(akiExtValue)); + + ASN1OctetString keyIdentifier = aki.getKeyIdentifierObject(); + if (keyIdentifier != null) + { + selector.setSubjectKeyIdentifier(keyIdentifier.getEncoded(ASN1Encoding.DER)); + } + } + catch (IOException ioe) + { + // ignore + } + } + + return selector; + } + + private static X509Certificate findFirstCert(List certStores, X509CertSelector selector, Set ignoreCerts) + throws CertStoreException + { + X509CertSelector altSelector = null; + + Iterator certStoreIter = certStores.iterator(); + while (certStoreIter.hasNext()) + { + CertStore certStore = (CertStore)certStoreIter.next(); + Collection certs = certStore.getCertificates(selector); + + // sometimes the subjectKeyIdentifier in a TA certificate, even when the authorityKeyIdentifier is set. + // where this happens we roll back to a simpler match to make sure we've got all the possibilities. + if (certs.isEmpty() && selector.getSubjectKeyIdentifier() != null) + { + if (altSelector == null) + { + altSelector = (X509CertSelector)selector.clone(); + altSelector.setSubjectKeyIdentifier(null); + } + + certs = certStore.getCertificates(altSelector); + } + + Iterator certIter = certs.iterator(); + while (certIter.hasNext()) + { + X509Certificate nextCert = (X509Certificate)certIter.next(); + if (ignoreCerts == null || !ignoreCerts.contains(nextCert)) + { + return nextCert; + } + } + } + return null; + } + + private static TrustAnchor findTrustAnchorForCert(X509Certificate cert, Set trustAnchors) + { + Iterator trustAnchorIter = trustAnchors.iterator(); + if (trustAnchorIter.hasNext()) + { + X500Principal certIssuer = cert.getIssuerX500Principal(); + + do + { + TrustAnchor trustAnchor = (TrustAnchor)trustAnchorIter.next(); + + try + { + X509Certificate taCert = trustAnchor.getTrustedCert(); + if (taCert != null) + { + if (certIssuer.equals(taCert.getSubjectX500Principal())) + { + cert.verify(taCert.getPublicKey(), "BC"); + return trustAnchor; + } + } + else + { + if (certIssuer.getName().equals(trustAnchor.getCAName())) + { + cert.verify(trustAnchor.getCAPublicKey(), "BC"); + return trustAnchor; + } + } + } + catch (Exception e) + { + } + } + while (trustAnchorIter.hasNext()); + } + return null; + } + + private static X509Certificate getProvidedCert(Set trustAnchors, List certStores, X509Certificate cert) + throws CertStoreException + { + Iterator trustAnchorIter = trustAnchors.iterator(); + while (trustAnchorIter.hasNext()) + { + TrustAnchor trustAnchor = (TrustAnchor)trustAnchorIter.next(); + X509Certificate taCert = trustAnchor.getTrustedCert(); + if (taCert != null && taCert.equals(cert)) + { + return taCert; + } + } + + X509CertSelector selector = new X509CertSelector(); + selector.setCertificate(cert); + + return findFirstCert(certStores, selector, null); + } + + private static boolean isValidSignature(SignerInformationVerifier verifier, SignerInformation signer, List errors) + { + boolean validSignature = false; + try + { + validSignature = signer.verify(verifier); + if (!validSignature) + { + ErrorBundle msg = createErrorBundle("SignedMailValidator.signatureNotVerified"); + errors.add(msg); + } + } + catch (Exception e) + { + ErrorBundle msg = createErrorBundle("SignedMailValidator.exceptionVerifyingSignature", e); + errors.add(msg); + } + return validSignature; + } + + private static boolean supportsKeyUsage(boolean[] ku, int kuBit) + { + return null == ku || (ku.length > kuBit && ku[kuBit]); + } } diff --git a/mail/src/test/java/org/bouncycastle/mail/smime/test/AllTests.java b/mail/src/test/java/org/bouncycastle/mail/smime/test/AllTests.java index 662fc75958..a71f67b6bf 100644 --- a/mail/src/test/java/org/bouncycastle/mail/smime/test/AllTests.java +++ b/mail/src/test/java/org/bouncycastle/mail/smime/test/AllTests.java @@ -47,14 +47,15 @@ public static Test suite() { TestSuite suite = new TestSuite("SMIME tests"); - suite.addTestSuite(NewSMIMESignedTest.class); - suite.addTestSuite(SignedMailValidatorTest.class); + suite.addTestSuite(JournalingSecureRandomEncryptTest.class); + suite.addTestSuite(MailGeneralTest.class); suite.addTestSuite(NewSMIMEAuthEnvelopedTest.class); suite.addTestSuite(NewSMIMEEnvelopedTest.class); + suite.addTestSuite(NewSMIMESignedTest.class); + suite.addTestSuite(SignedMailValidatorTest.class); suite.addTestSuite(SMIMECompressedTest.class); suite.addTestSuite(SMIMEMiscTest.class); suite.addTestSuite(SMIMEToolkitTest.class); - suite.addTestSuite(MailGeneralTest.class); return new BCTestSetup(suite); } diff --git a/mail/src/test/java/org/bouncycastle/mail/smime/test/CMSTestUtil.java b/mail/src/test/java/org/bouncycastle/mail/smime/test/CMSTestUtil.java index 61950472a5..b540bf133b 100644 --- a/mail/src/test/java/org/bouncycastle/mail/smime/test/CMSTestUtil.java +++ b/mail/src/test/java/org/bouncycastle/mail/smime/test/CMSTestUtil.java @@ -178,7 +178,7 @@ public class CMSTestUtil public static String dumpBase64( byte[] data) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); data = Base64.encode(data); diff --git a/mail/src/test/java/org/bouncycastle/mail/smime/test/MailGeneralTest.java b/mail/src/test/java/org/bouncycastle/mail/smime/test/MailGeneralTest.java index 82f853576a..92da52e44d 100644 --- a/mail/src/test/java/org/bouncycastle/mail/smime/test/MailGeneralTest.java +++ b/mail/src/test/java/org/bouncycastle/mail/smime/test/MailGeneralTest.java @@ -1045,9 +1045,16 @@ public void testSelfSignedCert() certStores.add(store); // first path - CertPath path = SignedMailValidator.createCertPath(rootCert, trustanchors, certStores); + CertPath path1 = SignedMailValidator.createCertPath(rootCert, trustanchors, certStores); + assertTrue("path size is not 1", path1.getCertificates().size() == 1); - assertTrue("path size is not 1", path.getCertificates().size() == 1); + Object[] pathAndUserProvided = SignedMailValidator.createCertPath(rootCert, trustanchors, certStores, null); + assertTrue("result length is not 2", pathAndUserProvided.length == 2); + CertPath path2 = (CertPath)pathAndUserProvided[0]; + List userProvided = (List)pathAndUserProvided[1]; + assertTrue("path size is not 1", path2.getCertificates().size() == 1); + assertTrue("user-provided size is not 1", userProvided.size() == 1); + assertTrue("user-provided value should be false", Boolean.FALSE.equals(userProvided.get(0))); // check message validation certList = new ArrayList(); @@ -1118,12 +1125,13 @@ public void operation() SignerInformation signer = (SignerInformation)validator .getSignerInformationStore().getSigners().iterator().next(); - assertEquals(1, validator.getCertsAndCRLs().getCertificates(null).size()); - assertEquals(0, validator.getCertsAndCRLs().getCRLs(null).size()); + CertStore certsAndCRLS = validator.getCertsAndCRLs(); + assertEquals(1, certsAndCRLS.getCertificates(null).size()); + assertEquals(0, certsAndCRLS.getCRLs(null).size()); SignedMailValidator.ValidationResult res = validator.getValidationResult(signer); assertEquals(1, res.getCertPath().getCertificates().size()); - assertEquals(2, res.getUserProvidedCerts().size()); + assertEquals(1, res.getUserProvidedCerts().size()); assertTrue(res.isVerifiedSignature()); assertTrue(res.isValidSignature()); diff --git a/mail/src/test/java/org/bouncycastle/mail/smime/test/NewSMIMEAuthEnvelopedTest.java b/mail/src/test/java/org/bouncycastle/mail/smime/test/NewSMIMEAuthEnvelopedTest.java index 0b6fa27126..a44b1b1054 100644 --- a/mail/src/test/java/org/bouncycastle/mail/smime/test/NewSMIMEAuthEnvelopedTest.java +++ b/mail/src/test/java/org/bouncycastle/mail/smime/test/NewSMIMEAuthEnvelopedTest.java @@ -24,7 +24,6 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.cms.CMSAlgorithm; -import org.bouncycastle.cms.CMSAuthEnvelopedDataGenerator; import org.bouncycastle.cms.KeyTransRecipientId; import org.bouncycastle.cms.RecipientId; import org.bouncycastle.cms.RecipientInformation; @@ -184,7 +183,7 @@ public void testAES128Encrypted() throws Exception { MimeBodyPart msg = SMIMETestUtil.makeMimeBodyPart("WallaWallaWashington"); - String algorithm = SMIMEAuthEnvelopedGenerator.AES256_GCM; + String algorithm = SMIMEAuthEnvelopedGenerator.AES128_GCM; verifyAlgorithm(algorithm, msg); } @@ -193,7 +192,7 @@ public void testAES192Encrypted() throws Exception { MimeBodyPart msg = SMIMETestUtil.makeMimeBodyPart("WallaWallaWashington"); - String algorithm = SMIMEAuthEnvelopedGenerator.AES256_GCM; + String algorithm = SMIMEAuthEnvelopedGenerator.AES192_GCM; verifyAlgorithm(algorithm, msg); } @@ -348,6 +347,43 @@ public void testCapEncrypt() SMIMETestUtil.verifyMessageBytes(msg, res); } + public void testChacha20Poly1305Encrypt() + throws Exception + { + MimeBodyPart msg = SMIMETestUtil.makeMimeBodyPart("WallaWallaWashington"); + + SMIMEAuthEnvelopedGenerator gen = new SMIMEAuthEnvelopedGenerator(); + + // + // create a subject key id - this has to be done the same way as + // it is done in the certificate associated with the private key + // + MessageDigest dig = MessageDigest.getInstance("SHA256", BC); + + dig.update(_reciCert.getPublicKey().getEncoded()); + + gen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(dig.digest(), _reciCert.getPublicKey()).setProvider(BC)); + + // + // generate a MimeBodyPart object which encapsulates the content + // we want encrypted. + // + MimeBodyPart mp = gen.generate(msg, new JceCMSContentEncryptorBuilder(CMSAlgorithm.ChaCha20Poly1305).setProvider(BC).build()); + + SMIMEAuthEnveloped m = new SMIMEAuthEnveloped(mp); + + dig.update(_reciCert.getPublicKey().getEncoded()); + + RecipientId recId = new KeyTransRecipientId(dig.digest()); + + RecipientInformationStore recipients = m.getRecipientInfos(); + RecipientInformation recipient = recipients.get(recId); + + MimeBodyPart res = SMIMEUtil.toMimeBodyPart(recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC))); + + SMIMETestUtil.verifyMessageBytes(msg, res); + } + public void testTwoRecipients() throws Exception { @@ -494,7 +530,7 @@ private void doTryAgreement(MimeBodyPart data, ASN1ObjectIdentifier algorithm) SMIMEAuthEnveloped ed = new SMIMEAuthEnveloped(res); - assertEquals(ed.getEncryptionAlgOID(), CMSAuthEnvelopedDataGenerator.AES128_GCM); + assertEquals(ed.getEncryptionAlgOID(), SMIMEAuthEnvelopedGenerator.AES128_GCM); RecipientInformationStore recipients = ed.getRecipientInfos(); diff --git a/mail/src/test/java/org/bouncycastle/mail/smime/test/SignedMailValidatorTest.java b/mail/src/test/java/org/bouncycastle/mail/smime/test/SignedMailValidatorTest.java index 0e05c976f6..7952f5fdf9 100644 --- a/mail/src/test/java/org/bouncycastle/mail/smime/test/SignedMailValidatorTest.java +++ b/mail/src/test/java/org/bouncycastle/mail/smime/test/SignedMailValidatorTest.java @@ -279,9 +279,16 @@ public void testSelfSignedCert() certStores.add(store); // first path - CertPath path = SignedMailValidator.createCertPath(rootCert, trustanchors, certStores); - - assertTrue("path size is not 1", path.getCertificates().size() == 1); + CertPath path1 = SignedMailValidator.createCertPath(rootCert, trustanchors, certStores); + assertTrue("path size is not 1", path1.getCertificates().size() == 1); + + Object[] pathAndUserProvided = SignedMailValidator.createCertPath(rootCert, trustanchors, certStores, null); + assertTrue("result length is not 2", pathAndUserProvided.length == 2); + CertPath path2 = (CertPath)pathAndUserProvided[0]; + List userProvided = (List)pathAndUserProvided[1]; + assertTrue("path size is not 1", path2.getCertificates().size() == 1); + assertTrue("user-provided size is not 1", userProvided.size() == 1); + assertTrue("user-provided value should be false", Boolean.FALSE.equals(userProvided.get(0))); // check message validation certList = new ArrayList(); diff --git a/mls/build.gradle b/mls/build.gradle index 7b099b2e57..e22d75908d 100644 --- a/mls/build.gradle +++ b/mls/build.gradle @@ -1,7 +1,7 @@ plugins { // OSGI - id "biz.aQute.bnd.builder" version "7.0.0" + id "biz.aQute.bnd.builder" version "7.1.0" // Provide convenience executables for trying out the examples. id 'application' id 'com.google.protobuf' version '0.9.4' @@ -79,9 +79,9 @@ checkstyleMain { compileJava { options.release = 8 - options.errorprone.disableWarningsInGeneratedCode = true - options.errorprone.errorproneArgs = ["-Xep:IgnoredPureGetter:OFF"] - options.errorprone.errorproneArgs.add("-XepExcludedPaths:.*/build/generated/.*") +// options.errorprone.disableWarningsInGeneratedCode = true +// options.errorprone.errorproneArgs = ["-Xep:IgnoredPureGetter:OFF"] +// options.errorprone.errorproneArgs.add("-XepExcludedPaths:.*/build/generated/.*") } compileJava9Java { @@ -133,7 +133,21 @@ def createStartScripts(String mainClassName) { application { applicationDistribution.into('bin') { from(newTask) - fileMode = 0755 + filePermissions { + user { + read = true + write = true + execute = true + } + group { + read = true + execute = true + } + other { + read = true + execute = true + } + } } } } @@ -163,6 +177,11 @@ jar { manifest.attributes('Export-Package': "${packages};version=${v}") manifest.attributes('Import-Package': "java.*;resolution:=optional,javax.*;resolution:=optional,!${packages},org.bouncycastle.*;version=\"[${v},${maxVersion})\"") manifest.attributes('Bundle-Version': "${v}") + manifest.attributes('Permissions': 'all-permissions') + manifest.attributes('Codebase': '*') + manifest.attributes('Application-Library-Allowable-Codebase': '*') + manifest.attributes('Caller-Allowable-Codebase': '*') + manifest.attributes('Trusted-Library': 'true') } task sourcesJar(type: Jar) { @@ -208,4 +227,4 @@ publishing { } -} \ No newline at end of file +} diff --git a/mls/src/main/java/org/bouncycastle/mls/TranscriptHash.java b/mls/src/main/java/org/bouncycastle/mls/TranscriptHash.java index f4433be57d..8328209308 100644 --- a/mls/src/main/java/org/bouncycastle/mls/TranscriptHash.java +++ b/mls/src/main/java/org/bouncycastle/mls/TranscriptHash.java @@ -42,7 +42,7 @@ public TranscriptHash(MlsCipherSuite suite, byte[] confirmed, byte[] interim) this.interim = interim; } - static public TranscriptHash fromConfirmationTag(MlsCipherSuite suite, byte[] confirmed, byte[] confirmationTag) + public static TranscriptHash fromConfirmationTag(MlsCipherSuite suite, byte[] confirmed, byte[] confirmationTag) throws IOException { TranscriptHash out = new TranscriptHash(suite, confirmed.clone(), new byte[0]); diff --git a/mls/src/main/java/org/bouncycastle/mls/TreeKEM/TreeKEMPublicKey.java b/mls/src/main/java/org/bouncycastle/mls/TreeKEM/TreeKEMPublicKey.java index 162297e572..fb934c1cc8 100644 --- a/mls/src/main/java/org/bouncycastle/mls/TreeKEM/TreeKEMPublicKey.java +++ b/mls/src/main/java/org/bouncycastle/mls/TreeKEM/TreeKEMPublicKey.java @@ -391,6 +391,7 @@ public LeafNode getLeafNode(LeafIndex index) return node.getLeafNode(); } + @SuppressWarnings("NonApiType") public ArrayList resolve(NodeIndex index) { boolean atLeaf = (index.level() == 0); diff --git a/mls/src/main/java/org/bouncycastle/mls/client/MLSClientImpl.java b/mls/src/main/java/org/bouncycastle/mls/client/MLSClientImpl.java index 201e34a78d..0b5e66cd3e 100644 --- a/mls/src/main/java/org/bouncycastle/mls/client/MLSClientImpl.java +++ b/mls/src/main/java/org/bouncycastle/mls/client/MLSClientImpl.java @@ -47,7 +47,7 @@ public class MLSClientImpl extends MLSClientGrpc.MLSClientImplBase { - class CachedGroup + static class CachedGroup { Group group; boolean encryptHandshake; @@ -70,7 +70,7 @@ public void resetPending() } } - class CachedJoin + static class CachedJoin { KeyPackageWithSecrets kpSecrets; Map externalPsks; @@ -82,7 +82,7 @@ public CachedJoin(KeyPackageWithSecrets kpSecrets) } } - class CachedReinit + static class CachedReinit { KeyPackageWithSecrets kpSk; Group.Tombstone tombstone; @@ -1423,7 +1423,7 @@ private void reInitCommitImpl(CachedGroup entry, MlsClient.CommitRequest request LeafNode leaf = entry.group.getTree().getLeafNode(entry.group.getIndex()); byte[] identity = leaf.getCredential().getIdentity(); KeyPackageWithSecrets kpSk = newKeyPackage(twm.getSuite(), identity); - ; + int reinitID = storeReinit(kpSk, twm, entry.encryptHandshake); byte[] commitBytes = MLSOutputStream.encode(twm.getMessage()); diff --git a/mls/src/main/java/org/bouncycastle/mls/codec/Capabilities.java b/mls/src/main/java/org/bouncycastle/mls/codec/Capabilities.java index f3b7a98bd7..789dec72b1 100644 --- a/mls/src/main/java/org/bouncycastle/mls/codec/Capabilities.java +++ b/mls/src/main/java/org/bouncycastle/mls/codec/Capabilities.java @@ -10,9 +10,9 @@ public class Capabilities implements MLSInputStream.Readable, MLSOutputStream.Writable { - static private final Short[] DEFAULT_SUPPORTED_VERSIONS = {ProtocolVersion.mls10.value}; - static private final short[] DEFAULT_SUPPORTED_CIPHERSUITES = MlsCipherSuite.ALL_SUPPORTED_SUITES; - static private final Short[] DEFAULT_SUPPORTED_CREDENTIALS = {CredentialType.basic.value, CredentialType.x509.value}; + private static final Short[] DEFAULT_SUPPORTED_VERSIONS = {ProtocolVersion.mls10.value}; + private static final short[] DEFAULT_SUPPORTED_CIPHERSUITES = MlsCipherSuite.ALL_SUPPORTED_SUITES; + private static final Short[] DEFAULT_SUPPORTED_CREDENTIALS = {CredentialType.basic.value, CredentialType.x509.value}; List versions; List cipherSuites; List extensions; diff --git a/mls/src/main/java/org/bouncycastle/mls/codec/Credential.java b/mls/src/main/java/org/bouncycastle/mls/codec/Credential.java index 8cb2b985c5..536c6ab908 100644 --- a/mls/src/main/java/org/bouncycastle/mls/codec/Credential.java +++ b/mls/src/main/java/org/bouncycastle/mls/codec/Credential.java @@ -22,7 +22,7 @@ public byte[] getIdentity() return identity; } - static public Credential forBasic(byte[] identity) + public static Credential forBasic(byte[] identity) { return new Credential(CredentialType.basic, identity, new ArrayList()); } diff --git a/mls/src/main/java/org/bouncycastle/mls/codec/Extension.java b/mls/src/main/java/org/bouncycastle/mls/codec/Extension.java index 3a58e85189..6ca37a2c52 100644 --- a/mls/src/main/java/org/bouncycastle/mls/codec/Extension.java +++ b/mls/src/main/java/org/bouncycastle/mls/codec/Extension.java @@ -32,7 +32,7 @@ public Extension(int extensionType, byte[] extension_data) this.extension_data = extension_data; } - static public Extension externalSender(List list) + public static Extension externalSender(List list) throws IOException { MLSOutputStream stream = new MLSOutputStream(); diff --git a/mls/src/main/java/org/bouncycastle/mls/codec/GroupContext.java b/mls/src/main/java/org/bouncycastle/mls/codec/GroupContext.java index 404ab78e24..fdd2a15ce4 100644 --- a/mls/src/main/java/org/bouncycastle/mls/codec/GroupContext.java +++ b/mls/src/main/java/org/bouncycastle/mls/codec/GroupContext.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.List; import org.bouncycastle.mls.crypto.MlsCipherSuite; @@ -28,12 +29,12 @@ public byte[] getConfirmedTranscriptHash() return confirmedTranscriptHash; } - public ArrayList getExtensions() + public List getExtensions() { return extensions; } - public GroupContext(MlsCipherSuite ciphersuite, byte[] groupID, long epoch, byte[] treeHash, byte[] confirmedTranscriptHash, ArrayList extensions) + public GroupContext(MlsCipherSuite ciphersuite, byte[] groupID, long epoch, byte[] treeHash, byte[] confirmedTranscriptHash, List extensions) { this.suite = ciphersuite; this.ciphersuite = ciphersuite.getSuiteID(); diff --git a/mls/src/main/java/org/bouncycastle/mls/codec/MLSMessage.java b/mls/src/main/java/org/bouncycastle/mls/codec/MLSMessage.java index 5591c74d2a..ab7271660e 100644 --- a/mls/src/main/java/org/bouncycastle/mls/codec/MLSMessage.java +++ b/mls/src/main/java/org/bouncycastle/mls/codec/MLSMessage.java @@ -23,7 +23,7 @@ public MLSMessage(WireFormat wireFormat) this.wireFormat = wireFormat; } - static public MLSMessage externalProposal(MlsCipherSuite suite, byte[] groupID, long epoch, Proposal proposal, int signerIndex, byte[] sigSk) + public static MLSMessage externalProposal(MlsCipherSuite suite, byte[] groupID, long epoch, Proposal proposal, int signerIndex, byte[] sigSk) throws Exception { switch (proposal.getProposalType()) @@ -59,7 +59,7 @@ static public MLSMessage externalProposal(MlsCipherSuite suite, byte[] groupID, return message; } - static public MLSMessage keyPackage(KeyPackage keyPackage) + public static MLSMessage keyPackage(KeyPackage keyPackage) { MLSMessage message = new MLSMessage(WireFormat.mls_key_package); message.version = ProtocolVersion.mls10; diff --git a/mls/src/main/java/org/bouncycastle/mls/codec/PrivateMessage.java b/mls/src/main/java/org/bouncycastle/mls/codec/PrivateMessage.java index 49203cd6e3..15c36203c0 100644 --- a/mls/src/main/java/org/bouncycastle/mls/codec/PrivateMessage.java +++ b/mls/src/main/java/org/bouncycastle/mls/codec/PrivateMessage.java @@ -42,7 +42,7 @@ public PrivateMessage(byte[] group_id, long epoch, ContentType content_type, byt ciphertext = stream.readOpaque(); } - static public PrivateMessage protect(AuthenticatedContent auth, MlsCipherSuite suite, GroupKeySet keys, byte[] senderDataSecretBytes, int paddingSize) + public static PrivateMessage protect(AuthenticatedContent auth, MlsCipherSuite suite, GroupKeySet keys, byte[] senderDataSecretBytes, int paddingSize) throws IOException, IllegalAccessException, InvalidCipherTextException { // Get KeyGeneration from the secret tree @@ -203,7 +203,7 @@ private void deserializeContentPt(byte[] contentPt, FramedContent content, Frame //TODO: read padding? } - static private byte[] serializeContentPt(FramedContent content, FramedContentAuthData auth, int paddingSize) + private static byte[] serializeContentPt(FramedContent content, FramedContentAuthData auth, int paddingSize) throws IOException { MLSOutputStream stream = new MLSOutputStream(); diff --git a/mls/src/main/java/org/bouncycastle/mls/codec/ProposalOrRef.java b/mls/src/main/java/org/bouncycastle/mls/codec/ProposalOrRef.java index 994e75ccac..c376f045e8 100644 --- a/mls/src/main/java/org/bouncycastle/mls/codec/ProposalOrRef.java +++ b/mls/src/main/java/org/bouncycastle/mls/codec/ProposalOrRef.java @@ -26,12 +26,12 @@ public byte[] getReference() } - static public ProposalOrRef forRef(byte[] ref) + public static ProposalOrRef forRef(byte[] ref) { return new ProposalOrRef(ProposalOrRefType.REFERENCE, null, ref); } - static public ProposalOrRef forProposal(Proposal proposal) + public static ProposalOrRef forProposal(Proposal proposal) { return new ProposalOrRef(ProposalOrRefType.PROPOSAL, proposal, null); } diff --git a/mls/src/main/java/org/bouncycastle/mls/codec/PublicMessage.java b/mls/src/main/java/org/bouncycastle/mls/codec/PublicMessage.java index cb8ed08ec4..6fe9780af2 100644 --- a/mls/src/main/java/org/bouncycastle/mls/codec/PublicMessage.java +++ b/mls/src/main/java/org/bouncycastle/mls/codec/PublicMessage.java @@ -74,7 +74,7 @@ public PublicMessage(FramedContent content, FramedContentAuthData auth, byte[] m } } - static public PublicMessage protect(AuthenticatedContent authContent, MlsCipherSuite suite, + public static PublicMessage protect(AuthenticatedContent authContent, MlsCipherSuite suite, byte[] membershipKeyBytes, byte[] groupContextBytes) throws IOException { diff --git a/mls/src/main/java/org/bouncycastle/mls/crypto/MlsCipherSuite.java b/mls/src/main/java/org/bouncycastle/mls/crypto/MlsCipherSuite.java index 40c7e20983..f549ede7ed 100644 --- a/mls/src/main/java/org/bouncycastle/mls/crypto/MlsCipherSuite.java +++ b/mls/src/main/java/org/bouncycastle/mls/crypto/MlsCipherSuite.java @@ -78,7 +78,7 @@ public void writeTo(MLSOutputStream stream) public static final MlsCipherSuite BCMLS_256_DHKEMX448_AES256GCM_SHA512_Ed448 = new MlsCipherSuite(MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448, new BcMlsSigner(MlsSigner.ed448), new BcMlsKdf(new SHA512Digest()), new BcMlsAead(HPKE.aead_AES_GCM256), new HPKE(HPKE.mode_base, HPKE.kem_X448_SHA512, HPKE.kdf_HKDF_SHA512, HPKE.aead_AES_GCM256)); public static final MlsCipherSuite BCMLS_256_DHKEMP521_AES256GCM_SHA512_P521 = new MlsCipherSuite(MLS_256_DHKEMP521_AES256GCM_SHA512_P521, new BcMlsSigner(MlsSigner.ecdsa_secp521r1_sha512), new BcMlsKdf(new SHA512Digest()), new BcMlsAead(HPKE.aead_AES_GCM256), new HPKE(HPKE.mode_base, HPKE.kem_P521_SHA512, HPKE.kdf_HKDF_SHA512, HPKE.aead_AES_GCM256)); public static final MlsCipherSuite BCMLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 = new MlsCipherSuite(MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448, new BcMlsSigner(MlsSigner.ed448), new BcMlsKdf(new SHA512Digest()), new BcMlsAead(HPKE.aead_CHACHA20_POLY1305), new HPKE(HPKE.mode_base, HPKE.kem_X448_SHA512, HPKE.kdf_HKDF_SHA512, HPKE.aead_CHACHA20_POLY1305)); - public static final MlsCipherSuite BCMLS_256_DHKEMP384_AES256GCM_SHA384_P384 = new MlsCipherSuite(MLS_256_DHKEMP384_AES256GCM_SHA384_P384, new BcMlsSigner(MlsSigner.ecdsa_secp384r1_sha384), new BcMlsKdf(new SHA384Digest()), new BcMlsAead(HPKE.aead_AES_GCM256), new HPKE(HPKE.mode_base, HPKE.kem_P384_SHA348, HPKE.kdf_HKDF_SHA384, HPKE.aead_AES_GCM256)); + public static final MlsCipherSuite BCMLS_256_DHKEMP384_AES256GCM_SHA384_P384 = new MlsCipherSuite(MLS_256_DHKEMP384_AES256GCM_SHA384_P384, new BcMlsSigner(MlsSigner.ecdsa_secp384r1_sha384), new BcMlsKdf(new SHA384Digest()), new BcMlsAead(HPKE.aead_AES_GCM256), new HPKE(HPKE.mode_base, HPKE.kem_P384_SHA384, HPKE.kdf_HKDF_SHA384, HPKE.aead_AES_GCM256)); public static final short[] ALL_SUPPORTED_SUITES = { MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519, @@ -107,7 +107,7 @@ public MlsCipherSuite(short id, MlsSigner signer, MlsKdf kdf, MlsAead aead, HPKE this.hpke = hpke; } - static public MlsCipherSuite getSuite(short id) + public static MlsCipherSuite getSuite(short id) throws Exception { switch (id) diff --git a/mls/src/main/java/org/bouncycastle/mls/crypto/bc/BcMlsAead.java b/mls/src/main/java/org/bouncycastle/mls/crypto/bc/BcMlsAead.java index 39fdddd6b2..9664d16760 100644 --- a/mls/src/main/java/org/bouncycastle/mls/crypto/bc/BcMlsAead.java +++ b/mls/src/main/java/org/bouncycastle/mls/crypto/bc/BcMlsAead.java @@ -1,6 +1,5 @@ package org.bouncycastle.mls.crypto.bc; -import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.engines.AESEngine; import org.bouncycastle.crypto.hpke.HPKE; @@ -10,12 +9,13 @@ import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.mls.crypto.MlsAead; +import org.bouncycastle.util.Arrays; public class BcMlsAead implements MlsAead { - AEADCipher cipher; private final short aeadId; + private final AEADCipher cipher; public BcMlsAead(short aeadId) { @@ -25,12 +25,14 @@ public BcMlsAead(short aeadId) { case HPKE.aead_AES_GCM128: case HPKE.aead_AES_GCM256: - cipher = new GCMBlockCipher(new AESEngine()); + cipher = GCMBlockCipher.newInstance(AESEngine.newInstance()); break; case HPKE.aead_CHACHA20_POLY1305: cipher = new ChaCha20Poly1305(); break; case HPKE.aead_EXPORT_ONLY: + default: + cipher = null; break; } } @@ -48,18 +50,6 @@ public int getKeySize() return -1; } - private int getTagSize() - { - switch (aeadId) - { - case HPKE.aead_AES_GCM128: - case HPKE.aead_AES_GCM256: - case HPKE.aead_CHACHA20_POLY1305: - return 16; - } - return -1; - } - public int getNonceSize() { switch (aeadId) @@ -75,30 +65,34 @@ public int getNonceSize() public byte[] open(byte[] key, byte[] nonce, byte[] aad, byte[] ct) throws InvalidCipherTextException { - CipherParameters params = new ParametersWithIV(new KeyParameter(key), nonce); - cipher.init(false, params); + return crypt(false, key, nonce, aad, ct); + } + + public byte[] seal(byte[] key, byte[] nonce, byte[] aad, byte[] pt) + throws InvalidCipherTextException + { + return crypt(true, key, nonce, aad, pt); + } + + private byte[] crypt(boolean forEncryption, byte[] key, byte[] nonce, byte[] aad, byte[] input) + throws InvalidCipherTextException + { + cipher.init(forEncryption, new ParametersWithIV(new KeyParameter(key), nonce)); + if (aad != null) { cipher.processAADBytes(aad, 0, aad.length); } - byte[] pt = new byte[cipher.getOutputSize(ct.length)]; + byte[] output = new byte[cipher.getOutputSize(input.length)]; + int len = cipher.processBytes(input, 0, input.length, output, 0); + len += cipher.doFinal(output, len); - int len = cipher.processBytes(ct, 0, ct.length, pt, 0); - len += cipher.doFinal(pt, len); - return pt; - } - - public byte[] seal(byte[] key, byte[] nonce, byte[] aad, byte[] pt) - throws InvalidCipherTextException - { - CipherParameters params = new ParametersWithIV(new KeyParameter(key), nonce); - cipher.init(true, params); - cipher.processAADBytes(aad, 0, aad.length); + if (len < output.length) + { + return Arrays.copyOf(output, len); + } - byte[] ct = new byte[cipher.getOutputSize(pt.length)]; - int len = cipher.processBytes(pt, 0, pt.length, ct, 0); - cipher.doFinal(ct, len); - return ct; + return output; } } diff --git a/mls/src/main/java/org/bouncycastle/mls/crypto/bc/BcMlsSigner.java b/mls/src/main/java/org/bouncycastle/mls/crypto/bc/BcMlsSigner.java index 64a91b4683..f95947c9f7 100644 --- a/mls/src/main/java/org/bouncycastle/mls/crypto/bc/BcMlsSigner.java +++ b/mls/src/main/java/org/bouncycastle/mls/crypto/bc/BcMlsSigner.java @@ -4,6 +4,7 @@ import java.math.BigInteger; import java.security.SecureRandom; +import org.bouncycastle.asn1.sec.SECObjectIdentifiers; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoException; import org.bouncycastle.crypto.Signer; @@ -14,8 +15,8 @@ import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator; import org.bouncycastle.crypto.generators.Ed448KeyPairGenerator; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import org.bouncycastle.crypto.params.ECNamedDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters; @@ -30,72 +31,36 @@ import org.bouncycastle.crypto.signers.ECDSASigner; import org.bouncycastle.crypto.signers.Ed25519Signer; import org.bouncycastle.crypto.signers.Ed448Signer; -import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.math.ec.FixedPointCombMultiplier; -import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve; -import org.bouncycastle.math.ec.custom.sec.SecP384R1Curve; -import org.bouncycastle.math.ec.custom.sec.SecP521R1Curve; import org.bouncycastle.mls.codec.MLSOutputStream; import org.bouncycastle.mls.crypto.MlsCipherSuite; import org.bouncycastle.mls.crypto.MlsSigner; -import org.bouncycastle.util.encoders.Hex; public class BcMlsSigner implements MlsSigner { Signer signer; - ECDomainParameters domainParams; + ECNamedDomainParameters domainParams; int sigID; public BcMlsSigner(int sigID) { this.sigID = sigID; - ECCurve curve; switch (sigID) { case ecdsa_secp256r1_sha256: signer = new DSADigestSigner(new ECDSASigner(), new SHA256Digest()); - curve = new SecP256R1Curve(); - domainParams = new ECDomainParameters( - curve, - curve.createPoint( - new BigInteger(1, Hex.decode("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")), - new BigInteger(1, Hex.decode("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5")) - ), - curve.getOrder(), - curve.getCofactor(), - Hex.decode("c49d360886e704936a6678e1139d26b7819f7e90") - ); + domainParams = ECNamedDomainParameters.lookup(SECObjectIdentifiers.secp256r1); break; case ecdsa_secp521r1_sha512: signer = new DSADigestSigner(new ECDSASigner(), new SHA512Digest()); - curve = new SecP521R1Curve(); - domainParams = new ECDomainParameters( - curve, - curve.createPoint( - new BigInteger("c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", 16), - new BigInteger("11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", 16) - ), - curve.getOrder(), - curve.getCofactor(), - Hex.decode("d09e8800291cb85396cc6717393284aaa0da64ba") - ); + domainParams = ECNamedDomainParameters.lookup(SECObjectIdentifiers.secp521r1); break; case ecdsa_secp384r1_sha384: signer = new DSADigestSigner(new ECDSASigner(), new SHA384Digest()); - curve = new SecP384R1Curve(); - domainParams = new ECDomainParameters( - curve, - curve.createPoint( - new BigInteger(1, Hex.decode("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7")), - new BigInteger(1, Hex.decode("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f")) - ), - curve.getOrder(), - curve.getCofactor(), - Hex.decode("a335926aa319a27a1d00896a6773a4827acdac73") - ); + domainParams = ECNamedDomainParameters.lookup(SECObjectIdentifiers.secp384r1); break; case ed25519: signer = new Ed25519Signer(); @@ -115,20 +80,16 @@ public AsymmetricCipherKeyPair generateSignatureKeyPair() case ecdsa_secp521r1_sha512: case ecdsa_secp384r1_sha384: ECKeyPairGenerator pGen = new ECKeyPairGenerator(); - ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( - domainParams, - random); - pGen.init(genParam); + pGen.init(new ECKeyGenerationParameters(domainParams, random)); return pGen.generateKeyPair(); - case ed448: - Ed448KeyPairGenerator kpg448 = new Ed448KeyPairGenerator(); - kpg448.init(new Ed448KeyGenerationParameters(random)); - return kpg448.generateKeyPair(); - case ed25519: Ed25519KeyPairGenerator kpg25519 = new Ed25519KeyPairGenerator(); kpg25519.init(new Ed25519KeyGenerationParameters(random)); return kpg25519.generateKeyPair(); + case ed448: + Ed448KeyPairGenerator kpg448 = new Ed448KeyPairGenerator(); + kpg448.init(new Ed448KeyGenerationParameters(random)); + return kpg448.generateKeyPair(); default: throw new IllegalStateException("invalid sig algorithm"); } @@ -142,10 +103,10 @@ public byte[] serializePublicKey(AsymmetricKeyParameter key) case ecdsa_secp521r1_sha512: case ecdsa_secp384r1_sha384: return ((ECPublicKeyParameters)key).getQ().getEncoded(false); - case ed448: - return ((Ed448PublicKeyParameters)key).getEncoded(); case ed25519: return ((Ed25519PublicKeyParameters)key).getEncoded(); + case ed448: + return ((Ed448PublicKeyParameters)key).getEncoded(); default: throw new IllegalStateException("invalid sig algorithm"); } @@ -160,10 +121,10 @@ public byte[] serializePrivateKey(AsymmetricKeyParameter key) case ecdsa_secp521r1_sha512: case ecdsa_secp384r1_sha384: return ((ECPrivateKeyParameters)key).getD().toByteArray(); - case ed448: - return ((Ed448PrivateKeyParameters)key).getEncoded(); case ed25519: return ((Ed25519PrivateKeyParameters)key).getEncoded(); + case ed448: + return ((Ed448PrivateKeyParameters)key).getEncoded(); default: throw new IllegalStateException("invalid sig algorithm"); } diff --git a/mls/src/main/java/org/bouncycastle/mls/protocol/Group.java b/mls/src/main/java/org/bouncycastle/mls/protocol/Group.java index bc24424546..04f3fbc08e 100644 --- a/mls/src/main/java/org/bouncycastle/mls/protocol/Group.java +++ b/mls/src/main/java/org/bouncycastle/mls/protocol/Group.java @@ -56,7 +56,7 @@ public class Group { - public class GroupWithMessage + public static class GroupWithMessage { public Group group; public MLSMessage message; @@ -193,7 +193,7 @@ public TombstoneWithMessage(Group group, Proposal.ReInit reinit, MLSMessage mess public static final short RESTART_COMMIT_PARAMS = 2; public static final short REINIT_COMMIT_PARAMS = 3; - static public class CommitParameters + public static class CommitParameters { short paramID; // External @@ -312,7 +312,7 @@ public CommitOptions(List extraProposals, boolean inlineTree, boolean } } - class JoinersWithPSKS + static class JoinersWithPSKS { List joiners; List psks; @@ -324,7 +324,7 @@ public JoinersWithPSKS(List joiners, List getExtensions() + public List getExtensions() { return extensions; } @@ -1184,7 +1184,7 @@ else if (commitOptions != null && commitOptions.extraProposals.size() == 1) return new TombstoneWithMessage(gwm.group, reinit, gwm.message); } - static public MLSMessage newMemberAdd(byte[] groupID, long epoch, KeyPackage newMember, AsymmetricCipherKeyPair sigSk) + public static MLSMessage newMemberAdd(byte[] groupID, long epoch, KeyPackage newMember, AsymmetricCipherKeyPair sigSk) throws Exception { MlsCipherSuite suite = newMember.getSuite(); diff --git a/mls/src/test/java/org/bouncycastle/mls/test/ClientVectorTest.java b/mls/src/test/java/org/bouncycastle/mls/test/ClientVectorTest.java index 4b96ccc867..71c7146784 100644 --- a/mls/src/test/java/org/bouncycastle/mls/test/ClientVectorTest.java +++ b/mls/src/test/java/org/bouncycastle/mls/test/ClientVectorTest.java @@ -3,6 +3,7 @@ import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; +import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -11,6 +12,7 @@ import junit.framework.TestCase; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.mls.TreeKEM.TreeKEMPublicKey; import org.bouncycastle.mls.codec.MLSInputStream; import org.bouncycastle.mls.codec.MLSMessage; @@ -20,6 +22,7 @@ import org.bouncycastle.mls.protocol.Group; import org.bouncycastle.test.TestResourceFinder; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.BigIntegers; import org.bouncycastle.util.encoders.Hex; public class ClientVectorTest @@ -134,6 +137,14 @@ public Epoch(List proposals, byte[] commit, byte[] epoch_authenticator) } MlsCipherSuite suite = MlsCipherSuite.getSuite(cipherSuite); + + if(cipherSuite == MlsCipherSuite.MLS_256_DHKEMP521_AES256GCM_SHA512_P521) + { + //Converts encoded HPKE private key for P521 to comply with length constraints + encryption_priv = BigIntegers.asUnsignedByteArray(66, new BigInteger(1, encryption_priv)); + init_priv = BigIntegers.asUnsignedByteArray(66, new BigInteger(1, init_priv)); + } + AsymmetricCipherKeyPair leafKeyPair = suite.getHPKE().deserializePrivateKey(encryption_priv, null); Map externalPsks = new HashMap(); for (PreSharedKeyID ext : externalPSKs) diff --git a/mls/src/test/java/org/bouncycastle/mls/test/MessageProtectionTest.java b/mls/src/test/java/org/bouncycastle/mls/test/MessageProtectionTest.java index 4d594cee3b..2e7d20779e 100644 --- a/mls/src/test/java/org/bouncycastle/mls/test/MessageProtectionTest.java +++ b/mls/src/test/java/org/bouncycastle/mls/test/MessageProtectionTest.java @@ -178,7 +178,7 @@ private MlsCipherSuite createNewSuite(short id) return new MlsCipherSuite(MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448, new BcMlsSigner(MlsSigner.ed448), new BcMlsKdf(new SHA512Digest()), new BcMlsAead(HPKE.aead_CHACHA20_POLY1305), new HPKE(HPKE.mode_base, HPKE.kem_X448_SHA512, HPKE.kdf_HKDF_SHA512, HPKE.aead_CHACHA20_POLY1305)); case MLS_256_DHKEMP384_AES256GCM_SHA384_P384: - return new MlsCipherSuite(MLS_256_DHKEMP384_AES256GCM_SHA384_P384, new BcMlsSigner(MlsSigner.ecdsa_secp384r1_sha384), new BcMlsKdf(new SHA384Digest()), new BcMlsAead(HPKE.aead_AES_GCM256), new HPKE(HPKE.mode_base, HPKE.kem_P384_SHA348, HPKE.kdf_HKDF_SHA384, HPKE.aead_AES_GCM256)); + return new MlsCipherSuite(MLS_256_DHKEMP384_AES256GCM_SHA384_P384, new BcMlsSigner(MlsSigner.ecdsa_secp384r1_sha384), new BcMlsKdf(new SHA384Digest()), new BcMlsAead(HPKE.aead_AES_GCM256), new HPKE(HPKE.mode_base, HPKE.kem_P384_SHA384, HPKE.kdf_HKDF_SHA384, HPKE.aead_AES_GCM256)); } return null; diff --git a/pg/build.gradle b/pg/build.gradle index 2bd4a4dd5a..2066fc92d2 100644 --- a/pg/build.gradle +++ b/pg/build.gradle @@ -1,6 +1,6 @@ plugins { - id "biz.aQute.bnd.builder" version "7.0.0" + id "biz.aQute.bnd.builder" version "7.1.0" } sourceSets { @@ -91,6 +91,11 @@ jar { manifest.attributes('Export-Package': "org.bouncycastle.{apache|bcpg|gpg|openpgp}.*;version=${v}") manifest.attributes('Import-Package': "java.*;resolution:=optional,javax.*;resolution:=optional,!org.bouncycastle.{apache|bcpg|gpg|openpgp|}.*,org.bouncycastle.*;version=\"[${v},${maxVersion})\"") manifest.attributes('Bundle-Version': "${v}") + manifest.attributes('Permissions': 'all-permissions') + manifest.attributes('Codebase': '*') + manifest.attributes('Application-Library-Allowable-Codebase': '*') + manifest.attributes('Caller-Allowable-Codebase': '*') + manifest.attributes('Trusted-Library': 'true') } @@ -129,4 +134,4 @@ publishing { } -} \ No newline at end of file +} diff --git a/pg/src/main/java/org/bouncycastle/apache/bzip2/CBZip2InputStream.java b/pg/src/main/java/org/bouncycastle/apache/bzip2/CBZip2InputStream.java index 752d90dc1a..fb79c328f5 100644 --- a/pg/src/main/java/org/bouncycastle/apache/bzip2/CBZip2InputStream.java +++ b/pg/src/main/java/org/bouncycastle/apache/bzip2/CBZip2InputStream.java @@ -140,6 +140,11 @@ public CBZip2InputStream(InputStream zStream) beginBlock(); } + public void close() throws IOException + { + implClose(true); + } + public int read() throws IOException { @@ -186,7 +191,7 @@ private void beginBlock() throw new IOException("Stream CRC error"); } - bsFinishedWithStream(); + // TODO If not a LeaveOpen stream, should we check that we are at the end of stream here? streamEnd = true; return; } @@ -250,22 +255,16 @@ private void endBlock() streamCRC = Integers.rotateLeft(streamCRC, 1) ^ blockFinalCRC; } - private void bsFinishedWithStream() + private void implClose(boolean closeInput) throws IOException { - try + if (this.bsStream != null) { - if (this.bsStream != null) + if (closeInput) { - if (this.bsStream != System.in) - { - this.bsStream.close(); - this.bsStream = null; - } + this.bsStream.close(); } - } - catch (IOException ioe) - { - //ignore + + this.bsStream = null; } } diff --git a/pg/src/main/java/org/bouncycastle/bcpg/AEADEncDataPacket.java b/pg/src/main/java/org/bouncycastle/bcpg/AEADEncDataPacket.java index f417e94d70..c3fada791a 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/AEADEncDataPacket.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/AEADEncDataPacket.java @@ -40,14 +40,22 @@ public AEADEncDataPacket(BCPGInputStream in, version = (byte)in.read(); if (version != VERSION_1) { - throw new UnsupportedPacketVersionException("wrong AEAD packet version: " + version); + throw new UnsupportedPacketVersionException("Unknown AEAD packet version: " + version); } algorithm = (byte)in.read(); aeadAlgorithm = (byte)in.read(); chunkSize = (byte)in.read(); - iv = new byte[AEADUtils.getIVLength(aeadAlgorithm)]; + try + { + int ivLen = AEADUtils.getIVLength(aeadAlgorithm); + iv = new byte[ivLen]; + } + catch (IllegalArgumentException e) + { + throw new MalformedPacketException("Unknown AEAD algorithm ID: " + aeadAlgorithm, e); + } in.readFully(iv); } diff --git a/pg/src/main/java/org/bouncycastle/bcpg/AEADUtils.java b/pg/src/main/java/org/bouncycastle/bcpg/AEADUtils.java index 504a657152..61c4b2f2bb 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/AEADUtils.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/AEADUtils.java @@ -51,8 +51,8 @@ public static int getAuthTagLength(int aeadAlgorithmTag) * Split a given byte array containing

    m
    bytes of key and
    n-8
    bytes of IV into * two separate byte arrays. *
    m
    is the key length of the cipher algorithm, while
    n
    is the IV length of the AEAD algorithm. - * Note, that the IV is filled with
    n-8
    bytes only, the remainder is left as 0s. - * Return an array of both arrays with the key and index 0 and the IV at index 1. + * Note that the IV is filled with
    n-8
    bytes only, the remainder is left as 0s. + * Return an array of both arrays with the key at index 0 and the IV at index 1. * * @param messageKeyAndIv
    m+n-8
    bytes of concatenated message key and IV * @param cipherAlgo symmetric cipher algorithm @@ -62,7 +62,7 @@ public static int getAuthTagLength(int aeadAlgorithmTag) public static byte[][] splitMessageKeyAndIv(byte[] messageKeyAndIv, int cipherAlgo, int aeadAlgo) { int keyLen = SymmetricKeyUtils.getKeyLengthInOctets(cipherAlgo); - int ivLen = AEADUtils.getIVLength(aeadAlgo); + int ivLen = getIVLength(aeadAlgo); byte[] messageKey = new byte[keyLen]; byte[] iv = new byte[ivLen]; System.arraycopy(messageKeyAndIv, 0, messageKey, 0, messageKey.length); diff --git a/pg/src/main/java/org/bouncycastle/bcpg/ArmoredInputStream.java b/pg/src/main/java/org/bouncycastle/bcpg/ArmoredInputStream.java index 817829d128..99cd1532ef 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/ArmoredInputStream.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/ArmoredInputStream.java @@ -4,6 +4,9 @@ import java.io.EOFException; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import org.bouncycastle.util.StringList; import org.bouncycastle.util.Strings; @@ -75,7 +78,7 @@ private static int decode(int in0, int in1, int in2, int in3, byte[] out) if (in2 == '=') { - b1 = decodingTable[in0] &0xff; + b1 = decodingTable[in0] & 0xff; b2 = decodingTable[in1] & 0xff; if ((b1 | b2) < 0) @@ -129,30 +132,33 @@ else if (in3 == '=') */ private boolean detectMissingChecksum = false; - private final CRC24 crc; - - InputStream in; - boolean start = true; - byte[] outBuf = new byte[3]; - int bufPtr = 3; - boolean crcFound = false; - boolean hasHeaders = true; - String header = null; - boolean newLineFound = false; - boolean clearText = false; - boolean restart = false; - StringList headerList= Strings.newList(); - int lastC = 0; - boolean isEndOfStream; - + private final CRC24 crc; + + InputStream in; + boolean start = true; + byte[] outBuf = new byte[3]; + int bufPtr = 3; + boolean crcFound = false; + boolean hasHeaders = true; + String header = null; + boolean newLineFound = false; + boolean clearText = false; + boolean restart = false; + StringList headerList = Strings.newList(); + int lastC = 0; + boolean isEndOfStream; + + private boolean validateAllowedHeaders = false; + private List allowedHeaders = defaultAllowedHeaders(); + /** - * Create a stream for reading a PGP armoured message, parsing up to a header + * Create a stream for reading a PGP armoured message, parsing up to a header * and then reading the data that follows. - * + * * @param in */ public ArmoredInputStream( - InputStream in) + InputStream in) throws IOException { this(in, true); @@ -160,21 +166,21 @@ public ArmoredInputStream( /** * Create an armoured input stream which will assume the data starts - * straight away, or parse for headers first depending on the value of + * straight away, or parse for headers first depending on the value of * hasHeaders. - * + * * @param in * @param hasHeaders true if headers are to be looked for, false otherwise. */ public ArmoredInputStream( - InputStream in, - boolean hasHeaders) + InputStream in, + boolean hasHeaders) throws IOException { this.in = in; this.hasHeaders = hasHeaders; this.crc = new FastCRC24(); - + if (hasHeaders) { parseHeaders(); @@ -184,40 +190,74 @@ public ArmoredInputStream( } private ArmoredInputStream( - InputStream in, - Builder builder) + InputStream in, + Builder builder) throws IOException { this.in = in; this.hasHeaders = builder.hasHeaders; this.detectMissingChecksum = builder.detectMissingCRC; this.crc = builder.ignoreCRC ? null : new FastCRC24(); + this.validateAllowedHeaders = builder.validateAllowedHeaders; + this.allowedHeaders = builder.allowedHeaders; if (hasHeaders) { parseHeaders(); } + if (validateAllowedHeaders) + { + rejectUnknownHeadersInCSFMessages(); + } + start = false; } + private void rejectUnknownHeadersInCSFMessages() + throws ArmoredInputException + { + Iterator headerLines = headerList.iterator(); + String header = (String)headerLines.next(); + + // Only reject unknown headers in cleartext signed messages + if (!header.startsWith("-----BEGIN PGP SIGNED MESSAGE-----")) + { + return; + } + + outerloop: + while (headerLines.hasNext()) + { + String headerLine = (String)headerLines.next(); + for (Iterator it = allowedHeaders.iterator(); it.hasNext(); ) + { + if (headerLine.startsWith((String)it.next() + ": ")) + { + continue outerloop; + } + } + throw new ArmoredInputException("Illegal ASCII armor header line in clearsigned message encountered: " + headerLine); + } + } + public int available() throws IOException { return in.available(); } - + private boolean parseHeaders() throws IOException { header = null; - - int c; - int last = 0; - boolean headerFound = false; - + + int c; + int last = 0; + boolean headerFound = false; + headerList = Strings.newList(); - + // // if restart we already have a header // @@ -234,15 +274,15 @@ private boolean parseHeaders() headerFound = true; break; } - + last = c; } } if (headerFound) { - boolean eolReached = false; - boolean crLf = false; + boolean eolReached = false; + boolean crLf = false; ByteArrayOutputStream buf = new ByteArrayOutputStream(); buf.write('-'); @@ -251,7 +291,7 @@ private boolean parseHeaders() { buf.write('-'); } - + while ((c = in.read()) >= 0) { if (last == '\r' && c == '\n') @@ -268,7 +308,16 @@ private boolean parseHeaders() } if (c == '\r' || (last != '\r' && c == '\n')) { - String line = Strings.fromUTF8ByteArray(buf.toByteArray()); + String line; + + try + { + line = Strings.fromUTF8ByteArray(buf.toByteArray()); + } + catch (Exception e) + { + throw new ArmoredInputException(e.getMessage()); + } if (line.trim().length() == 0) { break; @@ -293,10 +342,10 @@ private boolean parseHeaders() eolReached = true; } } - + last = c; } - + if (crLf) { int nl = in.read(); // skip last \n @@ -306,12 +355,12 @@ private boolean parseHeaders() } } } - + if (headerList.size() > 0) { header = headerList.get(0); } - + clearText = "-----BEGIN PGP SIGNED MESSAGE-----".equals(header); newLineFound = true; @@ -337,15 +386,17 @@ public boolean isEndOfStream() /** * Return the armor header line (if there is one) + * * @return the armor header line, null if none present. */ - public String getArmorHeaderLine() + public String getArmorHeaderLine() { return header; } - + /** * Return the armor headers (the lines after the armor header line), + * * @return an array of armor headers, null if there aren't any. */ public String[] getArmorHeaders() @@ -357,12 +408,12 @@ public String[] getArmorHeaders() return headerList.toStringArray(1, headerList.size()); } - - private int readIgnoreSpace() + + private int readIgnoreSpace() throws IOException { - int c = in.read(); - + int c = in.read(); + while (c == ' ' || c == '\t' || c == '\f' || c == '\u000B') // \u000B ~ \v { c = in.read(); @@ -375,11 +426,11 @@ private int readIgnoreSpace() return c; } - + public int read() throws IOException { - int c; + int c; if (start) { @@ -394,7 +445,7 @@ public int read() } start = false; } - + if (clearText) { c = in.read(); @@ -425,25 +476,25 @@ else if (newLineFound && c == '-') newLineFound = false; } } - + lastC = c; if (c < 0) { isEndOfStream = true; } - + return c; } if (bufPtr > 2 || crcFound) { c = readIgnoreSpace(); - + if (c == '\r' || c == '\n') { c = readIgnoreSpace(); - + while (c == '\n' || c == '\r') { c = readIgnoreSpace(); @@ -533,24 +584,24 @@ else if (newLineFound && c == '-') * an array of bytes. An attempt is made to read as many as * len bytes, but a smaller number may be read. * The number of bytes actually read is returned as an integer. - * + *

    * The first byte read is stored into element b[off], the * next one into b[off+1], and so on. The number of bytes read * is, at most, equal to len. - * + *

    * NOTE: We need to override the custom behavior of Java's {@link InputStream#read(byte[], int, int)}, * as the upstream method silently swallows {@link IOException IOExceptions}. * This would cause CRC checksum errors to go unnoticed. * - * @see Related BC bug report - * @param b byte array + * @param b byte array * @param off offset at which we start writing data to the array * @param len number of bytes we write into the array * @return total number of bytes read into the buffer - * * @throws IOException if an exception happens AT ANY POINT + * @see Related BC bug report */ - public int read(byte[] b, int off, int len) throws IOException + public int read(byte[] b, int off, int len) + throws IOException { checkIndexSize(b.length, off, len); @@ -567,7 +618,7 @@ public int read(byte[] b, int off, int len) throws IOException b[off] = (byte)c; int i = 1; - for (; i < len ; i++) + for (; i < len; i++) { c = read(); if (c == -1) @@ -610,6 +661,17 @@ public void setDetectMissingCRC(boolean detectMissing) this.detectMissingChecksum = detectMissing; } + private static List defaultAllowedHeaders() + { + List allowedHeaders = new ArrayList(); + allowedHeaders.add(ArmoredOutputStream.COMMENT_HDR); + allowedHeaders.add(ArmoredOutputStream.VERSION_HDR); + allowedHeaders.add(ArmoredOutputStream.CHARSET_HDR); + allowedHeaders.add(ArmoredOutputStream.HASH_HDR); + allowedHeaders.add(ArmoredOutputStream.MESSAGE_ID_HDR); + return allowedHeaders; + } + public static Builder builder() { return new Builder(); @@ -620,6 +682,8 @@ public static class Builder private boolean hasHeaders = true; private boolean detectMissingCRC = false; private boolean ignoreCRC = false; + private boolean validateAllowedHeaders = false; + private List allowedHeaders = defaultAllowedHeaders(); private Builder() { @@ -639,6 +703,18 @@ public Builder setParseForHeaders(boolean hasHeaders) return this; } + public Builder setValidateClearsignedMessageHeaders(boolean validateHeaders) + { + this.validateAllowedHeaders = validateHeaders; + return this; + } + + public Builder addAllowedArmorHeader(String header) + { + allowedHeaders.add(header.trim()); + return this; + } + /** * Change how the stream should react if it encounters missing CRC checksum. * The default value is false (ignore missing CRC checksums). If the behavior is set to true, diff --git a/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java b/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java index aa957720ad..77cabdcb76 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java @@ -612,6 +612,41 @@ public Builder addComment(String comment) return addHeader(COMMENT_HDR, comment); } + public Builder addEllipsizedComment(String comment) + { + int availableCommentCharsPerLine = 64 - (COMMENT_HDR.length() + 2); // ASCII armor width - header len + comment = comment.trim(); + + if (comment.length() > availableCommentCharsPerLine) + { + comment = comment.substring(0, availableCommentCharsPerLine - 1) + '…'; + } + addComment(comment); + return this; + } + + public Builder addSplitMultilineComment(String comment) + { + int availableCommentCharsPerLine = 64 - (COMMENT_HDR.length() + 2); // ASCII armor width - header len + + comment = comment.trim(); + for (String line : comment.split("\n")) + { + while (line.length() > availableCommentCharsPerLine) + { + // split comment into multiple lines + addComment(comment.substring(0, availableCommentCharsPerLine)); + line = line.substring(availableCommentCharsPerLine).trim(); + } + + if (line.length() != 0) + { + addComment(line); + } + } + return this; + } + /** * Set and replace the given header value with a single-line header. * If the value is

    null
    , this method will remove the header entirely. diff --git a/pg/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java b/pg/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java index 045ba3b6ba..2a782f39a8 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java @@ -239,8 +239,9 @@ public Packet readPacket() } else { - objStream = new BCPGInputStream( - new BufferedInputStream(new PartialInputStream(this, partial, bodyLen))); +// assert !this.next; + PartialInputStream pis = new PartialInputStream(this.in, partial, bodyLen); + objStream = new BCPGInputStream(new BufferedInputStream(pis)); } switch (tag) @@ -339,14 +340,11 @@ public void close() private static class PartialInputStream extends InputStream { - private BCPGInputStream in; + private final InputStream in; private boolean partial; private int dataLength; - PartialInputStream( - BCPGInputStream in, - boolean partial, - int dataLength) + PartialInputStream(InputStream in, boolean partial, int dataLength) { this.in = in; this.partial = partial; diff --git a/pg/src/main/java/org/bouncycastle/bcpg/ECDHPublicBCPGKey.java b/pg/src/main/java/org/bouncycastle/bcpg/ECDHPublicBCPGKey.java index 807459052a..92a076a5f6 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/ECDHPublicBCPGKey.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/ECDHPublicBCPGKey.java @@ -36,12 +36,12 @@ public ECDHPublicBCPGKey( super(in); int length = in.read(); - byte[] kdfParameters = new byte[length]; - if (kdfParameters.length != 3) + if (length != 3) { - throw new IllegalStateException("kdf parameters size of 3 expected."); + throw new MalformedPacketException("KDF parameters size of 3 expected."); } + byte[] kdfParameters = new byte[length]; in.readFully(kdfParameters); reserved = kdfParameters[0]; diff --git a/pg/src/main/java/org/bouncycastle/bcpg/FingerprintUtil.java b/pg/src/main/java/org/bouncycastle/bcpg/FingerprintUtil.java index adf16a67c0..9e249b3983 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/FingerprintUtil.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/FingerprintUtil.java @@ -3,6 +3,8 @@ import org.bouncycastle.util.Pack; import org.bouncycastle.util.encoders.Hex; +import java.util.Locale; + public class FingerprintUtil { @@ -141,7 +143,7 @@ public static void writeKeyID(long keyID, byte[] bytes) public static String prettifyFingerprint(byte[] fingerprint) { // -DM Hex.toHexString - char[] hex = Hex.toHexString(fingerprint).toUpperCase().toCharArray(); + char[] hex = Hex.toHexString(fingerprint).toUpperCase(Locale.getDefault()).toCharArray(); StringBuilder sb = new StringBuilder(); switch (hex.length) { diff --git a/pg/src/main/java/org/bouncycastle/bcpg/GnuExtendedS2K.java b/pg/src/main/java/org/bouncycastle/bcpg/GnuExtendedS2K.java new file mode 100644 index 0000000000..9e94b00376 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/bcpg/GnuExtendedS2K.java @@ -0,0 +1,19 @@ +package org.bouncycastle.bcpg; + +/** + * Add a constructor fort GNU-extended S2K + *

    + * This extension is documented on GnuPG documentation DETAILS file, + * section "GNU extensions to the S2K algorithm". Its support is + * already present in S2K class but lack for a constructor. + */ +public class GnuExtendedS2K + extends S2K +{ + public GnuExtendedS2K(int mode) + { + super(0x0); + this.type = GNU_DUMMY_S2K; + this.protectionMode = mode; + } +} diff --git a/pg/src/main/java/org/bouncycastle/bcpg/KeyIdentifier.java b/pg/src/main/java/org/bouncycastle/bcpg/KeyIdentifier.java index 16c58f15ef..9398792c2a 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/KeyIdentifier.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/KeyIdentifier.java @@ -2,6 +2,7 @@ import java.util.Iterator; import java.util.List; +import java.util.Locale; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; @@ -31,6 +32,14 @@ public KeyIdentifier(String hexEncoded) */ public KeyIdentifier(byte[] fingerprint) { + // Long KeyID + if (fingerprint.length == 8) + { + keyId = FingerprintUtil.longFromRightMostBytes(fingerprint); + this.fingerprint = null; + return; + } + this.fingerprint = Arrays.clone(fingerprint); // v4 @@ -69,7 +78,16 @@ public KeyIdentifier(byte[] fingerprint, long keyId) */ public KeyIdentifier(long keyId) { - this(null, keyId); + if (keyId == 0L) + { + this.keyId = 0L; + this.fingerprint = new byte[0]; + } + else + { + this.keyId = keyId; + this.fingerprint = null; + } } /** @@ -77,7 +95,7 @@ public KeyIdentifier(long keyId) */ private KeyIdentifier() { - this(new byte[0], 0L); + this(0L); } /** @@ -123,7 +141,7 @@ public long getKeyId() */ public boolean isWildcard() { - return keyId == 0L && fingerprint.length == 0; + return keyId == 0L && (fingerprint == null || fingerprint.length == 0); } /** @@ -152,6 +170,11 @@ public boolean matches(KeyIdentifier other) return true; } + return matchesExplicit(other); + } + + public boolean matchesExplicit(KeyIdentifier other) + { if (fingerprint != null && other.fingerprint != null) { return Arrays.constantTimeAreEqual(fingerprint, other.fingerprint); @@ -196,7 +219,7 @@ public boolean isPresentIn(List others) { for (Iterator it = others.iterator(); it.hasNext();) { - if (this.matches((KeyIdentifier)it.next())) + if (this.matchesExplicit((KeyIdentifier)it.next())) { return true; } @@ -247,6 +270,19 @@ public String toString() } // -DM Hex.toHexString - return Hex.toHexString(fingerprint).toUpperCase(); + return Hex.toHexString(fingerprint).toUpperCase(Locale.getDefault()); + } + + public String toPrettyPrint() + { + if (isWildcard()) + { + return "*"; + } + if (fingerprint == null) + { + return "0x" + Long.toHexString(keyId).toUpperCase(Locale.getDefault()); + } + return FingerprintUtil.prettifyFingerprint(fingerprint); } } diff --git a/pg/src/main/java/org/bouncycastle/bcpg/LiteralDataPacket.java b/pg/src/main/java/org/bouncycastle/bcpg/LiteralDataPacket.java index 2b1a196a51..8ab7ad86af 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/LiteralDataPacket.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/LiteralDataPacket.java @@ -31,6 +31,10 @@ public class LiteralDataPacket format = in.read(); int l = in.read(); + if (l < 0) + { + throw new MalformedPacketException("File name size cannot be negative."); + } fileName = new byte[l]; for (int i = 0; i != fileName.length; i++) diff --git a/pg/src/main/java/org/bouncycastle/bcpg/MPInteger.java b/pg/src/main/java/org/bouncycastle/bcpg/MPInteger.java index 286ab2ab34..91596f827e 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/MPInteger.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/MPInteger.java @@ -3,28 +3,30 @@ import java.io.IOException; import java.math.BigInteger; +import org.bouncycastle.util.BigIntegers; + /** * a multiple precision integer */ public class MPInteger extends BCPGObject { - BigInteger value = null; - - public MPInteger( - BCPGInputStream in) - throws IOException + private final BigInteger value; + + public MPInteger(BCPGInputStream in) throws IOException { - int length = StreamUtil.read2OctetLength(in); - byte[] bytes = new byte[(length + 7) / 8]; - - in.readFully(bytes); - - value = new BigInteger(1, bytes); + /* + * TODO RFC 9580 3.2. When parsing an MPI in a version 6 Key, Signature, or Public Key Encrypted + * Session Key (PKESK) packet, the implementation MUST check that the encoded length matches the + * length starting from the most significant non-zero bit; if it doesn't match, reject the packet as + * malformed. + */ + boolean validateLength = false; + + this.value = readMPI(in, validateLength); } - - public MPInteger( - BigInteger value) + + public MPInteger(BigInteger value) { if (value == null || value.signum() < 0) { @@ -33,27 +35,31 @@ public MPInteger( this.value = value; } - + public BigInteger getValue() { return value; } - - public void encode( - BCPGOutputStream out) - throws IOException + + public void encode(BCPGOutputStream out) throws IOException { StreamUtil.write2OctetLength(out, value.bitLength()); + BigIntegers.writeUnsignedByteArray(out, value); + } - byte[] bytes = value.toByteArray(); - - if (bytes[0] == 0) - { - out.write(bytes, 1, bytes.length - 1); - } - else + private static BigInteger readMPI(BCPGInputStream in, boolean validateLength) throws IOException + { + int bitLength = StreamUtil.read2OctetLength(in); + int byteLength = (bitLength + 7) / 8; + byte[] bytes = new byte[byteLength]; + in.readFully(bytes); + BigInteger n = new BigInteger(1, bytes); + + if (validateLength && n.bitLength() != bitLength) { - out.write(bytes, 0, bytes.length); + throw new IOException("malformed MPI"); } + + return n; } } diff --git a/pg/src/main/java/org/bouncycastle/bcpg/MalformedPacketException.java b/pg/src/main/java/org/bouncycastle/bcpg/MalformedPacketException.java new file mode 100644 index 0000000000..784a6253f6 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/bcpg/MalformedPacketException.java @@ -0,0 +1,23 @@ +package org.bouncycastle.bcpg; + +import java.io.IOException; + +public class MalformedPacketException + extends IOException +{ + + public MalformedPacketException(String message) + { + super(message); + } + + public MalformedPacketException(Throwable cause) + { + super(cause); + } + + public MalformedPacketException(String message, Throwable cause) + { + super(message, cause); + } +} diff --git a/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java b/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java index 483d41729b..083d975bf7 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java @@ -15,6 +15,10 @@ public abstract class OctetArrayBCPGKey OctetArrayBCPGKey(int length, BCPGInputStream in) throws IOException { + if (length > PublicKeyPacket.MAX_LEN) + { + throw new IOException("Max key length (" + PublicKeyPacket.MAX_LEN + ") exceeded (" + length + ")"); + } key = new byte[length]; in.readFully(key); } diff --git a/pg/src/main/java/org/bouncycastle/bcpg/Packet.java b/pg/src/main/java/org/bouncycastle/bcpg/Packet.java index 8456713607..237da7c748 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/Packet.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/Packet.java @@ -60,4 +60,18 @@ public boolean isCritical() { return getPacketTag() <= 39; } + + static int sanitizeLength(int len, int max, String variableName) + throws MalformedPacketException + { + if (len < 0) + { + throw new MalformedPacketException(variableName + " cannot be negative."); + } + if (len > max) + { + throw new MalformedPacketException(variableName + " (" + len + ") exceeds limit (" + max + ")."); + } + return len; + } } diff --git a/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyEncSessionPacket.java b/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyEncSessionPacket.java index d7a6e4ec52..b629441fb8 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyEncSessionPacket.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyEncSessionPacket.java @@ -55,6 +55,10 @@ public class PublicKeyEncSessionPacket else if (version == VERSION_6) { int keyInfoLen = in.read(); + if (keyInfoLen < 0) + { + throw new MalformedPacketException("Key Info Length cannot be negative: " + keyInfoLen); + } if (keyInfoLen == 0) { // anon recipient @@ -69,13 +73,20 @@ else if (version == VERSION_6) in.readFully(keyFingerprint); // Derived key-ID from fingerprint // TODO: Replace with getKeyIdentifier - if (keyVersion == PublicKeyPacket.VERSION_4) + try { - keyID = FingerprintUtil.keyIdFromV4Fingerprint(keyFingerprint); + if (keyVersion == PublicKeyPacket.VERSION_4) + { + keyID = FingerprintUtil.keyIdFromV4Fingerprint(keyFingerprint); + } + else + { + keyID = FingerprintUtil.keyIdFromV6Fingerprint(keyFingerprint); + } } - else + catch (IllegalArgumentException e) { - keyID = FingerprintUtil.keyIdFromV6Fingerprint(keyFingerprint); + throw new MalformedPacketException("Malformed fingerprint encoding.", e); } } } diff --git a/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java b/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java index b8a4fa0b25..4d21ac8094 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java @@ -22,6 +22,8 @@ public class PublicKeyPacket extends ContainedPacket implements PublicKeyAlgorithmTags { + public final static int MAX_LEN = 2 * 1024 * 1024; // 2mb; McEliece keys can get ~1mb in size, so allow some margin + /** * OpenPGP v3 keys are deprecated. * They can only be used with RSA. @@ -150,6 +152,10 @@ public class PublicKeyPacket { // TODO: Use keyOctets to be able to parse unknown keys keyOctets = StreamUtil.read4OctetLength(in); + if (keyOctets < 0) + { + throw new MalformedPacketException("Octet length cannot be negative."); + } } parseKey(in, algorithm, keyOctets); @@ -166,49 +172,56 @@ private void parseKey(BCPGInputStream in, int algorithmId, long optLen) throws IOException { - switch (algorithmId) + try { - case RSA_ENCRYPT: - case RSA_GENERAL: - case RSA_SIGN: - key = new RSAPublicBCPGKey(in); - break; - case DSA: - key = new DSAPublicBCPGKey(in); - break; - case ELGAMAL_ENCRYPT: - case ELGAMAL_GENERAL: - key = new ElGamalPublicBCPGKey(in); - break; - case ECDH: - key = new ECDHPublicBCPGKey(in); - break; - case X25519: - key = new X25519PublicBCPGKey(in); - break; - case X448: - key = new X448PublicBCPGKey(in); - break; - case ECDSA: - key = new ECDSAPublicBCPGKey(in); - break; - case EDDSA_LEGACY: - key = new EdDSAPublicBCPGKey(in); - break; - case Ed25519: - key = new Ed25519PublicBCPGKey(in); - break; - case Ed448: - key = new Ed448PublicBCPGKey(in); - break; - default: - if (version == VERSION_6 || version == LIBREPGP_5) + switch (algorithmId) { - // with version 5 & 6, we can gracefully handle unknown key types, as the length is known. - key = new UnknownBCPGKey((int) optLen, in); + case RSA_ENCRYPT: + case RSA_GENERAL: + case RSA_SIGN: + key = new RSAPublicBCPGKey(in); + break; + case DSA: + key = new DSAPublicBCPGKey(in); + break; + case ELGAMAL_ENCRYPT: + case ELGAMAL_GENERAL: + key = new ElGamalPublicBCPGKey(in); + break; + case ECDH: + key = new ECDHPublicBCPGKey(in); + break; + case X25519: + key = new X25519PublicBCPGKey(in); + break; + case X448: + key = new X448PublicBCPGKey(in); break; + case ECDSA: + key = new ECDSAPublicBCPGKey(in); + break; + case EDDSA_LEGACY: + key = new EdDSAPublicBCPGKey(in); + break; + case Ed25519: + key = new Ed25519PublicBCPGKey(in); + break; + case Ed448: + key = new Ed448PublicBCPGKey(in); + break; + default: + if (version == VERSION_6 || version == LIBREPGP_5) + { + // with version 5 & 6, we can gracefully handle unknown key types, as the length is known. + key = new UnknownBCPGKey((int)optLen, in); + break; + } + throw new IOException("unknown PGP public key algorithm encountered: " + algorithm); } - throw new IOException("unknown PGP public key algorithm encountered: " + algorithm); + } + catch (RuntimeException e) + { + throw new MalformedPacketException("Malformed PGP key.", e); } } @@ -221,6 +234,7 @@ private void parseKey(BCPGInputStream in, int algorithmId, long optLen) * @deprecated use versioned {@link #PublicKeyPacket(int, int, Date, BCPGKey)} instead */ @Deprecated + @SuppressWarnings("InlineMeSuggester") public PublicKeyPacket( int algorithm, Date time, diff --git a/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyUtils.java b/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyUtils.java index 48c77ba566..84d6891834 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyUtils.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyUtils.java @@ -30,27 +30,26 @@ public static boolean isSigningAlgorithm(int publicKeyAlgorithm) } } -// /** -// * Return true, if the public key algorithm that corresponds to the given ID is capable of encryption. -// * -// * @param publicKeyAlgorithm public key algorithm id -// * @return true if algorithm can encrypt -// */ -// public static boolean isEncryptionAlgorithm(int publicKeyAlgorithm) -// { -// switch (publicKeyAlgorithm) -// { -// case PublicKeyAlgorithmTags.RSA_GENERAL: -// case PublicKeyAlgorithmTags.RSA_ENCRYPT: -// case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: -// case PublicKeyAlgorithmTags.ECDH: -// case PublicKeyAlgorithmTags.ELGAMAL_GENERAL: -// case PublicKeyAlgorithmTags.DIFFIE_HELLMAN: -// case PublicKeyAlgorithmTags.X25519: -// case PublicKeyAlgorithmTags.X448: -// return true; -// default: -// return false; -// } -// } + /** + * Return true, if the public key algorithm that corresponds to the given ID is capable of encryption. + * @param publicKeyAlgorithm public key algorithm id + * @return true if algorithm can encrypt + */ + public static boolean isEncryptionAlgorithm(int publicKeyAlgorithm) + { + switch (publicKeyAlgorithm) + { + case PublicKeyAlgorithmTags.RSA_GENERAL: + case PublicKeyAlgorithmTags.RSA_ENCRYPT: + case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: + case PublicKeyAlgorithmTags.ECDH: + case PublicKeyAlgorithmTags.ELGAMAL_GENERAL: + case PublicKeyAlgorithmTags.DIFFIE_HELLMAN: + case PublicKeyAlgorithmTags.X25519: + case PublicKeyAlgorithmTags.X448: + return true; + default: + return false; + } + } } diff --git a/pg/src/main/java/org/bouncycastle/bcpg/PublicSubkeyPacket.java b/pg/src/main/java/org/bouncycastle/bcpg/PublicSubkeyPacket.java index 4c93e8b2eb..864ca349db 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/PublicSubkeyPacket.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/PublicSubkeyPacket.java @@ -34,6 +34,7 @@ public class PublicSubkeyPacket * @deprecated use versioned {@link #PublicSubkeyPacket(int, int, Date, BCPGKey)} instead */ @Deprecated + @SuppressWarnings("InlineMeSuggester") public PublicSubkeyPacket( int algorithm, Date time, diff --git a/pg/src/main/java/org/bouncycastle/bcpg/S2K.java b/pg/src/main/java/org/bouncycastle/bcpg/S2K.java index 7d1461eaed..6288b4e73f 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/S2K.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/S2K.java @@ -6,6 +6,7 @@ import java.security.SecureRandom; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.util.Integers; /** @@ -54,7 +55,7 @@ public class S2K * This method is deprecated to use, since it can be brute-forced when used * with a low-entropy string, such as those typically provided by users. * Additionally, the usage of Simple S2K can lead to key and IV reuse. - * Therefore, in OpenPGP v6, Therefore, when generating an S2K specifier, + * Therefore, in OpenPGP v6, when generating an S2K specifier, * an implementation MUST NOT use Simple S2K. * * @deprecated use {@link #SALTED_AND_ITERATED} or {@link #ARGON_2} instead. @@ -416,28 +417,26 @@ public void encode( BCPGOutputStream out) throws IOException { + out.write(type); + switch (type) { case SIMPLE: - out.write(type); out.write(algorithm); break; case SALTED: - out.write(type); out.write(algorithm); out.write(iv); break; case SALTED_AND_ITERATED: - out.write(type); out.write(algorithm); out.write(iv); writeOneOctetOrThrow(out, itCount, "Iteration count"); break; case ARGON_2: - out.write(type); out.write(iv); writeOneOctetOrThrow(out, passes, "Passes"); writeOneOctetOrThrow(out, parallelism, "Parallelism"); @@ -445,7 +444,6 @@ public void encode( break; case GNU_DUMMY_S2K: - out.write(type); out.write(algorithm); out.write('G'); out.write('N'); @@ -471,7 +469,7 @@ public void encode( private void writeOneOctetOrThrow(BCPGOutputStream out, int val, String valName) throws IOException { - if (val >= 256) + if ((val & 0xFFFFFF00) != 0) { throw new IllegalStateException(valName + " not encodable"); } @@ -539,27 +537,30 @@ public Argon2Params(byte[] salt, int passes, int parallelism, int memSizeExp) { throw new IllegalArgumentException("Argon2 uses 16 bytes of salt"); } - this.salt = salt; - - if (passes < 1) + if (passes < 1 | passes > 255) { - throw new IllegalArgumentException("Number of passes MUST be positive, non-zero"); + throw new IllegalArgumentException("Passes MUST be an integer value from 1 to 255."); } - this.passes = passes; - - if (parallelism < 1) + if (parallelism < 1 || parallelism > 255) { - throw new IllegalArgumentException("Parallelism MUST be positive, non-zero."); + throw new IllegalArgumentException("Parallelism MUST be an integer value from 1 to 255."); } - this.parallelism = parallelism; - // log₂p = logₑp / logₑ2 - double log2_p = Math.log(parallelism) / Math.log(2); - // see https://www.rfc-editor.org/rfc/rfc9580.html#section-3.7.1.4-5 - if (memSizeExp < (3 + Math.ceil(log2_p)) || memSizeExp > 31) + /* + * Memory size (i.e. 1 << memorySizeExponent) MUST be an integer number of kibibytes from 8*p to 2^32-1. + * Max here is 30 because we are treating memory size as a signed 32-bit value. + */ + int minExp = 35 - Integers.numberOfLeadingZeros(parallelism - 1); + int maxExp = 30; + if (memSizeExp < minExp || memSizeExp > maxExp) { - throw new IllegalArgumentException("Memory size exponent MUST be between 3 + ⌈log₂(parallelism)⌉ and 31"); + throw new IllegalArgumentException( + "Memory size exponent MUST be an integer value from 3 + bitlen(parallelism - 1) to 30."); } + + this.salt = salt; + this.passes = passes; + this.parallelism = parallelism; this.memSizeExp = memSizeExp; } @@ -685,7 +686,7 @@ public static GNUDummyParams internal() { return new GNUDummyParams(GNU_PROTECTION_MODE_INTERNAL); } - + /** * Return the GNU Dummy S2K protection method. * diff --git a/pg/src/main/java/org/bouncycastle/bcpg/SecretKeyPacket.java b/pg/src/main/java/org/bouncycastle/bcpg/SecretKeyPacket.java index d2f9f8873c..9cd10854aa 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/SecretKeyPacket.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/SecretKeyPacket.java @@ -14,6 +14,8 @@ public class SecretKeyPacket extends ContainedPacket implements PublicKeyAlgorithmTags { + public static final int MAX_S2K_ENCODING_LEN = 8192; // arbitrary + /** * S2K-usage octet indicating that the secret key material is unprotected. */ @@ -146,11 +148,11 @@ public class SecretKeyPacket if (this instanceof SecretSubkeyPacket) { - pubKeyPacket = new PublicSubkeyPacket(in); + pubKeyPacket = new PublicSubkeyPacket(in, newPacketFormat); } else { - pubKeyPacket = new PublicKeyPacket(in); + pubKeyPacket = new PublicKeyPacket(in, newPacketFormat); } int version = pubKeyPacket.getVersion(); @@ -178,7 +180,7 @@ public class SecretKeyPacket } if (version == PublicKeyPacket.VERSION_6 && (s2kUsage == USAGE_SHA1 || s2kUsage == USAGE_AEAD)) { - int s2KLen = in.read(); + int s2KLen = sanitizeLength(in.read(), MAX_S2K_ENCODING_LEN, "S2K length octet"); byte[] s2kBytes = new byte[s2KLen]; in.readFully(s2kBytes); @@ -194,8 +196,15 @@ public class SecretKeyPacket } if (s2kUsage == USAGE_AEAD) { - iv = new byte[AEADUtils.getIVLength(aeadAlgorithm)]; - Streams.readFully(in, iv); + try + { + iv = new byte[AEADUtils.getIVLength(aeadAlgorithm)]; + } + catch (IllegalArgumentException e) + { + throw new MalformedPacketException("Unknown AEAD algorithm", e); + } + in.readFully(iv); } else { @@ -227,7 +236,8 @@ public class SecretKeyPacket // encoded keyOctetCount does not contain checksum keyOctetCount += 2; } - this.secKeyData = new byte[(int) keyOctetCount]; + int sanitizedOctetCount = sanitizeLength((int) keyOctetCount, PublicKeyPacket.MAX_LEN, "Key octet count"); + this.secKeyData = new byte[sanitizedOctetCount]; in.readFully(secKeyData); } else @@ -342,7 +352,7 @@ public SecretKeyPacket( byte[] iv, byte[] secKeyData) { - super(keyTag); + super(keyTag, pubKeyPacket.hasNewPacketFormat()); this.pubKeyPacket = pubKeyPacket; this.encAlgorithm = encAlgorithm; diff --git a/pg/src/main/java/org/bouncycastle/bcpg/SignaturePacket.java b/pg/src/main/java/org/bouncycastle/bcpg/SignaturePacket.java index de2d3b5ac2..c8742de969 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/SignaturePacket.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/SignaturePacket.java @@ -8,6 +8,7 @@ import org.bouncycastle.bcpg.sig.IssuerFingerprint; import org.bouncycastle.bcpg.sig.IssuerKeyID; import org.bouncycastle.bcpg.sig.SignatureCreationTime; +import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Pack; import org.bouncycastle.util.io.Streams; @@ -18,6 +19,8 @@ public class SignaturePacket extends ContainedPacket implements PublicKeyAlgorithmTags { + public static final int MAX_SUBPACKET_LEN = 2 * 1024 * 1024; // 2mb, allows for embedded McEliece keys for example. + public static final int VERSION_2 = 2; public static final int VERSION_3 = 3; public static final int VERSION_4 = 4; // https://datatracker.ietf.org/doc/rfc4880/ @@ -149,6 +152,10 @@ private void parseV6(BCPGInputStream in) in.readFully(fingerPrint); int saltSize = in.read(); + if (saltSize < 0) + { + throw new MalformedPacketException("Negative salt size."); + } salt = new byte[saltSize]; in.readFully(salt); @@ -174,11 +181,11 @@ private void parseSubpackets(BCPGInputStream in) SignatureSubpacket p = (SignatureSubpacket)vec.elementAt(i); if (p instanceof IssuerKeyID) { - keyID = ((IssuerKeyID)p).getKeyID(); + keyID = parseKeyIdOrThrow((IssuerKeyID)p); } else if (p instanceof SignatureCreationTime) { - creationTime = ((SignatureCreationTime)p).getTime().getTime(); + creationTime = parseCreationTimeOrThrow((SignatureCreationTime)p); } hashedData[i] = p; @@ -192,7 +199,7 @@ else if (p instanceof SignatureCreationTime) SignatureSubpacket p = (SignatureSubpacket)vec.elementAt(i); if (p instanceof IssuerKeyID) { - keyID = ((IssuerKeyID)p).getKeyID(); + keyID = parseKeyIdOrThrow((IssuerKeyID)p); } unhashedData[i] = p; @@ -202,6 +209,45 @@ else if (p instanceof SignatureCreationTime) setCreationTime(); } + private long parseKeyIdOrThrow(IssuerKeyID keyID) + throws MalformedPacketException + { + try + { + return keyID.getKeyID(); + } + catch (IllegalArgumentException e) + { + throw new MalformedPacketException("Malformed IssuerKeyID subpacket.", e); + } + } + + private long parseKeyIdOrThrow(IssuerFingerprint fingerprint) + throws MalformedPacketException + { + try + { + return fingerprint.getKeyID(); + } + catch (IllegalArgumentException e) + { + throw new MalformedPacketException("Malformed IssuerFingerprint subpacket.", e); + } + } + + private long parseCreationTimeOrThrow(SignatureCreationTime creationTime) + throws MalformedPacketException + { + try + { + return creationTime.getTime().getTime(); + } + catch (RuntimeException e) + { + throw new MalformedPacketException("Malformed SignatureCreationTime subpacket.", e); + } + } + private Vector readSignatureSubpacketVector(BCPGInputStream in) throws IOException { @@ -214,6 +260,14 @@ private Vector readSignatureSubpacketVector(BCPGInputStream { hashedLength = StreamUtil.read2OctetLength(in); } + if (hashedLength < 0) + { + throw new MalformedPacketException("Signature subpackets encoding length cannot be negative."); + } + if (hashedLength > MAX_SUBPACKET_LEN) + { + throw new MalformedPacketException("Signature subpackets encoding length (" + hashedLength + ") exceeds max limit (" + MAX_SUBPACKET_LEN + ")"); + } byte[] hashed = new byte[hashedLength]; in.readFully(hashed); @@ -353,7 +407,22 @@ public SignaturePacket( byte[] fingerPrint, MPInteger[] signature) { - super(SIGNATURE); + this(version, false, signatureType, keyID, keyAlgorithm, hashAlgorithm, hashedData, unhashedData, fingerPrint, signature); + } + + public SignaturePacket( + int version, + boolean hasNewPacketFormat, + int signatureType, + long keyID, + int keyAlgorithm, + int hashAlgorithm, + SignatureSubpacket[] hashedData, + SignatureSubpacket[] unhashedData, + byte[] fingerPrint, + MPInteger[] signature) + { + super(SIGNATURE, hasNewPacketFormat); this.version = version; this.signatureType = signatureType; @@ -383,7 +452,7 @@ public SignaturePacket( byte[] signatureEncoding, byte[] salt) { - super(SIGNATURE); + super(SIGNATURE, true); this.version = version; this.signatureType = signatureType; @@ -413,7 +482,7 @@ public SignaturePacket( MPInteger[] signature, byte[] salt) { - super(SIGNATURE); + super(SIGNATURE, true); this.version = version; this.signatureType = signatureType; @@ -431,6 +500,40 @@ public SignaturePacket( } } + public static SignaturePacket copyOfWith(SignaturePacket packet, SignatureSubpacket[] unhashedSubpackets) + { + if (packet.getVersion() == SignaturePacket.VERSION_6) + { + return new SignaturePacket( + packet.getVersion(), + packet.getSignatureType(), + packet.getKeyID(), + packet.getKeyAlgorithm(), + packet.getHashAlgorithm(), + packet.getHashedSubPackets(), + unhashedSubpackets, + packet.getFingerPrint(), + packet.getSignatureBytes(), + packet.getSalt() + ); + } + else + { + return new SignaturePacket( + packet.getVersion(), + packet.hasNewPacketFormat(), + packet.getSignatureType(), + packet.getKeyID(), + packet.getKeyAlgorithm(), + packet.getHashAlgorithm(), + packet.getHashedSubPackets(), + unhashedSubpackets, + packet.getFingerPrint(), + packet.getSignature() + ); + } + } + /** * get the version number */ @@ -728,6 +831,7 @@ private void setCreationTime() * Therefore, we can also check the unhashed signature subpacket area. */ private void setIssuerKeyId() + throws MalformedPacketException { if (keyID != 0L) { @@ -739,12 +843,12 @@ private void setIssuerKeyId() SignatureSubpacket p = hashedData[idx]; if (p instanceof IssuerKeyID) { - keyID = ((IssuerKeyID) p).getKeyID(); + keyID = parseKeyIdOrThrow((IssuerKeyID)p); return; } if (p instanceof IssuerFingerprint) { - keyID = ((IssuerFingerprint) p).getKeyID(); + keyID = parseKeyIdOrThrow((IssuerFingerprint)p); return; } } @@ -754,12 +858,12 @@ private void setIssuerKeyId() SignatureSubpacket p = unhashedData[idx]; if (p instanceof IssuerKeyID) { - keyID = ((IssuerKeyID) p).getKeyID(); + keyID = parseKeyIdOrThrow((IssuerKeyID)p); return; } if (p instanceof IssuerFingerprint) { - keyID = ((IssuerFingerprint) p).getKeyID(); + keyID = parseKeyIdOrThrow((IssuerFingerprint)p); return; } } diff --git a/pg/src/main/java/org/bouncycastle/bcpg/SignatureSubpacketInputStream.java b/pg/src/main/java/org/bouncycastle/bcpg/SignatureSubpacketInputStream.java index b66ba0813c..b264c302ae 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/SignatureSubpacketInputStream.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/SignatureSubpacketInputStream.java @@ -128,58 +128,65 @@ else if (flags[StreamUtil.flag_partial]) } } - switch (type) + try { - case CREATION_TIME: - return new SignatureCreationTime(isCritical, isLongLength, data); - case EMBEDDED_SIGNATURE: - return new EmbeddedSignature(isCritical, isLongLength, data); - case KEY_EXPIRE_TIME: - return new KeyExpirationTime(isCritical, isLongLength, data); - case EXPIRE_TIME: - return new SignatureExpirationTime(isCritical, isLongLength, data); - case REVOCABLE: - return new Revocable(isCritical, isLongLength, data); - case EXPORTABLE: - return new Exportable(isCritical, isLongLength, data); - case FEATURES: - return new Features(isCritical, isLongLength, data); - case ISSUER_KEY_ID: - return new IssuerKeyID(isCritical, isLongLength, data); - case TRUST_SIG: - return new TrustSignature(isCritical, isLongLength, data); - case PREFERRED_COMP_ALGS: - case PREFERRED_HASH_ALGS: - case PREFERRED_SYM_ALGS: - return new PreferredAlgorithms(type, isCritical, isLongLength, data); - case LIBREPGP_PREFERRED_ENCRYPTION_MODES: - return new LibrePGPPreferredEncryptionModes(isCritical, isLongLength, data); - case PREFERRED_AEAD_ALGORITHMS: - return new PreferredAEADCiphersuites(isCritical, isLongLength, data); - case PREFERRED_KEY_SERV: - return new PreferredKeyServer(isCritical, isLongLength, data); - case KEY_FLAGS: - return new KeyFlags(isCritical, isLongLength, data); - case POLICY_URL: - return new PolicyURI(isCritical, isLongLength, data); - case PRIMARY_USER_ID: - return new PrimaryUserID(isCritical, isLongLength, data); - case SIGNER_USER_ID: - return new SignerUserID(isCritical, isLongLength, data); - case NOTATION_DATA: - return new NotationData(isCritical, isLongLength, data); - case REG_EXP: - return new RegularExpression(isCritical, isLongLength, data); - case REVOCATION_REASON: - return new RevocationReason(isCritical, isLongLength, data); - case REVOCATION_KEY: - return new RevocationKey(isCritical, isLongLength, data); - case SIGNATURE_TARGET: - return new SignatureTarget(isCritical, isLongLength, data); - case ISSUER_FINGERPRINT: - return new IssuerFingerprint(isCritical, isLongLength, data); - case INTENDED_RECIPIENT_FINGERPRINT: - return new IntendedRecipientFingerprint(isCritical, isLongLength, data); + switch (type) + { + case CREATION_TIME: + return new SignatureCreationTime(isCritical, isLongLength, data); + case EMBEDDED_SIGNATURE: + return new EmbeddedSignature(isCritical, isLongLength, data); + case KEY_EXPIRE_TIME: + return new KeyExpirationTime(isCritical, isLongLength, data); + case EXPIRE_TIME: + return new SignatureExpirationTime(isCritical, isLongLength, data); + case REVOCABLE: + return new Revocable(isCritical, isLongLength, data); + case EXPORTABLE: + return new Exportable(isCritical, isLongLength, data); + case FEATURES: + return new Features(isCritical, isLongLength, data); + case ISSUER_KEY_ID: + return new IssuerKeyID(isCritical, isLongLength, data); + case TRUST_SIG: + return new TrustSignature(isCritical, isLongLength, data); + case PREFERRED_COMP_ALGS: + case PREFERRED_HASH_ALGS: + case PREFERRED_SYM_ALGS: + return new PreferredAlgorithms(type, isCritical, isLongLength, data); + case LIBREPGP_PREFERRED_ENCRYPTION_MODES: + return new LibrePGPPreferredEncryptionModes(isCritical, isLongLength, data); + case PREFERRED_AEAD_ALGORITHMS: + return new PreferredAEADCiphersuites(isCritical, isLongLength, data); + case PREFERRED_KEY_SERV: + return new PreferredKeyServer(isCritical, isLongLength, data); + case KEY_FLAGS: + return new KeyFlags(isCritical, isLongLength, data); + case POLICY_URL: + return new PolicyURI(isCritical, isLongLength, data); + case PRIMARY_USER_ID: + return new PrimaryUserID(isCritical, isLongLength, data); + case SIGNER_USER_ID: + return new SignerUserID(isCritical, isLongLength, data); + case NOTATION_DATA: + return new NotationData(isCritical, isLongLength, data); + case REG_EXP: + return new RegularExpression(isCritical, isLongLength, data); + case REVOCATION_REASON: + return new RevocationReason(isCritical, isLongLength, data); + case REVOCATION_KEY: + return new RevocationKey(isCritical, isLongLength, data); + case SIGNATURE_TARGET: + return new SignatureTarget(isCritical, isLongLength, data); + case ISSUER_FINGERPRINT: + return new IssuerFingerprint(isCritical, isLongLength, data); + case INTENDED_RECIPIENT_FINGERPRINT: + return new IntendedRecipientFingerprint(isCritical, isLongLength, data); + } + } + catch (IllegalArgumentException e) + { + throw new MalformedPacketException("Malformed signature subpacket.", e); } return new SignatureSubpacket(type, isCritical, isLongLength, data); diff --git a/pg/src/main/java/org/bouncycastle/bcpg/SymmetricKeyEncSessionPacket.java b/pg/src/main/java/org/bouncycastle/bcpg/SymmetricKeyEncSessionPacket.java index aef46b6f2a..ad6f8b0e3f 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/SymmetricKeyEncSessionPacket.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/SymmetricKeyEncSessionPacket.java @@ -81,7 +81,19 @@ else if (version == VERSION_5 || version == VERSION_6) } else { - ivLen = AEADUtils.getIVLength(aeadAlgorithm); + try + { + ivLen = AEADUtils.getIVLength(aeadAlgorithm); + } + catch (IllegalArgumentException e) + { + throw new MalformedPacketException(e.getMessage(), e); + } + } + + if (ivLen < 0) + { + throw new MalformedPacketException("IV length cannot be negative."); } s2k = new S2K(in); @@ -92,11 +104,23 @@ else if (version == VERSION_5 || version == VERSION_6) throw new EOFException("Premature end of stream."); } - int authTagLen = AEADUtils.getAuthTagLength(aeadAlgorithm); + int authTagLen; + try + { + authTagLen = AEADUtils.getAuthTagLength(aeadAlgorithm); + } + catch (IllegalArgumentException e) + { + throw new MalformedPacketException("Unknown AEAD algorithm.", e); + } authTag = new byte[authTagLen]; // Read all trailing bytes byte[] sessKeyAndAuthTag = in.readAll(); + if (sessKeyAndAuthTag.length - authTagLen < 0) + { + throw new MalformedPacketException("AuthTagLen exceeds session key data."); + } // determine session key length by subtracting auth tag this.secKeyData = new byte[sessKeyAndAuthTag.length - authTagLen]; diff --git a/pg/src/main/java/org/bouncycastle/bcpg/UserAttributeSubpacketInputStream.java b/pg/src/main/java/org/bouncycastle/bcpg/UserAttributeSubpacketInputStream.java index dfc33988f6..e791abf2d7 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/UserAttributeSubpacketInputStream.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/UserAttributeSubpacketInputStream.java @@ -14,11 +14,20 @@ public class UserAttributeSubpacketInputStream implements UserAttributeSubpacketTags { InputStream in; - + private final int limit; + public UserAttributeSubpacketInputStream( InputStream in) + { + this(in, StreamUtil.findLimit(in)); + } + + public UserAttributeSubpacketInputStream( + InputStream in, + int limit) { this.in = in; + this.limit = limit; } public int available() @@ -78,7 +87,15 @@ public UserAttributeSubpacket readPacket() } else if (flags[StreamUtil.flag_partial]) { - throw new IOException("unrecognised length reading user attribute sub packet"); + throw new MalformedPacketException("unrecognised length reading user attribute sub packet"); + } + if (bodyLen < 1) + { + throw new MalformedPacketException("Body length octet too small."); + } + if (bodyLen > limit) + { + throw new MalformedPacketException("Body length octet (" + bodyLen + ") exceeds limitations (" + limit + ")."); } boolean longLength = flags[StreamUtil.flag_isLongLength]; @@ -95,10 +112,17 @@ else if (flags[StreamUtil.flag_partial]) int type = tag; - switch (type) + try + { + switch (type) + { + case IMAGE_ATTRIBUTE: + return new ImageAttribute(longLength, data); + } + } + catch (IllegalArgumentException e) { - case IMAGE_ATTRIBUTE: - return new ImageAttribute(longLength, data); + throw new MalformedPacketException("Malformed UserAttribute subpacket.", e); } return new UserAttributeSubpacket(type, longLength, data); diff --git a/pg/src/main/java/org/bouncycastle/bcpg/attr/ImageAttribute.java b/pg/src/main/java/org/bouncycastle/bcpg/attr/ImageAttribute.java index 437d33ba42..9c8e8c6419 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/attr/ImageAttribute.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/attr/ImageAttribute.java @@ -37,8 +37,16 @@ public ImageAttribute( byte[] data) { super(UserAttributeSubpacketTags.IMAGE_ATTRIBUTE, forceLongLength, data); + if (data.length < 4) + { + throw new IllegalArgumentException("Malformed ImageAttribute. Data length too short: " + data.length); + } hdrLength = ((data[1] & 0xff) << 8) | (data[0] & 0xff); + if (data.length < hdrLength) + { + throw new IllegalArgumentException("Malformed ImageAttribute. Header length exceeds data length."); + } version = data[2] & 0xff; encoding = data[3] & 0xff; diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/IntendedRecipientFingerprint.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/IntendedRecipientFingerprint.java index dfc3d2c34d..ff28c1320f 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/sig/IntendedRecipientFingerprint.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/IntendedRecipientFingerprint.java @@ -20,7 +20,7 @@ public IntendedRecipientFingerprint( boolean isLongLength, byte[] data) { - super(SignatureSubpacketTags.INTENDED_RECIPIENT_FINGERPRINT, critical, isLongLength, data); + super(SignatureSubpacketTags.INTENDED_RECIPIENT_FINGERPRINT, critical, isLongLength, verifyData(data)); } public IntendedRecipientFingerprint( @@ -32,6 +32,15 @@ public IntendedRecipientFingerprint( Arrays.prepend(fingerprint, (byte)keyVersion)); } + private static byte[] verifyData(byte[] data) + { + if (data.length < 1) + { + throw new IllegalArgumentException("Data too short. Expect at least one octet of key version number."); + } + return data; + } + public int getKeyVersion() { return data[0] & 0xff; @@ -46,4 +55,5 @@ public KeyIdentifier getKeyIdentifier() { return new KeyIdentifier(getFingerprint()); } + } diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/IssuerFingerprint.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/IssuerFingerprint.java index 7837c93a77..e79218bc0e 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/sig/IssuerFingerprint.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/IssuerFingerprint.java @@ -22,7 +22,7 @@ public IssuerFingerprint( boolean isLongLength, byte[] data) { - super(SignatureSubpacketTags.ISSUER_FINGERPRINT, critical, isLongLength, data); + super(SignatureSubpacketTags.ISSUER_FINGERPRINT, critical, isLongLength, verifyData(data)); } public IssuerFingerprint( @@ -34,6 +34,15 @@ public IssuerFingerprint( Arrays.prepend(fingerprint, (byte)keyVersion)); } + private static byte[] verifyData(byte[] data) + { + if (data.length < 1) + { + throw new IllegalArgumentException("Data too short. Expect at least one octet of key version."); + } + return data; + } + public int getKeyVersion() { return data[0] & 0xff; diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/KeyFlags.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/KeyFlags.java index a92b975f6d..60c5b979df 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/sig/KeyFlags.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/KeyFlags.java @@ -2,6 +2,7 @@ import org.bouncycastle.bcpg.SignatureSubpacket; import org.bouncycastle.bcpg.SignatureSubpacketTags; +import org.bouncycastle.util.Integers; /** * Signature Subpacket encoding the capabilities / intended uses of a key. @@ -49,29 +50,30 @@ public class KeyFlags * The private component of this key may be in the possession of more than one person. */ public static final int SHARED = 0x80; - - private static byte[] intToByteArray( - int v) - { - byte[] tmp = new byte[4]; - int size = 0; - for (int i = 0; i != 4; i++) + private static int dataToFlags(byte[] data) + { + int flags = 0, bytes = Math.min(4, data.length); + for (int i = 0; i < bytes; ++i) { - tmp[i] = (byte)(v >> (i * 8)); - if (tmp[i] != 0) - { - size = i; - } + flags |= (data[i] & 0xFF) << (i * 8); } + return flags; + } - byte[] data = new byte[size + 1]; - - System.arraycopy(tmp, 0, data, 0, data.length); + private static byte[] flagsToData(int flags) + { + int bits = 32 - Integers.numberOfLeadingZeros(flags); + int bytes = (bits + 7) / 8; + byte[] data = new byte[bytes]; + for (int i = 0; i < bytes; ++i) + { + data[i] = (byte)(flags >> (i * 8)); + } return data; } - + public KeyFlags( boolean critical, boolean isLongLength, @@ -84,7 +86,7 @@ public KeyFlags( boolean critical, int flags) { - super(SignatureSubpacketTags.KEY_FLAGS, critical, false, intToByteArray(flags)); + super(SignatureSubpacketTags.KEY_FLAGS, critical, false, flagsToData(flags)); } /** @@ -95,13 +97,6 @@ public KeyFlags( */ public int getFlags() { - int flags = 0; - - for (int i = 0; i != data.length; i++) - { - flags |= (data[i] & 0xff) << (i * 8); - } - - return flags; + return dataToFlags(data); } } diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/NotationData.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/NotationData.java index b1c4e970d7..55b2291587 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/sig/NotationData.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/NotationData.java @@ -27,7 +27,7 @@ public NotationData( boolean isLongLength, byte[] data) { - super(SignatureSubpacketTags.NOTATION_DATA, critical, isLongLength, data); + super(SignatureSubpacketTags.NOTATION_DATA, critical, isLongLength, verifyData(data)); } public NotationData( @@ -39,6 +39,21 @@ public NotationData( super(SignatureSubpacketTags.NOTATION_DATA, critical, false, createData(humanReadable, notationName, notationValue)); } + private static byte[] verifyData(byte[] data) + { + if (data.length < 8) + { + throw new IllegalArgumentException("Malformed notation data encoding (too short): " + data.length); + } + int nameLength = (((data[HEADER_FLAG_LENGTH] & 0xff) << 8) + (data[HEADER_FLAG_LENGTH + 1] & 0xff)); + int valueLength = (((data[HEADER_FLAG_LENGTH + HEADER_NAME_LENGTH] & 0xff) << 8) + (data[HEADER_FLAG_LENGTH + HEADER_NAME_LENGTH + 1] & 0xff)); + if (nameLength + valueLength + 4 > data.length) + { + throw new IllegalArgumentException("Malformed notation data encoding."); + } + return data; + } + private static byte[] createData(boolean humanReadable, String notationName, String notationValue) { ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -91,7 +106,7 @@ private static byte[] createData(boolean humanReadable, String notationName, Str public boolean isHumanReadable() { - return data[0] == (byte)0x80; + return (data[0] & 0x80) != 0; } public String getNotationName() diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/PreferredAEADCiphersuites.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/PreferredAEADCiphersuites.java index f58b25bb76..d99a01e9fa 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/sig/PreferredAEADCiphersuites.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/PreferredAEADCiphersuites.java @@ -30,6 +30,11 @@ public class PreferredAEADCiphersuites */ private static final Combination AES_128_OCB = new Combination(SymmetricKeyAlgorithmTags.AES_128, AEADAlgorithmTags.OCB); + public static PreferredAEADCiphersuites DEFAULT() + { + return new PreferredAEADCiphersuites(false, new Combination[]{AES_128_OCB}); + } + /** * Create a new PreferredAEADAlgorithms signature subpacket from raw data. * diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/RegularExpression.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/RegularExpression.java index c780011a8a..2cafb9fbd4 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/sig/RegularExpression.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/RegularExpression.java @@ -23,7 +23,7 @@ public RegularExpression( byte[] data) { super(SignatureSubpacketTags.REG_EXP, critical, isLongLength, data); - if (data[data.length - 1] != 0) + if (data.length == 0 || data[data.length - 1] != 0) { throw new IllegalArgumentException("data in regex missing null termination"); } diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/RevocationKey.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/RevocationKey.java index 4c0960fc64..8779f0585c 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/sig/RevocationKey.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/RevocationKey.java @@ -3,6 +3,7 @@ import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.bcpg.SignatureSubpacket; import org.bouncycastle.bcpg.SignatureSubpacketTags; +import org.bouncycastle.util.Arrays; /** * Represents revocation key OpenPGP signature sub packet. @@ -52,9 +53,7 @@ public int getAlgorithm() public byte[] getFingerprint() { - byte[] fingerprint = new byte[data.length - 2]; - System.arraycopy(data, 2, fingerprint, 0, fingerprint.length); - return fingerprint; + return Arrays.copyOfRange(data, 2, data.length); } public KeyIdentifier getKeyIdentifier() diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/RevocationReason.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/RevocationReason.java index 91634e79e1..186c56d571 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/sig/RevocationReason.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/RevocationReason.java @@ -2,6 +2,7 @@ import org.bouncycastle.bcpg.SignatureSubpacket; import org.bouncycastle.bcpg.SignatureSubpacketTags; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; /** @@ -26,31 +27,21 @@ public RevocationReason(boolean isCritical, byte reason, String description) private static byte[] createData(byte reason, String description) { - byte[] descriptionBytes = Strings.toUTF8ByteArray(description); - byte[] data = new byte[1 + descriptionBytes.length]; - - data[0] = reason; - System.arraycopy(descriptionBytes, 0, data, 1, descriptionBytes.length); - - return data; + return Arrays.prepend(Strings.toUTF8ByteArray(description), reason); } public byte getRevocationReason() { - return getData()[0]; + return data[0]; } public String getRevocationDescription() { - byte[] data = getData(); if (data.length == 1) { return ""; } - byte[] description = new byte[data.length - 1]; - System.arraycopy(data, 1, description, 0, description.length); - - return Strings.fromUTF8ByteArray(description); + return Strings.fromUTF8ByteArray(data, 1, data.length - 1); } } diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureExpirationTime.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureExpirationTime.java index d89d86c10e..7f7103fe8d 100644 --- a/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureExpirationTime.java +++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureExpirationTime.java @@ -29,7 +29,7 @@ public SignatureExpirationTime( boolean isLongLength, byte[] data) { - super(SignatureSubpacketTags.EXPIRE_TIME, critical, isLongLength, data); + super(SignatureSubpacketTags.EXPIRE_TIME, critical, isLongLength, verifyData(data)); } public SignatureExpirationTime( @@ -39,6 +39,15 @@ public SignatureExpirationTime( super(SignatureSubpacketTags.EXPIRE_TIME, critical, false, Utils.timeToBytes(seconds)); } + private static byte[] verifyData(byte[] data) + { + if (data.length != 4) + { + throw new IllegalArgumentException("Malformed data length. Expected 4, got " + data.length); + } + return data; + } + /** * return time in seconds before signature expires after creation time. */ diff --git a/pg/src/main/java/org/bouncycastle/openpgp/IntegrityProtectedInputStream.java b/pg/src/main/java/org/bouncycastle/openpgp/IntegrityProtectedInputStream.java new file mode 100644 index 0000000000..8d8efe5576 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/IntegrityProtectedInputStream.java @@ -0,0 +1,85 @@ +package org.bouncycastle.openpgp; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket; +import org.bouncycastle.util.Exceptions; + +/** + * {@link InputStream} that performs verification of integrity protection upon {@link #close()}. + */ +public class IntegrityProtectedInputStream + extends FilterInputStream +{ + + private final PGPEncryptedData esk; + + public IntegrityProtectedInputStream(InputStream in, PGPEncryptedData dataPacket) + { + super(in); + this.esk = dataPacket; + } + + @Override + public int read() + throws IOException + { + int i = in.read(); + if (i == -1) + { + close(); + } + return i; + } + + @Override + public int read(byte[] b) + throws IOException + { + int r = in.read(b); + if (r == -1) + { + close(); + } + return r; + } + + @Override + public int read(byte[] b, int off, int len) + throws IOException + { + int r = in.read(b, off, len); + if (r == -1) + { + close(); + } + return r; + } + + @Override + public void close() + throws IOException + { + super.close(); + if (esk.getEncData() instanceof SymmetricEncIntegrityPacket) + { + SymmetricEncIntegrityPacket seipd = (SymmetricEncIntegrityPacket) esk.getEncData(); + if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_1) + { + try + { + if (!esk.verify()) + { + throw new PGPException("Malformed integrity protected data."); + } + } + catch (PGPException e) + { + throw Exceptions.ioException(e.getMessage(), e); + } + } + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedData.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedData.java index fba7395286..201ba7e6b9 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedData.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedData.java @@ -7,7 +7,6 @@ import org.bouncycastle.bcpg.AEADAlgorithmTags; import org.bouncycastle.bcpg.AEADEncDataPacket; -import org.bouncycastle.bcpg.BCPGInputStream; import org.bouncycastle.bcpg.InputStreamPacket; import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket; import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; @@ -175,6 +174,11 @@ public boolean isIntegrityProtected() return (encData instanceof SymmetricEncIntegrityPacket); } + public InputStreamPacket getEncData() + { + return encData; + } + /** * Checks whether the packet is protected using an AEAD algorithm. * @@ -271,10 +275,11 @@ public int getAlgorithm() throw new UnsupportedOperationException("not supported - override required"); } - boolean processSymmetricEncIntegrityPacketDataStream(boolean withIntegrityPacket, PGPDataDecryptor dataDecryptor, BCPGInputStream encIn) + boolean processSymmetricEncIntegrityPacketDataStream(boolean withIntegrityPacket, PGPDataDecryptor dataDecryptor, + InputStream encIn) throws IOException { - encStream = new BCPGInputStream(dataDecryptor.getInputStream(encIn)); + encStream = dataDecryptor.getInputStream(encIn); if (withIntegrityPacket) { diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataGenerator.java index a0e3d295ca..7f9a34950c 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataGenerator.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataGenerator.java @@ -88,6 +88,7 @@ public class PGPEncryptedDataGenerator // If true, force generation of a session key, even if we only have a single password-based encryption method // and could therefore use the S2K output as session key directly. private boolean forceSessionKey = true; + private SessionKeyExtractionCallback sessionKeyExtractionCallback = null; /** * Base constructor. @@ -140,6 +141,10 @@ public void addMethod(PGPKeyEncryptionMethodGenerator method) methods.add(method); } + public void setSessionKeyExtractionCallback(SessionKeyExtractionCallback callback) + { + this.sessionKeyExtractionCallback = callback; + } /** * Create an OutputStream based on the configured methods. @@ -213,13 +218,25 @@ else if (directS2K) messageKey = sessionKey; } + if (sessionKeyExtractionCallback != null) + { + sessionKeyExtractionCallback.extractSessionKey(new PGPSessionKey(defAlgorithm, sessionKey)); + } + PGPDataEncryptor dataEncryptor = dataEncryptorBuilder.build(messageKey); digestCalc = dataEncryptor.getIntegrityCalculator(); BCPGHeaderObject encOut; for (int i = 0; i < methods.size(); i++) { PGPKeyEncryptionMethodGenerator method = (PGPKeyEncryptionMethodGenerator)methods.get(i); - pOut.writePacket(method.generate(dataEncryptorBuilder, sessionKey)); + if (directS2K) + { + pOut.writePacket(method.generate(dataEncryptorBuilder, null)); + } + else + { + pOut.writePacket(method.generate(dataEncryptorBuilder, sessionKey)); + } } try { @@ -394,6 +411,8 @@ public void close() // BCPGOutputStream bOut = new BCPGOutputStream(genOut, PacketTags.MOD_DETECTION_CODE, 20); + // For clarity; really only required if using partial body lengths + bOut.finish(); bOut.flush(); byte[] dig = digestCalc.getDigest(); @@ -441,4 +460,9 @@ public void close() this.finish(); } } + + public interface SessionKeyExtractionCallback + { + void extractSessionKey(PGPSessionKey sessionKey); + } } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataList.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataList.java index 2f55f519e7..7c2cf62c20 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataList.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedDataList.java @@ -154,6 +154,11 @@ public PGPEncryptedData get( return (PGPEncryptedData)methods.get(index); } + public InputStreamPacket getEncryptedData() + { + return data; + } + /** * Gets the number of encryption methods in this list. */ diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPKeyRing.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPKeyRing.java index c9a7630d1d..8507988deb 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPKeyRing.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPKeyRing.java @@ -93,6 +93,16 @@ static void readUserIDs( } } + /** + * Return the {@link KeyIdentifier} of this key rings primary key. + * + * @return primary key identifier + */ + public KeyIdentifier getKeyIdentifier() + { + return getPublicKey().getKeyIdentifier(); + } + /** * Return the first public key in the ring. In the case of a {@link PGPSecretKeyRing} * this is also the public key of the master key pair. diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPObjectFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPObjectFactory.java index 852fc2d0f1..cceae70506 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPObjectFactory.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPObjectFactory.java @@ -38,7 +38,7 @@ * */ public class PGPObjectFactory - implements Iterable + implements Iterable { private BCPGInputStream in; private KeyFingerPrintCalculator fingerPrintCalculator; @@ -141,6 +141,8 @@ public Object nextObject() return new PGPCompressedData(in); case PacketTags.LITERAL_DATA: return new PGPLiteralData(in); + case PacketTags.TRUST: + return new PGPTrust(in); case PacketTags.PUBLIC_KEY_ENC_SESSION: case PacketTags.SYMMETRIC_KEY_ENC_SESSION: case PacketTags.SYMMETRIC_KEY_ENC: @@ -167,6 +169,12 @@ public Object nextObject() return new PGPMarker(in); case PacketTags.PADDING: return new PGPPadding(in); + case PacketTags.MOD_DETECTION_CODE: + return new UnknownPacket(PacketTags.MOD_DETECTION_CODE, in); + case PacketTags.USER_ID: + return new UnknownPacket(PacketTags.USER_ID, in); + case PacketTags.USER_ATTRIBUTE: + return new UnknownPacket(PacketTags.USER_ATTRIBUTE, in); } int tag = in.nextPacketTag(); diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKey.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKey.java index 4f69293bcb..2e02fc05aa 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKey.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKey.java @@ -487,7 +487,14 @@ public Iterator getUserIDs() { if (ids.get(i) instanceof UserIDPacket) { - temp.add(((UserIDPacket)ids.get(i)).getID()); + try + { + temp.add(((UserIDPacket) ids.get(i)).getID()); + } + catch (IllegalArgumentException e) + { + // Skip non-UTF8 user-ids + } } } @@ -1157,7 +1164,7 @@ public static PGPPublicKey join( } // key signatures - joinPgpSignatureList(copy.keySigs, keySigs, true, true); + joinPgpSignatureList(copy.keySigs, keySigs, false, true); // user-ids and id sigs for (int idIdx = 0; idIdx < copy.ids.size(); idIdx++) diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java index 5f375c7b84..6fb8276cbe 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java @@ -3,7 +3,6 @@ import java.io.InputStream; import org.bouncycastle.bcpg.AEADEncDataPacket; -import org.bouncycastle.bcpg.BCPGInputStream; import org.bouncycastle.bcpg.InputStreamPacket; import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; @@ -201,93 +200,85 @@ private InputStream getDataStream( PGPSessionKey sessionKey) throws PGPException { - if (sessionKey.getAlgorithm() != SymmetricKeyAlgorithmTags.NULL) + if (sessionKey.getAlgorithm() == SymmetricKeyAlgorithmTags.NULL) { - try - { - // OpenPGP V5 style AEAD - if (encData instanceof AEADEncDataPacket) - { - AEADEncDataPacket aeadData = (AEADEncDataPacket)encData; - - if (aeadData.getAlgorithm() != sessionKey.getAlgorithm()) - { - throw new PGPException("session key and AEAD algorithm mismatch"); - } + return getInputStream(); + } - PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(aeadData, sessionKey); + try + { + InputStream encIn = getInputStream(); - BCPGInputStream encIn = encData.getInputStream(); + // OpenPGP V5 style AEAD + if (encData instanceof AEADEncDataPacket) + { + AEADEncDataPacket aeadData = (AEADEncDataPacket)encData; - encStream = new BCPGInputStream(dataDecryptor.getInputStream(encIn)); - } - else + if (aeadData.getAlgorithm() != sessionKey.getAlgorithm()) { + throw new PGPException("session key and AEAD algorithm mismatch"); + } - if (encData instanceof SymmetricEncIntegrityPacket) - { - SymmetricEncIntegrityPacket seipd = (SymmetricEncIntegrityPacket) encData; - // SEIPD v1 (OpenPGP v4) - if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_1) - { - PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(true, sessionKey.getAlgorithm(), sessionKey.getKey()); - - BCPGInputStream encIn = encData.getInputStream(); + PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(aeadData, sessionKey); - processSymmetricEncIntegrityPacketDataStream(true, dataDecryptor, encIn); - } - // SEIPD v2 (OpenPGP v6 AEAD) - else - { - PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(seipd, sessionKey); + encStream = dataDecryptor.getInputStream(encIn); + } + else + { - BCPGInputStream encIn = encData.getInputStream(); + if (encData instanceof SymmetricEncIntegrityPacket) + { + SymmetricEncIntegrityPacket seipd = (SymmetricEncIntegrityPacket) encData; + // SEIPD v1 (OpenPGP v4) + if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_1) + { + PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(true, sessionKey.getAlgorithm(), sessionKey.getKey()); - encStream = new BCPGInputStream(dataDecryptor.getInputStream(encIn)); - } + processSymmetricEncIntegrityPacketDataStream(true, dataDecryptor, encIn); } - // SED (Symmetrically Encrypted Data without Integrity Protection; Deprecated) + // SEIPD v2 (OpenPGP v6 AEAD) else { - PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(false, sessionKey.getAlgorithm(), sessionKey.getKey()); - - BCPGInputStream encIn = encData.getInputStream(); + PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(seipd, sessionKey); - processSymmetricEncIntegrityPacketDataStream(false, dataDecryptor, encIn); + encStream = dataDecryptor.getInputStream(encIn); } + } + // SED (Symmetrically Encrypted Data without Integrity Protection; Deprecated) + else + { + PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(false, sessionKey.getAlgorithm(), sessionKey.getKey()); - // - // some versions of PGP appear to produce 0 for the extra - // bytes rather than repeating the two previous bytes - // - /* - * Commented out in the light of the oracle attack. - if (iv[iv.length - 2] != (byte)v1 && v1 != 0) - { - throw new PGPDataValidationException("data check failed."); - } + processSymmetricEncIntegrityPacketDataStream(false, dataDecryptor, encIn); + } - if (iv[iv.length - 1] != (byte)v2 && v2 != 0) - { - throw new PGPDataValidationException("data check failed."); - } - */ + // + // some versions of PGP appear to produce 0 for the extra + // bytes rather than repeating the two previous bytes + // + /* + * Commented out in the light of the oracle attack. + if (iv[iv.length - 2] != (byte)v1 && v1 != 0) + { + throw new PGPDataValidationException("data check failed."); } - return encStream; - } - catch (PGPException e) - { - throw e; - } - catch (Exception e) - { - throw new PGPException("Exception starting decryption", e); + if (iv[iv.length - 1] != (byte)v2 && v2 != 0) + { + throw new PGPDataValidationException("data check failed."); + } + */ } + + return encStream; } - else + catch (PGPException e) + { + throw e; + } + catch (Exception e) { - return encData.getInputStream(); + throw new PGPException("Exception starting decryption", e); } } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyRing.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyRing.java index d113d3bde2..10f8b29327 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyRing.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyRing.java @@ -201,7 +201,7 @@ public PGPPublicKey getPublicKey(KeyIdentifier identifier) for (Iterator it = keys.iterator(); it.hasNext();) { PGPPublicKey k = (PGPPublicKey)it.next(); - if (identifier.matches(k.getKeyIdentifier())) + if (identifier.matchesExplicit(k.getKeyIdentifier())) { return k; } @@ -216,7 +216,7 @@ public Iterator getPublicKeys(KeyIdentifier identifier) for (Iterator it = keys.iterator(); it.hasNext();) { PGPPublicKey k = (PGPPublicKey)it.next(); - if (identifier.matches(k.getKeyIdentifier())) + if (identifier.matchesExplicit(k.getKeyIdentifier())) { matches.add(k); } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java index b6c814ed2f..0a9fa5e9bb 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java @@ -36,6 +36,7 @@ import org.bouncycastle.bcpg.X25519SecretBCPGKey; import org.bouncycastle.bcpg.X448SecretBCPGKey; import org.bouncycastle.gpg.SExprParser; +import org.bouncycastle.openpgp.operator.GnuDivertToCardSecretKeyEncryptor; import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory; import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; @@ -293,7 +294,7 @@ public PGPSecretKey( // // generate the certification // - PGPSignatureGenerator sGen = new PGPSignatureGenerator(certificationSignerBuilder); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(certificationSignerBuilder, masterKeyPair.getPublicKey()); sGen.init(PGPSignature.SUBKEY_BINDING, masterKeyPair.getPrivateKey()); @@ -302,7 +303,7 @@ public PGPSecretKey( { if (hashedPcks == null) { - PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(certificationSignerBuilder); + PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(certificationSignerBuilder, keyPair.getPublicKey()); signatureGenerator.init(PGPSignature.PRIMARYKEY_BINDING, keyPair.getPrivateKey()); @@ -382,7 +383,7 @@ private static PGPPublicKey certifiedPublicKey( try { - sGen = new PGPSignatureGenerator(certificationSignerBuilder); + sGen = new PGPSignatureGenerator(certificationSignerBuilder, keyPair.getPublicKey()); } catch (Exception e) { @@ -552,119 +553,117 @@ public Iterator getUserAttributes() return pub.getUserAttributes(); } - private byte[] extractKeyData( - PBESecretKeyDecryptor decryptorFactory) + private byte[] extractKeyData(PBESecretKeyDecryptor decryptorFactory) throws PGPException { byte[] encData = secret.getSecretKeyData(); - byte[] data = null; - if (secret.getEncAlgorithm() != SymmetricKeyAlgorithmTags.NULL) + if (secret.getEncAlgorithm() == SymmetricKeyAlgorithmTags.NULL) { - try - { - byte[] key = decryptorFactory.makeKeyFromPassPhrase(secret.getEncAlgorithm(), secret.getS2K()); - if (secret.getPublicKeyPacket().getVersion() >= PublicKeyPacket.VERSION_4) - { - if (secret.getS2KUsage() == SecretKeyPacket.USAGE_AEAD) - { - // privKey := AEAD(HKDF(S2K(passphrase), info), secrets, packetprefix) - return decryptorFactory.recoverKeyData( - secret.getEncAlgorithm(), - secret.getAeadAlgorithm(), - key, // s2k output = ikm for hkdf - secret.getIV(), // iv = aead nonce - secret.getPacketTag(), - secret.getPublicKeyPacket().getVersion(), - secret.getSecretKeyData(), - secret.getPublicKeyPacket().getEncodedContents()); - } - else - { - data = decryptorFactory.recoverKeyData(secret.getEncAlgorithm(), key, secret.getIV(), encData, 0, encData.length); + return encData; + } - boolean useSHA1 = secret.getS2KUsage() == SecretKeyPacket.USAGE_SHA1; - byte[] check = checksum(useSHA1 ? decryptorFactory.getChecksumCalculator(HashAlgorithmTags.SHA1) : null, data, (useSHA1) ? data.length - 20 : data.length - 2); + try + { + byte[] key = decryptorFactory.makeKeyFromPassPhrase(secret.getEncAlgorithm(), secret.getS2K()); + byte[] data; - if (!Arrays.constantTimeAreEqual(check.length, check, 0, data, data.length - check.length)) - { - throw new PGPException("checksum mismatch at in checksum of " + check.length + " bytes"); - } - } + if (secret.getPublicKeyPacket().getVersion() >= PublicKeyPacket.VERSION_4) + { + if (secret.getS2KUsage() == SecretKeyPacket.USAGE_AEAD) + { + // privKey := AEAD(HKDF(S2K(passphrase), info), secrets, packetprefix) + return decryptorFactory.recoverKeyData( + secret.getEncAlgorithm(), + secret.getAeadAlgorithm(), + key, // s2k output = ikm for hkdf + secret.getIV(), // iv = aead nonce + secret.getPacketTag(), + secret.getPublicKeyPacket().getVersion(), + secret.getSecretKeyData(), + secret.getPublicKeyPacket().getEncodedContents()); } - else // version 2 or 3, RSA only. + else { + data = decryptorFactory.recoverKeyData(secret.getEncAlgorithm(), key, secret.getIV(), encData, 0, encData.length); - data = new byte[encData.length]; - - byte[] iv = new byte[secret.getIV().length]; - - System.arraycopy(secret.getIV(), 0, iv, 0, iv.length); + boolean useSHA1 = secret.getS2KUsage() == SecretKeyPacket.USAGE_SHA1; + byte[] check = checksum(useSHA1 ? decryptorFactory.getChecksumCalculator(HashAlgorithmTags.SHA1) : null, data, (useSHA1) ? data.length - 20 : data.length - 2); - // - // read in the four numbers - // - int pos = 0; - - for (int i = 0; i != 4; i++) + if (!Arrays.constantTimeAreEqual(check.length, check, 0, data, data.length - check.length)) { - int encLen = ((((encData[pos] & 0xff) << 8) | (encData[pos + 1] & 0xff)) + 7) / 8; + throw new PGPException("checksum mismatch in checksum of " + check.length + " bytes"); + } + } + } + else // version 2 or 3, RSA only. + { - data[pos] = encData[pos]; - data[pos + 1] = encData[pos + 1]; + data = new byte[encData.length]; - if (encLen > (encData.length - (pos + 2))) - { - throw new PGPException("out of range encLen found in encData"); - } - byte[] tmp = decryptorFactory.recoverKeyData(secret.getEncAlgorithm(), key, iv, encData, pos + 2, encLen); - System.arraycopy(tmp, 0, data, pos + 2, tmp.length); - pos += 2 + encLen; + byte[] iv = new byte[secret.getIV().length]; - if (i != 3) - { - System.arraycopy(encData, pos - iv.length, iv, 0, iv.length); - } - } + System.arraycopy(secret.getIV(), 0, iv, 0, iv.length); + + // + // read in the four numbers + // + int pos = 0; - // - // verify and copy checksum - // + for (int i = 0; i != 4; i++) + { + int encLen = ((((encData[pos] & 0xff) << 8) | (encData[pos + 1] & 0xff)) + 7) / 8; data[pos] = encData[pos]; data[pos + 1] = encData[pos + 1]; - int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff); - int calcCs = 0; - for (int j = 0; j < data.length - 2; j++) + if (encLen > (encData.length - (pos + 2))) { - calcCs += data[j] & 0xff; + throw new PGPException("out of range encLen found in encData"); } + byte[] tmp = decryptorFactory.recoverKeyData(secret.getEncAlgorithm(), key, iv, encData, pos + 2, encLen); + System.arraycopy(tmp, 0, data, pos + 2, tmp.length); + pos += 2 + encLen; - calcCs &= 0xffff; - if (calcCs != cs) + if (i != 3) { - throw new PGPException("checksum mismatch: passphrase wrong, expected " - + Integer.toHexString(cs) - + " found " + Integer.toHexString(calcCs)); + System.arraycopy(encData, pos - iv.length, iv, 0, iv.length); } } + + // + // verify and copy checksum + // + + data[pos] = encData[pos]; + data[pos + 1] = encData[pos + 1]; + + int cs = ((encData[pos] << 8) & 0xff00) | (encData[pos + 1] & 0xff); + int calcCs = 0; + for (int j = 0; j < data.length - 2; j++) + { + calcCs += data[j] & 0xff; + } + + calcCs &= 0xffff; + if (calcCs != cs) + { + throw new PGPException("checksum mismatch: passphrase wrong, expected " + + Integer.toHexString(cs) + + " found " + Integer.toHexString(calcCs)); + } } - catch (PGPException e) - { - throw e; - } - catch (Exception e) - { - throw new PGPException("Exception decrypting key", e); - } + + return data; } - else + catch (PGPException e) { - data = encData; + throw e; + } + catch (Exception e) + { + throw new PGPException("Exception decrypting key", e); } - - return data; } /** @@ -840,6 +839,9 @@ public void encode(OutputStream outStream) { Util.encodePGPSignatures(out, pub.subSigs, false); } + + // For clarity; really only required if using partial body lengths + out.finish(); } /** @@ -887,7 +889,8 @@ public static PGPSecretKey copyWithNewPassword( byte[] keyData; int newEncAlgorithm = SymmetricKeyAlgorithmTags.NULL; - if (newKeyEncryptor == null || newKeyEncryptor.getAlgorithm() == SymmetricKeyAlgorithmTags.NULL) + if (newKeyEncryptor == null + || (newKeyEncryptor.getAlgorithm() == SymmetricKeyAlgorithmTags.NULL && !(newKeyEncryptor instanceof GnuDivertToCardSecretKeyEncryptor))) { s2kUsage = SecretKeyPacket.USAGE_NONE; if (key.secret.getS2KUsage() == SecretKeyPacket.USAGE_SHA1) // SHA-1 hash, need to rewrite checksum @@ -997,7 +1000,7 @@ public static PGPSecretKey copyWithNewPassword( SecretKeyPacket secret; - if (newKeyEncryptor!= null && newKeyEncryptor.getAeadAlgorithm() > 0) + if (newKeyEncryptor != null && newKeyEncryptor.getAeadAlgorithm() > 0) { s2kUsage = SecretKeyPacket.USAGE_AEAD; secret = generateSecretKeyPacket(!(key.secret instanceof SecretSubkeyPacket), key.secret.getPublicKeyPacket(), newEncAlgorithm, newKeyEncryptor.getAeadAlgorithm(), s2kUsage, s2k, iv, keyData); diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKeyRing.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKeyRing.java index a9c30d49df..8319fcb4c7 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKeyRing.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKeyRing.java @@ -263,7 +263,7 @@ public PGPPublicKey getPublicKey(KeyIdentifier identifier) for (Iterator it = keys.iterator(); it.hasNext();) { PGPSecretKey k = (PGPSecretKey)it.next(); - if (k.getPublicKey() != null && identifier.matches(k.getKeyIdentifier())) + if (k.getPublicKey() != null && identifier.matchesExplicit(k.getKeyIdentifier())) { return k.getPublicKey(); } @@ -272,7 +272,7 @@ public PGPPublicKey getPublicKey(KeyIdentifier identifier) for (Iterator it = extraPubKeys.iterator(); it.hasNext();) { PGPPublicKey k = (PGPPublicKey)it.next(); - if (identifier.matches(k.getKeyIdentifier())) + if (identifier.matchesExplicit(k.getKeyIdentifier())) { return k; } @@ -287,7 +287,7 @@ public Iterator getPublicKeys(KeyIdentifier identifier) for (Iterator it = keys.iterator(); it.hasNext();) { PGPSecretKey k = (PGPSecretKey)it.next(); - if (k.getPublicKey() != null && identifier.matches(k.getKeyIdentifier())) + if (k.getPublicKey() != null && identifier.matchesExplicit(k.getKeyIdentifier())) { matches.add(k.getPublicKey()); } @@ -296,7 +296,7 @@ public Iterator getPublicKeys(KeyIdentifier identifier) for (Iterator it = extraPubKeys.iterator(); it.hasNext();) { PGPPublicKey k = (PGPPublicKey)it.next(); - if (identifier.matches(k.getKeyIdentifier())) + if (identifier.matchesExplicit(k.getKeyIdentifier())) { matches.add(k); } @@ -309,7 +309,7 @@ public PGPSecretKey getSecretKey(KeyIdentifier identifier) for (Iterator it = keys.iterator(); it.hasNext();) { PGPSecretKey k = (PGPSecretKey)it.next(); - if (identifier.matches(k.getKeyIdentifier())) + if (identifier.matchesExplicit(k.getKeyIdentifier())) { return k; } @@ -323,7 +323,7 @@ public Iterator getSecretKeys(KeyIdentifier identifier) for (Iterator it = keys.iterator(); it.hasNext();) { PGPSecretKey k = (PGPSecretKey)it.next(); - if (identifier.matches(k.getKeyIdentifier())) + if (identifier.matchesExplicit(k.getKeyIdentifier())) { matches.add(k); } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSessionKey.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSessionKey.java index d713051d9d..c597d06687 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSessionKey.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSessionKey.java @@ -3,10 +3,13 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; public class PGPSessionKey { + private static final Pattern ASCII_ENCODING_PATTERN = Pattern.compile("(\\d{1,3}):([0-9A-Fa-f]+)"); + private final int algorithm; private final byte[] sessionKey; @@ -23,22 +26,20 @@ public int getAlgorithm() public byte[] getKey() { - byte[] copy = new byte[sessionKey.length]; - System.arraycopy(sessionKey, 0, copy, 0, sessionKey.length); - return copy; + return Arrays.clone(sessionKey); } - @SuppressWarnings("ArrayToString") public String toString() { - // mote: we only print the reference to sessionKey to prevent accidental disclosure of the actual key value. - return algorithm + ":" + sessionKey; + // NOTE: Avoid disclosing the sessionKey value. + String sessionKeyHashCode = Integer.toHexString(System.identityHashCode(sessionKey)); + + return algorithm + ":" + sessionKey.getClass().getName() + "@" + sessionKeyHashCode; } public static PGPSessionKey fromAsciiRepresentation(String ascii) { - Pattern pattern = Pattern.compile("(\\d{1,3}):([0-9A-Fa-f]+)"); - Matcher matcher = pattern.matcher(ascii); + Matcher matcher = ASCII_ENCODING_PATTERN.matcher(ascii); if (!matcher.matches()) { throw new IllegalArgumentException("Provided ascii encoding does not match expected format :"); diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java index 79419f1a11..f34ec745bb 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java @@ -5,6 +5,7 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.Date; +import java.util.Iterator; import java.util.List; import org.bouncycastle.asn1.ASN1EncodableVector; @@ -23,6 +24,8 @@ import org.bouncycastle.bcpg.TrustPacket; import org.bouncycastle.bcpg.sig.IssuerFingerprint; import org.bouncycastle.bcpg.sig.IssuerKeyID; +import org.bouncycastle.bcpg.sig.RevocationReason; +import org.bouncycastle.bcpg.sig.RevocationReasonTags; import org.bouncycastle.math.ec.rfc8032.Ed25519; import org.bouncycastle.math.ec.rfc8032.Ed448; import org.bouncycastle.openpgp.operator.PGPContentVerifier; @@ -195,7 +198,7 @@ public class PGPSignature */ public static final int THIRD_PARTY_CONFIRMATION = 0x50; - private final SignaturePacket sigPck; + final SignaturePacket sigPck; private final TrustPacket trustPck; private volatile PGPContentVerifier verifier; @@ -635,11 +638,30 @@ public long getKeyID() public List getKeyIdentifiers() { List identifiers = new ArrayList(); - identifiers.addAll(getHashedKeyIdentifiers()); - identifiers.addAll(getUnhashedKeyIdentifiers()); + if (getVersion() <= SignaturePacket.VERSION_3) + { + identifiers.add(new KeyIdentifier(getKeyID())); + } + else + { + identifiers.addAll(getHashedKeyIdentifiers()); + identifiers.addAll(getUnhashedKeyIdentifiers()); + } return identifiers; } + public boolean hasKeyIdentifier(KeyIdentifier identifier) + { + for (Iterator it = getKeyIdentifiers().iterator(); it.hasNext(); ) + { + if (((KeyIdentifier)it.next()).matchesExplicit(identifier)) + { + return true; + } + } + return false; + } + /** * Return a list of all {@link KeyIdentifier KeyIdentifiers} that could be derived from * any {@link IssuerFingerprint} or {@link IssuerKeyID} subpackets of the hashed signature @@ -782,12 +804,20 @@ else if (getKeyAlgorithm() == PublicKeyAlgorithmTags.EDDSA_LEGACY) byte[] b = BigIntegers.asUnsignedByteArray(sigValues[1].getValue()); if (a.length + b.length > Ed25519.SIGNATURE_SIZE) { + if (a.length > Ed448.PUBLIC_KEY_SIZE || b.length > Ed448.SIGNATURE_SIZE) + { + throw new PGPException("Malformed Ed448 signature encoding (too long)."); + } signature = new byte[Ed448.SIGNATURE_SIZE]; System.arraycopy(a, 0, signature, Ed448.PUBLIC_KEY_SIZE - a.length, a.length); System.arraycopy(b, 0, signature, Ed448.SIGNATURE_SIZE - b.length, b.length); } else { + if (a.length > Ed25519.PUBLIC_KEY_SIZE || b.length > Ed25519.SIGNATURE_SIZE) + { + throw new PGPException("Malformed Ed25519 signature encoding (too long)."); + } signature = new byte[Ed25519.SIGNATURE_SIZE]; System.arraycopy(a, 0, signature, Ed25519.PUBLIC_KEY_SIZE - a.length, a.length); System.arraycopy(b, 0, signature, Ed25519.SIGNATURE_SIZE - b.length, b.length); @@ -905,6 +935,46 @@ public static boolean isCertification(int signatureType) || PGPSignature.POSITIVE_CERTIFICATION == signatureType; } + public static boolean isRevocation(int signatureType) + { + return PGPSignature.KEY_REVOCATION == signatureType + || PGPSignature.CERTIFICATION_REVOCATION == signatureType + || PGPSignature.SUBKEY_REVOCATION == signatureType; + } + + public boolean isHardRevocation() + { + if (!isRevocation(getSignatureType())) + { + return false; // no revocation + } + + if (!hasSubpackets()) + { + return true; // consider missing subpackets (and therefore missing reason) as hard revocation + } + + // only consider reasons from the hashed packet area + RevocationReason reason = getHashedSubPackets() != null ? + getHashedSubPackets().getRevocationReason() : null; + if (reason == null) + { + return true; // missing reason packet is hard + } + + byte code = reason.getRevocationReason(); + if (code >= 100 && code <= 110) + { + // private / experimental reasons are considered hard + return true; + } + + // Reason is not from the set of known soft reasons + return code != RevocationReasonTags.KEY_SUPERSEDED && + code != RevocationReasonTags.KEY_RETIRED && + code != RevocationReasonTags.USER_NO_LONGER_VALID; + } + /** * Return true, if the cryptographic signature encoding of the two signatures match. * @@ -971,16 +1041,7 @@ public static PGPSignature join(PGPSignature sig1, PGPSignature sig2) SignatureSubpacket[] unhashed = (SignatureSubpacket[])merged.toArray(new SignatureSubpacket[0]); return new PGPSignature( - new SignaturePacket( - sig1.getSignatureType(), - sig1.getKeyID(), - sig1.getKeyAlgorithm(), - sig1.getHashAlgorithm(), - sig1.getHashedSubPackets().packets, - unhashed, - sig1.getDigestPrefix(), - sig1.sigPck.getSignature() - ) + SignaturePacket.copyOfWith(sig1.sigPck, unhashed) ); } } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureException.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureException.java new file mode 100644 index 0000000000..88b2887319 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureException.java @@ -0,0 +1,15 @@ +package org.bouncycastle.openpgp; + +public class PGPSignatureException + extends PGPException +{ + public PGPSignatureException(String message) + { + super(message); + } + + public PGPSignatureException(String message, Exception cause) + { + super(message, cause); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketGenerator.java index 4330035bc1..db65f140fc 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketGenerator.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignatureSubpacketGenerator.java @@ -1,11 +1,14 @@ package org.bouncycastle.openpgp; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; +import org.bouncycastle.bcpg.BCPGOutputStream; +import org.bouncycastle.bcpg.PacketFormat; import org.bouncycastle.bcpg.SignatureSubpacket; import org.bouncycastle.bcpg.SignatureSubpacketTags; import org.bouncycastle.bcpg.sig.EmbeddedSignature; @@ -69,10 +72,7 @@ public PGPSignatureSubpacketGenerator(PGPSignatureSubpacketVector sigSubV) */ public void setRevocable(boolean isCritical, boolean isRevocable) { - if (contains(SignatureSubpacketTags.REVOCABLE)) - { - throw new IllegalStateException("Revocable exists in the Signature Subpacket Generator"); - } + removePacketsOfType(SignatureSubpacketTags.REVOCABLE); packets.add(new Revocable(isCritical, isRevocable)); } @@ -97,10 +97,7 @@ public void setExportable(boolean isExportable) */ public void setExportable(boolean isCritical, boolean isExportable) { - if (contains(SignatureSubpacketTags.EXPORTABLE)) - { - throw new IllegalStateException("Exportable Certification exists in the Signature Subpacket Generator"); - } + removePacketsOfType(SignatureSubpacketTags.EXPORTABLE); packets.add(new Exportable(isCritical, isExportable)); } @@ -108,10 +105,11 @@ public void setExportable(boolean isCritical, boolean isExportable) * Specify the set of features of the key. * * @param isCritical true if should be treated as critical, false otherwise. - * @param feature features + * @param feature features bitmap */ public void setFeature(boolean isCritical, byte feature) { + removePacketsOfType(SignatureSubpacketTags.FEATURES); packets.add(new Features(isCritical, feature)); } @@ -126,6 +124,7 @@ public void setFeature(boolean isCritical, byte feature) */ public void setTrust(boolean isCritical, int depth, int trustAmount) { + removePacketsOfType(SignatureSubpacketTags.TRUST_SIG); packets.add(new TrustSignature(isCritical, depth, trustAmount)); } @@ -150,6 +149,7 @@ public void setKeyExpirationTime(long seconds) */ public void setKeyExpirationTime(boolean isCritical, long seconds) { + removePacketsOfType(SignatureSubpacketTags.KEY_EXPIRE_TIME); packets.add(new KeyExpirationTime(isCritical, seconds)); } @@ -175,6 +175,7 @@ public void setSignatureExpirationTime(long seconds) */ public void setSignatureExpirationTime(boolean isCritical, long seconds) { + removePacketsOfType(SignatureSubpacketTags.EXPIRE_TIME); packets.add(new SignatureExpirationTime(isCritical, seconds)); } @@ -200,6 +201,7 @@ public void setSignatureCreationTime(Date date) */ public void setSignatureCreationTime(boolean isCritical, Date date) { + removePacketsOfType(SignatureSubpacketTags.CREATION_TIME); packets.add(new SignatureCreationTime(isCritical, date)); } @@ -212,6 +214,7 @@ public void setSignatureCreationTime(boolean isCritical, Date date) */ public void setPreferredHashAlgorithms(boolean isCritical, int[] algorithms) { + removePacketsOfType(SignatureSubpacketTags.PREFERRED_HASH_ALGS); packets.add(new PreferredAlgorithms(SignatureSubpacketTags.PREFERRED_HASH_ALGS, isCritical, algorithms)); } @@ -225,6 +228,7 @@ public void setPreferredHashAlgorithms(boolean isCritical, int[] algorithms) */ public void setPreferredSymmetricAlgorithms(boolean isCritical, int[] algorithms) { + removePacketsOfType(SignatureSubpacketTags.PREFERRED_SYM_ALGS); packets.add(new PreferredAlgorithms(SignatureSubpacketTags.PREFERRED_SYM_ALGS, isCritical, algorithms)); } @@ -238,6 +242,7 @@ public void setPreferredSymmetricAlgorithms(boolean isCritical, int[] algorithms */ public void setPreferredCompressionAlgorithms(boolean isCritical, int[] algorithms) { + removePacketsOfType(SignatureSubpacketTags.PREFERRED_COMP_ALGS); packets.add(new PreferredAlgorithms(SignatureSubpacketTags.PREFERRED_COMP_ALGS, isCritical, algorithms)); } @@ -254,6 +259,7 @@ public void setPreferredCompressionAlgorithms(boolean isCritical, int[] algorith @Deprecated public void setPreferredAEADAlgorithms(boolean isCritical, int[] algorithms) { + removePacketsOfType(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS); packets.add(new PreferredAlgorithms(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS, isCritical, algorithms)); } @@ -268,6 +274,7 @@ public void setPreferredAEADAlgorithms(boolean isCritical, int[] algorithms) */ public void setPreferredAEADCiphersuites(boolean isCritical, PreferredAEADCiphersuites.Combination[] algorithms) { + removePacketsOfType(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS); packets.add(new PreferredAEADCiphersuites(isCritical, algorithms)); } @@ -280,6 +287,7 @@ public void setPreferredAEADCiphersuites(boolean isCritical, PreferredAEADCipher */ public void setPreferredAEADCiphersuites(PreferredAEADCiphersuites.Builder builder) { + removePacketsOfType(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS); packets.add(builder.build()); } @@ -300,6 +308,7 @@ public void setPreferredAEADCiphersuites(PreferredAEADCiphersuites.Builder build @Deprecated public void setPreferredLibrePgpEncryptionModes(boolean isCritical, int[] algorithms) { + removePacketsOfType(SignatureSubpacketTags.LIBREPGP_PREFERRED_ENCRYPTION_MODES); packets.add(new LibrePGPPreferredEncryptionModes(isCritical, algorithms)); } @@ -309,8 +318,23 @@ public void setPreferredLibrePgpEncryptionModes(boolean isCritical, int[] algori * * @param isCritical true if the subpacket should be treated as critical * @param uri key server URI + * @deprecated use {@link #addPreferredKeyServer(boolean, String)} instead. */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public void setPreferredKeyServer(boolean isCritical, String uri) + { + addPreferredKeyServer(isCritical, uri); + } + + /** + * Specify a preferred key server for the signed user-id / key. + * Note, that the key server might also be a http/ftp etc. URI pointing to the key itself. + * + * @param isCritical true if the subpacket should be treated as critical + * @param uri key server URI + */ + public void addPreferredKeyServer(boolean isCritical, String uri) { packets.add(new PreferredKeyServer(isCritical, uri)); } @@ -341,6 +365,7 @@ public void setKeyFlags(int flags) */ public void setKeyFlags(boolean isCritical, int flags) { + removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS); packets.add(new KeyFlags(isCritical, flags)); } @@ -424,9 +449,16 @@ public void setEmbeddedSignature(boolean isCritical, PGPSignature pgpSignature) public void addEmbeddedSignature(boolean isCritical, PGPSignature pgpSignature) throws IOException { - byte[] sig = pgpSignature.getEncoded(); + // Encode the signature forcing legacy packet format, such that we consistently cut off the proper amount + // of header bytes + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut, PacketFormat.LEGACY); + pgpSignature.encode(pOut); + pOut.close(); + byte[] sig = bOut.toByteArray(); byte[] data; + // Cut off the header bytes if (sig.length - 1 > 256) { data = new byte[sig.length - 3]; @@ -443,6 +475,7 @@ public void addEmbeddedSignature(boolean isCritical, PGPSignature pgpSignature) public void setPrimaryUserID(boolean isCritical, boolean isPrimaryUserID) { + removePacketsOfType(SignatureSubpacketTags.PRIMARY_USER_ID); packets.add(new PrimaryUserID(isCritical, isPrimaryUserID)); } @@ -485,6 +518,7 @@ public void addNotationData(boolean isCritical, boolean isHumanReadable, String */ public void setRevocationReason(boolean isCritical, byte reason, String description) { + removePacketsOfType(SignatureSubpacketTags.REVOCATION_REASON); packets.add(new RevocationReason(isCritical, reason, description)); } @@ -523,6 +557,7 @@ public void addRevocationKey(boolean isCritical, int keyAlgorithm, byte[] finger */ public void setIssuerKeyID(boolean isCritical, long keyID) { + removePacketsOfType(SignatureSubpacketTags.ISSUER_KEY_ID); packets.add(new IssuerKeyID(isCritical, keyID)); } @@ -536,6 +571,7 @@ public void setIssuerKeyID(boolean isCritical, long keyID) */ public void setSignatureTarget(boolean isCritical, int publicKeyAlgorithm, int hashAlgorithm, byte[] hashData) { + removePacketsOfType(SignatureSubpacketTags.SIGNATURE_TARGET); packets.add(new SignatureTarget(isCritical, publicKeyAlgorithm, hashAlgorithm, hashData)); } @@ -558,6 +594,7 @@ public void setIssuerFingerprint(boolean isCritical, PGPSecretKey secretKey) */ public void setIssuerFingerprint(boolean isCritical, PGPPublicKey publicKey) { + removePacketsOfType(SignatureSubpacketTags.ISSUER_FINGERPRINT); packets.add(new IssuerFingerprint(isCritical, publicKey.getVersion(), publicKey.getFingerprint())); } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSymmetricKeyEncryptedData.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSymmetricKeyEncryptedData.java index ac6f3d22b7..db93abc939 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSymmetricKeyEncryptedData.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSymmetricKeyEncryptedData.java @@ -3,7 +3,6 @@ import java.io.InputStream; import org.bouncycastle.bcpg.AEADEncDataPacket; -import org.bouncycastle.bcpg.BCPGInputStream; import org.bouncycastle.bcpg.InputStreamPacket; import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket; import org.bouncycastle.bcpg.UnsupportedPacketVersionException; @@ -31,11 +30,10 @@ protected InputStream createDecryptionStream(PGPDataDecryptorFactory dataDecrypt throw new PGPException("session key and AEAD algorithm mismatch"); } - PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor( - aeadData, sessionKey); - BCPGInputStream encIn = encData.getInputStream(); + PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(aeadData, sessionKey); + InputStream encIn = getInputStream(); - return new BCPGInputStream(dataDecryptor.getInputStream(encIn)); + return dataDecryptor.getInputStream(encIn); } else if (encData instanceof SymmetricEncIntegrityPacket) { @@ -44,7 +42,8 @@ else if (encData instanceof SymmetricEncIntegrityPacket) // OpenPGP v4 (SEIPD v1 with integrity protection) if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_1) { - PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(true, sessionKey.getAlgorithm(), sessionKey.getKey()); + PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(true, + sessionKey.getAlgorithm(), sessionKey.getKey()); return getDataStream(true, dataDecryptor); } @@ -52,7 +51,7 @@ else if (encData instanceof SymmetricEncIntegrityPacket) else if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_2) { PGPDataDecryptor dataDecryptor = dataDecryptorFactory.createDataDecryptor(seipd, sessionKey); - return new BCPGInputStream(dataDecryptor.getInputStream(encData.getInputStream())); + return dataDecryptor.getInputStream(getInputStream()); } // Unsupported @@ -76,7 +75,7 @@ private InputStream getDataStream( { try { - BCPGInputStream encIn = encData.getInputStream(); + InputStream encIn = getInputStream(); encIn.mark(dataDecryptor.getBlockSize() + 2); // iv + 2 octets checksum if (processSymmetricEncIntegrityPacketDataStream(withIntegrityPacket, dataDecryptor, encIn)) { diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPTrust.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPTrust.java new file mode 100644 index 0000000000..b5b6527353 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPTrust.java @@ -0,0 +1,34 @@ +package org.bouncycastle.openpgp; + +import java.io.IOException; + +import org.bouncycastle.bcpg.BCPGInputStream; +import org.bouncycastle.bcpg.TrustPacket; +import org.bouncycastle.util.Arrays; + +public class PGPTrust +{ + + private final TrustPacket packet; + + public PGPTrust(TrustPacket packet) + { + this.packet = packet; + } + + public PGPTrust(BCPGInputStream inputStream) + throws IOException + { + this((TrustPacket) inputStream.readPacket()); + } + + public TrustPacket getPacket() + { + return packet; + } + + public byte[] getLevelAndTrust() + { + return Arrays.clone(packet.getLevelAndTrustAmount()); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java index 76bad21f70..e81dde4a48 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java @@ -525,7 +525,7 @@ public static InputStream getDecoderStream( // // nothing but new lines, little else, assume regular armoring // - if (count < 4) + if (index < 4) { return new ArmoredInputStream(in); } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/Util.java b/pg/src/main/java/org/bouncycastle/openpgp/Util.java index af4a6c68e9..7263a3cb9c 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/Util.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/Util.java @@ -12,27 +12,29 @@ class Util static BCPGInputStream createBCPGInputStream(InputStream pgIn, int tag1) throws IOException { - BCPGInputStream bcIn = new BCPGInputStream(pgIn); + BCPGInputStream bcIn = BCPGInputStream.wrap(pgIn); + int nextTag = bcIn.nextPacketTag(); - if (bcIn.nextPacketTag() == tag1) + if (nextTag == tag1) { return bcIn; } - throw new IOException("unexpected tag " + bcIn.nextPacketTag() + " encountered"); + throw new IOException("unexpected tag " + nextTag + " encountered"); } static BCPGInputStream createBCPGInputStream(InputStream pgIn, int tag1, int tag2) throws IOException { - BCPGInputStream bcIn = new BCPGInputStream(pgIn); + BCPGInputStream bcIn = BCPGInputStream.wrap(pgIn); + int nextTag = bcIn.nextPacketTag(); - if (bcIn.nextPacketTag() == tag1 || bcIn.nextPacketTag() == tag2) + if (nextTag == tag1 || nextTag == tag2) { return bcIn; } - throw new IOException("unexpected tag " + bcIn.nextPacketTag() + " encountered"); + throw new IOException("unexpected tag " + nextTag + " encountered"); } static void encodePGPSignatures(OutputStream stream, List sigs, boolean forTransfer) diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/AbstractOpenPGPDocumentSignatureGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/api/AbstractOpenPGPDocumentSignatureGenerator.java new file mode 100644 index 0000000000..4111697472 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/AbstractOpenPGPDocumentSignatureGenerator.java @@ -0,0 +1,326 @@ +package org.bouncycastle.openpgp.api; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import org.bouncycastle.bcpg.sig.PreferredAlgorithms; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPKeyPair; +import org.bouncycastle.openpgp.PGPSignatureGenerator; +import org.bouncycastle.openpgp.api.exception.InvalidSigningKeyException; +import org.bouncycastle.openpgp.api.exception.KeyPassphraseException; + +public class AbstractOpenPGPDocumentSignatureGenerator> +{ + + protected final OpenPGPImplementation implementation; + protected final OpenPGPPolicy policy; + + // Below lists all use the same indexing + protected final List signatureGenerators = new ArrayList(); + protected final List signingKeys = new ArrayList(); + protected final List signatureCallbacks = new ArrayList(); + protected final List signingKeyPassphraseProviders = new ArrayList(); + + protected final KeyPassphraseProvider.DefaultKeyPassphraseProvider defaultKeyPassphraseProvider = + new KeyPassphraseProvider.DefaultKeyPassphraseProvider(); + + protected SubkeySelector signingKeySelector = new SubkeySelector() + { + @Override + public List select(OpenPGPCertificate certificate, + final OpenPGPPolicy policy) + { + List result = new ArrayList(); + for (Iterator it = certificate.getSigningKeys().iterator(); it.hasNext(); ) + { + OpenPGPCertificate.OpenPGPComponentKey key = it.next(); + if (policy.isAcceptablePublicKey(key.getPGPPublicKey())) + { + result.add(key); + } + } + return result; + } + }; + + public AbstractOpenPGPDocumentSignatureGenerator(OpenPGPImplementation implementation, OpenPGPPolicy policy) + { + this.implementation = implementation; + this.policy = policy; + } + + /** + * Replace the default signing key selector with a custom implementation. + * The signing key selector is responsible for selecting one or more signing subkeys from a signing key. + * + * @param signingKeySelector selector for signing (sub-)keys + * @return this + */ + public T setSigningKeySelector(SubkeySelector signingKeySelector) + { + if (signingKeySelector == null) + { + throw new NullPointerException(); + } + this.signingKeySelector = signingKeySelector; + return (T)this; + } + + /** + * Add a passphrase for unlocking signing keys to the set of available passphrases. + * + * @param passphrase passphrase + * @return this + */ + public T addKeyPassphrase(char[] passphrase) + { + defaultKeyPassphraseProvider.addPassphrase(passphrase); + return (T)this; + } + + /** + * Add an {@link OpenPGPKey} for message signing. + * The {@link #signingKeySelector} is responsible for selecting one or more subkeys of the key to sign with. + * If no (sub-)key in the signing key is capable of creating signatures, or if the key is expired or revoked, + * this method will throw an {@link InvalidSigningKeyException}. + * + * @param key OpenPGP key + * @return this + * @throws InvalidSigningKeyException if the key is not capable of signing + */ + public T addSigningKey( + OpenPGPKey key) + throws InvalidSigningKeyException + { + return addSigningKey(key, defaultKeyPassphraseProvider); + } + + /** + * Add an {@link OpenPGPKey} for message signing, using the provided {@link KeyPassphraseProvider} to + * unlock protected subkeys. + * The {@link #signingKeySelector} is responsible for selecting one or more subkeys of the key to sign with. + * If no (sub-)key in the signing key is capable of creating signatures, or if the key is expired or revoked, + * this method will throw an {@link InvalidSigningKeyException}. + * + * @param key OpenPGP key + * @param passphraseProvider provides the passphrase to unlock the signing key + * @return this + * @throws InvalidSigningKeyException if the OpenPGP key does not contain a usable signing subkey + */ + public T addSigningKey( + OpenPGPKey key, + KeyPassphraseProvider passphraseProvider) + throws InvalidSigningKeyException + { + return addSigningKey(key, passphraseProvider, null); + } + + /** + * Add an {@link OpenPGPKey} for message signing, using the {@link SignatureParameters.Callback} to + * allow modification of the signature contents. + * The {@link #signingKeySelector} is responsible for selecting one or more subkeys of the key to sign with. + * If no (sub-)key in the signing key is capable of creating signatures, or if the key is expired or revoked, + * this method will throw an {@link InvalidSigningKeyException}. + * + * @param key OpenPGP key + * @param signatureCallback optional callback to modify the signature contents with + * @return this + * @throws InvalidSigningKeyException if the OpenPGP key does not contain a usable signing subkey + */ + public T addSigningKey( + OpenPGPKey key, + SignatureParameters.Callback signatureCallback) + throws InvalidSigningKeyException + { + return addSigningKey(key, defaultKeyPassphraseProvider, signatureCallback); + } + + /** + * Add an {@link OpenPGPKey} for message signing, using the given {@link KeyPassphraseProvider} + * for unlocking protected subkeys and using the {@link SignatureParameters.Callback} to allow + * modification of the signature contents. + * The {@link #signingKeySelector} is responsible for selecting one or more subkeys of the key to sign with. + * If no (sub-)key in the signing key is capable of creating signatures, or if the key is expired or revoked, + * this method will throw an {@link InvalidSigningKeyException}. + * + * @param key OpenPGP key + * @param passphraseProvider key passphrase provider + * @param signatureCallback optional callback to modify the signature contents with + * @return this + * @throws InvalidSigningKeyException if the OpenPGP key does not contain a usable signing subkey + */ + public T addSigningKey( + OpenPGPKey key, + KeyPassphraseProvider passphraseProvider, + SignatureParameters.Callback signatureCallback) + throws InvalidSigningKeyException + { + List signingSubkeys = signingKeySelector.select(key, policy); + if (signingSubkeys.isEmpty()) + { + throw new InvalidSigningKeyException(key); + } + + for (Iterator it = signingSubkeys.iterator(); it.hasNext(); ) + { + OpenPGPKey.OpenPGPSecretKey signingKey = key.getSecretKey((OpenPGPCertificate.OpenPGPComponentKey)it.next()); + addSigningKey(signingKey, passphraseProvider, signatureCallback); + } + + return (T)this; + } + + /** + * Add the given signing (sub-)key for message signing, using the optional passphrase to unlock the + * key in case its locked, and using the given {@link SignatureParameters.Callback} to allow + * modification of the signature contents. + * + * @param signingKey signing (sub-)key + * @param passphrase optional subkey passphrase + * @param signatureCallback optional callback to modify the signature contents + * @return this + * @throws InvalidSigningKeyException if the subkey is not signing-capable + */ + public T addSigningKey( + OpenPGPKey.OpenPGPSecretKey signingKey, + char[] passphrase, + SignatureParameters.Callback signatureCallback) + throws InvalidSigningKeyException + { + return addSigningKey( + signingKey, + defaultKeyPassphraseProvider.addPassphrase(signingKey, passphrase), + signatureCallback); + } + + /** + * Add the given signing (sub-)key for message signing, using the passphrase provider to unlock the + * key in case its locked, and using the given {@link SignatureParameters.Callback} to allow + * modification of the signature contents. + * + * @param signingKey signing (sub-)key + * @param passphraseProvider passphrase provider for unlocking the subkey + * @param signatureCallback optional callback to modify the signature contents + * @return this + * @throws InvalidSigningKeyException if the subkey is not signing-capable + */ + public T addSigningKey( + OpenPGPKey.OpenPGPSecretKey signingKey, + KeyPassphraseProvider passphraseProvider, + SignatureParameters.Callback signatureCallback) + throws InvalidSigningKeyException + { + if (!signingKey.isSigningKey()) + { + throw new InvalidSigningKeyException(signingKey); + } + + signingKeys.add(signingKey); + signingKeyPassphraseProviders.add(passphraseProvider); + signatureCallbacks.add(signatureCallback); + return (T)this; + } + + protected PGPSignatureGenerator initSignatureGenerator( + OpenPGPKey.OpenPGPSecretKey signingKey, + KeyPassphraseProvider passphraseProvider, + SignatureParameters.Callback signatureCallback) + throws PGPException + { + SignatureParameters parameters = Utils.applySignatureParameters(signatureCallback, + SignatureParameters.dataSignature(policy).setSignatureHashAlgorithm(getPreferredHashAlgorithm(signingKey))); + + if (parameters == null) + { + throw new IllegalStateException("SignatureParameters Callback MUST NOT return null."); + } + + if (!signingKey.isSigningKey(parameters.getSignatureCreationTime())) + { + throw new InvalidSigningKeyException(signingKey); + } + + char[] passphrase = passphraseProvider.getKeyPassword(signingKey); + PGPKeyPair unlockedKey = signingKey.unlock(passphrase).getKeyPair(); + if (unlockedKey == null) + { + throw new KeyPassphraseException(signingKey, new PGPException("Cannot unlock secret key.")); + } + + return Utils.getPgpSignatureGenerator(implementation, signingKey.getPGPPublicKey(), + unlockedKey.getPrivateKey(), parameters, null, null); + } + + private int getPreferredHashAlgorithm(OpenPGPCertificate.OpenPGPComponentKey key) + { + // Determine the Hash Algorithm to use by inspecting the signing key's hash algorithm preferences + // TODO: Instead inspect the hash algorithm preferences of recipient certificates? + PreferredAlgorithms hashPreferences = key.getHashAlgorithmPreferences(); + if (hashPreferences != null) + { + int[] prefs = hashPreferences.getPreferences(); + List acceptablePrefs = new ArrayList(); + for (int i = 0; i < prefs.length; i++) + { + int algo = prefs[i]; + if (policy.isAcceptableDocumentSignatureHashAlgorithm(algo, new Date())) + { + acceptablePrefs.add(algo); + } + } + if (!acceptablePrefs.isEmpty()) + { + return acceptablePrefs.get(0); + } + } + return policy.getDefaultDocumentSignatureHashAlgorithm(); +// PreferredAlgorithms hashPreferences = key.getHashAlgorithmPreferences(); +// if (hashPreferences != null) +// { +// int[] pref = Arrays.stream(hashPreferences.getPreferences()) +// .filter(new IntPredicate() +// { // Replace lambda with anonymous class for IntPredicate +// @Override +// public boolean test(int it) +// { +// return policy.isAcceptableDocumentSignatureHashAlgorithm(it, new Date()); +// } +// }) +// .toArray(); +// if (pref.length != 0) +// { +// return pref[0]; +// } +// } +// return policy.getDefaultDocumentSignatureHashAlgorithm(); + } + + /** + * Set a callback that will be fired, if a passphrase for a protected signing key is missing. + * This can be used for example to implement interactive on-demand passphrase prompting. + * + * @param callback passphrase provider + * @return builder + */ + public T setMissingKeyPassphraseCallback(KeyPassphraseProvider callback) + { + defaultKeyPassphraseProvider.setMissingPassphraseCallback(callback); + return (T)this; + } + + protected void addSignToGenerator() + throws PGPException + { + for (int i = 0; i < signingKeys.size(); i++) + { + OpenPGPKey.OpenPGPSecretKey signingKey = signingKeys.get(i); + KeyPassphraseProvider keyPassphraseProvider = signingKeyPassphraseProviders.get(i); + SignatureParameters.Callback signatureCallback = signatureCallbacks.get(i); + PGPSignatureGenerator sigGen = initSignatureGenerator(signingKey, keyPassphraseProvider, signatureCallback); + signatureGenerators.add(sigGen); + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/AbstractOpenPGPKeySignatureGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/api/AbstractOpenPGPKeySignatureGenerator.java new file mode 100644 index 0000000000..927131bce9 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/AbstractOpenPGPKeySignatureGenerator.java @@ -0,0 +1,181 @@ +package org.bouncycastle.openpgp.api; + +import org.bouncycastle.bcpg.AEADAlgorithmTags; +import org.bouncycastle.bcpg.CompressionAlgorithmTags; +import org.bouncycastle.bcpg.HashAlgorithmTags; +import org.bouncycastle.bcpg.SignatureSubpacketTags; +import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.bouncycastle.bcpg.sig.Features; +import org.bouncycastle.bcpg.sig.KeyFlags; +import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites; +import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; + +public abstract class AbstractOpenPGPKeySignatureGenerator +{ + + /** + * Standard AEAD encryption preferences (SEIPDv2). + * By default, only announce support for OCB + AES. + */ + protected SignatureSubpacketsFunction defaultAeadAlgorithmPreferences = new SignatureSubpacketsFunction() + { + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.removePacketsOfType(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS); + subpackets.setPreferredAEADCiphersuites(PreferredAEADCiphersuites.builder(false) + .addCombination(SymmetricKeyAlgorithmTags.AES_256, AEADAlgorithmTags.OCB) + .addCombination(SymmetricKeyAlgorithmTags.AES_192, AEADAlgorithmTags.OCB) + .addCombination(SymmetricKeyAlgorithmTags.AES_128, AEADAlgorithmTags.OCB)); + return subpackets; + } + }; + + /** + * Standard symmetric-key encryption preferences (SEIPDv1). + * By default, announce support for AES. + */ + protected SignatureSubpacketsFunction defaultSymmetricKeyPreferences = new SignatureSubpacketsFunction() + { + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.removePacketsOfType(SignatureSubpacketTags.PREFERRED_SYM_ALGS); + subpackets.setPreferredSymmetricAlgorithms(false, new int[]{ + SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192, SymmetricKeyAlgorithmTags.AES_128 + }); + return subpackets; + } + }; + + /** + * Standard signature hash algorithm preferences. + * By default, only announce SHA3 and SHA2 algorithms. + */ + protected SignatureSubpacketsFunction defaultHashAlgorithmPreferences = new SignatureSubpacketsFunction() + { + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.removePacketsOfType(SignatureSubpacketTags.PREFERRED_HASH_ALGS); + subpackets.setPreferredHashAlgorithms(false, new int[]{ + HashAlgorithmTags.SHA3_512, HashAlgorithmTags.SHA3_256, + HashAlgorithmTags.SHA512, HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA256 + }); + return subpackets; + } + }; + + /** + * Standard compression algorithm preferences. + * By default, announce support for all known algorithms. + */ + protected SignatureSubpacketsFunction defaultCompressionAlgorithmPreferences = new SignatureSubpacketsFunction() + { + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.removePacketsOfType(SignatureSubpacketTags.PREFERRED_COMP_ALGS); + subpackets.setPreferredCompressionAlgorithms(false, new int[]{ + CompressionAlgorithmTags.UNCOMPRESSED, CompressionAlgorithmTags.ZIP, + CompressionAlgorithmTags.ZLIB, CompressionAlgorithmTags.BZIP2 + }); + return subpackets; + } + }; + + /** + * Standard features to announce. + * By default, announce SEIPDv1 (modification detection) and SEIPDv2. + */ + protected SignatureSubpacketsFunction defaultFeatures = new SignatureSubpacketsFunction() + { + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.removePacketsOfType(SignatureSubpacketTags.FEATURES); + subpackets.setFeature(false, (byte)(Features.FEATURE_MODIFICATION_DETECTION | Features.FEATURE_SEIPD_V2)); + return subpackets; + } + }; + + /** + * Standard signature subpackets for signing subkey's binding signatures. + * Sets the keyflag subpacket to SIGN_DATA. + */ + protected SignatureSubpacketsFunction signingSubkeySubpackets = new SignatureSubpacketsFunction() + { + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS); + subpackets.setKeyFlags(true, KeyFlags.SIGN_DATA); + return subpackets; + } + }; + + /** + * Standard signature subpackets for encryption subkey's binding signatures. + * Sets the keyflag subpacket to ENCRYPT_STORAGE|ENCRYPT_COMMS. + */ + protected SignatureSubpacketsFunction encryptionSubkeySubpackets = new SignatureSubpacketsFunction() + { + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS); + subpackets.setKeyFlags(true, KeyFlags.ENCRYPT_STORAGE | KeyFlags.ENCRYPT_COMMS); + return subpackets; + } + }; + + /** + * Standard signature subpackets for the direct-key signature. + * Sets default features, hash-, compression-, symmetric-key-, and AEAD algorithm preferences. + */ + protected SignatureSubpacketsFunction directKeySignatureSubpackets = new SignatureSubpacketsFunction() + { + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets = defaultFeatures.apply(subpackets); + subpackets = defaultHashAlgorithmPreferences.apply(subpackets); + subpackets = defaultCompressionAlgorithmPreferences.apply(subpackets); + subpackets = defaultSymmetricKeyPreferences.apply(subpackets); + subpackets = defaultAeadAlgorithmPreferences.apply(subpackets); + return subpackets; + } + }; + + public void setDefaultAeadAlgorithmPreferences(SignatureSubpacketsFunction aeadAlgorithmPreferences) + { + this.defaultAeadAlgorithmPreferences = aeadAlgorithmPreferences; + } + + public void setDefaultSymmetricKeyPreferences(SignatureSubpacketsFunction symmetricKeyPreferences) + { + this.defaultSymmetricKeyPreferences = symmetricKeyPreferences; + } + + public void setDefaultHashAlgorithmPreferences(SignatureSubpacketsFunction hashAlgorithmPreferences) + { + this.defaultHashAlgorithmPreferences = hashAlgorithmPreferences; + } + + public void setDefaultCompressionAlgorithmPreferences(SignatureSubpacketsFunction compressionAlgorithmPreferences) + { + this.defaultCompressionAlgorithmPreferences = compressionAlgorithmPreferences; + } + + public void setDirectKeySignatureSubpackets(SignatureSubpacketsFunction directKeySignatureSubpackets) + { + this.directKeySignatureSubpackets = directKeySignatureSubpackets; + } + + public void setDefaultFeatures(SignatureSubpacketsFunction features) + { + this.defaultFeatures = features; + } + + public void setSigningSubkeySubpackets(SignatureSubpacketsFunction signingSubkeySubpackets) + { + this.signingSubkeySubpackets = signingSubkeySubpackets; + } + + public void setEncryptionSubkeySubpackets(SignatureSubpacketsFunction encryptionSubkeySubpackets) + { + this.encryptionSubkeySubpackets = encryptionSubkeySubpackets; + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/DoubleBufferedInputStream.java b/pg/src/main/java/org/bouncycastle/openpgp/api/DoubleBufferedInputStream.java new file mode 100644 index 0000000000..63254ec488 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/DoubleBufferedInputStream.java @@ -0,0 +1,194 @@ +package org.bouncycastle.openpgp.api; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Implementation of an {@link InputStream} that double-buffers data from an underlying input stream. + * Upon reaching the end of the underlying data stream, the underlying data stream is + * automatically closed. + * Any exceptions while reading from the underlying input stream cause the {@link DoubleBufferedInputStream} + * to withhold pending data. + * This is done in order to minimize the risk of emitting unauthenticated plaintext, while at the same + * time being somewhat resource-efficient. + * The minimum number of bytes to withhold can be configured ({@link #BUFFER_SIZE} by default). + */ +public class DoubleBufferedInputStream + extends InputStream +{ + private static final int BUFFER_SIZE = 1024 * 1024 * 32; // 32 MiB + private byte[] buf1; + private byte[] buf2; + private int b1Pos; + private int b1Max; + private int b2Max; + private final I in; + private boolean closed = false; + + /** + * Create a {@link DoubleBufferedInputStream}, which buffers twice 32MiB. + * + * @param in input stream + */ + public DoubleBufferedInputStream(I in) + { + this(in, BUFFER_SIZE); + } + + /** + * Create a {@link DoubleBufferedInputStream}, which buffers twice the given buffer size in bytes. + * + * @param in input stream + * @param bufferSize buffer size + */ + public DoubleBufferedInputStream(I in, int bufferSize) + { + if (bufferSize <= 0) + { + throw new IllegalArgumentException("Buffer size cannot be zero nor negative."); + } + this.buf1 = new byte[bufferSize]; + this.buf2 = new byte[bufferSize]; + this.in = in; + b1Pos = -1; // indicate to fill() that we need to initialize + } + + /** + * Return the underlying {@link InputStream}. + * + * @return underlying input stream + */ + public I getInputStream() + { + return in; + } + + /** + * Buffer some data from the underlying {@link InputStream}. + * + * @throws IOException re-throw exceptions from the underlying input stream + */ + private void fill() + throws IOException + { + // init + if (b1Pos == -1) + { + // fill both buffers with data + b1Max = in.read(buf1); + b2Max = in.read(buf2); + + if (b2Max == -1) + { + // data fits into b1 -> close underlying stream + close(); + } + + b1Pos = 0; + return; + } + + // no data + if (b1Max <= 0) + { + return; + } + + // Reached end of buf1 + if (b1Pos == b1Max) + { + // swap buffers + byte[] t = buf1; + buf1 = buf2; + buf2 = t; + b1Max = b2Max; + + // reset reader pos + b1Pos = 0; + + // fill buf2 + try + { + b2Max = in.read(buf2); + // could not fill the buffer, or swallowed an IOException + if (b2Max != buf2.length) + { + // provoke the IOException otherwise swallowed by read(buf) + int i = in.read(); + // no exception was thrown, so either data became available, or EOF + if (i != -1) + { + // data became available, push to buf2 + buf2[b2Max++] = (byte)i; + } + } + } + catch (IOException e) + { + // set buffer max's to -1 to indicate to stop emitting data immediately + b1Max = -1; + b2Max = -1; + close(); + + throw e; + } + + // EOF + if (b2Max == -1) + { + close(); + } + } + } + + @Override + public void close() + throws IOException + { + // close the inner stream only once + if (!closed) + { + closed = true; + in.close(); + } + } + + @Override + public int read() + throws IOException + { + // fill the buffer(s) + fill(); + + // EOF / exception? + if (b1Max == -1) + { + close(); + return -1; + } + + // return byte from the buffer + return buf1[b1Pos++]; + } + + @Override + public int read(byte[] b, int off, int len) + throws IOException + { + // Fill the buffer(s) + fill(); + + // EOF / exception? + if (b1Max == -1) + { + close(); + return -1; + } + + int ret = Math.min(b1Max - b1Pos, len); + // emit data from the buffer + System.arraycopy(buf1, b1Pos, b, off, ret); + b1Pos += ret; + return ret; + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/EncryptedDataPacketType.java b/pg/src/main/java/org/bouncycastle/openpgp/api/EncryptedDataPacketType.java new file mode 100644 index 0000000000..32165157b7 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/EncryptedDataPacketType.java @@ -0,0 +1,99 @@ +package org.bouncycastle.openpgp.api; + +import org.bouncycastle.bcpg.AEADEncDataPacket; +import org.bouncycastle.bcpg.InputStreamPacket; +import org.bouncycastle.bcpg.SymmetricEncDataPacket; +import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket; +import org.bouncycastle.bcpg.UnsupportedPacketVersionException; +import org.bouncycastle.openpgp.PGPEncryptedDataList; +import org.bouncycastle.openpgp.PGPException; + +/** + * Encryption Mode. + */ +public enum EncryptedDataPacketType +{ + /** + * Symmetrically-Encrypted Data packet. + * This method is deprecated, as it does not protect against malleability. + * + * @deprecated + */ + @Deprecated + SED, // deprecated + /** + * Symmetrically-Encrypted-Integrity-Protected Data packet version 1. + * This method protects the message using symmetric encryption as specified in RFC4880. + * Support for this encryption mode is signalled using + * {@link org.bouncycastle.bcpg.sig.Features#FEATURE_MODIFICATION_DETECTION}. + */ + SEIPDv1, // v4 + + /** + * Symmetrically-Encrypted-Integrity-Protected Data packet version 2. + * This method protects the message using an AEAD encryption scheme specified in RFC9580. + * Support for this feature is signalled using {@link org.bouncycastle.bcpg.sig.Features#FEATURE_SEIPD_V2}. + */ + SEIPDv2, // v6 + + /** + * LibrePGP OCB-Encrypted Data packet. + * This method protects the message using an AEAD encryption scheme specified in LibrePGP. + * Support for this feature is signalled using {@link org.bouncycastle.bcpg.sig.Features#FEATURE_AEAD_ENCRYPTED_DATA}. + */ + LIBREPGP_OED // "v5" + ; + + /** + * Detect the type of the PGPEncryptedDataList's encrypted data packet. + * + * @param encDataList encrypted data list + * @return encrypted data packet type + * @throws PGPException if an unexpected data packet is encountered. + */ + public static EncryptedDataPacketType of(PGPEncryptedDataList encDataList) + throws PGPException + { + return of(encDataList.getEncryptedData()); + } + + /** + * Detect the type the provided encrypted data packet. + * + * @param encData encrypted data packet + * @return encrypted data packet type + * @throws PGPException if an unexpected data packet is encountered. + */ + public static EncryptedDataPacketType of(InputStreamPacket encData) + throws PGPException + { + if (encData instanceof SymmetricEncIntegrityPacket) + { + SymmetricEncIntegrityPacket seipd = (SymmetricEncIntegrityPacket) encData; + if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_1) + { + return SEIPDv1; + } + else if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_2) + { + return SEIPDv2; + } + else + { + throw new UnsupportedPacketVersionException("Symmetrically-Encrypted Integrity-Protected Data Packet of unknown version encountered: " + seipd.getVersion()); + } + } + else if (encData instanceof AEADEncDataPacket) + { + return LIBREPGP_OED; + } + else if (encData instanceof SymmetricEncDataPacket) + { + return SED; + } + else + { + throw new PGPException("Unexpected packet type: " + encData.getClass().getName()); + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/KeyPairGeneratorCallback.java b/pg/src/main/java/org/bouncycastle/openpgp/api/KeyPairGeneratorCallback.java index e30bb22cc2..60585ff5dc 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/api/KeyPairGeneratorCallback.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/KeyPairGeneratorCallback.java @@ -7,7 +7,6 @@ /** * Callback to generate a {@link PGPKeyPair} from a {@link PGPKeyPairGenerator} instance. */ -@FunctionalInterface public interface KeyPairGeneratorCallback { /** @@ -19,4 +18,46 @@ public interface KeyPairGeneratorCallback */ PGPKeyPair generateFrom(PGPKeyPairGenerator generator) throws PGPException; + + static class Util + { + public static KeyPairGeneratorCallback primaryKey() + { + return new KeyPairGeneratorCallback() + { + @Override + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException + { + return generator.generatePrimaryKey(); + } + }; + } + + public static KeyPairGeneratorCallback encryptionKey() + { + return new KeyPairGeneratorCallback() + { + @Override + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException + { + return generator.generateEncryptionSubkey(); + } + }; + } + + public static KeyPairGeneratorCallback signingKey() + { + return new KeyPairGeneratorCallback() + { + @Override + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException + { + return generator.generateSigningSubkey(); + } + }; + } + } } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/KeyPassphraseProvider.java b/pg/src/main/java/org/bouncycastle/openpgp/api/KeyPassphraseProvider.java new file mode 100644 index 0000000000..8c8c81eccb --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/KeyPassphraseProvider.java @@ -0,0 +1,132 @@ +package org.bouncycastle.openpgp.api; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.bouncycastle.util.Arrays; + +public interface KeyPassphraseProvider +{ + /** + * Return the passphrase for the given key. + * This callback is only fired, if the key is locked and a passphrase is required to unlock it. + * Returning null means, that the passphrase is not available. + * + * @param key the locked (sub-)key. + * @return passphrase or null + */ + char[] getKeyPassword(OpenPGPKey.OpenPGPSecretKey key); + + class DefaultKeyPassphraseProvider + implements KeyPassphraseProvider + { + private final Map passphraseMap = new HashMap(); + private final List allPassphrases = new ArrayList(); + private KeyPassphraseProvider callback; + + public DefaultKeyPassphraseProvider() + { + + } + + public DefaultKeyPassphraseProvider(OpenPGPKey key, char[] passphrase) + { + allPassphrases.add(passphrase); + + for (Iterator it = key.getSecretKeys().values().iterator(); it.hasNext(); ) + { + OpenPGPKey.OpenPGPSecretKey subkey = (OpenPGPKey.OpenPGPSecretKey)it.next(); + passphraseMap.put(subkey, passphrase); + } + } + + @Override + public char[] getKeyPassword(OpenPGPKey.OpenPGPSecretKey key) + { + if (!key.isLocked()) + { + passphraseMap.put(key, null); + return null; + } + + char[] passphrase = passphraseMap.get(key); + if (passphrase != null) + { + return passphrase; + } + + for (char[] knownPassphrase : allPassphrases) + { + if (key.isPassphraseCorrect(knownPassphrase)) + { + addPassphrase(key, knownPassphrase); + return knownPassphrase; + } + } + + if (callback != null) + { + passphrase = callback.getKeyPassword(key); + addPassphrase(key, passphrase); + } + return passphrase; + } + + public DefaultKeyPassphraseProvider addPassphrase(char[] passphrase) + { + boolean found = false; + for (Iterator it = allPassphrases.iterator(); it.hasNext();) + { + char[] existing = (char[])it.next(); + found |= (Arrays.areEqual(existing, passphrase)); + } + + if (!found) + { + allPassphrases.add(passphrase); + } + return this; + } + + public DefaultKeyPassphraseProvider addPassphrase(OpenPGPKey key, char[] passphrase) + { + for (OpenPGPKey.OpenPGPSecretKey subkey : key.getSecretKeys().values()) + { + if (!subkey.isLocked()) + { + passphraseMap.put(subkey, null); + continue; + } + + char[] existentPassphrase = passphraseMap.get(subkey); + if (existentPassphrase == null || !subkey.isPassphraseCorrect(existentPassphrase)) + { + passphraseMap.put(subkey, passphrase); + } + } + return this; + } + + public DefaultKeyPassphraseProvider addPassphrase(OpenPGPKey.OpenPGPSecretKey key, char[] passphrase) + { + if (!key.isLocked()) + { + passphraseMap.put(key, null); + return this; + } + + passphraseMap.put(key, passphrase); + + return this; + } + + public DefaultKeyPassphraseProvider setMissingPassphraseCallback(KeyPassphraseProvider callback) + { + this.callback = callback; + return this; + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/MessageEncryptionMechanism.java b/pg/src/main/java/org/bouncycastle/openpgp/api/MessageEncryptionMechanism.java new file mode 100644 index 0000000000..af41b12708 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/MessageEncryptionMechanism.java @@ -0,0 +1,158 @@ +package org.bouncycastle.openpgp.api; + +import org.bouncycastle.bcpg.AEADAlgorithmTags; +import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites; + +/** + * Encryption mode (SEIPDv1 / SEIPDv2 / OED) and algorithms. + */ +public class MessageEncryptionMechanism +{ + private final EncryptedDataPacketType mode; + private final int symmetricKeyAlgorithm; + private final int aeadAlgorithm; + + /** + * Create a {@link MessageEncryptionMechanism} tuple. + * + * @param mode encryption mode (packet type) + * @param symmetricKeyAlgorithm symmetric key algorithm for message encryption + * @param aeadAlgorithm aead algorithm for message encryption + */ + private MessageEncryptionMechanism(EncryptedDataPacketType mode, + int symmetricKeyAlgorithm, + int aeadAlgorithm) + { + this.mode = mode; + this.symmetricKeyAlgorithm = symmetricKeyAlgorithm; + this.aeadAlgorithm = aeadAlgorithm; + } + + public EncryptedDataPacketType getMode() + { + return mode; + } + + public int getSymmetricKeyAlgorithm() + { + return symmetricKeyAlgorithm; + } + + public int getAeadAlgorithm() + { + return aeadAlgorithm; + } + + /** + * The data will not be encrypted. + * Useful for sign-only operations. + * + * @return unencrypted encryption setup + */ + public static MessageEncryptionMechanism unencrypted() + { + int none = 0; + return new MessageEncryptionMechanism(EncryptedDataPacketType.SEIPDv1, + SymmetricKeyAlgorithmTags.NULL, none); + } + + @Deprecated + public static MessageEncryptionMechanism legacyEncryptedNonIntegrityProtected(int symmetricKeyAlgorithm) + { + int none = 0; + return new MessageEncryptionMechanism(EncryptedDataPacketType.SED, symmetricKeyAlgorithm, none); + } + + /** + * The data will be encrypted and integrity protected using a SEIPDv1 packet. + * + * @param symmetricKeyAlgorithm symmetric cipher algorithm for message encryption + * @return sym. enc. integrity protected encryption setup + */ + public static MessageEncryptionMechanism integrityProtected(int symmetricKeyAlgorithm) + { + int none = 0; + return new MessageEncryptionMechanism(EncryptedDataPacketType.SEIPDv1, symmetricKeyAlgorithm, none); + } + + /** + * The data will be OCB-encrypted as specified by the non-standard LibrePGP document. + * + * @param symmetricKeyAlgorithm symmetric key algorithm which will be combined with OCB to form + * an OCB-encrypted data packet + * @return LibrePGP OCB encryption setup + */ + public static MessageEncryptionMechanism librePgp(int symmetricKeyAlgorithm) + { + return new MessageEncryptionMechanism(EncryptedDataPacketType.LIBREPGP_OED, + symmetricKeyAlgorithm, AEADAlgorithmTags.OCB); + } + + /** + * The data will be AEAD-encrypted using the method described in RFC9580. + * + * @param symmetricKeyAlgorithm symmetric cipher algorithm + * @param aeadAlgorithm AEAD algorithm + * @return AEAD encryption setup + */ + public static MessageEncryptionMechanism aead(int symmetricKeyAlgorithm, int aeadAlgorithm) + { + return new MessageEncryptionMechanism(EncryptedDataPacketType.SEIPDv2, symmetricKeyAlgorithm, aeadAlgorithm); + } + + public static MessageEncryptionMechanism aead(PreferredAEADCiphersuites.Combination combination) + { + return aead(combination.getSymmetricAlgorithm(), combination.getAeadAlgorithm()); + } + + /** + * Return true, if the message will be encrypted. + * + * @return is encrypted + */ + public boolean isEncrypted() + { + return symmetricKeyAlgorithm != SymmetricKeyAlgorithmTags.NULL; + } + + @Override + public int hashCode() + { + return mode.hashCode() + + 13 * symmetricKeyAlgorithm + + 17 * aeadAlgorithm; + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (this == obj) + { + return true; + } + if (!(obj instanceof MessageEncryptionMechanism)) + { + return false; + } + MessageEncryptionMechanism m = (MessageEncryptionMechanism)obj; + return getMode() == m.getMode() + && getSymmetricKeyAlgorithm() == m.getSymmetricKeyAlgorithm() + && getAeadAlgorithm() == m.getAeadAlgorithm(); + } + + @Override + public String toString() + { + String out = mode.name() + "[cipher: " + symmetricKeyAlgorithm; + if (mode == EncryptedDataPacketType.SEIPDv2 || mode == EncryptedDataPacketType.LIBREPGP_OED) + { + out += " aead: " + aeadAlgorithm; + } + return out + "]"; + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/MissingMessagePassphraseCallback.java b/pg/src/main/java/org/bouncycastle/openpgp/api/MissingMessagePassphraseCallback.java new file mode 100644 index 0000000000..b3ff38af90 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/MissingMessagePassphraseCallback.java @@ -0,0 +1,13 @@ +package org.bouncycastle.openpgp.api; + +public interface MissingMessagePassphraseCallback +{ + /** + * Return a passphrase for message decryption. + * Returning null means, that no passphrase is available and decryption is aborted. + * + * @return passphrase + */ + char[] getMessagePassphrase(); + +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPApi.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPApi.java new file mode 100644 index 0000000000..db6e63d410 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPApi.java @@ -0,0 +1,240 @@ +package org.bouncycastle.openpgp.api; + +import java.util.Date; + +import org.bouncycastle.bcpg.PublicKeyPacket; +import org.bouncycastle.openpgp.PGPException; + +/** + * Main entry to the high level OpenPGP API. + */ +public abstract class OpenPGPApi +{ + private final OpenPGPImplementation implementation; + private final OpenPGPPolicy policy; + + /** + * Instantiate an {@link OpenPGPApi} based on the given {@link OpenPGPImplementation}. + * + * @param implementation OpenPGP implementation + */ + public OpenPGPApi(OpenPGPImplementation implementation) + { + this(implementation, implementation.policy()); + } + + /** + * Instantiate an {@link OpenPGPApi} object, passing in an {@link OpenPGPImplementation} and custom + * {@link OpenPGPPolicy}. + * + * @param implementation OpenPGP implementation + * @param policy algorithm policy + */ + public OpenPGPApi(OpenPGPImplementation implementation, OpenPGPPolicy policy) + { + this.implementation = implementation; + this.policy = policy; + } + + /** + * Return an {@link OpenPGPKeyReader} which can be used to parse binary or ASCII armored + * {@link OpenPGPKey OpenPGPKeys} or {@link OpenPGPCertificate OpenPGPCertificates}. + * + * @return key reader + */ + public OpenPGPKeyReader readKeyOrCertificate() + { + return new OpenPGPKeyReader(implementation, policy); + } + + /** + * Return an {@link OpenPGPKeyGenerator} which can be used to generate {@link OpenPGPKey OpenPGPKeys}. + * This method returns a generator for OpenPGP v6 keys as defined by rfc9580. + * + * @return key generator + * @throws PGPException if the key generator cannot be set up + */ + public OpenPGPKeyGenerator generateKey() + throws PGPException + { + return generateKey(PublicKeyPacket.VERSION_6); + } + + /** + * Return an {@link OpenPGPKeyGenerator} which can be used to generate {@link OpenPGPKey OpenPGPKeys} + * of the given key version. + * Valid version numbers are: + *
      + *
    • {@link PublicKeyPacket#VERSION_4} (rfc4880)
    • + *
    • {@link PublicKeyPacket#VERSION_6} (rfc9580)
    • + *
    • {@link PublicKeyPacket#LIBREPGP_5} (LibrePGP; experimental)
    • + *
    + * + * @param version key version number + * @return key generator + * @throws PGPException if the key generator cannot be set up + */ + public abstract OpenPGPKeyGenerator generateKey(int version) + throws PGPException; + + /** + * Return an {@link OpenPGPKeyGenerator} which can be used to generate {@link OpenPGPKey OpenPGPKeys}. + * The key and signatures will have a creation time of the passed creationTime. + * This method returns a generator for OpenPGP v6 keys as defined by rfc9580. + * + * @param creationTime key + signature creation time + * @return key generator + * @throws PGPException if the key generator cannot be set up + */ + public OpenPGPKeyGenerator generateKey(Date creationTime) + throws PGPException + { + return generateKey(PublicKeyPacket.VERSION_6, creationTime); + } + + /** + * Return an {@link OpenPGPKeyGenerator} which can be used to generate {@link OpenPGPKey OpenPGPKeys} + * of the given key version. + * The key and signatures will have a creation time of the passed creationTime. + * Valid version numbers are: + *
      + *
    • {@link PublicKeyPacket#VERSION_4} (rfc4880)
    • + *
    • {@link PublicKeyPacket#VERSION_6} (rfc9580)
    • + *
    • {@link PublicKeyPacket#LIBREPGP_5} (LibrePGP; experimental)
    • + *
    + * + * @param version key version number + * @param creationTime key + signatures creation time + * @return key generator + * @throws PGPException if the key generator cannot be set up + */ + public abstract OpenPGPKeyGenerator generateKey(int version, + Date creationTime) + throws PGPException; + + /** + * Return an {@link OpenPGPKeyGenerator} which can be used to generate {@link OpenPGPKey OpenPGPKeys}. + * The key and signatures will have a creation time of the passed creationTime. + * If aeadProtection is true, the key will use AEAD+Argon2 to protect the secret key material, + * otherwise it will use salted+iterated CFB mode. + * This method returns a generator for OpenPGP v6 keys as defined by rfc9580. + * + * @param creationTime key + signature creation time + * @param aeadProtection whether to use AEAD or CFB protection + * @return key generator + * @throws PGPException if the key generator cannot be set up + */ + public OpenPGPKeyGenerator generateKey(Date creationTime, boolean aeadProtection) + throws PGPException + { + return generateKey(PublicKeyPacket.VERSION_6, creationTime, aeadProtection); + } + + /** + * Return an {@link OpenPGPKeyGenerator} which can be used to generate {@link OpenPGPKey OpenPGPKeys} + * of the given key version. + * The key and signatures will have a creation time of the passed creationTime. + * If aeadProtection is true, the key will use AEAD+Argon2 to protect the secret key material, + * otherwise it will use salted+iterated CFB mode. + * Valid version numbers are: + *
      + *
    • {@link PublicKeyPacket#VERSION_4} (rfc4880)
    • + *
    • {@link PublicKeyPacket#VERSION_6} (rfc9580)
    • + *
    • {@link PublicKeyPacket#LIBREPGP_5} (LibrePGP; experimental)
    • + *
    + * + * @param creationTime key + signature creation time + * @param aeadProtection whether to use AEAD or CFB protection + * @return key generator + * @throws PGPException if the key generator cannot be set up + */ + public abstract OpenPGPKeyGenerator generateKey(int version, + Date creationTime, + boolean aeadProtection) + throws PGPException; + + /** + * Create an inline-signed and/or encrypted OpenPGP message. + * + * @return message generator + */ + public OpenPGPMessageGenerator signAndOrEncryptMessage() + { + return new OpenPGPMessageGenerator(implementation, policy); + } + + /** + * Create one or more detached signatures over some data. + * + * @return signature generator + */ + public OpenPGPDetachedSignatureGenerator createDetachedSignature() + { + return new OpenPGPDetachedSignatureGenerator(implementation, policy); + } + + /** + * Decrypt and/or verify an OpenPGP message. + * + * @return message processor + */ + public OpenPGPMessageProcessor decryptAndOrVerifyMessage() + { + return new OpenPGPMessageProcessor(implementation, policy); + } + + /** + * Verify detached signatures over some data. + * + * @return signature processor + */ + public OpenPGPDetachedSignatureProcessor verifyDetachedSignature() + { + return new OpenPGPDetachedSignatureProcessor(implementation, policy); + } + + public OpenPGPKeyEditor editKey(OpenPGPKey key) + throws PGPException + { + return editKey(key, (char[]) null); + } + + public OpenPGPKeyEditor editKey(OpenPGPKey key, final char[] primaryKeyPassphrase) + throws PGPException + { + return new OpenPGPKeyEditor( + key, + new KeyPassphraseProvider() + { + @Override + public char[] getKeyPassword(OpenPGPKey.OpenPGPSecretKey key) + { + return primaryKeyPassphrase; + } + }, + implementation, + policy); + } + + /** + * Modify an {@link OpenPGPKey}. + * + * @param key OpenPGP key + * @return key editor + */ + public OpenPGPKeyEditor editKey(OpenPGPKey key, KeyPassphraseProvider primaryKeyPassphraseProvider) + throws PGPException + { + return new OpenPGPKeyEditor(key, primaryKeyPassphraseProvider, implementation, policy); + } + + /** + * Return the underlying {@link OpenPGPImplementation} of this API handle. + * + * @return OpenPGP implementation + */ + public OpenPGPImplementation getImplementation() + { + return implementation; + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPCertificate.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPCertificate.java new file mode 100644 index 0000000000..19b954afa2 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPCertificate.java @@ -0,0 +1,3649 @@ +package org.bouncycastle.openpgp.api; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.bouncycastle.bcpg.ArmoredOutputStream; +import org.bouncycastle.bcpg.BCPGInputStream; +import org.bouncycastle.bcpg.BCPGOutputStream; +import org.bouncycastle.bcpg.FingerprintUtil; +import org.bouncycastle.bcpg.KeyIdentifier; +import org.bouncycastle.bcpg.PacketFormat; +import org.bouncycastle.bcpg.PublicKeyUtils; +import org.bouncycastle.bcpg.SignatureSubpacket; +import org.bouncycastle.bcpg.SignatureSubpacketTags; +import org.bouncycastle.bcpg.sig.Features; +import org.bouncycastle.bcpg.sig.KeyExpirationTime; +import org.bouncycastle.bcpg.sig.KeyFlags; +import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites; +import org.bouncycastle.bcpg.sig.PreferredAlgorithms; +import org.bouncycastle.bcpg.sig.PrimaryUserID; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPKeyRing; +import org.bouncycastle.openpgp.PGPObjectFactory; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPPublicKeyRing; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureException; +import org.bouncycastle.openpgp.PGPSignatureList; +import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; +import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector; +import org.bouncycastle.openpgp.PGPUtil; +import org.bouncycastle.openpgp.api.exception.IncorrectOpenPGPSignatureException; +import org.bouncycastle.openpgp.api.exception.MalformedOpenPGPSignatureException; +import org.bouncycastle.openpgp.api.exception.MissingIssuerCertException; +import org.bouncycastle.openpgp.api.util.UTCUtil; +import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider; + +/** + * OpenPGP certificates (TPKs - transferable public keys) are long-living structures that may change during + * their lifetime. A key-holder may add new components like subkeys or identities, along with associated + * binding self-signatures to the certificate and old components may expire / get revoked at some point. + * Since any such changes may have an influence on whether a data signature is valid at a given time, or what subkey + * should be used when generating an encrypted / signed message, an API is needed that provides a view on the + * certificate that takes into consideration a relevant window in time. + *

    + * Compared to a {@link PGPPublicKeyRing}, an {@link OpenPGPCertificate} has been evaluated at (or rather for) + * a given evaluation time. It offers a clean API for accessing the key-holder's preferences at a specific + * point in time and makes sure, that relevant self-signatures on certificate components are validated and verified. + * + * @see OpenPGP for Application Developers - Chapter 4 + * for background information on the terminology used in this class. + */ +public class OpenPGPCertificate +{ + final OpenPGPImplementation implementation; + final OpenPGPPolicy policy; + + protected PGPKeyRing keyRing; + + private final OpenPGPPrimaryKey primaryKey; + private final Map subkeys; + + // Note: get() needs to be accessed with OpenPGPCertificateComponent.getPublicComponent() to ensure + // proper functionality with secret key components. + private final Map componentSignatureChains; + + /** + * Instantiate an {@link OpenPGPCertificate} from a passed {@link PGPKeyRing} using the default + * {@link OpenPGPImplementation} and its {@link OpenPGPPolicy}. + * + * @param keyRing key ring + */ + public OpenPGPCertificate(PGPKeyRing keyRing) + { + this(keyRing, OpenPGPImplementation.getInstance()); + } + + /** + * Instantiate an {@link OpenPGPCertificate} from a parsed {@link PGPKeyRing} + * using the provided {@link OpenPGPImplementation} and its {@link OpenPGPPolicy}. + * + * @param keyRing public key ring + * @param implementation OpenPGP implementation + */ + public OpenPGPCertificate(PGPKeyRing keyRing, OpenPGPImplementation implementation) + { + this(keyRing, implementation, implementation.policy()); + } + + /** + * Instantiate an {@link OpenPGPCertificate} from a parsed {@link PGPKeyRing} + * using the provided {@link OpenPGPImplementation} and provided {@link OpenPGPPolicy}. + * + * @param keyRing public key ring + * @param implementation OpenPGP implementation + * @param policy OpenPGP policy + */ + public OpenPGPCertificate(PGPKeyRing keyRing, OpenPGPImplementation implementation, OpenPGPPolicy policy) + { + this.implementation = implementation; + this.policy = policy; + + this.keyRing = keyRing; + this.subkeys = new LinkedHashMap(); + this.componentSignatureChains = new LinkedHashMap(); + + Iterator rawKeys = keyRing.getPublicKeys(); + + PGPPublicKey rawPrimaryKey = rawKeys.next(); + this.primaryKey = new OpenPGPPrimaryKey(rawPrimaryKey, this); + processPrimaryKey(primaryKey); + + while (rawKeys.hasNext()) + { + PGPPublicKey rawSubkey = rawKeys.next(); + OpenPGPSubkey subkey = new OpenPGPSubkey(rawSubkey, this); + subkeys.put(rawSubkey.getKeyIdentifier(), subkey); + processSubkey(subkey); + } + } + + /** + * Return true, if this object is an {@link OpenPGPKey}, false otherwise. + * + * @return true if this is a secret key + */ + public boolean isSecretKey() + { + return false; + } + + /** + * Return a {@link List} of all {@link OpenPGPUserId OpenPGPUserIds} on the certificate, regardless of their + * validity. + * + * @return all user ids + */ + public List getAllUserIds() + { + return getPrimaryKey().getUserIDs(); + } + + /** + * Return a {@link List} of all valid {@link OpenPGPUserId OpenPGPUserIds} on the certificate. + * + * @return valid user ids + */ + public List getValidUserIds() + { + return getValidUserIds(new Date()); + } + + /** + * Return a {@link List} containing all {@link OpenPGPUserId OpenPGPUserIds} that are valid at the given + * evaluation time. + * + * @param evaluationTime reference time + * @return user ids that are valid at the given evaluation time + */ + public List getValidUserIds(Date evaluationTime) + { + return getPrimaryKey().getValidUserIDs(evaluationTime); + } + + /** + * Get a {@link Map} of all public {@link OpenPGPComponentKey component keys} keyed by their {@link KeyIdentifier}. + * + * @return all public keys + */ + public Map getPublicKeys() + { + Map keys = new LinkedHashMap(); + keys.put(primaryKey.getKeyIdentifier(), primaryKey); + keys.putAll(subkeys); + return keys; + } + + /** + * Return the primary key of the certificate. + * + * @return primary key + */ + public OpenPGPPrimaryKey getPrimaryKey() + { + return primaryKey; + } + + /** + * Return a {@link Map} containing the subkeys of this certificate, keyed by their {@link KeyIdentifier}. + * Note: This map does NOT contain the primary key ({@link #getPrimaryKey()}). + * + * @return subkeys + */ + public Map getSubkeys() + { + return new LinkedHashMap(subkeys); + } + + /** + * Return a {@link List} containing all {@link OpenPGPComponentKey component keys} that carry any of the + * given key flags at evaluation time. + * + * Note: To get all component keys that have EITHER {@link KeyFlags#ENCRYPT_COMMS} OR {@link KeyFlags#ENCRYPT_STORAGE}, + * call this method like this: + *

    +     * keys = getComponentKeysWithFlag(date, KeyFlags.ENCRYPT_COMMS, KeyFlags.ENCRYPT_STORAGE);
    +     * 
    + * If you instead want to access all keys, that have BOTH flags, you need to
    &
    both flags: + *
    +     * keys = getComponentKeysWithFlag(date, KeyFlags.ENCRYPT_COMMS & KeyFlags.ENCRYPT_STORAGE);
    +     * 
    + * + * @param evaluationTime reference time + * @param keyFlags key flags + * @return list of keys that carry any of the given key flags at evaluation time + */ + public List getComponentKeysWithFlag(Date evaluationTime, final int... keyFlags) + { + return filterKeys(evaluationTime, new KeyFilter() + { + @Override + public boolean test(OpenPGPComponentKey key, Date time) + { + return key.hasKeyFlags(time, keyFlags); + } + }); + } + + /** + * Return a {@link List} containing all {@link OpenPGPCertificateComponent components} of the certificate. + * Components are primary key, subkeys and identities (user-ids, user attributes). + * + * @return list of components + */ + public List getComponents() + { + return new ArrayList(componentSignatureChains.keySet()); + } + + /** + * Return all {@link OpenPGPComponentKey OpenPGPComponentKeys} in the certificate. + * The return value is a {@link List} containing the {@link OpenPGPPrimaryKey} and all + * {@link OpenPGPSubkey OpenPGPSubkeys}. + * + * @return list of all component keys + */ + public List getKeys() + { + List keys = new ArrayList(); + keys.add(primaryKey); + keys.addAll(subkeys.values()); + return keys; + } + + /** + * Return a {@link List} of all {@link OpenPGPComponentKey component keys} that are valid right now. + * + * @return all valid keys + */ + public List getValidKeys() + { + return getValidKeys(new Date()); + } + + /** + * Return a {@link List} of all {@link OpenPGPComponentKey component keys} that are valid at the given + * evaluation time. + * + * @param evaluationTime reference time + * @return all keys that are valid at evaluation time + */ + public List getValidKeys(Date evaluationTime) + { + return filterKeys(evaluationTime, new KeyFilter() + { + @Override + public boolean test(OpenPGPComponentKey key, Date time) + { + return true; + } + }); + } + + /** + * Return the {@link OpenPGPComponentKey} identified by the passed in {@link KeyIdentifier}. + * + * @param identifier key identifier + * @return component key + */ + public OpenPGPComponentKey getKey(KeyIdentifier identifier) + { + if (identifier.matchesExplicit(getPrimaryKey().getPGPPublicKey().getKeyIdentifier())) + { + return primaryKey; + } + + return subkeys.get(identifier); + } + + /** + * Return the {@link OpenPGPComponentKey} that likely issued the passed in {@link PGPSignature}. + * + * @param signature signature + * @return issuer (sub-)key + */ + public OpenPGPComponentKey getSigningKeyFor(PGPSignature signature) + { + List keyIdentifiers = signature.getKeyIdentifiers(); + + // Subkey binding signatures do not require issuer + int type = signature.getSignatureType(); + if (type == PGPSignature.SUBKEY_BINDING || + type == PGPSignature.SUBKEY_REVOCATION) + { + return primaryKey; + } + + // issuer is primary key + if (KeyIdentifier.matches(keyIdentifiers, getPrimaryKey().getKeyIdentifier(), true)) + { + return primaryKey; + } + + for (Iterator it = subkeys.keySet().iterator(); it.hasNext(); ) + { + KeyIdentifier subkeyIdentifier = it.next(); + if (KeyIdentifier.matches(keyIdentifiers, subkeyIdentifier, true)) + { + return subkeys.get(subkeyIdentifier); + } + } + + return null; // external issuer + } + + /** + * Return the {@link PGPKeyRing} that this certificate is based on. + * + * @return underlying key ring + */ + public PGPKeyRing getPGPKeyRing() + { + return keyRing; + } + + /** + * Return the underlying {@link PGPPublicKeyRing}. + * + * @return public keys + */ + public PGPPublicKeyRing getPGPPublicKeyRing() + { + if (keyRing instanceof PGPPublicKeyRing) + { + return (PGPPublicKeyRing)keyRing; + } + + List list = new ArrayList(); + for (Iterator it = keyRing.getPublicKeys(); it.hasNext(); ) + { + list.add(it.next()); + } + return new PGPPublicKeyRing(list); + } + + /** + * Return the {@link KeyIdentifier} of the certificates primary key. + * + * @return primary key identifier + */ + public KeyIdentifier getKeyIdentifier() + { + return primaryKey.getKeyIdentifier(); + } + + /** + * Return a list of ALL (sub-)key's identifiers, including those of expired / revoked / unbound keys. + * + * @return all keys identifiers + */ + public List getAllKeyIdentifiers() + { + List identifiers = new ArrayList(); + for (Iterator it = keyRing.getPublicKeys(); it.hasNext(); ) + { + PGPPublicKey key = it.next(); + identifiers.add(key.getKeyIdentifier()); + } + return identifiers; + } + + /** + * Return the current self-certification signature. + * This is either a DirectKey signature on the primary key, or the latest self-certification on + * a {@link OpenPGPUserId}. + * + * @return latest certification signature + */ + public OpenPGPComponentSignature getCertification() + { + return getCertification(new Date()); + } + + /** + * Return the most recent self-certification signature at evaluation time. + * This is either a DirectKey signature on the primary key, or the (at evaluation time) latest + * self-certification on an {@link OpenPGPUserId}. + * + * @param evaluationTime reference time + * @return latest certification signature + */ + public OpenPGPComponentSignature getCertification(Date evaluationTime) + { + return primaryKey.getCertification(evaluationTime); + } + + /** + * Return the most recent revocation signature on the certificate. + * This is either a KeyRevocation signature on the primary key, or the latest certification revocation + * signature on an {@link OpenPGPUserId}. + * + * @return latest certification revocation + */ + public OpenPGPComponentSignature getRevocation() + { + return getRevocation(new Date()); + } + + /** + * Return the (at evaluation time) most recent revocation signature on the certificate. + * This is either a KeyRevocation signature on the primary key, or the latest certification revocation + * signature on an {@link OpenPGPUserId}. + * + * @param evaluationTime reference time + * @return latest certification revocation + */ + public OpenPGPComponentSignature getRevocation(Date evaluationTime) + { + return primaryKey.getRevocation(evaluationTime); + } + + /** + * Return the last time, the key was modified (before right now). + * A modification is the addition of a new subkey, or key signature. + * + * @return last modification time + */ + public Date getLastModificationDate() + { + return getLastModificationDateAt(new Date()); + } + + /** + * Return the last time, the key was modified before or at the given evaluation time. + * + * @param evaluationTime evaluation time + * @return last modification time before or at evaluation time + */ + public Date getLastModificationDateAt(Date evaluationTime) + { + Date latestModification = null; + // Signature creation times + for (Iterator it = getComponents().iterator(); it.hasNext(); ) + { + OpenPGPSignatureChains componentChains = getAllSignatureChainsFor(it.next()); + + componentChains = componentChains.getChainsAt(evaluationTime); + for (Iterator it2 = componentChains.iterator(); it2.hasNext(); ) + { + for (Iterator it3 = it2.next().iterator(); it3.hasNext(); ) + { + OpenPGPSignatureChain.Link link = it3.next(); + if (latestModification == null || link.since().after(latestModification)) + { + latestModification = link.since(); + } + } + } + } + + if (latestModification != null) + { + return latestModification; + } + + // Key creation times + for (Iterator it = getKeys().iterator(); it.hasNext(); ) + { + OpenPGPComponentKey key = it.next(); + if (key.getCreationTime().after(evaluationTime)) + { + continue; + } + + if (latestModification == null || key.getCreationTime().after(latestModification)) + { + latestModification = key.getCreationTime(); + } + } + return latestModification; + } + + /** + * Join two copies of the same {@link OpenPGPCertificate}, merging its {@link OpenPGPCertificateComponent components} + * into a single instance. + * The ASCII armored {@link String} might contain more than one {@link OpenPGPCertificate}. + * Items that are not a copy of the base certificate are silently ignored. + * + * @param certificate base certificate + * @param armored ASCII armored {@link String} containing one or more copies of the same certificate, + * possibly containing a different set of components + * @return merged certificate + * @throws IOException if the armored data cannot be processed + * @throws PGPException if a protocol level error occurs + */ + public static OpenPGPCertificate join(OpenPGPCertificate certificate, String armored) + throws IOException, PGPException + { + ByteArrayInputStream bIn = new ByteArrayInputStream(armored.getBytes()); + InputStream decoderStream = PGPUtil.getDecoderStream(bIn); + BCPGInputStream wrapper = BCPGInputStream.wrap(decoderStream); + PGPObjectFactory objFac = certificate.implementation.pgpObjectFactory(wrapper); + + Object next; + while ((next = objFac.nextObject()) != null) + { + if (next instanceof PGPPublicKeyRing) + { + PGPPublicKeyRing publicKeys = (PGPPublicKeyRing)next; + OpenPGPCertificate otherCert = new OpenPGPCertificate(publicKeys, certificate.implementation); + try + { + return join(certificate, otherCert); + } + catch (IllegalArgumentException e) + { + // skip over wrong certificate + } + } + + else if (next instanceof PGPSecretKeyRing) + { + throw new IllegalArgumentException("Joining with a secret key is not supported."); + } + + else if (next instanceof PGPSignatureList) + { + // parse and join delegations / revocations + // those are signatures of type DIRECT_KEY or KEY_REVOCATION issued either by the primary key itself + // (self-signatures) or by a 3rd party (delegations / delegation revocations) + PGPSignatureList signatures = (PGPSignatureList)next; + + PGPPublicKeyRing publicKeys = certificate.getPGPPublicKeyRing(); + PGPPublicKey primaryKey = publicKeys.getPublicKey(); + for (Iterator it = signatures.iterator(); it.hasNext(); ) + { + primaryKey = PGPPublicKey.addCertification(primaryKey, it.next()); + } + publicKeys = PGPPublicKeyRing.insertPublicKey(publicKeys, primaryKey); + return new OpenPGPCertificate(publicKeys, certificate.implementation); + } + } + return null; + } + + /** + * Join two copies of the same {@link OpenPGPCertificate}, merging its {@link OpenPGPCertificateComponent components} + * into a single instance. + * + * @param certificate base certificate + * @param other copy of the same certificate, potentially carrying a different set of components + * @return merged certificate + * @throws PGPException if a protocol level error occurs + */ + public static OpenPGPCertificate join(OpenPGPCertificate certificate, OpenPGPCertificate other) + throws PGPException + { + PGPPublicKeyRing joined = PGPPublicKeyRing.join( + certificate.getPGPPublicKeyRing(), other.getPGPPublicKeyRing()); + return new OpenPGPCertificate(joined, certificate.implementation); + } + + /** + * Return the primary keys fingerprint in binary format. + * + * @return primary key fingerprint + */ + public byte[] getFingerprint() + { + return primaryKey.getPGPPublicKey().getFingerprint(); + } + + /** + * Return the primary keys fingerprint as a pretty-printed {@link String}. + * + * @return pretty-printed primary key fingerprint + */ + public String getPrettyFingerprint() + { + return FingerprintUtil.prettifyFingerprint(getFingerprint()); + } + + /** + * Return an ASCII armored {@link String} containing the certificate. + * + * @return armored certificate + * @throws IOException if the cert cannot be encoded + */ + public String toAsciiArmoredString() + throws IOException + { + return toAsciiArmoredString(PacketFormat.ROUNDTRIP); + } + + /** + * Return an ASCII armored {@link String} containing the certificate. + * + * @param packetFormat packet length encoding format + * @return armored certificate + * @throws IOException if the cert cannot be encoded + */ + public String toAsciiArmoredString(PacketFormat packetFormat) + throws IOException + { + ArmoredOutputStream.Builder armorBuilder = ArmoredOutputStream.builder() + .clearHeaders(); + // Add fingerprint comment + armorBuilder.addSplitMultilineComment(getPrettyFingerprint()); + + // Add user-id comments + for (Iterator it = getPrimaryKey().getUserIDs().iterator(); it.hasNext(); ) + { + armorBuilder.addEllipsizedComment(it.next().getUserId()); + } + + return toAsciiArmoredString(packetFormat, armorBuilder); + } + + /** + * Return an ASCII armored {@link String} containing the certificate. + * The {@link ArmoredOutputStream.Builder} can be used to customize the ASCII armor (headers, CRC etc.). + * + * @param packetFormat packet length encoding format + * @param armorBuilder builder for the ASCII armored output stream + * @return armored certificate + * @throws IOException if the cert cannot be encoded + */ + public String toAsciiArmoredString(PacketFormat packetFormat, ArmoredOutputStream.Builder armorBuilder) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ArmoredOutputStream aOut = armorBuilder.build(bOut); + + aOut.write(getEncoded(packetFormat)); + aOut.close(); + return bOut.toString(); + } + + /** + * Return a byte array containing the binary representation of the certificate. + * + * @return binary encoded certificate + * @throws IOException if the certificate cannot be encoded + */ + public byte[] getEncoded() + throws IOException + { + return getEncoded(PacketFormat.ROUNDTRIP); + } + + /** + * Return a byte array containing the binary representation of the certificate, encoded using the + * given packet length encoding format. + * + * @param format packet length encoding format + * @return binary encoded certificate + * @throws IOException if the certificate cannot be encoded + */ + public byte[] getEncoded(PacketFormat format) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut, format); + + // Make sure we export a TPK + List list = new ArrayList(); + for (Iterator it = getPGPKeyRing().getPublicKeys(); it.hasNext(); ) + { + list.add(it.next()); + } + PGPPublicKeyRing publicKeys = new PGPPublicKeyRing(list); + + publicKeys.encode(pOut, true); + pOut.close(); + return bOut.toByteArray(); + } + + private OpenPGPSignatureChain getSignatureChainFor(OpenPGPCertificateComponent component, + OpenPGPComponentKey origin, + Date evaluationDate) + { + // Check if there are signatures at all for the component + OpenPGPSignatureChains chainsForComponent = getAllSignatureChainsFor(component); + boolean isPrimaryKey = component == getPrimaryKey(); + if (isPrimaryKey && chainsForComponent.getCertificationAt(evaluationDate) == null) + { + // If cert has no direct-key signatures, consider primary UID bindings instead + OpenPGPUserId primaryUserId = getPrimaryUserId(evaluationDate); + if (primaryUserId != null) + { + chainsForComponent.addAll(getAllSignatureChainsFor(primaryUserId)); + } + } + + // Isolate chains which originate from the passed origin key component + OpenPGPSignatureChains fromOrigin = chainsForComponent.fromOrigin(origin); + if (fromOrigin == null) + { + return null; + } + + // Return chain that currently takes precedence + return fromOrigin.getChainAt(evaluationDate); + } + + /** + * Return all {@link OpenPGPSignatureChain OpenPGPSignatureChains} binding the given + * {@link OpenPGPCertificateComponent}. + * + * @param component certificate component + * @return all chains of the component + */ + private OpenPGPSignatureChains getAllSignatureChainsFor(OpenPGPCertificateComponent component) + { + OpenPGPSignatureChains chains = new OpenPGPSignatureChains(component.getPublicComponent()); + chains.addAll(componentSignatureChains.get(component.getPublicComponent())); + return chains; + } + + /** + * Process the given {@link OpenPGPPrimaryKey}, parsing all its signatures and identities. + * + * @param primaryKey primary key + */ + private void processPrimaryKey(OpenPGPPrimaryKey primaryKey) + { + OpenPGPSignatureChains keySignatureChains = new OpenPGPSignatureChains(primaryKey); + List keySignatures = primaryKey.getKeySignatures(); + + // Key Signatures + addSignaturesToChains(keySignatures, keySignatureChains); + componentSignatureChains.put(primaryKey, keySignatureChains); + + // Identities + for (Iterator it = primaryKey.identityComponents.iterator(); it.hasNext(); ) + { + OpenPGPIdentityComponent identity = it.next(); + OpenPGPSignatureChains identityChains = new OpenPGPSignatureChains(identity); + List bindings; + + if (identity instanceof OpenPGPUserId) + { + bindings = primaryKey.getUserIdSignatures((OpenPGPUserId)identity); + } + else + { + bindings = primaryKey.getUserAttributeSignatures((OpenPGPUserAttribute)identity); + } + addSignaturesToChains(bindings, identityChains); + componentSignatureChains.put(identity, identityChains); + } + } + + /** + * Process the given {@link OpenPGPSubkey}, parsing all its binding signatures. + * + * @param subkey subkey + */ + private void processSubkey(OpenPGPSubkey subkey) + { + List bindingSignatures = subkey.getKeySignatures(); + OpenPGPSignatureChains subkeyChains = new OpenPGPSignatureChains(subkey); + + for (Iterator it = bindingSignatures.iterator(); it.hasNext(); ) + { + OpenPGPComponentSignature sig = it.next(); + OpenPGPComponentKey issuer = subkey.getCertificate().getSigningKeyFor(sig.getSignature()); + if (issuer == null) + { + continue; // external key + } + + OpenPGPSignatureChains issuerChains = getAllSignatureChainsFor(issuer); + if (!issuerChains.chains.isEmpty()) + { + for (Iterator it2 = issuerChains.chains.iterator(); it2.hasNext(); ) + { + subkeyChains.add(it2.next().plus(sig)); + } + } + else + { + subkeyChains.add(new OpenPGPSignatureChain(OpenPGPSignatureChain.Link.create(sig))); + } + } + this.componentSignatureChains.put(subkey, subkeyChains); + } + + /** + * Return true, if the passed in component is - at evaluation time - properly bound to the certificate. + * + * @param component OpenPGP certificate component + * @param evaluationTime evaluation time + * @return true if component is bound at evaluation time, false otherwise + */ + private boolean isBound(OpenPGPCertificateComponent component, + Date evaluationTime) + { + return isBoundBy(component, getPrimaryKey(), evaluationTime); + } + + /** + * Return true, if the passed in component is - at evaluation time - properly bound to the certificate with + * a signature chain originating at the passed in root component. + * + * @param component OpenPGP certificate component + * @param root root certificate component + * @param evaluationTime evaluation time + * @return true if component is bound at evaluation time, originating at root, false otherwise + */ + private boolean isBoundBy(OpenPGPCertificateComponent component, + OpenPGPComponentKey root, + Date evaluationTime) + { + OpenPGPSignature.OpenPGPSignatureSubpacket keyExpiration = + component.getApplyingSubpacket(evaluationTime, SignatureSubpacketTags.KEY_EXPIRE_TIME); + if (keyExpiration != null) + { + KeyExpirationTime kexp = (KeyExpirationTime)keyExpiration.getSubpacket(); + if (kexp.getTime() != 0) + { + OpenPGPComponentKey key = component.getKeyComponent(); + Date expirationDate = new Date(1000 * kexp.getTime() + key.getCreationTime().getTime()); + if (expirationDate.before(evaluationTime)) + { + // Key is expired. + return false; + } + } + } + + try + { + OpenPGPSignatureChain chain = getSignatureChainFor(component, root, evaluationTime); + if (chain == null) + { + // Component is not bound at all + return false; + } + + // Chain needs to be valid (signatures correct) + if (chain.isValid(implementation.pgpContentVerifierBuilderProvider(), policy)) + { + // Chain needs to not contain a revocation signature, otherwise the component is considered revoked + return !chain.isRevocation(); + } + + // Signature is not correct + return false; + } + catch (PGPException e) + { + // Signature verification failed (signature broken?) + return false; + } + } + + /** + * Return a {@link List} containing all currently marked, valid encryption keys. + * + * @return encryption keys + */ + public List getEncryptionKeys() + { + return getEncryptionKeys(new Date()); + } + + /** + * Return a list of all keys that are - at evaluation time - valid encryption keys. + * + * @param evaluationTime evaluation time + * @return encryption keys + */ + public List getEncryptionKeys(Date evaluationTime) + { + return filterKeys(evaluationTime, new KeyFilter() + { + @Override + public boolean test(OpenPGPComponentKey key, Date time) + { + return key.isEncryptionKey(time); + } + }); + } + + /** + * Return a {@link List} containing all currently valid marked signing keys. + * + * @return list of signing keys + */ + public List getSigningKeys() + { + return getSigningKeys(new Date()); + } + + /** + * Return a list of all keys that - at evaluation time - are validly marked as signing keys. + * + * @param evaluationTime evaluation time + * @return list of signing keys + */ + public List getSigningKeys(Date evaluationTime) + { + return filterKeys(evaluationTime, new KeyFilter() + { + @Override + public boolean test(OpenPGPComponentKey key, Date time) + { + return key.isSigningKey(time); + } + }); + } + + /** + * Return a {@link List} containing all currently valid marked certification keys. + * + * @return list of certification keys + */ + public List getCertificationKeys() + { + return getCertificationKeys(new Date()); + } + + /** + * Return a list of all keys that - at evaluation time - are validly marked as certification keys. + * + * @param evaluationTime evaluation time + * @return list of certification keys + */ + public List getCertificationKeys(Date evaluationTime) + { + return filterKeys(evaluationTime, new KeyFilter() + { + @Override + public boolean test(OpenPGPComponentKey key, Date time) + { + return key.isCertificationKey(time); + } + }); + } + + /** + * Return {@link OpenPGPSignatureChains} that contain preference information. + * + * @return signature chain containing certificate-wide preferences (typically DK signature) + */ + private OpenPGPSignatureChain getPreferenceSignature(Date evaluationTime) + { + OpenPGPSignatureChain directKeyBinding = getPrimaryKey().getSignatureChains() + .fromOrigin(getPrimaryKey()) + .getCertificationAt(evaluationTime); + + if (directKeyBinding != null) + { + return directKeyBinding; + } + + List uidBindings = new ArrayList(); + for (Iterator it = getPrimaryKey().getUserIDs().iterator(); it.hasNext(); ) + { + OpenPGPSignatureChain uidBinding = getAllSignatureChainsFor(it.next()) + .fromOrigin(getPrimaryKey()).getCertificationAt(evaluationTime); + + if (uidBinding != null) + { + uidBindings.add(uidBinding); + } + } + + //uidBindings.sort(Comparator.comparing(OpenPGPSignatureChain::getSince).reversed()); + uidBindings.sort(new Comparator() + { + @Override + public int compare(OpenPGPSignatureChain o1, OpenPGPSignatureChain o2) + { + // Reverse comparison for descending order (mimics .reversed()) + return o2.getSince().compareTo(o1.getSince()); + } + }); + for (Iterator it = uidBindings.iterator(); it.hasNext(); ) + { + OpenPGPSignatureChain binding = it.next(); + PGPSignature sig = binding.getSignature().getSignature(); + if (sig.getHashedSubPackets().isPrimaryUserID()) + { + return binding; + } + } + + return uidBindings.isEmpty() ? null : uidBindings.get(0); + } + + /** + * Return all identities ({@link OpenPGPUserId User IDs}, {@link OpenPGPUserAttribute User Attributes} + * of the certificate. + * + * @return identities + */ + public List getIdentities() + { + return new ArrayList(primaryKey.identityComponents); + } + + /** + * Return the current primary {@link OpenPGPUserId} of the certificate. + * + * @return primary user id + */ + public OpenPGPUserId getPrimaryUserId() + { + return getPrimaryUserId(new Date()); + } + + /** + * Return the {@link OpenPGPUserId} that is considered primary at the given evaluation time. + * + * @param evaluationTime evaluation time + * @return primary user-id at evaluation time + */ + public OpenPGPUserId getPrimaryUserId(Date evaluationTime) + { + return primaryKey.getExplicitOrImplicitPrimaryUserId(evaluationTime); + } + + /** + * Return the {@link OpenPGPUserId} object matching the given user-id {@link String}. + * + * @param userId user-id + * @return user-id + */ + public OpenPGPUserId getUserId(String userId) + { + for (Iterator it = primaryKey.getUserIDs().iterator(); it.hasNext(); ) + { + OpenPGPUserId uid = (OpenPGPUserId)it.next(); + if (uid.getUserId().equals(userId)) + { + return uid; + } + } + return null; + } + + /** + * Return the time at which the certificate expires. + * + * @return expiration time of the certificate + */ + public Date getExpirationTime() + { + return getExpirationTime(new Date()); + } + + /** + * Return the time at which the certificate is expected to expire, considering the given evaluation time. + * + * @param evaluationTime reference time + * @return expiration time at evaluation time + */ + public Date getExpirationTime(Date evaluationTime) + { + return getPrimaryKey().getKeyExpirationDateAt(evaluationTime); + } + + /** + * Return an {@link OpenPGPSignatureChain} from the given 3rd-party certificate to this certificate, + * which represents a delegation of trust. + * If no delegation signature is found, return null. + * + * @param thirdPartyCertificate {@link OpenPGPCertificate} of a 3rd party. + * @return chain containing the latest delegation issued by the 3rd-party certificate + */ + public OpenPGPSignatureChain getDelegationBy(OpenPGPCertificate thirdPartyCertificate) + { + return getDelegationBy(thirdPartyCertificate, new Date()); + } + + /** + * Return an {@link OpenPGPSignatureChain} from the given 3rd-party certificate to this certificate, + * which represents a delegation of trust at evaluation time. + * If no delegation signature is found, return null. + * + * @param thirdPartyCertificate {@link OpenPGPCertificate} of a 3rd party. + * @param evaluationTime reference time + * @return chain containing the (at evaluation time) latest delegation issued by the 3rd-party certificate + */ + public OpenPGPSignatureChain getDelegationBy( + OpenPGPCertificate thirdPartyCertificate, + Date evaluationTime) + { + OpenPGPSignatureChains chainsBy = getPrimaryKey(). + getMergedDanglingExternalSignatureChainEndsFrom(thirdPartyCertificate, evaluationTime); + return chainsBy.getCertificationAt(evaluationTime); + } + + /** + * Return an {@link OpenPGPSignatureChain} from the given 3rd-party certificate to this certificate, + * which represents a revocation of trust. + * + * @param thirdPartyCertificate {@link OpenPGPCertificate} of a 3rd party. + * @return chain containing the latest revocation issued by the 3rd party certificate + */ + public OpenPGPSignatureChain getRevocationBy(OpenPGPCertificate thirdPartyCertificate) + { + return getRevocationBy(thirdPartyCertificate, new Date()); + } + + /** + * Return an {@link OpenPGPSignatureChain} from the given 3rd-party certificate to this certificate, + * which (at evaluation time) represents a revocation of trust. + * + * @param thirdPartyCertificate {@link OpenPGPCertificate} of a 3rd party. + * @param evaluationTime reference time + * @return chain containing the (at evaluation time) latest revocation issued by the 3rd party certificate + */ + public OpenPGPSignatureChain getRevocationBy( + OpenPGPCertificate thirdPartyCertificate, + Date evaluationTime) + { + OpenPGPSignatureChains chainsBy = getPrimaryKey() + .getMergedDanglingExternalSignatureChainEndsFrom(thirdPartyCertificate, evaluationTime); + return chainsBy.getRevocationAt(evaluationTime); + } + + /** + * Component on an OpenPGP certificate. + * Components can either be {@link OpenPGPComponentKey keys} or {@link OpenPGPIdentityComponent identities}. + */ + public static abstract class OpenPGPCertificateComponent + { + private final OpenPGPCertificate certificate; + + public OpenPGPCertificateComponent(OpenPGPCertificate certificate) + { + this.certificate = certificate; + } + + /** + * Return this components {@link OpenPGPCertificate}. + * + * @return certificate + */ + public OpenPGPCertificate getCertificate() + { + return certificate; + } + + /** + * Return a detailed String representation of this component. + * + * @return detailed String representation + */ + public abstract String toDetailString(); + + /** + * Return true, if the component is currently validly bound to the certificate. + * + * @return true if bound + */ + public boolean isBound() + { + return isBoundAt(new Date()); + } + + /** + * Return true, if this component is - at evaluation time - properly bound to its certificate. + * + * @param evaluationTime evaluation time + * @return true if bound, false otherwise + */ + public boolean isBoundAt(Date evaluationTime) + { + return getCertificate().isBound(this, evaluationTime); + } + + /** + * Return all {@link OpenPGPSignatureChains} that bind this component. + * + * @return signature chains + */ + public OpenPGPSignatureChains getSignatureChains() + { + OpenPGPSignatureChains chains = getCertificate().getAllSignatureChainsFor(this); + if (getPublicComponent() instanceof OpenPGPPrimaryKey) + { + OpenPGPPrimaryKey pk = (OpenPGPPrimaryKey)getPublicComponent(); + if (!pk.getUserIDs().isEmpty()) + { + chains.addAll(getCertificate().getAllSignatureChainsFor(pk.getUserIDs().get(0))); + } + } + return chains; + } + + /** + * Return the (at evaluation time) latest certification signature binding this component. + * + * @param evaluationTime reference time + * @return latest component certification signature + */ + public OpenPGPComponentSignature getCertification(Date evaluationTime) + { + OpenPGPSignatureChain certification = getSignatureChains().getCertificationAt(evaluationTime); + if (certification != null) + { + return certification.getSignature(); + } + return null; + } + + /** + * Return the (at evaluation time) latest revocation signature revoking this component. + * + * @param evaluationTime reference time + * @return latest component revocation signature + */ + public OpenPGPComponentSignature getRevocation(Date evaluationTime) + { + OpenPGPSignatureChain revocation = getSignatureChains().getRevocationAt(evaluationTime); + if (revocation != null) + { + return revocation.getSignature(); + } + return null; + } + + /** + * Return the latest self-signature on the component. + * That might either be a certification signature, or a revocation. + * + * @return latest self signature + */ + public OpenPGPComponentSignature getLatestSelfSignature() + { + return getLatestSelfSignature(new Date()); + } + + /** + * Return the (at evaluation time) latest self-signature on the component. + * That might either be a certification signature, or a revocation. + * + * @param evaluationTime reference time + * @return latest self signature + */ + public abstract OpenPGPComponentSignature getLatestSelfSignature(Date evaluationTime); + + /** + * Return the public {@link OpenPGPCertificateComponent} that belongs to this component. + * For public components (pubkeys, identities...), that's simply this, while secret components + * return their corresponding public component. + * This is used to properly map secret key and public key components in {@link Map Maps} that use + * {@link OpenPGPCertificateComponent components} as map keys. + * + * @return public certificate component + */ + protected OpenPGPCertificateComponent getPublicComponent() + { + return this; + } + + /** + * Return the {@link OpenPGPComponentKey} belonging to this {@link OpenPGPCertificateComponent}. + * If this {@link OpenPGPCertificateComponent} is an instance of {@link OpenPGPComponentKey}, + * the method simply returns
    this
    . + * If instead, the {@link OpenPGPCertificateComponent} is an {@link OpenPGPIdentityComponent}, + * the primary key it is bound to is returned. + * + * @return {@link OpenPGPComponentKey} of this {@link OpenPGPCertificateComponent}. + */ + protected abstract OpenPGPComponentKey getKeyComponent(); + + /** + * Return the {@link KeyFlags} signature subpacket that currently applies to the key. + * + * @return key flags subpacket + */ + public KeyFlags getKeyFlags() + { + return getKeyFlags(new Date()); + } + + /** + * Return the {@link KeyFlags} signature subpacket that - at evaluation time - applies to the key. + * + * @param evaluationTime evaluation time + * @return key flags subpacket + */ + public KeyFlags getKeyFlags(Date evaluationTime) + { + OpenPGPSignature.OpenPGPSignatureSubpacket subpacket = getApplyingSubpacket( + evaluationTime, SignatureSubpacketTags.KEY_FLAGS); + if (subpacket != null) + { + return (KeyFlags)subpacket.getSubpacket(); + } + return null; + } + + /** + * Return
    true
    , if the key has any of the given key flags. + *

    + * Note: To check if the key has EITHER flag A or B, call

    hasKeyFlags(evalTime, A, B)
    . + * To instead check, if the key has BOTH flags A AND B, call
    hasKeyFlags(evalTime, A & B)
    . + * + * @param evaluationTime evaluation time + * @param flags key flags (see {@link KeyFlags} for possible values) + * @return true if the key has ANY of the provided flags + */ + public boolean hasKeyFlags(Date evaluationTime, int... flags) + { + KeyFlags keyFlags = getKeyFlags(evaluationTime); + if (keyFlags == null) + { + // Key has no key-flags + return false; + } + + // Check if key has the desired key-flags + for (int i = 0; i < flags.length; ++i) + { + if (((keyFlags.getFlags() & flags[i]) == flags[i])) + { + return true; + } + } + return false; + } + + /** + * Return the {@link Features} signature subpacket that currently applies to the key. + * + * @return feature signature subpacket + */ + public Features getFeatures() + { + return getFeatures(new Date()); + } + + /** + * Return the {@link Features} signature subpacket that - at evaluation time - applies to the key. + * + * @param evaluationTime evaluation time + * @return features subpacket + */ + public Features getFeatures(Date evaluationTime) + { + OpenPGPSignature.OpenPGPSignatureSubpacket subpacket = getApplyingSubpacket(evaluationTime, SignatureSubpacketTags.FEATURES); + if (subpacket != null) + { + return (Features)subpacket.getSubpacket(); + } + return null; + } + + /** + * Return the {@link PreferredAEADCiphersuites} that apply to this (sub-)key. + * Note: This refers to AEAD preferences as defined in rfc9580, NOT LibrePGP AEAD algorithms. + * + * @return AEAD algorithm preferences + */ + public PreferredAEADCiphersuites getAEADCipherSuitePreferences() + { + return getAEADCipherSuitePreferences(new Date()); + } + + /** + * Return the {@link PreferredAEADCiphersuites} that - at evaluation time - apply to this (sub-)key. + * Note: This refers to AEAD preferences as defined in rfc9580, NOT LibrePGP AEAD algorithms. + * + * @param evaluationTime evaluation time + * @return AEAD algorithm preferences at evaluation time + */ + public PreferredAEADCiphersuites getAEADCipherSuitePreferences(Date evaluationTime) + { + OpenPGPSignature.OpenPGPSignatureSubpacket subpacket = getApplyingSubpacket(evaluationTime, + SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS); + if (subpacket != null) + { + return (PreferredAEADCiphersuites)subpacket.getSubpacket(); + } + return null; + } + + /** + * Return the current symmetric encryption algorithm preferences of this (sub-)key. + * + * @return current preferred symmetric-key algorithm preferences + */ + public PreferredAlgorithms getSymmetricCipherPreferences() + { + return getSymmetricCipherPreferences(new Date()); + } + + /** + * Return the symmetric encryption algorithm preferences of this (sub-)key at evaluation time. + * + * @param evaluationTime evaluation time + * @return current preferred symmetric-key algorithm preferences + */ + public PreferredAlgorithms getSymmetricCipherPreferences(Date evaluationTime) + { + OpenPGPSignature.OpenPGPSignatureSubpacket subpacket = getApplyingSubpacket(evaluationTime, SignatureSubpacketTags.PREFERRED_SYM_ALGS); + if (subpacket != null) + { + return (PreferredAlgorithms)subpacket.getSubpacket(); + } + return null; + } + + /** + * Return the current signature hash algorithm preferences of this (sub-)key. + * + * @return hash algorithm preferences + */ + public PreferredAlgorithms getHashAlgorithmPreferences() + { + return getHashAlgorithmPreferences(new Date()); + } + + /** + * Return the signature hash algorithm preferences of this (sub-)key at evaluation time. + * + * @param evaluationTime evaluation time + * @return hash algorithm preferences + */ + public PreferredAlgorithms getHashAlgorithmPreferences(Date evaluationTime) + { + OpenPGPSignature.OpenPGPSignatureSubpacket subpacket = getApplyingSubpacket(evaluationTime, SignatureSubpacketTags.PREFERRED_HASH_ALGS); + if (subpacket != null) + { + return (PreferredAlgorithms)subpacket.getSubpacket(); + } + return null; + } + + /** + * Return the compression algorithm preferences of this (sub-)key. + * + * @return compression algorithm preferences + */ + public PreferredAlgorithms getCompressionAlgorithmPreferences() + { + return getCompressionAlgorithmPreferences(new Date()); + } + + /** + * Return the compression algorithm preferences of this (sub-)key at evaluation time. + * + * @param evaluationTime reference time + * @return compression algorithm preferences + */ + public PreferredAlgorithms getCompressionAlgorithmPreferences(Date evaluationTime) + { + OpenPGPSignature.OpenPGPSignatureSubpacket subpacket = getApplyingSubpacket(evaluationTime, SignatureSubpacketTags.PREFERRED_COMP_ALGS); + if (subpacket != null) + { + return (PreferredAlgorithms)subpacket.getSubpacket(); + } + return null; + } + + /** + * Return the {@link Date}, at which the key expires. + * + * @return key expiration time + */ + public Date getKeyExpirationDate() + { + return getKeyExpirationDateAt(new Date()); + } + + /** + * Return the {@link Date}, at which the key - at evaluation time - expires. + * + * @param evaluationTime evaluation time + * @return key expiration time + */ + public Date getKeyExpirationDateAt(Date evaluationTime) + { + return getLatestSelfSignature(evaluationTime).getKeyExpirationTime(); + } + + /** + * Return the {@link SignatureSubpacket} instance of the given subpacketType, which currently applies to + * the key. Since subpackets from the Direct-Key signature apply to all subkeys of a certificate, + * this method first inspects the signature that immediately applies to this key (e.g. a subkey-binding + * signature), and - if the queried subpacket is found in there, returns that instance. + * Otherwise, indirectly applying signatures (e.g. Direct-Key signatures) are queried. + * That way, preferences from the direct-key signature are considered, but per-key overwrites take precedence. + * + * @param evaluationTime evaluation time + * @param subpacketType subpacket type that is being searched for + * @return subpacket from directly or indirectly applying signature + * @see + * OpenPGP for application developers - Attribute Shadowing + */ + protected OpenPGPSignature.OpenPGPSignatureSubpacket getApplyingSubpacket(Date evaluationTime, int subpacketType) + { + OpenPGPSignatureChain binding = getSignatureChains().getCertificationAt(evaluationTime); + if (binding == null) + { + // is not bound + return null; + } + + // Check signatures + try + { + if (!binding.isValid()) + { + // Binding is incorrect + return null; + } + } + catch (PGPSignatureException e) + { + // Binding cannot be verified + return null; + } + + // find signature "closest to the key", e.g. subkey binding signature + OpenPGPComponentSignature keySignature = binding.getSignature(); + + PGPSignatureSubpacketVector hashedSubpackets = keySignature.getSignature().getHashedSubPackets(); + if (hashedSubpackets == null || !hashedSubpackets.hasSubpacket(subpacketType)) + { + // If the subkey binding signature doesn't carry the desired subpacket, + // check direct-key or primary uid sig instead + OpenPGPSignatureChain preferenceBinding = getCertificate().getPreferenceSignature(evaluationTime); + if (preferenceBinding == null) + { + // No direct-key / primary uid sig found -> No subpacket + return null; + } + keySignature = preferenceBinding.getSignature(); + hashedSubpackets = keySignature.getSignature().getHashedSubPackets(); + } + // else -> attribute from DK sig is shadowed by SB sig + + // Extract subpacket from hashed area + SignatureSubpacket subpacket = hashedSubpackets.getSubpacket(subpacketType); + if (subpacket == null) + { + return null; + } + return OpenPGPSignature.OpenPGPSignatureSubpacket.hashed(subpacket, keySignature); + } + + /** + * Iterate over signatures issued over this component by the given 3rd-party certificate, + * merge them with the (at evaluation time) valid self-certification chain and return the + * results. + * + * @param thirdPartyCertificate certificate of a 3rd party + * @param evaluationTime reference time + * @return all 3rd party signatures on this component, merged with their issuer chains + */ + protected OpenPGPSignatureChains getMergedDanglingExternalSignatureChainEndsFrom( + OpenPGPCertificate thirdPartyCertificate, + Date evaluationTime) + { + OpenPGPSignatureChains chainsBy = new OpenPGPSignatureChains(this); + + OpenPGPSignatureChains allChains = getCertificate().getAllSignatureChainsFor(this) + .getChainsAt(evaluationTime); + for (Iterator it = allChains.iterator(); it.hasNext(); ) + { + OpenPGPSignatureChain.Link rootLink = it.next().getRootLink(); + for (Iterator it2 = thirdPartyCertificate.getKeys().iterator(); it2.hasNext(); ) + { + OpenPGPComponentKey issuerKey = it2.next(); + if (KeyIdentifier.matches( + rootLink.getSignature().getKeyIdentifiers(), + issuerKey.getKeyIdentifier(), + true)) + { + OpenPGPSignatureChain externalChain = issuerKey.getSignatureChains().getChainAt(evaluationTime); + externalChain = externalChain.plus( + new OpenPGPComponentSignature(rootLink.signature.getSignature(), issuerKey, this)); + chainsBy.add(externalChain); + } + } + } + return chainsBy; + } + } + + /** + * OpenPGP Signature made over some {@link OpenPGPCertificateComponent} on a {@link OpenPGPCertificate}. + */ + public static class OpenPGPComponentSignature + extends OpenPGPSignature + { + + private final OpenPGPCertificateComponent target; + + /** + * Component signature. + * + * @param signature signature + * @param issuer key that issued the signature. + * Is nullable (e.g. for 3rd party sigs where the certificate is not available). + * @param target signed certificate component + */ + public OpenPGPComponentSignature(PGPSignature signature, + OpenPGPComponentKey issuer, + OpenPGPCertificateComponent target) + { + super(signature, issuer); + this.target = target; + } + + /** + * Return the {@link OpenPGPComponentKey} that issued this signature. + * + * @return issuer + */ + public OpenPGPComponentKey getIssuerComponent() + { + return getIssuer(); + } + + /** + * Return the {@link OpenPGPCertificateComponent} that this signature was calculated over. + * + * @return target + */ + public OpenPGPCertificateComponent getTargetComponent() + { + return target; + } + + /** + * Return the {@link OpenPGPComponentKey} that this signature is calculated over. + * Contrary to {@link #getTargetComponent()}, which returns the actual target, this method returns the + * {@link OpenPGPComponentKey} "closest" to the target. + * For a subkey-binding signature, this is the target subkey, while for an identity-binding signature + * (binding for a user-id or attribute) the return value is the {@link OpenPGPComponentKey} which + * carries the identity. + * + * @return target key component of the signature + */ + public OpenPGPComponentKey getTargetKeyComponent() + { + if (getTargetComponent() instanceof OpenPGPIdentityComponent) + { + // Identity signatures indirectly authenticate the primary key + return ((OpenPGPIdentityComponent)getTargetComponent()).getPrimaryKey(); + } + if (getTargetComponent() instanceof OpenPGPComponentKey) + { + // Key signatures authenticate the target key + return (OpenPGPComponentKey)getTargetComponent(); + } + throw new IllegalArgumentException("Unknown target type."); + } + + /** + * Return the key expiration time stored in the signature. + * + * @return key expiration time + */ + public Date getKeyExpirationTime() + { + PGPSignatureSubpacketVector hashed = signature.getHashedSubPackets(); + if (hashed == null) + { + // v3 sigs have no expiration + return null; + } + long exp = hashed.getKeyExpirationTime(); + if (exp < 0) + { + throw new RuntimeException("Negative key expiration time"); + } + + if (exp == 0L) + { + // Explicit or implicit no expiration + return null; + } + + return new Date(getTargetKeyComponent().getCreationTime().getTime() + 1000 * exp); + } + + /** + * Verify this signature. + * + * @param implementation OpenPGP implementation + * @throws PGPSignatureException if the signature cannot be verified successfully + */ + public void verify(OpenPGPImplementation implementation) + throws PGPSignatureException + { + verify(implementation.pgpContentVerifierBuilderProvider(), implementation.policy()); + } + + /** + * Verify this signature. + * + * @param contentVerifierBuilderProvider provider for verifiers + * @param policy algorithm policy + * @throws PGPSignatureException if the signature cannot be verified successfully + */ + public void verify(PGPContentVerifierBuilderProvider contentVerifierBuilderProvider, + OpenPGPPolicy policy) + throws PGPSignatureException + { + if (issuer == null) + { + // No issuer available + throw new MissingIssuerCertException(this, "Issuer certificate unavailable."); + } + + sanitize(issuer, policy); + + // Direct-Key signature + if (signature.getSignatureType() == PGPSignature.DIRECT_KEY + || signature.getSignatureType() == PGPSignature.KEY_REVOCATION) + { + verifyKeySignature( + issuer, + target.getKeyComponent(), + contentVerifierBuilderProvider); + } + + // Subkey binding signature + else if (signature.getSignatureType() == PGPSignature.SUBKEY_BINDING) + { + // For signing-capable subkeys, check the embedded primary key binding signature + verifyEmbeddedPrimaryKeyBinding(contentVerifierBuilderProvider, policy, getCreationTime()); + + // Binding signature MUST NOT predate the subkey itself + if (((OpenPGPSubkey)target).getCreationTime().after(signature.getCreationTime())) + { + isCorrect = false; + throw new MalformedOpenPGPSignatureException(this, "Subkey binding signature predates subkey creation time."); + } + + verifyKeySignature( + issuer, + (OpenPGPSubkey)target, + contentVerifierBuilderProvider); + } + + else if (signature.getSignatureType() == PGPSignature.SUBKEY_REVOCATION) + { + // Binding signature MUST NOT predate the subkey itself + if (((OpenPGPSubkey)target).getCreationTime().after(signature.getCreationTime())) + { + isCorrect = false; + throw new MalformedOpenPGPSignatureException(this, "Subkey revocation signature predates subkey creation time."); + } + + verifyKeySignature( + issuer, + (OpenPGPSubkey)target, + contentVerifierBuilderProvider); + } + + // User-ID binding + else if (target instanceof OpenPGPUserId) + { + verifyUserIdSignature( + issuer, + (OpenPGPUserId)target, + contentVerifierBuilderProvider); + } + + // User-Attribute binding + else if (target instanceof OpenPGPUserAttribute) + { + verifyUserAttributeSignature( + issuer, + (OpenPGPUserAttribute)target, + contentVerifierBuilderProvider); + } + + else + { + throw new PGPSignatureException("Unexpected signature type: " + getType()); + } + } + + /** + * Verify a signature of type {@link PGPSignature#PRIMARYKEY_BINDING}, which is typically embedded as + * {@link org.bouncycastle.bcpg.sig.EmbeddedSignature} inside a signature of type + * {@link PGPSignature#SUBKEY_BINDING} for a signing capable subkey. + * + * @param contentVerifierBuilderProvider provider for content verifier builders + * @param policy algorithm policy + * @param signatureCreationTime creation time of the signature + * @throws PGPSignatureException if an exception happens during signature verification + */ + private void verifyEmbeddedPrimaryKeyBinding(PGPContentVerifierBuilderProvider contentVerifierBuilderProvider, + OpenPGPPolicy policy, Date signatureCreationTime) + throws PGPSignatureException + { + int keyFlags = signature.getHashedSubPackets().getKeyFlags(); + if ((keyFlags & KeyFlags.SIGN_DATA) != KeyFlags.SIGN_DATA) + { + // Non-signing key - no embedded primary key binding sig required + return; + } + + OpenPGPComponentKey subkey = getTargetKeyComponent(); + // Signing subkey needs embedded primary key binding signature + List embeddedSignatures = new ArrayList(); + try + { + PGPSignatureList sigList = signature.getHashedSubPackets().getEmbeddedSignatures(); + addSignatures(embeddedSignatures, sigList); + sigList = signature.getUnhashedSubPackets().getEmbeddedSignatures(); + addSignatures(embeddedSignatures, sigList); + } + catch (PGPException e) + { + throw new PGPSignatureException("Cannot extract embedded signature.", e); + } + + if (embeddedSignatures.isEmpty()) + { + throw new MalformedOpenPGPSignatureException( + this, + "Signing key SubkeyBindingSignature MUST contain embedded PrimaryKeyBindingSignature."); + } + + PGPSignatureException exception = null; + for (Iterator it = embeddedSignatures.iterator(); it.hasNext(); ) + { + PGPSignature primaryKeyBinding = it.next(); + OpenPGPCertificate.OpenPGPComponentSignature backSig = + new OpenPGPCertificate.OpenPGPComponentSignature( + primaryKeyBinding, + subkey, + issuer); + + if (primaryKeyBinding.getSignatureType() != PGPSignature.PRIMARYKEY_BINDING) + { + exception = new PGPSignatureException("Unexpected embedded signature type: " + primaryKeyBinding.getSignatureType()); + continue; + } + + if (!backSig.isEffectiveAt(signatureCreationTime)) + { + exception = new PGPSignatureException("Embedded PrimaryKeyBinding signature is expired or not yet effective."); + continue; + } + + try + { + backSig.sanitize(subkey, policy); + + // needs to be called last to prevent false positives + backSig.verifyKeySignature(subkey, issuer, contentVerifierBuilderProvider); + + // valid -> return successfully + return; + } + catch (PGPSignatureException e) + { + exception = e; + } + } + + // if we end up here, it means we have only found invalid sigs + throw exception; + } + + private static void addSignatures(List embeddedSignatures, PGPSignatureList sigList) + { + for (Iterator it = sigList.iterator(); it.hasNext(); ) + { + embeddedSignatures.add(it.next()); + } + } + + /** + * Verify a signature of type {@link PGPSignature#DIRECT_KEY}, {@link PGPSignature#KEY_REVOCATION}, + * {@link PGPSignature#SUBKEY_BINDING} or {@link PGPSignature#SUBKEY_REVOCATION}. + * + * @param issuer issuing component key + * @param target targeted component key + * @param contentVerifierBuilderProvider provider for content verifier builders + * @throws PGPSignatureException if an exception happens during signature verification + */ + protected void verifyKeySignature( + OpenPGPComponentKey issuer, + OpenPGPComponentKey target, + PGPContentVerifierBuilderProvider contentVerifierBuilderProvider) + throws PGPSignatureException + { + this.isTested = true; + try + { + signature.init(contentVerifierBuilderProvider, issuer.getPGPPublicKey()); + if (signature.getSignatureType() == PGPSignature.DIRECT_KEY + || signature.getSignatureType() == PGPSignature.KEY_REVOCATION) + { + // Direct-Key Signature + isCorrect = signature.verifyCertification(target.getPGPPublicKey()); + } + else if (signature.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) + { + isCorrect = signature.verifyCertification(target.getPGPPublicKey(), issuer.getPGPPublicKey()); + } + else + { + // Subkey Binding Signature + isCorrect = signature.verifyCertification(issuer.getPGPPublicKey(), target.getPGPPublicKey()); + } + + if (!isCorrect) + { + throw new IncorrectOpenPGPSignatureException(this, "Key Signature is not correct."); + } + } + catch (PGPException e) + { + this.isCorrect = false; + throw new PGPSignatureException("Key Signature could not be verified.", e); + } + catch (ClassCastException e) + { + this.isCorrect = false; + throw new PGPSignatureException("Key Signature could not be verified.", e); + } + } + + /** + * Verify a certification signature over an {@link OpenPGPUserId}. + * The signature is of type {@link PGPSignature#DEFAULT_CERTIFICATION}, {@link PGPSignature#NO_CERTIFICATION}, + * {@link PGPSignature#CASUAL_CERTIFICATION}, {@link PGPSignature#POSITIVE_CERTIFICATION} or + * {@link PGPSignature#CERTIFICATION_REVOCATION}. + * + * @param issuer issuing component key + * @param target targeted userid + * @param contentVerifierBuilderProvider provider for content verifier builders + * @throws PGPSignatureException if an exception happens during signature verification + */ + protected void verifyUserIdSignature(OpenPGPComponentKey issuer, + OpenPGPUserId target, + PGPContentVerifierBuilderProvider contentVerifierBuilderProvider) + throws PGPSignatureException + { + this.isTested = true; + try + { + signature.init(contentVerifierBuilderProvider, issuer.getPGPPublicKey()); + isCorrect = signature.verifyCertification(target.getUserId(), target.getPrimaryKey().getPGPPublicKey()); + if (!isCorrect) + { + throw new IncorrectOpenPGPSignatureException(this, "UserID Signature is not correct."); + } + } + catch (PGPException e) + { + this.isCorrect = false; + throw new PGPSignatureException("UserID Signature could not be verified.", e); + } + catch (ClassCastException e) + { + this.isCorrect = false; + throw new PGPSignatureException("UserID Signature could not be verified.", e); + } + } + + /** + * Verify a certification signature over an {@link OpenPGPUserAttribute}. + * The signature is of type {@link PGPSignature#DEFAULT_CERTIFICATION}, {@link PGPSignature#NO_CERTIFICATION}, + * {@link PGPSignature#CASUAL_CERTIFICATION}, {@link PGPSignature#POSITIVE_CERTIFICATION} or + * {@link PGPSignature#CERTIFICATION_REVOCATION}. + * + * @param issuer issuing component key + * @param target targeted userid + * @param contentVerifierBuilderProvider provider for content verifier builders + * @throws PGPSignatureException if an exception happens during signature verification + */ + protected void verifyUserAttributeSignature(OpenPGPComponentKey issuer, + OpenPGPUserAttribute target, + PGPContentVerifierBuilderProvider contentVerifierBuilderProvider) + throws PGPSignatureException + { + this.isTested = true; + try + { + signature.init(contentVerifierBuilderProvider, issuer.getPGPPublicKey()); + isCorrect = signature.verifyCertification(target.getUserAttribute(), target.getPrimaryKey().getPGPPublicKey()); + if (!isCorrect) + { + throw new IncorrectOpenPGPSignatureException(this, "UserAttribute Signature is not correct."); + } + } + catch (PGPException e) + { + this.isCorrect = false; + throw new PGPSignatureException("Could not verify UserAttribute Signature.", e); + } + catch (ClassCastException e) + { + this.isCorrect = false; + throw new PGPSignatureException("Could not verify UserAttribute Signature.", e); + } + } + + @Override + protected String getTargetDisplay() + { + return target.toString(); + } + } + + /** + * A component key is either an {@link OpenPGPPrimaryKey}, or an {@link OpenPGPSubkey}. + * + * @see + * OpenPGP for Application Developers - Layers of keys in OpenPGP + */ + public static abstract class OpenPGPComponentKey + extends OpenPGPCertificateComponent + { + protected final PGPPublicKey rawPubkey; + + /** + * Constructor. + * + * @param rawPubkey public key + * @param certificate certificate + */ + public OpenPGPComponentKey(PGPPublicKey rawPubkey, OpenPGPCertificate certificate) + { + super(certificate); + this.rawPubkey = rawPubkey; + } + + /** + * Return the underlying {@link PGPPublicKey} of this {@link OpenPGPComponentKey}. + * + * @return public key + */ + public PGPPublicKey getPGPPublicKey() + { + return rawPubkey; + } + + /** + * Return the {@link KeyIdentifier} of this key. + * + * @return key identifier + */ + public KeyIdentifier getKeyIdentifier() + { + return rawPubkey.getKeyIdentifier(); + } + + /** + * Return the public key algorithm. + * + * @return public key algorithm id + * @see org.bouncycastle.bcpg.PublicKeyAlgorithmTags + */ + public int getAlgorithm() + { + return getPGPPublicKey().getAlgorithm(); + } + + /** + * Return the public key version. + * + * @return key version + */ + public int getVersion() + { + return getPGPPublicKey().getVersion(); + } + + /** + * Return the creation time of this key. + * + * @return creation time + */ + public Date getCreationTime() + { + return rawPubkey.getCreationTime(); + } + + /** + * Return true, if this {@link OpenPGPComponentKey} represents the primary key of an {@link OpenPGPCertificate}. + * + * @return true if primary, false if subkey + */ + public abstract boolean isPrimaryKey(); + + @Override + public OpenPGPComponentSignature getLatestSelfSignature(Date evaluationTime) + { + OpenPGPSignatureChain currentDKChain = getSignatureChains().getChainAt(evaluationTime); + if (currentDKChain != null && !currentDKChain.chainLinks.isEmpty()) + { + return currentDKChain.getSignature(); + } + return null; + } + + /** + * Return true, if the key is currently marked as encryption key. + * + * @return true if the key is an encryption key, false otherwise + */ + public boolean isEncryptionKey() + { + return isEncryptionKey(new Date()); + } + + /** + * Return true, if the is - at evaluation time - marked as an encryption key. + * + * @param evaluationTime evaluation time + * @return true if key is an encryption key at evaluation time, false otherwise + */ + public boolean isEncryptionKey(Date evaluationTime) + { + if (!rawPubkey.isEncryptionKey()) + { + // Skip keys that are not encryption-capable by algorithm + return false; + } + + return hasKeyFlags(evaluationTime, KeyFlags.ENCRYPT_STORAGE) || + hasKeyFlags(evaluationTime, KeyFlags.ENCRYPT_COMMS); + } + + /** + * Return true, if the key is currently marked as a signing key for message signing. + * + * @return true, if key is currently signing key + */ + public boolean isSigningKey() + { + return isSigningKey(new Date()); + } + + /** + * Return true, if the key is - at evaluation time - marked as signing key for message signing. + * + * @param evaluationTime evaluation time + * @return true if key is signing key at evaluation time + */ + public boolean isSigningKey(Date evaluationTime) + { + if (!PublicKeyUtils.isSigningAlgorithm(rawPubkey.getAlgorithm())) + { + // Key is not signing-capable by algorithm + return false; + } + + return hasKeyFlags(evaluationTime, KeyFlags.SIGN_DATA); + } + + /** + * Return true, if the key is currently marked as certification key that can sign 3rd-party certificates. + * + * @return true, if key is certification key + */ + public boolean isCertificationKey() + { + return isCertificationKey(new Date()); + } + + /** + * Return true, if the key is - at evaluation time - marked as certification key that can sign 3rd-party + * certificates. + * + * @param evaluationTime evaluation time + * @return true if key is certification key at evaluation time + */ + public boolean isCertificationKey(Date evaluationTime) + { + if (!PublicKeyUtils.isSigningAlgorithm(rawPubkey.getAlgorithm())) + { + // Key is not signing-capable by algorithm + return false; + } + + return hasKeyFlags(evaluationTime, KeyFlags.CERTIFY_OTHER); + } + + @Override + protected OpenPGPComponentKey getKeyComponent() + { + // This already IS a component key + return this; + } + + @Override + public int hashCode() + { + return getPGPPublicKey().hashCode(); + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (this == obj) + { + return true; + } + if (!(obj instanceof OpenPGPComponentKey)) + { + return false; + } + OpenPGPComponentKey other = (OpenPGPComponentKey)obj; + return getPGPPublicKey().equals(other.getPGPPublicKey()); + } + } + + /** + * The primary key of a {@link OpenPGPCertificate}. + */ + public static class OpenPGPPrimaryKey + extends OpenPGPComponentKey + { + @Override + public String toString() + { + return "PrimaryKey[" + Long.toHexString(getKeyIdentifier().getKeyId()).toUpperCase(Locale.getDefault()) + "]"; + } + + @Override + public String toDetailString() + { + return "PrimaryKey[" + getKeyIdentifier() + "] (" + UTCUtil.format(getCreationTime()) + ")"; + } + + protected final List identityComponents; + + public OpenPGPPrimaryKey(PGPPublicKey rawPubkey, OpenPGPCertificate certificate) + { + super(rawPubkey, certificate); + this.identityComponents = new ArrayList(); + + Iterator userIds = rawPubkey.getUserIDs(); + while (userIds.hasNext()) + { + identityComponents.add(new OpenPGPUserId(userIds.next(), this)); + } + + Iterator userAttributes = rawPubkey.getUserAttributes(); + while (userAttributes.hasNext()) + { + identityComponents.add(new OpenPGPUserAttribute(userAttributes.next(), this)); + } + } + + @Override + public boolean isPrimaryKey() + { + return true; + } + + /** + * Return the latest DirectKey self-signature on this primary key. + * + * @return latest direct key self-signature. + */ + public OpenPGPComponentSignature getLatestDirectKeySelfSignature() + { + return getLatestDirectKeySelfSignature(new Date()); + } + + /** + * Return the (at evaluation time) latest DirectKey self-signature on this primary key. + * + * @param evaluationTime reference time + * @return latest (at evaluation time) direct key self-signature + */ + public OpenPGPComponentSignature getLatestDirectKeySelfSignature(Date evaluationTime) + { + OpenPGPSignatureChain currentDKChain = getCertificate().getAllSignatureChainsFor(this) + .getCertificationAt(evaluationTime); + if (currentDKChain != null && !currentDKChain.chainLinks.isEmpty()) + { + return currentDKChain.getSignature(); + } + + return null; + } + + /** + * Return the latest KeyRevocation self-signature on this primary key. + * + * @return latest key revocation self-signature + */ + public OpenPGPComponentSignature getLatestKeyRevocationSelfSignature() + { + return getLatestKeyRevocationSelfSignature(new Date()); + } + + /** + * Return the (at evaluation time) latest KeyRevocation self-signature on this primary key. + * + * @param evaluationTime reference time + * @return latest (at evaluation time) key revocation self-signature + */ + public OpenPGPComponentSignature getLatestKeyRevocationSelfSignature(Date evaluationTime) + { + OpenPGPSignatureChain currentRevocationChain = getCertificate().getAllSignatureChainsFor(this) + .getRevocationAt(evaluationTime); + if (currentRevocationChain != null && !currentRevocationChain.chainLinks.isEmpty()) + { + return currentRevocationChain.getSignature(); + } + return null; + } + + @Override + public OpenPGPComponentSignature getLatestSelfSignature(Date evaluationTime) + { + List signatures = new ArrayList(); + + OpenPGPComponentSignature directKeySig = getLatestDirectKeySelfSignature(evaluationTime); + if (directKeySig != null) + { + signatures.add(directKeySig); + } + + OpenPGPComponentSignature keyRevocation = getLatestKeyRevocationSelfSignature(evaluationTime); + if (keyRevocation != null) + { + signatures.add(keyRevocation); + } + + for (Iterator it = getCertificate().getIdentities().iterator(); it.hasNext(); ) + { + OpenPGPComponentSignature identitySig = it.next().getLatestSelfSignature(evaluationTime); + if (identitySig != null) + { + signatures.add(identitySig); + } + } + + OpenPGPComponentSignature latest = null; + for (Iterator it = signatures.iterator(); it.hasNext(); ) + { + OpenPGPComponentSignature signature = it.next(); + if (latest == null || signature.getCreationTime().after(latest.getCreationTime())) + { + latest = signature; + } + } + return latest; + } + + /** + * Return all {@link OpenPGPUserId OpenPGPUserIds} on this key. + * + * @return user ids + */ + public List getUserIDs() + { + List userIds = new ArrayList(); + for (Iterator it = identityComponents.iterator(); it.hasNext(); ) + { + OpenPGPIdentityComponent identity = it.next(); + if (identity instanceof OpenPGPUserId) + { + userIds.add((OpenPGPUserId)identity); + } + } + return userIds; + } + + /** + * Return a {@link List} containing all currently valid {@link OpenPGPUserId OpenPGPUserIds} on this + * primary key. + * + * @return valid userids + */ + public List getValidUserIds() + { + return getValidUserIDs(new Date()); + } + + /** + * Return a {@link List} containing all valid (at evaluation time) {@link OpenPGPUserId OpenPGPUserIds} + * on this primary key. + * + * @param evaluationTime reference time + * @return valid (at evaluation time) userids + */ + public List getValidUserIDs(Date evaluationTime) + { + List userIds = new ArrayList(); + for (Iterator it = identityComponents.iterator(); it.hasNext(); ) + { + OpenPGPIdentityComponent identity = it.next(); + if (identity instanceof OpenPGPUserId && identity.isBoundAt(evaluationTime)) + { + userIds.add((OpenPGPUserId)identity); + } + } + return userIds; + } + + /** + * Return the {@link OpenPGPUserId}, which is - at evaluation time - explicitly marked as primary. + * + * @param evaluationTime evaluation time + * @return explicit primary userid + */ + public OpenPGPUserId getExplicitPrimaryUserId(Date evaluationTime) + { + // Return the latest, valid, explicitly marked as primary UserID + OpenPGPSignature latestBinding = null; + OpenPGPUserId latestUid = null; + + for (Iterator it = getUserIDs().iterator(); it.hasNext(); ) + { + OpenPGPUserId userId = it.next(); + OpenPGPSignature.OpenPGPSignatureSubpacket subpacket = + userId.getApplyingSubpacket(evaluationTime, SignatureSubpacketTags.PRIMARY_USER_ID); + if (subpacket == null) + { + // Not bound at this time, or not explicit + continue; + } + + PrimaryUserID primaryUserId = (PrimaryUserID)subpacket.getSubpacket(); + if (!primaryUserId.isPrimaryUserID()) + { + // explicitly marked as not primary + continue; + } + + if (latestBinding == null || + subpacket.getSignature().getCreationTime().after(latestBinding.getCreationTime())) + { + latestBinding = subpacket.getSignature(); + latestUid = userId; + } + } + return latestUid; + } + + /** + * Return the {@link OpenPGPUserId}, which is - at evaluation time - considered primary, + * either because it is explicitly marked as primary userid, or because it is implicitly primary + * (e.g. because it is the sole user-id on the key). + * + * @param evaluationTime evaluation time + * @return primary user-id + */ + public OpenPGPUserId getExplicitOrImplicitPrimaryUserId(Date evaluationTime) + { + OpenPGPUserId explicitPrimaryUserId = getExplicitPrimaryUserId(evaluationTime); + if (explicitPrimaryUserId != null) + { + return explicitPrimaryUserId; + } + + // If no explicitly marked, valid primary UserID is found, return the oldest, valid UserId instead. + OpenPGPSignature oldestBinding = null; + OpenPGPUserId oldestUid = null; + + for (Iterator it = getUserIDs().iterator(); it.hasNext(); ) + { + OpenPGPUserId userId = it.next(); + OpenPGPSignatureChain chain = userId.getSignatureChains() + .getCertificationAt(evaluationTime); + if (chain == null) + { + // Not valid at this time + continue; + } + + OpenPGPSignature binding = chain.getSignature(); + if (oldestBinding == null || + binding.getCreationTime().before(oldestBinding.getCreationTime())) + { + oldestBinding = binding; + oldestUid = userId; + } + } + return oldestUid; + } + + /** + * Return all {@link OpenPGPUserAttribute OpenPGPUserAttributes} on this key. + * + * @return user attributes + */ + public List getUserAttributes() + { + List userAttributes = new ArrayList(); + for (Iterator it = identityComponents.iterator(); it.hasNext(); ) + { + OpenPGPIdentityComponent identity = it.next(); + if (identity instanceof OpenPGPUserAttribute) + { + userAttributes.add((OpenPGPUserAttribute)identity); + } + } + return userAttributes; + } + + /** + * Return all direct-key and key-revocation signatures on the primary key. + * + * @return key signatures + */ + protected List getKeySignatures() + { + Iterator iterator = rawPubkey.getSignatures(); + List list = new ArrayList(); + while (iterator.hasNext()) + { + PGPSignature sig = iterator.next(); + int type = sig.getSignatureType(); + if (type != PGPSignature.DIRECT_KEY && type != PGPSignature.KEY_REVOCATION) + { + continue; + } + // try to find issuer for self-signature + OpenPGPCertificate.OpenPGPComponentKey issuer = getCertificate() + .getSigningKeyFor(sig); + + list.add(new OpenPGPCertificate.OpenPGPComponentSignature(sig, issuer, this)); + } + return list; + } + + /** + * Return all signatures on the given {@link OpenPGPUserId}. + * + * @param identity user-id + * @return list of user-id signatures + */ + protected List getUserIdSignatures(OpenPGPUserId identity) + { + Iterator iterator = rawPubkey.getSignaturesForID(identity.getUserId()); + return signIterToList(identity, iterator); + } + + /** + * Return all signatures on the given {@link OpenPGPUserAttribute}. + * + * @param identity user-attribute + * @return list of user-attribute signatures + */ + protected List getUserAttributeSignatures(OpenPGPUserAttribute identity) + { + Iterator iterator = rawPubkey.getSignaturesForUserAttribute(identity.getUserAttribute()); + return signIterToList(identity, iterator); + } + + private List signIterToList(OpenPGPIdentityComponent identity, Iterator iterator) + { + List list = new ArrayList(); + while (iterator.hasNext()) + { + PGPSignature sig = iterator.next(); + // try to find issuer for self-signature + OpenPGPComponentKey issuer = getCertificate() + .getSigningKeyFor(sig); + + list.add(new OpenPGPComponentSignature(sig, issuer, identity)); + } + return list; + } + } + + /** + * A subkey on a {@link OpenPGPCertificate}. + */ + public static class OpenPGPSubkey + extends OpenPGPComponentKey + { + public OpenPGPSubkey(PGPPublicKey rawPubkey, OpenPGPCertificate certificate) + { + super(rawPubkey, certificate); + } + + @Override + public boolean isPrimaryKey() + { + return false; + } + + @Override + public String toString() + { + return "Subkey[" + Long.toHexString(getKeyIdentifier().getKeyId()).toUpperCase(Locale.getDefault()) + "]"; + } + + @Override + public String toDetailString() + { + return "Subkey[" + getKeyIdentifier() + "] (" + UTCUtil.format(getCreationTime()) + ")"; + } + + /** + * Return all subkey-binding and -revocation signatures on the subkey. + * + * @return subkey signatures + */ + protected List getKeySignatures() + { + Iterator iterator = rawPubkey.getSignatures(); + List list = new ArrayList(); + while (iterator.hasNext()) + { + PGPSignature sig = iterator.next(); + int type = sig.getSignatureType(); + if (type != PGPSignature.SUBKEY_BINDING && type != PGPSignature.SUBKEY_REVOCATION) + { + continue; + } + // try to find issuer for self-signature + OpenPGPCertificate.OpenPGPComponentKey issuer = getCertificate() + .getSigningKeyFor(sig); + + list.add(new OpenPGPCertificate.OpenPGPComponentSignature(sig, issuer, this)); + } + return list; + } + } + + /** + * An identity bound to the {@link OpenPGPPrimaryKey} of a {@link OpenPGPCertificate}. + * An identity may either be a {@link OpenPGPUserId} or (deprecated) {@link OpenPGPUserAttribute}. + */ + public static abstract class OpenPGPIdentityComponent + extends OpenPGPCertificateComponent + { + private final OpenPGPPrimaryKey primaryKey; + + public OpenPGPIdentityComponent(OpenPGPPrimaryKey primaryKey) + { + super(primaryKey.getCertificate()); + this.primaryKey = primaryKey; + } + + /** + * Return the primary key, which this identity belongs to. + * + * @return primary key + */ + public OpenPGPPrimaryKey getPrimaryKey() + { + return primaryKey; + } + + @Override + public OpenPGPComponentSignature getLatestSelfSignature(Date evaluationTime) + { + OpenPGPSignatureChain currentChain = getSignatureChains().getChainAt(evaluationTime); + if (currentChain != null && !currentChain.chainLinks.isEmpty()) + { + return currentChain.getSignature(); + } + return null; + } + + @Override + protected OpenPGPComponentKey getKeyComponent() + { + return primaryKey; + } + + /** + * Return the latest {@link OpenPGPSignatureChain} containing a certification issued by the given + * 3rd-party certificate over this identity component. + * + * @param thirdPartyCertificate certificate of a 3rd party + * @return 3rd party certification + */ + public OpenPGPSignatureChain getCertificationBy(OpenPGPCertificate thirdPartyCertificate) + { + return getCertificationBy(thirdPartyCertificate, new Date()); + } + + /** + * Return the latest (at evaluation time) {@link OpenPGPSignatureChain} containing a certification + * issued by the given 3rd-party certificate over this identity component. + * + * @param evaluationTime reference time + * @param thirdPartyCertificate certificate of a 3rd party + * @return 3rd party certification + */ + public OpenPGPSignatureChain getCertificationBy( + OpenPGPCertificate thirdPartyCertificate, + Date evaluationTime) + { + OpenPGPSignatureChains chainsBy = getMergedDanglingExternalSignatureChainEndsFrom(thirdPartyCertificate, evaluationTime); + return chainsBy.getCertificationAt(evaluationTime); + } + + /** + * Return the latest {@link OpenPGPSignatureChain} containing a revocation issued by the given + * 3rd-party certificate over this identity component. + * + * @param thirdPartyCertificate certificate of a 3rd party + * @return 3rd party revocation signature + */ + public OpenPGPSignatureChain getRevocationBy(OpenPGPCertificate thirdPartyCertificate) + { + return getRevocationBy(thirdPartyCertificate, new Date()); + } + + /** + * Return the latest (at evaluation time) {@link OpenPGPSignatureChain} containing a revocation issued by the given + * 3rd-party certificate over this identity component. + * + * @param thirdPartyCertificate certificate of a 3rd party + * @param evaluationTime reference time + * @return 3rd party revocation signature + */ + public OpenPGPSignatureChain getRevocationBy( + OpenPGPCertificate thirdPartyCertificate, + Date evaluationTime) + { + OpenPGPSignatureChains chainsBy = getMergedDanglingExternalSignatureChainEndsFrom(thirdPartyCertificate, evaluationTime); + return chainsBy.getRevocationAt(evaluationTime); + } + + @Override + public String toDetailString() + { + return toString(); + } + } + + /** + * A UserId. + */ + public static class OpenPGPUserId + extends OpenPGPIdentityComponent + { + private final String userId; + + public OpenPGPUserId(String userId, OpenPGPPrimaryKey primaryKey) + { + super(primaryKey); + this.userId = userId; + } + + /** + * Return the {@link String} representation of the {@link OpenPGPUserId}. + * + * @return user-id + */ + public String getUserId() + { + return userId; + } + + @Override + public String toString() + { + return "UserID[" + userId + "]"; + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (this == obj) + { + return true; + } + if (!(obj instanceof OpenPGPUserId)) + { + return false; + } + return getUserId().equals(((OpenPGPUserId)obj).getUserId()); + } + + @Override + public int hashCode() + { + return userId.hashCode(); + } + } + + /** + * A UserAttribute. + * Use of UserAttributes is deprecated in RFC9580. + */ + public static class OpenPGPUserAttribute + extends OpenPGPIdentityComponent + { + + private final PGPUserAttributeSubpacketVector userAttribute; + + public OpenPGPUserAttribute(PGPUserAttributeSubpacketVector userAttribute, OpenPGPPrimaryKey primaryKey) + { + super(primaryKey); + this.userAttribute = userAttribute; + } + + /** + * Return the underlying {@link PGPUserAttributeSubpacketVector} representing this {@link OpenPGPUserAttribute}. + * + * @return user attribute subpacket vector + */ + public PGPUserAttributeSubpacketVector getUserAttribute() + { + return userAttribute; + } + + @Override + public String toString() + { + return "UserAttribute" + userAttribute.toString(); + } + } + + /** + * Chain of {@link OpenPGPSignature signatures}. + * Such a chain originates from a certificates primary key and points towards some certificate component that + * is bound to the certificate. + * As for example a subkey can only be bound by a primary key that holds either at least one + * direct-key self-signature or at least one user-id binding signature, multiple signatures may form + * a validity chain. + * An {@link OpenPGPSignatureChain} can either be a certification + * ({@link #isCertification()}), e.g. it represents a positive binding, + * or it can be a revocation ({@link #isRevocation()}) which invalidates a positive binding. + */ + public static class OpenPGPSignatureChain + implements Comparable, Iterable + { + private final List chainLinks = new ArrayList(); + + private OpenPGPSignatureChain(Link rootLink) + { + this.chainLinks.add(rootLink); + } + + private OpenPGPSignatureChain(List links) + { + this.chainLinks.addAll(links); + } + + // copy constructor + private OpenPGPSignatureChain(OpenPGPSignatureChain copy) + { + this(copy.chainLinks); + } + + /** + * Return the signature from the leaf of the chain, which directly applies to the + * {@link OpenPGPCertificateComponent}. + * + * @return signature + */ + public OpenPGPComponentSignature getSignature() + { + return getLeafLink().getSignature(); + } + + /** + * Return the first revocation signature in the chain, or null if the chain does not contain any revocations. + * + * @return first revocation signature + */ + public OpenPGPComponentSignature getRevocation() + { + for (OpenPGPComponentSignature signature : getSignatures()) + { + if (signature.isRevocation()) + { + return signature; + } + } + return null; + } + + /** + * Return a List of all signatures in the chain. + * + * @return list of signatures + */ + public List getSignatures() + { + List signatures = new ArrayList(); + for (Link link : chainLinks) + { + signatures.add(link.getSignature()); + } + return signatures; + } + + /** + * Return an NEW instance of the {@link OpenPGPSignatureChain} with the new link appended. + * + * @param sig signature + * @return new instance + */ + public OpenPGPSignatureChain plus(OpenPGPComponentSignature sig) + { + if (getLeafLinkTargetKey() != sig.getIssuerComponent()) + { + throw new IllegalArgumentException("Chain head is not equal to link issuer."); + } + + OpenPGPSignatureChain chain = new OpenPGPSignatureChain(this); + + chain.chainLinks.add(Link.create(sig)); + + return chain; + } + + /** + * Factory method for creating an {@link OpenPGPSignatureChain} with only a single link. + * + * @param sig signature + * @return chain + */ + public static OpenPGPSignatureChain direct(OpenPGPComponentSignature sig) + { + return new OpenPGPSignatureChain(Link.create(sig)); + } + + /** + * Return the very first link in the chain. + * This is typically a link that originates from the issuing certificates primary key. + * + * @return root link + */ + public Link getRootLink() + { + return chainLinks.get(0); + } + + /** + * Return the issuer of the root link. This is typically the issuing certificates primary key. + * + * @return root links issuer + */ + public OpenPGPComponentKey getRootLinkIssuer() + { + return getRootLink().getSignature().getIssuer(); + } + + /** + * Return the last link in the chain, which applies to the chains target component. + * + * @return leaf link + */ + public Link getLeafLink() + { + return chainLinks.get(chainLinks.size() - 1); + } + + /** + * Return the {@link OpenPGPComponentKey} to which the leaf link applies to. + * For subkey binding signatures, this is the subkey. + * For user-id certification signatures, it is the primary key. + * + * @return target key component of the leaf link + */ + public OpenPGPComponentKey getLeafLinkTargetKey() + { + return getSignature().getTargetKeyComponent(); + } + + /** + * Return true, if the chain only consists of non-revocation signatures and is therefore a certification chain. + * + * @return true if the chain is a certification, false if it contains a revocation link. + */ + public boolean isCertification() + { + for (Iterator it = chainLinks.iterator(); it.hasNext(); ) + { + if (it.next() instanceof Revocation) + { + return false; + } + } + return true; + } + + /** + * Return true, if the chain contains at least one revocation signature. + * + * @return true if the chain is a revocation. + */ + public boolean isRevocation() + { + for (Iterator it = chainLinks.iterator(); it.hasNext(); ) + { + if (it.next() instanceof Revocation) + { + return true; + } + } + return false; + } + + /** + * Return true, if the chain contains at least one link that represents a hard revocation. + * + * @return true if chain is hard revocation, false if it is a certification or soft revocation + */ + public boolean isHardRevocation() + { + for (Iterator it = chainLinks.iterator(); it.hasNext(); ) + { + if (it.next().signature.signature.isHardRevocation()) + { + return true; + } + } + return false; + } + + /** + * Return the date since which this signature chain is valid. + * This is the creation time of the most recent link in the chain. + * + * @return most recent signature creation time + */ + public Date getSince() + { + Date latestDate = null; + for (Iterator it = chainLinks.iterator(); it.hasNext(); ) + { + Link link = (Link)it.next(); + OpenPGPComponentSignature signature = link.getSignature(); + Date currentDate = signature.getCreationTime(); + if (latestDate == null || currentDate.after(latestDate)) + { + latestDate = currentDate; + } + } + return latestDate; + } +// public Date getSince() +// { +// // Find most recent chain link +//// return chainLinks.stream() +//// .map(it -> it.signature) +//// .max(Comparator.comparing(OpenPGPComponentSignature::getCreationTime)) +//// .map(OpenPGPComponentSignature::getCreationTime) +//// .orElse(null); +// return chainLinks.stream() +// .map(new Function() +// { +// @Override +// public OpenPGPComponentSignature apply(Link it) +// { +// return it.signature; // Replace lambda: `it -> it.signature` +// } +// +// }) +// .max(new Comparator() +// { +// @Override +// public int compare(Object o1, Object o2) +// { +// // Replace method reference: `Comparator.comparing(OpenPGPComponentSignature::getCreationTime)` +// return ((OpenPGPComponentSignature)o1).getCreationTime().compareTo(((OpenPGPComponentSignature)o2).getCreationTime()); +// } +// }) +// .map(new Function() +// { +// @Override +// public Date apply(Object sig) +// { +// return ((OpenPGPComponentSignature)sig).getCreationTime(); // Replace method reference: `OpenPGPComponentSignature::getCreationTime` +// } +// }) +// .orElse(null); +// } + + /** + * Return the date until which the chain link is valid. + * This is the earliest expiration time of any signature in the chain. + * + * @return earliest expiration time + */ + public Date getUntil() + { + Date soonestExpiration = null; + for (Iterator it = chainLinks.iterator(); it.hasNext(); ) + { + Link link = it.next(); + Date until = link.until(); + if (until != null) + { + soonestExpiration = (soonestExpiration == null) ? until : + (until.before(soonestExpiration) ? until : soonestExpiration); + } + } + return soonestExpiration; + } + + /** + * Return true if the chain is effective at the given evaluation date, meaning all link signatures have + * been created before the evaluation time, and none signature expires before the evaluation time. + * + * @param evaluationDate reference time + * @return true if chain is effective at evaluation date + */ + public boolean isEffectiveAt(Date evaluationDate) + { + if (isHardRevocation()) + { + return true; + } + Date since = getSince(); + Date until = getUntil(); + // since <= eval <= until + return !evaluationDate.before(since) && (until == null || !evaluationDate.after(until)); + } + + /** + * Return true if the signature chain is valid, meaning all its chain links are valid. + * + * @return true if chain is valid + * @throws PGPSignatureException if an exception occurs during signature verification + */ + public boolean isValid() + throws PGPSignatureException + { + OpenPGPComponentKey rootKey = getRootLinkIssuer(); + if (rootKey == null) + { + throw new MissingIssuerCertException(getRootLink().signature, "Missing issuer certificate."); + } + OpenPGPCertificate cert = rootKey.getCertificate(); + return isValid(cert.implementation.pgpContentVerifierBuilderProvider(), cert.policy); + } + + /** + * Return true if the signature chain is valid, meaning all its chain links are valid. + * + * @param contentVerifierBuilderProvider provider for content verifier builders + * @param policy algorithm policy + * @return true if chain is valid + * @throws PGPSignatureException if an exception occurs during signature verification + */ + public boolean isValid(PGPContentVerifierBuilderProvider contentVerifierBuilderProvider, OpenPGPPolicy policy) + throws PGPSignatureException + { + boolean correct = true; + for (Iterator it = chainLinks.iterator(); it.hasNext(); ) + { + Link link = it.next(); + if (!link.signature.isTested) + { + link.verify(contentVerifierBuilderProvider, policy); + } + + if (!link.signature.isCorrect) + { + correct = false; + } + } + return correct; + } + + @Override + public String toString() + { + StringBuilder b = new StringBuilder(); + String until = getUntil() == null ? "EndOfTime" : UTCUtil.format(getUntil()); + b.append("From ").append(UTCUtil.format(getSince())).append(" until ").append(until).append("\n"); + for (Iterator it = chainLinks.iterator(); it.hasNext(); ) + { + Link link = it.next(); + b.append(" ").append(link.toString()).append("\n"); + } + return b.toString(); + } + + @Override + public int compareTo(OpenPGPSignatureChain other) + { + if (this == other) + { + return 0; + } + + if (isHardRevocation()) + { + return -1; + } + + if (other.isHardRevocation()) + { + return 1; + } + + int compare = -getRootLink().since().compareTo(other.getRootLink().since()); + if (compare != 0) + { + return compare; + } + + compare = -getLeafLink().since().compareTo(other.getLeafLink().since()); + if (compare != 0) + { + return compare; + } + + if (isRevocation()) + { + return 1; + } + return -1; + } + + @Override + public Iterator iterator() + { + return chainLinks.iterator(); + } + + /** + * Link in a {@link OpenPGPSignatureChain}. + */ + public static abstract class Link + { + protected final OpenPGPComponentSignature signature; + + public Link(OpenPGPComponentSignature signature) + { + this.signature = signature; + } + + /** + * Return the {@link Date} since when the link is effective. + * This is the creation time of the signature. + * + * @return signature creation time + */ + public Date since() + { + return signature.getCreationTime(); + } + + /** + * Return the {@link Date} until the signature is effective. + * This is, depending on which event is earlier in time, either the signature expiration time, + * or the key expiration time. + * + * @return time until the link is valid + */ + public Date until() + { + Date backSigExpiration = getBackSigExpirationTime(); + Date expirationTime = signature.getExpirationTime(); + + if (expirationTime == null) + { + return backSigExpiration; + } + + if (backSigExpiration == null || expirationTime.before(backSigExpiration)) + { + return expirationTime; + } + return backSigExpiration; + } + + /** + * Return the expiration time of the primary key binding signature. + * + * @return primary key binding signature expiration time + */ + private Date getBackSigExpirationTime() + { + if (signature.getSignature().getSignatureType() != PGPSignature.SUBKEY_BINDING) + { + return null; + } + + PGPSignatureSubpacketVector hashedSubpackets = signature.getSignature().getHashedSubPackets(); + if (hashedSubpackets == null) + { + return null; + } + + int keyFlags = signature.getSignature().getHashedSubPackets().getKeyFlags(); + if ((keyFlags & KeyFlags.SIGN_DATA) != KeyFlags.SIGN_DATA) + { + return null; + } + + try + { + PGPSignatureList embeddedSigs = hashedSubpackets.getEmbeddedSignatures(); + if (!embeddedSigs.isEmpty()) + { + OpenPGPComponentSignature backSig = new OpenPGPComponentSignature( + embeddedSigs.get(0), + // Primary Key Binding Signature has issuer and target swapped + /* issuer= */getSignature().getTargetKeyComponent(), + /* target= */getSignature().getIssuer()); + return backSig.getExpirationTime(); + } + return null; + } + catch (PGPException e) + { + return null; + } + } + + /** + * Verify the link signature. + * + * @param contentVerifierBuilderProvider provider for content verifier builders + * @param policy algorithm policy + * @return true if the signature is valid, false otherwise + * @throws PGPSignatureException if an exception occurs during signature verification + */ + public boolean verify(PGPContentVerifierBuilderProvider contentVerifierBuilderProvider, + OpenPGPPolicy policy) + throws PGPSignatureException + { + signature.verify(contentVerifierBuilderProvider, policy); // throws if invalid + return true; + } + + @Override + public String toString() + { + return signature.toString(); + } + + /** + * Factory method for creating Links from component signatures. + * Returns either a {@link Certification} in case the signature is a binding, + * or a {@link Revocation} in case the signature is a revocation signature. + * + * @param signature component signature + * @return link + */ + public static Link create(OpenPGPComponentSignature signature) + { + if (signature.isRevocation()) + { + return new Revocation(signature); + } + else + { + return new Certification(signature); + } + } + + /** + * Return the signature of the link. + * + * @return signature + */ + public OpenPGPComponentSignature getSignature() + { + return signature; + } + } + + /** + * "Positive" signature chain link. + */ + public static class Certification + extends Link + { + /** + * Positive certification. + * + * @param signature signature + */ + public Certification(OpenPGPComponentSignature signature) + { + super(signature); + } + } + + /** + * "Negative" signature chain link. + */ + public static class Revocation + extends Link + { + /** + * Revocation. + * + * @param signature signature + */ + public Revocation(OpenPGPComponentSignature signature) + { + super(signature); + } + + @Override + public Date since() + { + if (signature.signature.isHardRevocation()) + { + // hard revocations are valid retroactively, so we return the beginning of time here + return new Date(0L); + } + return super.since(); + } + + @Override + public Date until() + { + if (signature.signature.isHardRevocation()) + { + // hard revocations do not expire, so they are effective indefinitely + return new Date(Long.MAX_VALUE); + } + return super.until(); + } + } + } + + /** + * Collection of multiple {@link OpenPGPSignatureChain} objects. + */ + public static class OpenPGPSignatureChains + implements Iterable + { + private final OpenPGPCertificateComponent targetComponent; + private final Set chains = new TreeSet(); + + public OpenPGPSignatureChains(OpenPGPCertificateComponent component) + { + this.targetComponent = component; + } + + /** + * Add a single chain to the collection. + * + * @param chain chain + */ + public void add(OpenPGPSignatureChain chain) + { + this.chains.add(chain); + } + + /** + * Add all chains to the collection. + * + * @param otherChains other chains + */ + public void addAll(OpenPGPSignatureChains otherChains) + { + this.chains.addAll(otherChains.chains); + } + + /** + * Return true if the collection is empty. + * + * @return true if empty + */ + public boolean isEmpty() + { + return chains.isEmpty(); + } + + /** + * Return a positive certification chain for the component for the given evaluationTime. + * + * @param evaluationTime time for which validity of the {@link OpenPGPCertificateComponent} is checked. + * @return positive certification chain or null + */ + public OpenPGPSignatureChain getCertificationAt(Date evaluationTime) + { + for (Iterator it = chains.iterator(); it.hasNext(); ) + { + OpenPGPSignatureChain chain = it.next(); + boolean isEffective = chain.isEffectiveAt(evaluationTime); + boolean isCertification = chain.isCertification(); + if (isEffective && isCertification) + { + return chain; + } + } + return null; + } + + /** + * Return all {@link OpenPGPSignatureChain} objects, which are valid at the given evaluation time. + * + * @param evaluationTime reference time + * @return valid chains at reference time + */ + public OpenPGPSignatureChains getChainsAt(Date evaluationTime) + { + OpenPGPSignatureChains effectiveChains = new OpenPGPSignatureChains(targetComponent); + for (Iterator it = chains.iterator(); it.hasNext(); ) + { + OpenPGPSignatureChain chain = it.next(); + if (chain.isEffectiveAt(evaluationTime)) + { + effectiveChains.add(chain); + } + } + return effectiveChains; + } + + /** + * Return a negative certification chain for the component for the given evaluationTime. + * + * @param evaluationTime time for which revocation-ness of the {@link OpenPGPCertificateComponent} is checked. + * @return negative certification chain or null + */ + public OpenPGPSignatureChain getRevocationAt(Date evaluationTime) + { + for (Iterator it = chains.iterator(); it.hasNext(); ) + { + OpenPGPSignatureChain chain = it.next(); + if (chain.isRevocation() && chain.isEffectiveAt(evaluationTime)) + { + return chain; + } + } + return null; + } + + @Override + public String toString() + { + StringBuilder b = new StringBuilder(targetComponent.toDetailString()) + .append(" is bound with ").append(chains.size()).append(" chains:").append("\n"); + for (Iterator it = chains.iterator(); it.hasNext(); ) + { + OpenPGPSignatureChain chain = it.next(); + b.append(chain.toString()); + } + return b.toString(); + } + + /** + * Return all {@link OpenPGPSignatureChain} items which originate from the root {@link OpenPGPComponentKey}. + * + * @param root root key + * @return all chains with root key as origin + */ + public OpenPGPSignatureChains fromOrigin(OpenPGPComponentKey root) + { + OpenPGPSignatureChains chainsFromRoot = new OpenPGPSignatureChains(root); + for (Iterator it = chains.iterator(); it.hasNext(); ) + { + OpenPGPSignatureChain chain = it.next(); + if (chain.getRootLinkIssuer() == root) + { + chainsFromRoot.add(chain); + } + } + return chainsFromRoot; + } + + /** + * Return the latest chain, which is valid at the given evaluation time. + * + * @param evaluationDate reference time + * @return latest valid chain + */ + public OpenPGPSignatureChain getChainAt(Date evaluationDate) + { + OpenPGPSignatureChains atDate = getChainsAt(evaluationDate); + Iterator it = atDate.chains.iterator(); + if (it.hasNext()) + { + return it.next(); + } + return null; + } + + @Override + public Iterator iterator() + { + return chains.iterator(); + } + } + + private interface KeyFilter + { + boolean test(OpenPGPComponentKey key, Date evaluationTime); + } + + private List filterKeys(Date evaluationTime, KeyFilter filter) + { + List result = new ArrayList(); + for (Iterator it = getKeys().iterator(); it.hasNext(); ) + { + OpenPGPComponentKey key = it.next(); + if (isBound(key, evaluationTime) && filter.test(key, evaluationTime)) + { + result.add(key); + } + } + return result; + } + + private void addSignaturesToChains(List signatures, OpenPGPSignatureChains chains) + { + for (Iterator it = signatures.iterator(); it.hasNext(); ) + { + chains.add(OpenPGPSignatureChain.direct(it.next())); + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPDefaultPolicy.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPDefaultPolicy.java new file mode 100644 index 0000000000..b751ce27ee --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPDefaultPolicy.java @@ -0,0 +1,261 @@ +package org.bouncycastle.openpgp.api; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.bcpg.HashAlgorithmTags; +import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; +import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.bouncycastle.openpgp.api.util.UTCUtil; + +public class OpenPGPDefaultPolicy + implements OpenPGPPolicy +{ + private final Map documentHashAlgorithmCutoffDates = new HashMap(); + private final Map certificateHashAlgorithmCutoffDates = new HashMap(); + private final Map symmetricKeyAlgorithmCutoffDates = new HashMap(); + private final Map publicKeyMinimalBitStrengths = new HashMap(); + private int defaultDocumentSignatureHashAlgorithm = HashAlgorithmTags.SHA512; + private int defaultCertificationSignatureHashAlgorithm = HashAlgorithmTags.SHA512; + private int defaultSymmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_128; + + public OpenPGPDefaultPolicy() + { + /* + * Certification Signature Hash Algorithms + */ + setDefaultCertificationSignatureHashAlgorithm(HashAlgorithmTags.SHA512); + // SHA-3 + acceptCertificationSignatureHashAlgorithm(HashAlgorithmTags.SHA3_512); + acceptCertificationSignatureHashAlgorithm(HashAlgorithmTags.SHA3_256); + // SHA-2 + acceptCertificationSignatureHashAlgorithm(HashAlgorithmTags.SHA512); + acceptCertificationSignatureHashAlgorithm(HashAlgorithmTags.SHA384); + acceptCertificationSignatureHashAlgorithm(HashAlgorithmTags.SHA256); + acceptCertificationSignatureHashAlgorithm(HashAlgorithmTags.SHA224); + // SHA-1 + acceptCertificationSignatureHashAlgorithmUntil(HashAlgorithmTags.SHA1, UTCUtil.parse("2023-02-01 00:00:00 UTC")); + + acceptCertificationSignatureHashAlgorithmUntil(HashAlgorithmTags.RIPEMD160, UTCUtil.parse("2023-02-01 00:00:00 UTC")); + acceptCertificationSignatureHashAlgorithmUntil(HashAlgorithmTags.MD5, UTCUtil.parse("1997-02-01 00:00:00 UTC")); + + /* + * Document Signature Hash Algorithms + */ + setDefaultDocumentSignatureHashAlgorithm(HashAlgorithmTags.SHA512); + // SHA-3 + acceptDocumentSignatureHashAlgorithm(HashAlgorithmTags.SHA3_512); + acceptDocumentSignatureHashAlgorithm(HashAlgorithmTags.SHA3_256); + // SHA-2 + acceptDocumentSignatureHashAlgorithm(HashAlgorithmTags.SHA512); + acceptDocumentSignatureHashAlgorithm(HashAlgorithmTags.SHA384); + acceptDocumentSignatureHashAlgorithm(HashAlgorithmTags.SHA256); + acceptDocumentSignatureHashAlgorithm(HashAlgorithmTags.SHA224); + + /* + * Symmetric Key Algorithms + */ + setDefaultSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.AES_128); + acceptSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.AES_256); + acceptSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.AES_192); + acceptSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.AES_128); + acceptSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.TWOFISH); + acceptSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.CAMELLIA_256); + acceptSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.CAMELLIA_192); + acceptSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.CAMELLIA_128); + + /* + * Public Key Algorithms and key strengths + */ + acceptPublicKeyAlgorithmWithMinimalStrength(PublicKeyAlgorithmTags.RSA_GENERAL, 2000); + acceptPublicKeyAlgorithmWithMinimalStrength(PublicKeyAlgorithmTags.RSA_ENCRYPT, 2000); + acceptPublicKeyAlgorithmWithMinimalStrength(PublicKeyAlgorithmTags.RSA_SIGN, 2000); + + acceptPublicKeyAlgorithmWithMinimalStrength(PublicKeyAlgorithmTags.ECDSA, 250); + acceptPublicKeyAlgorithmWithMinimalStrength(PublicKeyAlgorithmTags.EDDSA_LEGACY, 250); + acceptPublicKeyAlgorithmWithMinimalStrength(PublicKeyAlgorithmTags.ECDH, 250); + + acceptPublicKeyAlgorithm(PublicKeyAlgorithmTags.X25519); + acceptPublicKeyAlgorithm(PublicKeyAlgorithmTags.X448); + acceptPublicKeyAlgorithm(PublicKeyAlgorithmTags.Ed25519); + acceptPublicKeyAlgorithm(PublicKeyAlgorithmTags.Ed448); + } + + public OpenPGPDefaultPolicy rejectHashAlgorithm(int hashAlgorithmId) + { + certificateHashAlgorithmCutoffDates.remove(hashAlgorithmId); + documentHashAlgorithmCutoffDates.remove(hashAlgorithmId); + return this; + } + + public OpenPGPDefaultPolicy acceptCertificationSignatureHashAlgorithm(int hashAlgorithmId) + { + return acceptCertificationSignatureHashAlgorithmUntil(hashAlgorithmId, null); + } + + public OpenPGPDefaultPolicy acceptCertificationSignatureHashAlgorithmUntil(int hashAlgorithmId, Date until) + { + certificateHashAlgorithmCutoffDates.put(hashAlgorithmId, until); + return this; + } + + public OpenPGPDefaultPolicy acceptDocumentSignatureHashAlgorithm(int hashAlgorithmId) + { + return acceptDocumentSignatureHashAlgorithmUntil(hashAlgorithmId, null); + } + + public OpenPGPDefaultPolicy acceptDocumentSignatureHashAlgorithmUntil(int hashAlgorithmId, Date until) + { + documentHashAlgorithmCutoffDates.put(hashAlgorithmId, until); + return this; + } + + public OpenPGPDefaultPolicy rejectSymmetricKeyAlgorithm(int symmetricKeyAlgorithmId) + { + symmetricKeyAlgorithmCutoffDates.remove(symmetricKeyAlgorithmId); + return this; + } + + public OpenPGPDefaultPolicy acceptSymmetricKeyAlgorithm(int symmetricKeyAlgorithmId) + { + return acceptSymmetricKeyAlgorithmUntil(symmetricKeyAlgorithmId, null); + } + + public OpenPGPDefaultPolicy acceptSymmetricKeyAlgorithmUntil(int symmetricKeyAlgorithmId, Date until) + { + symmetricKeyAlgorithmCutoffDates.put(symmetricKeyAlgorithmId, until); + return this; + } + + public OpenPGPDefaultPolicy rejectPublicKeyAlgorithm(int publicKeyAlgorithmId) + { + publicKeyMinimalBitStrengths.remove(publicKeyAlgorithmId); + return this; + } + + public OpenPGPDefaultPolicy acceptPublicKeyAlgorithm(int publicKeyAlgorithmId) + { + publicKeyMinimalBitStrengths.put(publicKeyAlgorithmId, null); + return this; + } + + public OpenPGPDefaultPolicy acceptPublicKeyAlgorithmWithMinimalStrength(int publicKeyAlgorithmId, int minBitStrength) + { + publicKeyMinimalBitStrengths.put(publicKeyAlgorithmId, minBitStrength); + return this; + } + + @Override + public boolean isAcceptableDocumentSignatureHashAlgorithm(int hashAlgorithmId, Date signatureCreationTime) + { + return isAcceptable(hashAlgorithmId, signatureCreationTime, documentHashAlgorithmCutoffDates); + } + + @Override + public boolean isAcceptableRevocationSignatureHashAlgorithm(int hashAlgorithmId, Date signatureCreationTime) + { + return isAcceptable(hashAlgorithmId, signatureCreationTime, certificateHashAlgorithmCutoffDates); + } + + @Override + public boolean isAcceptableCertificationSignatureHashAlgorithm(int hashAlgorithmId, Date signatureCreationTime) + { + return isAcceptable(hashAlgorithmId, signatureCreationTime, certificateHashAlgorithmCutoffDates); + } + + @Override + public int getDefaultCertificationSignatureHashAlgorithm() + { + return defaultCertificationSignatureHashAlgorithm; + } + + public OpenPGPDefaultPolicy setDefaultCertificationSignatureHashAlgorithm(int hashAlgorithmId) + { + defaultCertificationSignatureHashAlgorithm = hashAlgorithmId; + return this; + } + + @Override + public int getDefaultDocumentSignatureHashAlgorithm() + { + return defaultDocumentSignatureHashAlgorithm; + } + + public OpenPGPDefaultPolicy setDefaultDocumentSignatureHashAlgorithm(int hashAlgorithmId) + { + defaultDocumentSignatureHashAlgorithm = hashAlgorithmId; + return this; + } + + @Override + public boolean isAcceptableSymmetricKeyAlgorithm(int symmetricKeyAlgorithmId) + { + return isAcceptable(symmetricKeyAlgorithmId, symmetricKeyAlgorithmCutoffDates); + } + + @Override + public int getDefaultSymmetricKeyAlgorithm() + { + return defaultSymmetricKeyAlgorithm; + } + + public OpenPGPDefaultPolicy setDefaultSymmetricKeyAlgorithm(int symmetricKeyAlgorithmId) + { + defaultSymmetricKeyAlgorithm = symmetricKeyAlgorithmId; + return this; + } + + @Override + public boolean isAcceptablePublicKeyStrength(int publicKeyAlgorithmId, int bitStrength) + { + return isAcceptable(publicKeyAlgorithmId, bitStrength, publicKeyMinimalBitStrengths); + } + + @Override + public OpenPGPNotationRegistry getNotationRegistry() + { + return null; + } + + private boolean isAcceptable(int algorithmId, Date usageDate, Map cutoffTable) + { + if (!cutoffTable.containsKey(algorithmId)) + { + // algorithm is not listed in the map at all + return false; + } + + Date cutoffDate = cutoffTable.get(algorithmId); + if (cutoffDate == null) + { + // no cutoff date given -> algorithm is acceptable indefinitely + return true; + } + + return usageDate.before(cutoffDate); + } + + private boolean isAcceptable(int algorithmId, Map cutoffTable) + { + return cutoffTable.containsKey(algorithmId); + } + + private boolean isAcceptable(int algorithmId, int bitStrength, Map minBitStrengths) + { + if (!minBitStrengths.containsKey(algorithmId)) + { + // algorithm is not listed in the map at all + return false; + } + + Integer minBitStrength = minBitStrengths.get(algorithmId); + if (minBitStrength == null) + { + // no minimal bit strength defined -> accept all strengths + return true; + } + + return bitStrength >= minBitStrength; + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPDetachedSignatureGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPDetachedSignatureGenerator.java new file mode 100644 index 0000000000..68b5390c12 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPDetachedSignatureGenerator.java @@ -0,0 +1,96 @@ +package org.bouncycastle.openpgp.api; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureGenerator; + +/** + * High-Level OpenPGP Signature Generator for Detached Signatures. + * Detached signatures can be stored and distributed as a distinct object alongside the signed data. + * They are used for example to sign Release files of some Linux software distributions. + *

    + * To use this class, instantiate it, optionally providing a concrete {@link OpenPGPImplementation} and + * {@link OpenPGPPolicy} for algorithm policing. + * Then, add the desired {@link OpenPGPKey} you want to use for signing the data via one or more + * calls to {@link #addSigningKey(OpenPGPKey, KeyPassphraseProvider)}. + * You have fine-grained control over the signature by using the method + * {@link #addSigningKey(OpenPGPKey.OpenPGPSecretKey, char[], SignatureParameters.Callback)}. + * Lastly, retrieve a list of detached {@link OpenPGPSignature.OpenPGPDocumentSignature signatures} by calling + * {@link #sign(InputStream)}, passing in an {@link InputStream} containing the data you want to sign. + */ +public class OpenPGPDetachedSignatureGenerator + extends AbstractOpenPGPDocumentSignatureGenerator +{ + /** + * Instantiate a signature generator using the default {@link OpenPGPImplementation} and its {@link OpenPGPPolicy}. + */ + public OpenPGPDetachedSignatureGenerator() + { + this(OpenPGPImplementation.getInstance()); + } + + /** + * Instantiate a signature generator using the passed in {@link OpenPGPImplementation} and its {@link OpenPGPPolicy}. + * + * @param implementation custom OpenPGP implementation + */ + public OpenPGPDetachedSignatureGenerator(OpenPGPImplementation implementation) + { + this(implementation, implementation.policy()); + } + + /** + * Instantiate a signature generator using a custom {@link OpenPGPImplementation} and custom {@link OpenPGPPolicy}. + * + * @param implementation custom OpenPGP implementation + * @param policy custom OpenPGP policy + */ + public OpenPGPDetachedSignatureGenerator(OpenPGPImplementation implementation, OpenPGPPolicy policy) + { + super(implementation, policy); + } + + /** + * Pass in an {@link InputStream} containing the data that shall be signed and return a list of detached + * signatures. + * + * @param inputStream data to be signed + * @return detached signatures + * + * @throws IOException if something goes wrong processing the data + * @throws PGPException if signing fails + */ + public List sign(InputStream inputStream) + throws IOException, PGPException + { + addSignToGenerator(); + + byte[] buf = new byte[2048]; + int r; + while ((r = inputStream.read(buf)) != -1) + { + for (Iterator it = signatureGenerators.iterator(); it.hasNext();) + { + ((PGPSignatureGenerator) it.next()).update(buf, 0, r); + } + } + + List documentSignatures = new ArrayList(); + for (int i = 0; i < signatureGenerators.size(); i++) + { + PGPSignatureGenerator sigGen = signatureGenerators.get(i); + PGPSignature signature = sigGen.generate(); + OpenPGPSignature.OpenPGPDocumentSignature docSig = new OpenPGPSignature.OpenPGPDocumentSignature( + signature, signingKeys.get(i)); + documentSignatures.add(docSig); + } + + return documentSignatures; + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPDetachedSignatureProcessor.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPDetachedSignatureProcessor.java new file mode 100644 index 0000000000..b2146e5ba6 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPDetachedSignatureProcessor.java @@ -0,0 +1,298 @@ +package org.bouncycastle.openpgp.api; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import org.bouncycastle.bcpg.BCPGInputStream; +import org.bouncycastle.bcpg.KeyIdentifier; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPObjectFactory; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureException; +import org.bouncycastle.openpgp.PGPSignatureList; +import org.bouncycastle.openpgp.PGPUtil; + +/** + * High-Level Processor for Messages Signed Using Detached OpenPGP Signatures. + *

    + * To use this class, first instantiate the processor, optionally passing in a concrete + * {@link OpenPGPImplementation} and {@link OpenPGPPolicy}. + * Then, pass in any detached signatures you want to verify using {@link #addSignatures(InputStream)}. + * Next, provide the expected issuers {@link OpenPGPCertificate OpenPGPCertificates} for signature + * verification using {@link #addVerificationCertificate(OpenPGPCertificate)}. + * Signatures for which no certificate was provided, and certificates for which no signature was added, + * are ignored. + * Optionally, you can specify a validity date range for the signatures using + * {@link #verifyNotBefore(Date)} and {@link #verifyNotAfter(Date)}. + * Signatures outside this range will be ignored as invalid. + * Lastly, provide an {@link InputStream} containing the original plaintext data, over which you want to + * verify the detached signatures using {@link #process(InputStream)}. + * As a result you will receive a list containing all processed + * {@link OpenPGPSignature.OpenPGPDocumentSignature OpenPGPDocumentSignatures}. + * For these, you can check validity by calling {@link OpenPGPSignature.OpenPGPDocumentSignature#isValid()}. + */ +public class OpenPGPDetachedSignatureProcessor +{ + private final OpenPGPImplementation implementation; + private final OpenPGPPolicy policy; + private final OpenPGPKeyMaterialPool.OpenPGPCertificatePool certificatePool = new OpenPGPKeyMaterialPool.OpenPGPCertificatePool(); + private final List pgpSignatures = new ArrayList(); + private Date verifyNotAfter = new Date(); // now + private Date verifyNotBefore = new Date(0L); // beginning of time + + private OpenPGPMessageProcessor.PGPExceptionCallback exceptionCallback = null; + + /** + * Instantiate a signature processor using the default {@link OpenPGPImplementation} and its {@link OpenPGPPolicy}. + */ + public OpenPGPDetachedSignatureProcessor() + { + this(OpenPGPImplementation.getInstance()); + } + + /** + * Instantiate a signature processor using a custom {@link OpenPGPImplementation} and its {@link OpenPGPPolicy}. + * + * @param implementation custom OpenPGP implementation + */ + public OpenPGPDetachedSignatureProcessor(OpenPGPImplementation implementation) + { + this(implementation, implementation.policy()); + } + + /** + * Instantiate a signature processor using a custom {@link OpenPGPImplementation} and custom {@link OpenPGPPolicy}. + * + * @param implementation custom OpenPGP implementation + * @param policy custom OpenPGP policy + */ + public OpenPGPDetachedSignatureProcessor(OpenPGPImplementation implementation, OpenPGPPolicy policy) + { + this.implementation = implementation; + this.policy = policy; + } + + /** + * Read one or more {@link PGPSignature detached signatures} from the provided {@link InputStream} and + * add them to the processor. + * + * @param inputStream input stream of armored or unarmored detached OpenPGP signatures + * @return this + * @throws IOException if something goes wrong reading from the stream + */ + public OpenPGPDetachedSignatureProcessor addSignatures(InputStream inputStream) + throws IOException + { + InputStream decoderStream = PGPUtil.getDecoderStream(inputStream); + BCPGInputStream pIn = BCPGInputStream.wrap(decoderStream); + PGPObjectFactory objFac = implementation.pgpObjectFactory(pIn); + Object next; + while ((next = objFac.nextObject()) != null) + { + if (next instanceof PGPSignatureList) + { + addSignatures((PGPSignatureList)next); + } + else if (next instanceof PGPSignature) + { + addSignature((PGPSignature)next); + } + } + return this; + } + + /** + * Add one or more {@link PGPSignature detached signatures} from the given {@link PGPSignatureList} to the + * processor. + * + * @param signatures detached signature list + * @return this + */ + public OpenPGPDetachedSignatureProcessor addSignatures(PGPSignatureList signatures) + { + for (Iterator it = signatures.iterator(); it.hasNext(); ) + { + addSignature(it.next()); + } + return this; + } + + /** + * Add a single {@link PGPSignature detached signature} to the processor. + * + * @param signature detached signature + * @return this + */ + public OpenPGPDetachedSignatureProcessor addSignature(PGPSignature signature) + { + pgpSignatures.add(signature); + return this; + } + + /** + * Add an issuers {@link OpenPGPCertificate} for signature verification. + * + * @param certificate OpenPGP certificate + * @return this + */ + public OpenPGPDetachedSignatureProcessor addVerificationCertificate(OpenPGPCertificate certificate) + { + this.certificatePool.addItem(certificate); + return this; + } + + /** + * Reject detached signatures made before

    date
    . + * By default, this value is set to the beginning of time. + * + * @param date date + * @return this + */ + public OpenPGPDetachedSignatureProcessor verifyNotBefore(Date date) + { + this.verifyNotBefore = date; + return this; + } + + /** + * Reject detached signatures made after the given
    date
    . + * By default, this value is set to the current time at instantiation time, in order to prevent + * verification of signatures from the future. + * + * @param date date + * @return this + */ + public OpenPGPDetachedSignatureProcessor verifyNotAfter(Date date) + { + this.verifyNotAfter = date; + return this; + } + + /** + * Process the plaintext data from the given {@link InputStream} and return a list of processed + * detached signatures. + * Note: This list will NOT contain any malformed signatures, or signatures for which no verification key was found. + * Correctness of these signatures can be checked via {@link OpenPGPSignature.OpenPGPDocumentSignature#isValid()}. + * + * @param inputStream data over which the detached signatures are calculated + * @return list of processed detached signatures + * @throws IOException if the data cannot be processed + */ + public List process(InputStream inputStream) + throws IOException + { + List documentSignatures = new ArrayList(); + for (Iterator it = pgpSignatures.iterator(); it.hasNext(); ) + { + PGPSignature signature = (PGPSignature)it.next(); + // Match up signatures with certificates + + KeyIdentifier identifier = OpenPGPSignature.getMostExpressiveIdentifier(signature.getKeyIdentifiers()); + if (identifier == null) + { + // Missing issuer -> ignore sig + continue; + } + + OpenPGPCertificate certificate = certificatePool.provide(identifier); + if (certificate == null) + { + // missing cert -> ignore sig + continue; + } + + OpenPGPCertificate.OpenPGPComponentKey signingKey = certificate.getKey(identifier); + if (signingKey == null) + { + // unbound signing subkey -> ignore sig + continue; + } + + // Initialize signatures with verification key + try + { + signature.init(implementation.pgpContentVerifierBuilderProvider(), signingKey.getPGPPublicKey()); + } + catch (PGPException e) + { + if (exceptionCallback != null) + { + exceptionCallback.onException(e); + } + continue; + } + + OpenPGPSignature.OpenPGPDocumentSignature sig = + new OpenPGPSignature.OpenPGPDocumentSignature(signature, signingKey); + try + { + // sanitize signature (required subpackets, check algorithm policy...) + sig.sanitize(signingKey, policy); + } + catch (PGPSignatureException e) + { + if (exceptionCallback != null) + { + exceptionCallback.onException(e); + } + continue; + } + + // check allowed date range + if (!sig.createdInBounds(verifyNotBefore, verifyNotAfter)) + { + continue; + } + + // sig qualifies for further processing :) + documentSignatures.add(sig); + } + + // Process plaintext + byte[] buf = new byte[2048]; + int r; + while ((r = inputStream.read(buf)) != -1) + { + for (Iterator it = documentSignatures.iterator(); it.hasNext(); ) + { + ((OpenPGPSignature.OpenPGPDocumentSignature)it.next()).getSignature().update(buf, 0, r); + } + } + + // Verify signatures + for (Iterator it = documentSignatures.iterator(); it.hasNext(); ) + { + try + { + // verify the signature. Correctness can be checked via + ((OpenPGPSignature.OpenPGPDocumentSignature)it.next()).verify(); + } + catch (PGPException e) + { + if (exceptionCallback != null) + { + exceptionCallback.onException(e); + } + } + } + + return documentSignatures; + } + + /** + * Add a callback to which any OpenPGP-related exceptions are forwarded. + * Useful for debugging purposes. + * + * @param callback callback + * @return this + */ + public OpenPGPDetachedSignatureProcessor setExceptionCallback(OpenPGPMessageProcessor.PGPExceptionCallback callback) + { + this.exceptionCallback = callback; + return this; + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPEncryptionNegotiator.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPEncryptionNegotiator.java new file mode 100644 index 0000000000..953bf33940 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPEncryptionNegotiator.java @@ -0,0 +1,305 @@ +package org.bouncycastle.openpgp.api; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.bouncycastle.bcpg.sig.Features; +import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites; +import org.bouncycastle.bcpg.sig.PreferredAlgorithms; + +public abstract class OpenPGPEncryptionNegotiator +{ + /** + * Negotiate encryption mode and algorithms. + * + * @param configuration message generator configuration + * @return negotiated encryption mode and algorithms + */ + public abstract MessageEncryptionMechanism negotiateEncryption(OpenPGPMessageGenerator configuration); + + static PreferredAEADCiphersuites negotiateAEADCiphersuite(List certificates, OpenPGPPolicy policy) + { + return new PreferredAEADCiphersuites(false, new PreferredAEADCiphersuites.Combination[]{ + bestAEADCiphersuiteByWeight(certificates, policy) + }); + } + + /** + * Return true, if all recipient {@link OpenPGPCertificate certificates} contain at least one subkey that supports + * {@link Features#FEATURE_SEIPD_V2}. + * + * @param certificates certificates + * @return true if all certificates support the feature, false otherwise + */ + static boolean allRecipientsSupportSeipd2(List certificates) + { + return allRecipientsSupportEncryptionFeature(certificates, Features.FEATURE_SEIPD_V2); + } + + static boolean allRecipientsSupportLibrePGPOED(List certificates) + { + return allRecipientsSupportEncryptionFeature(certificates, Features.FEATURE_AEAD_ENCRYPTED_DATA); + } + + static boolean allRecipientsSupportEncryptionFeature(List certificates, byte feature) + { + for (Iterator it = certificates.iterator(); it.hasNext(); ) + { + List encryptionKeys = ((OpenPGPCertificate)it.next()).getEncryptionKeys(); + if (encryptionKeys.isEmpty()) + { + continue; + } + + boolean recipientHasSupport = false; + for (Iterator ckIt = encryptionKeys.iterator(); ckIt.hasNext(); ) + { + Features features = ((OpenPGPCertificate.OpenPGPComponentKey)ckIt.next()).getFeatures(); + if (features != null && features.supportsFeature(feature)) + { + recipientHasSupport = true; + break; + } + } + + if (!recipientHasSupport) + { + return false; + } + } + return true; + } + + public static PreferredAEADCiphersuites.Combination bestAEADCiphersuiteByWeight( + Collection certificates, OpenPGPPolicy policy) + { + return processCertificates( + certificates, + policy, + new KeyProcessor() + { + public boolean processKey(OpenPGPCertificate.OpenPGPComponentKey key, Map capableKeys) + { + Features features = key.getFeatures(); + if (features != null && features.supportsSEIPDv2()) + { + PreferredAEADCiphersuites prefs = key.getAEADCipherSuitePreferences(); + if (prefs != null) + { + capableKeys.put(key, prefs); + return true; + } + } + return false; + } + + public List getAlgorithms(PreferredAEADCiphersuites prefs, OpenPGPPolicy policy) + { + // Weigh the preferences descending by index: w(p_i) = 1/(i+1) + // This way, combinations with a smaller index have a higher weight than combinations with larger index. + // Additionally, we divide this weight by the number of capable subkeys per cert in order to + // prevent a certificate with many capable subkeys from outvoting other certificates + List result = new ArrayList(); + for (PreferredAEADCiphersuites.Combination c : prefs.getAlgorithms()) + { + if (c.getSymmetricAlgorithm() != SymmetricKeyAlgorithmTags.NULL + && policy.isAcceptableSymmetricKeyAlgorithm(c.getSymmetricAlgorithm())) + { + result.add(c); + } + } + return result; + } + }, + PreferredAEADCiphersuites.DEFAULT().getAlgorithms()[0] + ); + } + + static int bestSymmetricKeyAlgorithmByWeight( + Collection certificates, + OpenPGPPolicy policy) + { + return processCertificates( + certificates, + policy, + new KeyProcessor() + { + @Override + public boolean processKey(OpenPGPCertificate.OpenPGPComponentKey key, + Map capableKeys) + { + Features features = key.getFeatures(); + if (features != null && features.supportsModificationDetection()) + { + PreferredAlgorithms prefs = key.getSymmetricCipherPreferences(); + if (prefs != null) + { + capableKeys.put(key, prefs); + return true; + } + } + return false; + } + + @Override + public List getAlgorithms(PreferredAlgorithms preferences, OpenPGPPolicy policy) + { + // Weigh the preferences descending by index: w(p_i) = 1/(i+1) + // This way, combinations with a smaller index have a higher weight than combinations with larger index. + // Additionally, we divide this weight by the number of capable subkeys per cert in order to + // prevent a certificate with many capable subkeys from outvoting other certificates + List result = new ArrayList(); + int[] prefs = preferences.getPreferences(); + for (int i = 0; i < prefs.length; i++) + { + int alg = prefs[i]; + if (alg != SymmetricKeyAlgorithmTags.NULL && + policy.isAcceptableSymmetricKeyAlgorithm(alg)) + { + result.add(alg); + } + } + return result; + } + }, + SymmetricKeyAlgorithmTags.AES_128 // Default value + ); + } + + static int bestOEDEncryptionModeByWeight(Collection certificates, + final OpenPGPPolicy policy) + { + return processCertificates( + certificates, + policy, + new KeyProcessor() + { + @Override + public boolean processKey(OpenPGPCertificate.OpenPGPComponentKey key, + Map capableKeys) + { + // Only consider encryption keys capable of OED + Features features = key.getFeatures(); + if (features != null && features.supportsFeature(Features.FEATURE_AEAD_ENCRYPTED_DATA)) + { + PreferredAlgorithms prefs = key.getSymmetricCipherPreferences(); + if (prefs != null) + { + capableKeys.put(key, prefs); + return true; + } + } + return false; + } + + @Override + public List getAlgorithms(PreferredAlgorithms preferences, OpenPGPPolicy policy) + { + // Count the keys symmetric key preferences (that can be used with OED) and update the weight map + + List result = new ArrayList(); + int[] prefs = preferences.getPreferences(); + for (int i = 0; i < prefs.length; i++) + { + int alg = prefs[i]; + if (isOEDCompatible(alg) && + policy.isAcceptableSymmetricKeyAlgorithm(alg)) + { + result.add(alg); + } + } + return result; + } + + private boolean isOEDCompatible(int alg) + { + switch (alg) + { + case SymmetricKeyAlgorithmTags.AES_128: + case SymmetricKeyAlgorithmTags.AES_192: + case SymmetricKeyAlgorithmTags.AES_256: + case SymmetricKeyAlgorithmTags.CAMELLIA_128: + case SymmetricKeyAlgorithmTags.CAMELLIA_192: + case SymmetricKeyAlgorithmTags.CAMELLIA_256: + return true; + default: + return false; + } + } + }, + SymmetricKeyAlgorithmTags.AES_128 // Default value + ); + } + + private interface KeyProcessor + { + /** + * Process a certificate's encryption key and return true to include it + */ + boolean processKey(OpenPGPCertificate.OpenPGPComponentKey key, Map capableKeys); + + /** + * Process preferences and return algorithms to consider + */ + List getAlgorithms(T preferences, OpenPGPPolicy policy); + } + + private static R processCertificates( + Collection certificates, + OpenPGPPolicy policy, + KeyProcessor keyProcessor, + R defaultResult) + { + Map weights = new HashMap(); + + // Go through all certificate's capable subkeys + for (Iterator it = certificates.iterator(); it.hasNext(); ) + { + List encryptionKeys = it.next().getEncryptionKeys(); + if (encryptionKeys.isEmpty()) + { + continue; + } + + // Only consider encryption keys capable of SEIPDv1/OED + Map capableKeys = new HashMap(); + for (Iterator ckIt = encryptionKeys.iterator(); ckIt.hasNext(); ) + { + keyProcessor.processKey(ckIt.next(), capableKeys); + } + + // Count the keys [AEAD preferences | symmetric key preferences (that can be used with OED)] + // and update the weight map + for (Iterator ckIt = capableKeys.keySet().iterator(); ckIt.hasNext(); ) + { + T prefs = capableKeys.get(ckIt.next()); + List algorithms = keyProcessor.getAlgorithms(prefs, policy); + for (int i = 0; i < algorithms.size(); i++) + { + R c = algorithms.get(i); + float current = weights.containsKey(c) ? weights.get(c) : 0; + weights.put(c, current + (1f / (i + 1)) / capableKeys.size()); + } + } + } + + R maxKey = defaultResult; + float maxWeight = -1; + // Select the entry with the highest weight + for (Iterator> it = weights.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry entry = it.next(); + if (entry.getValue() > maxWeight) + { + maxWeight = entry.getValue(); + maxKey = entry.getKey(); + } + } + return maxKey; + } +} \ No newline at end of file diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPImplementation.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPImplementation.java new file mode 100644 index 0000000000..1697e54879 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPImplementation.java @@ -0,0 +1,210 @@ +package org.bouncycastle.openpgp.api; + +import java.io.InputStream; + +import org.bouncycastle.bcpg.S2K; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPObjectFactory; +import org.bouncycastle.openpgp.PGPPrivateKey; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPSessionKey; +import org.bouncycastle.openpgp.api.bc.BcOpenPGPImplementation; +import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; +import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory; +import org.bouncycastle.openpgp.operator.PBEKeyEncryptionMethodGenerator; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilderProvider; +import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptorFactory; +import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; +import org.bouncycastle.openpgp.operator.PGPContentSignerBuilderProvider; +import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider; +import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder; +import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; +import org.bouncycastle.openpgp.operator.PGPKeyPairGeneratorProvider; +import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; +import org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator; +import org.bouncycastle.openpgp.operator.SessionKeyDataDecryptorFactory; + +/** + * Bouncy Castle provides two implementations of OpenPGP operators. + * The
    JCA/JCE
    implementation makes use of Java Cryptography Architecture and the + * Java Cryptography Extension, while
    Bc
    uses Bouncy Castles Lightweight Cryptography API. + * The purpose of {@link OpenPGPImplementation} is to define a shared interface for instantiating concrete + * objects of either API. + * It is advised to define the desired implementation by calling {@link #setInstance(OpenPGPImplementation)} and + * acquiring it via {@link #getInstance()}, as swapping out the entire implementation can then be done by + * replacing the instance in one single place. + * This pattern was successfully explored by PGPainless. + */ +public abstract class OpenPGPImplementation +{ + private static OpenPGPImplementation INSTANCE; + private OpenPGPPolicy policy = new OpenPGPDefaultPolicy(); + + /** + * Replace the {@link OpenPGPImplementation} instance that is returned by {@link #getInstance()}. + * @param implementation instance + */ + public static void setInstance(OpenPGPImplementation implementation) + { + INSTANCE = implementation; + } + + /** + * Return the currently set {@link OpenPGPImplementation} instance. + * The default is {@link BcOpenPGPImplementation}. + * + * @return instance + */ + public static OpenPGPImplementation getInstance() + { + if (INSTANCE == null) + { + setInstance(new BcOpenPGPImplementation()); + } + return INSTANCE; + } + + public OpenPGPPolicy policy() + { + return policy; + } + + public OpenPGPImplementation setPolicy(OpenPGPPolicy policy) + { + this.policy = policy; + return this; + } + + /** + * Return an instance of {@link PGPObjectFactory} based on the given {@link InputStream}. + * + * @param packetInputStream packet input stream + * @return object factory + */ + public abstract PGPObjectFactory pgpObjectFactory(InputStream packetInputStream); + + /** + * Return an instance of {@link PGPContentVerifierBuilderProvider} which is responsible for providing + * implementations needed for signature verification. + * + * @return content verifier builder provider + */ + public abstract PGPContentVerifierBuilderProvider pgpContentVerifierBuilderProvider(); + + /** + * Return an instance of {@link PBESecretKeyDecryptorBuilderProvider} which is responsible for providing + * implementations needed for secret key unlocking. + * + * @return secret key decryptor builder provider + */ + public abstract PBESecretKeyDecryptorBuilderProvider pbeSecretKeyDecryptorBuilderProvider(); + + /** + * Return an instance of {@link PGPDataEncryptorBuilder} which is responsible for providing implementations + * needed for creating encrypted data packets. + * + * @param symmetricKeyAlgorithm symmetric encryption algorithm + * @return data encryptor builder + */ + public abstract PGPDataEncryptorBuilder pgpDataEncryptorBuilder( + int symmetricKeyAlgorithm); + + /** + * Return an instance of {@link PublicKeyKeyEncryptionMethodGenerator} which is responsible for + * creating public-key-based encryptors for OpenPGP messages. + * Public-key-based encryptors are used when a message is encrypted for a recipients public key. + * + * @param encryptionSubkey subkey for which a message shall be encrypted + * @return public-key key-encryption method generator + */ + public abstract PublicKeyKeyEncryptionMethodGenerator publicKeyKeyEncryptionMethodGenerator( + PGPPublicKey encryptionSubkey); + + /** + * Return an instance of {@link PBEKeyEncryptionMethodGenerator} which is responsible for creating + * symmetric-key-based encryptors for OpenPGP messages, using {@link S2K#SALTED_AND_ITERATED} mode. + * Symmetric-key-based encryptors are used when a message is encrypted using a passphrase. + * + * @param messagePassphrase passphrase to encrypt the message with + * @return pbe key encryption method generator + */ + public abstract PBEKeyEncryptionMethodGenerator pbeKeyEncryptionMethodGenerator( + char[] messagePassphrase); + + /** + * Return an instance of {@link PBEKeyEncryptionMethodGenerator} which is responsible for creating + * symmetric-key-based encryptors for OpenPGP messages, using {@link S2K#ARGON_2} mode. + * Symmetric-key-based encryptors are used when a message is encrypted using a passphrase. + * + * @param messagePassphrase passphrase to encrypt the message with + * @param argon2Params parameters for the Argon2 hash function + * @return pbe key encryption method generator + */ + public abstract PBEKeyEncryptionMethodGenerator pbeKeyEncryptionMethodGenerator( + char[] messagePassphrase, + S2K.Argon2Params argon2Params); + + /** + * Return an instance of {@link PGPContentSignerBuilder}, which is responsible for providing concrete + * implementations needed for signature creation. + * + * @param publicKeyAlgorithm the signing-keys public-key algorithm + * @param hashAlgorithm signature hash algorithm + * @return content signer builder + */ + public abstract PGPContentSignerBuilder pgpContentSignerBuilder( + int publicKeyAlgorithm, + int hashAlgorithm); + + /** + * Return an instance of the {@link PBEDataDecryptorFactory}, which is responsible for providing concrete + * implementations needed to decrypt OpenPGP messages that were encrypted symmetrically with a passphrase. + * + * @param messagePassphrase message passphrase + * @return pbe data decryptor factory + * @throws PGPException if the factory cannot be instantiated + */ + public abstract PBEDataDecryptorFactory pbeDataDecryptorFactory( + char[] messagePassphrase) + throws PGPException; + + /** + * Return an instance of the {@link SessionKeyDataDecryptorFactory}, which is responsible for providing + * concrete implementations needed to decrypt OpenPGP messages using a {@link PGPSessionKey}. + * + * @param sessionKey session key + * @return session-key data decryptor factory + */ + public abstract SessionKeyDataDecryptorFactory sessionKeyDataDecryptorFactory( + PGPSessionKey sessionKey); + + /** + * Return an instance of the {@link PublicKeyDataDecryptorFactory}, which is responsible for providing + * concrete implementations needed to decrypt OpenPGP messages using a {@link PGPPrivateKey}. + * + * @param decryptionKey private decryption key + * @return public-key data decryptor factory + */ + public abstract PublicKeyDataDecryptorFactory publicKeyDataDecryptorFactory( + PGPPrivateKey decryptionKey); + + /** + * Return an instance of the {@link PGPDigestCalculatorProvider}, which is responsible for providing + * concrete {@link org.bouncycastle.openpgp.operator.PGPDigestCalculator} implementations. + * + * @return pgp digest calculator provider + * @throws PGPException if the provider cannot be instantiated + */ + public abstract PGPDigestCalculatorProvider pgpDigestCalculatorProvider() + throws PGPException; + + public abstract PGPKeyPairGeneratorProvider pgpKeyPairGeneratorProvider(); + + public abstract PGPContentSignerBuilderProvider pgpContentSignerBuilderProvider(int hashAlgorithmId); + + public abstract KeyFingerPrintCalculator keyFingerPrintCalculator(); + + public abstract PBESecretKeyEncryptorFactory pbeSecretKeyEncryptorFactory(boolean aead) throws PGPException; + + public abstract PBESecretKeyEncryptorFactory pbeSecretKeyEncryptorFactory(boolean aead, int symmetricKeyAlgorithm, int iterationCount) throws PGPException; +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKey.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKey.java new file mode 100644 index 0000000000..4bb5a98f35 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKey.java @@ -0,0 +1,584 @@ +package org.bouncycastle.openpgp.api; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.bouncycastle.bcpg.BCPGOutputStream; +import org.bouncycastle.bcpg.HashAlgorithmTags; +import org.bouncycastle.bcpg.KeyIdentifier; +import org.bouncycastle.bcpg.PacketFormat; +import org.bouncycastle.bcpg.PublicKeyPacket; +import org.bouncycastle.bcpg.S2K; +import org.bouncycastle.bcpg.SecretKeyPacket; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPKeyPair; +import org.bouncycastle.openpgp.PGPKeyValidationException; +import org.bouncycastle.openpgp.PGPPrivateKey; +import org.bouncycastle.openpgp.PGPSecretKey; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.openpgp.api.exception.KeyPassphraseException; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilderProvider; +import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; +import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptorFactory; + +/** + * An {@link OpenPGPKey} (TSK - transferable secret key) is the pendant to an {@link OpenPGPCertificate}, + * but containing the secret key material in addition to the public components. + * It consists of one or multiple {@link OpenPGPSecretKey} objects. + */ +public class OpenPGPKey + extends OpenPGPCertificate +{ + // This class extends OpenPGPCertificate, but also holds secret key components in a dedicated map. + private final Map secretKeys; + + /** + * Create an {@link OpenPGPKey} instance based on a {@link PGPSecretKeyRing}. + * The {@link OpenPGPImplementation} will be acquired by invoking {@link OpenPGPImplementation#getInstance()}. + * + * @param keyRing secret key ring + */ + public OpenPGPKey(PGPSecretKeyRing keyRing) + { + this(keyRing, OpenPGPImplementation.getInstance()); + } + + /** + * Create an {@link OpenPGPKey} instance based on a {@link PGPSecretKeyRing}, + * a provided {@link OpenPGPImplementation} and its {@link OpenPGPPolicy}. + * + * @param keyRing secret key ring + * @param implementation OpenPGP implementation + */ + public OpenPGPKey(PGPSecretKeyRing keyRing, OpenPGPImplementation implementation) + { + this(keyRing, implementation, implementation.policy()); + } + + /** + * Create an {@link OpenPGPKey} instance based on a {@link PGPSecretKeyRing}, + * a provided {@link OpenPGPImplementation} and {@link OpenPGPPolicy}. + * + * @param keyRing secret key ring + * @param implementation OpenPGP implementation + * @param policy OpenPGP policy + */ + public OpenPGPKey(PGPSecretKeyRing keyRing, OpenPGPImplementation implementation, OpenPGPPolicy policy) + { + super(keyRing, implementation, policy); + + // Process and map secret keys + this.secretKeys = new LinkedHashMap(); + for (Iterator it = getKeys().iterator(); it.hasNext(); ) + { + OpenPGPComponentKey key = (OpenPGPComponentKey)it.next(); + KeyIdentifier identifier = key.getKeyIdentifier(); + PGPSecretKey secretKey = keyRing.getSecretKey(identifier); + if (secretKey == null) + { + continue; + } + + secretKeys.put(identifier, new OpenPGPSecretKey(key, secretKey, implementation.pbeSecretKeyDecryptorBuilderProvider())); + } + } + + @Override + public boolean isSecretKey() + { + return true; + } + + /** + * Return the {@link OpenPGPCertificate} of this {@link OpenPGPKey}. + * + * @return certificate + */ + public OpenPGPCertificate toCertificate() + { + return new OpenPGPCertificate(getPGPPublicKeyRing(), implementation, policy); + } + + @Override + public List getComponents() + { + // We go through the list of components returned by OpenPGPCertificate and replace those components + // where we have the secret key available + + // contains only public components + List components = super.getComponents(); + for (int i = components.size() - 1; i >= 0; i--) + { + OpenPGPCertificateComponent component = (OpenPGPCertificateComponent)components.get(i); + if (component instanceof OpenPGPComponentKey) + { + OpenPGPSecretKey secretKey = getSecretKey((OpenPGPComponentKey)component); + if (secretKey != null) + { + // swap in secret component + components.remove(i); + components.add(i, secretKey); + } + } + } + return components; + } + + /** + * Return the {@link OpenPGPSecretKey} of this key's primary key. + * + * @return primary secret key + */ + public OpenPGPSecretKey getPrimarySecretKey() + { + return getSecretKey(getPrimaryKey()); + } + + /** + * Return a {@link Map} containing all {@link OpenPGPSecretKey} components (secret subkeys) of the key. + * + * @return secret key components + */ + public Map getSecretKeys() + { + return new LinkedHashMap(secretKeys); + } + + /** + * Return the {@link OpenPGPSecretKey} identified by the passed {@link KeyIdentifier}. + * + * @param identifier key identifier + * @return corresponding secret key or null + */ + public OpenPGPSecretKey getSecretKey(KeyIdentifier identifier) + { + return secretKeys.get(identifier); + } + + /** + * Return the {@link OpenPGPSecretKey} that corresponds to the passed {@link OpenPGPComponentKey}. + * + * @param key component key + * @return corresponding secret key or null + */ + public OpenPGPSecretKey getSecretKey(OpenPGPComponentKey key) + { + return getSecretKey(key.getKeyIdentifier()); + } + + /** + * Replace the given secret key component. + * + * @param secretKey secret key + */ + void replaceSecretKey(OpenPGPSecretKey secretKey) + { + keyRing = PGPSecretKeyRing.insertSecretKey((PGPSecretKeyRing)keyRing, secretKey.rawSecKey); + secretKeys.put(secretKey.getKeyIdentifier(), secretKey); + } + + @Override + public PGPSecretKeyRing getPGPKeyRing() + { + return getPGPSecretKeyRing(); + } + + /** + * Return the underlying {@link PGPSecretKeyRing}. + * + * @return secret key ring + */ + public PGPSecretKeyRing getPGPSecretKeyRing() + { + return (PGPSecretKeyRing)super.getPGPKeyRing(); + } + + @Override + public byte[] getEncoded(PacketFormat packetFormat) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut, packetFormat); + getPGPSecretKeyRing().encode(pOut); + pOut.close(); + return bOut.toByteArray(); + } + + /** + * Secret key component of a {@link org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPPrimaryKey} or + * {@link org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPSubkey}. + */ + public static class OpenPGPSecretKey + extends OpenPGPComponentKey + { + private final PGPSecretKey rawSecKey; + private final OpenPGPComponentKey pubKey; + private final PBESecretKeyDecryptorBuilderProvider decryptorBuilderProvider; + + /** + * Constructor. + * + * @param pubKey corresponding public key component + * @param secKey secret key + * @param decryptorBuilderProvider for unlocking private keys + */ + public OpenPGPSecretKey(OpenPGPComponentKey pubKey, + PGPSecretKey secKey, + PBESecretKeyDecryptorBuilderProvider decryptorBuilderProvider) + { + super(pubKey.getPGPPublicKey(), pubKey.getCertificate()); + this.decryptorBuilderProvider = decryptorBuilderProvider; + this.rawSecKey = secKey; + this.pubKey = pubKey; + } + + @Override + protected OpenPGPCertificateComponent getPublicComponent() + { + // return the public key component to properly map this secret key to its public key component when + // the public key component is used as key in a map. + return pubKey; + } + + @Override + public boolean isPrimaryKey() + { + return getPublicKey().isPrimaryKey(); + } + + @Override + public OpenPGPComponentSignature getLatestSelfSignature(Date evaluationTime) + { + return getPublicKey().getLatestSelfSignature(evaluationTime); + } + + /** + * Return the {@link OpenPGPKey} which this {@link OpenPGPSecretKey} belongs to. + * + * @return OpenPGPKey + */ + public OpenPGPKey getOpenPGPKey() + { + return (OpenPGPKey)getCertificate(); + } + + @Override + public String toDetailString() + { + return "Private" + pubKey.toDetailString(); + } + + /** + * Return the underlying {@link PGPSecretKey}. + * + * @return secret key + */ + public PGPSecretKey getPGPSecretKey() + { + return rawSecKey; + } + + /** + * Return the public {@link OpenPGPComponentKey} corresponding to this {@link OpenPGPSecretKey}. + * + * @return public component key + */ + public OpenPGPComponentKey getPublicKey() + { + return pubKey; + } + + /** + * If true, the secret key is not available in plain and likely needs to be decrypted by providing + * a key passphrase. + * + * @return true if the key is locked + */ + public boolean isLocked() + { + return getPGPSecretKey().getS2KUsage() != SecretKeyPacket.USAGE_NONE; + } + + /** + * Unlock an unprotected {@link OpenPGPSecretKey}. + * + * @return unlocked private key + * @throws PGPException if the key cannot be unlocked + */ + public OpenPGPPrivateKey unlock() + throws PGPException + { + return unlock((char[])null); + } + + /** + * Unlock a protected {@link OpenPGPSecretKey}. + * + * @param passphraseProvider provider for key passphrases + * @return unlocked private key + * @throws PGPException if the key cannot be unlocked + */ + public OpenPGPPrivateKey unlock(KeyPassphraseProvider passphraseProvider) + throws PGPException + { + if (!isLocked()) + { + return unlock((char[])null); + } + return unlock(passphraseProvider.getKeyPassword(this)); + } + + /** + * Access the {@link PGPKeyPair} by unlocking the potentially locked secret key using the provided + * passphrase. Note: If the key is not locked, it is sufficient to pass null as passphrase. + * + * @param passphrase passphrase or null + * @return keypair containing unlocked private key + * @throws PGPException if the key cannot be unlocked + */ + public OpenPGPPrivateKey unlock(char[] passphrase) + throws PGPException + { + sanitizeProtectionMode(); + PBESecretKeyDecryptor decryptor = null; + try + { + if (passphrase != null) + { + decryptor = decryptorBuilderProvider.provide().build(passphrase); + } + + PGPPrivateKey privateKey = getPGPSecretKey().extractPrivateKey(decryptor); + if (privateKey == null) + { + return null; + } + + PGPKeyPair unlockedKey = new PGPKeyPair(getPGPSecretKey().getPublicKey(), privateKey); + return new OpenPGPPrivateKey(this, unlockedKey); + } + catch (PGPException e) + { + throw new KeyPassphraseException(this, e); + } + } + + private void sanitizeProtectionMode() + throws PGPException + { + if (!isLocked()) + { + return; + } + + PGPSecretKey secretKey = getPGPSecretKey(); + S2K s2k = secretKey.getS2K(); + if (s2k == null) + { + throw new PGPKeyValidationException("Legacy CFB using MD5 is not allowed."); + } + + if (s2k.getType() == S2K.ARGON_2 && secretKey.getS2KUsage() != SecretKeyPacket.USAGE_AEAD) + { + throw new PGPKeyValidationException("Argon2 without AEAD is not allowed."); + } + + if (getVersion() == PublicKeyPacket.VERSION_6) + { + if (secretKey.getS2KUsage() == SecretKeyPacket.USAGE_CHECKSUM) + { + throw new PGPKeyValidationException("Version 6 keys MUST NOT use malleable CFB."); + } + if (s2k.getType() == S2K.SIMPLE) + { + throw new PGPKeyValidationException("Version 6 keys MUST NOT use SIMPLE S2K."); + } + } + } + + /** + * Return true if the provided passphrase is correct. + * Note: This method will always return false for stripped secret keys. + * + * @param passphrase passphrase + * @return true if the passphrase is correct + */ + public boolean isPassphraseCorrect(char[] passphrase) + { + if (passphrase != null && !isLocked()) + { + return false; + } + + try + { + OpenPGPPrivateKey privateKey = unlock(passphrase); + return privateKey != null && privateKey.unlockedKey != null; + } + catch (PGPException e) + { + return false; + } + } + } + + /** + * Unlocked {@link OpenPGPSecretKey}. + */ + public static class OpenPGPPrivateKey + { + private final OpenPGPSecretKey secretKey; + private final PGPKeyPair unlockedKey; + + public OpenPGPPrivateKey(OpenPGPSecretKey secretKey, PGPKeyPair unlockedKey) + { + this.secretKey = secretKey; + this.unlockedKey = unlockedKey; + } + + /** + * Return the public {@link OpenPGPComponentKey} of this {@link OpenPGPPrivateKey}. + * + * @return public component key + */ + public OpenPGPComponentKey getPublicKey() + { + return secretKey.getPublicKey(); + } + + /** + * Return the {@link OpenPGPSecretKey} in its potentially locked form. + * + * @return secret key + */ + public OpenPGPSecretKey getSecretKey() + { + return secretKey; + } + + /** + * Return the unlocked {@link PGPKeyPair} containing the decrypted {@link PGPPrivateKey}. + * + * @return unlocked private key + */ + public PGPKeyPair getKeyPair() + { + return unlockedKey; + } + + /** + * Return the used {@link OpenPGPImplementation}. + * + * @return implementation + */ + private OpenPGPImplementation getImplementation() + { + return getSecretKey().getOpenPGPKey().implementation; + } + + /** + * Return a NEW instance of the {@link OpenPGPSecretKey} locked with the new passphrase. + * If the key was unprotected before, or if it was protected using AEAD, the new instance will be + * protected using AEAD as well. + * + * @param newPassphrase new passphrase + * @return new instance of the key, locked with the new passphrase + * @throws PGPException if the key cannot be locked + */ + public OpenPGPSecretKey changePassphrase(char[] newPassphrase) + throws PGPException + { + boolean useAead = !secretKey.isLocked() || + secretKey.getPGPSecretKey().getS2KUsage() == SecretKeyPacket.USAGE_AEAD; + + return changePassphrase(newPassphrase, getImplementation(), useAead); + } + + /** + * Return a NEW instance of the {@link OpenPGPSecretKey} locked with the new passphrase. + * + * @param newPassphrase new passphrase + * @param implementation OpenPGP implementation + * @param useAEAD whether to protect the key using AEAD + * @return new instance of the key, locked with the new passphrase + * @throws PGPException if the key cannot be locked + */ + public OpenPGPSecretKey changePassphrase(char[] newPassphrase, + OpenPGPImplementation implementation, + boolean useAEAD) + throws PGPException + { + return changePassphrase(newPassphrase, implementation.pbeSecretKeyEncryptorFactory(useAEAD)); + } + + /** + * Return a NEW instance of the {@link OpenPGPSecretKey} locked with the new passphrase. + * + * @param newPassphrase new passphrase + * @param keyEncryptorFactory factory for {@link PBESecretKeyEncryptor} instances + * @return new instance of the key, locked with the new passphrase + * @throws PGPException if the key cannot be locked + */ + public OpenPGPSecretKey changePassphrase(char[] newPassphrase, + PBESecretKeyEncryptorFactory keyEncryptorFactory) + throws PGPException + { + PBESecretKeyEncryptor keyEncryptor; + if (newPassphrase == null || newPassphrase.length == 0) + { + keyEncryptor = null; + } + else + { + keyEncryptor = keyEncryptorFactory.build( + newPassphrase, + getKeyPair().getPublicKey().getPublicKeyPacket()); + } + + return changePassphrase(keyEncryptor); + } + + /** + * Return a NEW instance of the {@link OpenPGPSecretKey} locked using the given {@link PBESecretKeyEncryptor}. + * + * @param keyEncryptor encryptor + * @return new instance of the key, locked with the key encryptor + * @throws PGPException if the key cannot be locked + */ + public OpenPGPSecretKey changePassphrase(PBESecretKeyEncryptor keyEncryptor) + throws PGPException + { + PGPSecretKey encrypted = new PGPSecretKey( + getKeyPair().getPrivateKey(), + getKeyPair().getPublicKey(), + getImplementation().pgpDigestCalculatorProvider().get(HashAlgorithmTags.SHA1), + getSecretKey().isPrimaryKey(), + keyEncryptor); + + OpenPGPSecretKey sk = new OpenPGPSecretKey( + getSecretKey().getPublicKey(), + encrypted, + getImplementation().pbeSecretKeyDecryptorBuilderProvider()); + sk.sanitizeProtectionMode(); + return sk; + } + + /** + * Return a NEW instance of the {@link OpenPGPSecretKey} with removed passphrase protection. + * + * @return unlocked new instance of the key + * @throws PGPException if the key cannot be unlocked + */ + public OpenPGPSecretKey removePassphrase() + throws PGPException + { + return changePassphrase((PBESecretKeyEncryptor)null); + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyEditor.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyEditor.java new file mode 100644 index 0000000000..5a7801bad1 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyEditor.java @@ -0,0 +1,478 @@ +package org.bouncycastle.openpgp.api; + +import java.util.Date; + +import org.bouncycastle.bcpg.HashAlgorithmTags; +import org.bouncycastle.bcpg.KeyIdentifier; +import org.bouncycastle.bcpg.PublicKeyUtils; +import org.bouncycastle.bcpg.sig.KeyFlags; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPKeyPair; +import org.bouncycastle.openpgp.PGPKeyValidationException; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPPublicKeyRing; +import org.bouncycastle.openpgp.PGPSecretKey; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureGenerator; +import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.bouncycastle.openpgp.api.exception.OpenPGPKeyException; +import org.bouncycastle.openpgp.operator.PGPKeyPairGenerator; + +public class OpenPGPKeyEditor + extends AbstractOpenPGPKeySignatureGenerator +{ + + private final OpenPGPImplementation implementation; + private final OpenPGPPolicy policy; + private OpenPGPKey key; + private final OpenPGPKey.OpenPGPPrivateKey primaryKey; + + public OpenPGPKeyEditor(OpenPGPKey key, KeyPassphraseProvider passphraseProvider) + throws PGPException + { + this(key, passphraseProvider, key.implementation); + } + + public OpenPGPKeyEditor(OpenPGPKey key, + KeyPassphraseProvider passphraseProvider, + OpenPGPImplementation implementation) + throws PGPException + { + this(key, passphraseProvider, implementation, implementation.policy()); + } + + public OpenPGPKeyEditor(OpenPGPKey key, + KeyPassphraseProvider passphraseProvider, + OpenPGPImplementation implementation, + OpenPGPPolicy policy) + throws PGPException + { + this.key = key; + this.primaryKey = key.getPrimarySecretKey().unlock(passphraseProvider); + this.implementation = implementation; + this.policy = policy; + } + + public OpenPGPKeyEditor addDirectKeySignature(SignatureParameters.Callback signatureCallback) + throws PGPException + { + SignatureParameters parameters = Utils.applySignatureParameters(signatureCallback, + SignatureParameters.directKeySignature(policy)); + + if (parameters != null) + { + PGPPublicKey publicPrimaryKey = key.getPrimaryKey().getPGPPublicKey(); + + PGPSignatureGenerator dkSigGen = Utils.getPgpSignatureGenerator(implementation, publicPrimaryKey, + primaryKey.getKeyPair().getPrivateKey(), parameters, parameters.getSignatureCreationTime(), null); + + PGPPublicKey pubKey = Utils.injectCertification(publicPrimaryKey, dkSigGen); + this.key = generateOpenPGPKey(pubKey); + } + return this; + } + + /** + * Add a user-id to the primary key. + * If the key already contains the given user-id, a new certification signature will be added to the user-id. + * + * @param userId user-id + * @return this + * @throws PGPException if the key cannot be modified + */ + public OpenPGPKeyEditor addUserId(String userId) + throws PGPException + { + return addUserId(userId, null); + } + + /** + * Add a user-id to the primary key, modifying the contents of the certification signature using the given + * {@link SignatureParameters.Callback}. + * If the key already contains the given user-id, a new certification signature will be added to the user-id. + * + * @param userId user-id + * @param signatureCallback callback to modify the certification signature contents + * @return this + * @throws PGPException if the key cannot be modified + */ + public OpenPGPKeyEditor addUserId(String userId, + SignatureParameters.Callback signatureCallback) + throws PGPException + { + // care needs to run with Java 5 + if (userId == null || userId.trim().length() == 0) + { + throw new IllegalArgumentException("User-ID cannot be null or empty."); + } + + SignatureParameters parameters = Utils.applySignatureParameters(signatureCallback, + SignatureParameters.certification(policy)); + + if (parameters != null) + { + PGPPublicKey publicPrimaryKey = key.getPrimaryKey().getPGPPublicKey(); + + PGPSignatureGenerator uidSigGen = Utils.getPgpSignatureGenerator(implementation, publicPrimaryKey, + primaryKey.getKeyPair().getPrivateKey(), parameters, parameters.getSignatureCreationTime(), null); + + this.key = generateOpenPGPKey(Utils.injectCertification(userId, publicPrimaryKey, uidSigGen)); + } + return this; + } + + /** + * Revoke the given {@link OpenPGPCertificate.OpenPGPIdentityComponent}. + * + * @param identity user-id to be revoked + * @return this + * @throws PGPException if the key cannot be modified + */ + public OpenPGPKeyEditor revokeIdentity(OpenPGPCertificate.OpenPGPIdentityComponent identity) + throws PGPException + { + return revokeIdentity(identity, null); + } + + /** + * Revoke the given {@link OpenPGPCertificate.OpenPGPUserId}, allowing modification of the revocation signature + * using the given {@link SignatureParameters.Callback}. + * + * @param identity user-id to revoke + * @param signatureCallback callback to modify the revocation signature contents + * @return this + * @throws PGPException if the key cannot be modified + */ + public OpenPGPKeyEditor revokeIdentity(OpenPGPCertificate.OpenPGPIdentityComponent identity, + SignatureParameters.Callback signatureCallback) + throws PGPException + { + if (!key.getComponents().contains(identity)) + { + throw new IllegalArgumentException("UserID or UserAttribute is not part of the certificate."); + } + + SignatureParameters parameters = Utils.applySignatureParameters(signatureCallback, + SignatureParameters.certificationRevocation(policy)); + + if (parameters != null) + { + PGPPublicKey publicPrimaryKey = key.getPrimaryKey().getPGPPublicKey(); + + PGPSignatureGenerator idSigGen = Utils.getPgpSignatureGenerator(implementation, publicPrimaryKey, + primaryKey.getKeyPair().getPrivateKey(), parameters, parameters.getSignatureCreationTime(), null); + + // Inject signature into the certificate + PGPPublicKey pubKey; + if (identity instanceof OpenPGPCertificate.OpenPGPUserId) + { + OpenPGPCertificate.OpenPGPUserId userId = (OpenPGPCertificate.OpenPGPUserId)identity; + pubKey = Utils.injectCertification(userId.getUserId(), publicPrimaryKey, idSigGen); + } + else + { + OpenPGPCertificate.OpenPGPUserAttribute userAttribute = (OpenPGPCertificate.OpenPGPUserAttribute)identity; + PGPSignature uattrSig = idSigGen.generateCertification(userAttribute.getUserAttribute(), publicPrimaryKey); + pubKey = PGPPublicKey.addCertification(publicPrimaryKey, userAttribute.getUserAttribute(), uattrSig); + } + this.key = generateOpenPGPKey(pubKey); + } + return this; + } + + public OpenPGPKeyEditor addEncryptionSubkey() + throws PGPException + { + return addEncryptionSubkey(KeyPairGeneratorCallback.Util.encryptionKey()); + } + + public OpenPGPKeyEditor addEncryptionSubkey(KeyPairGeneratorCallback keyGenCallback) + throws PGPException + { + return addEncryptionSubkey(keyGenCallback, key.getPrimaryKey().getVersion(), new Date()); + } + + public OpenPGPKeyEditor addEncryptionSubkey(KeyPairGeneratorCallback keyGenCallback, + int version, + Date creationTime) + throws PGPException + { + PGPKeyPairGenerator kpGen = implementation.pgpKeyPairGeneratorProvider() + .get(version, creationTime); + return addEncryptionSubkey(keyGenCallback.generateFrom(kpGen), null); + } + + public OpenPGPKeyEditor addEncryptionSubkey(PGPKeyPair encryptionSubkey, + SignatureParameters.Callback bindingSigCallback) + throws PGPException + { + if (!encryptionSubkey.getPublicKey().isEncryptionKey()) + { + throw new PGPKeyValidationException("Provided subkey is not encryption-capable."); + } + + updateKey(encryptionSubkey, bindingSigCallback, key.getPrimaryKey().getPGPPublicKey(), new Utils.HashedSubpacketsOperation() + { + @Override + public void operate(PGPSignatureSubpacketGenerator hashedSubpackets) + throws PGPException + { + hashedSubpackets.setKeyFlags(KeyFlags.ENCRYPT_STORAGE | KeyFlags.ENCRYPT_COMMS); + } + }); + + return this; + } + + public OpenPGPKeyEditor addSigningSubkey() + throws PGPException + { + return addSigningSubkey(KeyPairGeneratorCallback.Util.signingKey()); + } + + public OpenPGPKeyEditor addSigningSubkey(KeyPairGeneratorCallback keyGenCallback) + throws PGPException + { + return addSigningSubkey(keyGenCallback, key.getPrimaryKey().getVersion(), new Date()); + } + + public OpenPGPKeyEditor addSigningSubkey(KeyPairGeneratorCallback keyGenCallback, + int version, + Date creationTime) + throws PGPException + { + PGPKeyPairGenerator kpGen = implementation.pgpKeyPairGeneratorProvider() + .get(version, creationTime); + return addSigningSubkey(keyGenCallback.generateFrom(kpGen), null, null); + } + + public OpenPGPKeyEditor addSigningSubkey(PGPKeyPair signingSubkey, + SignatureParameters.Callback bindingSigCallback, + SignatureParameters.Callback backSigCallback) + throws PGPException + { + if (!PublicKeyUtils.isSigningAlgorithm(signingSubkey.getPublicKey().getAlgorithm())) + { + throw new PGPKeyValidationException("Provided subkey is not signing-capable."); + } + + SignatureParameters backSigParameters = Utils.applySignatureParameters(backSigCallback, + SignatureParameters.primaryKeyBinding(policy)); + + PGPPublicKey publicPrimaryKey = key.getPrimaryKey().getPGPPublicKey(); + + final PGPSignature backSig = Utils.getBackSignature(signingSubkey, backSigParameters, publicPrimaryKey, implementation, null); + + updateKey(signingSubkey, bindingSigCallback, publicPrimaryKey, new Utils.HashedSubpacketsOperation() + { + @Override + public void operate(PGPSignatureSubpacketGenerator hashedSubpackets) + throws PGPException + { + hashedSubpackets.setKeyFlags(KeyFlags.SIGN_DATA); + Utils.addEmbeddedSiganture(backSig, hashedSubpackets); + } + }); + + return this; + } + + /** + * Add a component key to the certificate. + * The bindingSigCallback can be used to modify the subkey binding signature. + * If it is null, no subkey binding signature will be generated. + * The backSigCallback can be used to modify the embedded primary key binding signature. + * If it is null, no primary key binding signature will be generated. + * You MUST only pass a non-null value here, if the subkey is capable of creating signatures. + * + * @param subkey component key + * @param bindingSigCallback callback to modify the subkey binding signature + * @param backSigCallback callback to modify the embedded primary key binding signature + * @return this + * @throws PGPException + */ + public OpenPGPKeyEditor addSubkey(PGPKeyPair subkey, + SignatureParameters.Callback bindingSigCallback, + SignatureParameters.Callback backSigCallback) + throws PGPException + { + if (PublicKeyUtils.isSigningAlgorithm(subkey.getPublicKey().getAlgorithm()) + && backSigCallback != null) + { + throw new PGPKeyValidationException("Provided subkey is not signing-capable, so we cannot create a back-signature."); + } + + PGPPublicKey publicSubKey = subkey.getPublicKey(); + + SignatureParameters backSigParameters = Utils.applySignatureParameters(backSigCallback, + SignatureParameters.primaryKeyBinding(policy)); + + PGPPublicKey publicPrimaryKey = key.getPrimaryKey().getPGPPublicKey(); + + final PGPSignature backSig = Utils.getBackSignature(subkey, backSigParameters, publicPrimaryKey, implementation, null); + + SignatureParameters parameters = Utils.applySignatureParameters(bindingSigCallback, + SignatureParameters.subkeyBinding(policy)); + + if (parameters != null) + { + PGPSignatureGenerator subKeySigGen = Utils.getPgpSignatureGenerator(implementation, publicPrimaryKey, + primaryKey.getKeyPair().getPrivateKey(), parameters, parameters.getSignatureCreationTime(), + new Utils.HashedSubpacketsOperation() + { + @Override + public void operate(PGPSignatureSubpacketGenerator hashedSubpackets) + throws PGPException + { + Utils.addEmbeddedSiganture(backSig, hashedSubpackets); + } + }); + + // Inject signature into the certificate + publicSubKey = Utils.injectCertification(publicSubKey, subKeySigGen, publicPrimaryKey); + } + + this.key = generateOpenPGPKey(subkey, publicSubKey); + + return this; + } + + public OpenPGPKeyEditor revokeComponentKey(OpenPGPCertificate.OpenPGPComponentKey componentKey) + throws PGPException + { + return revokeComponentKey(componentKey, null); + } + + public OpenPGPKeyEditor revokeComponentKey(OpenPGPCertificate.OpenPGPComponentKey componentKey, + SignatureParameters.Callback revocationSignatureCallback) + throws PGPException + { + boolean contained = key.getKey(componentKey.getKeyIdentifier()) != null; + if (!contained) + { + throw new IllegalArgumentException("Provided component key is not part of the OpenPGP key."); + } + + boolean isSubkeyRevocation = !componentKey.getKeyIdentifier().equals(key.getKeyIdentifier()); + SignatureParameters parameters; + if (isSubkeyRevocation) + { + // Generate Subkey Revocation Signature + parameters = SignatureParameters.subkeyRevocation(policy); + } + else + { + // Generate Key Revocation Signature + parameters = SignatureParameters.keyRevocation(policy); + } + + parameters = Utils.applySignatureParameters(revocationSignatureCallback, parameters); + + PGPPublicKey publicPrimaryKey = key.getPrimaryKey().getPGPPublicKey(); + PGPSignatureGenerator revGen = Utils.getPgpSignatureGenerator(implementation, publicPrimaryKey, + primaryKey.getKeyPair().getPrivateKey(), parameters, parameters.getSignatureCreationTime(), null); + + if (isSubkeyRevocation) + { + publicPrimaryKey = Utils.injectCertification(componentKey.getPGPPublicKey(), revGen, publicPrimaryKey); + } + else + { + publicPrimaryKey = Utils.injectCertification(publicPrimaryKey, revGen); + } + this.key = generateOpenPGPKey(publicPrimaryKey); + + return this; + } + + public OpenPGPKeyEditor revokeKey() + throws PGPException + { + return revokeKey(null); + } + + public OpenPGPKeyEditor revokeKey(SignatureParameters.Callback revocationSignatureCallback) + throws PGPException + { + return revokeComponentKey(key.getPrimaryKey(), revocationSignatureCallback); + } + + /** + * Change the passphrase of the given component key. + * + * @param componentKeyIdentifier identifier of the component key, whose passphrase shall be changed + * @param oldPassphrase old passphrase (or null) + * @param newPassphrase new passphrase (or null) + * @param useAEAD whether to use AEAD + * @return this + * @throws OpenPGPKeyException if the secret component of the component key is missing + * @throws PGPException if the key passphrase cannot be changed + */ + public OpenPGPKeyEditor changePassphrase(KeyIdentifier componentKeyIdentifier, + char[] oldPassphrase, + char[] newPassphrase, + boolean useAEAD) + throws OpenPGPKeyException, PGPException + { + OpenPGPKey.OpenPGPSecretKey secretKey = key.getSecretKey(componentKeyIdentifier); + if (secretKey == null) + { + throw new OpenPGPKeyException(key, "Secret component key " + componentKeyIdentifier + + " is missing from the key."); + } + + OpenPGPKey.OpenPGPPrivateKey privateKey = secretKey.unlock(oldPassphrase); + secretKey = privateKey.changePassphrase(newPassphrase, implementation, useAEAD); + + key.replaceSecretKey(secretKey); + return this; + } + + /** + * Return the modified {@link OpenPGPKey}. + * + * @return modified key + */ + public OpenPGPKey done() + { + return key; + } + + private OpenPGPKey generateOpenPGPKey(PGPPublicKey publicPrimaryKey) + { + PGPPublicKeyRing publicKeyRing = PGPPublicKeyRing.insertPublicKey(key.getPGPPublicKeyRing(), publicPrimaryKey); + PGPSecretKeyRing secretKeyRing = PGPSecretKeyRing.replacePublicKeys(key.getPGPKeyRing(), publicKeyRing); + return new OpenPGPKey(secretKeyRing, implementation, policy); + } + + private OpenPGPKey generateOpenPGPKey(PGPKeyPair subkey, PGPPublicKey publicSubKey) + throws PGPException + { + PGPSecretKey secretSubkey = new PGPSecretKey( + subkey.getPrivateKey(), + publicSubKey, + implementation.pgpDigestCalculatorProvider().get(HashAlgorithmTags.SHA1), + false, + null); + PGPSecretKeyRing secretKeyRing = PGPSecretKeyRing.insertSecretKey(key.getPGPKeyRing(), secretSubkey); + return new OpenPGPKey(secretKeyRing, implementation, policy); + } + + private void updateKey(PGPKeyPair subkey, SignatureParameters.Callback bindingSigCallback, PGPPublicKey publicPrimaryKey, Utils.HashedSubpacketsOperation operation) + throws PGPException + { + SignatureParameters parameters = Utils.applySignatureParameters(bindingSigCallback, + SignatureParameters.subkeyBinding(policy)); + + if (parameters != null) + { + PGPSignatureGenerator subKeySigGen = Utils.getPgpSignatureGenerator(implementation, publicPrimaryKey, + primaryKey.getKeyPair().getPrivateKey(), parameters, parameters.getSignatureCreationTime(), + operation); + + PGPPublicKey publicSubKey = Utils.injectCertification(subkey.getPublicKey(), subKeySigGen, publicPrimaryKey); + this.key = generateOpenPGPKey(subkey, publicSubKey); + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyGenerator.java new file mode 100644 index 0000000000..612320cd4d --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyGenerator.java @@ -0,0 +1,733 @@ +package org.bouncycastle.openpgp.api; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Iterator; +import java.util.List; + +import org.bouncycastle.bcpg.HashAlgorithmTags; +import org.bouncycastle.bcpg.PublicKeyPacket; +import org.bouncycastle.bcpg.PublicKeyUtils; +import org.bouncycastle.bcpg.PublicSubkeyPacket; +import org.bouncycastle.bcpg.S2K; +import org.bouncycastle.bcpg.SignatureSubpacketTags; +import org.bouncycastle.bcpg.sig.KeyFlags; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPKeyPair; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPSecretKey; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureGenerator; +import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; +import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; +import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptorFactory; +import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; +import org.bouncycastle.openpgp.operator.PGPKeyPairGenerator; +import org.bouncycastle.openpgp.operator.PGPKeyPairGeneratorProvider; +import org.bouncycastle.util.Arrays; + +/** + * High-level generator class for OpenPGP v6 keys. + */ +public class OpenPGPKeyGenerator + extends AbstractOpenPGPKeySignatureGenerator +{ + // SECONDS + private static final long SECONDS_PER_MINUTE = 60; + private static final long SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE; + private static final long SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR; + private static final long SECONDS_PER_YEAR = 365 * SECONDS_PER_DAY; + + private final int keyVersion; + private final OpenPGPImplementation implementationProvider; + private final Configuration configuration; // contains BC or JCA/JCE implementations + + public OpenPGPKeyGenerator(OpenPGPImplementation implementation, + boolean aead, + Date creationTime) + throws PGPException + { + this(implementation, PublicKeyPacket.VERSION_6, aead, creationTime); + } + + public OpenPGPKeyGenerator(OpenPGPImplementation implementationProvider, + int version, + boolean aead, + Date creationTime) + throws PGPException + { + this( + implementationProvider, + version, + implementationProvider.pgpKeyPairGeneratorProvider(), + implementationProvider.pgpDigestCalculatorProvider(), + implementationProvider.pbeSecretKeyEncryptorFactory(aead), + implementationProvider.keyFingerPrintCalculator(), + creationTime + ); + } + + /** + * Generate a new OpenPGP key generator for v6 keys. + * + * @param kpGenProvider key pair generator provider + * @param digestCalculatorProvider digest calculator provider + * @param keyEncryptionBuilderProvider secret key encryption builder provider (AEAD) + * @param keyFingerPrintCalculator calculator for key fingerprints + * @param creationTime key creation time + */ + public OpenPGPKeyGenerator( + OpenPGPImplementation implementationProvider, + int keyVersion, + PGPKeyPairGeneratorProvider kpGenProvider, + PGPDigestCalculatorProvider digestCalculatorProvider, + PBESecretKeyEncryptorFactory keyEncryptionBuilderProvider, + KeyFingerPrintCalculator keyFingerPrintCalculator, + Date creationTime) + { + if (keyVersion != PublicKeyPacket.VERSION_4 && + keyVersion != PublicKeyPacket.LIBREPGP_5 && + keyVersion != PublicKeyPacket.VERSION_6) + { + throw new IllegalArgumentException("Generating keys of version " + keyVersion + " is not supported."); + } + + this.implementationProvider = implementationProvider; + this.keyVersion = keyVersion; + this.configuration = new Configuration(creationTime, kpGenProvider, digestCalculatorProvider, keyEncryptionBuilderProvider, keyFingerPrintCalculator); + } + + /** + * Generate an OpenPGP key consisting of a certify-only primary key, + * a dedicated signing-subkey and dedicated encryption-subkey. + * The key will optionally carry the provided user-id. + * See {@link PGPKeyPairGenerator#generatePrimaryKey()} for the primary key type, + * {@link PGPKeyPairGenerator#generateSigningSubkey()} for the signing-subkey type and + * {@link PGPKeyPairGenerator#generateEncryptionSubkey()} for the encryption-subkey key type. + * + * @param userId nullable user id + * @return OpenPGP key + * @throws PGPException if the key cannot be prepared + */ + public WithPrimaryKey classicKey(String userId) + throws PGPException + { + WithPrimaryKey builder = withPrimaryKey() + .addSigningSubkey() + .addEncryptionSubkey(); + + if (userId != null) + { + builder.addUserId(userId); + } + + return builder; + } + + /** + * Generate an OpenPGP key consisting of an Ed25519 certify-only primary key, + * a dedicated Ed25519 sign-only subkey and dedicated X25519 encryption-only subkey. + * The key will optionally carry the provided user-id. + * + * @param userId nullable user id + * @return OpenPGP key + * @throws PGPException if the key cannot be generated + */ + public WithPrimaryKey ed25519x25519Key(String userId) + throws PGPException + { + WithPrimaryKey builder = withPrimaryKey(new KeyPairGeneratorCallback() + { + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException + { + return generator.generateEd25519KeyPair(); + } + }) + .addSigningSubkey(new KeyPairGeneratorCallback() + { + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException + { + return generator.generateEd25519KeyPair(); + } + }) + .addEncryptionSubkey(new KeyPairGeneratorCallback() + { + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException + { + return generator.generateX25519KeyPair(); + } + }); + + if (userId != null) + { + builder.addUserId(userId); + } + + return builder; + } + + + /** + * Generate an OpenPGP key consisting of an Ed448 certify-only primary key, + * a dedicated Ed448 sign-only subkey and dedicated X448 encryption-only subkey. + * The key will optionally carry the provided user-id. + * + * @param userId nullable user id + * @return OpenPGP key + * @throws PGPException if the key cannot be generated + */ + public WithPrimaryKey ed448x448Key(String userId) + throws PGPException + { + WithPrimaryKey builder = withPrimaryKey(new KeyPairGeneratorCallback() + { + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException + { + return generator.generateEd448KeyPair(); + } + }) + .addSigningSubkey(new KeyPairGeneratorCallback() + { + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException + { + return generator.generateEd448KeyPair(); + } + }) + .addEncryptionSubkey(new KeyPairGeneratorCallback() + { + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException + { + return generator.generateX448KeyPair(); + } + }); + + if (userId != null) + { + builder.addUserId(userId); + } + + return builder; + } + + /** + * Generate a sign-only OpenPGP key. + * The key consists of a single, user-id-less primary key, which is capable of signing and certifying. + * See {@link PGPKeyPairGenerator#generatePrimaryKey()} for the key type. + * + * @return sign-only (+certify) OpenPGP key + * @throws PGPException if the key cannot be generated + */ + public WithPrimaryKey signOnlyKey() + throws PGPException + { + return withPrimaryKey( + KeyPairGeneratorCallback.Util.primaryKey(), + SignatureParameters.Callback.Util.modifyHashedSubpackets(new SignatureSubpacketsFunction() + { + @Override + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS); + subpackets.setKeyFlags(true, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA); + return subpackets; + } + })); + } + + /** + * Generate an OpenPGP key with a certification-capable primary key. + * See {@link PGPKeyPairGenerator#generatePrimaryKey()} for the primary key type + * + * @return builder + * @throws PGPException if the key cannot be generated + */ + public WithPrimaryKey withPrimaryKey() + throws PGPException + { + return withPrimaryKey(KeyPairGeneratorCallback.Util.primaryKey()); + } + + /** + * Generate an OpenPGP key with a certification-capable primary key. + * The primary key type can be decided using the {@link KeyPairGeneratorCallback}. + * + * @param keyGenCallback callback to decide the key type + * @return builder + * @throws PGPException if the key cannot be generated + */ + public WithPrimaryKey withPrimaryKey( + KeyPairGeneratorCallback keyGenCallback) + throws PGPException + { + return withPrimaryKey(keyGenCallback, null); + } + + /** + * Generate an OpenPGP key with a certification-capable primary key. + * The primary key type can be decided using the {@link KeyPairGeneratorCallback}. + * The {@link SignatureParameters.Callback} can be used to modify the preferences in the direct-key self signature. + * If the callback itself is null, the generator will create a default direct-key signature. + * If the result of {@link SignatureParameters.Callback#apply(SignatureParameters)} is null, no direct-key + * signature will be generated for the key. + * + * @param keyGenCallback callback to decide the key type + * @param preferenceSignatureCallback callback to modify the direct-key signature + * @return builder + * @throws PGPException if the key cannot be generated + */ + public WithPrimaryKey withPrimaryKey( + KeyPairGeneratorCallback keyGenCallback, + SignatureParameters.Callback preferenceSignatureCallback) + throws PGPException + { + PGPKeyPair primaryKeyPair = keyGenCallback.generateFrom(configuration.kpGenProvider.get( + keyVersion, configuration.keyCreationTime)); + + if (primaryKeyPair.getPublicKey().getPublicKeyPacket() instanceof PublicSubkeyPacket) + { + throw new IllegalArgumentException("Primary key MUST NOT consist of subkey packet."); + } + + if (!PublicKeyUtils.isSigningAlgorithm(primaryKeyPair.getPublicKey().getAlgorithm())) + { + throw new PGPException("Primary key MUST use signing-capable algorithm."); + } + + SignatureParameters parameters = Utils.applySignatureParameters(preferenceSignatureCallback, + SignatureParameters.directKeySignature(implementationProvider.policy())); + + if (parameters != null) + { + PGPSignatureGenerator preferenceSigGen = Utils.getPgpSignatureGenerator(implementationProvider, + primaryKeyPair.getPublicKey(), primaryKeyPair.getPrivateKey(), parameters, configuration.keyCreationTime, + new Utils.HashedSubpacketsOperation() + { + @Override + public void operate(PGPSignatureSubpacketGenerator hashedSubpackets) + throws PGPException + { + hashedSubpackets = directKeySignatureSubpackets.apply(hashedSubpackets); + hashedSubpackets.setKeyFlags(true, KeyFlags.CERTIFY_OTHER); + hashedSubpackets.setKeyExpirationTime(false, 5 * SECONDS_PER_YEAR); + } + }); + + primaryKeyPair = new PGPKeyPair( + Utils.injectCertification(primaryKeyPair.getPublicKey(), preferenceSigGen), + primaryKeyPair.getPrivateKey()); + } + + return new WithPrimaryKey(implementationProvider, configuration, primaryKeyPair); + } + + /** + * Intermediate builder class. + * Constructs an OpenPGP key from a specified primary key. + */ + public class WithPrimaryKey + { + private final OpenPGPImplementation implementation; + private final Configuration configuration; + private PGPKeyPair primaryKey; + private final List subkeys = new ArrayList(); + + /** + * Builder. + * + * @param implementation cryptographic implementation + * @param primaryKey specified primary key + */ + private WithPrimaryKey(OpenPGPImplementation implementation, Configuration configuration, PGPKeyPair primaryKey) + { + this.implementation = implementation; + this.configuration = configuration; + this.primaryKey = primaryKey; + } + + /** + * Attach a User-ID with a positive certification to the key. + * + * @param userId user-id + * @return builder + * @throws PGPException if the user-id cannot be added + */ + public WithPrimaryKey addUserId(String userId) + throws PGPException + { + return addUserId(userId, null); + } + + /** + * Attach a User-ID with a positive certification to the key. + * The subpackets of the user-id certification can be modified using the userIdSubpackets callback. + * + * @param userId user-id + * @param signatureParameters signature parameters + * @return builder + * @throws PGPException if the user-id cannot be added + */ + public WithPrimaryKey addUserId( + String userId, + SignatureParameters.Callback signatureParameters) + throws PGPException + { + // care - needs to run with Java 5. + if (userId == null || userId.trim().length() == 0) + { + throw new IllegalArgumentException("User-ID cannot be null or empty."); + } + + SignatureParameters parameters = Utils.applySignatureParameters(signatureParameters, + SignatureParameters.certification(implementation.policy())); + + if (parameters != null) + { + PGPSignatureGenerator uidSigGen = Utils.getPgpSignatureGenerator(implementation, primaryKey.getPublicKey(), + primaryKey.getPrivateKey(), parameters, configuration.keyCreationTime, null); + primaryKey = new PGPKeyPair(Utils.injectCertification(userId, primaryKey.getPublicKey(), uidSigGen), primaryKey.getPrivateKey()); + } + + return this; + } + + /** + * Add an encryption-capable subkey to the OpenPGP key. + * See {@link PGPKeyPairGenerator#generateEncryptionSubkey()} for the key type. + * + * @return builder + * @throws PGPException if the key cannot be generated + */ + public WithPrimaryKey addEncryptionSubkey() + throws PGPException + { + return addEncryptionSubkey(KeyPairGeneratorCallback.Util.encryptionKey()); + } + + /** + * Add an encryption-capable subkey to the OpenPGP key. + * The type of the subkey can be decided by implementing the {@link KeyPairGeneratorCallback}. + * + * @param keyGenCallback callback to decide the encryption subkey type + * @return builder + * @throws PGPException if the key cannot be generated + */ + public WithPrimaryKey addEncryptionSubkey(KeyPairGeneratorCallback keyGenCallback) + throws PGPException + { + return addEncryptionSubkey(keyGenCallback, null); + } + + /** + * Add an encryption-capable subkey to the OpenPGP key. + * The type of the subkey can be decided by implementing the {@link KeyPairGeneratorCallback}. + * The binding signature can be modified by implementing the {@link SignatureSubpacketsFunction}. + * + * @param generatorCallback callback to specify the encryption key type. + * @param bindingSubpacketsCallback nullable callback to modify the binding signature subpackets + * @return builder + * @throws PGPException if the key cannot be generated + */ + public WithPrimaryKey addEncryptionSubkey( + KeyPairGeneratorCallback generatorCallback, + SignatureParameters.Callback bindingSubpacketsCallback) + throws PGPException + { + PGPKeyPairGenerator generator = configuration.kpGenProvider.get( + keyVersion, configuration.keyCreationTime); + PGPKeyPair subkey = generatorCallback.generateFrom(generator); + subkey = subkey.asSubkey(implementation.keyFingerPrintCalculator()); + + return addEncryptionSubkey(subkey, bindingSubpacketsCallback); + } + + /** + * Add an encryption-capable subkey to the OpenPGP key. + * IMPORTANT: The custom key encryptor will only be used, if in the final step the key is retrieved + * using {@link #build()}. + * If instead {@link #build(char[])} is used, the key-specific encryptor is overwritten with an encryptor + * built from the argument passed into {@link #build(char[])}. + * + * @param encryptionSubkey encryption subkey + * @param bindingSubpacketsCallback nullable callback to modify the subkey binding signature subpackets + * @return builder + * @throws PGPException if the key cannot be generated + */ + public WithPrimaryKey addEncryptionSubkey( + PGPKeyPair encryptionSubkey, + SignatureParameters.Callback bindingSubpacketsCallback) + throws PGPException + { + if (!(encryptionSubkey.getPublicKey().getPublicKeyPacket() instanceof PublicSubkeyPacket)) + { + throw new IllegalArgumentException("Encryption subkey MUST NOT consist of a primary key packet."); + } + + if (!encryptionSubkey.getPublicKey().isEncryptionKey()) + { + throw new PGPException("Encryption key MUST use encryption-capable algorithm."); + } + + encryptionSubkey = updateSubkey(encryptionSubkey, bindingSubpacketsCallback, new Utils.HashedSubpacketsOperation() + { + @Override + public void operate(PGPSignatureSubpacketGenerator hashedSubpackets) + throws PGPException + { + hashedSubpackets = encryptionSubkeySubpackets.apply(hashedSubpackets); + } + }); + + subkeys.add(encryptionSubkey); + return this; + } + + /** + * Add a signing-capable subkey to the OpenPGP key. + * The binding signature will contain a primary-key back-signature. + * See {@link PGPKeyPairGenerator#generateSigningSubkey()} for the key type. + * + * @return builder + * @throws PGPException if the key cannot be generated + */ + public WithPrimaryKey addSigningSubkey() + throws PGPException + { + return addSigningSubkey(KeyPairGeneratorCallback.Util.signingKey()); + } + + /** + * Add a signing-capable subkey to the OpenPGP key. + * The signing-key type can be specified by overriding the {@link KeyPairGeneratorCallback}. + * The binding signature will contain a primary-key back-signature. + * IMPORTANT: The custom subkey passphrase will only be used, if in the final step the key is retrieved + * using {@link #build()}. + * If instead {@link #build(char[])} is used, the key-specific passphrase is overwritten with the argument + * passed into {@link #build(char[])}. + * + * @param keyGenCallback callback to specify the signing-key type + * @return builder + * @throws PGPException if the key cannot be generated + */ + public WithPrimaryKey addSigningSubkey(KeyPairGeneratorCallback keyGenCallback) + throws PGPException + { + return addSigningSubkey(keyGenCallback, null, null); + } + + /** + * Add a signing-capable subkey to the OpenPGP key. + * The signing-key type can be specified by overriding the {@link KeyPairGeneratorCallback}. + * The binding signature will contain a primary-key back-signature. + * The contents of the binding signature(s) can be modified by overriding the respective + * {@link SignatureSubpacketsFunction} instances. + * IMPORTANT: The custom subkey passphrase will only be used, if in the final step the key is retrieved + * using {@link #build()}. + * If instead {@link #build(char[])} is used, the key-specific passphrase is overwritten with the argument + * passed into {@link #build(char[])}. + * + * @param keyGenCallback callback to specify the signing-key type + * @param bindingSignatureCallback callback to modify the contents of the signing subkey binding signature + * @param backSignatureCallback callback to modify the contents of the embedded primary key binding signature + * @return builder + * @throws PGPException if the key cannot be generated + */ + public WithPrimaryKey addSigningSubkey(KeyPairGeneratorCallback keyGenCallback, + SignatureParameters.Callback bindingSignatureCallback, + SignatureParameters.Callback backSignatureCallback) + throws PGPException + { + PGPKeyPair subkey = keyGenCallback.generateFrom(configuration.kpGenProvider.get( + keyVersion, configuration.keyCreationTime)); + subkey = subkey.asSubkey(configuration.keyFingerprintCalculator); + return addSigningSubkey(subkey, bindingSignatureCallback, backSignatureCallback); + } + + /** + * Add a signing-capable subkey to the OpenPGP key. + * The signing-key type can be specified by overriding the {@link KeyPairGeneratorCallback}. + * The binding signature will contain a primary-key back-signature. + * The contents of the binding signature(s) can be modified by overriding the respective + * {@link SignatureSubpacketsFunction} instances. + * IMPORTANT: The custom key encryptor will only be used, if in the final step the key is retrieved + * using {@link #build()}. + * If instead {@link #build(char[])} is used, the key-specific encryptor is overwritten with an encryptor + * built from the argument passed into {@link #build(char[])}. + * + * @param signingSubkey signing subkey + * @param bindingSignatureCallback callback to modify the contents of the signing subkey binding signature + * @param backSignatureCallback callback to modify the contents of the embedded primary key binding signature + * @return builder + * @throws PGPException if the key cannot be generated + */ + public WithPrimaryKey addSigningSubkey(PGPKeyPair signingSubkey, + SignatureParameters.Callback bindingSignatureCallback, + SignatureParameters.Callback backSignatureCallback) + throws PGPException + { + if (!(signingSubkey.getPublicKey().getPublicKeyPacket() instanceof PublicSubkeyPacket)) + { + throw new IllegalArgumentException("Signing subkey MUST NOT consist of primary key packet."); + } + + if (!PublicKeyUtils.isSigningAlgorithm(signingSubkey.getPublicKey().getAlgorithm())) + { + throw new PGPException("Signing key MUST use signing-capable algorithm."); + } + + SignatureParameters parameters = Utils.applySignatureParameters(backSignatureCallback, + SignatureParameters.primaryKeyBinding(implementation.policy())); + + // Generate PrimaryKeySignature (Back-Signature) + final PGPSignature backSig = Utils.getBackSignature(signingSubkey, parameters, primaryKey.getPublicKey(), + implementation, configuration.keyCreationTime); + + signingSubkey = updateSubkey(signingSubkey, bindingSignatureCallback, new Utils.HashedSubpacketsOperation() + { + @Override + public void operate(PGPSignatureSubpacketGenerator hashedSubpackets) + throws PGPException + { + hashedSubpackets = signingSubkeySubpackets.apply(hashedSubpackets); + Utils.addEmbeddedSiganture(backSig, hashedSubpackets); + } + }); + + subkeys.add(signingSubkey); + + return this; + } + + + /** + * Build the {@link PGPSecretKeyRing OpenPGP key} without protecting the secret keys. + * + * @return OpenPGP key + * @throws PGPException if the key cannot be generated + */ + public OpenPGPKey build() + throws PGPException + { + return build(null); + } + + /** + * Build the {@link PGPSecretKeyRing OpenPGP key} using a single passphrase used to protect all subkeys. + * The passphrase will override whichever key protectors were specified in previous builder steps. + * + * @param passphrase nullable passphrase + * @return OpenPGP key + * @throws PGPException if the key cannot be generated + */ + public OpenPGPKey build(char[] passphrase) + throws PGPException + { + PBESecretKeyEncryptor primaryKeyEncryptor = configuration.keyEncryptorBuilderProvider + .build(passphrase, primaryKey.getPublicKey().getPublicKeyPacket()); + PGPSecretKey primarySecretKey = new PGPSecretKey( + primaryKey.getPrivateKey(), + primaryKey.getPublicKey(), + configuration.digestCalculatorProvider.get(HashAlgorithmTags.SHA1), + true, + primaryKeyEncryptor); + sanitizeKeyEncryptor(primaryKeyEncryptor); + List keys = new ArrayList(); + keys.add(primarySecretKey); + + for (Iterator it = subkeys.iterator(); it.hasNext(); ) + { + PGPKeyPair key = (PGPKeyPair)it.next(); + PBESecretKeyEncryptor subkeyEncryptor = configuration.keyEncryptorBuilderProvider + .build(passphrase, key.getPublicKey().getPublicKeyPacket()); + PGPSecretKey subkey = new PGPSecretKey( + key.getPrivateKey(), + key.getPublicKey(), + configuration.digestCalculatorProvider.get(HashAlgorithmTags.SHA1), + false, + subkeyEncryptor); + sanitizeKeyEncryptor(subkeyEncryptor); + keys.add(subkey); + } + + if (passphrase != null) + { + Arrays.fill(passphrase, (char)0); + } + + PGPSecretKeyRing secretKeys = new PGPSecretKeyRing(keys); + return new OpenPGPKey(secretKeys, implementation); + } + + protected void sanitizeKeyEncryptor(PBESecretKeyEncryptor keyEncryptor) + { + if (keyEncryptor == null) + { + // Unprotected is okay + return; + } + + S2K s2k = keyEncryptor.getS2K(); + if (s2k.getType() == S2K.SIMPLE || s2k.getType() == S2K.SALTED) + { + throw new IllegalArgumentException("S2K specifiers SIMPLE and SALTED are not allowed for secret key encryption."); + } + else if (s2k.getType() == S2K.ARGON_2) + { + if (keyEncryptor.getAeadAlgorithm() == 0) + { + throw new IllegalArgumentException("Argon2 MUST be used with AEAD."); + } + } + } + + private PGPKeyPair updateSubkey(PGPKeyPair subkey, SignatureParameters.Callback bindingSubpacketsCallback, + Utils.HashedSubpacketsOperation operation) + throws PGPException + { + SignatureParameters parameters = Utils.applySignatureParameters(bindingSubpacketsCallback, + SignatureParameters.subkeyBinding(implementation.policy()).setSignatureCreationTime(configuration.keyCreationTime)); + + if (parameters != null) + { + PGPSignatureGenerator bindingSigGen = Utils.getPgpSignatureGenerator(implementation, primaryKey.getPublicKey(), + primaryKey.getPrivateKey(), parameters, parameters.getSignatureCreationTime(), operation); + + PGPPublicKey publicSubkey = Utils.injectCertification(subkey.getPublicKey(), bindingSigGen, primaryKey.getPublicKey()); + subkey = new PGPKeyPair(publicSubkey, subkey.getPrivateKey()); + } + return subkey; + } + } + + /** + * Bundle implementation-specific provider classes. + */ + private static class Configuration + { + final Date keyCreationTime; + final PGPKeyPairGeneratorProvider kpGenProvider; + final PGPDigestCalculatorProvider digestCalculatorProvider; + final PBESecretKeyEncryptorFactory keyEncryptorBuilderProvider; + final KeyFingerPrintCalculator keyFingerprintCalculator; + + public Configuration(Date keyCreationTime, + PGPKeyPairGeneratorProvider keyPairGeneratorProvider, + PGPDigestCalculatorProvider digestCalculatorProvider, + PBESecretKeyEncryptorFactory keyEncryptorBuilderProvider, + KeyFingerPrintCalculator keyFingerPrintCalculator) + { + this.keyCreationTime = new Date((keyCreationTime.getTime() / 1000) * 1000); + this.kpGenProvider = keyPairGeneratorProvider; + this.digestCalculatorProvider = digestCalculatorProvider; + this.keyEncryptorBuilderProvider = keyEncryptorBuilderProvider; + this.keyFingerprintCalculator = keyFingerPrintCalculator; + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyMaterialPool.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyMaterialPool.java new file mode 100644 index 0000000000..9dd543316a --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyMaterialPool.java @@ -0,0 +1,210 @@ +package org.bouncycastle.openpgp.api; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.bouncycastle.bcpg.KeyIdentifier; + +/** + * Implementation of the {@link OpenPGPKeyMaterialProvider} which caches items in a {@link HashMap}. + * It allows to provide key or certificates dynamically via a {@link #callback} that can be set using + * {@link #setMissingItemCallback(OpenPGPKeyMaterialProvider)}. + * Results from this callback are automatically cached for later access. This behavior can be adjusted via + * {@link #setCacheResultsFromCallback(boolean)}. + * + * @param {@link OpenPGPCertificate} or {@link OpenPGPKey} + */ +public abstract class OpenPGPKeyMaterialPool + implements OpenPGPKeyMaterialProvider +{ + private final Map pool = new HashMap(); + private OpenPGPKeyMaterialProvider callback = null; + private boolean cacheResultsFromCallback = true; + + /** + * Create an empty pool. + */ + public OpenPGPKeyMaterialPool() + { + + } + + /** + * Create a pool from the single provided item. + * @param item item + */ + public OpenPGPKeyMaterialPool(M item) + { + addItem(item); + } + + /** + * Create a pool and initialize its contents with the provided collection of items. + * @param items collection of keys or certificates + */ + public OpenPGPKeyMaterialPool(Collection items) + { + for (M item : items) + { + addItem(item); + } + } + + /** + * Set a callback that gets fired whenever an item is requested, which is not found in the pool. + * + * @param callback callback + * @return this + */ + public OpenPGPKeyMaterialPool setMissingItemCallback(OpenPGPKeyMaterialProvider callback) + { + if (callback == null) + { + throw new NullPointerException(); + } + this.callback = callback; + return this; + } + + /** + * Decide, whether the implementation should add {@link OpenPGPCertificate certificates} returned by + * {@link #callback} to the pool of cached certificates. + * + * @param cacheResults if true, cache certificates from callback + * @return this + */ + public OpenPGPKeyMaterialPool setCacheResultsFromCallback(boolean cacheResults) + { + this.cacheResultsFromCallback = cacheResults; + return this; + } + + @Override + public M provide(KeyIdentifier componentKeyIdentifier) + { + M result = pool.get(componentKeyIdentifier); + if (result == null && callback != null) + { + // dynamically request certificate or key from callback + result = callback.provide(componentKeyIdentifier); + if (cacheResultsFromCallback) + { + addItem(result); + } + } + return result; + } + + /** + * Add a certificate to the pool. + * Note: If multiple items share the same subkey material, adding an item might overwrite the reference to + * another item for that subkey. + * + * @param item OpenPGP key or certificate that shall be added into the pool + * @return this + */ + public OpenPGPKeyMaterialPool addItem(M item) + { + if (item != null) + { + for (Iterator it = item.getAllKeyIdentifiers().iterator(); it.hasNext();) + { + pool.put(it.next(), item); + } + } + return this; + } + + /** + * Return all items from the pool. + * @return all items + */ + public Collection getAllItems() + { + Stream distinct = pool.values().stream().distinct(); + return distinct.collect(Collectors.toList()); + } + + /** + * Implementation of {@link OpenPGPKeyMaterialPool} tailored to provide {@link OpenPGPKey OpenPGPKeys}. + */ + public static class OpenPGPKeyPool + extends OpenPGPKeyMaterialPool + implements OpenPGPKeyProvider + { + public OpenPGPKeyPool() + { + super(); + } + + public OpenPGPKeyPool(Collection items) + { + super(items); + } + + @Override + public OpenPGPKeyPool setMissingItemCallback(OpenPGPKeyMaterialProvider callback) + { + super.setMissingItemCallback(callback); + return this; + } + + @Override + public OpenPGPKeyPool setCacheResultsFromCallback(boolean cacheResults) + { + super.setCacheResultsFromCallback(cacheResults); + return this; + } + + @Override + public OpenPGPKeyPool addItem(OpenPGPKey item) + { + super.addItem(item); + return this; + } + } + + /** + * Implementation of {@link OpenPGPKeyMaterialPool} tailored to providing + * {@link OpenPGPCertificate OpenPGPCertificates}. + */ + public static class OpenPGPCertificatePool + extends OpenPGPKeyMaterialPool + implements OpenPGPCertificateProvider + { + public OpenPGPCertificatePool() + { + super(); + } + + public OpenPGPCertificatePool(Collection items) + { + super(items); + } + + @Override + public OpenPGPCertificatePool setMissingItemCallback(OpenPGPKeyMaterialProvider callback) + { + super.setMissingItemCallback(callback); + return this; + } + + @Override + public OpenPGPCertificatePool setCacheResultsFromCallback(boolean cacheResults) + { + super.setCacheResultsFromCallback(cacheResults); + return this; + } + + @Override + public OpenPGPCertificatePool addItem(OpenPGPCertificate item) + { + super.addItem(item); + return this; + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyMaterialProvider.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyMaterialProvider.java new file mode 100644 index 0000000000..61b0af8c73 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyMaterialProvider.java @@ -0,0 +1,40 @@ +package org.bouncycastle.openpgp.api; + +import org.bouncycastle.bcpg.KeyIdentifier; + +/** + * Interface for providing OpenPGP keys or certificates. + * + * @param either {@link OpenPGPCertificate} or {@link OpenPGPKey} + */ +public interface OpenPGPKeyMaterialProvider +{ + /** + * Provide the requested {@link OpenPGPCertificate} or {@link OpenPGPKey} containing the component key identified + * by the passed in {@link KeyIdentifier}. + * + * @param componentKeyIdentifier identifier of a component key (primary key or subkey) + * @return the OpenPGP certificate or key containing the identified component key + */ + M provide(KeyIdentifier componentKeyIdentifier); + + /** + * Interface for requesting {@link OpenPGPCertificate OpenPGPCertificates} by providing a {@link KeyIdentifier}. + * The {@link KeyIdentifier} can either be that of the certificates primary key, or of a subkey. + */ + interface OpenPGPCertificateProvider + extends OpenPGPKeyMaterialProvider + { + + } + + /** + * Interface for requesting {@link OpenPGPKey OpenPGPKeys} by providing a {@link KeyIdentifier}. + * The {@link KeyIdentifier} can either be that of the keys primary key, or of a subkey. + */ + interface OpenPGPKeyProvider + extends OpenPGPKeyMaterialProvider + { + + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyReader.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyReader.java new file mode 100644 index 0000000000..28545a192d --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPKeyReader.java @@ -0,0 +1,394 @@ +package org.bouncycastle.openpgp.api; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.bouncycastle.bcpg.BCPGInputStream; +import org.bouncycastle.openpgp.PGPMarker; +import org.bouncycastle.openpgp.PGPObjectFactory; +import org.bouncycastle.openpgp.PGPPublicKeyRing; +import org.bouncycastle.openpgp.PGPSecretKeyRing; +import org.bouncycastle.openpgp.PGPUtil; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.io.Streams; + +/** + * Reader for {@link OpenPGPKey OpenPGPKeys} or {@link OpenPGPCertificate OpenPGPCertificates}. + */ +public class OpenPGPKeyReader +{ + private final OpenPGPImplementation implementation; + private final OpenPGPPolicy policy; + + public OpenPGPKeyReader() + { + this(OpenPGPImplementation.getInstance()); + } + + public OpenPGPKeyReader(OpenPGPImplementation implementation) + { + this(implementation, implementation.policy()); + } + + public OpenPGPKeyReader(OpenPGPImplementation implementation, OpenPGPPolicy policy) + { + this.implementation = implementation; + this.policy = policy; + } + + /** + * Parse a single {@link OpenPGPCertificate} from an ASCII armored string. + * + * @param armored ASCII armored string + * @return parsed certificate + * @throws IOException if the parsed object is a secret key or if the cert cannot be parsed + */ + public OpenPGPCertificate parseCertificate(String armored) + throws IOException + { + OpenPGPCertificate certificate = parseKeyOrCertificate(armored); + if (certificate instanceof OpenPGPKey) + { + throw new IOException("Could not parse OpenPGPCertificate: Is OpenPGPKey."); + } + return certificate; + } + + /** + * Parse a single {@link OpenPGPCertificate} from an {@link InputStream}. + * + * @param inputStream ASCII armored or binary input stream + * @return parsed certificate + * @throws IOException if the parsed object is a secret key or if the cert cannot be parsed + */ + public OpenPGPCertificate parseCertificate(InputStream inputStream) + throws IOException + { + OpenPGPCertificate certificate = parseKeyOrCertificate(inputStream); + if (certificate instanceof OpenPGPKey) + { + throw new IOException("Could not parse OpenPGPCertificate: Is OpenPGPKey."); + } + return certificate; + } + + /** + * Parse a single {@link OpenPGPCertificate} from bytes. + * + * @param bytes ASCII armored or binary bytes + * @return parsed certificate + * @throws IOException if the parsed object is a secret key or if the cert cannot be parsed + */ + public OpenPGPCertificate parseCertificate(byte[] bytes) + throws IOException + { + OpenPGPCertificate certificate = parseKeyOrCertificate(bytes); + if (certificate instanceof OpenPGPKey) + { + throw new IOException("Could not parse OpenPGPCertificate: Is OpenPGPKey."); + } + return certificate; + } + + /** + * Parse a single {@link OpenPGPCertificate} or {@link OpenPGPKey} from an ASCII armored string. + * + * @param armored ASCII armored string + * @return parsed certificate or key + * @throws IOException if the key or certificate cannot be parsed + * + * @deprecated use {@link #parseKeyOrCertificate(String)} instead. + */ + @Deprecated + public OpenPGPCertificate parseCertificateOrKey(String armored) + throws IOException + { + return parseKeyOrCertificate(armored); + } + + /** + * Parse a single {@link OpenPGPCertificate} or {@link OpenPGPKey} from an {@link InputStream}. + * + * @param inputStream input stream containing the ASCII armored or binary key or certificate + * @return parsed certificate or key + * @throws IOException if the key or certificate cannot be parsed + * + * @deprecated use {@link #parseKeyOrCertificate(InputStream)} instead. + */ + @Deprecated + public OpenPGPCertificate parseCertificateOrKey(InputStream inputStream) + throws IOException + { + return parseKeyOrCertificate(inputStream); + } + + /** + * Parse a single {@link OpenPGPCertificate} or {@link OpenPGPKey} from bytes. + * + * @param bytes ASCII armored or binary key or certificate + * @return parsed certificate or key + * @throws IOException if the key or certificate cannot be parsed + * + * @deprecated use {@link #parseKeyOrCertificate(byte[])} instead. + */ + @Deprecated + public OpenPGPCertificate parseCertificateOrKey(byte[] bytes) + throws IOException + { + return parseKeyOrCertificate(bytes); + } + + /** + * Parse a single {@link OpenPGPCertificate} or {@link OpenPGPKey} from an ASCII armored string. + * + * @param armored ASCII armored string + * @return parsed certificate or key + * @throws IOException if the key or certificate cannot be parsed + */ + public OpenPGPCertificate parseKeyOrCertificate(String armored) + throws IOException + { + return parseKeyOrCertificate(Strings.toUTF8ByteArray(armored)); + } + + /** + * Parse a single {@link OpenPGPCertificate} or {@link OpenPGPKey} from an {@link InputStream}. + * + * @param inputStream input stream containing the ASCII armored or binary key or certificate + * @return parsed certificate or key + * @throws IOException if the key or certificate cannot be parsed + */ + public OpenPGPCertificate parseKeyOrCertificate(InputStream inputStream) + throws IOException + { + return parseKeyOrCertificate(Streams.readAll(inputStream)); + } + + /** + * Parse a single {@link OpenPGPCertificate} or {@link OpenPGPKey} from bytes. + * + * @param bytes ASCII armored or binary key or certificate + * @return parsed certificate or key + * @throws IOException if the key or certificate cannot be parsed + */ + public OpenPGPCertificate parseKeyOrCertificate(byte[] bytes) + throws IOException + { + ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); + InputStream decoderStream = PGPUtil.getDecoderStream(bIn); + BCPGInputStream pIn = BCPGInputStream.wrap(decoderStream); + PGPObjectFactory objectFactory = implementation.pgpObjectFactory(pIn); + Object object = objectFactory.nextObject(); + + while (object instanceof PGPMarker) + { + object = objectFactory.nextObject(); + } + if (object instanceof PGPSecretKeyRing) + { + return new OpenPGPKey((PGPSecretKeyRing) object, implementation, policy); + } + else if (object instanceof PGPPublicKeyRing) + { + return new OpenPGPCertificate((PGPPublicKeyRing) object, implementation, policy); + } + else + { + throw new IOException("Neither a certificate, nor secret key."); + } + } + + /** + * Parse an {@link OpenPGPKey} from an ASCII armored string. + * + * @param armored ASCII armored string + * @return parsed key + * @throws IOException if the key cannot be parsed. + */ + public OpenPGPKey parseKey(String armored) + throws IOException + { + return parseKey(Strings.toUTF8ByteArray(armored)); + } + + /** + * Parse an {@link OpenPGPKey} from an {@link InputStream} + * + * @param inputStream containing the ASCII armored or binary key + * @return parsed key + * @throws IOException if the key cannot be parsed. + */ + public OpenPGPKey parseKey(InputStream inputStream) + throws IOException + { + return parseKey(Streams.readAll(inputStream)); + } + + /** + * Parse an {@link OpenPGPKey} from bytes. + * + * @param bytes ASCII armored or binary key + * @return parsed key + * @throws IOException if the key cannot be parsed. + */ + public OpenPGPKey parseKey(byte[] bytes) + throws IOException + { + ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); + InputStream decoderStream = PGPUtil.getDecoderStream(bIn); + BCPGInputStream pIn = BCPGInputStream.wrap(decoderStream); + PGPObjectFactory objectFactory = implementation.pgpObjectFactory(pIn); + + Object object = objectFactory.nextObject(); + while (object instanceof PGPMarker) + { + object = objectFactory.nextObject(); + } + if (!(object instanceof PGPSecretKeyRing)) + { + throw new IOException("Not a secret key."); + } + + PGPSecretKeyRing keyRing = (PGPSecretKeyRing) object; + return new OpenPGPKey(keyRing, implementation, policy); + } + + public List parseKeysOrCertificates(String armored) + throws IOException + { + return parseKeysOrCertificates(Strings.toUTF8ByteArray(armored)); + } + + public List parseKeysOrCertificates(InputStream inputStream) + throws IOException + { + return parseKeysOrCertificates(Streams.readAll(inputStream)); + } + + public List parseKeysOrCertificates(byte[] bytes) + throws IOException + { + List certsOrKeys = new ArrayList(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); + InputStream decoderStream = PGPUtil.getDecoderStream(bIn); + // Call getDecoderStream() twice, to make sure the stream is a BufferedInputStreamExt. + // This is necessary, so that for streams containing multiple concatenated armored blocks of keys, + // we parse all of them and do not quit after reading the first one. + decoderStream = PGPUtil.getDecoderStream(decoderStream); + PGPObjectFactory objectFactory = implementation.pgpObjectFactory(decoderStream); + Object object; + + while ((object = objectFactory.nextObject()) != null) + { + if (object instanceof PGPMarker) + { + continue; + } + if (object instanceof PGPSecretKeyRing) + { + certsOrKeys.add(new OpenPGPKey((PGPSecretKeyRing) object, implementation, policy)); + } + else if (object instanceof PGPPublicKeyRing) + { + certsOrKeys.add(new OpenPGPCertificate((PGPPublicKeyRing) object, implementation, policy)); + } + else + { + throw new IOException("Neither a certificate, nor secret key."); + } + } + return certsOrKeys; + } + + public List parseCertificates(String armored) + throws IOException + { + return parseCertificates(Strings.toUTF8ByteArray(armored)); + } + + public List parseCertificates(InputStream inputStream) + throws IOException + { + return parseCertificates(Streams.readAll(inputStream)); + } + + public List parseCertificates(byte[] bytes) + throws IOException + { + List certs = new ArrayList(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); + InputStream decoderStream = PGPUtil.getDecoderStream(bIn); + // Call getDecoderStream() twice, to make sure the stream is a BufferedInputStreamExt. + // This is necessary, so that for streams containing multiple concatenated armored blocks of certs, + // we parse all of them and do not quit after reading the first one. + decoderStream = PGPUtil.getDecoderStream(decoderStream); + PGPObjectFactory objectFactory = implementation.pgpObjectFactory(decoderStream); + Object object; + + while ((object = objectFactory.nextObject()) != null) + { + if (object instanceof PGPMarker) + { + continue; + } + else if (object instanceof PGPPublicKeyRing) + { + certs.add(new OpenPGPCertificate((PGPPublicKeyRing) object, implementation, policy)); + } + else + { + throw new IOException("Encountered unexpected packet: " + object.getClass().getName()); + } + } + return certs; + } + + public List parseKeys(String armored) + throws IOException + { + return parseKeys(Strings.toUTF8ByteArray(armored)); + } + + public List parseKeys(InputStream inputStream) + throws IOException + { + return parseKeys(Streams.readAll(inputStream)); + } + + public List parseKeys(byte[] bytes) + throws IOException + { + List keys = new ArrayList(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); + InputStream decoderStream = PGPUtil.getDecoderStream(bIn); + // Call getDecoderStream() twice, to make sure the stream is a BufferedInputStreamExt. + // This is necessary, so that for streams containing multiple concatenated armored blocks of keys, + // we parse all of them and do not quit after reading the first one. + decoderStream = PGPUtil.getDecoderStream(decoderStream); + PGPObjectFactory objectFactory = implementation.pgpObjectFactory(decoderStream); + Object object; + + while ((object = objectFactory.nextObject()) != null) + { + if (object instanceof PGPMarker) + { + continue; + } + else if (object instanceof PGPSecretKeyRing) + { + keys.add(new OpenPGPKey((PGPSecretKeyRing) object, implementation, policy)); + } + else + { + throw new IOException("Encountered unexpected packet: " + object.getClass().getName()); + } + } + return keys; + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPMessageGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPMessageGenerator.java new file mode 100644 index 0000000000..09f751bb05 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPMessageGenerator.java @@ -0,0 +1,669 @@ +package org.bouncycastle.openpgp.api; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.bouncycastle.bcpg.AEADAlgorithmTags; +import org.bouncycastle.bcpg.ArmoredOutputStream; +import org.bouncycastle.bcpg.CompressionAlgorithmTags; +import org.bouncycastle.bcpg.S2K; +import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites; +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.openpgp.PGPCompressedDataGenerator; +import org.bouncycastle.openpgp.PGPEncryptedDataGenerator; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPLiteralData; +import org.bouncycastle.openpgp.PGPLiteralDataGenerator; +import org.bouncycastle.openpgp.PGPOnePassSignature; +import org.bouncycastle.openpgp.PGPPadding; +import org.bouncycastle.openpgp.PGPSignatureGenerator; +import org.bouncycastle.openpgp.api.exception.InvalidEncryptionKeyException; +import org.bouncycastle.openpgp.operator.PBEKeyEncryptionMethodGenerator; +import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder; +import org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator; + +/** + * Generator for OpenPGP messages. + * This class can generate armored/unarmored, encrypted and/or signed OpenPGP message artifacts. + * By default, the generator will merely pack plaintext into an armored + * {@link org.bouncycastle.bcpg.LiteralDataPacket}. + * If however, the user provides one or more recipient certificates/keys + * ({@link #addEncryptionCertificate(OpenPGPCertificate)} / + * {@link #addEncryptionCertificate(OpenPGPCertificate.OpenPGPComponentKey)}) + * or message passphrases {@link #addEncryptionPassphrase(char[])}, the message will be encrypted. + * The encryption mechanism is automatically decided, based on the provided recipient certificates, aiming to maximize + * interoperability. + * If the user provides one or more signing keys by calling {@link #addSigningKey(OpenPGPKey)} or + * {@link #addSigningKey(OpenPGPKey.OpenPGPSecretKey, KeyPassphraseProvider, SignatureParameters.Callback)}, + * the message will be signed. + */ +public class OpenPGPMessageGenerator + extends AbstractOpenPGPDocumentSignatureGenerator +{ + public static final int BUFFER_SIZE = 1024; + + private boolean isArmored = true; + public boolean isAllowPadding = true; + private final List encryptionKeys = new ArrayList(); + private final List messagePassphrases = new ArrayList(); + + // Literal Data metadata + private Date fileModificationDate = null; + private String filename = null; + private char format = PGPLiteralData.BINARY; + private PGPEncryptedDataGenerator.SessionKeyExtractionCallback sessionKeyExtractionCallback; + + public OpenPGPMessageGenerator() + { + this(OpenPGPImplementation.getInstance()); + } + + public OpenPGPMessageGenerator(OpenPGPImplementation implementation) + { + this(implementation, implementation.policy()); + } + + public OpenPGPMessageGenerator(OpenPGPImplementation implementation, OpenPGPPolicy policy) + { + super(implementation, policy); + } + + /** + * Add a recipients certificate to the set of encryption keys. + * Subkeys will be selected using the default {@link SubkeySelector}, which can be replaced by calling + * {@link #setEncryptionKeySelector(SubkeySelector)}. + * The recipient will be able to decrypt the message using their corresponding secret key. + * + * @param recipientCertificate recipient certificate (public key) + * @return this + */ + public OpenPGPMessageGenerator addEncryptionCertificate(OpenPGPCertificate recipientCertificate) + throws InvalidEncryptionKeyException + { + return addEncryptionCertificate(recipientCertificate, encryptionKeySelector); + } + + /** + * Add a recipients certificate to the set of encryption keys. + * Subkeys will be selected using the provided {@link SubkeySelector}. + * The recipient will be able to decrypt the message using their corresponding secret key. + * + * @param recipientCertificate recipient certificate (public key) + * @param subkeySelector selector for encryption subkeys + * @return this + * @throws InvalidEncryptionKeyException if the certificate is not capable of encryption + */ + public OpenPGPMessageGenerator addEncryptionCertificate(OpenPGPCertificate recipientCertificate, + SubkeySelector subkeySelector) + throws InvalidEncryptionKeyException + { + List subkeys = + subkeySelector.select(recipientCertificate, policy); + if (subkeys.isEmpty()) + { + throw new InvalidEncryptionKeyException(recipientCertificate); + } + this.encryptionKeys.addAll(subkeys); + return this; + } + + /** + * Add a (sub-)key to the set of recipient encryption keys. + * The recipient will be able to decrypt the message using their corresponding secret key. + * + * @param encryptionKey encryption capable subkey + * @return this + * @throws InvalidEncryptionKeyException if the key is not capable of encryption + */ + public OpenPGPMessageGenerator addEncryptionCertificate(OpenPGPCertificate.OpenPGPComponentKey encryptionKey) + throws InvalidEncryptionKeyException + { + if (!encryptionKey.isEncryptionKey()) + { + throw new InvalidEncryptionKeyException(encryptionKey); + } + encryptionKeys.add(encryptionKey); + return this; + } + + /** + * Add a message passphrase. + * In addition to optional public key encryption, the message will be decryptable using the given passphrase. + * + * @param passphrase passphrase + * @return this + */ + public OpenPGPMessageGenerator addEncryptionPassphrase(char[] passphrase) + { + messagePassphrases.add(passphrase); + return this; + } + + /** + * Specify, whether the output OpenPGP message will be ASCII armored or not. + * + * @param armored boolean + * @return this + */ + public OpenPGPMessageGenerator setArmored(boolean armored) + { + this.isArmored = armored; + return this; + } + + public OpenPGPMessageGenerator setAllowPadding(boolean allowPadding) + { + this.isAllowPadding = allowPadding; + return this; + } + + /** + * Set metadata (filename, modification date, binary format) from a file. + * + * @param file file + * @return this + */ + public OpenPGPMessageGenerator setFileMetadata(File file) + { + this.filename = file.getName(); + this.fileModificationDate = new Date(file.lastModified()); + this.format = PGPLiteralData.BINARY; + return this; + } + + /** + * Set a callback which fires once the session key for message encryption is known. + * This callback can be used to extract the session key, e.g. to emit it to the user (in case of SOP). + * + * @param callback callback + * @return this + */ + public OpenPGPMessageGenerator setSessionKeyExtractionCallback( + PGPEncryptedDataGenerator.SessionKeyExtractionCallback callback) + { + this.sessionKeyExtractionCallback = callback; + return this; + } + + /** + * Open an {@link OpenPGPMessageOutputStream} over the given output stream. + * + * @param out output stream + * @return OpenPGP message output stream + * @throws PGPException if the output stream cannot be created + */ + public OpenPGPMessageOutputStream open(OutputStream out) + throws PGPException, IOException + { + OpenPGPMessageOutputStream.Builder streamBuilder = OpenPGPMessageOutputStream.builder(); + + applyOptionalAsciiArmor(streamBuilder); + applyOptionalEncryption(streamBuilder, sessionKeyExtractionCallback); + applySignatures(streamBuilder); + applyOptionalCompression(streamBuilder); + applyLiteralDataWrap(streamBuilder); + + return streamBuilder.build(out); + } + + /** + * Apply ASCII armor if necessary. + * The output will only be wrapped in ASCII armor, if {@link #setArmored(boolean)} is set + * to true (is true by default). + * The {@link ArmoredOutputStream} will be instantiated using the {@link ArmoredOutputStreamFactory} + * which can be replaced using {@link #setArmorStreamFactory(ArmoredOutputStreamFactory)}. + * + * @param builder OpenPGP message output stream builder + */ + private void applyOptionalAsciiArmor(OpenPGPMessageOutputStream.Builder builder) + { + if (isArmored) + { + builder.armor(armorStreamFactory); + } + } + + /** + * Optionally apply message encryption. + * If no recipient certificates and no encryption passphrases were supplied, no encryption + * will be applied. + * Otherwise, encryption mode and algorithms will be negotiated and message encryption will be applied. + * + * @param builder OpenPGP message output stream builder + * @param sessionKeyExtractionCallback callback to extract the session key (nullable) + */ + private void applyOptionalEncryption( + OpenPGPMessageOutputStream.Builder builder, + PGPEncryptedDataGenerator.SessionKeyExtractionCallback sessionKeyExtractionCallback) + { + MessageEncryptionMechanism encryption = encryptionNegotiator.negotiateEncryption(this); + if (!encryption.isEncrypted()) + { + return; // No encryption + } + + PGPDataEncryptorBuilder encBuilder = implementation.pgpDataEncryptorBuilder( + encryption.getSymmetricKeyAlgorithm()); + + // Specify container type for the plaintext + switch (encryption.getMode()) + { + case SEIPDv1: + encBuilder.setWithIntegrityPacket(true); + break; + + case SEIPDv2: + encBuilder.setWithAEAD(encryption.getAeadAlgorithm(), 6); + encBuilder.setUseV6AEAD(); + break; + + case LIBREPGP_OED: + encBuilder.setWithAEAD(encryption.getAeadAlgorithm(), 6); + encBuilder.setUseV5AEAD(); + break; + } + + final PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(encBuilder); + // For sake of interoperability and simplicity, we always use a dedicated session key for message encryption + // even if only a single PBE encryption method was added and S2K result could be used as session-key directly. + encGen.setForceSessionKey(true); + encGen.setSessionKeyExtractionCallback(sessionKeyExtractionCallback); + + // Setup asymmetric message encryption + for (OpenPGPCertificate.OpenPGPComponentKey encryptionSubkey : encryptionKeys) + { + PublicKeyKeyEncryptionMethodGenerator method = implementation.publicKeyKeyEncryptionMethodGenerator( + encryptionSubkey.getPGPPublicKey()); + encGen.addMethod(method); + } + + // Setup symmetric (password-based) message encryption + for (char[] passphrase : messagePassphrases) + { + PBEKeyEncryptionMethodGenerator skeskGen; + switch (encryption.getMode()) + { + case SEIPDv1: + case LIBREPGP_OED: + // "v4" and LibrePGP use symmetric-key encrypted session key packets version 4 (SKESKv4) + skeskGen = implementation.pbeKeyEncryptionMethodGenerator(passphrase); + break; + + case SEIPDv2: + // v6 uses symmetric-key encrypted session key packets version 6 (SKESKv6) using AEAD + skeskGen = implementation.pbeKeyEncryptionMethodGenerator( + passphrase, S2K.Argon2Params.memoryConstrainedParameters()); + break; + default: + continue; + } + + skeskGen.setSecureRandom(CryptoServicesRegistrar.getSecureRandom()); // Prevent NPE + encGen.addMethod(skeskGen); + } + + // Finally apply encryption + builder.encrypt(new OpenPGPMessageOutputStream.OutputStreamFactory() + { + @Override + public OutputStream get(OutputStream o) + throws PGPException, IOException + { + try + { + return encGen.open(o, new byte[BUFFER_SIZE]); + } + catch (IOException e) + { + throw new PGPException("Could not open encryptor OutputStream", e); + } + } + }); + + // Optionally, append a padding packet as the last packet inside the SEIPDv2 packet. + if (encryption.getMode() == EncryptedDataPacketType.SEIPDv2 && isAllowPadding) + { + builder.padding(new OpenPGPMessageOutputStream.OutputStreamFactory() + { + @Override + public OutputStream get(OutputStream o) + { + return new OpenPGPMessageOutputStream.PaddingPacketAppenderOutputStream(o, new OpenPGPMessageOutputStream.PaddingPacketFactory() + { + @Override + public PGPPadding providePaddingPacket() + { + return new PGPPadding(); + } + }); + } + }); + } + } + + /** + * Apply OpenPGP inline-signatures. + * + * @param builder OpenPGP message output stream builder + */ + private void applySignatures(OpenPGPMessageOutputStream.Builder builder) + { + builder.sign(new OpenPGPMessageOutputStream.OutputStreamFactory() + { + @Override + public OutputStream get(OutputStream o) + throws PGPException, IOException + { + addSignToGenerator(); + + // One-Pass-Signatures + Iterator sigGens = signatureGenerators.iterator(); + while (sigGens.hasNext()) + { + PGPSignatureGenerator gen = sigGens.next(); + PGPOnePassSignature ops = gen.generateOnePassVersion(sigGens.hasNext()); + ops.encode(o); + } + + return new OpenPGPMessageOutputStream.SignatureGeneratorOutputStream(o, signatureGenerators); + } + }); + } + + private void applyOptionalCompression(OpenPGPMessageOutputStream.Builder builder) + { + int compressionAlgorithm = compressionNegotiator.negotiateCompression(this, policy); + if (compressionAlgorithm == CompressionAlgorithmTags.UNCOMPRESSED) + { + return; // Uncompressed + } + + final PGPCompressedDataGenerator compGen = new PGPCompressedDataGenerator(compressionAlgorithm); + + builder.compress(new OpenPGPMessageOutputStream.OutputStreamFactory() + { + @Override + public OutputStream get(OutputStream o) + throws PGPException, IOException + { + try + { + return compGen.open(o, new byte[BUFFER_SIZE]); + } + catch (IOException e) + { + throw new PGPException("Could not apply compression", e); + } + } + }); + } + + /** + * Setup wrapping of the message plaintext in a literal data packet. + * + * @param builder OpenPGP message output stream + */ + private void applyLiteralDataWrap(OpenPGPMessageOutputStream.Builder builder) + { + final PGPLiteralDataGenerator litGen = new PGPLiteralDataGenerator(); + builder.literalData(new OpenPGPMessageOutputStream.OutputStreamFactory() + { + @Override + public OutputStream get(final OutputStream o) + throws PGPException, IOException + { + try + { + return litGen.open(o, + format, + filename != null ? filename : "", + fileModificationDate != null ? fileModificationDate : PGPLiteralData.NOW, + new byte[BUFFER_SIZE]); + } + catch (IOException e) + { + throw new PGPException("Could not apply literal data wrapping", e); + } + } + }); + } + + // Factory for creating ASCII armor + private ArmoredOutputStreamFactory armorStreamFactory = + new ArmoredOutputStreamFactory() + { + @Override + public ArmoredOutputStream get(OutputStream outputStream) + { + return ArmoredOutputStream.builder() + .clearHeaders() // Hide version + .enableCRC(false) // Disable CRC sum + .build(outputStream); + } + }; + + private SubkeySelector encryptionKeySelector = new SubkeySelector() + { + @Override + public List select(OpenPGPCertificate certificate, + OpenPGPPolicy policy) + { + List result = new ArrayList(); + for (Iterator it = certificate.getEncryptionKeys().iterator(); it.hasNext(); ) + { + OpenPGPCertificate.OpenPGPComponentKey key = it.next(); + if (policy.isAcceptablePublicKey(key.getPGPPublicKey())) + { + result.add(key); + } + } + return result; + } + }; + + // Encryption method negotiator for when only password-based encryption is requested + private OpenPGPEncryptionNegotiator passwordBasedEncryptionNegotiator = new OpenPGPEncryptionNegotiator() + { + @Override + public MessageEncryptionMechanism negotiateEncryption(OpenPGPMessageGenerator configuration) + { + return MessageEncryptionMechanism.aead(SymmetricKeyAlgorithmTags.AES_256, AEADAlgorithmTags.OCB); + } + }; + + // Encryption method negotiator for when public-key encryption is requested + private OpenPGPEncryptionNegotiator publicKeyBasedEncryptionNegotiator = new OpenPGPEncryptionNegotiator() + { + @Override + public MessageEncryptionMechanism negotiateEncryption(OpenPGPMessageGenerator configuration) + { +// List certificates = encryptionKeys.stream() +// .map(OpenPGPCertificate.OpenPGPCertificateComponent::getCertificate) +// .distinct() +// .collect(Collectors.toList()); + + List certificates = new ArrayList(); + Set uniqueCertificates = new HashSet(); // For distinctness + + for (Iterator it = encryptionKeys.iterator(); it.hasNext(); ) + { + OpenPGPCertificate cert = it.next().getCertificate(); + if (uniqueCertificates.add(cert)) + { // `Set.add()` returns true if the element was new + certificates.add(cert); + } + } + + // Decide, if SEIPDv2 (OpenPGP v6-style AEAD) is supported by all recipients. + if (OpenPGPEncryptionNegotiator.allRecipientsSupportSeipd2(certificates)) + { + PreferredAEADCiphersuites commonDenominator = + OpenPGPEncryptionNegotiator.negotiateAEADCiphersuite(certificates, policy); + return MessageEncryptionMechanism.aead(commonDenominator.getAlgorithms()[0]); + } + else if (OpenPGPEncryptionNegotiator.allRecipientsSupportLibrePGPOED(certificates)) + { + return MessageEncryptionMechanism.librePgp( + OpenPGPEncryptionNegotiator.bestOEDEncryptionModeByWeight(certificates, policy)); + } + else + { + return MessageEncryptionMechanism.integrityProtected( + OpenPGPEncryptionNegotiator.bestSymmetricKeyAlgorithmByWeight( + certificates, policy)); + } + + } + }; + + // Primary encryption method negotiator + private final OpenPGPEncryptionNegotiator encryptionNegotiator = new OpenPGPEncryptionNegotiator() + { + @Override + public MessageEncryptionMechanism negotiateEncryption(OpenPGPMessageGenerator configuration) + { + // No encryption methods provided -> Unencrypted message + if (encryptionKeys.isEmpty() && messagePassphrases.isEmpty()) + { + return MessageEncryptionMechanism.unencrypted(); + } + + // No public-key encryption requested -> password-based encryption + else if (encryptionKeys.isEmpty()) + { + // delegate negotiation to pbe negotiator + return passwordBasedEncryptionNegotiator.negotiateEncryption(configuration); + } + else + { + // delegate negotiation to pkbe negotiator + return publicKeyBasedEncryptionNegotiator.negotiateEncryption(configuration); + } + } + }; + + + // TODO: Implement properly, taking encryption into account (sign-only should not compress) + private CompressionNegotiator compressionNegotiator = new CompressionNegotiator() + { + @Override + public int negotiateCompression(OpenPGPMessageGenerator configuration, OpenPGPPolicy policy) + { + return CompressionAlgorithmTags.UNCOMPRESSED; + } + }; + + /** + * Replace the default {@link OpenPGPEncryptionNegotiator} that gets to decide, which + * {@link MessageEncryptionMechanism} mode to use if only password-based encryption is used. + * + * @param pbeNegotiator custom PBE negotiator. + * @return this + */ + public OpenPGPMessageGenerator setPasswordBasedEncryptionNegotiator(OpenPGPEncryptionNegotiator pbeNegotiator) + { + if (pbeNegotiator == null) + { + throw new NullPointerException(); + } + this.passwordBasedEncryptionNegotiator = pbeNegotiator; + return this; + } + + /** + * Replace the default {@link OpenPGPEncryptionNegotiator} that decides, which + * {@link MessageEncryptionMechanism} mode to use if public-key encryption is used. + * + * @param pkbeNegotiator custom encryption negotiator that gets to decide if PK-based encryption is used + * @return this + */ + public OpenPGPMessageGenerator setPublicKeyBasedEncryptionNegotiator(OpenPGPEncryptionNegotiator pkbeNegotiator) + { + if (pkbeNegotiator == null) + { + throw new NullPointerException(); + } + this.publicKeyBasedEncryptionNegotiator = pkbeNegotiator; + return this; + } + + /** + * Replace the default encryption key selector with a custom implementation. + * The encryption key selector is responsible for selecting one or more encryption subkeys from a + * recipient certificate. + * + * @param encryptionKeySelector selector for encryption (sub-)keys + * @return this + */ + public OpenPGPMessageGenerator setEncryptionKeySelector(SubkeySelector encryptionKeySelector) + { + if (encryptionKeySelector == null) + { + throw new NullPointerException(); + } + this.encryptionKeySelector = encryptionKeySelector; + return this; + } + + + /** + * Replace the default {@link CompressionNegotiator} with a custom implementation. + * The {@link CompressionNegotiator} is used to negotiate, whether and how to compress the literal data packet. + * + * @param compressionNegotiator negotiator + * @return this + */ + public OpenPGPMessageGenerator setCompressionNegotiator(CompressionNegotiator compressionNegotiator) + { + if (compressionNegotiator == null) + { + throw new NullPointerException(); + } + this.compressionNegotiator = compressionNegotiator; + return this; + } + + /** + * Replace the {@link ArmoredOutputStreamFactory} with a custom implementation. + * + * @param factory factory for {@link ArmoredOutputStream} instances + * @return this + */ + public OpenPGPMessageGenerator setArmorStreamFactory(ArmoredOutputStreamFactory factory) + { + if (factory == null) + { + throw new NullPointerException(); + } + this.armorStreamFactory = factory; + return this; + } + + + public interface ArmoredOutputStreamFactory + extends OpenPGPMessageOutputStream.OutputStreamFactory + { + ArmoredOutputStream get(OutputStream out); + } + + public interface CompressionNegotiator + { + /** + * Negotiate a compression algorithm. + * Returning {@link org.bouncycastle.bcpg.CompressionAlgorithmTags#UNCOMPRESSED} will result in no compression. + * + * @param messageGenerator message generator + * @return negotiated compression algorithm ID + */ + int negotiateCompression(OpenPGPMessageGenerator messageGenerator, OpenPGPPolicy policy); + } + +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPMessageInputStream.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPMessageInputStream.java new file mode 100644 index 0000000000..6601c07e35 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPMessageInputStream.java @@ -0,0 +1,1157 @@ +package org.bouncycastle.openpgp.api; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.bouncycastle.bcpg.AEADEncDataPacket; +import org.bouncycastle.bcpg.BCPGInputStream; +import org.bouncycastle.bcpg.KeyIdentifier; +import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket; +import org.bouncycastle.openpgp.PGPCompressedData; +import org.bouncycastle.openpgp.PGPEncryptedDataList; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPLiteralData; +import org.bouncycastle.openpgp.PGPMarker; +import org.bouncycastle.openpgp.PGPObjectFactory; +import org.bouncycastle.openpgp.PGPOnePassSignature; +import org.bouncycastle.openpgp.PGPOnePassSignatureList; +import org.bouncycastle.openpgp.PGPPadding; +import org.bouncycastle.openpgp.PGPSessionKey; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureException; +import org.bouncycastle.openpgp.PGPSignatureList; + +/** + * An {@link InputStream} that processes an OpenPGP message. + * Its contents are the plaintext from the messages LiteralData packet. + * You can get information about the message (signatures, encryption method, message metadata) + * by reading ALL data from the stream, closing it with {@link #close()} and then retrieving a {@link Result} object + * by calling {@link #getResult()}. + */ +public class OpenPGPMessageInputStream + extends InputStream +{ + public static int MAX_RECURSION = 16; + + private final PGPObjectFactory objectFactory; + private final OpenPGPImplementation implementation; + + private final OpenPGPMessageProcessor processor; + + private final Result.Builder resultBuilder; + private final Layer layer; // the packet layer processed by this input stream + + private InputStream in; + private final List packetHandlers = new ArrayList() + {{ + add(new SignatureListHandler()); + add(new OnePassSignatureHandler()); + add(new MarkerHandler()); + add(new LiteralDataHandler()); + add(new CompressedDataHandler()); + add(new EncryptedDataHandler()); + add(new DefaultPacketHandler()); // Must be last + }}; + + private final List closeHandlers = new ArrayList() + {{ + add(new SignatureListHandler()); + add(new PaddingHandler()); + add(new MarkerHandler()); + add(new DefaultPacketHandler()); + }}; + + OpenPGPMessageInputStream(PGPObjectFactory objectFactory, + OpenPGPMessageProcessor processor) + { + this(objectFactory, processor, Result.builder()); + } + + private OpenPGPMessageInputStream(PGPObjectFactory objectFactory, + OpenPGPMessageProcessor processor, + Result.Builder resultBuilder) + { + this.objectFactory = objectFactory; + this.processor = processor; + this.implementation = processor.getImplementation(); + this.resultBuilder = resultBuilder; + try + { + this.layer = resultBuilder.openLayer(); + } + catch (PGPException e) + { + // cannot happen + throw new AssertionError(e); + } + } + + void process() + throws IOException, PGPException + { + Object next; + while ((next = objectFactory.nextObject()) != null) + { + for (PacketHandler handler : packetHandlers) + { + if (handler.canHandle(next)) + { + handler.handle(next); + break; + } + } + + if (in != null) + { + return; // Found data stream, stop processing + } + } + } + + @Override + public void close() + throws IOException + { + in.close(); + Object next; + + while ((next = objectFactory.nextObject()) != null) + { + boolean handled = false; + for (Iterator it = closeHandlers.iterator(); it.hasNext();) + { + PacketHandler handler = (PacketHandler)it.next(); + if (handler.canHandle(next)) + { + handler.close(next); + handled = true; + break; + } + } + + if (!handled) + { + processor.onException(new PGPException("Unexpected trailing packet encountered: " + + next.getClass().getName())); + } + } + + resultBuilder.verifySignatures(processor); + resultBuilder.closeLayer(); + } + + @Override + public int read() + throws IOException + { + int i = in.read(); + if (i >= 0) + { + layer.onePassSignatures.update(i); + layer.prefixedSignatures.update(i); +// byte b = (byte)i; +// layer.onePassVerifier.update(b); +// layer.prefixedVerifier.update(b); + } + return i; + } + + @Override + public int read(byte[] b) + throws IOException + { + int i = in.read(b); + if (i >= 0) + { + layer.onePassSignatures.update(b, 0, i); + layer.prefixedSignatures.update(b, 0, i); +// layer.onePassVerifier.update(b, 0, i); +// layer.prefixedVerifier.update(b, 0, i); + } + return i; + } + + @Override + public int read(byte[] b, int off, int len) + throws IOException + { + int bytesRead = in.read(b, off, len); + if (bytesRead > 0) + { + layer.onePassSignatures.update(b, off, bytesRead); + layer.prefixedSignatures.update(b, off, bytesRead); +// layer.onePassVerifier.update(b, off, bytesRead); +// layer.prefixedVerifier.update(b, off, bytesRead); + } + return bytesRead; + } + + public Result getResult() + { + return resultBuilder.build(); + } + + public static class Result + { + private final List documentSignatures = new ArrayList(); + private OpenPGPCertificate.OpenPGPComponentKey decryptionKey; + private char[] decryptionPassphrase; + private PGPSessionKey sessionKey; + private MessageEncryptionMechanism encryptionMethod = MessageEncryptionMechanism.unencrypted(); + private int compressionAlgorithm = 0; + private String filename; + private char fileFormat; + private Date fileModificationTime; + + private Result(List layers) + { + for (Iterator it = layers.iterator(); it.hasNext(); ) + { + Layer l = it.next(); + if (l.signatures != null) + { + documentSignatures.addAll(l.signatures); + } + + if (l.nested instanceof EncryptedData) + { + EncryptedData encryptedData = (EncryptedData)l.nested; + encryptionMethod = encryptedData.encryption; + sessionKey = encryptedData.sessionKey; + decryptionKey = encryptedData.decryptionKey; + decryptionPassphrase = encryptedData.decryptionPassphrase; + } + else if (l.nested instanceof CompressedData) + { + CompressedData compressedData = (CompressedData)l.nested; + compressionAlgorithm = compressedData.compressionAlgorithm; + } + else if (l.nested instanceof LiteralData) + { + LiteralData literalData = (LiteralData)l.nested; + filename = literalData.filename; + fileFormat = literalData.encoding; + fileModificationTime = literalData.modificationTime; + } + } + } + + static Builder builder() + { + return new Builder(); + } + + public MessageEncryptionMechanism getEncryptionMethod() + { + return encryptionMethod; + } + + public OpenPGPCertificate.OpenPGPComponentKey getDecryptionKey() + { + return decryptionKey; + } + + public char[] getDecryptionPassphrase() + { + return decryptionPassphrase; + } + + public PGPSessionKey getSessionKey() + { + return sessionKey; + } + + public int getCompressionAlgorithm() + { + return compressionAlgorithm; + } + + public String getFilename() + { + return filename; + } + + public char getFileFormat() + { + return fileFormat; + } + + public Date getFileModificationTime() + { + return fileModificationTime; + } + + public List getSignatures() + { + return new ArrayList(documentSignatures); + } + + static class Builder + { + private final List layers = new ArrayList(); + + private Builder() + { + + } + + Layer last() + { + return layers.get(layers.size() - 1); + } + + /** + * Enter a nested OpenPGP packet layer. + * + * @return the new layer + * @throws PGPException if the parser exceeded the maximum nesting depth ({@link #MAX_RECURSION}). + */ + Layer openLayer() + throws PGPException + { + if (layers.size() >= MAX_RECURSION) + { + throw new PGPException("Exceeded maximum packet nesting depth."); + } + Layer layer = new Layer(); + layers.add(layer); + return layer; + } + + /** + * Close a nested OpenPGP packet layer. + */ + void closeLayer() + { + for (int i = layers.size() - 1; i >= 0; i--) + { + Layer l = layers.get(i); + if (l.isOpen()) + { + l.close(); + return; + } + } + } + + /** + * Set the nested packet type of the current layer to {@link CompressedData}. + * + * @param compressionAlgorithm compression algorithm ID + */ + void compressed(int compressionAlgorithm) + { + last().setNested(new CompressedData(compressionAlgorithm)); + } + + /** + * Add One-Pass-Signature packets on the current layer. + * + * @param pgpOnePassSignatures one pass signature packets + */ + void onePassSignatures(PGPOnePassSignatureList pgpOnePassSignatures) + { +// last().onePassVerifier.addSignatures(pgpOnePassSignatures.iterator()); + last().onePassSignatures.addOnePassSignatures(pgpOnePassSignatures); + } + + /** + * Build the {@link Result}. + * + * @return result + */ + Result build() + { + return new Result(layers); + } + + /** + * Add prefixed signatures on the current layer. + * + * @param prefixedSigs prefixed signatures + */ + void prefixedSignatures(PGPSignatureList prefixedSigs) + { + last().prefixedSignatures.addAll(prefixedSigs); + //last().prefixedVerifier.addSignatures(prefixedSigs.iterator()); + } + + /** + * Initialize any signatures on the current layer, prefixed and one-pass-signatures. + * + * @param processor message processor + */ + void initSignatures(OpenPGPMessageProcessor processor) + { + last().onePassSignatures.init(processor); + last().prefixedSignatures.init(processor); +// last().onePassVerifier.commonInit(processor); +// last().prefixedVerifier.commonInit(processor); + } + + /** + * Verify all signatures on the current layer, prefixed and one-pass-signatures. + * + * @param processor message processor + */ + void verifySignatures(OpenPGPMessageProcessor processor) + { + Layer last = last(); + if (last.signatures != null) + { + return; + } + + last.signatures = new ArrayList(); + last.signatures.addAll(last.onePassSignatures.verify(processor)); + last.signatures.addAll(last.prefixedSignatures.verify(processor)); +// last.signatures.addAll(last.onePassVerifier.verify(processor)); +// last.signatures.addAll(last.prefixedVerifier.verify(processor)); + } + + /** + * Set literal data metadata on the current layer. + * + * @param fileName filename + * @param format data format + * @param modificationTime modification time + */ + void literalData(String fileName, char format, Date modificationTime) + { + last().setNested(new LiteralData(fileName, format, modificationTime)); + } + + /** + * Set metadata from an encrypted data packet on the current layer. + * + * @param decrypted decryption result + */ + void encrypted(OpenPGPMessageProcessor.Decrypted decrypted) + { + last().setNested(new EncryptedData(decrypted)); + } + } + } + + static class Layer + { + private final OnePassSignatures onePassSignatures = new OnePassSignatures(); + private final PrefixedSignatures prefixedSignatures = new PrefixedSignatures(); +// private final OnePassSignatureVerifier onePassVerifier = new OnePassSignatureVerifier(); +// private final PrefixedSignatureVerifier prefixedVerifier = new PrefixedSignatureVerifier(); + private List signatures = null; + + private Nested nested; + private boolean open = true; + + void setNested(Nested nested) + { + this.nested = nested; + } + + void close() + { + this.open = false; + } + + boolean isOpen() + { + return open; + } + } + + static class Nested + { + } + + static class CompressedData + extends Nested + { + private final int compressionAlgorithm; + + public CompressedData(int algorithm) + { + this.compressionAlgorithm = algorithm; + } + } + + static class LiteralData + extends Nested + { + private final String filename; + private final char encoding; + private final Date modificationTime; + + LiteralData(String filename, char encoding, Date modificationTime) + { + this.filename = filename; + this.encoding = encoding; + this.modificationTime = modificationTime; + } + } + + static class EncryptedData + extends Nested + { + private final OpenPGPCertificate.OpenPGPComponentKey decryptionKey; + private final char[] decryptionPassphrase; + private final PGPSessionKey sessionKey; + private final MessageEncryptionMechanism encryption; + + EncryptedData(OpenPGPMessageProcessor.Decrypted decrypted) + { + this.decryptionKey = decrypted.decryptionKey; + this.decryptionPassphrase = decrypted.decryptionPassphrase; + this.sessionKey = decrypted.sessionKey; + if (decrypted.esk.getEncData() instanceof SymmetricEncIntegrityPacket) + { + SymmetricEncIntegrityPacket seipd = (SymmetricEncIntegrityPacket)decrypted.esk.getEncData(); + if (seipd.getVersion() == SymmetricEncIntegrityPacket.VERSION_2) + { + encryption = MessageEncryptionMechanism.aead( + seipd.getCipherAlgorithm(), seipd.getAeadAlgorithm()); + } + else + { + encryption = MessageEncryptionMechanism.integrityProtected(sessionKey.getAlgorithm()); + } + } + else if (decrypted.esk.getEncData() instanceof AEADEncDataPacket) + { + encryption = MessageEncryptionMechanism.librePgp(sessionKey.getAlgorithm()); + } + else + { + throw new RuntimeException("Unexpected encrypted data packet type: " + decrypted.esk.getClass().getName()); + } + } + } + + private static class PacketHandler + { + public boolean canHandle(Object packet) + { + return false; + } + + public void handle(Object packet) + throws IOException, PGPException + { + + } + + public void close(Object packet) + throws IOException + { + + } + } + + private class SignatureListHandler + extends PacketHandler + { + public boolean canHandle(Object packet) + { + return packet instanceof PGPSignatureList; + } + + public void handle(Object packet) + { + PGPSignatureList prefixedSigs = (PGPSignatureList)packet; + resultBuilder.prefixedSignatures(prefixedSigs); + } + + public void close(Object packet) + { + PGPSignatureList sigList = (PGPSignatureList)packet; + resultBuilder.last().onePassSignatures.addSignatures(sigList); + //resultBuilder.last().onePassVerifier.addPGPSinatures(sigList.iterator()); + } + } + + private class LiteralDataHandler + extends PacketHandler + { + @Override + public boolean canHandle(Object packet) + { + return packet instanceof PGPLiteralData; + } + + @Override + public void handle(Object packet) + throws IOException, PGPException + { + PGPLiteralData literalData = (PGPLiteralData)packet; + resultBuilder.literalData( + literalData.getFileName(), + (char)literalData.getFormat(), + literalData.getModificationTime() + ); + in = literalData.getDataStream(); + resultBuilder.initSignatures(processor); + } + } + + private class OnePassSignatureHandler + extends PacketHandler + { + @Override + public boolean canHandle(Object packet) + { + return packet instanceof PGPOnePassSignatureList; + } + + @Override + public void handle(Object packet) + throws IOException, PGPException + { + PGPOnePassSignatureList pgpOnePassSignatures = (PGPOnePassSignatureList)packet; + resultBuilder.onePassSignatures(pgpOnePassSignatures); + } + } + + private static class MarkerHandler + extends PacketHandler + { + @Override + public boolean canHandle(Object packet) + { + return packet instanceof PGPMarker; + } + } + + private class CompressedDataHandler + extends PacketHandler + { + @Override + public boolean canHandle(Object packet) + { + return packet instanceof PGPCompressedData; + } + + @Override + public void handle(Object packet) + throws IOException, PGPException + { + PGPCompressedData compressedData = (PGPCompressedData)packet; + resultBuilder.compressed(compressedData.getAlgorithm()); + + InputStream decompressed = compressedData.getDataStream(); + processNestedStream(decompressed); + } + + private void processNestedStream(InputStream input) + throws IOException, PGPException + { + InputStream decodeIn = BCPGInputStream.wrap(input); + PGPObjectFactory decFac = implementation.pgpObjectFactory(decodeIn); + OpenPGPMessageInputStream nestedIn = + new OpenPGPMessageInputStream(decFac, processor, resultBuilder); + in = nestedIn; + nestedIn.process(); + } + } + + private class EncryptedDataHandler + extends PacketHandler + { + @Override + public boolean canHandle(Object packet) + { + return packet instanceof PGPEncryptedDataList; + } + + @Override + public void handle(Object packet) + throws IOException, PGPException + { + PGPEncryptedDataList encryptedDataList = (PGPEncryptedDataList)packet; + OpenPGPMessageProcessor.Decrypted decrypted = processor.decrypt(encryptedDataList); + + resultBuilder.encrypted(decrypted); + processNestedStream(decrypted.inputStream); + } + + private void processNestedStream(InputStream input) + throws IOException, PGPException + { + InputStream decodeIn = BCPGInputStream.wrap(input); + PGPObjectFactory decFac = implementation.pgpObjectFactory(decodeIn); + OpenPGPMessageInputStream nestedIn = + new OpenPGPMessageInputStream(decFac, processor, resultBuilder); + in = nestedIn; + nestedIn.process(); + } + } + + private static class PaddingHandler + extends PacketHandler + { + public boolean canHandle(Object packet) + { + return packet instanceof PGPPadding; + } + } + + private class DefaultPacketHandler + extends PacketHandler + { + @Override + public boolean canHandle(Object packet) + { + return true; // Catch-all handler + } + + @Override + public void handle(Object packet) + throws PGPException + { + processor.onException(new PGPException("Unexpected packet: " + packet.getClass().getName())); + } + } + + static class OnePassSignatures + { + private final List onePassSignatures = new ArrayList(); + private final List signatures = new ArrayList(); + private final Map issuers = new HashMap(); + + OnePassSignatures() + { + + } + + void addOnePassSignatures(PGPOnePassSignatureList onePassSignatures) + { + for (Iterator it = onePassSignatures.iterator(); it.hasNext();) + { + PGPOnePassSignature ops = (PGPOnePassSignature)it.next(); + this.onePassSignatures.add(ops); + } + } + + void addSignatures(PGPSignatureList signatures) + { + for (Iterator it = signatures.iterator(); it.hasNext();) + { + PGPSignature signature = (PGPSignature)it.next(); + this.signatures.add(signature); + } + } + + void init(OpenPGPMessageProcessor processor) + { + + for (Iterator it = onePassSignatures.iterator(); it.hasNext();) + { + PGPOnePassSignature ops = (PGPOnePassSignature)it.next(); + KeyIdentifier identifier = ops.getKeyIdentifier(); + OpenPGPCertificate cert = processor.provideCertificate(identifier); + if (cert == null) + { + continue; + } + + try + { + OpenPGPCertificate.OpenPGPComponentKey key = cert.getKey(identifier); + issuers.put(ops, key); + ops.init(processor.getImplementation().pgpContentVerifierBuilderProvider(), + key.getPGPPublicKey()); + } + catch (PGPException e) + { + processor.onException(e); + } + } + } + + void update(int i) + { + for (Iterator it = onePassSignatures.iterator(); it.hasNext();) + { + PGPOnePassSignature onePassSignature = (PGPOnePassSignature)it.next(); + if (issuers.containsKey(onePassSignature)) + { + onePassSignature.update((byte) i); + } + } + } + + void update(byte[] b, int off, int len) + { + for (Iterator it = onePassSignatures.iterator(); it.hasNext();) + { + PGPOnePassSignature onePassSignature = (PGPOnePassSignature)it.next(); + if (issuers.containsKey(onePassSignature)) + { + onePassSignature.update(b, off, len); + } + } + } + + List verify( + OpenPGPMessageProcessor processor) + { + OpenPGPPolicy policy = processor.getImplementation().policy(); + List dataSignatures = new ArrayList(); + int num = onePassSignatures.size(); + for (int i = 0; i < signatures.size(); i++) + { + PGPSignature signature = signatures.get(i); + PGPOnePassSignature ops = onePassSignatures.get(num - i - 1); + OpenPGPCertificate.OpenPGPComponentKey key = issuers.get(ops); + if (key == null) + { + continue; + } + + OpenPGPSignature.OpenPGPDocumentSignature dataSignature = + new OpenPGPSignature.OpenPGPDocumentSignature(signature, key); + try + { + dataSignature.sanitize(key, policy); + } + catch (PGPSignatureException e) + { + // continue + } + + if (!dataSignature.createdInBounds(processor.getVerifyNotBefore(), processor.getVerifyNotAfter())) + { + // sig is not in bounds + continue; + } + + try + { + dataSignature.verify(ops); + } + catch (PGPException e) + { + processor.onException(e); + } + dataSignatures.add(dataSignature); + } + return dataSignatures; + } + } + + static class PrefixedSignatures + { + private final List prefixedSignatures = new ArrayList(); + private final List dataSignatures = new ArrayList(); + + PrefixedSignatures() + { + + } + + void addAll(PGPSignatureList signatures) + { + for (Iterator it = signatures.iterator(); it.hasNext();) + { + PGPSignature signature = (PGPSignature)it.next(); + this.prefixedSignatures.add(signature); + } + } + + void init(OpenPGPMessageProcessor processor) + { + for (Iterator it = prefixedSignatures.iterator(); it.hasNext();) + { + PGPSignature sig = (PGPSignature)it.next(); + KeyIdentifier identifier = OpenPGPSignature.getMostExpressiveIdentifier(sig.getKeyIdentifiers()); + if (identifier == null) + { + dataSignatures.add(new OpenPGPSignature.OpenPGPDocumentSignature(sig, null)); + continue; + } + OpenPGPCertificate cert = processor.provideCertificate(identifier); + if (cert == null) + { + dataSignatures.add(new OpenPGPSignature.OpenPGPDocumentSignature(sig, null)); + continue; + } + + OpenPGPCertificate.OpenPGPComponentKey key = cert.getKey(identifier); + OpenPGPSignature.OpenPGPDocumentSignature signature = new OpenPGPSignature.OpenPGPDocumentSignature(sig, key); + dataSignatures.add(signature); + try + { + signature.signature.init( + processor.getImplementation().pgpContentVerifierBuilderProvider(), + cert.getKey(identifier).getPGPPublicKey()); + } + catch (PGPException e) + { + processor.onException(e); + } + } + } + + void update(int i) + { + for (Iterator it = prefixedSignatures.iterator(); it.hasNext();) + { + PGPSignature signature = (PGPSignature)it.next(); + signature.update((byte) i); + } + } + + void update(byte[] buf, int off, int len) + { + for (Iterator it = prefixedSignatures.iterator(); it.hasNext();) + { + PGPSignature signature = (PGPSignature)it.next(); + signature.update(buf, off, len); + } + } + + List verify(OpenPGPMessageProcessor processor) + { + List verifiedSignatures = new ArrayList(); + OpenPGPPolicy policy = processor.getImplementation().policy(); + for (Iterator it = dataSignatures.iterator(); it.hasNext();) + { + OpenPGPSignature.OpenPGPDocumentSignature sig = (OpenPGPSignature.OpenPGPDocumentSignature)it.next(); + try + { + sig.sanitize(sig.issuer, policy); + } + catch (PGPSignatureException e) + { + processor.onException(e); + continue; + } + + try + { + sig.verify(); + } + catch (PGPException e) + { + processor.onException(e); + } + verifiedSignatures.add(sig); + } + return verifiedSignatures; + } + } + +// private static abstract class BaseSignatureVerifier +// { +// protected final List signatures = new ArrayList<>(); +// protected final Map issuers = new HashMap<>(); +// +// public void addSignatures(Iterator it) +// { +// while (it.hasNext()) +// { +// this.signatures.add(it.next()); +// } +// } +// +// protected void commonInit(OpenPGPMessageProcessor processor) +// throws PGPException +// { +// for (R sig : signatures) +// { +// KeyIdentifier identifier = getKeyIdentifier(sig); +// OpenPGPCertificate cert = processor.provideCertificate(identifier); +// +// if (cert != null) +// { +// OpenPGPCertificate.OpenPGPComponentKey key = cert.getKey(identifier); +// issuers.put(sig, key); +// initSignature(sig, key, processor); +// } +// } +// } +// +// public abstract void update(byte i); +// +// public abstract void update(byte[] buf, int off, int len); +// +// public List verify( +// OpenPGPMessageProcessor processor) +// { +// List results = new ArrayList<>(); +// OpenPGPPolicy policy = processor.getImplementation().policy(); +// +// for (R sig : signatures) +// { +// KeyIdentifier keyId = getKeyIdentifier(sig); +// OpenPGPCertificate.OpenPGPComponentKey key = issuers.get(keyId); +// +// OpenPGPSignature.OpenPGPDocumentSignature docSig = +// new OpenPGPSignature.OpenPGPDocumentSignature((PGPSignature)sig, key); +// +// try +// { +// if (key != null) +// { +// docSig.verify(); +// } +// docSig.sanitize(key, policy); +// } +// catch (PGPException e) +// { +// processor.onException(e); +// } +// +// results.add(docSig); +// } +// return results; +// } +// +// protected abstract KeyIdentifier getKeyIdentifier(R sig); +// +// protected abstract void initSignature(R sig, +// OpenPGPCertificate.OpenPGPComponentKey key, +// OpenPGPMessageProcessor processor) +// throws PGPException; +// } +// +// private static class OnePassSignatureVerifier +// extends BaseSignatureVerifier +// { +// private final List pgpSignatureList = new ArrayList<>(); +// +// public void addPGPSinatures(Iterator it) +// { +// while (it.hasNext()) +// { +// pgpSignatureList.add(it.next()); +// } +// } +// +// @Override +// protected KeyIdentifier getKeyIdentifier(PGPOnePassSignature sig) +// { +// // One-pass signatures directly include their key ID +// return sig.getKeyIdentifier(); +// } +// +// @Override +// protected void initSignature(PGPOnePassSignature sig, +// OpenPGPCertificate.OpenPGPComponentKey key, +// OpenPGPMessageProcessor processor) +// throws PGPException +// { +// // Initialize for one-pass signature verification +// sig.init(processor.getImplementation().pgpContentVerifierBuilderProvider(), +// key.getPGPPublicKey() +// ); +// } +// +// public void update(byte i) +// { +// for (PGPOnePassSignature sig : signatures) +// { +// sig.update(i); +// } +// } +// +// public void update(byte[] buf, int off, int len) +// { +// for (PGPOnePassSignature sig : signatures) +// { +// sig.update(buf, off, len); +// } +// } +// +// public List verify( +// OpenPGPMessageProcessor processor) +// { +// OpenPGPPolicy policy = processor.getImplementation().policy(); +// List dataSignatures = new ArrayList<>(); +// int num = signatures.size(); +// for (int i = 0; i < signatures.size(); i++) +// { +// PGPSignature signature = pgpSignatureList.get(i); +// PGPOnePassSignature ops = signatures.get(num - i - 1); +// OpenPGPCertificate.OpenPGPComponentKey key = issuers.get(ops); +// if (key == null) +// { +// continue; +// } +// +// OpenPGPSignature.OpenPGPDocumentSignature dataSignature = +// new OpenPGPSignature.OpenPGPDocumentSignature(signature, key); +// try +// { +// dataSignature.sanitize(key, policy); +// } +// catch (PGPSignatureException e) +// { +// // continue +// } +// +// if (!dataSignature.createdInBounds(processor.getVerifyNotBefore(), processor.getVerifyNotAfter())) +// { +// // sig is not in bounds +// continue; +// } +// +// try +// { +// dataSignature.verify(ops); +// } +// catch (PGPException e) +// { +// processor.onException(e); +// } +// dataSignatures.add(dataSignature); +// } +// return dataSignatures; +// } +// } +// +// private static class PrefixedSignatureVerifier +// extends BaseSignatureVerifier +// { +// @Override +// protected KeyIdentifier getKeyIdentifier(PGPSignature sig) +// { +// // Prefixed signatures may have multiple key identifiers +// return OpenPGPSignature.getMostExpressiveIdentifier(sig.getKeyIdentifiers()); +// } +// +// @Override +// protected void initSignature(PGPSignature sig, +// OpenPGPCertificate.OpenPGPComponentKey key, +// OpenPGPMessageProcessor processor) +// throws PGPException +// { +// // Initialize for prefixed signature verification +// sig.init( +// processor.getImplementation().pgpContentVerifierBuilderProvider(), +// key.getPGPPublicKey() +// ); +// } +// +// public void update(byte i) +// { +// for (PGPSignature sig : signatures) +// { +// sig.update(i); +// } +// } +// +// public void update(byte[] buf, int off, int len) +// { +// for (PGPSignature sig : signatures) +// { +// sig.update(buf, off, len); +// } +// } +// } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPMessageOutputStream.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPMessageOutputStream.java new file mode 100644 index 0000000000..b5ba7ae790 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPMessageOutputStream.java @@ -0,0 +1,471 @@ +package org.bouncycastle.openpgp.api; + +import org.bouncycastle.bcpg.BCPGOutputStream; +import org.bouncycastle.bcpg.PacketFormat; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPPadding; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureGenerator; +import org.bouncycastle.util.io.TeeOutputStream; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; +import java.util.Stack; + +/** + * Implementation of an {@link OutputStream} tailored to creating OpenPGP messages. + * Since not all OpenPGP-related OutputStreams forward {@link #close()} calls, we need to keep track of nested streams + * and close them in order. + * This stream can create OpenPGP messages following the following EBNF (which is a subset of the EBNF defined in RFC9580): + *
      + *
    • OpenPGP Message := ASCII-Armor(Optionally Encrypted Message) | Optionally Encrypted Message
    • + *
    • Literal Message := LiteralDataPacket
    • + *
    • Optionally Compressed Message := Literal Message | + * CompressedDataPacket(Literal Message)
    • + *
    • Optionally Signed Message := Optionally Compressed Message | + * OnePassSignaturePacket + Optionally Signed Message + SignaturePacket
    • + *
    • Optionally Padded Message := Optionally Signed Message | Optionally Signed Message + PaddingPacket
    • + *
    • Encrypted Message := SEIPDv1(Optionally Padded Message) | + * SEIPDv2(Optionally Padded Message) | + * OED(Optionally Padded Message)
    • + *
    • Optionally Encrypted Message := Optionally Padded Message | Encrypted Message
    • + *
    + * Therefore, this stream is capable of creating a wide variety of OpenPGP message, from simply + * LiteralDataPacket-wrapped plaintext over signed messages to encrypted, signed and padded messages. + * The following considerations lead to why this particular subset was chosen: + *
      + *
    • An encrypted message is not distinguishable from randomness, so it makes no sense to compress it
    • + *
    • Since signatures also consist of data which is not distinguishable from randomness, + * it makes no sense to compress them either
    • + *
    • Padding packets are used to prevent traffic analysis. + * Since they contain random data, we do not compress them. + * If a message is encrypted, we want to encrypt the padding packet to prevent an intermediate from stripping it
    • + *
    • Since (v4) signatures leak some metadata about the message plaintext (the hash and the issuer), + * for encrypted messages we always place signatures inside the encryption container (sign-then-encrypt)
    • + *
    • Prefix-signed messages (where a SignaturePacket is prefixed to an OpenPGP message) are + * inferior to One-Pass-Signed messages, so this stream cannot produce those.
    • + *
    • Messages using the Cleartext-Signature Framework are "different enough" to deserve their own + * message generator / stream.
    • + *
    + */ +public class OpenPGPMessageOutputStream + extends OutputStream +{ + // sink for the OpenPGP message + private final OutputStream baseOut; // non-null + + private final OutputStream armorOut; // nullable + private final OutputStream encodeOut; // non-null + private final OutputStream encryptOut; // nullable + private final OutputStream paddingOut; // nullable + private final OutputStream signOut; // nullable + private final OutputStream compressOut; // nullable + private final OutputStream literalOut; // non-null + + // pipe plaintext data into this stream + private final OutputStream plaintextOut; // non-null + + OpenPGPMessageOutputStream(OutputStream baseOut, Builder builder) + throws PGPException, IOException + { + this.baseOut = baseOut; + OutputStream innermostOut = baseOut; + + // ASCII ARMOR + if (builder.armorFactory != null) + { + armorOut = builder.armorFactory.get(innermostOut); + innermostOut = armorOut; + } + else + { + armorOut = null; + } + + // BCPG (decide packet length encoding format) + encodeOut = new BCPGOutputStream(innermostOut, PacketFormat.CURRENT); + innermostOut = encodeOut; + + // ENCRYPT + if (builder.encryptionStreamFactory != null) + { + encryptOut = builder.encryptionStreamFactory.get(innermostOut); + innermostOut = encryptOut; + } + else + { + encryptOut = null; + } + + // PADDING + if (builder.paddingStreamFactory != null) + { + paddingOut = builder.paddingStreamFactory.get(innermostOut); + innermostOut = paddingOut; + } + else + { + paddingOut = null; + } + + // SIGN + if (builder.signatureStreamFactory != null) + { + signOut = builder.signatureStreamFactory.get(innermostOut); + // signOut does not forward write() calls down, so we do *not* set innermostOut to it + } + else + { + signOut = null; + } + + // COMPRESS + if (builder.compressionStreamFactory != null) + { + compressOut = builder.compressionStreamFactory.get(innermostOut); + innermostOut = compressOut; + } + else + { + compressOut = null; + } + + // LITERAL DATA + if (builder.literalDataStreamFactory == null) + { + throw new PGPException("Missing instructions for LiteralData encoding."); + } + literalOut = builder.literalDataStreamFactory.get(innermostOut); + + if (signOut != null) + { + this.plaintextOut = new TeeOutputStream(literalOut, signOut); + } + else + { + this.plaintextOut = literalOut; + } + } + + @Override + public void write(int i) + throws IOException + { + plaintextOut.write(i); + } + + @Override + public void write(byte[] b) + throws IOException + { + write(b, 0, b.length); + } + + @Override + public void write(byte[] b, int off, int len) + throws IOException + { + plaintextOut.write(b, off, len); + } + + @Override + public void flush() + throws IOException + { + literalOut.flush(); + if (compressOut != null) + { + compressOut.flush(); + } + if (signOut != null) + { + signOut.flush(); + } + if (paddingOut != null) + { + paddingOut.flush(); + } + if (encryptOut != null) + { + encryptOut.flush(); + } + encodeOut.flush(); + if (armorOut != null) + { + armorOut.flush(); + } + baseOut.flush(); + } + + @Override + public void close() + throws IOException + { + literalOut.close(); + if (compressOut != null) + { + compressOut.close(); + } + if (signOut != null) + { + signOut.close(); + } + if (paddingOut != null) + { + paddingOut.close(); + } + if (encryptOut != null) + { + encryptOut.close(); + } + encodeOut.close(); + if (armorOut != null) + { + armorOut.close(); + } + baseOut.close(); + } + + /** + * Factory class for wrapping output streams. + */ + public interface OutputStreamFactory + { + /** + * Wrap the given base stream with another {@link OutputStream} and return the result. + * @param base base output stream + * @return wrapped output stream + * @throws PGPException if the wrapping stream cannot be instantiated + */ + OutputStream get(OutputStream base) throws PGPException, IOException; + } + + static Builder builder() + { + return new Builder(); + } + + /** + * Builder class for {@link OpenPGPMessageOutputStream} instances. + */ + static class Builder + { + private OpenPGPMessageGenerator.ArmoredOutputStreamFactory armorFactory; + private OutputStreamFactory paddingStreamFactory; + private OutputStreamFactory encryptionStreamFactory; + private OutputStreamFactory signatureStreamFactory; + private OutputStreamFactory compressionStreamFactory; + private OutputStreamFactory literalDataStreamFactory; + + /** + * Specify a factory for ASCII armoring the message. + * + * @param factory armor stream factory + * @return this + */ + public Builder armor(OpenPGPMessageGenerator.ArmoredOutputStreamFactory factory) + { + this.armorFactory = factory; + return this; + } + + /** + * Specify a factory for encrypting the message. + * + * @param factory encryption stream factory + * @return this + */ + public Builder encrypt(OutputStreamFactory factory) + { + this.encryptionStreamFactory = factory; + return this; + } + + /** + * Specify a factory for padding the message. + * + * @param factory padding stream factory + * @return this + */ + public Builder padding(OutputStreamFactory factory) + { + this.paddingStreamFactory = factory; + return this; + } + + /** + * Specify a factory for signing the message. + * + * @param factory signing stream factory + * @return this + */ + public Builder sign(OutputStreamFactory factory) + { + this.signatureStreamFactory = factory; + return this; + } + + /** + * Specify a factory for compressing the message. + * ' + * @param factory compression stream factory + * @return this + */ + public Builder compress(OutputStreamFactory factory) + { + this.compressionStreamFactory = factory; + return this; + } + + /** + * Specify a factory for literal-data-wrapping the message. + * + * @param factory literal data stream factory + * @return this + */ + public Builder literalData(OutputStreamFactory factory) + { + this.literalDataStreamFactory = factory; + return this; + } + + /** + * Construct the {@link OpenPGPMessageOutputStream} over the base output stream. + * + * @param baseOut base output stream + * @return OpenPGP message output stream + * @throws PGPException if a stream cannot be created + * @throws IOException if a signature cannot be generated + */ + public OpenPGPMessageOutputStream build(OutputStream baseOut) + throws PGPException, IOException + { + return new OpenPGPMessageOutputStream(baseOut, this); + } + } + + /** + * OutputStream which updates {@link PGPSignatureGenerator} instances with data that is written to it. + * Note: Data written to this stream will *NOT* be forwarded to the underlying {@link OutputStream}. + * Once {@link #close()} is called, it will generate {@link PGPSignature} objects from the generators and write + * those to the underlying {@link OutputStream}. + */ + static class SignatureGeneratorOutputStream + extends OutputStream + { + + private final OutputStream out; + private final List signatureGenerators; + + public SignatureGeneratorOutputStream(OutputStream out, List signatureGenerators) + { + this.out = out; + this.signatureGenerators = signatureGenerators; + } + + @Override + public void write(int i) + throws IOException + { + for (PGPSignatureGenerator sigGen : signatureGenerators) + { + sigGen.update((byte)i); + } + } + + @Override + public void write(byte[] b) + throws IOException + { + for (PGPSignatureGenerator sigGen : signatureGenerators) + { + sigGen.update(b); + } + } + + @Override + public void write(byte[] b, int off, int len) + throws IOException + { + for (PGPSignatureGenerator sigGen : signatureGenerators) + { + sigGen.update(b, off, len); + } + } + + @Override + public void close() + throws IOException + { + for (int i = signatureGenerators.size() - 1; i >= 0; i--) + { + PGPSignatureGenerator gen = signatureGenerators.get(i); + PGPSignature sig = null; + try + { + sig = gen.generate(); + } + catch (PGPException e) + { + throw new RuntimeException(e); + } + sig.encode(out); + } + } + } + + /** + * OutputStream which appends a {@link org.bouncycastle.bcpg.PaddingPacket} to the data + * once {@link #close()} is called. + */ + static class PaddingPacketAppenderOutputStream + extends OutputStream + { + private final OutputStream out; + private final PaddingPacketFactory packetFactory; + + public PaddingPacketAppenderOutputStream(OutputStream out, PaddingPacketFactory packetFactory) + { + this.out = out; + this.packetFactory = packetFactory; + } + + @Override + public void write(byte[] b) + throws IOException + { + out.write(b); + } + + @Override + public void write(byte[] b, int off, int len) + throws IOException + { + out.write(b, off, len); + } + + @Override + public void write(int i) + throws IOException + { + out.write(i); + } + + @Override + public void close() + throws IOException + { + packetFactory.providePaddingPacket().encode(out); + out.close(); + } + } + + /** + * Factory interface for creating PGPPadding objects. + */ + public interface PaddingPacketFactory + { + PGPPadding providePaddingPacket(); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPMessageProcessor.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPMessageProcessor.java new file mode 100644 index 0000000000..546d70a1bd --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPMessageProcessor.java @@ -0,0 +1,543 @@ +package org.bouncycastle.openpgp.api; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.bouncycastle.bcpg.KeyIdentifier; +import org.bouncycastle.openpgp.IntegrityProtectedInputStream; +import org.bouncycastle.openpgp.PGPEncryptedData; +import org.bouncycastle.openpgp.PGPEncryptedDataList; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPKeyPair; +import org.bouncycastle.openpgp.PGPObjectFactory; +import org.bouncycastle.openpgp.PGPPBEEncryptedData; +import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData; +import org.bouncycastle.openpgp.PGPSessionKey; +import org.bouncycastle.openpgp.PGPSessionKeyEncryptedData; +import org.bouncycastle.openpgp.PGPUtil; +import org.bouncycastle.openpgp.api.exception.KeyPassphraseException; +import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory; +import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; +import org.bouncycastle.openpgp.operator.SessionKeyDataDecryptorFactory; +import org.bouncycastle.util.Arrays; + +public class OpenPGPMessageProcessor +{ + private final OpenPGPImplementation implementation; + private final Configuration configuration; + + /** + * Create a new {@link OpenPGPMessageProcessor} using the default {@link OpenPGPImplementation}. + */ + public OpenPGPMessageProcessor() + { + this(OpenPGPImplementation.getInstance()); + } + + /** + * Create a new {@link OpenPGPMessageProcessor} using the given {@link OpenPGPImplementation}. + * + * @param implementation openpgp implementation + */ + public OpenPGPMessageProcessor(OpenPGPImplementation implementation) + { + this(implementation, implementation.policy()); + } + + public OpenPGPMessageProcessor(OpenPGPImplementation implementation, OpenPGPPolicy policy) + { + this.implementation = implementation; + this.configuration = new Configuration(policy); + } + + /** + * Add an {@link OpenPGPCertificate} for signature verification. + * If the message contains any signatures, the provided certificate will be considered as a candidate to verify + * the signature. + * + * @param issuerCertificate OpenPGP certificate + * @return this + */ + public OpenPGPMessageProcessor addVerificationCertificate(OpenPGPCertificate issuerCertificate) + { + configuration.certificatePool.addItem(issuerCertificate); + return this; + } + + public OpenPGPMessageProcessor verifyNotAfter(Date date) + { + configuration.verifyNotAfter = date; + return this; + } + + public OpenPGPMessageProcessor verifyNotBefore(Date date) + { + configuration.verifyNotBefore = date; + return this; + } + + /** + * Add an {@link OpenPGPKey} as potential decryption key. + * If the message is encrypted for an {@link OpenPGPKey}, this key can be tried to decrypt the message. + * Keys added via this method will also be available for message decryption if the message was encrypted + * to an anonymous recipient (wildcard key-id / fingerprint). + * + * @param key OpenPGP key + * @return this + */ + public OpenPGPMessageProcessor addDecryptionKey(OpenPGPKey key) + { + configuration.keyPool.addItem(key); + return this; + } + + /** + * Add an {@link OpenPGPKey} as potential decryption key, along with a {@link KeyPassphraseProvider} dedicated + * to this key. + * If the message is encrypted for an {@link OpenPGPKey}, this key can be tried to decrypt the message. + * Keys added via this method will also be available for message decryption if the message was encrypted + * to an anonymous recipient (wildcard key-id / fingerprint). + * + * @param key OpenPGP key + * @return this + */ + public OpenPGPMessageProcessor addDecryptionKey(OpenPGPKey key, char[] passphrase) + { + configuration.keyPool.addItem(key); + configuration.keyPassphraseProvider.addPassphrase(key, passphrase); + return this; + } + + /** + * Add a passphrase for secret key decryption. + * If the corresponding {@link OpenPGPKey} which key this passphrase is for is known in advance, + * it is highly advised to call {@link #addDecryptionKey(OpenPGPKey, char[])} instead, due to performance reasons. + * + * @param passphrase key-passphrase + * @return this + */ + public OpenPGPMessageProcessor addDecryptionKeyPassphrase(char[] passphrase) + { + configuration.keyPassphraseProvider.addPassphrase(passphrase); + return this; + } + + /** + * Set a provider for dynamically requesting missing passphrases used to unlock encrypted + * {@link OpenPGPKey OpenPGPKeys}. + * This provider is called, if a key cannot be unlocked using any passphrase provided via + * {@link #addDecryptionKey(OpenPGPKey, char[])}. + * + * @param keyPassphraseProvider key passphrase provider + * @return this + */ + public OpenPGPMessageProcessor setMissingOpenPGPKeyPassphraseProvider( + KeyPassphraseProvider keyPassphraseProvider) + { + this.configuration.keyPassphraseProvider.setMissingPassphraseCallback(keyPassphraseProvider); + return this; + } + + /** + * Set a {@link OpenPGPKeyMaterialProvider.OpenPGPCertificateProvider} to allow dynamic requesting certificates + * for signature verification. + * This provider is called if the requested {@link OpenPGPCertificate} has not yet been added explicitly + * via {@link #addVerificationCertificate(OpenPGPCertificate)}. + * This allows lazily requesting verification certificates at runtime. + * + * @param certificateProvider provider for OpenPGP certificates + * @return this + */ + public OpenPGPMessageProcessor setMissingOpenPGPCertificateProvider( + OpenPGPKeyMaterialProvider.OpenPGPCertificateProvider certificateProvider) + { + configuration.certificatePool.setMissingItemCallback(certificateProvider); + return this; + } + + /** + * Set a provider for {@link OpenPGPKey OpenPGPKeys}, which can be used to decrypt encrypted messages. + * This provider is called if an {@link OpenPGPKey} required to decrypt the message has not yet been + * explicitly added via {@link #addDecryptionKey(OpenPGPKey)}. + * This allows lazily requesting decryption keys at runtime. + * + * @param keyProvider provider for OpenPGP keys + * @return this + */ + public OpenPGPMessageProcessor setMissingOpenPGPKeyProvider( + OpenPGPKeyMaterialProvider.OpenPGPKeyProvider keyProvider) + { + configuration.keyPool.setMissingItemCallback(keyProvider); + return this; + } + + /** + * Set a passphrase to decrypt a symmetrically encrypted OpenPGP message. + * + * @param messagePassphrase passphrase for message decryption + * @return this + */ + public OpenPGPMessageProcessor addMessagePassphrase(char[] messagePassphrase) + { + this.configuration.addMessagePassphrase(messagePassphrase); + return this; + } + + /** + * Set a {@link MissingMessagePassphraseCallback} which will be invoked if the message is encrypted using a passphrase, + * but no working passphrase was provided. + * + * @param callback callback + * @return this + */ + public OpenPGPMessageProcessor setMissingMessagePassphraseCallback( + MissingMessagePassphraseCallback callback) + { + this.configuration.missingMessagePassphraseCallback = callback; + return this; + } + + /** + * Set a {@link PGPSessionKey} with which an encrypted OpenPGP message can be decrypted without the need for + * using a private key or passphrase. + * Typically, this method can be used, if the {@link PGPSessionKey} of a message is already known (e.g. because + * the message has already been decrypted before). + * The benefit of this is, that public-key operations can be costly. + * + * @param sessionKey session key + * @return this + */ + public OpenPGPMessageProcessor setSessionKey(PGPSessionKey sessionKey) + { + configuration.sessionKey = sessionKey; + return this; + } + + /** + * Process an OpenPGP message. + * + * @param messageIn input stream of the OpenPGP message + * @return plaintext input stream + * @throws IOException + * @throws PGPException + */ + public OpenPGPMessageInputStream process(InputStream messageIn) + throws IOException, PGPException + { + // Remove potential ASCII armoring + InputStream packetInputStream = PGPUtil.getDecoderStream(messageIn); + + PGPObjectFactory objectFactory = implementation.pgpObjectFactory(packetInputStream); + OpenPGPMessageInputStream in = new OpenPGPMessageInputStream(objectFactory, this); + in.process(); + return in; + } + + Date getVerifyNotBefore() + { + return configuration.verifyNotBefore; + } + + Date getVerifyNotAfter() + { + return configuration.verifyNotAfter; + } + + /** + * Bundle together metadata about the decryption result. + * That includes the encrypted data packet itself, the passphrase or (sub-)key that was used to decrypt the + * session-key, the session-key itself and lastly the resulting decrypted packet input stream. + */ + static class Decrypted + { + final InputStream inputStream; + final PGPSessionKey sessionKey; + final PGPEncryptedData esk; + OpenPGPCertificate.OpenPGPComponentKey decryptionKey; + char[] decryptionPassphrase; + + public Decrypted(PGPEncryptedData encryptedData, + PGPSessionKey decryptedSessionKey, + InputStream decryptedIn) + { + this.esk = encryptedData; + this.sessionKey = decryptedSessionKey; + this.inputStream = decryptedIn; + } + } + + /** + * Decrypt an encrypted data packet by trying passphrases and/or decryption keys. + * + * @param encDataList encrypted data + * @return decrypted data + * @throws PGPException in case of an error + */ + Decrypted decrypt(PGPEncryptedDataList encDataList) + throws PGPException + { + // Since decryption using session key is the most "deliberate" and "specific", we'll try that first + if (configuration.sessionKey != null) + { + // decrypt with provided session key + SessionKeyDataDecryptorFactory decryptorFactory = + implementation.sessionKeyDataDecryptorFactory(configuration.sessionKey); + PGPSessionKeyEncryptedData encData = encDataList.extractSessionKeyEncryptedData(); + InputStream decryptedIn = encData.getDataStream(decryptorFactory); + IntegrityProtectedInputStream verifyingIn = new IntegrityProtectedInputStream(decryptedIn, encData); + + return new Decrypted(encData, configuration.sessionKey, verifyingIn); + } + + List skesks = skesks(encDataList); + List pkesks = pkesks(encDataList); + + PGPException exception = null; + + // If the user explicitly provided a message passphrase, we'll try that next + if (!skesks.isEmpty() && !configuration.messagePassphrases.isEmpty()) + { + for (PGPPBEEncryptedData skesk : skesks) + { + for (char[] passphrase : configuration.messagePassphrases) + { + try + { + // Extract message session key with passphrase + PBEDataDecryptorFactory passphraseDecryptorFactory = + implementation.pbeDataDecryptorFactory(passphrase); + PGPSessionKey decryptedSessionKey = skesk.getSessionKey(passphraseDecryptorFactory); + + // Decrypt the message with the decrypted session key + SessionKeyDataDecryptorFactory skDecryptorFactory = + implementation.sessionKeyDataDecryptorFactory(decryptedSessionKey); + PGPSessionKeyEncryptedData encData = encDataList.extractSessionKeyEncryptedData(); + InputStream decryptedIn = encData.getDataStream(skDecryptorFactory); + IntegrityProtectedInputStream verifyingIn = new IntegrityProtectedInputStream(decryptedIn, encData); + + Decrypted decrypted = new Decrypted(encData, decryptedSessionKey, verifyingIn); + decrypted.decryptionPassphrase = passphrase; + + return decrypted; + } + catch (PGPException e) + { + onException(e); + // cache first exception, then continue to try next skesk if present + exception = exception != null ? exception : e; + } + } + } + } + + // Then we'll try decryption using secret key(s) + for (PGPPublicKeyEncryptedData pkesk : pkesks) + { + KeyIdentifier identifier = pkesk.getKeyIdentifier(); + OpenPGPKey key = configuration.keyPool.provide(identifier); + if (key == null) + { + continue; + } + + OpenPGPKey.OpenPGPSecretKey decryptionKey = key.getSecretKeys().get(identifier); + if (decryptionKey == null) + { + continue; + } + + try + { + if (!decryptionKey.isEncryptionKey()) + { + throw new PGPException("Key is not an encryption key and can therefore not decrypt."); + } + + char[] keyPassphrase = configuration.keyPassphraseProvider.getKeyPassword(decryptionKey); + PGPKeyPair unlockedKey = decryptionKey.unlock(keyPassphrase).getKeyPair(); + if (unlockedKey == null) + { + throw new KeyPassphraseException(decryptionKey, new PGPException("Cannot unlock secret key.")); + } + + // Decrypt the message session key using the private key + PublicKeyDataDecryptorFactory pkDecryptorFactory = + implementation.publicKeyDataDecryptorFactory(unlockedKey.getPrivateKey()); + PGPSessionKey decryptedSessionKey = pkesk.getSessionKey(pkDecryptorFactory); + + // Decrypt the message using the decrypted session key + SessionKeyDataDecryptorFactory skDecryptorFactory = + implementation.sessionKeyDataDecryptorFactory(decryptedSessionKey); + PGPSessionKeyEncryptedData encData = encDataList.extractSessionKeyEncryptedData(); + InputStream decryptedIn = encData.getDataStream(skDecryptorFactory); + IntegrityProtectedInputStream verifyingIn = new IntegrityProtectedInputStream(decryptedIn, encData); + Decrypted decrypted = new Decrypted(encData, decryptedSessionKey, verifyingIn); + decrypted.decryptionKey = decryptionKey; + return decrypted; + } + catch (PGPException e) + { + onException(e); + } + } + + // And lastly, we'll prompt the user dynamically for a message passphrase + if (!skesks.isEmpty() && configuration.missingMessagePassphraseCallback != null) + { + char[] passphrase; + while ((passphrase = configuration.missingMessagePassphraseCallback.getMessagePassphrase()) != null) + { + for (PGPPBEEncryptedData skesk : skesks) + { + try + { + // Decrypt the message session key using a passphrase + PBEDataDecryptorFactory passphraseDecryptorFactory = implementation.pbeDataDecryptorFactory(passphrase); + PGPSessionKey decryptedSessionKey = skesk.getSessionKey(passphraseDecryptorFactory); + + // Decrypt the data using the decrypted session key + SessionKeyDataDecryptorFactory skDecryptorFactory = implementation.sessionKeyDataDecryptorFactory(decryptedSessionKey); + PGPSessionKeyEncryptedData encData = encDataList.extractSessionKeyEncryptedData(); + InputStream decryptedIn = encData.getDataStream(skDecryptorFactory); + IntegrityProtectedInputStream verifyingIn = new IntegrityProtectedInputStream(decryptedIn, encData); + Decrypted decrypted = new Decrypted(encData, decryptedSessionKey, verifyingIn); + decrypted.decryptionPassphrase = passphrase; + return decrypted; + } + catch (PGPException e) + { + onException(e); + // cache first exception, then continue to try next skesk if present + exception = exception != null ? exception : e; + } + } + } + + if (exception != null) + { + throw exception; + } + } + + throw new PGPException("No working decryption method found."); + } + + /** + * Return all symmetric-key-encrypted-session-key (SKESK) packets leading the encrypted data packet. + * + * @param encDataList encrypted data list + * @return list of skesk packets (might be empty) + */ + private List skesks(PGPEncryptedDataList encDataList) + { + List list = new ArrayList(); + for (PGPEncryptedData encData : encDataList) + { + if (encData instanceof PGPPBEEncryptedData) + { + list.add((PGPPBEEncryptedData) encData); + } + } + return list; + } + + /** + * Return all public-key-encrypted-session-key (PKESK) packets leading the encrypted data packet. + * + * @param encDataList encrypted data list + * @return list of pkesk packets (might be empty) + */ + private List pkesks(PGPEncryptedDataList encDataList) + { + List list = new ArrayList(); + for (PGPEncryptedData encData : encDataList) + { + if (encData instanceof PGPPublicKeyEncryptedData) + { + list.add((PGPPublicKeyEncryptedData) encData); + } + } + return list; + } + + OpenPGPCertificate provideCertificate(KeyIdentifier identifier) + { + return configuration.certificatePool.provide(identifier); + } + + OpenPGPImplementation getImplementation() + { + return implementation; + } + + /** + * Method that can be called if a {@link PGPException} is thrown. + * If the user provided a {@link PGPExceptionCallback} ({@link Configuration#exceptionCallback} is not null), + * the exception will be passed along to that callback. + * Otherwise, nothing happens. + * + * @param e exception + */ + void onException(PGPException e) + { + if (configuration.exceptionCallback != null) + { + configuration.exceptionCallback.onException(e); + } + } + + public static class Configuration + { + private final OpenPGPPolicy policy; + private final OpenPGPKeyMaterialPool.OpenPGPCertificatePool certificatePool; + private final OpenPGPKeyMaterialPool.OpenPGPKeyPool keyPool; + private final KeyPassphraseProvider.DefaultKeyPassphraseProvider keyPassphraseProvider; + public final List messagePassphrases = new ArrayList(); + private MissingMessagePassphraseCallback missingMessagePassphraseCallback; + private PGPExceptionCallback exceptionCallback = null; + private PGPSessionKey sessionKey; + private Date verifyNotAfter = new Date(); // now + private Date verifyNotBefore = new Date(0L); // beginning of time + + public Configuration(OpenPGPPolicy policy) + { + this.policy = policy; + this.certificatePool = new OpenPGPKeyMaterialPool.OpenPGPCertificatePool(); + this.keyPool = new OpenPGPKeyMaterialPool.OpenPGPKeyPool(); + this.keyPassphraseProvider = new KeyPassphraseProvider.DefaultKeyPassphraseProvider(); + } + + /** + * Add a passphrase that will be tried when a symmetric-key-encrypted-session-key packet is found + * during the decryption process. + * + * @param messagePassphrase passphrase to decrypt the message with + * @return this + */ + public Configuration addMessagePassphrase(char[] messagePassphrase) + { + boolean found = false; + for (char[] existing : messagePassphrases) + { + found |= Arrays.areEqual(existing, messagePassphrase); + } + + if (!found) + { + messagePassphrases.add(messagePassphrase); + } + return this; + } + } + + /** + * Callback to handle {@link PGPException PGPExceptions}. + */ + public interface PGPExceptionCallback + { + void onException(PGPException e); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPPolicy.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPPolicy.java new file mode 100644 index 0000000000..e8f870a479 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPPolicy.java @@ -0,0 +1,324 @@ +package org.bouncycastle.openpgp.api; + +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + +import org.bouncycastle.bcpg.SignatureSubpacket; +import org.bouncycastle.bcpg.sig.NotationData; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; + +/** + * Policy for OpenPGP algorithms and features. + */ +public interface OpenPGPPolicy +{ + /** + * Return true, if the given {@link PGPPublicKey} is an acceptable signing key. + * Note: Although signing requires a secret key, we perform checks on the public part for consistency. + * + * @param key key + * @return true if acceptable signing key + */ + default boolean isAcceptableSigningKey(PGPPublicKey key) + { + return isAcceptablePublicKey(key); + } + + /** + * Return true, if the given {@link PGPPublicKey} is an acceptable signature verification key. + * Note: The asymmetry between this and {@link #isAcceptableSigningKey(PGPPublicKey)} is useful + * to prevent creation of signatures using a legacy key, while still allowing verification of + * signatures made using the same key. + * + * @param key key + * @return true if acceptable verification key + */ + default boolean isAcceptableVerificationKey(PGPPublicKey key) + { + return isAcceptablePublicKey(key); + } + + /** + * Return true, if the given {@link PGPPublicKey} is acceptable for encrypting messages. + * + * @param key key + * @return true if acceptable encryption key + */ + default boolean isAcceptableEncryptionKey(PGPPublicKey key) + { + return isAcceptablePublicKey(key); + } + + /** + * Return true, if the given {@link PGPPublicKey} is acceptable for decrypting messages. + * Note: Although decryption requires a secret key, we perform checks on the public part for consistency. + * The asymmetry between this and {@link #isAcceptableEncryptionKey(PGPPublicKey)} is useful + * to prevent creation of new encrypted messages using a legacy key, while still allowing decryption + * of existing messages using the same key. + * + * @param key key + * @return true if acceptable decryption key + */ + default boolean isAcceptableDecryptionKey(PGPPublicKey key) + { + return isAcceptablePublicKey(key); + } + + /** + * Return true, if the given {@link PGPPublicKey} is acceptable. + * + * @param key key + * @return true if acceptable key + */ + default boolean isAcceptablePublicKey(PGPPublicKey key) + { + return isAcceptablePublicKeyStrength(key.getAlgorithm(), key.getBitStrength()); + } + + /** + * Return true, if the given {@link PGPSignature} is acceptable (uses acceptable hash algorithm, + * does not contain unknown critical notations or subpackets). + * Note: A signature being acceptable does NOT mean that it is correct or valid. + * + * @param signature signature + * @return true if acceptable + */ + default boolean isAcceptableSignature(PGPSignature signature) + { + return hasAcceptableSignatureHashAlgorithm(signature) && + hasNoCriticalUnknownNotations(signature) && + hasNoCriticalUnknownSubpackets(signature); + } + + /** + * Return true, if the given {@link PGPSignature} was made using an acceptable signature hash algorithm. + * + * @param signature signature + * @return true if hash algorithm is acceptable + */ + default boolean hasAcceptableSignatureHashAlgorithm(PGPSignature signature) + { + switch (signature.getSignatureType()) + { + case PGPSignature.DEFAULT_CERTIFICATION: + case PGPSignature.NO_CERTIFICATION: + case PGPSignature.CASUAL_CERTIFICATION: + case PGPSignature.POSITIVE_CERTIFICATION: + case PGPSignature.DIRECT_KEY: + case PGPSignature.SUBKEY_BINDING: + case PGPSignature.PRIMARYKEY_BINDING: + return hasAcceptableCertificationSignatureHashAlgorithm(signature); + + case PGPSignature.CERTIFICATION_REVOCATION: + case PGPSignature.KEY_REVOCATION: + case PGPSignature.SUBKEY_REVOCATION: + return hasAcceptableRevocationSignatureHashAlgorithm(signature); + + case PGPSignature.BINARY_DOCUMENT: + case PGPSignature.CANONICAL_TEXT_DOCUMENT: + default: + return hasAcceptableDocumentSignatureHashAlgorithm(signature); + } + } + + /** + * Return true, if the {@link PGPSignature} uses an acceptable data/document signature hash algorithm. + * + * @param signature data / document signature + * @return true if hash algorithm is acceptable + */ + default boolean hasAcceptableDocumentSignatureHashAlgorithm(PGPSignature signature) + { + return isAcceptableDocumentSignatureHashAlgorithm(signature.getHashAlgorithm(), signature.getCreationTime()); + } + + /** + * Return true, if the {@link PGPSignature} uses an acceptable revocation signature hash algorithm. + * + * @param signature revocation signature + * @return true if hash algorithm is acceptable + */ + default boolean hasAcceptableRevocationSignatureHashAlgorithm(PGPSignature signature) + { + return isAcceptableRevocationSignatureHashAlgorithm(signature.getHashAlgorithm(), signature.getCreationTime()); + } + + /** + * Return true, if the {@link PGPSignature} uses an acceptable certification signature hash algorithm. + * + * @param signature certification signature + * @return true if hash algorithm is acceptable + */ + default boolean hasAcceptableCertificationSignatureHashAlgorithm(PGPSignature signature) + { + return isAcceptableCertificationSignatureHashAlgorithm(signature.getHashAlgorithm(), signature.getCreationTime()); + } + + /** + * Return true, if the hashed subpacket area of the signature does NOT contain unknown critical notations. + * @param signature signature + * @return true if signature is free from unknown critical notations + */ + default boolean hasNoCriticalUnknownNotations(PGPSignature signature) + { + PGPSignatureSubpacketVector hashedSubpackets = signature.getHashedSubPackets(); + if (hashedSubpackets == null) + { + return true; + } + + OpenPGPNotationRegistry registry = getNotationRegistry(); + + NotationData[] notations = hashedSubpackets.getNotationDataOccurrences(); + for (NotationData notation : notations) + { + if (notation.isCritical() && !registry.isNotationKnown(notation.getNotationName())) + { + return false; + } + } + return true; + } + + /** + * Return true, if the hashed subpacket area of the signature does NOT contain unknown critical subpackets. + * @param signature signature + * @return true if signature is free from unknown critical subpackets + */ + default boolean hasNoCriticalUnknownSubpackets(PGPSignature signature) + { + PGPSignatureSubpacketVector hashedSubpackets = signature.getHashedSubPackets(); + if (hashedSubpackets == null) + { + return true; + } + + for (SignatureSubpacket subpacket : hashedSubpackets.toArray()) + { + if (subpacket.isCritical() && + // only consider subpackets which are not recognized by SignatureSubpacketInputStream + subpacket.getClass().equals(SignatureSubpacket.class)) + { + if (!isKnownSignatureSubpacket(subpacket.getType())) + { + return false; + } + } + } + return true; + } + + /** + * Return true, if the given signature subpacket ID is known by the implementation. + * Note: This method is only called for subpackets not recognized by + * {@link org.bouncycastle.bcpg.SignatureSubpacketInputStream}. + * + * @param signatureSubpacketTag signature subpacket ID + * @return true if subpacket tag is known + */ + default boolean isKnownSignatureSubpacket(int signatureSubpacketTag) + { + // Overwrite this, allowing custom critical signature subpackets + return false; + } + + /** + * Return true, if the given hash algorithm is - at signature creation time - an acceptable document signature + * hash algorithm. + * + * @param hashAlgorithmId hash algorithm ID + * @param signatureCreationTime optional signature creation time + * @return true if hash algorithm is acceptable at creation time + */ + boolean isAcceptableDocumentSignatureHashAlgorithm(int hashAlgorithmId, Date signatureCreationTime); + + /** + * Return true, if the given hash algorithm is - at signature creation time - an acceptable revocation signature + * hash algorithm. + * + * @param hashAlgorithmId hash algorithm ID + * @param signatureCreationTime optional signature creation time + * @return true if hash algorithm is acceptable at creation time + */ + boolean isAcceptableRevocationSignatureHashAlgorithm(int hashAlgorithmId, Date signatureCreationTime); + + /** + * Return true, if the given hash algorithm is - at signature creation time - an acceptable certification signature + * hash algorithm. + * + * @param hashAlgorithmId hash algorithm ID + * @param signatureCreationTime optional signature creation time + * @return true if hash algorithm is acceptable at creation time + */ + boolean isAcceptableCertificationSignatureHashAlgorithm(int hashAlgorithmId, Date signatureCreationTime); + + /** + * Return the default certification signature hash algorithm ID. + * This is used as fallback, if negotiation of a commonly supported hash algorithm fails. + * + * @return default certification signature hash algorithm ID + */ + int getDefaultCertificationSignatureHashAlgorithm(); + + /** + * Return the default document signature hash algorithm ID. + * This is used as fallback, if negotiation of a commonly supported hash algorithm fails. + * + * @return default document signature hash algorithm ID + */ + int getDefaultDocumentSignatureHashAlgorithm(); + + /** + * Return true, if the given symmetric-key algorithm is acceptable. + * + * @param symmetricKeyAlgorithmId symmetric-key algorithm + * @return true if symmetric-key algorithm is acceptable + */ + boolean isAcceptableSymmetricKeyAlgorithm(int symmetricKeyAlgorithmId); + + /** + * Return the default symmetric-key algorithm, which is used as a fallback if symmetric encryption algorithm + * negotiation fails. + * + * @return default symmetric-key algorithm + */ + int getDefaultSymmetricKeyAlgorithm(); + + /** + * Return true, if the given bitStrength is acceptable for the given public key algorithm ID. + * + * @param publicKeyAlgorithmId ID of a public key algorithm + * @param bitStrength key bit strength + * @return true if strength is acceptable + */ + boolean isAcceptablePublicKeyStrength(int publicKeyAlgorithmId, int bitStrength); + + /** + * Return the policies {@link OpenPGPNotationRegistry} containing known notation names. + * + * @return notation registry + */ + OpenPGPNotationRegistry getNotationRegistry(); + + /** + * The {@link OpenPGPNotationRegistry} can be used to register known notations, such that signatures containing + * notation instances of the same name, which are marked as critical do not invalidate the signature. + */ + class OpenPGPNotationRegistry + { + private final Set knownNotations = new HashSet(); + + public boolean isNotationKnown(String notationName) + { + return knownNotations.contains(notationName); + } + + public void addKnownNotation(String notationName) + { + this.knownNotations.add(notationName); + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPSignature.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPSignature.java new file mode 100644 index 0000000000..6a7432cc0e --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPSignature.java @@ -0,0 +1,781 @@ +package org.bouncycastle.openpgp.api; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; + +import org.bouncycastle.bcpg.ArmoredOutputStream; +import org.bouncycastle.bcpg.BCPGOutputStream; +import org.bouncycastle.bcpg.KeyIdentifier; +import org.bouncycastle.bcpg.PacketFormat; +import org.bouncycastle.bcpg.SignaturePacket; +import org.bouncycastle.bcpg.SignatureSubpacket; +import org.bouncycastle.bcpg.SignatureSubpacketTags; +import org.bouncycastle.bcpg.sig.NotationData; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPOnePassSignature; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureException; +import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; +import org.bouncycastle.openpgp.api.exception.MalformedOpenPGPSignatureException; +import org.bouncycastle.openpgp.api.util.UTCUtil; +import org.bouncycastle.util.encoders.Hex; + +/** + * An OpenPGP signature. + * This is a wrapper around {@link PGPSignature} which tracks the verification state of the signature. + */ +public abstract class OpenPGPSignature +{ + protected final PGPSignature signature; + protected final OpenPGPCertificate.OpenPGPComponentKey issuer; + protected boolean isTested = false; + protected boolean isCorrect = false; + + /** + * Create an {@link OpenPGPSignature}. + * + * @param signature signature + * @param issuer issuer subkey + */ + public OpenPGPSignature(PGPSignature signature, OpenPGPCertificate.OpenPGPComponentKey issuer) + { + this.signature = signature; + this.issuer = issuer; + } + + /** + * Return the {@link PGPSignature}. + * + * @return signature + */ + public PGPSignature getSignature() + { + return signature; + } + + /** + * Return the {@link OpenPGPCertificate.OpenPGPComponentKey} subkey that issued this signature. + * This method might return null, if the issuer certificate is not available. + * + * @return issuer subkey or null + */ + public OpenPGPCertificate.OpenPGPComponentKey getIssuer() + { + return issuer; + } + + /** + * Return the {@link OpenPGPCertificate} that contains the subkey that issued this signature. + * This method might return null if the issuer certificate is not available + * + * @return issuer certificate or null + */ + public OpenPGPCertificate getIssuerCertificate() + { + return issuer != null ? issuer.getCertificate() : null; + } + + /** + * Return a {@link List} of possible {@link KeyIdentifier} candidates. + * + * @return key identifier candidates + */ + public List getKeyIdentifiers() + { + return signature.getKeyIdentifiers(); + } + + /** + * Return the most expressive {@link KeyIdentifier} from available candidates. + * + * @return most expressive key identifier + */ + public KeyIdentifier getKeyIdentifier() + { + List identifiers = getKeyIdentifiers(); + return getMostExpressiveIdentifier(identifiers); + } + + /** + * Return the most expressive issuer {@link KeyIdentifier}. + * Due to historic reasons, signatures MAY contain more than one issuer packet, which might contain inconsistent + * information (issuer key-ids / issuer fingerprints). + * Throw wildcards (anonymous issuers) into the mix, and it becomes apparent, that there needs to be a way to + * select the "best" issuer identifier. + * If there are more than one issuer packet, this method returns the most expressive (prefer fingerprints over + * key-ids, prefer non-wildcard over wildcard) and returns that. + * + * @param identifiers list of available identifiers + * @return the best identifier + */ + public static KeyIdentifier getMostExpressiveIdentifier(List identifiers) + { + if (identifiers.isEmpty()) + { + // none + return null; + } + if (identifiers.size() == 1) + { + // single + return identifiers.get(0); + } + + // Find most expressive identifier + for (Iterator it = identifiers.iterator(); it.hasNext();) + { + KeyIdentifier identifier = (KeyIdentifier)it.next(); + + // non-wildcard and has fingerprint + if (!identifier.isWildcard() && identifier.getFingerprint() != null) + { + return identifier; + } + } + + // Find non-wildcard identifier + for (Iterator it = identifiers.iterator(); it.hasNext();) + { + KeyIdentifier identifier = (KeyIdentifier)it.next(); + // non-wildcard (and no fingerprint) + if (!identifier.isWildcard()) + { + return identifier; + } + } + // else return first identifier + return identifiers.get(0); + } + + /** + * Return true, if this signature has been tested and is correct. + * + * @return true if the signature is tested and is correct, false otherwise + */ + public boolean isTestedCorrect() + { + return isTested && isCorrect; + } + + /** + * Return the creation time of the signature. + * + * @return signature creation time + */ + public Date getCreationTime() + { + return signature.getCreationTime(); + } + + /** + * Return the expiration time of the signature. + * If no expiration time was included (or if the signature was explicitly marked as non-expiring), + * return null, otherwise return the time of expiration. + * The signature is no longer valid, once the expiration time is exceeded. + * + * @return expiration time + */ + public Date getExpirationTime() + { + PGPSignatureSubpacketVector hashed = signature.getHashedSubPackets(); + if (hashed == null) + { + // v3 sigs have no expiration + return null; + } + long exp = hashed.getSignatureExpirationTime(); + if (exp < 0) + { + throw new RuntimeException("Negative expiration time"); + } + + if (exp == 0L) + { + // Explicit or implicit no expiration + return null; + } + + return new Date(getCreationTime().getTime() + 1000 * exp); + } + + /** + * Return true, if the signature is not a hard revocation, and if the evaluation time falls into the period + * between signature creation time and expiration or revocation. + * + * @param evaluationTime time for which you want to determine effectiveness of the signature + * @return true if the signature is effective at the given evaluation time + */ + public boolean isEffectiveAt(Date evaluationTime) + { + if (isHardRevocation()) + { + // hard revocation is valid at all times + return true; + } + + // creation <= eval < expiration + Date creation = getCreationTime(); + Date expiration = getExpirationTime(); + return !evaluationTime.before(creation) && (expiration == null || evaluationTime.before(expiration)); + } + + /** + * Return true, if this signature is a hard revocation. + * Contrary to soft revocations (the key / signature / user-id was gracefully retired), a hard revocation + * has a serious reason, like key compromise, or no reason at all. + * Hard revocations invalidate the key / signature / user-id retroactively, while soft revocations only + * invalidate from the time of revocation signature creation onwards. + * + * @return true if the signature is a hard revocation + */ + public boolean isHardRevocation() + { + return signature.isHardRevocation(); + } + + /** + * Return true, if this signature is a certification. + * Certification signatures are used to bind user-ids to a key. + * + * @return true if the signature is a certification + */ + public boolean isCertification() + { + return signature.isCertification(); + } + + + /** + * Check certain requirements for OpenPGP signatures. + * + * @param issuer signature issuer + * @throws MalformedOpenPGPSignatureException if the signature is malformed + */ + void sanitize(OpenPGPCertificate.OpenPGPComponentKey issuer, + OpenPGPPolicy policy) + throws PGPSignatureException + { + if (!policy.isAcceptablePublicKey(issuer.getPGPPublicKey())) + { + throw new PGPSignatureException("Unacceptable issuer key."); + } + if (!policy.hasAcceptableSignatureHashAlgorithm(signature)) + { + throw new PGPSignatureException("Unacceptable hash algorithm: " + signature.getHashAlgorithm()); + } + + if (signature.getVersion() < SignaturePacket.VERSION_4) + { + if (signature.getCreationTime().before(issuer.getCreationTime())) + { + throw new MalformedOpenPGPSignatureException( + this, "Signature predates issuer key creation time."); + } + return; + } + + PGPSignatureSubpacketVector hashed = signature.getHashedSubPackets(); + if (hashed == null) + { + throw new MalformedOpenPGPSignatureException( + this, "Missing hashed signature subpacket area."); + } + PGPSignatureSubpacketVector unhashed = signature.getUnhashedSubPackets(); + + if (hashed.getSignatureCreationTime() == null) + { + // Signatures MUST have hashed creation time subpacket + throw new MalformedOpenPGPSignatureException( + this, "Signature does not have a hashed SignatureCreationTime subpacket."); + } + + if (hashed.getSignatureCreationTime().before(issuer.getCreationTime())) + { + throw new MalformedOpenPGPSignatureException( + this, "Signature predates issuer key creation time."); + } + + NotationData[] notations = hashed.getNotationDataOccurrences(); + for (int i = 0; i< notations.length; i++ ) + { + NotationData notation = notations[i]; + if (notation.isCritical()) + { + throw new MalformedOpenPGPSignatureException( + this, "Critical unknown NotationData encountered: " + notation.getNotationName()); + } + } + + SignatureSubpacket[] signatureSubpackets = hashed.toArray(); + for (int i = 0; i != signatureSubpackets.length; i++) + { + SignatureSubpacket unknownSubpacket = signatureSubpackets[i]; + // SignatureSubpacketInputStream returns unknown subpackets as SignatureSubpacket + if (unknownSubpacket.isCritical() && + unknownSubpacket.getClass().equals(SignatureSubpacket.class)) + { + throw new MalformedOpenPGPSignatureException( + this, "Critical hashed unknown SignatureSubpacket encountered: " + unknownSubpacket.getType()); + } + } + + switch (signature.getVersion()) + { + case SignaturePacket.VERSION_4: + case SignaturePacket.VERSION_5: + if (hashed.getIssuerFingerprint() == null && + unhashed.getIssuerFingerprint() == null && + hashed.getSubpacket(SignatureSubpacketTags.ISSUER_KEY_ID) == null && + unhashed.getSubpacket(SignatureSubpacketTags.ISSUER_KEY_ID) == null) + { + int type = signature.getSignatureType(); + if (type != PGPSignature.SUBKEY_BINDING && type != PGPSignature.PRIMARYKEY_BINDING) + { + throw new MalformedOpenPGPSignatureException( + this, "Missing IssuerKeyID and IssuerFingerprint subpacket."); + } + } + break; + + case SignaturePacket.VERSION_6: + if (hashed.getSubpacket(SignatureSubpacketTags.ISSUER_KEY_ID) != null) + { + throw new MalformedOpenPGPSignatureException( + this, "v6 signature MUST NOT contain IssuerKeyID subpacket."); + } + if (hashed.getIssuerFingerprint() == null && unhashed.getIssuerFingerprint() == null) + { + throw new MalformedOpenPGPSignatureException( + this, "v6 signature MUST contain IssuerFingerprint subpacket."); + } + break; + + default: + } + } + + /** + * Return true, if this signature is a revocation, false otherwise. + * @return true if signature is revocation + */ + public boolean isRevocation() + { + return PGPSignature.isRevocation(signature.getSignatureType()); + } + + @Override + public String toString() + { + String issuerInfo = getIssuerDisplay(); + String period = UTCUtil.format(getCreationTime()) + + (getExpirationTime() == null ? "" : ">" + UTCUtil.format(getExpirationTime())); + String validity = isTested ? (isCorrect ? "✓" : "✗") : "❓"; + // -DM Hex.toHexString + return getType() + (signature.isHardRevocation() ? "(hard)" : "") + " " + Hex.toHexString(signature.getDigestPrefix()) + + " " + issuerInfo + " -> " + getTargetDisplay() + " (" + period + ") " + validity; + } + + protected String getIssuerDisplay() + { + if (issuer != null) + { + return issuer.toString(); + } + + KeyIdentifier issuerIdentifier = getKeyIdentifier(); + if (issuerIdentifier == null) + { + return "External[unknown]"; + } + + if (issuerIdentifier.isWildcard()) + { + return "Anonymous"; + } + return "External[" + Long.toHexString(issuerIdentifier.getKeyId()) + .toUpperCase(Locale.getDefault()) + "]"; + } + + protected abstract String getTargetDisplay(); + + protected String getType() + { + switch (signature.getSignatureType()) + { + case PGPSignature.BINARY_DOCUMENT: + return "BINARY_DOCUMENT"; + case PGPSignature.CANONICAL_TEXT_DOCUMENT: + return "CANONICAL_TEXT_DOCUMENT"; + case PGPSignature.STAND_ALONE: + return "STANDALONE"; + case PGPSignature.DEFAULT_CERTIFICATION: + return "DEFAULT_CERTIFICATION"; + case PGPSignature.NO_CERTIFICATION: + return "NO_CERTIFICATION"; + case PGPSignature.CASUAL_CERTIFICATION: + return "CASUAL_CERTIFICATION"; + case PGPSignature.POSITIVE_CERTIFICATION: + return "POSITIVE_CERTIFICATION"; + case PGPSignature.SUBKEY_BINDING: + return "SUBKEY_BINDING"; + case PGPSignature.PRIMARYKEY_BINDING: + return "PRIMARYKEY_BINDING"; + case PGPSignature.DIRECT_KEY: + return "DIRECT_KEY"; + case PGPSignature.KEY_REVOCATION: + return "KEY_REVOCATION"; + case PGPSignature.SUBKEY_REVOCATION: + return "SUBKEY_REVOCATION"; + case PGPSignature.CERTIFICATION_REVOCATION: + return "CERTIFICATION_REVOCATION"; + case PGPSignature.TIMESTAMP: + return "TIMESTAMP"; + case PGPSignature.THIRD_PARTY_CONFIRMATION: + return "THIRD_PARTY_CONFIRMATION"; + default: + return "UNKNOWN (" + signature.getSignatureType() + ")"; + } + } + + /** + * Return an ASCII armored String representation of the signature. + * If the signature contains issuer information, the fingerprint or key-id of the issuer will be added + * to the ASCII armor as a comment header. + * + * @return ASCII armored signature + * @throws IOException if the signature cannot be encoded + */ + public String toAsciiArmoredString() + throws IOException + { + return toAsciiArmoredString(PacketFormat.ROUNDTRIP); + } + + /** + * Return an ASCII armored String representation of the signature. + * If the signature contains issuer information, the fingerprint or key-id of the issuer will be added + * to the ASCII armor as a comment header. + * + * @param packetFormat decide, which packet format to use when encoding the signature + * @return ASCII armored signature + * @throws IOException if the signature cannot be encoded + */ + public String toAsciiArmoredString(PacketFormat packetFormat) + throws IOException + { + ArmoredOutputStream.Builder armorBuilder = ArmoredOutputStream.builder() + .clearHeaders(); + if (getKeyIdentifier() != null) + { + armorBuilder.addSplitMultilineComment(getKeyIdentifier().toPrettyPrint()); + } + return toAsciiArmoredString(packetFormat, armorBuilder); + } + + /** + * Return an ASCII armored String representation of the signature. + * The ASCII armor can be configured using the passed {@link ArmoredOutputStream.Builder}. + * + * @param packetFormat decide, which packet format to use when encoding the signature + * @param armorBuilder builder for the ASCII armored output stream + * @return ASCII armored signature + * @throws IOException if the signature cannot be encoded + */ + public String toAsciiArmoredString(PacketFormat packetFormat, ArmoredOutputStream.Builder armorBuilder) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ArmoredOutputStream aOut = armorBuilder.build(bOut); + aOut.write(getEncoded(packetFormat)); + aOut.close(); + return bOut.toString(); + } + + /** + * Return the binary encoding of the signature. + * + * @return binary encoding + * @throws IOException if the signature cannot be encoded + */ + public byte[] getEncoded() + throws IOException + { + return getEncoded(PacketFormat.ROUNDTRIP); + } + + /** + * Return the binary encoding of the signature. + * + * @param packetFormat decide, which packet format to use when encoding the signature + * @return binary encoding + * @throws IOException if the signature cannot be encoded + */ + public byte[] getEncoded(PacketFormat packetFormat) + throws IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + BCPGOutputStream pOut = new BCPGOutputStream(bOut, packetFormat); + signature.encode(pOut); + pOut.close(); + return bOut.toByteArray(); + } + + /** + * {@link SignatureSubpacket} and the {@link OpenPGPSignature} that contains it. + */ + public static final class OpenPGPSignatureSubpacket + { + private final SignatureSubpacket subpacket; + private final OpenPGPSignature signature; + private final boolean hashed; + + private OpenPGPSignatureSubpacket(SignatureSubpacket subpacket, + OpenPGPSignature signature, + boolean hashed) + { + this.signature = signature; + this.subpacket = subpacket; + this.hashed = hashed; + } + + /** + * Create a {@link OpenPGPSignatureSubpacket} contained in the hashed area of an {@link OpenPGPSignature}. + * + * @param subpacket subpacket + * @param signature the signature containing the subpacket + * @return OpenPGPSignatureSubpacket + */ + public static OpenPGPSignatureSubpacket hashed(SignatureSubpacket subpacket, OpenPGPSignature signature) + { + return new OpenPGPSignatureSubpacket(subpacket, signature, true); + } + + /** + * Create a {@link OpenPGPSignatureSubpacket} contained in the unhashed area of an {@link OpenPGPSignature}. + * + * @param subpacket subpacket + * @param signature the signature containing the subpacket + * @return OpenPGPSignatureSubpacket + */ + public static OpenPGPSignatureSubpacket unhashed(SignatureSubpacket subpacket, OpenPGPSignature signature) + { + return new OpenPGPSignatureSubpacket(subpacket, signature, false); + } + + /** + * Return the {@link OpenPGPSignature} that contains the {@link SignatureSubpacket}. + * @return signature + */ + public OpenPGPSignature getSignature() + { + return signature; + } + + /** + * Return the {@link SignatureSubpacket} itself. + * @return + */ + public SignatureSubpacket getSubpacket() + { + return subpacket; + } + + /** + * Return
    true
    if the subpacket is contained in the hashed area of the {@link OpenPGPSignature}, + * false otherwise. + * @return true if the subpacket is hashed, false if it is unhashed + */ + public boolean isHashed() + { + return hashed; + } + } + + /** + * An {@link OpenPGPSignature} made over a binary or textual document (e.g. a message). + * Also known as a Data Signature. + * An {@link OpenPGPDocumentSignature} CANNOT live on a {@link OpenPGPCertificate}. + */ + public static class OpenPGPDocumentSignature + extends OpenPGPSignature + { + protected final OpenPGPDocumentSignature attestedSignature; + + /** + * Create a document signature of level 0 (signature is made directly over the document). + * + * @param signature signature + * @param issuer public issuer-signing-key-component (or null if not available) + */ + public OpenPGPDocumentSignature(PGPSignature signature, OpenPGPCertificate.OpenPGPComponentKey issuer) + { + super(signature, issuer); + this.attestedSignature = null; + } + + @Override + protected String getTargetDisplay() + { + return ""; + } + + /** + * Create a document signature of level greater than 0 (signature is made as an attestation over + * other signature(s) + document). + * If the attested signature is itself an attestation, it will recursively contain its attested signature. + * + * @param signature attestation signature + * @param issuer public issuer signing-key-component (or null if not available) + * @param attestedSignature the attested signature + */ + public OpenPGPDocumentSignature(PGPSignature signature, + OpenPGPCertificate.OpenPGPComponentKey issuer, + OpenPGPDocumentSignature attestedSignature) + { + super(signature, issuer); + this.attestedSignature = attestedSignature; + } + + /** + * Return the signature attestation level of this signature. + * If this signature was created directly over a document, this method returns 0. + * A level greater than 0 indicates that the signature is an attestation over at least one other signature. + * + * @return signature attestation level + */ + public int getSignatureLevel() + { + if (attestedSignature == null) + { + return 0; // signature over data + } + else + { + return 1 + attestedSignature.getSignatureLevel(); + } + } + + /** + * Return the attested signature (or null if this is not an attestation signature). + * + * @return attested signature or null + */ + public OpenPGPDocumentSignature getAttestedSignature() + { + return attestedSignature; + } + + /** + * Verify the correctness of an inline signature by evaluating the corresponding {@link PGPOnePassSignature}. + * + * @param ops one-pass-signature packet + * @return true if the signature is correct, false otherwise + * @throws PGPException if the signature cannot be verified + */ + public boolean verify(PGPOnePassSignature ops) + throws PGPException + { + isTested = true; + isCorrect = ops.verify(signature); + return isCorrect; + } + + /** + * Verify the correctness of a prefixed-signature. + * + * @return true if the signature is correct, false otherwise + * @throws PGPException if the signature cannot be verified + */ + public boolean verify() + throws PGPException + { + isTested = true; + isCorrect = signature.verify(); + return isCorrect; + } + + /** + * Return true, if the signature is valid at this moment. + * A valid signature is effective, correct and was issued by a valid signing key. + * + * @return true if the signature is valid now. + */ + public boolean isValid() + throws PGPSignatureException + { + return isValid(OpenPGPImplementation.getInstance().policy()); + } + + /** + * Return true, if the signature is valid at this moment using the given policy. + * A valid signature is effective, correct and was issued by a valid signing key. + * + * @param policy policy + * @return true if the signature is valid now. + */ + public boolean isValid(OpenPGPPolicy policy) + throws PGPSignatureException + { + return isValidAt(getCreationTime(), policy); + } + + /** + * Return true, if th signature is valid at the given date. + * A valid signature is effective, correct and was issued by a valid signing key. + * + * @param date evaluation time + * @return true if the signature is valid at the given date + * @throws IllegalStateException if the signature has not yet been tested using a
    verify()
    method. + */ + public boolean isValidAt(Date date) + throws PGPSignatureException + { + return isValidAt(date, OpenPGPImplementation.getInstance().policy()); + } + + /** + * Return true, if th signature is valid at the given date using the given policy. + * A valid signature is effective, correct and was issued by a valid signing key. + * + * @param date evaluation time + * @param policy policy + * @return true if the signature is valid at the given date + * @throws IllegalStateException if the signature has not yet been tested using a
    verify()
    method. + */ + public boolean isValidAt(Date date, OpenPGPPolicy policy) + throws PGPSignatureException + { + if (!isTested) + { + throw new IllegalStateException("Signature has not yet been verified."); + } + if (!isTestedCorrect()) + { + return false; + } + + sanitize(issuer, policy); + + return issuer.getCertificate().getPrimaryKey().isBoundAt(date) && + issuer.isBoundAt(date) && + issuer.isSigningKey(date); + } + + /** + * Check, if the creation time of the signature is within the interval + *
    notBefore <= creationTime <= notAfter
    + * + * @param notBefore earliest accepted creation time + * @param notAfter latest accepted creation time + * @return true if sig was created in bounds, false otherwise + */ + public boolean createdInBounds(Date notBefore, Date notAfter) + { + return !getCreationTime().before(notBefore) && !getCreationTime().after(notAfter); + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPV6KeyGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPV6KeyGenerator.java deleted file mode 100644 index e512b3a3e8..0000000000 --- a/pg/src/main/java/org/bouncycastle/openpgp/api/OpenPGPV6KeyGenerator.java +++ /dev/null @@ -1,1248 +0,0 @@ -package org.bouncycastle.openpgp.api; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; -import java.util.List; - -import org.bouncycastle.bcpg.AEADAlgorithmTags; -import org.bouncycastle.bcpg.CompressionAlgorithmTags; -import org.bouncycastle.bcpg.HashAlgorithmTags; -import org.bouncycastle.bcpg.PublicKeyPacket; -import org.bouncycastle.bcpg.PublicKeyUtils; -import org.bouncycastle.bcpg.PublicSubkeyPacket; -import org.bouncycastle.bcpg.S2K; -import org.bouncycastle.bcpg.SignatureSubpacketTags; -import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; -import org.bouncycastle.bcpg.sig.Features; -import org.bouncycastle.bcpg.sig.KeyFlags; -import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPKeyPair; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSignature; -import org.bouncycastle.openpgp.PGPSignatureGenerator; -import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; -import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; -import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; -import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptorFactory; -import org.bouncycastle.openpgp.operator.PGPContentSignerBuilderProvider; -import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; -import org.bouncycastle.openpgp.operator.PGPKeyPairGenerator; -import org.bouncycastle.openpgp.operator.PGPKeyPairGeneratorProvider; -import org.bouncycastle.util.Arrays; - -/** - * High-level generator class for OpenPGP v6 keys. - */ -public class OpenPGPV6KeyGenerator -{ - /** - * Hash algorithm for key signatures if no other one is provided during construction. - */ - public static final int DEFAULT_SIGNATURE_HASH_ALGORITHM = HashAlgorithmTags.SHA3_512; - - // SECONDS - private static final long SECONDS_PER_MINUTE = 60; - private static final long SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE; - private static final long SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR; - private static final long SECONDS_PER_YEAR = 365 * SECONDS_PER_DAY; - - /** - * Standard AEAD encryption preferences (SEIPDv2). - * By default, only announce support for OCB + AES. - */ - public static SignatureSubpacketsFunction DEFAULT_AEAD_ALGORITHM_PREFERENCES = new SignatureSubpacketsFunction() - { - public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) - { - subpackets.removePacketsOfType(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS); - subpackets.setPreferredAEADCiphersuites(PreferredAEADCiphersuites.builder(false) - .addCombination(SymmetricKeyAlgorithmTags.AES_256, AEADAlgorithmTags.OCB) - .addCombination(SymmetricKeyAlgorithmTags.AES_192, AEADAlgorithmTags.OCB) - .addCombination(SymmetricKeyAlgorithmTags.AES_128, AEADAlgorithmTags.OCB)); - return subpackets; - } - }; - - /** - * Standard symmetric-key encryption preferences (SEIPDv1). - * By default, announce support for AES. - */ - public static SignatureSubpacketsFunction DEFAULT_SYMMETRIC_KEY_PREFERENCES = new SignatureSubpacketsFunction() - { - public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) - { - subpackets.removePacketsOfType(SignatureSubpacketTags.PREFERRED_SYM_ALGS); - subpackets.setPreferredSymmetricAlgorithms(false, new int[]{ - SymmetricKeyAlgorithmTags.AES_256, SymmetricKeyAlgorithmTags.AES_192, SymmetricKeyAlgorithmTags.AES_128 - }); - return subpackets; - } - }; - - /** - * Standard signature hash algorithm preferences. - * By default, only announce SHA3 and SHA2 algorithms. - */ - public static SignatureSubpacketsFunction DEFAULT_HASH_ALGORITHM_PREFERENCES = new SignatureSubpacketsFunction() - { - public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) - { - subpackets.removePacketsOfType(SignatureSubpacketTags.PREFERRED_HASH_ALGS); - subpackets.setPreferredHashAlgorithms(false, new int[]{ - HashAlgorithmTags.SHA3_512, HashAlgorithmTags.SHA3_256, - HashAlgorithmTags.SHA512, HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA256 - }); - return subpackets; - } - }; - - /** - * Standard compression algorithm preferences. - * By default, announce support for all known algorithms. - */ - public static SignatureSubpacketsFunction DEFAULT_COMPRESSION_ALGORITHM_PREFERENCES = new SignatureSubpacketsFunction() - { - public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) - { - subpackets.removePacketsOfType(SignatureSubpacketTags.PREFERRED_COMP_ALGS); - subpackets.setPreferredCompressionAlgorithms(false, new int[]{ - CompressionAlgorithmTags.UNCOMPRESSED, CompressionAlgorithmTags.ZIP, - CompressionAlgorithmTags.ZLIB, CompressionAlgorithmTags.BZIP2 - }); - return subpackets; - } - }; - - /** - * Standard features to announce. - * By default, announce SEIPDv1 (modification detection) and SEIPDv2. - */ - public static SignatureSubpacketsFunction DEFAULT_FEATURES = new SignatureSubpacketsFunction() - { - public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) - { - subpackets.removePacketsOfType(SignatureSubpacketTags.FEATURES); - subpackets.setFeature(false, (byte)(Features.FEATURE_MODIFICATION_DETECTION | Features.FEATURE_SEIPD_V2)); - return subpackets; - } - }; - - /** - * Standard signature subpackets for signing subkey's binding signatures. - * Sets the keyflag subpacket to SIGN_DATA. - */ - public static SignatureSubpacketsFunction SIGNING_SUBKEY_SUBPACKETS = new SignatureSubpacketsFunction() - { - public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) - { - subpackets.removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS); - subpackets.setKeyFlags(true, KeyFlags.SIGN_DATA); - return subpackets; - } - }; - - /** - * Standard signature subpackets for encryption subkey's binding signatures. - * Sets the keyflag subpacket to ENCRYPT_STORAGE|ENCRYPT_COMMS. - */ - public static SignatureSubpacketsFunction ENCRYPTION_SUBKEY_SUBPACKETS = new SignatureSubpacketsFunction() - { - public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) - { - subpackets.removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS); - subpackets.setKeyFlags(true, KeyFlags.ENCRYPT_STORAGE | KeyFlags.ENCRYPT_COMMS); - return subpackets; - } - }; - - /** - * Standard signature subpackets for the direct-key signature. - * Sets default features, hash-, compression-, symmetric-key-, and AEAD algorithm preferences. - */ - public static SignatureSubpacketsFunction DIRECT_KEY_SIGNATURE_SUBPACKETS = new SignatureSubpacketsFunction() - { - public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) - { - subpackets = DEFAULT_FEATURES.apply(subpackets); - subpackets = DEFAULT_HASH_ALGORITHM_PREFERENCES.apply(subpackets); - subpackets = DEFAULT_COMPRESSION_ALGORITHM_PREFERENCES.apply(subpackets); - subpackets = DEFAULT_SYMMETRIC_KEY_PREFERENCES.apply(subpackets); - subpackets = DEFAULT_AEAD_ALGORITHM_PREFERENCES.apply(subpackets); - return subpackets; - } - }; - - private final Implementation impl; // contains BC or JCA/JCE implementations - private final Configuration conf; - - /** - * Generate a new OpenPGP key generator for v6 keys. - * - * @param kpGenProvider key pair generator provider - * @param contentSignerBuilderProvider content signer builder provider - * @param digestCalculatorProvider digest calculator provider - * @param keyEncryptionBuilderProvider secret key encryption builder provider (AEAD) - * @param keyFingerPrintCalculator calculator for key fingerprints - * @param creationTime key creation time - */ - public OpenPGPV6KeyGenerator( - PGPKeyPairGeneratorProvider kpGenProvider, - PGPContentSignerBuilderProvider contentSignerBuilderProvider, - PGPDigestCalculatorProvider digestCalculatorProvider, - PBESecretKeyEncryptorFactory keyEncryptionBuilderProvider, - KeyFingerPrintCalculator keyFingerPrintCalculator, - Date creationTime) - { - this.impl = new Implementation(kpGenProvider, contentSignerBuilderProvider, digestCalculatorProvider, keyEncryptionBuilderProvider, keyFingerPrintCalculator); - this.conf = new Configuration(new Date((creationTime.getTime() / 1000) * 1000)); - } - - /** - * Generate an OpenPGP key consisting of a certify-only primary key, - * a dedicated signing-subkey and dedicated encryption-subkey. - * The key will carry the provided user-id and be protected using the provided passphrase. - * See {@link PGPKeyPairGenerator#generatePrimaryKey()} for the primary key type, - * {@link PGPKeyPairGenerator#generateSigningSubkey()} for the signing-subkey type and - * {@link PGPKeyPairGenerator#generateEncryptionSubkey()} for the encryption-subkey key type. - * - * @param userId user id - * @param passphrase nullable passphrase. - * @return OpenPGP key - * @throws PGPException if the key cannot be generated - */ - public PGPSecretKeyRing classicKey(String userId, char[] passphrase) - throws PGPException - { - return withPrimaryKey() - .addUserId(userId) - .addSigningSubkey() - .addEncryptionSubkey() - .build(passphrase); - } - - /** - * Generate an OpenPGP key consisting of an Ed25519 certify-only primary key, - * a dedicated Ed25519 sign-only subkey and dedicated X25519 encryption-only subkey. - * The key will carry the provided user-id and be protected using the provided passphrase. - * - * @param userId user id - * @param passphrase nullable passphrase - * @return OpenPGP key - * @throws PGPException if the key cannot be generated - */ - public PGPSecretKeyRing ed25519x25519Key(String userId, char[] passphrase) - throws PGPException - { - return withPrimaryKey(new KeyPairGeneratorCallback() - { - public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) - throws PGPException - { - return generator.generateEd25519KeyPair(); - } - }) - .addSigningSubkey(new KeyPairGeneratorCallback() - { - public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) - throws PGPException - { - return generator.generateEd25519KeyPair(); - } - }) - .addEncryptionSubkey(new KeyPairGeneratorCallback() - { - public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) - throws PGPException - { - return generator.generateX25519KeyPair(); - } - }) - .addUserId(userId) - .build(passphrase); - } - - - /** - * Generate an OpenPGP key consisting of an Ed448 certify-only primary key, - * a dedicated Ed448 sign-only subkey and dedicated X448 encryption-only subkey. - * The key will carry the provided user-id and be protected using the provided passphrase. - * - * @param userId user id - * @param passphrase nullable passphrase - * @return OpenPGP key - * @throws PGPException if the key cannot be generated - */ - public PGPSecretKeyRing ed448x448Key(String userId, char[] passphrase) - throws PGPException - { - return withPrimaryKey(new KeyPairGeneratorCallback() - { - public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) - throws PGPException - { - return generator.generateEd448KeyPair(); - } - }) - .addSigningSubkey(new KeyPairGeneratorCallback() - { - public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) - throws PGPException - { - return generator.generateEd448KeyPair(); - } - }) - .addEncryptionSubkey(new KeyPairGeneratorCallback() - { - public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) - throws PGPException - { - return generator.generateX448KeyPair(); - } - }) - .addUserId(userId) - .build(passphrase); - } - - /** - * Generate a sign-only OpenPGP key. - * The key consists of a single, user-id-less primary key, which is capable of signing and certifying. - * See {@link PGPKeyPairGenerator#generatePrimaryKey()} for the key type. - * - * @param passphrase nullable passphrase to protect the key with - * @return sign-only (+certify) OpenPGP key - * @throws PGPException if the key cannot be generated - */ - public PGPSecretKeyRing signOnlyKey(char[] passphrase) - throws PGPException - { - return signOnlyKey(passphrase, null); - } - - /** - * Generate a sign-only OpenPGP key. - * The key consists of a single, user-id-less primary key, which is capable of signing and certifying. - * It carries a single direct-key signature with signing-related preferences whose subpackets can be - * modified by providing a {@link SignatureSubpacketsFunction}. - * - * @param passphrase nullable passphrase to protect the key with - * @param userSubpackets callback to modify the direct-key signature subpackets with - * @return sign-only (+certify) OpenPGP key - * @throws PGPException if the key cannot be generated - */ - public PGPSecretKeyRing signOnlyKey( - char[] passphrase, - SignatureSubpacketsFunction userSubpackets) - throws PGPException - { - PGPKeyPair primaryKeyPair = impl.kpGenProvider.get(PublicKeyPacket.VERSION_6, conf.keyCreationTime) - .generatePrimaryKey(); - PBESecretKeyEncryptor encryptor = impl.keyEncryptorBuilderProvider - .build(passphrase, primaryKeyPair.getPublicKey().getPublicKeyPacket()); - return signOnlyKey(primaryKeyPair, encryptor, userSubpackets); - } - - /** - * Generate a sign-only OpenPGP key. - * The key consists of a single, user-id-less primary key, which is capable of signing and certifying. - * It carries a single direct-key signature with signing-related preferences whose subpackets can be - * modified by providing a {@link SignatureSubpacketsFunction}. - * - * @param primaryKeyPair signing-capable primary key - * @param keyEncryptor nullable encryptor to protect the primary key with - * @param userSubpackets callback to modify the direct-key signature subpackets with - * @return sign-only (+certify) OpenPGP key - * @throws PGPException if the key cannot be generated - */ - public PGPSecretKeyRing signOnlyKey( - PGPKeyPair primaryKeyPair, - PBESecretKeyEncryptor keyEncryptor, - SignatureSubpacketsFunction userSubpackets) - throws PGPException - { - if (primaryKeyPair.getPublicKey().getPublicKeyPacket() instanceof PublicSubkeyPacket) - { - throw new IllegalArgumentException("Primary key MUST NOT consist of subkey packet."); - } - - return primaryKeyWithDirectKeySig(primaryKeyPair, - new SignatureSubpacketsFunction() - { - public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator baseSubpackets) - { - // remove unrelated subpackets not needed for sign-only keys - baseSubpackets.removePacketsOfType(SignatureSubpacketTags.PREFERRED_AEAD_ALGORITHMS); - baseSubpackets.removePacketsOfType(SignatureSubpacketTags.PREFERRED_SYM_ALGS); - baseSubpackets.removePacketsOfType(SignatureSubpacketTags.PREFERRED_COMP_ALGS); - - // replace key flags -> CERTIFY_OTHER|SIGN_DATA - baseSubpackets.removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS); - baseSubpackets.setKeyFlags(true, KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA); - return baseSubpackets; - } - }, - userSubpackets, // apply user-provided subpacket changes - keyEncryptor) - .build(); - } - - /** - * Generate an OpenPGP key with a certification-capable primary key. - * See {@link PGPKeyPairGenerator#generatePrimaryKey()} for the primary key type - * - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey withPrimaryKey() - throws PGPException - { - return withPrimaryKey((SignatureSubpacketsFunction)null); - } - - public WithPrimaryKey withPrimaryKey( - KeyPairGeneratorCallback keyGenCallback) - throws PGPException - { - return withPrimaryKey(keyGenCallback, null); - } - - /** - * Generate an OpenPGP key with a certification-capable primary key. - * See {@link PGPKeyPairGenerator#generatePrimaryKey()} for the primary key type - * The key will carry a direct-key signature, whose subpackets can be modified by overriding the - * given {@link SignatureSubpacketsFunction}. - * - * @param directKeySubpackets nullable callback to modify the direct-key signatures subpackets - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey withPrimaryKey( - SignatureSubpacketsFunction directKeySubpackets) - throws PGPException - { - return withPrimaryKey( - new KeyPairGeneratorCallback() - { - public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) - throws PGPException - { - return generator.generatePrimaryKey(); - } - }, - directKeySubpackets); - } - - /** - * Generate an OpenPGP key with a certification-capable primary key. - * The {@link KeyPairGeneratorCallback} can be used to specify the primary key type. - * The key will carry a direct-key signature, whose subpackets can be modified by overriding the - * given {@link SignatureSubpacketsFunction}. - * - * @param keyGenCallback callback to specify the primary key type - * @param directKeySubpackets nullable callback to modify the direct-key signatures subpackets - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey withPrimaryKey( - KeyPairGeneratorCallback keyGenCallback, - SignatureSubpacketsFunction directKeySubpackets) - throws PGPException - { - return withPrimaryKey(keyGenCallback, directKeySubpackets, null); - } - - /** - * Generate an OpenPGP key with a certification-capable primary key. - * The key will carry a direct-key signature, whose subpackets can be modified by overriding the - * given {@link SignatureSubpacketsFunction}. - * - * @param primaryKeyPair primary key - * @param directKeySubpackets nullable callback to modify the direct-key signatures subpackets - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey withPrimaryKey( - PGPKeyPair primaryKeyPair, - SignatureSubpacketsFunction directKeySubpackets) - throws PGPException - { - return withPrimaryKey( - primaryKeyPair, - directKeySubpackets, - null); - } - - /** - * Generate an OpenPGP key with a certification-capable primary key. - * The {@link KeyPairGeneratorCallback} can be used to specify the primary key type. - * The key will carry a direct-key signature, whose subpackets can be modified by overriding the - * given {@link SignatureSubpacketsFunction}. - * IMPORTANT: The custom primary key passphrase will only be used, if in the final step the key is retrieved - * using {@link WithPrimaryKey#build()}. - * If instead {@link WithPrimaryKey#build(char[])} is used, the key-specific passphrase is overwritten with the argument - * passed into {@link WithPrimaryKey#build(char[])}. - * - * @param keyGenCallback callback to specify the primary key type - * @param directKeySubpackets nullable callback to modify the direct-key signatures subpackets - * @param passphrase nullable passphrase to protect the primary key with - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey withPrimaryKey( - KeyPairGeneratorCallback keyGenCallback, - SignatureSubpacketsFunction directKeySubpackets, - char[] passphrase) - throws PGPException - { - PGPKeyPair primaryKeyPair = keyGenCallback.generateFrom( - impl.kpGenProvider.get(PublicKeyPacket.VERSION_6, conf.keyCreationTime)); - PBESecretKeyEncryptor keyEncryptor = impl.keyEncryptorBuilderProvider - .build(passphrase, primaryKeyPair.getPublicKey().getPublicKeyPacket()); - return withPrimaryKey(primaryKeyPair, directKeySubpackets, keyEncryptor); - } - - /** - * Generate an OpenPGP key with a certification-capable primary key. - * The {@link KeyPairGeneratorCallback} can be used to specify the primary key type. - * The key will carry a direct-key signature, whose subpackets can be modified by overriding the - * given {@link SignatureSubpacketsFunction}. - * IMPORTANT: The custom keyEncryptor will only be used, if in the final step the key is retrieved - * using {@link WithPrimaryKey#build()}. - * If instead {@link WithPrimaryKey#build(char[])} is used, the key-specific encryptor is overwritten with - * an encryptor built from the argument passed into {@link WithPrimaryKey#build(char[])}. - * - * @param primaryKeyPair primary key - * @param directKeySubpackets nullable callback to modify the direct-key signatures subpackets - * @param keyEncryptor nullable encryptor to protect the primary key with - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey withPrimaryKey( - final PGPKeyPair primaryKeyPair, - SignatureSubpacketsFunction directKeySubpackets, - PBESecretKeyEncryptor keyEncryptor) - throws PGPException - { - if (primaryKeyPair.getPublicKey().getPublicKeyPacket() instanceof PublicSubkeyPacket) - { - throw new IllegalArgumentException("Primary key MUST NOT consist of subkey packet."); - } - - if (!PublicKeyUtils.isSigningAlgorithm(primaryKeyPair.getPublicKey().getAlgorithm())) - { - throw new PGPException("Primary key MUST use signing-capable algorithm."); - } - - return primaryKeyWithDirectKeySig( - primaryKeyPair, - new SignatureSubpacketsFunction() - { - public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) - { - subpackets.setIssuerFingerprint(true, primaryKeyPair.getPublicKey()); - subpackets.setSignatureCreationTime(conf.keyCreationTime); - subpackets.setKeyFlags(true, KeyFlags.CERTIFY_OTHER); - subpackets = DIRECT_KEY_SIGNATURE_SUBPACKETS.apply(subpackets); - subpackets.setKeyExpirationTime(false, 5 * SECONDS_PER_YEAR); - return subpackets; - } - }, - directKeySubpackets, - keyEncryptor); - } - - /** - * Specify the primary key and attach a direct-key signature. - * The direct-key signature's subpackets will first be modified using the baseSubpackets callback, followed - * by the customSubpackets callback. - * If both baseSubpackets and customSubpackets are null, no direct-key signature will be attached. - * - * @param primaryKeyPair primary key pair - * @param baseSubpackets base signature subpackets callback - * @param customSubpackets user-provided signature subpackets callback - * @param keyEncryptor key encryptor - * @return builder - * @throws PGPException if the key cannot be generated - */ - private WithPrimaryKey primaryKeyWithDirectKeySig( - PGPKeyPair primaryKeyPair, - SignatureSubpacketsFunction baseSubpackets, - SignatureSubpacketsFunction customSubpackets, - PBESecretKeyEncryptor keyEncryptor) - throws PGPException - { - if (baseSubpackets != null || customSubpackets != null) - { - // DK sig - PGPSignatureGenerator dkSigGen = new PGPSignatureGenerator( - impl.contentSignerBuilderProvider.get(primaryKeyPair.getPublicKey()), - primaryKeyPair.getPublicKey()); - dkSigGen.init(PGPSignature.DIRECT_KEY, primaryKeyPair.getPrivateKey()); - - PGPSignatureSubpacketGenerator subpackets = new PGPSignatureSubpacketGenerator(); - // application-dictated subpackets - if (baseSubpackets != null) - { - subpackets = baseSubpackets.apply(subpackets); - } - - // Allow the user to modify the direct-key signature subpackets - if (customSubpackets != null) - { - subpackets = customSubpackets.apply(subpackets); - } - - dkSigGen.setHashedSubpackets(subpackets.generate()); - - PGPSignature dkSig = dkSigGen.generateCertification(primaryKeyPair.getPublicKey()); - primaryKeyPair = new PGPKeyPair( - PGPPublicKey.addCertification(primaryKeyPair.getPublicKey(), dkSig), - primaryKeyPair.getPrivateKey()); - } - - Key primaryKey = new Key(primaryKeyPair, keyEncryptor); - - return new WithPrimaryKey(impl, conf, primaryKey); - } - - /** - * Intermediate builder class. - * Constructs an OpenPGP key from a specified primary key. - */ - public static class WithPrimaryKey - { - - private final Implementation impl; - private final Configuration conf; - private Key primaryKey; - private final List subkeys = new ArrayList(); - - /** - * Builder. - * - * @param implementation cryptographic implementation - * @param configuration key configuration - * @param primaryKey specified primary key - */ - private WithPrimaryKey(Implementation implementation, Configuration configuration, Key primaryKey) - { - this.impl = implementation; - this.conf = configuration; - this.primaryKey = primaryKey; - } - - /** - * Attach a User-ID with a positive certification to the key. - * - * @param userId user-id - * @return builder - * @throws PGPException if the user-id cannot be added - */ - public WithPrimaryKey addUserId(String userId) - throws PGPException - { - return addUserId(userId, null); - } - - /** - * Attach a User-ID with a positive certification to the key. - * The subpackets of the user-id certification can be modified using the userIdSubpackets callback. - * - * @param userId user-id - * @param userIdSubpackets callback to modify the certification subpackets - * @return builder - * @throws PGPException if the user-id cannot be added - */ - public WithPrimaryKey addUserId( - String userId, - SignatureSubpacketsFunction userIdSubpackets) - throws PGPException - { - return addUserId(userId, PGPSignature.POSITIVE_CERTIFICATION, userIdSubpackets); - } - - /** - * Attach a User-ID with a positive certification to the key. - * The subpackets of the user-id certification can be modified using the userIdSubpackets callback. - * - * @param userId user-id - * @param certificationType signature type - * @param userIdSubpackets callback to modify the certification subpackets - * @return builder - * @throws PGPException if the user-id cannot be added - */ - public WithPrimaryKey addUserId( - String userId, - int certificationType, - SignatureSubpacketsFunction userIdSubpackets) - throws PGPException - { - if (userId == null || userId.trim().length() == 0) - { - throw new IllegalArgumentException("User-ID cannot be null or empty."); - } - - if (!PGPSignature.isCertification(certificationType)) - { - throw new IllegalArgumentException("Signature type MUST be a certification type (0x10 - 0x13)"); - } - - PGPSignatureGenerator uidSigGen = new PGPSignatureGenerator( - impl.contentSignerBuilderProvider.get(primaryKey.pair.getPublicKey()), - primaryKey.pair.getPublicKey()); - uidSigGen.init(certificationType, primaryKey.pair.getPrivateKey()); - - PGPSignatureSubpacketGenerator subpackets = new PGPSignatureSubpacketGenerator(); - subpackets.setIssuerFingerprint(true, primaryKey.pair.getPublicKey()); - subpackets.setSignatureCreationTime(conf.keyCreationTime); - - if (userIdSubpackets != null) - { - subpackets = userIdSubpackets.apply(subpackets); - } - uidSigGen.setHashedSubpackets(subpackets.generate()); - - PGPSignature uidSig = uidSigGen.generateCertification(userId, primaryKey.pair.getPublicKey()); - PGPPublicKey pubKey = PGPPublicKey.addCertification(primaryKey.pair.getPublicKey(), userId, uidSig); - primaryKey = new Key(new PGPKeyPair(pubKey, primaryKey.pair.getPrivateKey()), primaryKey.encryptor); - - return this; - } - - /** - * Add an encryption-capable subkey to the OpenPGP key. - * See {@link PGPKeyPairGenerator#generateEncryptionSubkey()} for the key type. - * - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey addEncryptionSubkey() - throws PGPException - { - return addEncryptionSubkey(new KeyPairGeneratorCallback() - { - public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) - throws PGPException - { - return generator.generateEncryptionSubkey(); - } - }); - } - - /** - * Add an encryption-capable subkey to the OpenPGP key. - * The type of the subkey can be decided by implementing the {@link KeyPairGeneratorCallback}. - * - * @param keyGenCallback callback to decide the encryption subkey type - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey addEncryptionSubkey(KeyPairGeneratorCallback keyGenCallback) - throws PGPException - { - return addEncryptionSubkey(keyGenCallback, (char[])null); - } - - /** - * Add an encryption-capable subkey to the OpenPGP key. - * The type of the subkey can be decided by implementing the {@link KeyPairGeneratorCallback}. - * The binding signature can be modified by implementing the {@link SignatureSubpacketsFunction}. - * - * @param generatorCallback callback to specify the encryption key type. - * @param bindingSubpacketsCallback nullable callback to modify the binding signature subpackets - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey addEncryptionSubkey( - KeyPairGeneratorCallback generatorCallback, - SignatureSubpacketsFunction bindingSubpacketsCallback) - throws PGPException - { - PGPKeyPairGenerator generator = impl.kpGenProvider.get( - primaryKey.pair.getPublicKey().getVersion(), - conf.keyCreationTime - ); - PGPKeyPair subkey = generatorCallback.generateFrom(generator); - - return addEncryptionSubkey(subkey, bindingSubpacketsCallback, null); - } - - /** - * Add an encryption-capable subkey to the OpenPGP key. - * The subkey will be protected using the provided subkey passphrase. - * IMPORTANT: The custom subkey passphrase will only be used, if in the final step the key is retrieved - * using {@link #build()}. - * If instead {@link #build(char[])} is used, the key-specific passphrase is overwritten with the argument - * passed into {@link #build(char[])}. - * See {@link PGPKeyPairGenerator#generateEncryptionSubkey()} for the key type. - * - * @param passphrase nullable subkey passphrase - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey addEncryptionSubkey(char[] passphrase) - throws PGPException - { - return addEncryptionSubkey(new KeyPairGeneratorCallback() - { - public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) - throws PGPException - { - return generator.generateEncryptionSubkey(); - } - }, passphrase); - } - - /** - * Add an encryption-capable subkey to the OpenPGP key. - * The key type can be specified by overriding {@link KeyPairGeneratorCallback}. - * The subkey will be protected using the provided subkey passphrase. - * IMPORTANT: The custom subkey passphrase will only be used, if in the final step the key is retrieved - * using {@link #build()}. - * If instead {@link #build(char[])} is used, the key-specific passphrase is overwritten with the argument - * passed into {@link #build(char[])}. - * - * @param keyGenCallback callback to specify the key type - * @param passphrase nullable passphrase for the encryption subkey - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey addEncryptionSubkey(KeyPairGeneratorCallback keyGenCallback, - char[] passphrase) - throws PGPException - { - return addEncryptionSubkey(keyGenCallback, null, passphrase); - } - - /** - * Add an encryption-capable subkey to the OpenPGP key. - * The key type can be specified by overriding {@link KeyPairGeneratorCallback}. - * The binding signatures subpackets can be modified by overriding the {@link SignatureSubpacketsFunction}. - * The subkey will be protected using the provided subkey passphrase. - * IMPORTANT: The custom subkey passphrase will only be used, if in the final step the key is retrieved - * using {@link #build()}. - * If instead {@link #build(char[])} is used, the key-specific passphrase is overwritten with the argument - * passed into {@link #build(char[])}. - * - * @param keyGenCallback callback to specify the key type - * @param bindingSignatureCallback nullable callback to modify the binding signature subpackets - * @param passphrase nullable passphrase for the encryption subkey - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey addEncryptionSubkey(KeyPairGeneratorCallback keyGenCallback, - SignatureSubpacketsFunction bindingSignatureCallback, - char[] passphrase) - throws PGPException - { - PGPKeyPair subkey = keyGenCallback.generateFrom( - impl.kpGenProvider.get(PublicKeyPacket.VERSION_6, conf.keyCreationTime)); - subkey = subkey.asSubkey(impl.keyFingerprintCalculator); - PBESecretKeyEncryptor keyEncryptor = impl.keyEncryptorBuilderProvider.build(passphrase, subkey.getPublicKey().getPublicKeyPacket()); - return addEncryptionSubkey(subkey, bindingSignatureCallback, keyEncryptor); - } - - - /** - * Add an encryption-capable subkey to the OpenPGP key. - * IMPORTANT: The custom key encryptor will only be used, if in the final step the key is retrieved - * using {@link #build()}. - * If instead {@link #build(char[])} is used, the key-specific encryptor is overwritten with an encryptor - * built from the argument passed into {@link #build(char[])}. - * - * @param encryptionSubkey encryption subkey - * @param bindingSubpacketsCallback nullable callback to modify the subkey binding signature subpackets - * @param keyEncryptor nullable encryptor to encrypt the encryption subkey - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey addEncryptionSubkey( - PGPKeyPair encryptionSubkey, - SignatureSubpacketsFunction bindingSubpacketsCallback, - PBESecretKeyEncryptor keyEncryptor) - throws PGPException - { - if (!(encryptionSubkey.getPublicKey().getPublicKeyPacket() instanceof PublicSubkeyPacket)) - { - throw new IllegalArgumentException("Encryption subkey MUST NOT consist of a primary key packet."); - } - - if (!encryptionSubkey.getPublicKey().isEncryptionKey()) - { - throw new PGPException("Encryption key MUST use encryption-capable algorithm."); - } - // generate binding signature - PGPSignatureSubpacketGenerator subpackets = new PGPSignatureSubpacketGenerator(); - subpackets.setIssuerFingerprint(true, primaryKey.pair.getPublicKey()); - subpackets.setSignatureCreationTime(conf.keyCreationTime); - subpackets = ENCRYPTION_SUBKEY_SUBPACKETS.apply(subpackets); - - // allow subpacket customization - PGPPublicKey publicSubkey = getPublicSubKey(encryptionSubkey, bindingSubpacketsCallback, subpackets); - Key subkey = new Key(new PGPKeyPair(publicSubkey, encryptionSubkey.getPrivateKey()), keyEncryptor); - subkeys.add(subkey); - return this; - } - - /** - * Add a signing-capable subkey to the OpenPGP key. - * The binding signature will contain a primary-key back-signature. - * See {@link PGPKeyPairGenerator#generateSigningSubkey()} for the key type. - * - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey addSigningSubkey() - throws PGPException - { - return addSigningSubkey(new KeyPairGeneratorCallback() - { - public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) - throws PGPException - { - return generator.generateSigningSubkey(); - } - }); - } - - /** - * Add a signing-capable subkey to the OpenPGP key. - * The binding signature will contain a primary-key back-signature. - * The key type can be specified by overriding {@link KeyPairGeneratorCallback}. - * - * @param keyGenCallback callback to specify the signing-subkey type - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey addSigningSubkey(KeyPairGeneratorCallback keyGenCallback) - throws PGPException - { - return addSigningSubkey(keyGenCallback, null); - } - - /** - * Add a signing-capable subkey to the OpenPGP key. - * See {@link PGPKeyPairGenerator#generateSigningSubkey()} for the key type. - * The binding signature will contain a primary-key back-signature. - * IMPORTANT: The custom subkey passphrase will only be used, if in the final step the key is retrieved - * using {@link #build()}. - * If instead {@link #build(char[])} is used, the key-specific passphrase is overwritten with the argument - * passed into {@link #build(char[])}. - * - * @param passphrase nullable passphrase - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey addSigningSubkey(char[] passphrase) - throws PGPException - { - return addSigningSubkey(new KeyPairGeneratorCallback() - { - public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) - throws PGPException - { - return generator.generateSigningSubkey(); - } - }, passphrase); - } - - /** - * Add a signing-capable subkey to the OpenPGP key. - * The signing-key type can be specified by overriding the {@link KeyPairGeneratorCallback}. - * The binding signature will contain a primary-key back-signature. - * IMPORTANT: The custom subkey passphrase will only be used, if in the final step the key is retrieved - * using {@link #build()}. - * If instead {@link #build(char[])} is used, the key-specific passphrase is overwritten with the argument - * passed into {@link #build(char[])}. - * - * @param keyGenCallback callback to specify the signing-key type - * @param passphrase nullable passphrase - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey addSigningSubkey(KeyPairGeneratorCallback keyGenCallback, - char[] passphrase) - throws PGPException - { - return addSigningSubkey(keyGenCallback, null, null, passphrase); - } - - /** - * Add a signing-capable subkey to the OpenPGP key. - * The signing-key type can be specified by overriding the {@link KeyPairGeneratorCallback}. - * The binding signature will contain a primary-key back-signature. - * The contents of the binding signature(s) can be modified by overriding the respective - * {@link SignatureSubpacketsFunction} instances. - * IMPORTANT: The custom subkey passphrase will only be used, if in the final step the key is retrieved - * using {@link #build()}. - * If instead {@link #build(char[])} is used, the key-specific passphrase is overwritten with the argument - * passed into {@link #build(char[])}. - * - * @param keyGenCallback callback to specify the signing-key type - * @param bindingSignatureCallback callback to modify the contents of the signing subkey binding signature - * @param backSignatureCallback callback to modify the contents of the embedded primary key binding signature - * @param passphrase nullable passphrase - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey addSigningSubkey(KeyPairGeneratorCallback keyGenCallback, - SignatureSubpacketsFunction bindingSignatureCallback, - SignatureSubpacketsFunction backSignatureCallback, - char[] passphrase) - throws PGPException - { - PGPKeyPair subkey = keyGenCallback.generateFrom(impl.kpGenProvider.get(PublicKeyPacket.VERSION_6, conf.keyCreationTime)); - subkey = subkey.asSubkey(impl.keyFingerprintCalculator); - PBESecretKeyEncryptor keyEncryptor = impl.keyEncryptorBuilderProvider.build(passphrase, subkey.getPublicKey().getPublicKeyPacket()); - return addSigningSubkey(subkey, bindingSignatureCallback, backSignatureCallback, keyEncryptor); - } - - /** - * Add a signing-capable subkey to the OpenPGP key. - * The signing-key type can be specified by overriding the {@link KeyPairGeneratorCallback}. - * The binding signature will contain a primary-key back-signature. - * The contents of the binding signature(s) can be modified by overriding the respective - * {@link SignatureSubpacketsFunction} instances. - * IMPORTANT: The custom key encryptor will only be used, if in the final step the key is retrieved - * using {@link #build()}. - * If instead {@link #build(char[])} is used, the key-specific encryptor is overwritten with an encryptor - * built from the argument passed into {@link #build(char[])}. - * - * @param signingSubkey signing subkey - * @param bindingSignatureCallback callback to modify the contents of the signing subkey binding signature - * @param backSignatureCallback callback to modify the contents of the embedded primary key binding signature - * @param keyEncryptor nullable encryptor to protect the signing subkey - * @return builder - * @throws PGPException if the key cannot be generated - */ - public WithPrimaryKey addSigningSubkey(PGPKeyPair signingSubkey, - SignatureSubpacketsFunction bindingSignatureCallback, - SignatureSubpacketsFunction backSignatureCallback, - PBESecretKeyEncryptor keyEncryptor) - throws PGPException - { - if (!(signingSubkey.getPublicKey().getPublicKeyPacket() instanceof PublicSubkeyPacket)) - { - throw new IllegalArgumentException("Signing subkey MUST NOT consist of primary key packet."); - } - - if (!PublicKeyUtils.isSigningAlgorithm(signingSubkey.getPublicKey().getAlgorithm())) - { - throw new PGPException("Signing key MUST use signing-capable algorithm."); - } - - PGPSignatureSubpacketGenerator backSigSubpackets = new PGPSignatureSubpacketGenerator(); - backSigSubpackets.setIssuerFingerprint(true, signingSubkey.getPublicKey()); - backSigSubpackets.setSignatureCreationTime(conf.keyCreationTime); - if (backSignatureCallback != null) - { - backSigSubpackets = backSignatureCallback.apply(backSigSubpackets); - } - - PGPSignatureSubpacketGenerator bindingSigSubpackets = new PGPSignatureSubpacketGenerator(); - bindingSigSubpackets.setIssuerFingerprint(true, primaryKey.pair.getPublicKey()); - bindingSigSubpackets.setSignatureCreationTime(conf.keyCreationTime); - - bindingSigSubpackets = SIGNING_SUBKEY_SUBPACKETS.apply(bindingSigSubpackets); - - PGPSignatureGenerator backSigGen = new PGPSignatureGenerator( - impl.contentSignerBuilderProvider.get(signingSubkey.getPublicKey()), - signingSubkey.getPublicKey()); - backSigGen.init(PGPSignature.PRIMARYKEY_BINDING, signingSubkey.getPrivateKey()); - backSigGen.setHashedSubpackets(backSigSubpackets.generate()); - PGPSignature backSig = backSigGen.generateCertification( - primaryKey.pair.getPublicKey(), signingSubkey.getPublicKey()); - - try - { - bindingSigSubpackets.addEmbeddedSignature(false, backSig); - } - catch (IOException e) - { - throw new PGPException("Cannot embed back-signature.", e); - } - - PGPPublicKey signingPubKey = getPublicSubKey(signingSubkey, bindingSignatureCallback, bindingSigSubpackets); - signingSubkey = new PGPKeyPair(signingPubKey, signingSubkey.getPrivateKey()); - subkeys.add(new Key(signingSubkey, keyEncryptor)); - - return this; - } - - /** - * Build the {@link PGPSecretKeyRing OpenPGP key}, allowing individual passphrases for the subkeys. - * - * @return OpenPGP key - * @throws PGPException if the key cannot be generated - */ - public PGPSecretKeyRing build() - throws PGPException - { - PGPSecretKey primarySecretKey = new PGPSecretKey( - primaryKey.pair.getPrivateKey(), - primaryKey.pair.getPublicKey(), - impl.digestCalculatorProvider.get(HashAlgorithmTags.SHA1), - true, - primaryKey.encryptor); - List keys = new ArrayList(); - keys.add(primarySecretKey); - - for (Iterator it = subkeys.iterator(); it.hasNext();) - { - Key key = (Key)it.next(); - PGPSecretKey subkey = new PGPSecretKey( - key.pair.getPrivateKey(), - key.pair.getPublicKey(), - impl.digestCalculatorProvider.get(HashAlgorithmTags.SHA1), - false, - key.encryptor); - keys.add(subkey); - } - - return new PGPSecretKeyRing(keys); - } - - /** - * Build the {@link PGPSecretKeyRing OpenPGP key} using a single passphrase used to protect all subkeys. - * The passphrase will override whichever key protectors were specified in previous builder steps. - * - * @param passphrase nullable passphrase - * @return OpenPGP key - * @throws PGPException if the key cannot be generated - */ - public PGPSecretKeyRing build(char[] passphrase) - throws PGPException - { - PBESecretKeyEncryptor primaryKeyEncryptor = impl.keyEncryptorBuilderProvider - .build(passphrase, primaryKey.pair.getPublicKey().getPublicKeyPacket()); - sanitizeKeyEncryptor(primaryKeyEncryptor); - PGPSecretKey primarySecretKey = new PGPSecretKey( - primaryKey.pair.getPrivateKey(), - primaryKey.pair.getPublicKey(), - impl.digestCalculatorProvider.get(HashAlgorithmTags.SHA1), - true, - primaryKeyEncryptor); - List keys = new ArrayList(); - keys.add(primarySecretKey); - - for (Iterator it = subkeys.iterator(); it.hasNext();) - { - Key key = (Key)it.next(); - PBESecretKeyEncryptor subkeyEncryptor = impl.keyEncryptorBuilderProvider - .build(passphrase, key.pair.getPublicKey().getPublicKeyPacket()); - sanitizeKeyEncryptor(subkeyEncryptor); - PGPSecretKey subkey = new PGPSecretKey( - key.pair.getPrivateKey(), - key.pair.getPublicKey(), - impl.digestCalculatorProvider.get(HashAlgorithmTags.SHA1), - false, - subkeyEncryptor); - keys.add(subkey); - } - - if (passphrase != null) - { - Arrays.fill(passphrase, (char)0); - } - - return new PGPSecretKeyRing(keys); - } - - protected void sanitizeKeyEncryptor(PBESecretKeyEncryptor keyEncryptor) - { - if (keyEncryptor == null) - { - // Unprotected is okay - return; - } - - S2K s2k = keyEncryptor.getS2K(); - if (s2k.getType() == S2K.SIMPLE || s2k.getType() == S2K.SALTED) - { - throw new IllegalArgumentException("S2K specifiers SIMPLE and SALTED are not allowed for secret key encryption."); - } - else if (s2k.getType() == S2K.ARGON_2) - { - if (keyEncryptor.getAeadAlgorithm() == 0) - { - throw new IllegalArgumentException("Argon2 MUST be used with AEAD."); - } - } - } - - private PGPPublicKey getPublicSubKey(PGPKeyPair encryptionSubkey, SignatureSubpacketsFunction bindingSubpacketsCallback, PGPSignatureSubpacketGenerator subpackets) - throws PGPException - { - if (bindingSubpacketsCallback != null) - { - subpackets = bindingSubpacketsCallback.apply(subpackets); - } - - PGPSignatureGenerator bindingSigGen = new PGPSignatureGenerator( - impl.contentSignerBuilderProvider.get(primaryKey.pair.getPublicKey()), - primaryKey.pair.getPublicKey()); - bindingSigGen.init(PGPSignature.SUBKEY_BINDING, primaryKey.pair.getPrivateKey()); - bindingSigGen.setHashedSubpackets(subpackets.generate()); - - PGPSignature bindingSig = bindingSigGen.generateCertification(primaryKey.pair.getPublicKey(), encryptionSubkey.getPublicKey()); - return PGPPublicKey.addCertification(encryptionSubkey.getPublicKey(), bindingSig); - } - } - - /** - * Bundle implementation-specific provider classes. - */ - private static class Implementation - { - final PGPKeyPairGeneratorProvider kpGenProvider; - final PGPContentSignerBuilderProvider contentSignerBuilderProvider; - final PGPDigestCalculatorProvider digestCalculatorProvider; - final PBESecretKeyEncryptorFactory keyEncryptorBuilderProvider; - final KeyFingerPrintCalculator keyFingerprintCalculator; - - public Implementation(PGPKeyPairGeneratorProvider keyPairGeneratorProvider, - PGPContentSignerBuilderProvider contentSignerBuilderProvider, - PGPDigestCalculatorProvider digestCalculatorProvider, - PBESecretKeyEncryptorFactory keyEncryptorBuilderProvider, - KeyFingerPrintCalculator keyFingerPrintCalculator) - { - this.kpGenProvider = keyPairGeneratorProvider; - this.contentSignerBuilderProvider = contentSignerBuilderProvider; - this.digestCalculatorProvider = digestCalculatorProvider; - this.keyEncryptorBuilderProvider = keyEncryptorBuilderProvider; - this.keyFingerprintCalculator = keyFingerPrintCalculator; - } - } - - /** - * Bundle configuration-specific data. - */ - private static class Configuration - { - final Date keyCreationTime; - - public Configuration(Date keyCreationTime) - { - this.keyCreationTime = keyCreationTime; - } - } - - /** - * Tuple of a {@link PGPKeyPair} and (nullable) {@link PBESecretKeyEncryptor}. - */ - private static class Key - { - private final PGPKeyPair pair; - private final PBESecretKeyEncryptor encryptor; - - public Key(PGPKeyPair key, PBESecretKeyEncryptor encryptor) - { - this.pair = key; - this.encryptor = encryptor; - } - } -} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/SignatureParameters.java b/pg/src/main/java/org/bouncycastle/openpgp/api/SignatureParameters.java new file mode 100644 index 0000000000..26611a7d0c --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/SignatureParameters.java @@ -0,0 +1,338 @@ +package org.bouncycastle.openpgp.api; + +import java.util.Date; + +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.bouncycastle.util.Arrays; + +/** + * Parameters for signature generation. + * Some signature builders allow the user to pass in a {@link Callback}, which can be used to modify + * {@link SignatureParameters} instances prior to signature generation. + */ +public class SignatureParameters +{ + private int signatureType; + private Date signatureCreationTime = new Date(); + private int signatureHashAlgorithmId; + private SignatureSubpacketsFunction hashedSubpacketsFunction; + private SignatureSubpacketsFunction unhashedSubpacketsFunction; + + private final int[] allowedSignatureTypes; + + private SignatureParameters(int... allowedSignatureTypes) + { + this.allowedSignatureTypes = allowedSignatureTypes; + } + + /** + * Create default signature parameters object for a direct-key signature. + * When issued as a self-signature, direct-key signatures can be used to store algorithm preferences + * on the key, which apply to the entire certificate (including all subkeys). + * When issued as a third-party signature, direct-key signatures act as delegations, with which for example the + * web-of-trust can be built. + * + * @param policy algorithm policy + * @return parameters + * @see + * OpenPGP Web-of-Trust + */ + public static SignatureParameters directKeySignature(OpenPGPPolicy policy) + { + return new SignatureParameters(PGPSignature.DIRECT_KEY) + .setSignatureType(PGPSignature.DIRECT_KEY) + .setSignatureHashAlgorithm(policy.getDefaultCertificationSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Create default signature parameters for a key revocation signature. + * When issued as a self-signature, key revocation signatures can be used to revoke an entire certificate. + * To revoke only individual subkeys, see {@link #subkeyRevocation(OpenPGPPolicy)} instead. + * When issued as a third-party signature, key revocation signatures are used to revoke earlier delegation + * signatures. + * + * @param policy algorithm policy + * @return parameters + */ + public static SignatureParameters keyRevocation(OpenPGPPolicy policy) + { + return new SignatureParameters(PGPSignature.KEY_REVOCATION) + .setSignatureType(PGPSignature.KEY_REVOCATION) + .setSignatureHashAlgorithm(policy.getDefaultCertificationSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Create a default signature parameters object for a certification signature. + * The default signature type is {@link PGPSignature#POSITIVE_CERTIFICATION}, but can be changed to + * {@link PGPSignature#DEFAULT_CERTIFICATION}, {@link PGPSignature#NO_CERTIFICATION}, + * {@link PGPSignature#CASUAL_CERTIFICATION}. + * When issued as a self-signature, certifications can be used to bind user-ids to the certificate. + * When issued as third-party signatures, certificates act as a statement, expressing that the issuer + * is convinced that the user-id "belongs to" the certificate. + * + * @param policy algorithm policy + * @return parameters + */ + public static SignatureParameters certification(OpenPGPPolicy policy) + { + return new SignatureParameters( + PGPSignature.DEFAULT_CERTIFICATION, + PGPSignature.NO_CERTIFICATION, + PGPSignature.CASUAL_CERTIFICATION, + PGPSignature.POSITIVE_CERTIFICATION) + .setSignatureType(PGPSignature.POSITIVE_CERTIFICATION) + .setSignatureHashAlgorithm(policy.getDefaultCertificationSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Create a default signature parameters object for a subkey binding signature. + * + * @param policy algorithm policy + * @return parameters + */ + public static SignatureParameters subkeyBinding(OpenPGPPolicy policy) + { + return new SignatureParameters(PGPSignature.SUBKEY_BINDING) + .setSignatureType(PGPSignature.SUBKEY_BINDING) + .setSignatureHashAlgorithm(policy.getDefaultCertificationSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Create default signature parameters for a subkey revocation signature. + * + * @param policy algorithm policy + * @return parameters + */ + public static SignatureParameters subkeyRevocation(OpenPGPPolicy policy) + { + return new SignatureParameters(PGPSignature.SUBKEY_REVOCATION) + .setSignatureType(PGPSignature.SUBKEY_REVOCATION) + .setSignatureHashAlgorithm(policy.getDefaultCertificationSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Create a default signature parameters object for a primary-key binding (back-sig) signature. + * + * @param policy algorithm policy + * @return parameters + */ + public static SignatureParameters primaryKeyBinding(OpenPGPPolicy policy) + { + return new SignatureParameters(PGPSignature.PRIMARYKEY_BINDING) + .setSignatureType(PGPSignature.PRIMARYKEY_BINDING) + .setSignatureHashAlgorithm(policy.getDefaultCertificationSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Create a default signature parameters object for a certification-revocation signature. + * + * @param policy algorithm policy + * @return parameters + */ + public static SignatureParameters certificationRevocation(OpenPGPPolicy policy) + { + return new SignatureParameters(PGPSignature.CERTIFICATION_REVOCATION) + .setSignatureType(PGPSignature.CERTIFICATION_REVOCATION) + .setSignatureHashAlgorithm(policy.getDefaultCertificationSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Create a default signature parameters object for a data/document signature. + * The default signature type is {@link PGPSignature#BINARY_DOCUMENT}, but can be changed to + * {@link PGPSignature#CANONICAL_TEXT_DOCUMENT}. + * + * @param policy algorithm policy + * @return parameters + */ + public static SignatureParameters dataSignature(OpenPGPPolicy policy) + { + return new SignatureParameters(PGPSignature.BINARY_DOCUMENT, PGPSignature.CANONICAL_TEXT_DOCUMENT) + .setSignatureType(PGPSignature.BINARY_DOCUMENT) + .setSignatureHashAlgorithm(policy.getDefaultDocumentSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Change the signature type of the signature to-be-generated to the given type. + * Depending on which factory method was used to instantiate the signature parameters object, + * only certain signature types are allowed. Passing an illegal signature type causes an + * {@link IllegalArgumentException} to be thrown. + * + * @param signatureType signature type + * @return parameters + * @throws IllegalArgumentException if an illegal signature type is passed + */ + public SignatureParameters setSignatureType(int signatureType) + { + if (!Arrays.contains(allowedSignatureTypes, signatureType)) + { + throw new IllegalArgumentException("Illegal signature type provided."); + } + + this.signatureType = signatureType; + return this; + } + + /** + * Return the signature type for the signature to-be-generated. + * + * @return signature type + */ + public int getSignatureType() + { + return signatureType; + } + + /** + * Change the creation time of the signature to-be-generated. + * + * @param signatureCreationTime signature creation time + * @return parameters + */ + public SignatureParameters setSignatureCreationTime(Date signatureCreationTime) + { + if (signatureCreationTime == null) + { + throw new NullPointerException("Signature creation time cannot be null."); + } + + this.signatureCreationTime = signatureCreationTime; + + return this; + } + + /** + * Return the creation time of the signature to-be-generated. + * + * @return signature creation time + */ + public Date getSignatureCreationTime() + { + return signatureCreationTime; + } + + /** + * Change the hash algorithm for the signature to-be-generated. + * + * @param signatureHashAlgorithmId signature hash algorithm id + * @return parameters + */ + public SignatureParameters setSignatureHashAlgorithm(int signatureHashAlgorithmId) + { + this.signatureHashAlgorithmId = signatureHashAlgorithmId; + return this; + } + + /** + * Return the hash algorithm id of the signature to-be-generated. + * + * @return hash algorithm id + */ + public int getSignatureHashAlgorithmId() + { + return signatureHashAlgorithmId; + } + + /** + * Set a function, which is applied to the hashed subpackets area of the signature to-be-generated. + * + * @param subpacketsFunction function to apply to the hashed signature subpackets + * @return parameters + */ + public SignatureParameters setHashedSubpacketsFunction(SignatureSubpacketsFunction subpacketsFunction) + { + this.hashedSubpacketsFunction = subpacketsFunction; + return this; + } + + /** + * Apply the hashed subpackets function set via {@link #setHashedSubpacketsFunction(SignatureSubpacketsFunction)} + * to the given hashed subpackets. + * + * @param hashedSubpackets hashed signature subpackets + * @return modified hashed subpackets + */ + PGPSignatureSubpacketGenerator applyToHashedSubpackets(PGPSignatureSubpacketGenerator hashedSubpackets) + { + if (hashedSubpacketsFunction != null) + { + return hashedSubpacketsFunction.apply(hashedSubpackets); + } + return hashedSubpackets; + } + + /** + * Set a function, which is applied to the unhashed subpackets area of the signature to-be-generated. + * + * @param subpacketsFunction function to apply to the unhashed signature subpackets + * @return parameters + */ + public SignatureParameters setUnhashedSubpacketsFunction(SignatureSubpacketsFunction subpacketsFunction) + { + this.unhashedSubpacketsFunction = subpacketsFunction; + return this; + } + + /** + * Apply the unhashed subpackets function set via {@link #setUnhashedSubpacketsFunction(SignatureSubpacketsFunction)} + * to the given unhashed subpackets. + * + * @param unhashedSubpackets unhashed signature subpackets + * @return modified unhashed subpackets + */ + PGPSignatureSubpacketGenerator applyToUnhashedSubpackets(PGPSignatureSubpacketGenerator unhashedSubpackets) + { + if (unhashedSubpacketsFunction != null) + { + return unhashedSubpacketsFunction.apply(unhashedSubpackets); + } + return unhashedSubpackets; + } + + /** + * Callback, allowing the user to modify {@link SignatureParameters} before use. + */ + public interface Callback + { + /** + * Apply custom changes to {@link SignatureParameters}. + * + * @param parameters parameters instance + * @return modified parameters, or null + */ + default SignatureParameters apply(SignatureParameters parameters) + { + return parameters; + } + + static class Util + { + /** + * Shortcut method returning a {@link Callback} which only applies the given + * {@link SignatureSubpacketsFunction} to the hashed signature subpacket area of a signature. + * + * @param function signature subpackets function to apply to the hashed area + * @return callback + */ + public static Callback modifyHashedSubpackets(SignatureSubpacketsFunction function) + { + return new Callback() + { + @Override + public SignatureParameters apply(SignatureParameters parameters) + { + return parameters.setHashedSubpacketsFunction(function); + } + }; + } + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/SignatureSubpacketsFunction.java b/pg/src/main/java/org/bouncycastle/openpgp/api/SignatureSubpacketsFunction.java index 177954b692..9d7637e89a 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/api/SignatureSubpacketsFunction.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/SignatureSubpacketsFunction.java @@ -5,7 +5,7 @@ /** * Callback to modify the contents of a {@link PGPSignatureSubpacketGenerator}. - * The {@link OpenPGPV6KeyGenerator} already prepopulates the hashed subpacket areas of signatures during + * The {@link OpenPGPKeyGenerator} already prepopulates the hashed subpacket areas of signatures during * key generation. This callback is useful to apply custom changes to the hashed subpacket area during the * generation process. */ diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/SubkeySelector.java b/pg/src/main/java/org/bouncycastle/openpgp/api/SubkeySelector.java new file mode 100644 index 0000000000..5369b4a2f4 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/SubkeySelector.java @@ -0,0 +1,24 @@ +package org.bouncycastle.openpgp.api; + +import org.bouncycastle.bcpg.KeyIdentifier; +import org.bouncycastle.openpgp.PGPKeyRing; + +import java.util.List; + +/** + * Interface for selecting a subset of keys from a {@link PGPKeyRing}. + * This is useful e.g. for selecting a signing key from an OpenPGP key, or a for selecting all + * encryption capable subkeys of a certificate. + */ +public interface SubkeySelector +{ + /** + * Given a {@link PGPKeyRing}, select a subset of the key rings (sub-)keys and return their + * {@link KeyIdentifier KeyIdentifiers}. + * + * @param certificate OpenPGP key or certificate + * @param policy OpenPGP algorithm policy + * @return non-null list of identifiers + */ + List select(OpenPGPCertificate certificate, OpenPGPPolicy policy); +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/Utils.java b/pg/src/main/java/org/bouncycastle/openpgp/api/Utils.java new file mode 100644 index 0000000000..cd506e99ce --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/Utils.java @@ -0,0 +1,118 @@ +package org.bouncycastle.openpgp.api; + +import java.io.IOException; +import java.util.Date; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPKeyPair; +import org.bouncycastle.openpgp.PGPPrivateKey; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureGenerator; +import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; + +class Utils +{ + static void addEmbeddedSiganture(final PGPSignature backSig, PGPSignatureSubpacketGenerator hashedSubpackets) + throws PGPException + { + if (backSig != null) + { + try + { + hashedSubpackets.addEmbeddedSignature(true, backSig); + } + catch (IOException e) + { + throw new PGPException("Cannot encode embedded back-signature.", e); + } + } + } + + static PGPSignature getBackSignature(PGPKeyPair signingSubkey, SignatureParameters backSigParameters, + PGPPublicKey publicPrimaryKey, OpenPGPImplementation implementation, Date date) + throws PGPException + { + PGPSignature backSig = null; + if (backSigParameters != null) + { + PGPSignatureGenerator backSigGen = getPgpSignatureGenerator(implementation, signingSubkey.getPublicKey(), + signingSubkey.getPrivateKey(), backSigParameters, date, null); + + backSig = backSigGen.generateCertification(publicPrimaryKey, signingSubkey.getPublicKey()); + } + return backSig; + } + + static PGPPublicKey injectCertification(PGPPublicKey publicKey, PGPSignatureGenerator revGen, PGPPublicKey publicPrimaryKey) + throws PGPException + { + PGPSignature revocation = revGen.generateCertification(publicPrimaryKey, publicKey); + return PGPPublicKey.addCertification(publicKey, revocation); + } + + static PGPPublicKey injectCertification(PGPPublicKey publicKey, PGPSignatureGenerator revGen) + throws PGPException + { + // Inject signature into the certificate + PGPSignature revocation = revGen.generateCertification(publicKey); + return PGPPublicKey.addCertification(publicKey, revocation); + } + + static PGPPublicKey injectCertification(String userId, PGPPublicKey publicPrimaryKey, PGPSignatureGenerator uidSigGen) + throws PGPException + { + // Inject UID and signature into the certificate + PGPSignature uidSig = uidSigGen.generateCertification(userId, publicPrimaryKey); + return PGPPublicKey.addCertification(publicPrimaryKey, userId, uidSig); + } + + public interface HashedSubpacketsOperation + { + void operate(PGPSignatureSubpacketGenerator hashedSubpackets) + throws PGPException; + } + + static PGPSignatureGenerator getPgpSignatureGenerator(OpenPGPImplementation implementationProvider, + PGPPublicKey publicKey, + PGPPrivateKey privateKey, + SignatureParameters parameters, + Date date, + HashedSubpacketsOperation operation) + throws PGPException + { + PGPSignatureGenerator sigGen = new PGPSignatureGenerator( + implementationProvider.pgpContentSignerBuilder( + publicKey.getAlgorithm(), + parameters.getSignatureHashAlgorithmId()), + publicKey); + sigGen.init(parameters.getSignatureType(), privateKey); + + final PGPSignatureSubpacketGenerator hashedSubpackets = new PGPSignatureSubpacketGenerator(); + hashedSubpackets.setIssuerFingerprint(true, publicKey); + if (date != null) + { + hashedSubpackets.setSignatureCreationTime(date); + } + if (operation != null) + { + operation.operate(hashedSubpackets); + } + parameters.applyToHashedSubpackets(hashedSubpackets); + sigGen.setHashedSubpackets(hashedSubpackets.generate()); + + PGPSignatureSubpacketGenerator unhashedSubpackets = new PGPSignatureSubpacketGenerator(); + unhashedSubpackets = parameters.applyToUnhashedSubpackets(unhashedSubpackets); + sigGen.setUnhashedSubpackets(unhashedSubpackets.generate()); + return sigGen; + } + + static SignatureParameters applySignatureParameters(SignatureParameters.Callback signatureCallback, SignatureParameters parameters) + { + if (signatureCallback != null) + { + parameters = signatureCallback.apply(parameters); + } + return parameters; + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/bc/BcOpenPGPApi.java b/pg/src/main/java/org/bouncycastle/openpgp/api/bc/BcOpenPGPApi.java new file mode 100644 index 0000000000..297cd8cdac --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/bc/BcOpenPGPApi.java @@ -0,0 +1,60 @@ +package org.bouncycastle.openpgp.api.bc; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.api.OpenPGPApi; +import org.bouncycastle.openpgp.api.OpenPGPImplementation; +import org.bouncycastle.openpgp.api.OpenPGPPolicy; +import org.bouncycastle.openpgp.api.OpenPGPKeyGenerator; + +import java.util.Date; + +/** + * Implementation of {@link OpenPGPApi} using Bouncy Castles implementation of OpenPGP classes. + */ +public class BcOpenPGPApi + extends OpenPGPApi +{ + public BcOpenPGPApi() + { + this(new BcOpenPGPImplementation()); + } + + public BcOpenPGPApi(OpenPGPImplementation implementation) + { + super(implementation); + } + + public BcOpenPGPApi(OpenPGPPolicy policy) + { + this(new BcOpenPGPImplementation(), policy); + } + + public BcOpenPGPApi(OpenPGPImplementation implementation, OpenPGPPolicy policy) + { + super(implementation, policy); + } + + @Override + public OpenPGPKeyGenerator generateKey(int version) + throws PGPException + { + return new BcOpenPGPKeyGenerator(version); + } + + @Override + public OpenPGPKeyGenerator generateKey(int version, + Date creationTime) + throws PGPException + { + return new BcOpenPGPKeyGenerator(version, creationTime); + } + + @Override + public OpenPGPKeyGenerator generateKey(int version, + Date creationTime, + boolean aeadProtection) + throws PGPException + { + return new BcOpenPGPKeyGenerator(version, creationTime, aeadProtection); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/bc/BcOpenPGPImplementation.java b/pg/src/main/java/org/bouncycastle/openpgp/api/bc/BcOpenPGPImplementation.java new file mode 100644 index 0000000000..ff6f24b9d2 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/bc/BcOpenPGPImplementation.java @@ -0,0 +1,161 @@ +package org.bouncycastle.openpgp.api.bc; + +import java.io.InputStream; + +import org.bouncycastle.bcpg.S2K; +import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPObjectFactory; +import org.bouncycastle.openpgp.PGPPrivateKey; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPSessionKey; +import org.bouncycastle.openpgp.api.OpenPGPImplementation; +import org.bouncycastle.openpgp.bc.BcPGPObjectFactory; +import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; +import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory; +import org.bouncycastle.openpgp.operator.PBEKeyEncryptionMethodGenerator; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilderProvider; +import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptorFactory; +import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; +import org.bouncycastle.openpgp.operator.PGPContentSignerBuilderProvider; +import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider; +import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder; +import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; +import org.bouncycastle.openpgp.operator.PGPKeyPairGeneratorProvider; +import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; +import org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator; +import org.bouncycastle.openpgp.operator.SessionKeyDataDecryptorFactory; +import org.bouncycastle.openpgp.operator.bc.BcAEADSecretKeyEncryptorFactory; +import org.bouncycastle.openpgp.operator.bc.BcCFBSecretKeyEncryptorFactory; +import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; +import org.bouncycastle.openpgp.operator.bc.BcPBEDataDecryptorFactory; +import org.bouncycastle.openpgp.operator.bc.BcPBEKeyEncryptionMethodGenerator; +import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilderProvider; +import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder; +import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilderProvider; +import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider; +import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder; +import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; +import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPairGeneratorProvider; +import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory; +import org.bouncycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator; +import org.bouncycastle.openpgp.operator.bc.BcSessionKeyDataDecryptorFactory; + +/** + * Implementation of {@link OpenPGPImplementation} using Bouncy Castles implementation of OpenPGP classes. + */ +public class BcOpenPGPImplementation + extends OpenPGPImplementation +{ + @Override + public PGPObjectFactory pgpObjectFactory(InputStream packetInputStream) + { + return new BcPGPObjectFactory(packetInputStream) + .setThrowForUnknownCriticalPackets(true); + } + + @Override + public PGPContentVerifierBuilderProvider pgpContentVerifierBuilderProvider() + { + return new BcPGPContentVerifierBuilderProvider(); + } + + @Override + public PBESecretKeyDecryptorBuilderProvider pbeSecretKeyDecryptorBuilderProvider() + { + return new BcPBESecretKeyDecryptorBuilderProvider(); + } + + @Override + public PGPDataEncryptorBuilder pgpDataEncryptorBuilder(int symmetricKeyAlgorithm) + { + return new BcPGPDataEncryptorBuilder(symmetricKeyAlgorithm); + } + + @Override + public PublicKeyKeyEncryptionMethodGenerator publicKeyKeyEncryptionMethodGenerator(PGPPublicKey encryptionSubkey) + { + return new BcPublicKeyKeyEncryptionMethodGenerator(encryptionSubkey); + } + + @Override + public PBEKeyEncryptionMethodGenerator pbeKeyEncryptionMethodGenerator(char[] messagePassphrase) + { + return new BcPBEKeyEncryptionMethodGenerator(messagePassphrase); + } + + @Override + public PBEKeyEncryptionMethodGenerator pbeKeyEncryptionMethodGenerator(char[] messagePassphrase, S2K.Argon2Params argon2Params) + { + return new BcPBEKeyEncryptionMethodGenerator(messagePassphrase, argon2Params); + } + + @Override + public PGPContentSignerBuilder pgpContentSignerBuilder(int publicKeyAlgorithm, int hashAlgorithm) + { + return new BcPGPContentSignerBuilder(publicKeyAlgorithm, hashAlgorithm); + } + + @Override + public PBEDataDecryptorFactory pbeDataDecryptorFactory(char[] messagePassphrase) + throws PGPException + { + return new BcPBEDataDecryptorFactory(messagePassphrase, pgpDigestCalculatorProvider()); + } + + @Override + public SessionKeyDataDecryptorFactory sessionKeyDataDecryptorFactory(PGPSessionKey sessionKey) + { + return new BcSessionKeyDataDecryptorFactory(sessionKey); + } + + @Override + public PublicKeyDataDecryptorFactory publicKeyDataDecryptorFactory(PGPPrivateKey decryptionKey) + { + return new BcPublicKeyDataDecryptorFactory(decryptionKey); + } + + @Override + public PGPDigestCalculatorProvider pgpDigestCalculatorProvider() + throws PGPException + { + return new BcPGPDigestCalculatorProvider(); + } + + @Override + public PGPKeyPairGeneratorProvider pgpKeyPairGeneratorProvider() + { + return new BcPGPKeyPairGeneratorProvider(); + } + + @Override + public PGPContentSignerBuilderProvider pgpContentSignerBuilderProvider(int hashAlgorithmId) + { + return new BcPGPContentSignerBuilderProvider(hashAlgorithmId); + } + + @Override + public KeyFingerPrintCalculator keyFingerPrintCalculator() + { + return new BcKeyFingerprintCalculator(); + } + + @Override + public PBESecretKeyEncryptorFactory pbeSecretKeyEncryptorFactory(boolean aead) + { + return pbeSecretKeyEncryptorFactory(aead, SymmetricKeyAlgorithmTags.AES_128, 0x60); + } + + @Override + public PBESecretKeyEncryptorFactory pbeSecretKeyEncryptorFactory(boolean aead, int symmetricKeyAlgorithm, int iterationCount) + { + if (aead) + { + return new BcAEADSecretKeyEncryptorFactory(); + } + else + { + return new BcCFBSecretKeyEncryptorFactory(symmetricKeyAlgorithm, iterationCount); + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/bc/BcOpenPGPKeyGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/api/bc/BcOpenPGPKeyGenerator.java new file mode 100644 index 0000000000..218fb6c73d --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/bc/BcOpenPGPKeyGenerator.java @@ -0,0 +1,51 @@ +package org.bouncycastle.openpgp.api.bc; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.api.OpenPGPKeyGenerator; + +import java.util.Date; + +/** + * Bouncy Castle implementation of {@link OpenPGPKeyGenerator}. + */ +public class BcOpenPGPKeyGenerator + extends OpenPGPKeyGenerator +{ + + /** + * Create a new key generator for OpenPGP v6 keys. + * + * @param version key version + */ + public BcOpenPGPKeyGenerator(int version) + throws PGPException + { + this(version, new Date()); + } + + /** + * Create a new key generator for OpenPGP v6 keys. + * The key creation time will be set to {@code creationTime} + * + * @param version key version + * @param creationTime creation time of the generated OpenPGP key + */ + public BcOpenPGPKeyGenerator(int version, Date creationTime) + throws PGPException + { + this(version, creationTime, true); + } + + /** + * Create a new OpenPGP key generator for v6 keys. + * + * @param version key version + * @param creationTime creation time of the key and signatures + * @param aeadProtection whether the key shall be protected using AEAD. If false, the key is protected using CFB. + */ + public BcOpenPGPKeyGenerator(int version, Date creationTime, boolean aeadProtection) + throws PGPException + { + super(new BcOpenPGPImplementation(), version, aeadProtection, creationTime); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/bc/BcOpenPGPV6KeyGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/api/bc/BcOpenPGPV6KeyGenerator.java deleted file mode 100644 index 8953dc4ce9..0000000000 --- a/pg/src/main/java/org/bouncycastle/openpgp/api/bc/BcOpenPGPV6KeyGenerator.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.bouncycastle.openpgp.api.bc; - -import org.bouncycastle.openpgp.api.OpenPGPV6KeyGenerator; -import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptorFactory; -import org.bouncycastle.openpgp.operator.bc.BcAEADSecretKeyEncryptorFactory; -import org.bouncycastle.openpgp.operator.bc.BcCFBSecretKeyEncryptorFactory; -import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; -import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilderProvider; -import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; -import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPairGeneratorProvider; - -import java.util.Date; - -/** - * Bouncy Castle implementation of {@link OpenPGPV6KeyGenerator}. - */ -public class BcOpenPGPV6KeyGenerator - extends OpenPGPV6KeyGenerator -{ - - /** - * Create a new key generator for OpenPGP v6 keys. - */ - public BcOpenPGPV6KeyGenerator() - { - this(new Date()); - } - - /** - * Create a new key generator for OpenPGP v6 keys. - * The key creation time will be set to {@code creationTime} - * - * @param creationTime creation time of the generated OpenPGP key - */ - public BcOpenPGPV6KeyGenerator(Date creationTime) - { - this(DEFAULT_SIGNATURE_HASH_ALGORITHM, creationTime, true); - } - - /** - * Create a new key generator for OpenPGP v6 keys. - * Signatures on the key will be generated using the specified {@code signatureHashAlgorithm}. - * - * @param signatureHashAlgorithm ID of the hash algorithm to be used for signature generation - */ - public BcOpenPGPV6KeyGenerator(int signatureHashAlgorithm) - { - this(signatureHashAlgorithm, new Date(), true); - } - - /** - * Create a new OpenPGP key generator for v6 keys. - * - * @param signatureHashAlgorithm ID of the hash algorithm used for signatures on the key - * @param creationTime creation time of the key and signatures - */ - public BcOpenPGPV6KeyGenerator(int signatureHashAlgorithm, Date creationTime, boolean aeadProtection) - { - super( - new BcPGPKeyPairGeneratorProvider(), - new BcPGPContentSignerBuilderProvider(signatureHashAlgorithm), - new BcPGPDigestCalculatorProvider(), - keyEncryptorFactory(aeadProtection), - new BcKeyFingerprintCalculator(), - creationTime); - } - - private static PBESecretKeyEncryptorFactory keyEncryptorFactory(boolean aeadProtection) - { - if (aeadProtection) - { - return new BcAEADSecretKeyEncryptorFactory(); - } - else - { - return new BcCFBSecretKeyEncryptorFactory(); - } - } -} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/exception/IncorrectOpenPGPSignatureException.java b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/IncorrectOpenPGPSignatureException.java new file mode 100644 index 0000000000..44d5c34aa4 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/IncorrectOpenPGPSignatureException.java @@ -0,0 +1,15 @@ +package org.bouncycastle.openpgp.api.exception; + +import org.bouncycastle.openpgp.api.OpenPGPSignature; + +/** + * An OpenPGP signature is not correct. + */ +public class IncorrectOpenPGPSignatureException + extends OpenPGPSignatureException +{ + public IncorrectOpenPGPSignatureException(OpenPGPSignature signature, String message) + { + super(signature, message); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/exception/InvalidEncryptionKeyException.java b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/InvalidEncryptionKeyException.java new file mode 100644 index 0000000000..9e3f04b488 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/InvalidEncryptionKeyException.java @@ -0,0 +1,37 @@ +package org.bouncycastle.openpgp.api.exception; + +import org.bouncycastle.openpgp.api.OpenPGPCertificate; +import org.bouncycastle.util.Arrays; + +/** + * Exception that gets thrown if the user tries to encrypt a message for an + * {@link org.bouncycastle.openpgp.api.OpenPGPCertificate} that does not contain any usable, valid encryption keys. + */ +public class InvalidEncryptionKeyException + extends OpenPGPKeyException +{ + + public InvalidEncryptionKeyException(OpenPGPCertificate certificate) + { + super(certificate, "Certificate " + certificate.getKeyIdentifier() + + " does not contain any usable subkeys capable of encryption."); + } + + public InvalidEncryptionKeyException(OpenPGPCertificate.OpenPGPComponentKey encryptionSubkey) + { + super(encryptionSubkey, componentKeyErrorMessage(encryptionSubkey)); + } + + private static String componentKeyErrorMessage(OpenPGPCertificate.OpenPGPComponentKey componentKey) + { + if (componentKey.getKeyIdentifier().equals(componentKey.getCertificate().getKeyIdentifier())) + { + return "The primary key " + componentKey.getKeyIdentifier() + " is not usable for encryption."; + } + else + { + return "The subkey " + componentKey.getKeyIdentifier() + " from the certificate " + + componentKey.getCertificate().getKeyIdentifier() + " is not usable for encryption."; + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/exception/InvalidSigningKeyException.java b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/InvalidSigningKeyException.java new file mode 100644 index 0000000000..fccdefecb9 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/InvalidSigningKeyException.java @@ -0,0 +1,33 @@ +package org.bouncycastle.openpgp.api.exception; + +import org.bouncycastle.openpgp.api.OpenPGPCertificate; +import org.bouncycastle.openpgp.api.OpenPGPKey; + +public class InvalidSigningKeyException + extends OpenPGPKeyException +{ + + public InvalidSigningKeyException(OpenPGPKey key) + { + super(key, "The key " + key.getKeyIdentifier() + + " does not contain any usable component keys capable of signing."); + } + + public InvalidSigningKeyException(OpenPGPCertificate.OpenPGPComponentKey componentKey) + { + super(componentKey, componentKeyErrorMessage(componentKey)); + } + + private static String componentKeyErrorMessage(OpenPGPCertificate.OpenPGPComponentKey componentKey) + { + if (componentKey.getKeyIdentifier().equals(componentKey.getCertificate().getKeyIdentifier())) + { + return "The primary key " + componentKey.getKeyIdentifier() + " is not usable for signing."; + } + else + { + return "The subkey " + componentKey.getKeyIdentifier() + " from the certificate " + + componentKey.getCertificate().getKeyIdentifier() + " is not usable for signing."; + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/exception/KeyPassphraseException.java b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/KeyPassphraseException.java new file mode 100644 index 0000000000..7a51216fdf --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/KeyPassphraseException.java @@ -0,0 +1,34 @@ +package org.bouncycastle.openpgp.api.exception; + + +import org.bouncycastle.openpgp.api.OpenPGPCertificate; + +public class KeyPassphraseException + extends OpenPGPKeyException +{ + private final Exception cause; + + public KeyPassphraseException(OpenPGPCertificate.OpenPGPComponentKey key, Exception cause) + { + super(key, componentKeyErrorMessage(key, cause)); + this.cause = cause; + } + + private static String componentKeyErrorMessage(OpenPGPCertificate.OpenPGPComponentKey key, Exception cause) + { + if (key.getKeyIdentifier().equals(key.getCertificate().getKeyIdentifier())) + { + return "Cannot unlock primary key " + key.getKeyIdentifier() + ": " + cause.getMessage(); + } + else + { + return "Cannot unlock subkey " + key.getKeyIdentifier() + " from key " + + key.getCertificate().getKeyIdentifier() + ": " + cause.getMessage(); + } + } + + public Exception getCause() + { + return cause; + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/exception/MalformedOpenPGPSignatureException.java b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/MalformedOpenPGPSignatureException.java new file mode 100644 index 0000000000..06d941a7cf --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/MalformedOpenPGPSignatureException.java @@ -0,0 +1,16 @@ +package org.bouncycastle.openpgp.api.exception; + +import org.bouncycastle.openpgp.api.OpenPGPSignature; + +/** + * An OpenPGP Signature is malformed (missing required subpackets, etc.). + */ +public class MalformedOpenPGPSignatureException + extends OpenPGPSignatureException +{ + + public MalformedOpenPGPSignatureException(OpenPGPSignature signature, String message) + { + super(signature, message); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/exception/MissingIssuerCertException.java b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/MissingIssuerCertException.java new file mode 100644 index 0000000000..4a37432966 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/MissingIssuerCertException.java @@ -0,0 +1,15 @@ +package org.bouncycastle.openpgp.api.exception; + +import org.bouncycastle.openpgp.api.OpenPGPSignature; + +/** + * The OpenPGP certificate (public key) required to verify a signature is not available. + */ +public class MissingIssuerCertException + extends OpenPGPSignatureException +{ + public MissingIssuerCertException(OpenPGPSignature signature, String message) + { + super(signature, message); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/exception/OpenPGPKeyException.java b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/OpenPGPKeyException.java new file mode 100644 index 0000000000..04e5787ea5 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/OpenPGPKeyException.java @@ -0,0 +1,68 @@ +package org.bouncycastle.openpgp.api.exception; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.api.OpenPGPCertificate; + +/** + * Exception representing an unusable or invalid {@link org.bouncycastle.openpgp.api.OpenPGPKey} + * or {@link OpenPGPCertificate}. + * Note: The term "key" is used to refer to both a certificate and a key. + */ +public class OpenPGPKeyException + extends PGPException +{ + private final OpenPGPCertificate key; + private final OpenPGPCertificate.OpenPGPComponentKey componentKey; + + private OpenPGPKeyException(OpenPGPCertificate key, + OpenPGPCertificate.OpenPGPComponentKey componentKey, + String message) + { + super(message); + this.key = key; + this.componentKey = componentKey; + } + + /** + * Something is wrong with a key or certificate in general (no particular subkey). + * + * @param key certificate or key + * @param message message + */ + public OpenPGPKeyException(OpenPGPCertificate key, String message) + { + this(key, null, message); + } + + /** + * Something is wrong with an individual component key of a key or certificate. + * + * @param componentKey component key + * @param message message + */ + public OpenPGPKeyException(OpenPGPCertificate.OpenPGPComponentKey componentKey, String message) + { + this(componentKey.getCertificate(), componentKey, message); + } + + /** + * Return the problematic key or certificate. + * + * @return key or certificate + */ + public OpenPGPCertificate getKey() + { + return key; + } + + /** + * Return the problematic component key. + * Might be null, if the problem affects the entire key or certificate. + * + * @return component key + */ + public OpenPGPCertificate.OpenPGPComponentKey getComponentKey() + { + return componentKey; + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/exception/OpenPGPSignatureException.java b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/OpenPGPSignatureException.java new file mode 100644 index 0000000000..16df89d966 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/exception/OpenPGPSignatureException.java @@ -0,0 +1,21 @@ +package org.bouncycastle.openpgp.api.exception; + +import org.bouncycastle.openpgp.PGPSignatureException; +import org.bouncycastle.openpgp.api.OpenPGPSignature; + +public class OpenPGPSignatureException + extends PGPSignatureException +{ + private final OpenPGPSignature signature; + + public OpenPGPSignatureException(OpenPGPSignature signature, String message) + { + super(message); + this.signature = signature; + } + + public OpenPGPSignature getSignature() + { + return signature; + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/jcajce/JcaOpenPGPApi.java b/pg/src/main/java/org/bouncycastle/openpgp/api/jcajce/JcaOpenPGPApi.java new file mode 100644 index 0000000000..771208cdab --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/jcajce/JcaOpenPGPApi.java @@ -0,0 +1,63 @@ +package org.bouncycastle.openpgp.api.jcajce; + +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.api.OpenPGPApi; +import org.bouncycastle.openpgp.api.OpenPGPPolicy; +import org.bouncycastle.openpgp.api.OpenPGPKeyGenerator; + +import java.security.Provider; +import java.security.SecureRandom; +import java.util.Date; + +/** + * Implementation of {@link OpenPGPApi} using the JCA/JCE implementation of OpenPGP classes. + */ +public class JcaOpenPGPApi + extends OpenPGPApi +{ + private final Provider provider; + + public JcaOpenPGPApi(Provider provider) + { + this(provider, CryptoServicesRegistrar.getSecureRandom()); + } + + public JcaOpenPGPApi(Provider provider, SecureRandom random) + { + super(new JcaOpenPGPImplementation(provider, random)); + this.provider = provider; + } + + public JcaOpenPGPApi(Provider provider, OpenPGPPolicy policy) + { + this(provider, CryptoServicesRegistrar.getSecureRandom(), policy); + } + + public JcaOpenPGPApi(Provider provider, SecureRandom random, OpenPGPPolicy policy) + { + super(new JcaOpenPGPImplementation(provider, random), policy); + this.provider = provider; + } + + @Override + public OpenPGPKeyGenerator generateKey(int version) + throws PGPException + { + return new JcaOpenPGPKeyGenerator(version, provider); + } + + @Override + public OpenPGPKeyGenerator generateKey(int version, Date creationTime) + throws PGPException + { + return new JcaOpenPGPKeyGenerator(version, creationTime, provider); + } + + @Override + public OpenPGPKeyGenerator generateKey(int version, Date creationTime, boolean aeadProtection) + throws PGPException + { + return new JcaOpenPGPKeyGenerator(version, creationTime, aeadProtection, provider); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/jcajce/JcaOpenPGPImplementation.java b/pg/src/main/java/org/bouncycastle/openpgp/api/jcajce/JcaOpenPGPImplementation.java new file mode 100644 index 0000000000..08425937ef --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/jcajce/JcaOpenPGPImplementation.java @@ -0,0 +1,229 @@ +package org.bouncycastle.openpgp.api.jcajce; + +import java.io.InputStream; +import java.security.Provider; +import java.security.SecureRandom; + +import org.bouncycastle.bcpg.S2K; +import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPObjectFactory; +import org.bouncycastle.openpgp.PGPPrivateKey; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPSessionKey; +import org.bouncycastle.openpgp.api.OpenPGPImplementation; +import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory; +import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; +import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory; +import org.bouncycastle.openpgp.operator.PBEKeyEncryptionMethodGenerator; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilderProvider; +import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptorFactory; +import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; +import org.bouncycastle.openpgp.operator.PGPContentSignerBuilderProvider; +import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider; +import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder; +import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; +import org.bouncycastle.openpgp.operator.PGPKeyPairGeneratorProvider; +import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; +import org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator; +import org.bouncycastle.openpgp.operator.SessionKeyDataDecryptorFactory; +import org.bouncycastle.openpgp.operator.jcajce.JcaAEADSecretKeyEncryptorFactory; +import org.bouncycastle.openpgp.operator.jcajce.JcaCFBSecretKeyEncryptorFactory; +import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilderProvider; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPairGeneratorProvider; +import org.bouncycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder; +import org.bouncycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator; +import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilderProvider; +import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder; +import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder; +import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; +import org.bouncycastle.openpgp.operator.jcajce.JceSessionKeyDataDecryptorFactoryBuilder; + +/** + * Implementation of {@link OpenPGPImplementation} using the JCA/JCE implementation of OpenPGP classes. + */ +public class JcaOpenPGPImplementation + extends OpenPGPImplementation +{ + private final Provider provider; + private final SecureRandom secureRandom; + + public JcaOpenPGPImplementation() + { + this(new BouncyCastleProvider(), CryptoServicesRegistrar.getSecureRandom()); + } + + public JcaOpenPGPImplementation(Provider provider, SecureRandom secureRandom) + { + this.provider = provider; + this.secureRandom = secureRandom; + } + + @Override + public PGPObjectFactory pgpObjectFactory(InputStream packetInputStream) + { + return new JcaPGPObjectFactory(packetInputStream) + .setThrowForUnknownCriticalPackets(true); + } + + @Override + public PGPContentVerifierBuilderProvider pgpContentVerifierBuilderProvider() + { + JcaPGPContentVerifierBuilderProvider p = new JcaPGPContentVerifierBuilderProvider(); + p.setProvider(provider); + return p; + } + + @Override + public PBESecretKeyDecryptorBuilderProvider pbeSecretKeyDecryptorBuilderProvider() + { + JcaPGPDigestCalculatorProviderBuilder dp = new JcaPGPDigestCalculatorProviderBuilder(); + dp.setProvider(provider); + JcePBESecretKeyDecryptorBuilderProvider p = new JcePBESecretKeyDecryptorBuilderProvider(dp) + .setProvider(provider); + return p; + } + + @Override + public PGPDataEncryptorBuilder pgpDataEncryptorBuilder(int symmetricKeyAlgorithm) + { + JcePGPDataEncryptorBuilder b = new JcePGPDataEncryptorBuilder(symmetricKeyAlgorithm); + b.setProvider(provider); + b.setSecureRandom(secureRandom); + return b; + } + + @Override + public PublicKeyKeyEncryptionMethodGenerator publicKeyKeyEncryptionMethodGenerator(PGPPublicKey encryptionSubkey) + { + JcePublicKeyKeyEncryptionMethodGenerator g = new JcePublicKeyKeyEncryptionMethodGenerator(encryptionSubkey); + g.setProvider(provider); + g.setSecureRandom(secureRandom); + return g; + } + + @Override + public PBEKeyEncryptionMethodGenerator pbeKeyEncryptionMethodGenerator(char[] messagePassphrase) + { + JcePBEKeyEncryptionMethodGenerator g = new JcePBEKeyEncryptionMethodGenerator(messagePassphrase); + g.setProvider(provider); + g.setSecureRandom(secureRandom); + return g; + } + + @Override + public PBEKeyEncryptionMethodGenerator pbeKeyEncryptionMethodGenerator(char[] messagePassphrase, S2K.Argon2Params argon2Params) + { + JcePBEKeyEncryptionMethodGenerator g = new JcePBEKeyEncryptionMethodGenerator(messagePassphrase, argon2Params); + g.setProvider(provider); + g.setSecureRandom(secureRandom); + return g; + } + + @Override + public PGPContentSignerBuilder pgpContentSignerBuilder(int publicKeyAlgorithm, int hashAlgorithm) + { + JcaPGPContentSignerBuilder b = new JcaPGPContentSignerBuilder(publicKeyAlgorithm, hashAlgorithm); + b.setProvider(provider); + b.setDigestProvider(provider); + b.setSecureRandom(secureRandom); + return b; + } + + @Override + public PBEDataDecryptorFactory pbeDataDecryptorFactory(char[] messagePassphrase) + throws PGPException + { + return new JcePBEDataDecryptorFactoryBuilder(pgpDigestCalculatorProvider()) + .setProvider(provider) + .build(messagePassphrase); + } + + @Override + public SessionKeyDataDecryptorFactory sessionKeyDataDecryptorFactory(PGPSessionKey sessionKey) + { + return new JceSessionKeyDataDecryptorFactoryBuilder() + .setProvider(provider) + .build(sessionKey); + } + + @Override + public PublicKeyDataDecryptorFactory publicKeyDataDecryptorFactory(PGPPrivateKey decryptionKey) + { + return new JcePublicKeyDataDecryptorFactoryBuilder() + .setProvider(provider) + .setContentProvider(provider) + .build(decryptionKey); + } + + @Override + public PGPDigestCalculatorProvider pgpDigestCalculatorProvider() + throws PGPException + { + return new JcaPGPDigestCalculatorProviderBuilder() + .setProvider(provider) + .build(); + } + + @Override + public PGPKeyPairGeneratorProvider pgpKeyPairGeneratorProvider() + { + return new JcaPGPKeyPairGeneratorProvider() + .setProvider(provider) + .setSecureRandom(secureRandom); + } + + @Override + public PGPContentSignerBuilderProvider pgpContentSignerBuilderProvider(int hashAlgorithmId) + { + return new JcaPGPContentSignerBuilderProvider(hashAlgorithmId) + .setSecurityProvider(provider) + .setDigestProvider(provider) + .setSecureRandom(secureRandom); + } + + @Override + public KeyFingerPrintCalculator keyFingerPrintCalculator() + { + return new JcaKeyFingerprintCalculator() + .setProvider(provider); + } + + @Override + public PBESecretKeyEncryptorFactory pbeSecretKeyEncryptorFactory(boolean aead) + throws PGPException + { + if (aead) + { + return new JcaAEADSecretKeyEncryptorFactory() + .setProvider(provider); + } + else + { + return new JcaCFBSecretKeyEncryptorFactory(SymmetricKeyAlgorithmTags.AES_128, 0x60) + .setProvider(provider); + } + } + + @Override + public PBESecretKeyEncryptorFactory pbeSecretKeyEncryptorFactory(boolean aead, int symmetricKeyAlgorithm, int iterationCount) + throws PGPException + { + if (aead) + { + return new JcaAEADSecretKeyEncryptorFactory() + .setProvider(provider); + } + else + { + return new JcaCFBSecretKeyEncryptorFactory(symmetricKeyAlgorithm, iterationCount) + .setProvider(provider); + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/jcajce/JcaOpenPGPKeyGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/api/jcajce/JcaOpenPGPKeyGenerator.java new file mode 100644 index 0000000000..c0401336f7 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/jcajce/JcaOpenPGPKeyGenerator.java @@ -0,0 +1,43 @@ +package org.bouncycastle.openpgp.api.jcajce; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.api.OpenPGPKeyGenerator; + +import java.security.Provider; +import java.security.SecureRandom; +import java.util.Date; + +/** + * JCA/JCE implementation of the {@link OpenPGPKeyGenerator}. + */ +public class JcaOpenPGPKeyGenerator + extends OpenPGPKeyGenerator +{ + + public JcaOpenPGPKeyGenerator(int version, Provider provider) + throws PGPException + { + this(version, new Date(), provider); + } + + public JcaOpenPGPKeyGenerator(int version, Date creationTime, Provider provider) + throws PGPException + { + this(version, creationTime, true, provider); + } + + /** + * Create a new OpenPGP key generator for v6 keys. + * + * @param creationTime creation time of the key and signatures + */ + public JcaOpenPGPKeyGenerator(int version, Date creationTime, boolean aeadProtection, Provider provider) + throws PGPException + { + super( + new JcaOpenPGPImplementation(provider, new SecureRandom()), + version, + aeadProtection, + creationTime); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/jcajce/JcaOpenPGPV6KeyGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/api/jcajce/JcaOpenPGPV6KeyGenerator.java deleted file mode 100644 index d0890f321e..0000000000 --- a/pg/src/main/java/org/bouncycastle/openpgp/api/jcajce/JcaOpenPGPV6KeyGenerator.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.bouncycastle.openpgp.api.jcajce; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.api.OpenPGPV6KeyGenerator; -import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptorFactory; -import org.bouncycastle.openpgp.operator.jcajce.JcaAEADSecretKeyEncryptorFactory; -import org.bouncycastle.openpgp.operator.jcajce.JcaCFBSecretKeyEncryptorFactory; -import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; -import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilderProvider; -import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; -import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPairGeneratorProvider; - -import java.security.Provider; -import java.util.Date; - -public class JcaOpenPGPV6KeyGenerator - extends OpenPGPV6KeyGenerator -{ - - public JcaOpenPGPV6KeyGenerator(Provider provider) - throws PGPException - { - this(new Date(), provider); - } - - public JcaOpenPGPV6KeyGenerator(Date creationTime, Provider provider) - throws PGPException - { - this(DEFAULT_SIGNATURE_HASH_ALGORITHM, creationTime, true, provider); - } - - public JcaOpenPGPV6KeyGenerator(int signatureHashAlgorithm, Provider provider) - throws PGPException - { - this(signatureHashAlgorithm, new Date(), true, provider); - } - - /** - * Create a new OpenPGP key generator for v6 keys. - * - * @param signatureHashAlgorithm ID of the hash algorithm used for signatures on the key - * @param creationTime creation time of the key and signatures - */ - public JcaOpenPGPV6KeyGenerator(int signatureHashAlgorithm, Date creationTime, boolean aeadProtection, Provider provider) - throws PGPException - { - super( - new JcaPGPKeyPairGeneratorProvider() - .setProvider(provider), - new JcaPGPContentSignerBuilderProvider(signatureHashAlgorithm) - .setSecurityProvider(provider), - new JcaPGPDigestCalculatorProviderBuilder() - .setProvider(provider) - .build(), - keyEncryptorFactory(provider, aeadProtection), - new JcaKeyFingerprintCalculator(), - creationTime); - } - - private static PBESecretKeyEncryptorFactory keyEncryptorFactory(Provider provider, boolean aeadProtection) - throws PGPException - { - if (aeadProtection) - { - return new JcaAEADSecretKeyEncryptorFactory().setProvider(provider); - } - else - { - return new JcaCFBSecretKeyEncryptorFactory().setProvider(provider); - - } - } -} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/package-info.java b/pg/src/main/java/org/bouncycastle/openpgp/api/package-info.java new file mode 100644 index 0000000000..099545ae27 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/package-info.java @@ -0,0 +1,23 @@ +/** + * The
    api
    package contains a high-level OpenPGP API layer on top of the + *
    openpgp
    mid-level API. + * It is tailored to provide a modern OpenPGP experience, following the guidance from rfc9580 ("OpenPGP v6"), + * while also being interoperable with rfc4880 ("OpenPGP v4"). + *

    + * From an architectural point of view, the hierarchy of the individual layers is as follows: + *

      + *
    • + *
      api
      specifies a high-level API using mid-level implementations from
      openpgp
      . + * This layer strives to be easy to use, hard to misuse and secure by default. + *
    • + *
    • + *
      openpgp
      defines a powerful, flexible, but quite verbose API using packet definitions + * from
      bcpg
      . + *
    • + *
    • + *
      bcpg
      implements serialization / deserialization of OpenPGP packets. + * It does not contain any business logic. + *
    • + *
    + */ +package org.bouncycastle.openpgp.api; \ No newline at end of file diff --git a/pg/src/main/java/org/bouncycastle/openpgp/api/util/UTCUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/api/util/UTCUtil.java new file mode 100644 index 0000000000..78ce9a5f7d --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/api/util/UTCUtil.java @@ -0,0 +1,51 @@ +package org.bouncycastle.openpgp.api.util; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +/** + * Utility class for parsing and formatting UTC timestamps. + */ +public class UTCUtil +{ + private static SimpleDateFormat utc() + { + // Java's SimpleDateFormat is not thread-safe, therefore we return a new instance on every invocation. + // See https://stackoverflow.com/a/6840856/11150851 + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); + format.setTimeZone(TimeZone.getTimeZone("UTC")); + return format; + } + + /** + * Format a {@link Date} as UTC timestamp. + * + * @param timestamp date + * @return formatted timestamp + */ + public static String format(Date timestamp) + { + return utc().format(timestamp); + } + + /** + * Parse a UTC timestamp. + * The timestamp needs to be provided in the form 'yyyy-MM-dd HH:mm:ss z'. + * + * @param utcTimestamp timestamp + * @return date + */ + public static Date parse(String utcTimestamp) + { + try + { + return utc().parse(utcTimestamp); + } + catch (ParseException e) + { + throw new IllegalArgumentException("Malformed UTC timestamp: " + utcTimestamp, e); + } + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/GnuDivertToCardSecretKeyEncryptor.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/GnuDivertToCardSecretKeyEncryptor.java new file mode 100644 index 0000000000..e3485a19d8 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/GnuDivertToCardSecretKeyEncryptor.java @@ -0,0 +1,54 @@ +package org.bouncycastle.openpgp.operator; + +import org.bouncycastle.bcpg.GnuExtendedS2K; +import org.bouncycastle.bcpg.S2K; +import org.bouncycastle.openpgp.PGPException; + +/** + * Secret key encryptor that allows to represent a secret key embedded + * on a smartcard, using GNU S2K extensions. + *

    + * This extension is documented on GnuPG documentation DETAILS file, + * section "GNU extensions to the S2K algorithm". + */ +public class GnuDivertToCardSecretKeyEncryptor + extends PBESecretKeyEncryptor +{ + private byte[] serial; + + public GnuDivertToCardSecretKeyEncryptor(PGPDigestCalculator s2kDigestCalculator, byte[] serial) + { + super(0, s2kDigestCalculator, 0, null, null); + this.s2k = new GnuExtendedS2K(S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD); + this.serial = new byte[serial.length + 1]; + this.serial[0] = (byte)serial.length; + System.arraycopy(serial, 0, this.serial, 1, serial.length); + } + + @Override + public byte[] encryptKeyData(byte[] key, byte[] keyData, int keyOff, + int keyLen) + throws PGPException + { + if (serial != null && serial.length > 16) + { + byte[] result = new byte[17]; + System.arraycopy(serial, 0, result, 0, result.length); + return result; + } + return serial; + } + + @Override + public byte[] getKey() + throws PGPException + { + return null; + } + + @Override + public byte[] getCipherIV() + { + return new byte[0]; + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyDecryptorBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyDecryptorBuilder.java new file mode 100644 index 0000000000..b19389b50e --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyDecryptorBuilder.java @@ -0,0 +1,9 @@ +package org.bouncycastle.openpgp.operator; + +import org.bouncycastle.openpgp.PGPException; + +public interface PBESecretKeyDecryptorBuilder +{ + PBESecretKeyDecryptor build(char[] passphrase) + throws PGPException; +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyDecryptorBuilderProvider.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyDecryptorBuilderProvider.java new file mode 100644 index 0000000000..e94ddb551b --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PBESecretKeyDecryptorBuilderProvider.java @@ -0,0 +1,15 @@ +package org.bouncycastle.openpgp.operator; + +import org.bouncycastle.openpgp.PGPException; + +/** + * Provider for {@link PBESecretKeyDecryptorBuilder} instances. + * The purpose of this class is to act as an abstract factory, whose subclasses can decide, which concrete + * implementation of {@link PBESecretKeyDecryptorBuilder} (builder for objects that can unlock encrypted + * secret keys) to return. + */ +public interface PBESecretKeyDecryptorBuilderProvider +{ + PBESecretKeyDecryptorBuilder provide() + throws PGPException; +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyPairGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyPairGenerator.java index a4c5c4953e..2dc54f5c42 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyPairGenerator.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyPairGenerator.java @@ -1,5 +1,7 @@ package org.bouncycastle.openpgp.operator; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.sec.SECObjectIdentifiers; import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPKeyPair; @@ -178,4 +180,114 @@ public abstract PGPKeyPair generateLegacyEd25519KeyPair() */ public abstract PGPKeyPair generateLegacyX25519KeyPair() throws PGPException; + + /** + * Generate an ECDH elliptic curve encryption key over the NIST p-256 curve. + * + * @return NIST p-256 ECDSA encryption key pair + * @throws PGPException if the key pair cannot be generated + * + * @see + * RFC6637 - Elliptic Curve Cryptography in OpenPGP + */ + public PGPKeyPair generateNistP256ECDHKeyPair() + throws PGPException + { + return generateECDHKeyPair(SECObjectIdentifiers.secp256r1); + } + + /** + * Generate an ECDH elliptic curve encryption key over the NIST p-384 curve. + * + * @return NIST p-384 ECDSA encryption key pair + * @throws PGPException if the key pair cannot be generated + * + * @see + * RFC6637 - Elliptic Curve Cryptography in OpenPGP + */ + public PGPKeyPair generateNistP384ECDHKeyPair() + throws PGPException + { + return generateECDHKeyPair(SECObjectIdentifiers.secp384r1); + } + + /** + * Generate an ECDH elliptic curve encryption key over the NIST p-521 curve. + * + * @return NIST p-521 ECDSA encryption key pair + * @throws PGPException if the key pair cannot be generated + * + * @see + * RFC6637 - Elliptic Curve Cryptography in OpenPGP + */ + public PGPKeyPair generateNistP521ECDHKeyPair() + throws PGPException + { + return generateECDHKeyPair(SECObjectIdentifiers.secp521r1); + } + + /** + * Generate an ECDSA elliptic curve signing key over the NIST p-256 curve. + * + * @return NIST p-256 ECDSA signing key pair + * @throws PGPException if the key pair cannot be generated + * + * @see + * RFC6637 - Elliptic Curve Cryptography in OpenPGP + */ + public PGPKeyPair generateNistP256ECDSAKeyPair() + throws PGPException + { + return generateECDSAKeyPair(SECObjectIdentifiers.secp256r1); + } + + /** + * Generate an ECDSA elliptic curve signing key over the NIST p-384 curve. + * + * @return NIST p-384 ECDSA signing key pair + * @throws PGPException if the key pair cannot be generated + * + * @see + * RFC6637 - Elliptic Curve Cryptography in OpenPGP + */ + public PGPKeyPair generateNistP384ECDSAKeyPair() + throws PGPException + { + return generateECDSAKeyPair(SECObjectIdentifiers.secp384r1); + } + + /** + * Generate an ECDSA elliptic curve signing key over the NIST p-521 curve. + * + * @return NIST p-521 ECDSA signing key pair + * @throws PGPException if the key pair cannot be generated + * + * @see + * RFC6637 - Elliptic Curve Cryptography in OpenPGP + */ + public PGPKeyPair generateNistP521ECDSAKeyPair() + throws PGPException + { + return generateECDSAKeyPair(SECObjectIdentifiers.secp521r1); + } + + /** + * Generate an elliptic curve Diffie-Hellman encryption key pair over the curve identified by the given OID. + * + * @param curveOID OID of the elliptic curve + * @return PGP key pair + * @throws PGPException if the key pair cannot be generated + */ + public abstract PGPKeyPair generateECDHKeyPair(ASN1ObjectIdentifier curveOID) + throws PGPException; + + /** + * Generate an elliptic curve signing key over the curve identified by the given OID. + * + * @param curveOID OID of the elliptic curve + * @return PGP key pair + * @throws PGPException if the key pair cannot be generated + */ + public abstract PGPKeyPair generateECDSAKeyPair(ASN1ObjectIdentifier curveOID) + throws PGPException; } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPUtil.java index 2d77e5d9a1..b651960b19 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPUtil.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPUtil.java @@ -63,8 +63,7 @@ static byte[] makeKeyFromPassPhrase( { if (s2k.getType() == S2K.ARGON_2) { - Argon2Parameters.Builder builder = new Argon2Parameters - .Builder(Argon2Parameters.ARGON2_id) + Argon2Parameters.Builder builder = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id) .withSalt(s2k.getIV()) .withIterations(s2k.getPasses()) .withParallelism(s2k.getParallelism()) @@ -97,13 +96,13 @@ else if (s2k.getHashAlgorithm() != digestCalculator.getAlgorithm()) byte[] iv = s2k != null? s2k.getIV() : null; while (generatedBytes < keyBytes.length) { - if (s2k != null) + for (int i = 0; i != loopCount; i++) { - for (int i = 0; i != loopCount; i++) - { - dOut.write(0); - } + dOut.write(0); + } + if (s2k != null) + { switch (s2k.getType()) { case S2K.SIMPLE: @@ -151,28 +150,15 @@ else if (s2k.getHashAlgorithm() != digestCalculator.getAlgorithm()) } else { - for (int i = 0; i != loopCount; i++) - { - dOut.write((byte)0); - } - dOut.write(pBytes); } dOut.close(); byte[] dig = digestCalculator.getDigest(); - - if (dig.length > (keyBytes.length - generatedBytes)) - { - System.arraycopy(dig, 0, keyBytes, generatedBytes, keyBytes.length - generatedBytes); - } - else - { - System.arraycopy(dig, 0, keyBytes, generatedBytes, dig.length); - } - - generatedBytes += dig.length; + int toCopy = Math.min(dig.length, keyBytes.length - generatedBytes); + System.arraycopy(dig, 0, keyBytes, generatedBytes, toCopy); + generatedBytes += toCopy; loopCount++; } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java index 4893e7fe36..8f8c0630ac 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java @@ -1,5 +1,8 @@ package org.bouncycastle.openpgp.operator; +import java.io.IOException; +import java.math.BigInteger; + import org.bouncycastle.bcpg.ContainedPacket; import org.bouncycastle.bcpg.MPInteger; import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; @@ -8,9 +11,6 @@ import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.util.Properties; -import java.io.IOException; -import java.math.BigInteger; - /** * Abstract generator class for encryption methods that produce PKESK (public-key encrypted session key) packets. * PKESKs are used when encrypting a message for a recipients public key. @@ -21,7 +21,7 @@ public abstract class PublicKeyKeyEncryptionMethodGenerator { public static final String SESSION_KEY_OBFUSCATION_PROPERTY = "org.bouncycastle.openpgp.session_key_obfuscation"; public static final long WILDCARD_KEYID = 0L; - /** + /*@ * @deprecated use WILDCARD_KEYID */ public static final long WILDCARD = 0L; @@ -94,6 +94,7 @@ public PublicKeyKeyEncryptionMethodGenerator setSessionKeyObfuscation(boolean en * TODO: Remove in a future release */ @Deprecated + @SuppressWarnings("InlineMeSuggester") public PublicKeyKeyEncryptionMethodGenerator setUseWildcardKeyID(boolean enabled) { return setUseWildcardRecipient(enabled); diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcCFBSecretKeyEncryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcCFBSecretKeyEncryptorFactory.java index 93bc4a3650..ccde1f85fa 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcCFBSecretKeyEncryptorFactory.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcCFBSecretKeyEncryptorFactory.java @@ -2,7 +2,6 @@ import org.bouncycastle.bcpg.HashAlgorithmTags; import org.bouncycastle.bcpg.PublicKeyPacket; -import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptorFactory; @@ -19,6 +18,16 @@ public class BcCFBSecretKeyEncryptorFactory implements PBESecretKeyEncryptorFactory { + private final int symmetricKeyAlgorithm; + private final int iterationCount; + + public BcCFBSecretKeyEncryptorFactory(int symmetricKeyAlgorithm, + int iterationCount) + { + this.symmetricKeyAlgorithm = symmetricKeyAlgorithm; + this.iterationCount = iterationCount; + } + @Override public PBESecretKeyEncryptor build(char[] passphrase, PublicKeyPacket pubKeyPacket) { @@ -38,9 +47,9 @@ public PBESecretKeyEncryptor build(char[] passphrase, PublicKeyPacket pubKeyPack } return new BcPBESecretKeyEncryptorBuilder( - SymmetricKeyAlgorithmTags.AES_256, + symmetricKeyAlgorithm, checksumCalc, - 0xff) // MAX iteration count + iterationCount) // MAX iteration count .build(passphrase); } } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcKeyFingerprintCalculator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcKeyFingerprintCalculator.java index 9a4c7e2c07..07c2bd42e6 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcKeyFingerprintCalculator.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcKeyFingerprintCalculator.java @@ -25,6 +25,10 @@ public byte[] calculateFingerprint(PublicKeyPacket publicPk) if (publicPk.getVersion() <= PublicKeyPacket.VERSION_3) { + if (!(key instanceof RSAPublicBCPGKey)) + { + throw new PGPException("Version 3 OpenPGP keys can only use RSA. Found " + key.getClass().getName()); + } RSAPublicBCPGKey rK = (RSAPublicBCPGKey)key; try diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilder.java index cd1d20b1c3..d95754c7df 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilder.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilder.java @@ -3,9 +3,11 @@ import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilder; import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; public class BcPBESecretKeyDecryptorBuilder + implements PBESecretKeyDecryptorBuilder { private PGPDigestCalculatorProvider calculatorProvider; diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilderProvider.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilderProvider.java new file mode 100644 index 0000000000..532ca3bced --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBESecretKeyDecryptorBuilderProvider.java @@ -0,0 +1,14 @@ +package org.bouncycastle.openpgp.operator.bc; + +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilder; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilderProvider; + +public class BcPBESecretKeyDecryptorBuilderProvider + implements PBESecretKeyDecryptorBuilderProvider +{ + @Override + public PBESecretKeyDecryptorBuilder provide() + { + return new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()); + } +} diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java index a64e782912..771e753213 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java @@ -94,6 +94,7 @@ public PGPPrivateKey getPGPPrivateKey(PGPPublicKey pubKey, AsymmetricKeyParamete * @deprecated use versioned {@link #getPGPPublicKey(int, int, PGPAlgorithmParameters, AsymmetricKeyParameter, Date)} instead */ @Deprecated + @SuppressWarnings("InlineMeSuggester") public PGPPublicKey getPGPPublicKey(int algorithm, PGPAlgorithmParameters algorithmParameters, AsymmetricKeyParameter pubKey, Date time) throws PGPException { diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyPair.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyPair.java index f1f23a6976..40d9d1e733 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyPair.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyPair.java @@ -14,13 +14,6 @@ public class BcPGPKeyPair extends PGPKeyPair { - @Deprecated - private static PGPPublicKey getPublicKey(int algorithm, PGPAlgorithmParameters parameters, AsymmetricKeyParameter pubKey, Date date) - throws PGPException - { - return getPublicKey(PublicKeyPacket.VERSION_4, algorithm, parameters, pubKey, date); - } - private static PGPPublicKey getPublicKey(int version, int algorithm, PGPAlgorithmParameters parameters, AsymmetricKeyParameter pubKey, Date date) throws PGPException { @@ -34,6 +27,7 @@ private static PGPPrivateKey getPrivateKey(PGPPublicKey pub, AsymmetricKeyParame } @Deprecated + @SuppressWarnings("InlineMeSuggester") public BcPGPKeyPair(int algorithm, AsymmetricCipherKeyPair keyPair, Date date) throws PGPException { @@ -48,6 +42,7 @@ public BcPGPKeyPair(int version, int algorithm, AsymmetricCipherKeyPair keyPair, } @Deprecated + @SuppressWarnings("InlineMeSuggester") public BcPGPKeyPair(int algorithm, PGPAlgorithmParameters parameters, AsymmetricCipherKeyPair keyPair, Date date) throws PGPException { diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyPairGeneratorProvider.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyPairGeneratorProvider.java index 42e1eef9af..45ab6a85e4 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyPairGeneratorProvider.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyPairGeneratorProvider.java @@ -1,14 +1,25 @@ package org.bouncycastle.openpgp.operator.bc; +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Date; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x9.ECNamedCurveTable; +import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; import org.bouncycastle.bcpg.PublicKeyPacket; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.crypto.ec.CustomNamedCurves; +import org.bouncycastle.crypto.generators.ECKeyPairGenerator; import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator; import org.bouncycastle.crypto.generators.Ed448KeyPairGenerator; import org.bouncycastle.crypto.generators.RSAKeyPairGenerator; import org.bouncycastle.crypto.generators.X25519KeyPairGenerator; import org.bouncycastle.crypto.generators.X448KeyPairGenerator; +import org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import org.bouncycastle.crypto.params.ECNamedDomainParameters; import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters; import org.bouncycastle.crypto.params.Ed448KeyGenerationParameters; import org.bouncycastle.crypto.params.RSAKeyGenerationParameters; @@ -19,12 +30,8 @@ import org.bouncycastle.openpgp.operator.PGPKeyPairGenerator; import org.bouncycastle.openpgp.operator.PGPKeyPairGeneratorProvider; -import java.math.BigInteger; -import java.security.SecureRandom; -import java.util.Date; - public class BcPGPKeyPairGeneratorProvider - extends PGPKeyPairGeneratorProvider + extends PGPKeyPairGeneratorProvider { private SecureRandom random = CryptoServicesRegistrar.getSecureRandom(); @@ -128,5 +135,44 @@ public PGPKeyPair generateLegacyX25519KeyPair() AsymmetricCipherKeyPair keyPair = gen.generateKeyPair(); return new BcPGPKeyPair(version, PublicKeyAlgorithmTags.ECDH, keyPair, creationTime); } + + @Override + public PGPKeyPair generateECDHKeyPair(ASN1ObjectIdentifier curveOID) + throws PGPException + { + ECKeyPairGenerator gen = new ECKeyPairGenerator(); + gen.init(new ECKeyGenerationParameters( + new ECNamedDomainParameters(curveOID, getNamedCurveByOid(curveOID)), + CryptoServicesRegistrar.getSecureRandom())); + + AsymmetricCipherKeyPair keyPair = gen.generateKeyPair(); + return new BcPGPKeyPair(version, PublicKeyAlgorithmTags.ECDH, keyPair, creationTime); + } + + @Override + public PGPKeyPair generateECDSAKeyPair(ASN1ObjectIdentifier curveOID) + throws PGPException + { + ECKeyPairGenerator gen = new ECKeyPairGenerator(); + gen.init(new ECKeyGenerationParameters( + new ECNamedDomainParameters(curveOID, getNamedCurveByOid(curveOID)), + CryptoServicesRegistrar.getSecureRandom())); + + AsymmetricCipherKeyPair keyPair = gen.generateKeyPair(); + return new BcPGPKeyPair(version, PublicKeyAlgorithmTags.ECDSA, keyPair, creationTime); + } + } + + private static X9ECParameters getNamedCurveByOid( + ASN1ObjectIdentifier oid) + { + X9ECParameters params = CustomNamedCurves.getByOID(oid); + + if (params == null) + { + params = ECNamedCurveTable.getByOID(oid); + } + + return params; } } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java index ffc262be30..a407e38710 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java @@ -1,7 +1,6 @@ package org.bouncycastle.openpgp.operator.bc; import java.io.IOException; -import java.math.BigInteger; import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers; import org.bouncycastle.asn1.edec.EdECObjectIdentifiers; @@ -18,6 +17,7 @@ import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.RawAgreement; import org.bouncycastle.crypto.Wrapper; +import org.bouncycastle.crypto.agreement.BasicRawAgreement; import org.bouncycastle.crypto.agreement.ECDHBasicAgreement; import org.bouncycastle.crypto.agreement.X25519Agreement; import org.bouncycastle.crypto.agreement.X448Agreement; @@ -37,7 +37,6 @@ import org.bouncycastle.openpgp.operator.PGPPad; import org.bouncycastle.openpgp.operator.RFC6637Utils; import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.BigIntegers; /** * A decryptor factory for handling public key decryption operations. @@ -210,15 +209,11 @@ else if (ecPubKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448)) } else { - ECDomainParameters ecParameters = ((ECPrivateKeyParameters) privKey).getParameters(); - + ECDomainParameters ecParameters = ((ECPrivateKeyParameters)privKey).getParameters(); ECPublicKeyParameters ephPub = new ECPublicKeyParameters(ecParameters.getCurve().decodePoint(pEnc), - ecParameters); + ecParameters); - ECDHBasicAgreement agreement = new ECDHBasicAgreement(); - agreement.init(privKey); - BigInteger S = agreement.calculateAgreement(ephPub); - secret = BigIntegers.asUnsignedByteArray(agreement.getFieldSize(), S); + secret = BcUtil.getSecret(new BasicRawAgreement(new ECDHBasicAgreement()), privKey, ephPub); } hashAlgorithm = ecPubKey.getHashAlgorithm(); symmetricKeyAlgorithm = ecPubKey.getSymmetricKeyAlgorithm(); diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java index a59d12dc76..ea70b108f1 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java @@ -17,6 +17,7 @@ import org.bouncycastle.crypto.KeyGenerationParameters; import org.bouncycastle.crypto.RawAgreement; import org.bouncycastle.crypto.Wrapper; +import org.bouncycastle.crypto.agreement.BasicRawAgreement; import org.bouncycastle.crypto.agreement.ECDHBasicAgreement; import org.bouncycastle.crypto.agreement.X25519Agreement; import org.bouncycastle.crypto.agreement.X448Agreement; @@ -38,7 +39,6 @@ import org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator; import org.bouncycastle.openpgp.operator.RFC6637Utils; import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.BigIntegers; /** * A method generator for supporting public key based encryption operations. @@ -122,10 +122,8 @@ else if (ecPubKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448)) AsymmetricCipherKeyPair ephKp = getAsymmetricCipherKeyPair(new ECKeyPairGenerator(), new ECKeyGenerationParameters(((ECPublicKeyParameters)cryptoPublicKey).getParameters(), random)); - ECDHBasicAgreement agreement = new ECDHBasicAgreement(); - agreement.init(ephKp.getPrivate()); - BigInteger S = agreement.calculateAgreement(cryptoPublicKey); - byte[] secret = BigIntegers.asUnsignedByteArray(agreement.getFieldSize(), S); + byte[] secret = BcUtil.getSecret(new BasicRawAgreement(new ECDHBasicAgreement()), + ephKp.getPrivate(), cryptoPublicKey); byte[] ephPubEncoding = ((ECPublicKeyParameters)ephKp.getPublic()).getQ().getEncoded(false); diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaCFBSecretKeyEncryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaCFBSecretKeyEncryptorFactory.java index b7fca675f2..c8a576b7fe 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaCFBSecretKeyEncryptorFactory.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaCFBSecretKeyEncryptorFactory.java @@ -12,13 +12,17 @@ public class JcaCFBSecretKeyEncryptorFactory implements PBESecretKeyEncryptorFactory { + private final int symmetricKeyAlgorithm; + private final int iterationCount; private JcaPGPDigestCalculatorProviderBuilder digestCalcProviderBuilder = new JcaPGPDigestCalculatorProviderBuilder(); private JcePBESecretKeyEncryptorBuilder encBuilder; - public JcaCFBSecretKeyEncryptorFactory() + public JcaCFBSecretKeyEncryptorFactory(int symmetricKeyAlgorithm, int iterationCount) throws PGPException { + this.symmetricKeyAlgorithm = symmetricKeyAlgorithm; + this.iterationCount = iterationCount; encBuilder = builder(); } @@ -34,9 +38,9 @@ private JcePBESecretKeyEncryptorBuilder builder() throws PGPException { return new JcePBESecretKeyEncryptorBuilder( - SymmetricKeyAlgorithmTags.AES_256, + symmetricKeyAlgorithm, digestCalcProviderBuilder.build().get(HashAlgorithmTags.SHA1), - 0x60 + iterationCount ); } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaKeyFingerprintCalculator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaKeyFingerprintCalculator.java index ba57198af1..4737059dad 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaKeyFingerprintCalculator.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaKeyFingerprintCalculator.java @@ -66,6 +66,10 @@ public byte[] calculateFingerprint(PublicKeyPacket publicPk) if (publicPk.getVersion() <= PublicKeyPacket.VERSION_3) { + if (!(key instanceof RSAPublicBCPGKey)) + { + throw new PGPException("Version 3 OpenPGP keys can only use RSA. Found " + key.getClass().getName()); + } RSAPublicBCPGKey rK = (RSAPublicBCPGKey)key; try diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java index 28cd4bb57f..32ce31e282 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java @@ -143,6 +143,7 @@ public PGPPrivateKey getPGPPrivateKey(PGPPublicKey pub, PrivateKey privKey) * @deprecated use versioned {@link #getPGPPublicKey(int, int, PGPAlgorithmParameters, PublicKey, Date)} instead. */ @Deprecated + @SuppressWarnings("InlineMeSuggester") public PGPPublicKey getPGPPublicKey(int algorithm, PGPAlgorithmParameters algorithmParameters, PublicKey pubKey, Date time) throws PGPException { diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyPair.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyPair.java index 86f8f8d75c..75f7fcc4cd 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyPair.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyPair.java @@ -18,25 +18,11 @@ public class JcaPGPKeyPair extends PGPKeyPair { - @Deprecated - private static PGPPublicKey getPublicKey(int algorithm, PublicKey pubKey, Date date) - throws PGPException - { - return getPublicKey(PublicKeyPacket.VERSION_4, algorithm, pubKey, date); - } - private static PGPPublicKey getPublicKey(int version, int algorithm, PublicKey pubKey, Date date) throws PGPException { return new JcaPGPKeyConverter().getPGPPublicKey(version, algorithm, pubKey, date); } - - @Deprecated - private static PGPPublicKey getPublicKey(int algorithm, PGPAlgorithmParameters algorithmParameters, PublicKey pubKey, Date date) - throws PGPException - { - return getPublicKey(PublicKeyPacket.VERSION_4, algorithm, algorithmParameters, pubKey, date); - } private static PGPPublicKey getPublicKey(int version, int algorithm, PGPAlgorithmParameters algorithmParameters, PublicKey pubKey, Date date) throws PGPException @@ -60,6 +46,7 @@ private static PGPPrivateKey getPrivateKey(PGPPublicKey pub, PrivateKey privKey) * @deprecated use versioned {@link #JcaPGPKeyPair(int, int, KeyPair, Date)} instead */ @Deprecated + @SuppressWarnings("InlineMeSuggester") public JcaPGPKeyPair(int algorithm, KeyPair keyPair, Date date) throws PGPException { @@ -93,6 +80,7 @@ public JcaPGPKeyPair(int version, int algorithm, KeyPair keyPair, Date date) * @deprecated use versioned {@link #JcaPGPKeyPair(int, int, PGPAlgorithmParameters, KeyPair, Date)} instead */ @Deprecated + @SuppressWarnings("InlineMeSuggester") public JcaPGPKeyPair(int algorithm, PGPAlgorithmParameters parameters, KeyPair keyPair, Date date) throws PGPException { diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyPairGeneratorProvider.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyPairGeneratorProvider.java index 329bf9f052..bb69846cc0 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyPairGeneratorProvider.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyPairGeneratorProvider.java @@ -1,13 +1,16 @@ package org.bouncycastle.openpgp.operator.jcajce; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; import org.bouncycastle.bcpg.PublicKeyPacket; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import org.bouncycastle.jcajce.spec.EdDSAParameterSpec; import org.bouncycastle.jcajce.spec.XDHParameterSpec; import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; import org.bouncycastle.jcajce.util.NamedJcaJceHelper; import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; +import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPKeyPair; import org.bouncycastle.openpgp.operator.PGPKeyPairGenerator; @@ -212,5 +215,41 @@ public PGPKeyPair generateLegacyX25519KeyPair() throw new PGPException("Cannot generate LegacyX25519 key pair.", e); } } + + @Override + public PGPKeyPair generateECDHKeyPair(ASN1ObjectIdentifier curveOID) + throws PGPException + { + try + { + KeyPairGenerator gen = helper.createKeyPairGenerator("ECDH"); + String curveName = ECUtil.getCurveName(curveOID); + gen.initialize(new ECNamedCurveGenParameterSpec(curveName)); + KeyPair keyPair = gen.generateKeyPair(); + return new JcaPGPKeyPair(version, PublicKeyAlgorithmTags.ECDH, keyPair, creationTime); + } + catch (GeneralSecurityException e) + { + throw new PGPException("Cannot generate ECDH key pair.", e); + } + } + + @Override + public PGPKeyPair generateECDSAKeyPair(ASN1ObjectIdentifier curveOID) + throws PGPException + { + try + { + KeyPairGenerator gen = helper.createKeyPairGenerator("ECDSA"); + String curveName = ECUtil.getCurveName(curveOID); + gen.initialize(new ECNamedCurveGenParameterSpec(curveName)); + KeyPair keyPair = gen.generateKeyPair(); + return new JcaPGPKeyPair(version, PublicKeyAlgorithmTags.ECDSA, keyPair, creationTime); + } + catch (GeneralSecurityException e) + { + throw new PGPException("Cannot generate ECDSA key pair.", e); + } + } } } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADCipherUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADCipherUtil.java index 0ebe601a36..5c77c49eb2 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADCipherUtil.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADCipherUtil.java @@ -76,7 +76,7 @@ public ASN1Primitive toASN1Primitive() if (icvLen != 12) { - v.add(new ASN1Integer(icvLen)); + v.add(ASN1Integer.valueOf(icvLen)); } return new DERSequence(v); diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEKeyEncryptionMethodGenerator.java index 32ad340394..bcb5a5df55 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEKeyEncryptionMethodGenerator.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEKeyEncryptionMethodGenerator.java @@ -1,5 +1,6 @@ package org.bouncycastle.openpgp.operator.jcajce; +import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Provider; @@ -12,12 +13,11 @@ import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; +import org.bouncycastle.bcpg.AEADAlgorithmTags; import org.bouncycastle.bcpg.S2K; +import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; import org.bouncycastle.bcpg.SymmetricKeyUtils; -import org.bouncycastle.crypto.InvalidCipherTextException; -import org.bouncycastle.crypto.modes.AEADCipher; -import org.bouncycastle.crypto.params.AEADParameters; -import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.jcajce.spec.AEADParameterSpec; import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; import org.bouncycastle.jcajce.util.NamedJcaJceHelper; import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; @@ -25,7 +25,6 @@ import org.bouncycastle.openpgp.PGPUtil; import org.bouncycastle.openpgp.operator.PBEKeyEncryptionMethodGenerator; import org.bouncycastle.openpgp.operator.PGPDigestCalculator; -import org.bouncycastle.openpgp.operator.bc.BcAEADUtil; /** * JCE based generator for password based encryption (PBE) data protection methods. @@ -152,26 +151,74 @@ protected byte[] encryptSessionInfo(int encAlgorithm, byte[] key, byte[] session } protected byte[] generateV6KEK(int kekAlgorithm, byte[] ikm, byte[] info) - { - return JceAEADUtil.generateHKDFBytes(ikm, null, info, SymmetricKeyUtils.getKeyLengthInOctets(kekAlgorithm)); - } - - protected byte[] getEskAndTag(int kekAlgorithm, int aeadAlgorithm, byte[] sessionKey, byte[] key, byte[] iv, byte[] info) - throws PGPException - { - AEADCipher aeadCipher = BcAEADUtil.createAEADCipher(kekAlgorithm, aeadAlgorithm); - aeadCipher.init(true, new AEADParameters(new KeyParameter(key), 128, iv, info)); - int outLen = aeadCipher.getOutputSize(sessionKey.length); - byte[] eskAndTag = new byte[outLen]; - int len = aeadCipher.processBytes(sessionKey, 0, sessionKey.length, eskAndTag, 0); - try - { - len += aeadCipher.doFinal(eskAndTag, len); - } - catch (InvalidCipherTextException e) - { - throw new PGPException("cannot encrypt session info", e); - } - return eskAndTag; - } + { + return JceAEADUtil.generateHKDFBytes(ikm, null, info, SymmetricKeyUtils.getKeyLengthInOctets(kekAlgorithm)); + } + + protected byte[] getEskAndTag(int kekAlgorithm, int aeadAlgorithm, byte[] sessionKey, byte[] key, byte[] iv, byte[] info) + throws PGPException + { + String algorithm = getBaseAEADAlgorithm(kekAlgorithm); + + Cipher aeadCipher = createAEADCipher(algorithm, aeadAlgorithm); + + try + { + aeadCipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, algorithm), new AEADParameterSpec(iv, 128, info)); + int outLen = aeadCipher.getOutputSize(sessionKey.length); + byte[] eskAndTag = new byte[outLen]; + + int len = aeadCipher.update(sessionKey, 0, sessionKey.length, eskAndTag, 0); + + len += aeadCipher.doFinal(eskAndTag, len); + + if (len < eskAndTag.length) + { + byte[] rv = new byte[len]; + System.arraycopy(eskAndTag, 0, rv, 0, len); + return rv; + } + + return eskAndTag; + } + catch (GeneralSecurityException e) + { + throw new PGPException("cannot encrypt session info", e); + } + } + + private static String getBaseAEADAlgorithm(int encAlgorithm) + throws PGPException + { + if (encAlgorithm == SymmetricKeyAlgorithmTags.AES_128 + || encAlgorithm == SymmetricKeyAlgorithmTags.AES_192 + || encAlgorithm == SymmetricKeyAlgorithmTags.AES_256) + { + return "AES"; + } + else if (encAlgorithm == SymmetricKeyAlgorithmTags.CAMELLIA_128 + || encAlgorithm == SymmetricKeyAlgorithmTags.CAMELLIA_192 + || encAlgorithm == SymmetricKeyAlgorithmTags.CAMELLIA_256) + { + return "Camellia"; + } + throw new PGPException("AEAD only supported for AES and Camellia based algorithms"); + } + + private Cipher createAEADCipher(String algorithm, int aeadAlgorithm) + throws PGPException + { + // Block Cipher must work on 16 byte blocks + switch (aeadAlgorithm) + { + case AEADAlgorithmTags.EAX: + return helper.createCipher(algorithm + "/EAX/NoPadding"); + case AEADAlgorithmTags.OCB: + return helper.createCipher(algorithm + "/OCB/NoPadding"); + case AEADAlgorithmTags.GCM: + return helper.createCipher(algorithm + "/GCM/NoPadding"); + default: + throw new PGPException("unrecognised AEAD algorithm: " + aeadAlgorithm); + } + } } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilder.java index d99af1cc70..d08c9fc190 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilder.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilder.java @@ -15,9 +15,11 @@ import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPUtil; import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilder; import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; public class JcePBESecretKeyDecryptorBuilder + implements PBESecretKeyDecryptorBuilder { private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); private PGPDigestCalculatorProvider calculatorProvider; diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilderProvider.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilderProvider.java new file mode 100644 index 0000000000..8818fdf969 --- /dev/null +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBESecretKeyDecryptorBuilderProvider.java @@ -0,0 +1,37 @@ +package org.bouncycastle.openpgp.operator.jcajce; + +import java.security.Provider; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilder; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptorBuilderProvider; + +public class JcePBESecretKeyDecryptorBuilderProvider + implements PBESecretKeyDecryptorBuilderProvider +{ + private final JcaPGPDigestCalculatorProviderBuilder digestCalculatorProviderBuilder; + private Provider provider; + + public JcePBESecretKeyDecryptorBuilderProvider(JcaPGPDigestCalculatorProviderBuilder digestCalculatorProviderBuilder) + { + this.digestCalculatorProviderBuilder = digestCalculatorProviderBuilder; + } + + public JcePBESecretKeyDecryptorBuilderProvider setProvider(Provider provider) + { + this.provider = provider; + return this; + } + + @Override + public PBESecretKeyDecryptorBuilder provide() + throws PGPException + { + JcePBESecretKeyDecryptorBuilder b = new JcePBESecretKeyDecryptorBuilder(digestCalculatorProviderBuilder.build()); + if (provider != null) + { + b.setProvider(provider); + } + return b; + } +} diff --git a/pg/src/main/jdk1.4/org/bouncycastle/bcpg/MalformedPacketException.java b/pg/src/main/jdk1.4/org/bouncycastle/bcpg/MalformedPacketException.java new file mode 100644 index 0000000000..97e851e1ee --- /dev/null +++ b/pg/src/main/jdk1.4/org/bouncycastle/bcpg/MalformedPacketException.java @@ -0,0 +1,30 @@ +package org.bouncycastle.bcpg; + +import java.io.IOException; + +public class MalformedPacketException + extends IOException +{ + private final Throwable cause; + + public MalformedPacketException(String message) + { + this(message, null); + } + + public MalformedPacketException(Throwable cause) + { + this(cause.getMessage(), cause); + } + + public MalformedPacketException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/pg/src/main/jdk1.5/org/bouncycastle/openpgp/api/OpenPGPDefaultPolicy.java b/pg/src/main/jdk1.5/org/bouncycastle/openpgp/api/OpenPGPDefaultPolicy.java new file mode 100644 index 0000000000..7cc3d037cb --- /dev/null +++ b/pg/src/main/jdk1.5/org/bouncycastle/openpgp/api/OpenPGPDefaultPolicy.java @@ -0,0 +1,479 @@ +package org.bouncycastle.openpgp.api; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.bcpg.HashAlgorithmTags; +import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; +import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; + +import org.bouncycastle.bcpg.SignatureSubpacket; +import org.bouncycastle.bcpg.sig.NotationData; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; +import org.bouncycastle.openpgp.api.util.UTCUtil; + +public class OpenPGPDefaultPolicy + implements OpenPGPPolicy +{ + private final Map documentHashAlgorithmCutoffDates = new HashMap(); + private final Map certificateHashAlgorithmCutoffDates = new HashMap(); + private final Map symmetricKeyAlgorithmCutoffDates = new HashMap(); + private final Map publicKeyMinimalBitStrengths = new HashMap(); + private int defaultDocumentSignatureHashAlgorithm = HashAlgorithmTags.SHA512; + private int defaultCertificationSignatureHashAlgorithm = HashAlgorithmTags.SHA512; + private int defaultSymmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_128; + + public OpenPGPDefaultPolicy() + { + /* + * Certification Signature Hash Algorithms + */ + setDefaultCertificationSignatureHashAlgorithm(HashAlgorithmTags.SHA512); + // SHA-3 + acceptCertificationSignatureHashAlgorithm(HashAlgorithmTags.SHA3_512); + acceptCertificationSignatureHashAlgorithm(HashAlgorithmTags.SHA3_256); + // SHA-2 + acceptCertificationSignatureHashAlgorithm(HashAlgorithmTags.SHA512); + acceptCertificationSignatureHashAlgorithm(HashAlgorithmTags.SHA384); + acceptCertificationSignatureHashAlgorithm(HashAlgorithmTags.SHA256); + acceptCertificationSignatureHashAlgorithm(HashAlgorithmTags.SHA224); + // SHA-1 + acceptCertificationSignatureHashAlgorithmUntil(HashAlgorithmTags.SHA1, UTCUtil.parse("2023-02-01 00:00:00 UTC")); + + acceptCertificationSignatureHashAlgorithmUntil(HashAlgorithmTags.RIPEMD160, UTCUtil.parse("2023-02-01 00:00:00 UTC")); + acceptCertificationSignatureHashAlgorithmUntil(HashAlgorithmTags.MD5, UTCUtil.parse("1997-02-01 00:00:00 UTC")); + + /* + * Document Signature Hash Algorithms + */ + setDefaultDocumentSignatureHashAlgorithm(HashAlgorithmTags.SHA512); + // SHA-3 + acceptDocumentSignatureHashAlgorithm(HashAlgorithmTags.SHA3_512); + acceptDocumentSignatureHashAlgorithm(HashAlgorithmTags.SHA3_256); + // SHA-2 + acceptDocumentSignatureHashAlgorithm(HashAlgorithmTags.SHA512); + acceptDocumentSignatureHashAlgorithm(HashAlgorithmTags.SHA384); + acceptDocumentSignatureHashAlgorithm(HashAlgorithmTags.SHA256); + acceptDocumentSignatureHashAlgorithm(HashAlgorithmTags.SHA224); + + /* + * Symmetric Key Algorithms + */ + setDefaultSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.AES_128); + acceptSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.AES_256); + acceptSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.AES_192); + acceptSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.AES_128); + acceptSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.TWOFISH); + acceptSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.CAMELLIA_256); + acceptSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.CAMELLIA_192); + acceptSymmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.CAMELLIA_128); + + /* + * Public Key Algorithms and key strengths + */ + acceptPublicKeyAlgorithmWithMinimalStrength(PublicKeyAlgorithmTags.RSA_GENERAL, 2000); + acceptPublicKeyAlgorithmWithMinimalStrength(PublicKeyAlgorithmTags.RSA_ENCRYPT, 2000); + acceptPublicKeyAlgorithmWithMinimalStrength(PublicKeyAlgorithmTags.RSA_SIGN, 2000); + + acceptPublicKeyAlgorithmWithMinimalStrength(PublicKeyAlgorithmTags.ECDSA, 250); + acceptPublicKeyAlgorithmWithMinimalStrength(PublicKeyAlgorithmTags.EDDSA_LEGACY, 250); + acceptPublicKeyAlgorithmWithMinimalStrength(PublicKeyAlgorithmTags.ECDH, 250); + + acceptPublicKeyAlgorithm(PublicKeyAlgorithmTags.X25519); + acceptPublicKeyAlgorithm(PublicKeyAlgorithmTags.X448); + acceptPublicKeyAlgorithm(PublicKeyAlgorithmTags.Ed25519); + acceptPublicKeyAlgorithm(PublicKeyAlgorithmTags.Ed448); + } + + /** + * Return true, if the given {@link PGPPublicKey} is an acceptable signing key. + * Note: Although signing requires a secret key, we perform checks on the public part for consistency. + * + * @param key key + * @return true if acceptable signing key + */ + public boolean isAcceptableSigningKey(PGPPublicKey key) + { + return isAcceptablePublicKey(key); + } + + /** + * Return true, if the given {@link PGPPublicKey} is an acceptable signature verification key. + * Note: The asymmetry between this and {@link #isAcceptableSigningKey(PGPPublicKey)} is useful + * to prevent creation of signatures using a legacy key, while still allowing verification of + * signatures made using the same key. + * + * @param key key + * @return true if acceptable verification key + */ + public boolean isAcceptableVerificationKey(PGPPublicKey key) + { + return isAcceptablePublicKey(key); + } + + /** + * Return true, if the given {@link PGPPublicKey} is acceptable for encrypting messages. + * + * @param key key + * @return true if acceptable encryption key + */ + public boolean isAcceptableEncryptionKey(PGPPublicKey key) + { + return isAcceptablePublicKey(key); + } + + /** + * Return true, if the given {@link PGPPublicKey} is acceptable for decrypting messages. + * Note: Although decryption requires a secret key, we perform checks on the public part for consistency. + * The asymmetry between this and {@link #isAcceptableEncryptionKey(PGPPublicKey)} is useful + * to prevent creation of new encrypted messages using a legacy key, while still allowing decryption + * of existing messages using the same key. + * + * @param key key + * @return true if acceptable decryption key + */ + public boolean isAcceptableDecryptionKey(PGPPublicKey key) + { + return isAcceptablePublicKey(key); + } + + /** + * Return true, if the given {@link PGPPublicKey} is acceptable. + * + * @param key key + * @return true if acceptable key + */ + public boolean isAcceptablePublicKey(PGPPublicKey key) + { + return isAcceptablePublicKeyStrength(key.getAlgorithm(), key.getBitStrength()); + } + + /** + * Return true, if the given {@link PGPSignature} is acceptable (uses acceptable hash algorithm, + * does not contain unknown critical notations or subpackets). + * Note: A signature being acceptable does NOT mean that it is correct or valid. + * + * @param signature signature + * @return true if acceptable + */ + public boolean isAcceptableSignature(PGPSignature signature) + { + return hasAcceptableSignatureHashAlgorithm(signature) && + hasNoCriticalUnknownNotations(signature) && + hasNoCriticalUnknownSubpackets(signature); + } + + /** + * Return true, if the given {@link PGPSignature} was made using an acceptable signature hash algorithm. + * + * @param signature signature + * @return true if hash algorithm is acceptable + */ + public boolean hasAcceptableSignatureHashAlgorithm(PGPSignature signature) + { + switch (signature.getSignatureType()) + { + case PGPSignature.DEFAULT_CERTIFICATION: + case PGPSignature.NO_CERTIFICATION: + case PGPSignature.CASUAL_CERTIFICATION: + case PGPSignature.POSITIVE_CERTIFICATION: + case PGPSignature.DIRECT_KEY: + case PGPSignature.SUBKEY_BINDING: + case PGPSignature.PRIMARYKEY_BINDING: + return hasAcceptableCertificationSignatureHashAlgorithm(signature); + + case PGPSignature.CERTIFICATION_REVOCATION: + case PGPSignature.KEY_REVOCATION: + case PGPSignature.SUBKEY_REVOCATION: + return hasAcceptableRevocationSignatureHashAlgorithm(signature); + + case PGPSignature.BINARY_DOCUMENT: + case PGPSignature.CANONICAL_TEXT_DOCUMENT: + default: + return hasAcceptableDocumentSignatureHashAlgorithm(signature); + } + } + + /** + * Return true, if the {@link PGPSignature} uses an acceptable data/document signature hash algorithm. + * + * @param signature data / document signature + * @return true if hash algorithm is acceptable + */ + public boolean hasAcceptableDocumentSignatureHashAlgorithm(PGPSignature signature) + { + return isAcceptableDocumentSignatureHashAlgorithm(signature.getHashAlgorithm(), signature.getCreationTime()); + } + + /** + * Return true, if the {@link PGPSignature} uses an acceptable revocation signature hash algorithm. + * + * @param signature revocation signature + * @return true if hash algorithm is acceptable + */ + public boolean hasAcceptableRevocationSignatureHashAlgorithm(PGPSignature signature) + { + return isAcceptableRevocationSignatureHashAlgorithm(signature.getHashAlgorithm(), signature.getCreationTime()); + } + + /** + * Return true, if the {@link PGPSignature} uses an acceptable certification signature hash algorithm. + * + * @param signature certification signature + * @return true if hash algorithm is acceptable + */ + public boolean hasAcceptableCertificationSignatureHashAlgorithm(PGPSignature signature) + { + return isAcceptableCertificationSignatureHashAlgorithm(signature.getHashAlgorithm(), signature.getCreationTime()); + } + + /** + * Return true, if the hashed subpacket area of the signature does NOT contain unknown critical notations. + * + * @param signature signature + * @return true if signature is free from unknown critical notations + */ + public boolean hasNoCriticalUnknownNotations(PGPSignature signature) + { + PGPSignatureSubpacketVector hashedSubpackets = signature.getHashedSubPackets(); + if (hashedSubpackets == null) + { + return true; + } + + OpenPGPNotationRegistry registry = getNotationRegistry(); + + NotationData[] notations = hashedSubpackets.getNotationDataOccurrences(); + for (NotationData notation : notations) + { + if (notation.isCritical() && !registry.isNotationKnown(notation.getNotationName())) + { + return false; + } + } + return true; + } + + /** + * Return true, if the hashed subpacket area of the signature does NOT contain unknown critical subpackets. + * + * @param signature signature + * @return true if signature is free from unknown critical subpackets + */ + public boolean hasNoCriticalUnknownSubpackets(PGPSignature signature) + { + PGPSignatureSubpacketVector hashedSubpackets = signature.getHashedSubPackets(); + if (hashedSubpackets == null) + { + return true; + } + + for (SignatureSubpacket subpacket : hashedSubpackets.toArray()) + { + if (subpacket.isCritical() && + // only consider subpackets which are not recognized by SignatureSubpacketInputStream + subpacket.getClass().equals(SignatureSubpacket.class)) + { + if (!isKnownSignatureSubpacket(subpacket.getType())) + { + return false; + } + } + } + return true; + } + + /** + * Return true, if the given signature subpacket ID is known by the implementation. + * Note: This method is only called for subpackets not recognized by + * {@link org.bouncycastle.bcpg.SignatureSubpacketInputStream}. + * + * @param signatureSubpacketTag signature subpacket ID + * @return true if subpacket tag is known + */ + public boolean isKnownSignatureSubpacket(int signatureSubpacketTag) + { + // Overwrite this, allowing custom critical signature subpackets + return false; + } + + public OpenPGPDefaultPolicy rejectHashAlgorithm(int hashAlgorithmId) + { + certificateHashAlgorithmCutoffDates.remove(hashAlgorithmId); + documentHashAlgorithmCutoffDates.remove(hashAlgorithmId); + return this; + } + + public OpenPGPDefaultPolicy acceptCertificationSignatureHashAlgorithm(int hashAlgorithmId) + { + return acceptCertificationSignatureHashAlgorithmUntil(hashAlgorithmId, null); + } + + public OpenPGPDefaultPolicy acceptCertificationSignatureHashAlgorithmUntil(int hashAlgorithmId, Date until) + { + certificateHashAlgorithmCutoffDates.put(hashAlgorithmId, until); + return this; + } + + public OpenPGPDefaultPolicy acceptDocumentSignatureHashAlgorithm(int hashAlgorithmId) + { + return acceptDocumentSignatureHashAlgorithmUntil(hashAlgorithmId, null); + } + + public OpenPGPDefaultPolicy acceptDocumentSignatureHashAlgorithmUntil(int hashAlgorithmId, Date until) + { + documentHashAlgorithmCutoffDates.put(hashAlgorithmId, until); + return this; + } + + public OpenPGPDefaultPolicy rejectSymmetricKeyAlgorithm(int symmetricKeyAlgorithmId) + { + symmetricKeyAlgorithmCutoffDates.remove(symmetricKeyAlgorithmId); + return this; + } + + public OpenPGPDefaultPolicy acceptSymmetricKeyAlgorithm(int symmetricKeyAlgorithmId) + { + return acceptSymmetricKeyAlgorithmUntil(symmetricKeyAlgorithmId, null); + } + + public OpenPGPDefaultPolicy acceptSymmetricKeyAlgorithmUntil(int symmetricKeyAlgorithmId, Date until) + { + symmetricKeyAlgorithmCutoffDates.put(symmetricKeyAlgorithmId, until); + return this; + } + + public OpenPGPDefaultPolicy rejectPublicKeyAlgorithm(int publicKeyAlgorithmId) + { + publicKeyMinimalBitStrengths.remove(publicKeyAlgorithmId); + return this; + } + + public OpenPGPDefaultPolicy acceptPublicKeyAlgorithm(int publicKeyAlgorithmId) + { + publicKeyMinimalBitStrengths.put(publicKeyAlgorithmId, null); + return this; + } + + public OpenPGPDefaultPolicy acceptPublicKeyAlgorithmWithMinimalStrength(int publicKeyAlgorithmId, int minBitStrength) + { + publicKeyMinimalBitStrengths.put(publicKeyAlgorithmId, minBitStrength); + return this; + } + + @Override + public boolean isAcceptableDocumentSignatureHashAlgorithm(int hashAlgorithmId, Date signatureCreationTime) + { + return isAcceptable(hashAlgorithmId, signatureCreationTime, documentHashAlgorithmCutoffDates); + } + + @Override + public boolean isAcceptableRevocationSignatureHashAlgorithm(int hashAlgorithmId, Date signatureCreationTime) + { + return isAcceptable(hashAlgorithmId, signatureCreationTime, certificateHashAlgorithmCutoffDates); + } + + @Override + public boolean isAcceptableCertificationSignatureHashAlgorithm(int hashAlgorithmId, Date signatureCreationTime) + { + return isAcceptable(hashAlgorithmId, signatureCreationTime, certificateHashAlgorithmCutoffDates); + } + + @Override + public int getDefaultCertificationSignatureHashAlgorithm() + { + return defaultCertificationSignatureHashAlgorithm; + } + + public OpenPGPDefaultPolicy setDefaultCertificationSignatureHashAlgorithm(int hashAlgorithmId) + { + defaultCertificationSignatureHashAlgorithm = hashAlgorithmId; + return this; + } + + @Override + public int getDefaultDocumentSignatureHashAlgorithm() + { + return defaultDocumentSignatureHashAlgorithm; + } + + public OpenPGPDefaultPolicy setDefaultDocumentSignatureHashAlgorithm(int hashAlgorithmId) + { + defaultDocumentSignatureHashAlgorithm = hashAlgorithmId; + return this; + } + + @Override + public boolean isAcceptableSymmetricKeyAlgorithm(int symmetricKeyAlgorithmId) + { + return isAcceptable(symmetricKeyAlgorithmId, symmetricKeyAlgorithmCutoffDates); + } + + @Override + public int getDefaultSymmetricKeyAlgorithm() + { + return defaultSymmetricKeyAlgorithm; + } + + public OpenPGPDefaultPolicy setDefaultSymmetricKeyAlgorithm(int symmetricKeyAlgorithmId) + { + defaultSymmetricKeyAlgorithm = symmetricKeyAlgorithmId; + return this; + } + + @Override + public boolean isAcceptablePublicKeyStrength(int publicKeyAlgorithmId, int bitStrength) + { + return isAcceptable(publicKeyAlgorithmId, bitStrength, publicKeyMinimalBitStrengths); + } + + @Override + public OpenPGPNotationRegistry getNotationRegistry() + { + return null; + } + + private boolean isAcceptable(int algorithmId, Date usageDate, Map cutoffTable) + { + if (!cutoffTable.containsKey(algorithmId)) + { + // algorithm is not listed in the map at all + return false; + } + + Date cutoffDate = cutoffTable.get(algorithmId); + if (cutoffDate == null) + { + // no cutoff date given -> algorithm is acceptable indefinitely + return true; + } + + return usageDate.before(cutoffDate); + } + + private boolean isAcceptable(int algorithmId, Map cutoffTable) + { + return cutoffTable.containsKey(algorithmId); + } + + private boolean isAcceptable(int algorithmId, int bitStrength, Map minBitStrengths) + { + if (!minBitStrengths.containsKey(algorithmId)) + { + // algorithm is not listed in the map at all + return false; + } + + Integer minBitStrength = minBitStrengths.get(algorithmId); + if (minBitStrength == null) + { + // no minimal bit strength defined -> accept all strengths + return true; + } + + return bitStrength >= minBitStrength; + } +} diff --git a/pg/src/main/jdk1.5/org/bouncycastle/openpgp/api/OpenPGPPolicy.java b/pg/src/main/jdk1.5/org/bouncycastle/openpgp/api/OpenPGPPolicy.java new file mode 100644 index 0000000000..9a9d1d4c27 --- /dev/null +++ b/pg/src/main/jdk1.5/org/bouncycastle/openpgp/api/OpenPGPPolicy.java @@ -0,0 +1,228 @@ +package org.bouncycastle.openpgp.api; + +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + +import org.bouncycastle.bcpg.SignatureSubpacket; +import org.bouncycastle.bcpg.sig.NotationData; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; + +/** + * Policy for OpenPGP algorithms and features. + */ +public interface OpenPGPPolicy +{ + /** + * Return true, if the given {@link PGPPublicKey} is an acceptable signing key. + * Note: Although signing requires a secret key, we perform checks on the public part for consistency. + * + * @param key key + * @return true if acceptable signing key + */ + boolean isAcceptableSigningKey(PGPPublicKey key); + + /** + * Return true, if the given {@link PGPPublicKey} is an acceptable signature verification key. + * Note: The asymmetry between this and {@link #isAcceptableSigningKey(PGPPublicKey)} is useful + * to prevent creation of signatures using a legacy key, while still allowing verification of + * signatures made using the same key. + * + * @param key key + * @return true if acceptable verification key + */ + boolean isAcceptableVerificationKey(PGPPublicKey key); + + /** + * Return true, if the given {@link PGPPublicKey} is acceptable for encrypting messages. + * + * @param key key + * @return true if acceptable encryption key + */ + boolean isAcceptableEncryptionKey(PGPPublicKey key); + + /** + * Return true, if the given {@link PGPPublicKey} is acceptable for decrypting messages. + * Note: Although decryption requires a secret key, we perform checks on the public part for consistency. + * The asymmetry between this and {@link #isAcceptableEncryptionKey(PGPPublicKey)} is useful + * to prevent creation of new encrypted messages using a legacy key, while still allowing decryption + * of existing messages using the same key. + * + * @param key key + * @return true if acceptable decryption key + */ + boolean isAcceptableDecryptionKey(PGPPublicKey key); + + /** + * Return true, if the given {@link PGPPublicKey} is acceptable. + * + * @param key key + * @return true if acceptable key + */ + boolean isAcceptablePublicKey(PGPPublicKey key); + + /** + * Return true, if the given {@link PGPSignature} is acceptable (uses acceptable hash algorithm, + * does not contain unknown critical notations or subpackets). + * Note: A signature being acceptable does NOT mean that it is correct or valid. + * + * @param signature signature + * @return true if acceptable + */ + boolean isAcceptableSignature(PGPSignature signature); + + /** + * Return true, if the given {@link PGPSignature} was made using an acceptable signature hash algorithm. + * + * @param signature signature + * @return true if hash algorithm is acceptable + */ + boolean hasAcceptableSignatureHashAlgorithm(PGPSignature signature); + + /** + * Return true, if the {@link PGPSignature} uses an acceptable data/document signature hash algorithm. + * + * @param signature data / document signature + * @return true if hash algorithm is acceptable + */ + boolean hasAcceptableDocumentSignatureHashAlgorithm(PGPSignature signature); + + /** + * Return true, if the {@link PGPSignature} uses an acceptable revocation signature hash algorithm. + * + * @param signature revocation signature + * @return true if hash algorithm is acceptable + */ + boolean hasAcceptableRevocationSignatureHashAlgorithm(PGPSignature signature); + + /** + * Return true, if the {@link PGPSignature} uses an acceptable certification signature hash algorithm. + * + * @param signature certification signature + * @return true if hash algorithm is acceptable + */ + boolean hasAcceptableCertificationSignatureHashAlgorithm(PGPSignature signature); + + /** + * Return true, if the hashed subpacket area of the signature does NOT contain unknown critical notations. + * @param signature signature + * @return true if signature is free from unknown critical notations + */ + boolean hasNoCriticalUnknownNotations(PGPSignature signature); + + /** + * Return true, if the hashed subpacket area of the signature does NOT contain unknown critical subpackets. + * @param signature signature + * @return true if signature is free from unknown critical subpackets + */ + boolean hasNoCriticalUnknownSubpackets(PGPSignature signature); + + /** + * Return true, if the given signature subpacket ID is known by the implementation. + * Note: This method is only called for subpackets not recognized by + * {@link org.bouncycastle.bcpg.SignatureSubpacketInputStream}. + * + * @param signatureSubpacketTag signature subpacket ID + * @return true if subpacket tag is known + */ + boolean isKnownSignatureSubpacket(int signatureSubpacketTag); + + /** + * Return true, if the given hash algorithm is - at signature creation time - an acceptable document signature + * hash algorithm. + * + * @param hashAlgorithmId hash algorithm ID + * @param signatureCreationTime optional signature creation time + * @return true if hash algorithm is acceptable at creation time + */ + boolean isAcceptableDocumentSignatureHashAlgorithm(int hashAlgorithmId, Date signatureCreationTime); + + /** + * Return true, if the given hash algorithm is - at signature creation time - an acceptable revocation signature + * hash algorithm. + * + * @param hashAlgorithmId hash algorithm ID + * @param signatureCreationTime optional signature creation time + * @return true if hash algorithm is acceptable at creation time + */ + boolean isAcceptableRevocationSignatureHashAlgorithm(int hashAlgorithmId, Date signatureCreationTime); + + /** + * Return true, if the given hash algorithm is - at signature creation time - an acceptable certification signature + * hash algorithm. + * + * @param hashAlgorithmId hash algorithm ID + * @param signatureCreationTime optional signature creation time + * @return true if hash algorithm is acceptable at creation time + */ + boolean isAcceptableCertificationSignatureHashAlgorithm(int hashAlgorithmId, Date signatureCreationTime); + + /** + * Return the default certification signature hash algorithm ID. + * This is used as fallback, if negotiation of a commonly supported hash algorithm fails. + * + * @return default certification signature hash algorithm ID + */ + int getDefaultCertificationSignatureHashAlgorithm(); + + /** + * Return the default document signature hash algorithm ID. + * This is used as fallback, if negotiation of a commonly supported hash algorithm fails. + * + * @return default document signature hash algorithm ID + */ + int getDefaultDocumentSignatureHashAlgorithm(); + + /** + * Return true, if the given symmetric-key algorithm is acceptable. + * + * @param symmetricKeyAlgorithmId symmetric-key algorithm + * @return true if symmetric-key algorithm is acceptable + */ + boolean isAcceptableSymmetricKeyAlgorithm(int symmetricKeyAlgorithmId); + + /** + * Return the default symmetric-key algorithm, which is used as a fallback if symmetric encryption algorithm + * negotiation fails. + * + * @return default symmetric-key algorithm + */ + int getDefaultSymmetricKeyAlgorithm(); + + /** + * Return true, if the given bitStrength is acceptable for the given public key algorithm ID. + * + * @param publicKeyAlgorithmId ID of a public key algorithm + * @param bitStrength key bit strength + * @return true if strength is acceptable + */ + boolean isAcceptablePublicKeyStrength(int publicKeyAlgorithmId, int bitStrength); + + /** + * Return the policies {@link OpenPGPNotationRegistry} containing known notation names. + * + * @return notation registry + */ + OpenPGPNotationRegistry getNotationRegistry(); + + /** + * The {@link OpenPGPNotationRegistry} can be used to register known notations, such that signatures containing + * notation instances of the same name, which are marked as critical do not invalidate the signature. + */ + class OpenPGPNotationRegistry + { + private final Set knownNotations = new HashSet(); + + public boolean isNotationKnown(String notationName) + { + return knownNotations.contains(notationName); + } + + public void addKnownNotation(String notationName) + { + this.knownNotations.add(notationName); + } + } +} diff --git a/pg/src/main/jdk1.5/org/bouncycastle/openpgp/api/SignatureParameters.java b/pg/src/main/jdk1.5/org/bouncycastle/openpgp/api/SignatureParameters.java new file mode 100644 index 0000000000..0c28b40b88 --- /dev/null +++ b/pg/src/main/jdk1.5/org/bouncycastle/openpgp/api/SignatureParameters.java @@ -0,0 +1,333 @@ +package org.bouncycastle.openpgp.api; + +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.bouncycastle.util.Arrays; + +import java.util.Date; + +/** + * Parameters for signature generation. + * Some signature builders allow the user to pass in a {@link Callback}, which can be used to modify + * {@link SignatureParameters} instances prior to signature generation. + */ +public class SignatureParameters +{ + private int signatureType; + private Date signatureCreationTime = new Date(); + private int signatureHashAlgorithmId; + private SignatureSubpacketsFunction hashedSubpacketsFunction; + private SignatureSubpacketsFunction unhashedSubpacketsFunction; + + private final int[] allowedSignatureTypes; + + private SignatureParameters(int... allowedSignatureTypes) + { + this.allowedSignatureTypes = allowedSignatureTypes; + } + + /** + * Create default signature parameters object for a direct-key signature. + * When issued as a self-signature, direct-key signatures can be used to store algorithm preferences + * on the key, which apply to the entire certificate (including all subkeys). + * When issued as a third-party signature, direct-key signatures act as delegations, with which for example the + * web-of-trust can be built. + * + * @param policy algorithm policy + * @return parameters + * @see + * OpenPGP Web-of-Trust + */ + public static SignatureParameters directKeySignature(OpenPGPPolicy policy) + { + return new SignatureParameters(PGPSignature.DIRECT_KEY) + .setSignatureType(PGPSignature.DIRECT_KEY) + .setSignatureHashAlgorithm(policy.getDefaultCertificationSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Create default signature parameters for a key revocation signature. + * When issued as a self-signature, key revocation signatures can be used to revoke an entire certificate. + * To revoke only individual subkeys, see {@link #subkeyRevocation(OpenPGPPolicy)} instead. + * When issued as a third-party signature, key revocation signatures are used to revoke earlier delegation + * signatures. + * + * @param policy algorithm policy + * @return parameters + */ + public static SignatureParameters keyRevocation(OpenPGPPolicy policy) + { + return new SignatureParameters(PGPSignature.KEY_REVOCATION) + .setSignatureType(PGPSignature.KEY_REVOCATION) + .setSignatureHashAlgorithm(policy.getDefaultCertificationSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Create a default signature parameters object for a certification signature. + * The default signature type is {@link PGPSignature#POSITIVE_CERTIFICATION}, but can be changed to + * {@link PGPSignature#DEFAULT_CERTIFICATION}, {@link PGPSignature#NO_CERTIFICATION}, + * {@link PGPSignature#CASUAL_CERTIFICATION}. + * When issued as a self-signature, certifications can be used to bind user-ids to the certificate. + * When issued as third-party signatures, certificates act as a statement, expressing that the issuer + * is convinced that the user-id "belongs to" the certificate. + * + * @param policy algorithm policy + * @return parameters + */ + public static SignatureParameters certification(OpenPGPPolicy policy) + { + return new SignatureParameters( + PGPSignature.DEFAULT_CERTIFICATION, + PGPSignature.NO_CERTIFICATION, + PGPSignature.CASUAL_CERTIFICATION, + PGPSignature.POSITIVE_CERTIFICATION) + .setSignatureType(PGPSignature.POSITIVE_CERTIFICATION) + .setSignatureHashAlgorithm(policy.getDefaultCertificationSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Create a default signature parameters object for a subkey binding signature. + * + * @param policy algorithm policy + * @return parameters + */ + public static SignatureParameters subkeyBinding(OpenPGPPolicy policy) + { + return new SignatureParameters(PGPSignature.SUBKEY_BINDING) + .setSignatureType(PGPSignature.SUBKEY_BINDING) + .setSignatureHashAlgorithm(policy.getDefaultCertificationSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Create default signature parameters for a subkey revocation signature. + * + * @param policy algorithm policy + * @return parameters + */ + public static SignatureParameters subkeyRevocation(OpenPGPPolicy policy) + { + return new SignatureParameters(PGPSignature.SUBKEY_REVOCATION) + .setSignatureType(PGPSignature.SUBKEY_REVOCATION) + .setSignatureHashAlgorithm(policy.getDefaultCertificationSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Create a default signature parameters object for a primary-key binding (back-sig) signature. + * + * @param policy algorithm policy + * @return parameters + */ + public static SignatureParameters primaryKeyBinding(OpenPGPPolicy policy) + { + return new SignatureParameters(PGPSignature.PRIMARYKEY_BINDING) + .setSignatureType(PGPSignature.PRIMARYKEY_BINDING) + .setSignatureHashAlgorithm(policy.getDefaultCertificationSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Create a default signature parameters object for a certification-revocation signature. + * + * @param policy algorithm policy + * @return parameters + */ + public static SignatureParameters certificationRevocation(OpenPGPPolicy policy) + { + return new SignatureParameters(PGPSignature.CERTIFICATION_REVOCATION) + .setSignatureType(PGPSignature.CERTIFICATION_REVOCATION) + .setSignatureHashAlgorithm(policy.getDefaultCertificationSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Create a default signature parameters object for a data/document signature. + * The default signature type is {@link PGPSignature#BINARY_DOCUMENT}, but can be changed to + * {@link PGPSignature#CANONICAL_TEXT_DOCUMENT}. + * + * @param policy algorithm policy + * @return parameters + */ + public static SignatureParameters dataSignature(OpenPGPPolicy policy) + { + return new SignatureParameters(PGPSignature.BINARY_DOCUMENT, PGPSignature.CANONICAL_TEXT_DOCUMENT) + .setSignatureType(PGPSignature.BINARY_DOCUMENT) + .setSignatureHashAlgorithm(policy.getDefaultDocumentSignatureHashAlgorithm()) + .setSignatureCreationTime(new Date()); + } + + /** + * Change the signature type of the signature to-be-generated to the given type. + * Depending on which factory method was used to instantiate the signature parameters object, + * only certain signature types are allowed. Passing an illegal signature type causes an + * {@link IllegalArgumentException} to be thrown. + * + * @param signatureType signature type + * @return parameters + * @throws IllegalArgumentException if an illegal signature type is passed + */ + public SignatureParameters setSignatureType(int signatureType) + { + if (!Arrays.contains(allowedSignatureTypes, signatureType)) + { + throw new IllegalArgumentException("Illegal signature type provided."); + } + + this.signatureType = signatureType; + return this; + } + + /** + * Return the signature type for the signature to-be-generated. + * + * @return signature type + */ + public int getSignatureType() + { + return signatureType; + } + + /** + * Change the creation time of the signature to-be-generated. + * + * @param signatureCreationTime signature creation time + * @return parameters + */ + public SignatureParameters setSignatureCreationTime(Date signatureCreationTime) + { + if (signatureCreationTime == null) + { + throw new NullPointerException("Signature creation time cannot be null."); + } + this.signatureCreationTime = signatureCreationTime; + return this; + } + + /** + * Return the creation time of the signature to-be-generated. + * + * @return signature creation time + */ + public Date getSignatureCreationTime() + { + return signatureCreationTime; + } + + /** + * Change the hash algorithm for the signature to-be-generated. + * + * @param signatureHashAlgorithmId signature hash algorithm id + * @return parameters + */ + public SignatureParameters setSignatureHashAlgorithm(int signatureHashAlgorithmId) + { + this.signatureHashAlgorithmId = signatureHashAlgorithmId; + return this; + } + + /** + * Return the hash algorithm id of the signature to-be-generated. + * + * @return hash algorithm id + */ + public int getSignatureHashAlgorithmId() + { + return signatureHashAlgorithmId; + } + + /** + * Set a function, which is applied to the hashed subpackets area of the signature to-be-generated. + * + * @param subpacketsFunction function to apply to the hashed signature subpackets + * @return parameters + */ + public SignatureParameters setHashedSubpacketsFunction(SignatureSubpacketsFunction subpacketsFunction) + { + this.hashedSubpacketsFunction = subpacketsFunction; + return this; + } + + /** + * Apply the hashed subpackets function set via {@link #setHashedSubpacketsFunction(SignatureSubpacketsFunction)} + * to the given hashed subpackets. + * + * @param hashedSubpackets hashed signature subpackets + * @return modified hashed subpackets + */ + PGPSignatureSubpacketGenerator applyToHashedSubpackets(PGPSignatureSubpacketGenerator hashedSubpackets) + { + if (hashedSubpacketsFunction != null) + { + return hashedSubpacketsFunction.apply(hashedSubpackets); + } + return hashedSubpackets; + } + + /** + * Set a function, which is applied to the unhashed subpackets area of the signature to-be-generated. + * + * @param subpacketsFunction function to apply to the unhashed signature subpackets + * @return parameters + */ + public SignatureParameters setUnhashedSubpacketsFunction(SignatureSubpacketsFunction subpacketsFunction) + { + this.unhashedSubpacketsFunction = subpacketsFunction; + return this; + } + + /** + * Apply the unhashed subpackets function set via {@link #setUnhashedSubpacketsFunction(SignatureSubpacketsFunction)} + * to the given unhashed subpackets. + * + * @param unhashedSubpackets unhashed signature subpackets + * @return modified unhashed subpackets + */ + PGPSignatureSubpacketGenerator applyToUnhashedSubpackets(PGPSignatureSubpacketGenerator unhashedSubpackets) + { + if (unhashedSubpacketsFunction != null) + { + return unhashedSubpacketsFunction.apply(unhashedSubpackets); + } + return unhashedSubpackets; + } + + /** + * Callback, allowing the user to modify {@link SignatureParameters} before use. + */ + public interface Callback + { + /** + * Apply custom changes to {@link SignatureParameters}. + * + * @param parameters parameters instance + * @return modified parameters, or null + */ + SignatureParameters apply(SignatureParameters parameters); + + static class Util + { + /** + * Shortcut method returning a {@link Callback} which only applies the given + * {@link SignatureSubpacketsFunction} to the hashed signature subpacket area of a signature. + * + * @param function signature subpackets function to apply to the hashed area + * @return callback + */ + public static Callback modifyHashedSubpackets(final SignatureSubpacketsFunction function) + { + return new Callback() + { + @Override + public SignatureParameters apply(SignatureParameters parameters) + { + return parameters.setHashedSubpacketsFunction(function); + } + }; + } + } + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/OpenPGPTestKeys.java b/pg/src/test/java/org/bouncycastle/openpgp/OpenPGPTestKeys.java new file mode 100644 index 0000000000..28c19bd875 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/OpenPGPTestKeys.java @@ -0,0 +1,453 @@ +package org.bouncycastle.openpgp; + +import org.bouncycastle.bcpg.ArmoredInputStream; +import org.bouncycastle.bcpg.BCPGInputStream; +import org.bouncycastle.openpgp.bc.BcPGPObjectFactory; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +public class OpenPGPTestKeys +{ + /** + * Alice's Ed25519 OpenPGP key. + * + * @see + * Alice's OpenPGP Secret Key Material + */ + public static final String ALICE_KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + + "Comment: Alice's OpenPGP Transferable Secret Key\n" + + "Comment: https://www.ietf.org/id/draft-bre-openpgp-samples-01.html\n" + + "\n" + + "lFgEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U\n" + + "b7O1u10AAP9XBeW6lzGOLx7zHH9AsUDUTb2pggYGMzd0P3ulJ2AfvQ4RtCZBbGlj\n" + + "ZSBMb3ZlbGFjZSA8YWxpY2VAb3BlbnBncC5leGFtcGxlPoiQBBMWCAA4AhsDBQsJ\n" + + "CAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE64W7X6M6deFelE5j8jFVDE9H444FAl2l\n" + + "nzoACgkQ8jFVDE9H447pKwD6A5xwUqIDprBzrHfahrImaYEZzncqb25vkLV2arYf\n" + + "a78A/R3AwtLQvjxwLDuzk4dUtUwvUYibL2sAHwj2kGaHnfICnF0EXEcE6RIKKwYB\n" + + "BAGXVQEFAQEHQEL/BiGtq0k84Km1wqQw2DIikVYrQrMttN8d7BPfnr4iAwEIBwAA\n" + + "/3/xFPG6U17rhTuq+07gmEvaFYKfxRB6sgAYiW6TMTpQEK6IeAQYFggAIBYhBOuF\n" + + "u1+jOnXhXpROY/IxVQxPR+OOBQJcRwTpAhsMAAoJEPIxVQxPR+OOWdABAMUdSzpM\n" + + "hzGs1O0RkWNQWbUzQ8nUOeD9wNbjE3zR+yfRAQDbYqvtWQKN4AQLTxVJN5X5AWyb\n" + + "Pnn+We1aTBhaGa86AQ==\n" + + "=n8OM\n" + + "-----END PGP PRIVATE KEY BLOCK-----"; + /** + * Alice's Ed25519 OpenPGP v4 certificate. + * + * @see + * Alice's OpenPGP Certificate + */ + public static final String ALICE_CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + + "Comment: Alice's OpenPGP certificate\n" + + "Comment: https://www.ietf.org/id/draft-bre-openpgp-samples-01.html\n" + + "\n" + + "mDMEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U\n" + + "b7O1u120JkFsaWNlIExvdmVsYWNlIDxhbGljZUBvcGVucGdwLmV4YW1wbGU+iJAE\n" + + "ExYIADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQTrhbtfozp14V6UTmPy\n" + + "MVUMT0fjjgUCXaWfOgAKCRDyMVUMT0fjjukrAPoDnHBSogOmsHOsd9qGsiZpgRnO\n" + + "dypvbm+QtXZqth9rvwD9HcDC0tC+PHAsO7OTh1S1TC9RiJsvawAfCPaQZoed8gK4\n" + + "OARcRwTpEgorBgEEAZdVAQUBAQdAQv8GIa2rSTzgqbXCpDDYMiKRVitCsy203x3s\n" + + "E9+eviIDAQgHiHgEGBYIACAWIQTrhbtfozp14V6UTmPyMVUMT0fjjgUCXEcE6QIb\n" + + "DAAKCRDyMVUMT0fjjlnQAQDFHUs6TIcxrNTtEZFjUFm1M0PJ1Dng/cDW4xN80fsn\n" + + "0QEA22Kr7VkCjeAEC08VSTeV+QFsmz55/lntWkwYWhmvOgE=\n" + + "=iIGO\n" + + "-----END PGP PUBLIC KEY BLOCK-----"; + /** + * Alice's Ed25519 OpenPGP v4 revocation certificate. + * + * @see + * Alice's Revocation Certificate + */ + public static final String ALICE_REVOCATION_CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + + "Comment: Alice's revocation certificate\n" + + "Comment: https://www.ietf.org/id/draft-bre-openpgp-samples-01.html\n" + + "\n" + + "iHgEIBYIACAWIQTrhbtfozp14V6UTmPyMVUMT0fjjgUCXaWkOwIdAAAKCRDyMVUM\n" + + "T0fjjoBlAQDA9ukZFKRFGCooVcVoDVmxTaHLUXlIg9TPh2f7zzI9KgD/SLNXUOaH\n" + + "O6TozOS7C9lwIHwwdHdAxgf5BzuhLT9iuAM=\n" + + "=Tm8h\n" + + "-----END PGP PUBLIC KEY BLOCK-----"; + + /** + * Bob's RSA-3072 OpenPGP v4 Secret Key Material. + * + * @see + * Bob's OpenPGP Secret Key Material + */ + public static final String BOB_KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + + "Comment: D1A6 6E1A 23B1 82C9 980F 788C FBFC C82A 015E 7330\n" + + "Comment: Bob Babbage \n" + + "\n" + + "xcSYBF2lnPIBDAC5cL9PQoQLTMuhjbYvb4Ncuuo0bfmgPRFywX53jPhoFf4Zg6mv\n" + + "/seOXpgecTdOcVttfzC8ycIKrt3aQTiwOG/ctaR4Bk/t6ayNFfdUNxHWk4WCKzdz\n" + + "/56fW2O0F23qIRd8UUJp5IIlN4RDdRCtdhVQIAuzvp2oVy/LaS2kxQoKvph/5pQ/\n" + + "5whqsyroEWDJoSV0yOb25B/iwk/pLUFoyhDG9bj0kIzDxrEqW+7Ba8nocQlecMF3\n" + + "X5KMN5kp2zraLv9dlBBpWW43XktjcCZgMy20SouraVma8Je/ECwUWYUiAZxLIlMv\n" + + "9CurEOtxUw6N3RdOtLmYZS9uEnn5y1UkF88o8Nku890uk6BrewFzJyLAx5wRZ4F0\n" + + "qV/yq36UWQ0JB/AUGhHVPdFf6pl6eaxBwT5GXvbBUibtf8YI2og5RsgTWtXfU7eb\n" + + "SGXrl5ZMpbA6mbfhd0R8aPxWfmDWiIOhBufhMCvUHh1sApMKVZnvIff9/0Dca3wb\n" + + "vLIwa3T4CyshfT0AEQEAAQAL/RZqbJW2IqQDCnJi4Ozm++gPqBPiX1RhTWSjwxfM\n" + + "cJKUZfzLj414rMKm6Jh1cwwGY9jekROhB9WmwaaKT8HtcIgrZNAlYzANGRCM4TLK\n" + + "3VskxfSwKKna8l+s+mZglqbAjUg3wmFuf9Tj2xcUZYmyRm1DEmcN2ZzpvRtHgX7z\n" + + "Wn1mAKUlSDJZSQks0zjuMNbupcpyJokdlkUg2+wBznBOTKzgMxVNC9b2g5/tMPUs\n" + + "hGGWmF1UH+7AHMTaS6dlmr2ZBIyogdnfUqdNg5sZwsxSNrbglKP4sqe7X61uEAIQ\n" + + "bD7rT3LonLbhkrj3I8wilUD8usIwt5IecoHhd9HziqZjRCc1BUBkboUEoyedbDV4\n" + + "i4qfsFZ6CEWoLuD5pW7dEp0M+WeuHXO164Rc+LnH6i1VQrpb1Okl4qO6ejIpIjBI\n" + + "1t3GshtUu/mwGBBxs60KBX5g77mFQ9lLCRj8lSYqOsHRKBhUp4qM869VA+fD0BRP\n" + + "fqPT0I9IH4Oa/A3jYJcg622GwQYA1LhnP208Waf6PkQSJ6kyr8ymY1yVh9VBE/g6\n" + + "fRDYA+pkqKnw9wfH2Qho3ysAA+OmVOX8Hldg+Pc0Zs0e5pCavb0En8iFLvTA0Q2E\n" + + "LR5rLue9uD7aFuKFU/VdcddY9Ww/vo4k5p/tVGp7F8RYCFn9rSjIWbfvvZi1q5Tx\n" + + "+akoZbga+4qQ4WYzB/obdX6SCmi6BndcQ1QdjCCQU6gpYx0MddVERbIp9+2SXDyL\n" + + "hpxjSyz+RGsZi/9UAshT4txP4+MZBgDfK3ZqtW+h2/eMRxkANqOJpxSjMyLO/FXN\n" + + "WxzTDYeWtHNYiAlOwlQZEPOydZFty9IVzzNFQCIUCGjQ/nNyhw7adSgUk3+BXEx/\n" + + "MyJPYY0BYuhLxLYcrfQ9nrhaVKxRJj25SVHj2ASsiwGJRZW4CC3uw40OYxfKEvNC\n" + + "mer/VxM3kg8qqGf9KUzJ1dVdAvjyx2Hz6jY2qWCyRQ6IMjWHyd43C4r3jxooYKUC\n" + + "YnstRQyb/gCSKahveSEjo07CiXMr88UGALwzEr3npFAsPW3osGaFLj49y1oRe11E\n" + + "he9gCHFm+fuzbXrWmdPjYU5/ZdqdojzDqfu4ThfnipknpVUM1o6MQqkjM896FHm8\n" + + "zbKVFSMhEP6DPHSCexMFrrSgN03PdwHTO6iBaIBBFqmGY01tmJ03SxvSpiBPON9P\n" + + "NVvy/6UZFedTq8A07OUAxO62YUSNtT5pmK2vzs3SAZJmbFbMh+NN204TRI72GlqT\n" + + "t5hcfkuv8hrmwPS/ZR6q312mKQ6w/1pqO9qizSFCb2IgQmFiYmFnZSA8Ym9iQG9w\n" + + "ZW5wZ3AuZXhhbXBsZT7CwQ4EEwEKADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgEC\n" + + "F4AWIQTRpm4aI7GCyZgPeIz7/MgqAV5zMAUCXaWe+gAKCRD7/MgqAV5zMG9sC/9U\n" + + "2T3RrqEbw533FPNfEflhEVRIZ8gDXKM8hU6cqqEzCmzZT6xYTe6sv4y+PJBGXJFX\n" + + "yhj0g6FDkSyboM5litOcTupURObVqMgA/Y4UKERznm4fzzH9qek85c4ljtLyNufe\n" + + "doL2pp3vkGtn7eD0QFRaLLmnxPKQ/TlZKdLE1G3u8Uot8QHicaR6GnAdc5UXQJE3\n" + + "BiV7jZuDyWmZ1cUNwJkKL6oRtp+ZNDOQCrLNLecKHcgCqrpjSQG5oouba1I1Q6Vl\n" + + "sP44dhA1nkmLHtxlTOzpeHj4jnk1FaXmyasurrrI5CgU/L2Oi39DGKTH/A/cywDN\n" + + "4ZplIQ9zR8enkbXquUZvFDe+Xz+6xRXtb5MwQyWODB3nHw85HocLwRoIN9WdQEI+\n" + + "L8a/56AuOwhs8llkSuiITjR7r9SgKJC2WlAHl7E8lhJ3VDW3ELC56KH308d6mwOG\n" + + "ZRAqIAKzM1T5FGjMBhq7ZV0eqdEntBh3EcOIfj2M8rg1MzJv+0mHZOIjByawikbH\n" + + "xJgEXaWc8gEMANYwv1xsYyunXYK0X1vY/rP1NNPvhLyLIE7NpK90YNBj+xS1ldGD\n" + + "bUdZqZeef2xJe8gMQg05DoD1DF3GipZ0Ies65beh+d5hegb7N4pzh0LzrBrVNHar\n" + + "29b5ExdI7i4iYD5TO6Vr/qTUOiAN/byqELEzAb+L+b2DVz/RoCm4PIp1DU9ewcc2\n" + + "WB38Ofqut3nLYA5tqJ9XvAiEQme+qAVcM3ZFcaMt4I4dXhDZZNg+D9LiTWcxdUPB\n" + + "leu8iwDRjAgyAhPzpFp+nWoqWA81uIiULWD1Fj+IVoY3ZvgivoYOiEFBJ9lbb4te\n" + + "g9m5UT/AaVDTWuHzbspVlbiVe+qyB77C2daWzNyx6UYBPLOo4r0t0c91kbNE5lgj\n" + + "Z7xz6los0N1U8vq91EFSeQJoSQ62XWavYmlCLmdNT6BNfgh4icLsT7Vr1QMX9jzn\n" + + "JtTPxdXytSdHvpSpULsqJ016l0dtmONcK3z9mj5N5z0k1tg1AH970TGYOe2aUcSx\n" + + "IRDMXDOPyzEfjwARAQABAAv9F2CwsjS+Sjh1M1vegJbZjei4gF1HHpEM0K0PSXsp\n" + + "SfVvpR4AoSJ4He6CXSMWg0ot8XKtDuZoV9jnJaES5UL9pMAD7JwIOqZm/DYVJM5h\n" + + "OASCh1c356/wSbFbzRHPtUdZO9Q30WFNJM5pHbCJPjtNoRmRGkf71RxtvHBzy7np\n" + + "Ga+W6U/NVKHw0i0CYwMI0YlKDakYW3Pm+QL+gHZFvngGweTod0f9l2VLLAmeQR/c\n" + + "+EZs7lNumhuZ8mXcwhUc9JQIhOkpO+wreDysEFkAcsKbkQP3UDUsA1gFx9pbMzT0\n" + + "tr1oZq2a4QBtxShHzP/ph7KLpN+6qtjks3xB/yjTgaGmtrwM8tSe0wD1RwXS+/1o\n" + + "BHpXTnQ7TfeOGUAu4KCoOQLv6ELpKWbRBLWuiPwMdbGpvVFALO8+kvKAg9/r+/ny\n" + + "zM2GQHY+J3Jh5JxPiJnHfXNZjIKLbFbIPdSKNyJBuazXW8xIa//mEHMI5OcvsZBK\n" + + "clAIp7LXzjEjKXIwHwDcTn9pBgDpdOKTHOtJ3JUKx0rWVsDH6wq6iKV/FTVSY5jl\n" + + "zN+puOEsskF1Lfxn9JsJihAVO3yNsp6RvkKtyNlFazaCVKtDAmkjoh60XNxcNRqr\n" + + "gCnwdpbgdHP6v/hvZY54ZaJjz6L2e8unNEkYLxDt8cmAyGPgH2XgL7giHIp9jrsQ\n" + + "aS381gnYwNX6wE1aEikgtY91nqJjwPlibF9avSyYQoMtEqM/1UjTjB2KdD/MitK5\n" + + "fP0VpvuXpNYZedmyq4UOMwdkiNMGAOrfmOeT0olgLrTMT5H97Cn3Yxbk13uXHNu/\n" + + "ZUZZNe8s+QtuLfUlKAJtLEUutN33TlWQY522FV0m17S+b80xJib3yZVJteVurrh5\n" + + "HSWHAM+zghQAvCesg5CLXa2dNMkTCmZKgCBvfDLZuZbjFwnwCI6u/NhOY9egKuUf\n" + + "SA/je/RXaT8m5VxLYMxwqQXKApzD87fv0tLPlVIEvjEsaf992tFEFSNPcG1l/jpd\n" + + "5AVXw6kKuf85UkJtYR1x2MkQDrqY1QX/XMw00kt8y9kMZUre19aCArcmor+hDhRJ\n" + + "E3Gt4QJrD9z/bICESw4b4z2DbgD/Xz9IXsA/r9cKiM1h5QMtXvuhyfVeM01enhxM\n" + + "GbOH3gjqqGNKysx0UODGEwr6AV9hAd8RWXMchJLaExK9J5SRawSg671ObAU24SdY\n" + + "vMQ9Z4kAQ2+1ReUZzf3ogSMRZtMT+d18gT6L90/y+APZIaoArLPhebIAGq39HLmJ\n" + + "26x3z0WAgrpA1kNsjXEXkoiZGPLKIGoe3hrCwPYEGAEKACAWIQTRpm4aI7GCyZgP\n" + + "eIz7/MgqAV5zMAUCXaWc8gIbDAAKCRD7/MgqAV5zMOn/C/9ugt+HZIwX308zI+QX\n" + + "c5vDLReuzmJ3ieE0DMO/uNSC+K1XEioSIZP91HeZJ2kbT9nn9fuReuoff0T0Dief\n" + + "rbwcIQQHFFkrqSp1K3VWmUGp2JrUsXFVdjy/fkBIjTd7c5boWljv/6wAsSfiv2V0\n" + + "JSM8EFU6TYXxswGjFVfc6X97tJNeIrXL+mpSmPPqy2bztcCCHkWS5lNLWQw+R7Vg\n" + + "71Fe6yBSNVrqC2/imYG2J9zlowjx1XU63Wdgqp2Wxt0l8OmsB/W80S1fRF5G4SDH\n" + + "s9HXglXXqPsBRZJYfP+VStm9L5P/sKjCcX6WtZR7yS6G8zj/X767MLK/djANvpPd\n" + + "NVniEke6hM3CNBXYPAMhQBMWhCulcoz+0lxi8L34rMN+Dsbma96psdUrn7uLaB91\n" + + "6we0CTfF8qqm7BsVAgalon/UUiuMY80U3ueoj3okiSTiHIjD/YtpXSPioC8nMng7\n" + + "xqAY9Bwizt4FWgXuLm1a4+So4V9j1TRCXd12Uc2l2RNmgDE=\n" + + "=FAzO\n" + + "-----END PGP PRIVATE KEY BLOCK-----\n"; + /** + * Bob's RSA-3072 OpenPGP v4 Certificate. + * @see + * Bob's OpenPGP Certificate + */ + public static final String BOB_CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + + "Comment: D1A6 6E1A 23B1 82C9 980F 788C FBFC C82A 015E 7330\n" + + "Comment: Bob Babbage \n" + + "\n" + + "xsDNBF2lnPIBDAC5cL9PQoQLTMuhjbYvb4Ncuuo0bfmgPRFywX53jPhoFf4Zg6mv\n" + + "/seOXpgecTdOcVttfzC8ycIKrt3aQTiwOG/ctaR4Bk/t6ayNFfdUNxHWk4WCKzdz\n" + + "/56fW2O0F23qIRd8UUJp5IIlN4RDdRCtdhVQIAuzvp2oVy/LaS2kxQoKvph/5pQ/\n" + + "5whqsyroEWDJoSV0yOb25B/iwk/pLUFoyhDG9bj0kIzDxrEqW+7Ba8nocQlecMF3\n" + + "X5KMN5kp2zraLv9dlBBpWW43XktjcCZgMy20SouraVma8Je/ECwUWYUiAZxLIlMv\n" + + "9CurEOtxUw6N3RdOtLmYZS9uEnn5y1UkF88o8Nku890uk6BrewFzJyLAx5wRZ4F0\n" + + "qV/yq36UWQ0JB/AUGhHVPdFf6pl6eaxBwT5GXvbBUibtf8YI2og5RsgTWtXfU7eb\n" + + "SGXrl5ZMpbA6mbfhd0R8aPxWfmDWiIOhBufhMCvUHh1sApMKVZnvIff9/0Dca3wb\n" + + "vLIwa3T4CyshfT0AEQEAAc0hQm9iIEJhYmJhZ2UgPGJvYkBvcGVucGdwLmV4YW1w\n" + + "bGU+wsEOBBMBCgA4AhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE0aZuGiOx\n" + + "gsmYD3iM+/zIKgFeczAFAl2lnvoACgkQ+/zIKgFeczBvbAv/VNk90a6hG8Od9xTz\n" + + "XxH5YRFUSGfIA1yjPIVOnKqhMwps2U+sWE3urL+MvjyQRlyRV8oY9IOhQ5Esm6DO\n" + + "ZYrTnE7qVETm1ajIAP2OFChEc55uH88x/anpPOXOJY7S8jbn3naC9qad75BrZ+3g\n" + + "9EBUWiy5p8TykP05WSnSxNRt7vFKLfEB4nGkehpwHXOVF0CRNwYle42bg8lpmdXF\n" + + "DcCZCi+qEbafmTQzkAqyzS3nCh3IAqq6Y0kBuaKLm2tSNUOlZbD+OHYQNZ5Jix7c\n" + + "ZUzs6Xh4+I55NRWl5smrLq66yOQoFPy9jot/Qxikx/wP3MsAzeGaZSEPc0fHp5G1\n" + + "6rlGbxQ3vl8/usUV7W+TMEMljgwd5x8POR6HC8EaCDfVnUBCPi/Gv+egLjsIbPJZ\n" + + "ZEroiE40e6/UoCiQtlpQB5exPJYSd1Q1txCwueih99PHepsDhmUQKiACszNU+RRo\n" + + "zAYau2VdHqnRJ7QYdxHDiH49jPK4NTMyb/tJh2TiIwcmsIpGzsDNBF2lnPIBDADW\n" + + "ML9cbGMrp12CtF9b2P6z9TTT74S8iyBOzaSvdGDQY/sUtZXRg21HWamXnn9sSXvI\n" + + "DEINOQ6A9QxdxoqWdCHrOuW3ofneYXoG+zeKc4dC86wa1TR2q9vW+RMXSO4uImA+\n" + + "Uzula/6k1DogDf28qhCxMwG/i/m9g1c/0aApuDyKdQ1PXsHHNlgd/Dn6rrd5y2AO\n" + + "baifV7wIhEJnvqgFXDN2RXGjLeCOHV4Q2WTYPg/S4k1nMXVDwZXrvIsA0YwIMgIT\n" + + "86Rafp1qKlgPNbiIlC1g9RY/iFaGN2b4Ir6GDohBQSfZW2+LXoPZuVE/wGlQ01rh\n" + + "827KVZW4lXvqsge+wtnWlszcselGATyzqOK9LdHPdZGzROZYI2e8c+paLNDdVPL6\n" + + "vdRBUnkCaEkOtl1mr2JpQi5nTU+gTX4IeInC7E+1a9UDF/Y85ybUz8XV8rUnR76U\n" + + "qVC7KidNepdHbZjjXCt8/Zo+Tec9JNbYNQB/e9ExmDntmlHEsSEQzFwzj8sxH48A\n" + + "EQEAAcLA9gQYAQoAIBYhBNGmbhojsYLJmA94jPv8yCoBXnMwBQJdpZzyAhsMAAoJ\n" + + "EPv8yCoBXnMw6f8L/26C34dkjBffTzMj5Bdzm8MtF67OYneJ4TQMw7+41IL4rVcS\n" + + "KhIhk/3Ud5knaRtP2ef1+5F66h9/RPQOJ5+tvBwhBAcUWSupKnUrdVaZQanYmtSx\n" + + "cVV2PL9+QEiNN3tzluhaWO//rACxJ+K/ZXQlIzwQVTpNhfGzAaMVV9zpf3u0k14i\n" + + "tcv6alKY8+rLZvO1wIIeRZLmU0tZDD5HtWDvUV7rIFI1WuoLb+KZgbYn3OWjCPHV\n" + + "dTrdZ2CqnZbG3SXw6awH9bzRLV9EXkbhIMez0deCVdeo+wFFklh8/5VK2b0vk/+w\n" + + "qMJxfpa1lHvJLobzOP9fvrswsr92MA2+k901WeISR7qEzcI0Fdg8AyFAExaEK6Vy\n" + + "jP7SXGLwvfisw34OxuZr3qmx1Sufu4toH3XrB7QJN8XyqqbsGxUCBqWif9RSK4xj\n" + + "zRTe56iPeiSJJOIciMP9i2ldI+KgLycyeDvGoBj0HCLO3gVaBe4ubVrj5KjhX2PV\n" + + "NEJd3XZRzaXZE2aAMQ==\n" + + "=F9yX\n" + + "-----END PGP PUBLIC KEY BLOCK-----\n"; + /** + * Bob's RSA-3072 Revocation Certificate. + * @see + * Bob's Revocation Certificate + */ + public static final String BOB_REVOCATION_CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + + "Comment: Bob's revocation certificate\n" + + "Comment: https://www.ietf.org/id/draft-bre-openpgp-samples-01.html\n" + + "\n" + + "iQG2BCABCgAgFiEE0aZuGiOxgsmYD3iM+/zIKgFeczAFAl2lnQQCHQAACgkQ+/zI\n" + + "KgFeczAIHAv/RrlGlPFKsW0BShC8sVtPfbT1N9lUqyrsgBhrUryM/i+rBtkbnSjp\n" + + "28R5araupt0og1g2L5VsCRM+ql0jf0zrZXOorKfAO70HCP3X+MlEquvztMUZGJRZ\n" + + "7TSMgIY1MeFgLmOw9pDKf3tSoouBOpPe5eVfXviEDDo2zOfdntjPyCMlxHgAcjZo\n" + + "XqMaurV+nKWoIx0zbdpNLsRy4JZcmnOSFdPw37R8U2miPi2qNyVwcyCxQy0LjN7Y\n" + + "AWadrs9vE0DrneSVP2OpBhl7g+Dj2uXJQRPVXcq6w9g5Fir6DnlhekTLsa78T5cD\n" + + "n8q7aRusMlALPAOosENOgINgsVcjuILkPN1eD+zGAgHgdiKaep1+P3pbo5n0CLki\n" + + "UCAsLnCEo8eBV9DCb/n1FlI5yhQhgQyMYlp/49H0JSc3IY9KHhv6f0zIaRWs0JuD\n" + + "ajcXTJ9AyB+SA6GBb9Q+XsNXjZ1gj75ekUD1sQ3ezTvVfovgP5bD+vPvILhSImKB\n" + + "aU6V3zld/x/1\n" + + "=mMwU\n" + + "-----END PGP PUBLIC KEY BLOCK-----"; + + /** + * Carol's OpenPGP v4 key. + */ + public static final String CAROL_KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + + "\n" + + "xcQTBF3+CmgRDADZhdKTM3ms3XpXnQke83FgaIBtP1g1qhqpCfg50WiPS0kjiMC0\n" + + "OJz2vh59nusbBLzgI//Y1VMhKfIWYbqMcIY+lWbseHjl52rqW6AaJ0TH4NgVt7vh\n" + + "yVeJt0k/NnxvNhMd0587KXmfpDxrwBqc/l5cVB+p0rL8vs8kxojHXAi5V3koM0Uj\n" + + "REWs5Jpj/XU9LhEoyXZkeJC/pes1u6UKoFYn7dFIP49Kkd1kb+1bNfdPYtA0JpcG\n" + + "zYgeMNOvdWJwn43dNhxoeuXfmAEhA8LdzT0C0O+7akXOKWrfhXJ8MTBqvPgWZYx7\n" + + "MNuQx/ejIMZHl+Iaf7hG976ILH+NCGiKkhidd9GIuA/WteHiQbXLyfiQ4n8P12q9\n" + + "+4dq6ybUM65tnozRyyN+1m3rU2a/+Ly3JCh4TeO27w+cxMWkaeHyTQaJVMbMbDpX\n" + + "duVd32MA33UVNH5/KXMVczVi5asVjuKDSojJDV1QwX8izZNl1t+AI0L3balCabV0\n" + + "SFhlfnBEUj1my1sBAMOSO/I67BvBS3IPHZWXHjgclhs26mPzRlZLryAUWR2DDACH\n" + + "5fx+yUAdZ8Vu/2zWTHxwWJ/X6gGTLqa9CmfDq5UDqYFFzuWwN4HJ+ryOuak1CGwS\n" + + "KJUBSA75HExbv0naWg+suy+pEDvF0VALPU9VUkSQtHyR10YO2FWOe3AEtpbYDRwp\n" + + "dr1ZwEbb3L6IGQ5i/4CNHbJ2u3yUeXsDNAvrpVSEcIjA01RPCOKmf58SDZp4yDdP\n" + + "xGhM8w6a18+fdQr22f2cJ0xgfPlbzFbO+FUsEgKvn6QTLhbaYw4zs7rdQDejWHV8\n" + + "2hP4K+rb9FwknYdV9uo4m77MgGlU+4yvJnGEYaL3jwjI3bH9aooNOl6XbvVAzNzo\n" + + "mYmaTO7mp6xFAu43yuGyd9K+1E4k7CQTROxTZ+RdtQjV95hSsEmMg792nQvDSBW4\n" + + "xwfOQ7pf3kC7r9fm8u9nBlEN12HsbQ8Yvux/ld5q5RaIlD19jzfVR6+hJzbj2ZnU\n" + + "yQs4ksAfIHTzTdLttRxS9lTRTkVx2vbUnoSBy6TYF1mf6nRPpSm1riZxnkR4+BQL\n" + + "/0rUAxwegTNIG/5M612s2a45QvYK1turZ7spI1RGitJUIjBXUuR76jIsyqagIhBl\n" + + "5nEsQ4HLv8OQ3EgJ5T9gldLFpHNczLxBQnnNwfPoD2e0kC/iy0rfiNX8HWpTgQpb\n" + + "zAosLj5/E0iNlildynIhuqBosyRWFqGva0O6qioL90srlzlfKCloe9R9w3HizjCb\n" + + "f59yEspuJt9iHVNOPOW2Wj5ub0KTiJPp9vBmrFaB79/IlgojpQoYvQ77Hx5A9CJq\n" + + "paMCHGOW6Uz9euN1ozzETEkIPtL8XAxcogfpe2JKE1uS7ugxsKEGEDfxOQFKAGV0\n" + + "XFtIx50vFCr2vQro0WB858CGN47dCxChhNUxNtGc11JNEkNv/X7hKtRf/5VCmnaz\n" + + "GWwNK47cqZ7GJfEBnElD7s/tQvTC5Qp7lg9gEt47TUX0bjzUTCxNvLosuKL9+J1W\n" + + "ln1myRpff/5ZOAnZTPHR+AbX4bRB4sK5zijQe4139Dn2oRYK+EIYoBAxFxSOzehP\n" + + "IQAA/2BCN5HryGjVff2t7Q6fVrQQS9hsMisszZl5rWwUOO6zETHCigQfEQgAPAUC\n" + + "Xf4KaQMLCQoJEJunidx21oSaBBUKCQgCFgECF4ACGwMCHgEWIQRx/9oARAnl3bDD\n" + + "6PGbp4ncdtaEmgAAYoUA/1VpxdR2wYT/pC8FrKsbmIxLJRLDNlED3ihivWp/B2e/\n" + + "AQCT2oi9zqbjprCKAnzoIYTGTil4yFfmeey8GjMOxUHz4M0mQ2Fyb2wgT2xkc3R5\n" + + "bGUgPGNhcm9sQG9wZW5wZ3AuZXhhbXBsZT7CigQTEQgAPAUCXf4KaQMLCQoJEJun\n" + + "idx21oSaBBUKCQgCFgECF4ACGwMCHgEWIQRx/9oARAnl3bDD6PGbp4ncdtaEmgAA\n" + + "UEwA/2TFwL0mymjCSaQH8KdQuygI+itpNggM+Y8FF8hn9fo1AP9ogDIl9V3C8t59\n" + + "C/Mrc4HvP1ABR2nwZeK5+A5lLoH4Y8fD8QRd/gpoEAwA2YXSkzN5rN16V50JHvNx\n" + + "YGiAbT9YNaoaqQn4OdFoj0tJI4jAtDic9r4efZ7rGwS84CP/2NVTISnyFmG6jHCG\n" + + "PpVm7Hh45edq6lugGidEx+DYFbe74clXibdJPzZ8bzYTHdOfOyl5n6Q8a8AanP5e\n" + + "XFQfqdKy/L7PJMaIx1wIuVd5KDNFI0RFrOSaY/11PS4RKMl2ZHiQv6XrNbulCqBW\n" + + "J+3RSD+PSpHdZG/tWzX3T2LQNCaXBs2IHjDTr3VicJ+N3TYcaHrl35gBIQPC3c09\n" + + "AtDvu2pFzilq34VyfDEwarz4FmWMezDbkMf3oyDGR5fiGn+4Rve+iCx/jQhoipIY\n" + + "nXfRiLgP1rXh4kG1y8n4kOJ/D9dqvfuHausm1DOubZ6M0csjftZt61Nmv/i8tyQo\n" + + "eE3jtu8PnMTFpGnh8k0GiVTGzGw6V3blXd9jAN91FTR+fylzFXM1YuWrFY7ig0qI\n" + + "yQ1dUMF/Is2TZdbfgCNC922pQmm1dEhYZX5wRFI9ZstbDACH5fx+yUAdZ8Vu/2zW\n" + + "THxwWJ/X6gGTLqa9CmfDq5UDqYFFzuWwN4HJ+ryOuak1CGwSKJUBSA75HExbv0na\n" + + "Wg+suy+pEDvF0VALPU9VUkSQtHyR10YO2FWOe3AEtpbYDRwpdr1ZwEbb3L6IGQ5i\n" + + "/4CNHbJ2u3yUeXsDNAvrpVSEcIjA01RPCOKmf58SDZp4yDdPxGhM8w6a18+fdQr2\n" + + "2f2cJ0xgfPlbzFbO+FUsEgKvn6QTLhbaYw4zs7rdQDejWHV82hP4K+rb9FwknYdV\n" + + "9uo4m77MgGlU+4yvJnGEYaL3jwjI3bH9aooNOl6XbvVAzNzomYmaTO7mp6xFAu43\n" + + "yuGyd9K+1E4k7CQTROxTZ+RdtQjV95hSsEmMg792nQvDSBW4xwfOQ7pf3kC7r9fm\n" + + "8u9nBlEN12HsbQ8Yvux/ld5q5RaIlD19jzfVR6+hJzbj2ZnUyQs4ksAfIHTzTdLt\n" + + "tRxS9lTRTkVx2vbUnoSBy6TYF1mf6nRPpSm1riZxnkR4+BQL/jEGmn1tLhxfjfDA\n" + + "5vFFj73+FXdFCdFKSI0VpdoU1fgR5DX72ZQUYYUCKYTYikXv1mqdH/5VthptrktC\n" + + "oAco4zVxM04sK7Xthl+uTOhei8/Dd9ZLdSIoNcRjrr/uh5sUzUfIC9iuT3SXiZ/D\n" + + "0yVq0Uu/gWPB3ZIG/sFacxOXAr6RYhvz9MqnwXS1sVT5TyO3XIQ5JseIgIRyV/Sf\n" + + "4F/4Qui9wMzzSajTwCsttMGKf67k228AaJVv+IpFoo+OtCa7wbJukqfNQN3m2ojf\n" + + "V5CcoCzsoRsoTInhrpQmM+gGoQBXBArT1xk3KK3VdZibYfMoxeIGXw0MoNJzFuGK\n" + + "+PcnhV3ETFMNcszd0Pb9s86g7hYtpRmE12Jlai2MzPSmyztlsRP9tcZwYy7JdPZf\n" + + "xXQP24XWat7eP2qWxTnkEP4/wKYb81m7CZ4RvUO/nd1aA5c9IBYknbgmCAAKvHVD\n" + + "iTY61E5GbC9aTiI4WIwjItroikukUJE+p77rpjxfw/1U51BnmQAA/ih5jIthn2ZE\n" + + "r1YoOsUs8CBhylTsRZK6VS4ZCErcyl2tD2LCigQYEQgAPAUCXf4KaQMLCQoJEJun\n" + + "idx21oSaBBUKCQgCFgECF4ACGwwCHgEWIQRx/9oARAnl3bDD6PGbp4ncdtaEmgAA\n" + + "QSkA/3WEWqZxvZmpVxpEMxJWaGQRwUhGake8OhC1WfywCtarAQCLwfBsyEv5jBEi\n" + + "1FkOSekLi8WNMdUx3XMyvP8nJ65P2Q==\n" + + "=Xj8h\n" + + "-----END PGP PRIVATE KEY BLOCK-----\n"; + /** + * Carol's OpenPGP v4 certificate. + */ + public static final String CAROL_CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + + "\n" + + "xsPuBF3+CmgRDADZhdKTM3ms3XpXnQke83FgaIBtP1g1qhqpCfg50WiPS0kjiMC0\n" + + "OJz2vh59nusbBLzgI//Y1VMhKfIWYbqMcIY+lWbseHjl52rqW6AaJ0TH4NgVt7vh\n" + + "yVeJt0k/NnxvNhMd0587KXmfpDxrwBqc/l5cVB+p0rL8vs8kxojHXAi5V3koM0Uj\n" + + "REWs5Jpj/XU9LhEoyXZkeJC/pes1u6UKoFYn7dFIP49Kkd1kb+1bNfdPYtA0JpcG\n" + + "zYgeMNOvdWJwn43dNhxoeuXfmAEhA8LdzT0C0O+7akXOKWrfhXJ8MTBqvPgWZYx7\n" + + "MNuQx/ejIMZHl+Iaf7hG976ILH+NCGiKkhidd9GIuA/WteHiQbXLyfiQ4n8P12q9\n" + + "+4dq6ybUM65tnozRyyN+1m3rU2a/+Ly3JCh4TeO27w+cxMWkaeHyTQaJVMbMbDpX\n" + + "duVd32MA33UVNH5/KXMVczVi5asVjuKDSojJDV1QwX8izZNl1t+AI0L3balCabV0\n" + + "SFhlfnBEUj1my1sBAMOSO/I67BvBS3IPHZWXHjgclhs26mPzRlZLryAUWR2DDACH\n" + + "5fx+yUAdZ8Vu/2zWTHxwWJ/X6gGTLqa9CmfDq5UDqYFFzuWwN4HJ+ryOuak1CGwS\n" + + "KJUBSA75HExbv0naWg+suy+pEDvF0VALPU9VUkSQtHyR10YO2FWOe3AEtpbYDRwp\n" + + "dr1ZwEbb3L6IGQ5i/4CNHbJ2u3yUeXsDNAvrpVSEcIjA01RPCOKmf58SDZp4yDdP\n" + + "xGhM8w6a18+fdQr22f2cJ0xgfPlbzFbO+FUsEgKvn6QTLhbaYw4zs7rdQDejWHV8\n" + + "2hP4K+rb9FwknYdV9uo4m77MgGlU+4yvJnGEYaL3jwjI3bH9aooNOl6XbvVAzNzo\n" + + "mYmaTO7mp6xFAu43yuGyd9K+1E4k7CQTROxTZ+RdtQjV95hSsEmMg792nQvDSBW4\n" + + "xwfOQ7pf3kC7r9fm8u9nBlEN12HsbQ8Yvux/ld5q5RaIlD19jzfVR6+hJzbj2ZnU\n" + + "yQs4ksAfIHTzTdLttRxS9lTRTkVx2vbUnoSBy6TYF1mf6nRPpSm1riZxnkR4+BQL\n" + + "/0rUAxwegTNIG/5M612s2a45QvYK1turZ7spI1RGitJUIjBXUuR76jIsyqagIhBl\n" + + "5nEsQ4HLv8OQ3EgJ5T9gldLFpHNczLxBQnnNwfPoD2e0kC/iy0rfiNX8HWpTgQpb\n" + + "zAosLj5/E0iNlildynIhuqBosyRWFqGva0O6qioL90srlzlfKCloe9R9w3HizjCb\n" + + "f59yEspuJt9iHVNOPOW2Wj5ub0KTiJPp9vBmrFaB79/IlgojpQoYvQ77Hx5A9CJq\n" + + "paMCHGOW6Uz9euN1ozzETEkIPtL8XAxcogfpe2JKE1uS7ugxsKEGEDfxOQFKAGV0\n" + + "XFtIx50vFCr2vQro0WB858CGN47dCxChhNUxNtGc11JNEkNv/X7hKtRf/5VCmnaz\n" + + "GWwNK47cqZ7GJfEBnElD7s/tQvTC5Qp7lg9gEt47TUX0bjzUTCxNvLosuKL9+J1W\n" + + "ln1myRpff/5ZOAnZTPHR+AbX4bRB4sK5zijQe4139Dn2oRYK+EIYoBAxFxSOzehP\n" + + "IcKKBB8RCAA8BQJd/gppAwsJCgkQm6eJ3HbWhJoEFQoJCAIWAQIXgAIbAwIeARYh\n" + + "BHH/2gBECeXdsMPo8Zunidx21oSaAABihQD/VWnF1HbBhP+kLwWsqxuYjEslEsM2\n" + + "UQPeKGK9an8HZ78BAJPaiL3OpuOmsIoCfOghhMZOKXjIV+Z57LwaMw7FQfPgzSZD\n" + + "YXJvbCBPbGRzdHlsZSA8Y2Fyb2xAb3BlbnBncC5leGFtcGxlPsKKBBMRCAA8BQJd\n" + + "/gppAwsJCgkQm6eJ3HbWhJoEFQoJCAIWAQIXgAIbAwIeARYhBHH/2gBECeXdsMPo\n" + + "8Zunidx21oSaAABQTAD/ZMXAvSbKaMJJpAfwp1C7KAj6K2k2CAz5jwUXyGf1+jUA\n" + + "/2iAMiX1XcLy3n0L8ytzge8/UAFHafBl4rn4DmUugfhjzsPMBF3+CmgQDADZhdKT\n" + + "M3ms3XpXnQke83FgaIBtP1g1qhqpCfg50WiPS0kjiMC0OJz2vh59nusbBLzgI//Y\n" + + "1VMhKfIWYbqMcIY+lWbseHjl52rqW6AaJ0TH4NgVt7vhyVeJt0k/NnxvNhMd0587\n" + + "KXmfpDxrwBqc/l5cVB+p0rL8vs8kxojHXAi5V3koM0UjREWs5Jpj/XU9LhEoyXZk\n" + + "eJC/pes1u6UKoFYn7dFIP49Kkd1kb+1bNfdPYtA0JpcGzYgeMNOvdWJwn43dNhxo\n" + + "euXfmAEhA8LdzT0C0O+7akXOKWrfhXJ8MTBqvPgWZYx7MNuQx/ejIMZHl+Iaf7hG\n" + + "976ILH+NCGiKkhidd9GIuA/WteHiQbXLyfiQ4n8P12q9+4dq6ybUM65tnozRyyN+\n" + + "1m3rU2a/+Ly3JCh4TeO27w+cxMWkaeHyTQaJVMbMbDpXduVd32MA33UVNH5/KXMV\n" + + "czVi5asVjuKDSojJDV1QwX8izZNl1t+AI0L3balCabV0SFhlfnBEUj1my1sMAIfl\n" + + "/H7JQB1nxW7/bNZMfHBYn9fqAZMupr0KZ8OrlQOpgUXO5bA3gcn6vI65qTUIbBIo\n" + + "lQFIDvkcTFu/SdpaD6y7L6kQO8XRUAs9T1VSRJC0fJHXRg7YVY57cAS2ltgNHCl2\n" + + "vVnARtvcvogZDmL/gI0dsna7fJR5ewM0C+ulVIRwiMDTVE8I4qZ/nxINmnjIN0/E\n" + + "aEzzDprXz591CvbZ/ZwnTGB8+VvMVs74VSwSAq+fpBMuFtpjDjOzut1AN6NYdXza\n" + + "E/gr6tv0XCSdh1X26jibvsyAaVT7jK8mcYRhovePCMjdsf1qig06Xpdu9UDM3OiZ\n" + + "iZpM7uanrEUC7jfK4bJ30r7UTiTsJBNE7FNn5F21CNX3mFKwSYyDv3adC8NIFbjH\n" + + "B85Dul/eQLuv1+by72cGUQ3XYextDxi+7H+V3mrlFoiUPX2PN9VHr6EnNuPZmdTJ\n" + + "CziSwB8gdPNN0u21HFL2VNFORXHa9tSehIHLpNgXWZ/qdE+lKbWuJnGeRHj4FAv+\n" + + "MQaafW0uHF+N8MDm8UWPvf4Vd0UJ0UpIjRWl2hTV+BHkNfvZlBRhhQIphNiKRe/W\n" + + "ap0f/lW2Gm2uS0KgByjjNXEzTiwrte2GX65M6F6Lz8N31kt1Iig1xGOuv+6HmxTN\n" + + "R8gL2K5PdJeJn8PTJWrRS7+BY8Hdkgb+wVpzE5cCvpFiG/P0yqfBdLWxVPlPI7dc\n" + + "hDkmx4iAhHJX9J/gX/hC6L3AzPNJqNPAKy20wYp/ruTbbwBolW/4ikWij460JrvB\n" + + "sm6Sp81A3ebaiN9XkJygLOyhGyhMieGulCYz6AahAFcECtPXGTcordV1mJth8yjF\n" + + "4gZfDQyg0nMW4Yr49yeFXcRMUw1yzN3Q9v2zzqDuFi2lGYTXYmVqLYzM9KbLO2Wx\n" + + "E/21xnBjLsl09l/FdA/bhdZq3t4/apbFOeQQ/j/AphvzWbsJnhG9Q7+d3VoDlz0g\n" + + "FiSduCYIAAq8dUOJNjrUTkZsL1pOIjhYjCMi2uiKS6RQkT6nvuumPF/D/VTnUGeZ\n" + + "wooEGBEIADwFAl3+CmkDCwkKCRCbp4ncdtaEmgQVCgkIAhYBAheAAhsMAh4BFiEE\n" + + "cf/aAEQJ5d2ww+jxm6eJ3HbWhJoAAEEpAP91hFqmcb2ZqVcaRDMSVmhkEcFIRmpH\n" + + "vDoQtVn8sArWqwEAi8HwbMhL+YwRItRZDknpC4vFjTHVMd1zMrz/JyeuT9k=\n" + + "=pa/S\n" + + "-----END PGP PUBLIC KEY BLOCK-----\n"; + + /** + * Minimal OpenPGP v6 key. + * @see + * Sample Version 6 Secret Key + */ + public static final String V6_KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + + "\n" + + "xUsGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laMAGXKB\n" + + "exK+cH6NX1hs5hNhIB00TrJmosgv3mg1ditlsLfCsQYfGwoAAABCBYJjh3/jAwsJ\n" + + "BwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6\n" + + "2azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lwgyU2kCcUmKfvBXbAf6rh\n" + + "RYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaEQsiPlR4zxP/TP7mhfVEe\n" + + "7XWPxtnMUMtf15OyA51YBMdLBmOHf+MZAAAAIIaTJINn+eUBXbki+PSAld2nhJh/\n" + + "LVmFsS+60WyvXkQ1AE1gCk95TUR3XFeibg/u/tVY6a//1q0NWC1X+yui3O24wpsG\n" + + "GBsKAAAALAWCY4d/4wKbDCIhBssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce6\n" + + "2azJAAAAAAQBIKbpGG2dWTX8j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDE\n" + + "M0g12vYxoWM8Y81W+bHBw805I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUr\n" + + "k0mXubZvyl4GBg==\n" + + "-----END PGP PRIVATE KEY BLOCK-----"; + /** + * Locked, minimal OpenPGP v6 key. + * @see + * Sample Locked Version 6 Secret Key + */ + public static final String V6_KEY_LOCKED = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + + "\n" + + "xYIGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laP9JgkC\n" + + "FARdb9ccngltHraRe25uHuyuAQQVtKipJ0+r5jL4dacGWSAheCWPpITYiyfyIOPS\n" + + "3gIDyg8f7strd1OB4+LZsUhcIjOMpVHgmiY/IutJkulneoBYwrEGHxsKAAAAQgWC\n" + + "Y4d/4wMLCQcFFQoOCAwCFgACmwMCHgkiIQbLGGxPBgmml+TVLfpscisMHx4nwYpW\n" + + "cI9lJewnutmsyQUnCQIHAgAAAACtKCAQPi19In7A5tfORHHbNr/JcIMlNpAnFJin\n" + + "7wV2wH+q4UWFs7kDsBJ+xP2i8CMEWi7Ha8tPlXGpZR4UruETeh1mhELIj5UeM8T/\n" + + "0z+5oX1RHu11j8bZzFDLX9eTsgOdWATHggZjh3/jGQAAACCGkySDZ/nlAV25Ivj0\n" + + "gJXdp4SYfy1ZhbEvutFsr15ENf0mCQIUBA5hhGgp2oaavg6mFUXcFMwBBBUuE8qf\n" + + "9Ock+xwusd+GAglBr5LVyr/lup3xxQvHXFSjjA2haXfoN6xUGRdDEHI6+uevKjVR\n" + + "v5oAxgu7eJpaXNjCmwYYGwoAAAAsBYJjh3/jApsMIiEGyxhsTwYJppfk1S36bHIr\n" + + "DB8eJ8GKVnCPZSXsJ7rZrMkAAAAABAEgpukYbZ1ZNfyP5WMUzbUnSGpaUSD5t2Ki\n" + + "Nacp8DkBClZRa2c3AMQzSDXa9jGhYzxjzVb5scHDzTkjyRZWRdTq8U6L4da+/+Kt\n" + + "ruh8m7Xo2ehSSFyWRSuTSZe5tm/KXgYG\n" + + "-----END PGP PRIVATE KEY BLOCK-----"; + /** + * Passphrase to unlock {@link #V6_KEY_LOCKED} with. + */ + public static final String V6_KEY_LOCKED_PASSPHRASE = "correct horse battery staple"; + /** + * Sample Version 6 Certificate. + * @see + * Sample Version 6 Certificate + */ + public static final String V6_CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + + "\n" + + "xioGY4d/4xsAAAAg+U2nu0jWCmHlZ3BqZYfQMxmZu52JGggkLq2EVD34laPCsQYf\n" + + "GwoAAABCBYJjh3/jAwsJBwUVCg4IDAIWAAKbAwIeCSIhBssYbE8GCaaX5NUt+mxy\n" + + "KwwfHifBilZwj2Ul7Ce62azJBScJAgcCAAAAAK0oIBA+LX0ifsDm185Ecds2v8lw\n" + + "gyU2kCcUmKfvBXbAf6rhRYWzuQOwEn7E/aLwIwRaLsdry0+VcallHhSu4RN6HWaE\n" + + "QsiPlR4zxP/TP7mhfVEe7XWPxtnMUMtf15OyA51YBM4qBmOHf+MZAAAAIIaTJINn\n" + + "+eUBXbki+PSAld2nhJh/LVmFsS+60WyvXkQ1wpsGGBsKAAAALAWCY4d/4wKbDCIh\n" + + "BssYbE8GCaaX5NUt+mxyKwwfHifBilZwj2Ul7Ce62azJAAAAAAQBIKbpGG2dWTX8\n" + + "j+VjFM21J0hqWlEg+bdiojWnKfA5AQpWUWtnNwDEM0g12vYxoWM8Y81W+bHBw805\n" + + "I8kWVkXU6vFOi+HWvv/ira7ofJu16NnoUkhclkUrk0mXubZvyl4GBg==\n" + + "-----END PGP PUBLIC KEY BLOCK-----"; + + public static PGPPublicKeyRing readPGPPublicKeyRing(String armor) + throws IOException + { + ByteArrayInputStream bIn = new ByteArrayInputStream(armor.getBytes()); + ArmoredInputStream aIn = new ArmoredInputStream(bIn); + BCPGInputStream pIn = new BCPGInputStream(aIn); + PGPObjectFactory objFac = new BcPGPObjectFactory(pIn); + PGPPublicKeyRing publicKeys = (PGPPublicKeyRing) objFac.nextObject(); + pIn.close(); + aIn.close(); + return publicKeys; + } + + public static PGPSecretKeyRing readPGPSecretKeyRing(String armor) + throws IOException + { + ByteArrayInputStream bIn = new ByteArrayInputStream(armor.getBytes()); + ArmoredInputStream aIn = new ArmoredInputStream(bIn); + BCPGInputStream pIn = new BCPGInputStream(aIn); + PGPObjectFactory objFac = new BcPGPObjectFactory(pIn); + PGPSecretKeyRing secretKeys = (PGPSecretKeyRing) objFac.nextObject(); + pIn.close(); + aIn.close(); + return secretKeys; + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/APITest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/APITest.java new file mode 100644 index 0000000000..2a597d8e9e --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/APITest.java @@ -0,0 +1,32 @@ +package org.bouncycastle.openpgp.api.test; + +import org.bouncycastle.bcpg.test.AbstractPacketTest; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.api.OpenPGPApi; +import org.bouncycastle.openpgp.api.bc.BcOpenPGPApi; +import org.bouncycastle.openpgp.api.jcajce.JcaOpenPGPApi; + +import java.io.IOException; +import java.util.Date; + +public abstract class APITest + extends AbstractPacketTest +{ + @Override + public void performTest() + throws Exception + { + performTestWith(new BcOpenPGPApi()); + performTestWith(new JcaOpenPGPApi(new BouncyCastleProvider())); + } + + public Date currentTimeRounded() + { + Date now = new Date(); + return new Date((now.getTime() / 1000) * 1000); // rounded to seconds + } + + protected abstract void performTestWith(OpenPGPApi api) + throws PGPException, IOException; +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/AllTests.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/AllTests.java new file mode 100644 index 0000000000..7d3004c6ab --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/AllTests.java @@ -0,0 +1,67 @@ +package org.bouncycastle.openpgp.api.test; + +import java.security.Security; + +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.test.PrintTestResult; +import org.bouncycastle.util.test.SimpleTestResult; + +public class AllTests + extends TestCase +{ + public void testAPI() + { + Security.addProvider(new BouncyCastleProvider()); + + org.bouncycastle.util.test.Test[] tests = RegressionTest.tests; + + for (int i = 0; i != tests.length; i++) + { + SimpleTestResult result = (SimpleTestResult)tests[i].perform(); + + if (!result.isSuccessful()) + { + fail(result.toString()); + } + } + } + + + public static void main(String[] args) + { + PrintTestResult.printResult(junit.textui.TestRunner.run(suite())); + } + + public static Test suite() + { + TestSuite suite = new TestSuite("OpenPGP Packet Tests"); + + suite.addTestSuite(AllTests.class); + + return new BCPacketTests(suite); + } + + static class BCPacketTests + extends TestSetup + { + public BCPacketTests(Test test) + { + super(test); + } + + protected void setUp() + { + Security.addProvider(new BouncyCastleProvider()); + } + + protected void tearDown() + { + Security.removeProvider("BC"); + } + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/ChangeKeyPassphraseTest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/ChangeKeyPassphraseTest.java new file mode 100644 index 0000000000..ed24018f57 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/ChangeKeyPassphraseTest.java @@ -0,0 +1,121 @@ +package org.bouncycastle.openpgp.api.test; + +import java.io.IOException; + +import org.bouncycastle.bcpg.SecretKeyPacket; +import org.bouncycastle.openpgp.OpenPGPTestKeys; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.api.OpenPGPApi; +import org.bouncycastle.openpgp.api.OpenPGPKey; + +public class ChangeKeyPassphraseTest + extends APITest +{ + @Override + protected void performTestWith(OpenPGPApi api) + throws PGPException, IOException + { + if (System.getProperty("java.version").indexOf("1.5.") < 0) + { + removeAEADPassphrase(api); + addAEADPassphrase(api); + changeAEADPassphrase(api); + + testChangingCFBPassphrase(api); + } + } + + private void removeAEADPassphrase(OpenPGPApi api) + throws IOException, PGPException { + OpenPGPKey key = api.readKeyOrCertificate() + .parseKey(OpenPGPTestKeys.V6_KEY_LOCKED); + + OpenPGPKey.OpenPGPSecretKey secretKey = key.getPrimarySecretKey(); + isTrue("Expect test key to be locked initially", secretKey.isLocked()); + OpenPGPKey.OpenPGPPrivateKey privateKey = secretKey.unlock(OpenPGPTestKeys.V6_KEY_LOCKED_PASSPHRASE.toCharArray()); + OpenPGPKey.OpenPGPSecretKey unlocked = privateKey.removePassphrase(); + isFalse("Expect key to be unlocked after unlocking - duh", unlocked.isLocked()); + + OpenPGPKey expected = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY); + isEncodingEqual("Expect unlocked key encoding to equal the unprotected test vector", + expected.getPrimarySecretKey().getPGPSecretKey().getEncoded(), + unlocked.getPGPSecretKey().getEncoded()); + } + + private void addAEADPassphrase(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY); + OpenPGPKey.OpenPGPSecretKey secretKey = key.getPrimarySecretKey(); + isFalse("Expect unlocked test vector to be unlocked", secretKey.isLocked()); + + OpenPGPKey.OpenPGPPrivateKey privateKey = secretKey.unlock(); + OpenPGPKey.OpenPGPSecretKey locked = privateKey.changePassphrase( + "sw0rdf1sh".toCharArray(), + api.getImplementation(), + true); + isTrue("Expect test key to be locked after locking", locked.isLocked()); + isEquals("Expect locked key to use AEAD", + SecretKeyPacket.USAGE_AEAD, locked.getPGPSecretKey().getS2KUsage()); + isTrue("Expect key to be unlockable with used passphrase", + locked.isPassphraseCorrect("sw0rdf1sh".toCharArray())); + } + + private void changeAEADPassphrase(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate() + .parseKey(OpenPGPTestKeys.V6_KEY_LOCKED); + + OpenPGPKey.OpenPGPSecretKey secretKey = key.getPrimarySecretKey(); + isTrue("Expect locked test vector to be locked initially", + secretKey.isLocked()); + OpenPGPKey.OpenPGPPrivateKey privateKey = secretKey.unlock(OpenPGPTestKeys.V6_KEY_LOCKED_PASSPHRASE.toCharArray()); + OpenPGPKey.OpenPGPSecretKey relocked = privateKey.changePassphrase("sw0rdf1sh".toCharArray()); + isTrue("Expect key to still be locked after changing passphrase", relocked.isLocked()); + isTrue("Expect key to be unlockable with used passphrase", + relocked.isPassphraseCorrect("sw0rdf1sh".toCharArray())); + isEquals("Expect re-locked key to use AEAD", + relocked.getPGPSecretKey().getS2KUsage(), SecretKeyPacket.USAGE_AEAD); + } + + private void testChangingCFBPassphrase(OpenPGPApi api) + throws PGPException, IOException + { + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.ALICE_KEY); + + OpenPGPKey.OpenPGPSecretKey secretKey = key.getPrimarySecretKey(); + isFalse("Expect Alice' key to not be locked initially", secretKey.isLocked()); + + OpenPGPKey.OpenPGPPrivateKey privateKey = secretKey.unlock(); + OpenPGPKey.OpenPGPSecretKey locked = privateKey.changePassphrase( + "sw0rdf1sh".toCharArray(), api.getImplementation(), false); + isTrue("Expect Alice' key to be locked after locking", locked.isLocked()); + isEquals("Expect CFB mode to be used for locking, since we did not use AEAD.", + locked.getPGPSecretKey().getS2KUsage(), SecretKeyPacket.USAGE_SHA1); + isTrue("Expect key to be unlockable with used passphrase", + locked.isPassphraseCorrect("sw0rdf1sh".toCharArray())); + + privateKey = locked.unlock("sw0rdf1sh".toCharArray()); + OpenPGPKey.OpenPGPSecretKey relocked = privateKey.changePassphrase("0r4ng3".toCharArray()); + isEquals("Expect CFB to be used after changing passphrase of CFB-protected key", + relocked.getPGPSecretKey().getS2KUsage(), SecretKeyPacket.USAGE_SHA1); + isTrue("Expect key to be unlockable with new passphrase", + relocked.isPassphraseCorrect("0r4ng3".toCharArray())); + + privateKey = relocked.unlock("0r4ng3".toCharArray()); + OpenPGPKey.OpenPGPSecretKey unlocked = privateKey.removePassphrase(); + isFalse("Expect key to be unlocked after removing passphrase", unlocked.isLocked()); + } + + @Override + public String getName() + { + return "ChangeKeyPassphraseTest"; + } + + public static void main(String[] args) + { + runTest(new ChangeKeyPassphraseTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/DoubleBufferedInputStreamTest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/DoubleBufferedInputStreamTest.java new file mode 100644 index 0000000000..b34b7f3406 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/DoubleBufferedInputStreamTest.java @@ -0,0 +1,164 @@ +package org.bouncycastle.openpgp.api.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.bcpg.test.AbstractPacketTest; +import org.bouncycastle.openpgp.api.DoubleBufferedInputStream; +import org.bouncycastle.util.io.Streams; + +public class DoubleBufferedInputStreamTest + extends AbstractPacketTest +{ + + @Override + public String getName() + { + return "RetainingInputStreamTest"; + } + + @Override + public void performTest() + throws Exception + { + throwWhileReadingNthBlock(); + successfullyReadSmallerThanBuffer(); + successfullyReadGreaterThanBuffer(); + + throwWhileReadingFirstBlock(); + throwWhileClosing(); + } + + private void successfullyReadSmallerThanBuffer() + throws IOException + { + byte[] bytes = getSequentialBytes(400); + ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); + DoubleBufferedInputStream retIn = new DoubleBufferedInputStream(bIn, 512); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + Streams.pipeAll(retIn, bOut); + isEncodingEqual(bytes, bOut.toByteArray()); + } + + private void successfullyReadGreaterThanBuffer() + throws IOException + { + byte[] bytes = getSequentialBytes(2000); + ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); + DoubleBufferedInputStream retIn = new DoubleBufferedInputStream(bIn, 512); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + Streams.pipeAll(retIn, bOut); + isEncodingEqual(bytes, bOut.toByteArray()); + } + + private void throwWhileReadingFirstBlock() + { + InputStream throwAfterNBytes = new InputStream() + { + int throwAt = 314; + int r = 0; + + @Override + public int read() + throws IOException + { + int i = r; + if (r == throwAt) + { + throw new IOException("Oopsie"); + } + r++; + return i; + } + }; + DoubleBufferedInputStream retIn = new DoubleBufferedInputStream(throwAfterNBytes, 512); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + try + { + Streams.pipeAll(retIn, bOut); + } + catch (IOException e) + { + isEquals("Oopsie", e.getMessage()); + } + isEquals("throwWhileReadingFirstBlock: expected no bytes emitted", 0, bOut.toByteArray().length); + } + + private void throwWhileReadingNthBlock() + { + InputStream throwAfterNBytes = new InputStream() + { + int throwAt = 10; + int r = 0; + + @Override + public int read() + throws IOException + { + int i = r; + if (r == throwAt) + { + throw new IOException("Oopsie"); + } + r++; + return i; + } + }; + DoubleBufferedInputStream retIn = new DoubleBufferedInputStream(throwAfterNBytes, 4); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + try + { + Streams.pipeAll(retIn, bOut); + } + catch (IOException e) + { + isEquals("Oopsie", e.getMessage()); + } + byte[] got = bOut.toByteArray(); + isEquals("throwWhileReadingNthBlock: expected 4 bytes emitted. Got " + got.length, 4, got.length); + } + + private void throwWhileClosing() + { + byte[] bytes = getSequentialBytes(100); + ByteArrayInputStream bIn = new ByteArrayInputStream(bytes); + FilterInputStream throwOnClose = new FilterInputStream(bIn) + { + @Override + public void close() + throws IOException + { + throw new IOException("Oopsie"); + } + }; + DoubleBufferedInputStream retIn = new DoubleBufferedInputStream(throwOnClose, 512); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + try + { + Streams.pipeAll(retIn, bOut); + } + catch (IOException e) + { + isEquals("Oopsie", e.getMessage()); + } + isEquals("throwWhileClosing: len mismatch", 0, bOut.toByteArray().length); + } + + private byte[] getSequentialBytes(int n) + { + byte[] bytes = new byte[n]; + for (int i = 0; i < bytes.length; i++) + { + bytes[i] = (byte)(i % 128); + } + return bytes; + } + + public static void main(String[] args) + { + runTest(new DoubleBufferedInputStreamTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPCertificateTest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPCertificateTest.java new file mode 100644 index 0000000000..7fbd93f5a2 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPCertificateTest.java @@ -0,0 +1,886 @@ +package org.bouncycastle.openpgp.api.test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Date; +import java.util.List; + +import org.bouncycastle.bcpg.ArmoredInputStream; +import org.bouncycastle.bcpg.BCPGInputStream; +import org.bouncycastle.bcpg.KeyIdentifier; +import org.bouncycastle.bcpg.SignatureSubpacketTags; +import org.bouncycastle.bcpg.sig.Features; +import org.bouncycastle.bcpg.sig.KeyFlags; +import org.bouncycastle.openpgp.OpenPGPTestKeys; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPObjectFactory; +import org.bouncycastle.openpgp.PGPSignature; +import org.bouncycastle.openpgp.PGPSignatureList; +import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.bouncycastle.openpgp.api.OpenPGPApi; +import org.bouncycastle.openpgp.api.OpenPGPCertificate; +import org.bouncycastle.openpgp.api.OpenPGPKey; +import org.bouncycastle.openpgp.api.OpenPGPKeyGenerator; +import org.bouncycastle.openpgp.api.SignatureParameters; +import org.bouncycastle.openpgp.api.SignatureSubpacketsFunction; +import org.bouncycastle.openpgp.api.util.UTCUtil; +import org.bouncycastle.openpgp.bc.BcPGPObjectFactory; +import org.bouncycastle.util.Strings; + +public class OpenPGPCertificateTest + extends APITest +{ + + @Override + public String getName() + { + return "OpenPGPCertificateTest"; + } + + @Override + protected void performTestWith(OpenPGPApi api) + throws IOException, PGPException + { + testOpenPGPv6Key(api); + + testBaseCasePrimaryKeySigns(api); + testBaseCaseSubkeySigns(api); + testPKSignsPKRevokedNoSubpacket(api); + testSKSignsPKRevokedNoSubpacket(api); + testPKSignsPKRevocationSuperseded(api); + testGetPrimaryUserId(api); + } + + private void testOpenPGPv6Key(OpenPGPApi api) + throws IOException + { + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY); + + isTrue("Test key has no identities", key.getIdentities().isEmpty()); + + OpenPGPCertificate.OpenPGPPrimaryKey primaryKey = key.getPrimaryKey(); + isEquals("Primary key identifier mismatch", + new KeyIdentifier("CB186C4F0609A697E4D52DFA6C722B0C1F1E27C18A56708F6525EC27BAD9ACC9"), + primaryKey.getKeyIdentifier()); + OpenPGPKey.OpenPGPSecretKey secretPrimaryKey = key.getSecretKey(primaryKey); + isTrue("Secret Primary key MUST have reference to its public component", + primaryKey == secretPrimaryKey.getPublicKey()); + isTrue("Primary key is expected to be signing key", primaryKey.isSigningKey()); + isTrue("Primary secret key is expected to be signing key", secretPrimaryKey.isSigningKey()); + isTrue("Primary secret key is expected to be certification key", secretPrimaryKey.isCertificationKey()); + isTrue("Primary key is expected to be certification key", primaryKey.isCertificationKey()); + + List signingKeys = key.getSigningKeys(); + isEquals("Expected exactly 1 signing key", 1, signingKeys.size()); + OpenPGPCertificate.OpenPGPPrimaryKey signingKey = (OpenPGPCertificate.OpenPGPPrimaryKey) signingKeys.get(0); + isEquals("Signing key is expected to be the same as primary key", primaryKey, signingKey); + + Features signingKeyFeatures = signingKey.getFeatures(); + // Features are extracted from direct-key signature + isEquals("Signing key features mismatch. Expect features to be extracted from DK signature.", + Features.FEATURE_MODIFICATION_DETECTION | Features.FEATURE_SEIPD_V2, + signingKeyFeatures.getFeatures()); + + List encryptionKeys = key.getEncryptionKeys(); + isEquals("Expected exactly 1 encryption key", 1, encryptionKeys.size()); + OpenPGPCertificate.OpenPGPSubkey encryptionKey = (OpenPGPCertificate.OpenPGPSubkey) encryptionKeys.get(0); + isTrue("Subkey MUST be encryption key", encryptionKey.isEncryptionKey()); + isEquals("Encryption subkey identifier mismatch", + new KeyIdentifier("12C83F1E706F6308FE151A417743A1F033790E93E9978488D1DB378DA9930885"), + encryptionKey.getKeyIdentifier()); + + KeyFlags encryptionKeyFlags = encryptionKey.getKeyFlags(); + // Key Flags are extracted from subkey-binding signature + isEquals("Encryption key flag mismatch. Expected key flags to be extracted from SB sig.", + KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, + encryptionKeyFlags.getFlags()); + + Features encryptionKeyFeatures = encryptionKey.getFeatures(); + // Features are extracted from direct-key signature + isEquals("Encryption key features mismatch. Expected features to be extracted from DK sig.", + Features.FEATURE_MODIFICATION_DETECTION | Features.FEATURE_SEIPD_V2, + encryptionKeyFeatures.getFeatures()); + } + + private void testBaseCasePrimaryKeySigns(OpenPGPApi api) + throws IOException + { + // https://sequoia-pgp.gitlab.io/openpgp-interoperability-test-suite/results.html#Key_revocation_test__primary_key_signs_and_is_not_revoked__base_case_ + String cert = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + + "\n" + + "xsBNBFpJegABCACzr1V+GxVkrtfDjihYK+HtyEIcO52uw7O2kd7JbduYp4RK17jy\n" + + "75N3EnsgmiIkSxXCWr+rTtonNs1zCJeUa/gwnNfs7mVgjL2rMOZU/KZ4MP0yOYU5\n" + + "u5FjNPWz8hpFQ9GKqfdj0Op61h1pCQO45IjUQ3dCDj9Rfn44zHMB1ZrbmIH9nTR1\n" + + "YIGHWmdm0LItb2WxIkwzWBAJ5acTlsmLyZZEQ1+8NDqktyzwFoQqTJvLU4StY2k6\n" + + "h18ZKZdPyrdLoEyOuWkvjxmbhDk1Gt5KiS/yy7mrzIPLr0dmJe4vc8WLV+bXoyNE\n" + + "x3H8o9CFcYehLfyqsy40lg92d6Kp96ww8dZ5ABEBAAHCwMQEHwEKAHgFgl4L4QAJ\n" + + "EAitUcrkcPAGRxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9y\n" + + "Z4csZe1ah1tj2AjxfdDMsH2wvSEwZjb/73ICKnm7BySQAhUKApsDAh4BFiEE4yy2\n" + + "2oICkbfnbbGoCK1RyuRw8AYAAGYFCACiKnCb2NBZa/Jj1aJe4R2rxPZj2ERXWe3b\n" + + "JKNPKT7K0rVDkTw1JRiTfCsuAY2lY9sKJdhQZl+azXm64vvTc6hEGRQ/+XssDlE2\n" + + "DIn8C34HDc495ZnryHNB8Dd5l1HdjqxfGIY6HBPJUdx0dedwP42Oisg9t5KsC8zl\n" + + "d/+MIRgzkp+Dg0LXJVnDuwWEPoo2N6WhAr5ReLvXxALX5ht9Lb3lP0DASZvAKy9B\n" + + "O/wRCr294J8dg/CowAfloyf0Ko+JjyjanmZn3acy5CGkVN2mc+PFUekGZDDy5ooY\n" + + "kgXO/CmApuTNvabct+A7IVVdWWM5SWb90JvaV9SWji6nQphVm7StwsDEBB8BCgB4\n" + + "BYJaSXoACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lh\n" + + "LXBncC5vcmfVZdjLYZxDX2hvy3aGrsE4i0avLDMzf3e9kVHmaD6PAgIVCgKbAwIe\n" + + "ARYhBOMsttqCApG3522xqAitUcrkcPAGAABQYwgArfIRxq95npUKAOPXs25nZlvy\n" + + "+xQbrmsTxHhAYW8eGFcz82QwumoqrR8VfrojxM+eCZdTI85nM5kzznYDU2+cMhsZ\n" + + "Vm5+VhGZy3e3QH4J/E31D7t1opCvj5g1eRJ4LgywB+cYGcZBYp/bQT9SUYuhZH2O\n" + + "XCR04qSbpVUCIApnhBHxKNtOlqjAkHeaOdW/8XePsbfvrtVOLGYgrZXfY7Nqy3+W\n" + + "zbdm8UvVPFXH+uHEzTgyvYbnJBYkjORmCqUKs860PL8ekeg+sL4PHSRj1UUfwcQD\n" + + "55q0m3Vtew2KiIUi4wKi5LceDtprjoO5utU/1YfEAiNMeSQHXKq83dpazvjrUs0S\n" + + "anVsaWV0QGV4YW1wbGUub3JnwsDEBBMBCgB4BYJaSXoACRAIrVHK5HDwBkcUAAAA\n" + + "AAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmc6Rix7CeIfWwnaQjk3\n" + + "bBrkAiY7jS9N+shuRdHZ0gKKsgIVCgKbAwIeARYhBOMsttqCApG3522xqAitUcrk\n" + + "cPAGAACf9QgAsxtfAbyGbtofjrXTs9lsKEWvGgk02fSYyKjPbyaRqh72MlIlUXwq\n" + + "q1ih2TJc3vwF8aNVDrcb9DnBabdt2M1vI3PUaeG31BmakC/XZCNCrbbJkyd/vdML\n" + + "qw7prLrp0auVNNhLYxOK9usXbClNxluo4i/lSFVo5B9ai+ne1kKKiplzqy2qqhde\n" + + "plomcwGHbB1CkZ04DmCMbSSFAGxYqUC/bBm0bolCebw/KIz9sEojNKt6mvsFN67/\n" + + "hMYeJS0HVlwwc6i8iKSzC2D53iywhtvkdiKECXQeXDf9zNXAn1wpK01SLJ0iig7c\n" + + "DFrtoqkfPYzbNfC0bt34fNx9iz3w9aEH8c7ATQRaSsuAAQgAu5yau9psltmWiUn7\n" + + "fsRSqbQInO0iWnu4DK9IXB3ghNYMcii3JJEjHzgIxGf3GiJEjzubyRQaX5J/p7yB\n" + + "1fOH8z7FYUuax1saGf9c1/b02N9gyXNlHam31hNaaL3ffFczI95p7MNrTtroTt5o\n" + + "Zqsc+i+oKLZn7X0YAI4tEYwhSnUQYB/F7YqkkI4eV+7CxZPA8pBhXiAOK/zn416P\n" + + "sZ6JS5wsM65yCtOHcAAIBnKDnC+bQi+f1WZesSocy/rXx3QEQmodDu3ojhS+VxcY\n" + + "GeZCUcFF0FyZBIkGjHIVQLyOfjP3FRJ4qFXMz9/YIVoM4Y6guTERMTEj/KDG4BP7\n" + + "RfJHTQARAQABwsI8BBgBCgHwBYJeC+EACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0\n" + + "QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfcAa1ZPWTtg60w3Oo4dt4Fa8cKFYbZ\n" + + "YsqDSHV5pwEfMwKbAsC8oAQZAQoAbwWCXgvhAAkQEPy8/w6Op5FHFAAAAAAAHgAg\n" + + "c2FsdEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3JnL6I2+VyN5T1FoVgj3cdnMLYC\n" + + "pcB5i/FRSCVKybuLzrgWIQTOphDQhPpR8hHhxGwQ/Lz/Do6nkQAArk8H/AhjM9lq\n" + + "bffFL6RRR4HTjelspy4A3nyTicCljrDuXDUh23GfLvajTR5h16ZBqAF7cpb9rrlz\n" + + "1C1WcS5JLVxzXAe7f+KOfXu+eyLhpTzZ8VT3pK3hHGaYwlVlXrBZP0JXgL8hm6hD\n" + + "SXZQZtcpsnQ1uIHC9ONxUB4liNFhTqQCQYdQJFiFs1umUbo/C4KdzlDI08bM3CqE\n" + + "Kat9vUFuGG68mDg0CrRZEWt946L5i8kZmBUkSShIm2k5e2qE/muYeM6qKQNsxlx3\n" + + "VIf5eUhtxCi9fg7SjvHkdUSFstYcxAdaohWCFCEsDJI12hzcKQazSjvtKF4BNBKg\n" + + "X/wLsbVQnYLd9ggWIQTjLLbaggKRt+dtsagIrVHK5HDwBgAANjMH/1MY7DJyxkiT\n" + + "jc/jzmnVxqtHOZDCSmUqk0eh/6BHs+ostWqkGC6+7dfxDnptwcqandYey4KF2ajt\n" + + "4nOwu0xQw/NEF3i81h7IiewY7G+YT69DUd+DvVUQemfKNYVOrMqoH7QU5o4YojdJ\n" + + "iDeIp2d/JyJrqyof78JFAHnNZgHC2T2zo9E54dnOTY9VNUNCOUct5Rby0GXjTIUR\n" + + "O0f485eGuZxVWdLRllDYOiCrQHPSHhrxHVXVMbYJoroPy+IyaJanVoAWgyipBmmI\n" + + "DV8aINM2RLMsGkuPTRtITI2ZlGOQN7xgy4LqWzjPnrzMXfwBEDx/nrwdG6zEGMK8\n" + + "AkVkMT5uJJvCwjwEGAEKAfAFglro/4AJEAitUcrkcPAGRxQAAAAAAB4AIHNhbHRA\n" + + "bm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZ/Q0Z6WDH2+8/F1xEEuiApsjnn2lGNZ2\n" + + "DeIaklJzdqQOApsCwLygBBkBCgBvBYJa6P+ACRAQ/Lz/Do6nkUcUAAAAAAAeACBz\n" + + "YWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfrVATyX3tgcM2z41fqYquxVhJR\n" + + "avN6+w2SU4xEG++SqBYhBM6mENCE+lHyEeHEbBD8vP8OjqeRAABGVggAsB8M2KI5\n" + + "cxXKKgVHL1dEfzg9halVavktfcT6ZVC/+aDp94tvBCL16Guhq4ccN7DATrWx430/\n" + + "GecY6E77qvhDzmCclSbdLbiZmsrVX9kCmTfrJzFQ64KfvIS5GgbL21+ZJ+pKW2HO\n" + + "MBGn6sgAPmTqM5UsDCpsEKDt5CJcJr3sTc8D9NhEnc0dKsQ91+n9ms3W5tyyE6r9\n" + + "pyM6ThBCMhbQkR7hE9XWAQeO1ILSFGnie0aFcTU0Oo0wL1MaiSyA/8XpKq23xfx1\n" + + "kNS9hQkdq0aWehNoTJdCt1Nq1cWABy2rQR0x+qhGWowfsAjnBautxvet28t2kPCA\n" + + "IMniYpWc89BwfhYhBOMsttqCApG3522xqAitUcrkcPAGAACq1gf/Q7H9Re5SWk+U\n" + + "On/NQPRedf544YJ/YdQnve/hSaPGL33cUzf4yxzFILnK19Ird5f8/mTT1pg99L3i\n" + + "xE3N5031JJKwFpCB69Rsysg88ZLDL2VLc3xdsAQdUbVaCqeRHKwtMtpBvbAFvF9p\n" + + "lwam0SSXHHr/JkYm5ufXN6I8ib/nwr1bFbf/Se0Wuk9RG4ne9JUBCrGxakyVd+Og\n" + + "LLhvzOmJa7fDC0uUZhTKFbjMxLhaas4HFYiRbfz2T0xz9gyDytDWsEFM+XoKHlEH\n" + + "8Fx/U2B5/8N0Q+pIFoEuOmBO+5EPvPIlxNByHgiaNIuKt1Mu+UAb2Spl6D5zbDfX\n" + + "/3vqxdhYHw==\n" + + "=Ric2\n" + + "-----END PGP PUBLIC KEY BLOCK-----\n"; + TestSignature t0 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJYaEaACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmeoPMfalw2oS7uyOKnOXJSN8Gx7pr/BMlo3Xn8nTgx6\n" + + "ORYhBOMsttqCApG3522xqAitUcrkcPAGAABXbAf/WfWaQYNuATAKwxYrJx4fd5kt\n" + + "0M6sn1q7wK1MIxursG2+FuKafV25O9+pde8Nog77OEgegwk+HokOVFpVXfOzHQjs\n" + + "8dwWTtTQlX5NIBNvtqS7cvCKhjsqaHKgmzsenMjCEbpDZ3C5CoqcYicykqEU/Ia0\n" + + "ZGC4lzRByrgNy/w+/iLN748S707bzBLVc/sE73k9N5pANAlE+cA/sHI1Gp2WxJR9\n" + + "t2Fk4x6/85PEnF1RHI16p/wSEeuRaBpyw9QGZBbVDVt5wvgttxZjteGGSwBM3WI/\n" + + "gPfC0LW+JQ2W+dwY0PN/7yuARVRhXpKiBI4xqp7x3OanQX6quU77g3B8nXAt3A==\n" + + "=StqT\n" + + "-----END PGP SIGNATURE-----\n", false, "Sig predates primary key"); + TestSignature t1 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJa564ACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmfM0EN4Ei0bQv6UO9BRq2wtUfV948cRynRMBb8TSGCG\n" + + "tBYhBOMsttqCApG3522xqAitUcrkcPAGAAAlNwf+L0KQK9i/xmYKOMV2EX13QUoZ\n" + + "vvb/pHGZaCQ9JtvEF2l2DT0DqByZ+tOv5Y4isU+un7CraoyvyajAwR0Yqk937B6C\n" + + "HQHKMkmIl+5R4/xqSoWYmOidbrgilojPMBEhB3INQ8/THjjFijtLzitVhnWBd7+u\n" + + "s0kcqnWnOdx2By4aDe+UEiyCfSE02e/0tIsM71RqiU91zH6dl6+q8nml7PsYuTFV\n" + + "V09oQTbBuuvUe+YgN/uvyKVIsA64lQ+YhqEeIA8Quek7fHhW+du9OIhSPsbYodyx\n" + + "VWMTXwSWKGNvZNAkpmgUYqFjS2Cx5ZUWblZLjrNKBwnnmt50qvUN7+o2pjlnfA==\n" + + "=UuXb\n" + + "-----END PGP SIGNATURE-----\n", true); + TestSignature t2 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJdP4iACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmfFzYGoiuSjN+gz1IDD4ZvRXGuPTHks0/pIiGY90mrZ\n" + + "WxYhBOMsttqCApG3522xqAitUcrkcPAGAABGPAf/ck7tJAFoPIDd9fTPZANpNGoW\n" + + "Fq6VuNfy/nLjz2gkHFX/lLAxQ0N3McIdRA++Ik/omb0lis3R2DVNgwqNm2OF34HE\n" + + "qxmPmrQHBgk2q0fDH4NCE0XnYQjQT65V99IfiaQu+oS3Mq8MuYsDYvRVvRKMwt49\n" + + "fcDnvFtAtCqEETdv6wV5cUZmdQ3L9NU9bApJ0jk+EHVdpfTUIbOYYGnsIe/4Aa0d\n" + + "jgzu4Em79ynosOn//953XJ7OO8LCDi1EKt+nFuZARUlt/Jwwull6zzp7HUPw6HPt\n" + + "Upp7os8TIPC4STwoSeEKaxEkrbMGFnDcoDajnKKRt5+MkB24Oq7PHvnzgnPpVg==\n" + + "=Ljv7\n" + + "-----END PGP SIGNATURE-----\n", true); + TestSignature t3 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJmhTYiCRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmfbjQf/zfoJQT0hhna4RDjOESBLgGaCbc5HLeo751F4\n" + + "NxYhBOMsttqCApG3522xqAitUcrkcPAGAABqBQgAkkNmYf6yLPvox+ZayrLtMb9D\n" + + "ghgt0nau72DSazsJ6SAq2QqIdr0RRhRa2gCETkp4PpeoDWmIvoVj35ZnfyeO/jqy\n" + + "HECvRwO0WPA5FXQM6uG7s40vDTRFjlJMpPyHWnn2igcR64iDxBGmc40xi9CcmJP9\n" + + "tmA26+1Nzj1LcfNvknKZ2UIOmnXiZY0QssIdyqsmJrdFpXs4UCLUzdXkfFLoxksU\n" + + "mk4B6hig2IKMj5mnbWy/JQSXtjjI+HHmtzgWfXs7d9iQ61CklbtCOiPeWxvoqlGG\n" + + "oK1wV1olcSar/RPKTlMmQpAg9dztQgrNs1oF7EF3i9kwNP7I5JzekPiOLH6oMw==\n" + + "=5KMU\n" + + "-----END PGP SIGNATURE-----\n", true); + + signatureValidityTest(api, cert, t0, t1, t2, t3); + } + + private void testBaseCaseSubkeySigns(OpenPGPApi api) + throws IOException + { + // https://sequoia-pgp.gitlab.io/openpgp-interoperability-test-suite/results.html#Key_revocation_test__subkey_signs__primary_key_is_not_revoked__base_case_ + String cert = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + + "\n" + + "xsBNBFpJegABCACzr1V+GxVkrtfDjihYK+HtyEIcO52uw7O2kd7JbduYp4RK17jy\n" + + "75N3EnsgmiIkSxXCWr+rTtonNs1zCJeUa/gwnNfs7mVgjL2rMOZU/KZ4MP0yOYU5\n" + + "u5FjNPWz8hpFQ9GKqfdj0Op61h1pCQO45IjUQ3dCDj9Rfn44zHMB1ZrbmIH9nTR1\n" + + "YIGHWmdm0LItb2WxIkwzWBAJ5acTlsmLyZZEQ1+8NDqktyzwFoQqTJvLU4StY2k6\n" + + "h18ZKZdPyrdLoEyOuWkvjxmbhDk1Gt5KiS/yy7mrzIPLr0dmJe4vc8WLV+bXoyNE\n" + + "x3H8o9CFcYehLfyqsy40lg92d6Kp96ww8dZ5ABEBAAHCwMQEHwEKAHgFgl4L4QAJ\n" + + "EAitUcrkcPAGRxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9y\n" + + "Z4csZe1ah1tj2AjxfdDMsH2wvSEwZjb/73ICKnm7BySQAhUKApsDAh4BFiEE4yy2\n" + + "2oICkbfnbbGoCK1RyuRw8AYAAGYFCACiKnCb2NBZa/Jj1aJe4R2rxPZj2ERXWe3b\n" + + "JKNPKT7K0rVDkTw1JRiTfCsuAY2lY9sKJdhQZl+azXm64vvTc6hEGRQ/+XssDlE2\n" + + "DIn8C34HDc495ZnryHNB8Dd5l1HdjqxfGIY6HBPJUdx0dedwP42Oisg9t5KsC8zl\n" + + "d/+MIRgzkp+Dg0LXJVnDuwWEPoo2N6WhAr5ReLvXxALX5ht9Lb3lP0DASZvAKy9B\n" + + "O/wRCr294J8dg/CowAfloyf0Ko+JjyjanmZn3acy5CGkVN2mc+PFUekGZDDy5ooY\n" + + "kgXO/CmApuTNvabct+A7IVVdWWM5SWb90JvaV9SWji6nQphVm7StwsDEBB8BCgB4\n" + + "BYJaSXoACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lh\n" + + "LXBncC5vcmfVZdjLYZxDX2hvy3aGrsE4i0avLDMzf3e9kVHmaD6PAgIVCgKbAwIe\n" + + "ARYhBOMsttqCApG3522xqAitUcrkcPAGAABQYwgArfIRxq95npUKAOPXs25nZlvy\n" + + "+xQbrmsTxHhAYW8eGFcz82QwumoqrR8VfrojxM+eCZdTI85nM5kzznYDU2+cMhsZ\n" + + "Vm5+VhGZy3e3QH4J/E31D7t1opCvj5g1eRJ4LgywB+cYGcZBYp/bQT9SUYuhZH2O\n" + + "XCR04qSbpVUCIApnhBHxKNtOlqjAkHeaOdW/8XePsbfvrtVOLGYgrZXfY7Nqy3+W\n" + + "zbdm8UvVPFXH+uHEzTgyvYbnJBYkjORmCqUKs860PL8ekeg+sL4PHSRj1UUfwcQD\n" + + "55q0m3Vtew2KiIUi4wKi5LceDtprjoO5utU/1YfEAiNMeSQHXKq83dpazvjrUs0S\n" + + "anVsaWV0QGV4YW1wbGUub3JnwsDEBBMBCgB4BYJaSXoACRAIrVHK5HDwBkcUAAAA\n" + + "AAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmc6Rix7CeIfWwnaQjk3\n" + + "bBrkAiY7jS9N+shuRdHZ0gKKsgIVCgKbAwIeARYhBOMsttqCApG3522xqAitUcrk\n" + + "cPAGAACf9QgAsxtfAbyGbtofjrXTs9lsKEWvGgk02fSYyKjPbyaRqh72MlIlUXwq\n" + + "q1ih2TJc3vwF8aNVDrcb9DnBabdt2M1vI3PUaeG31BmakC/XZCNCrbbJkyd/vdML\n" + + "qw7prLrp0auVNNhLYxOK9usXbClNxluo4i/lSFVo5B9ai+ne1kKKiplzqy2qqhde\n" + + "plomcwGHbB1CkZ04DmCMbSSFAGxYqUC/bBm0bolCebw/KIz9sEojNKt6mvsFN67/\n" + + "hMYeJS0HVlwwc6i8iKSzC2D53iywhtvkdiKECXQeXDf9zNXAn1wpK01SLJ0iig7c\n" + + "DFrtoqkfPYzbNfC0bt34fNx9iz3w9aEH8c7ATQRaSsuAAQgAu5yau9psltmWiUn7\n" + + "fsRSqbQInO0iWnu4DK9IXB3ghNYMcii3JJEjHzgIxGf3GiJEjzubyRQaX5J/p7yB\n" + + "1fOH8z7FYUuax1saGf9c1/b02N9gyXNlHam31hNaaL3ffFczI95p7MNrTtroTt5o\n" + + "Zqsc+i+oKLZn7X0YAI4tEYwhSnUQYB/F7YqkkI4eV+7CxZPA8pBhXiAOK/zn416P\n" + + "sZ6JS5wsM65yCtOHcAAIBnKDnC+bQi+f1WZesSocy/rXx3QEQmodDu3ojhS+VxcY\n" + + "GeZCUcFF0FyZBIkGjHIVQLyOfjP3FRJ4qFXMz9/YIVoM4Y6guTERMTEj/KDG4BP7\n" + + "RfJHTQARAQABwsI8BBgBCgHwBYJeC+EACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0\n" + + "QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfcAa1ZPWTtg60w3Oo4dt4Fa8cKFYbZ\n" + + "YsqDSHV5pwEfMwKbAsC8oAQZAQoAbwWCXgvhAAkQEPy8/w6Op5FHFAAAAAAAHgAg\n" + + "c2FsdEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3JnL6I2+VyN5T1FoVgj3cdnMLYC\n" + + "pcB5i/FRSCVKybuLzrgWIQTOphDQhPpR8hHhxGwQ/Lz/Do6nkQAArk8H/AhjM9lq\n" + + "bffFL6RRR4HTjelspy4A3nyTicCljrDuXDUh23GfLvajTR5h16ZBqAF7cpb9rrlz\n" + + "1C1WcS5JLVxzXAe7f+KOfXu+eyLhpTzZ8VT3pK3hHGaYwlVlXrBZP0JXgL8hm6hD\n" + + "SXZQZtcpsnQ1uIHC9ONxUB4liNFhTqQCQYdQJFiFs1umUbo/C4KdzlDI08bM3CqE\n" + + "Kat9vUFuGG68mDg0CrRZEWt946L5i8kZmBUkSShIm2k5e2qE/muYeM6qKQNsxlx3\n" + + "VIf5eUhtxCi9fg7SjvHkdUSFstYcxAdaohWCFCEsDJI12hzcKQazSjvtKF4BNBKg\n" + + "X/wLsbVQnYLd9ggWIQTjLLbaggKRt+dtsagIrVHK5HDwBgAANjMH/1MY7DJyxkiT\n" + + "jc/jzmnVxqtHOZDCSmUqk0eh/6BHs+ostWqkGC6+7dfxDnptwcqandYey4KF2ajt\n" + + "4nOwu0xQw/NEF3i81h7IiewY7G+YT69DUd+DvVUQemfKNYVOrMqoH7QU5o4YojdJ\n" + + "iDeIp2d/JyJrqyof78JFAHnNZgHC2T2zo9E54dnOTY9VNUNCOUct5Rby0GXjTIUR\n" + + "O0f485eGuZxVWdLRllDYOiCrQHPSHhrxHVXVMbYJoroPy+IyaJanVoAWgyipBmmI\n" + + "DV8aINM2RLMsGkuPTRtITI2ZlGOQN7xgy4LqWzjPnrzMXfwBEDx/nrwdG6zEGMK8\n" + + "AkVkMT5uJJvCwjwEGAEKAfAFglro/4AJEAitUcrkcPAGRxQAAAAAAB4AIHNhbHRA\n" + + "bm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZ/Q0Z6WDH2+8/F1xEEuiApsjnn2lGNZ2\n" + + "DeIaklJzdqQOApsCwLygBBkBCgBvBYJa6P+ACRAQ/Lz/Do6nkUcUAAAAAAAeACBz\n" + + "YWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfrVATyX3tgcM2z41fqYquxVhJR\n" + + "avN6+w2SU4xEG++SqBYhBM6mENCE+lHyEeHEbBD8vP8OjqeRAABGVggAsB8M2KI5\n" + + "cxXKKgVHL1dEfzg9halVavktfcT6ZVC/+aDp94tvBCL16Guhq4ccN7DATrWx430/\n" + + "GecY6E77qvhDzmCclSbdLbiZmsrVX9kCmTfrJzFQ64KfvIS5GgbL21+ZJ+pKW2HO\n" + + "MBGn6sgAPmTqM5UsDCpsEKDt5CJcJr3sTc8D9NhEnc0dKsQ91+n9ms3W5tyyE6r9\n" + + "pyM6ThBCMhbQkR7hE9XWAQeO1ILSFGnie0aFcTU0Oo0wL1MaiSyA/8XpKq23xfx1\n" + + "kNS9hQkdq0aWehNoTJdCt1Nq1cWABy2rQR0x+qhGWowfsAjnBautxvet28t2kPCA\n" + + "IMniYpWc89BwfhYhBOMsttqCApG3522xqAitUcrkcPAGAACq1gf/Q7H9Re5SWk+U\n" + + "On/NQPRedf544YJ/YdQnve/hSaPGL33cUzf4yxzFILnK19Ird5f8/mTT1pg99L3i\n" + + "xE3N5031JJKwFpCB69Rsysg88ZLDL2VLc3xdsAQdUbVaCqeRHKwtMtpBvbAFvF9p\n" + + "lwam0SSXHHr/JkYm5ufXN6I8ib/nwr1bFbf/Se0Wuk9RG4ne9JUBCrGxakyVd+Og\n" + + "LLhvzOmJa7fDC0uUZhTKFbjMxLhaas4HFYiRbfz2T0xz9gyDytDWsEFM+XoKHlEH\n" + + "8Fx/U2B5/8N0Q+pIFoEuOmBO+5EPvPIlxNByHgiaNIuKt1Mu+UAb2Spl6D5zbDfX\n" + + "/3vqxdhYHw==\n" + + "=Ric2\n" + + "-----END PGP PUBLIC KEY BLOCK-----\n"; + TestSignature t0 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJYaEaACRAQ/Lz/Do6nkUcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmdVa4OG6WfRoRlj5+Zb6avhJUIZFvcIFiLuvrJp8Hio\n" + + "iBYhBM6mENCE+lHyEeHEbBD8vP8OjqeRAAAbaQgAjhBh0dLO0Sqiqkb2M3KWc25V\n" + + "hJlcP3isFROJ0jikmXxkG9W04AvlA78tSxEP2n8a0CbxH/hT4g8mFb/qM5FKZcKf\n" + + "HQxjbjUxBmVHa3EfMkwT7u1mVRmoWtJ59oVsKoqRb/kZ14i6VZ9NzfK8MRlL0e24\n" + + "oNjkksZQ8ImjwwtvxSinxhezA6BtWi+dDnXAnG5Vva+6N/GRNPAAd8kFTPrlEqEz\n" + + "uRbpq76r4taPjRjzMNcwZJoRVHSahWhDcXxNTalVUwt0DZFAskZ3gI+0VgU11bK1\n" + + "QmIw2iR4itQY5f10HFNcl7uHLKnul0YyuvA5509HwCuEpdYUV/OxtlpVRaJ+yg==\n" + + "=Rc6K\n" + + "-----END PGP SIGNATURE-----\n", false, "Signature predates primary key"); + TestSignature t1 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJa564ACRAQ/Lz/Do6nkUcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmfcG7Iqn3OOKVjeJ61MlgERt08kcxh0x+BZFD7a8K7V\n" + + "VBYhBM6mENCE+lHyEeHEbBD8vP8OjqeRAACBIwf9EoS24IFeT3cPFf/nWxLFkbZK\n" + + "fiy9WzyK4wlpO3VTyWPbXi6zpC4I5Rbp2jDk/c7Q3DnOZqFDv6TriTwuLYTJGPxr\n" + + "U3dtDsFcKp4FcbgFyCDKIuLB+3kLaNpMXqdttEkY3Wd5m33XrBB7M0l5xZCk56Jm\n" + + "H5L1sGNNNkCzG6P44qu69o5fkWxbYuX22fyhdeyxucJHMztqiMQYDwT7eSA92A1v\n" + + "5OwA5D/k7GeyYFBFisxRijkdVtxstC9zkagC19VnZo7MRekA9gXj7kIna4XYRhfb\n" + + "uQnN47HXdiWQytwypLvZ8JEJpRruyMAaHjX5OBXh0SK11xYWb6wB93+QfOahtg==\n" + + "=UlUZ\n" + + "-----END PGP SIGNATURE-----\n", false, "Subkey is not bound at this time"); + TestSignature t2 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJdP4iACRAQ/Lz/Do6nkUcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmcgkZw3ZSg8CZCKqJw2r4VqCpTuUhz6N0zX43d+1xop\n" + + "2hYhBM6mENCE+lHyEeHEbBD8vP8OjqeRAADnqAgAq+m6dDZpNOBaXH9nwv8/+HgR\n" + + "MvRjnuLoa6zB5tcUhGPPVS0gg1PW0wfxlo1GPmgW3QDlV1zvcfYAZmV9uEC61wn/\n" + + "+FkqN0Tceo487UvkWARE/mmRj5L8OgUTfqm1eebFQlMu/MeG9YOg+tXBy7XS7hy3\n" + + "UdntIbtsv5oRTcybTnn5oiU2OFDlFC6sBNzOQt7wpyB1TKp2BdcsAv1RwmyCCCK4\n" + + "bnmrpYH6woWMyVEVeMYfOHAx9vHD+od8Vf/v5L1M2N0nHzRWjjkobTVUr+xt/CyW\n" + + "nq8SoazKYu3ETpZLeWX6Bciuv9+pzUCeClOSmBB1MFyyrTgbkOacHgrYnLvvtQ==\n" + + "=WCKA\n" + + "-----END PGP SIGNATURE-----\n", true); + TestSignature t3 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJmhTYiCRAQ/Lz/Do6nkUcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmdi3dCpJ4nZincNH5owv8+fJ5YpXljqtegtoBEnbbHP\n" + + "thYhBM6mENCE+lHyEeHEbBD8vP8OjqeRAAD0cQf/e8RHocRESJPbosqUuvC3ELnD\n" + + "oSsJomDMUDfSfgpS5EhkOyJhvcrHkCbsHH2xlUEQ+zjJWY/dwM3FUkoj+p3kb/JC\n" + + "Rn5cqQYlME+uJzjdHMyQCSOI1SvYwKCLCGPARDbCpeINrV++Oy29e6cv6/IcPlgo\n" + + "k/0A7XuNq0YNxC7oopCj5ye3yVUvUmSCG2iV4oiWW5GhhPRzMeW7MFQmS0NUkAI8\n" + + "hzJ8juTG4xP8SXnHCMakasZhJmtpMDd2BDZ7CrhWiWUQGrtd0eYkuyodreqVMGIF\n" + + "BN80YgTNFW2MrblhDRRmxAqWzD9FedBwwSdgYbtkDwjsSq0S1jQV6aPndJqiLw==\n" + + "=CIl0\n" + + "-----END PGP SIGNATURE-----\n", true); + + signatureValidityTest(api, cert, t0, t1, t2, t3); + } + + private void testPKSignsPKRevokedNoSubpacket(OpenPGPApi api) + throws IOException + { + String cert = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + + "\n" + + "xsBNBFpJegABCACzr1V+GxVkrtfDjihYK+HtyEIcO52uw7O2kd7JbduYp4RK17jy\n" + + "75N3EnsgmiIkSxXCWr+rTtonNs1zCJeUa/gwnNfs7mVgjL2rMOZU/KZ4MP0yOYU5\n" + + "u5FjNPWz8hpFQ9GKqfdj0Op61h1pCQO45IjUQ3dCDj9Rfn44zHMB1ZrbmIH9nTR1\n" + + "YIGHWmdm0LItb2WxIkwzWBAJ5acTlsmLyZZEQ1+8NDqktyzwFoQqTJvLU4StY2k6\n" + + "h18ZKZdPyrdLoEyOuWkvjxmbhDk1Gt5KiS/yy7mrzIPLr0dmJe4vc8WLV+bXoyNE\n" + + "x3H8o9CFcYehLfyqsy40lg92d6Kp96ww8dZ5ABEBAAHCwLsEIAEKAG8FglwqrYAJ\n" + + "EAitUcrkcPAGRxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9y\n" + + "Z4KjdWVHTHye8HeUynibpgE5TYfFnnBt9bbOj99oplaTFiEE4yy22oICkbfnbbGo\n" + + "CK1RyuRw8AYAAMxeB/4+QAncX1+678HeO1fweQ0Zkf4O6+Ew6EgCp4I2UZu+a5H8\n" + + "ryI3B4WNShCDoV3CfOcUtUSUA8EOyrpYSW/3jPVfb01uxDNsZpf9piZG7DelIAef\n" + + "wvQaZHJeytchv5+Wo+Jo6qg26BgvUlXW2x5NNcScGvCZt1RQ712PRDAfUnppRXBj\n" + + "+IXWzOs52uYGFDFzJSLEUy6dtTdNCJk78EMoHsOwC7g5uUyHbjSfrdQncxgMwikl\n" + + "C2LFSS7xYZwDgkkb70AT10Ot2jL6rLIT/1ChQZ0oRGJLBHiz3FUpanDQIDD49+dp\n" + + "6FUmUUsubwwFkxBHyCbQ8cdbfBILNiD1pEo31dPTwsDEBB8BCgB4BYJeC+EACRAI\n" + + "rVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmeH\n" + + "LGXtWodbY9gI8X3QzLB9sL0hMGY2/+9yAip5uwckkAIVCgKbAwIeARYhBOMsttqC\n" + + "ApG3522xqAitUcrkcPAGAABmBQgAoipwm9jQWWvyY9WiXuEdq8T2Y9hEV1nt2ySj\n" + + "Tyk+ytK1Q5E8NSUYk3wrLgGNpWPbCiXYUGZfms15uuL703OoRBkUP/l7LA5RNgyJ\n" + + "/At+Bw3OPeWZ68hzQfA3eZdR3Y6sXxiGOhwTyVHcdHXncD+NjorIPbeSrAvM5Xf/\n" + + "jCEYM5Kfg4NC1yVZw7sFhD6KNjeloQK+UXi718QC1+YbfS295T9AwEmbwCsvQTv8\n" + + "EQq9veCfHYPwqMAH5aMn9CqPiY8o2p5mZ92nMuQhpFTdpnPjxVHpBmQw8uaKGJIF\n" + + "zvwpgKbkzb2m3LfgOyFVXVljOUlm/dCb2lfUlo4up0KYVZu0rcLAxAQfAQoAeAWC\n" + + "Wkl6AAkQCK1RyuRw8AZHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1w\n" + + "Z3Aub3Jn1WXYy2GcQ19ob8t2hq7BOItGrywzM393vZFR5mg+jwICFQoCmwMCHgEW\n" + + "IQTjLLbaggKRt+dtsagIrVHK5HDwBgAAUGMIAK3yEcaveZ6VCgDj17NuZ2Zb8vsU\n" + + "G65rE8R4QGFvHhhXM/NkMLpqKq0fFX66I8TPngmXUyPOZzOZM852A1NvnDIbGVZu\n" + + "flYRmct3t0B+CfxN9Q+7daKQr4+YNXkSeC4MsAfnGBnGQWKf20E/UlGLoWR9jlwk\n" + + "dOKkm6VVAiAKZ4QR8SjbTpaowJB3mjnVv/F3j7G3767VTixmIK2V32Ozast/ls23\n" + + "ZvFL1TxVx/rhxM04Mr2G5yQWJIzkZgqlCrPOtDy/HpHoPrC+Dx0kY9VFH8HEA+ea\n" + + "tJt1bXsNioiFIuMCouS3Hg7aa46DubrVP9WHxAIjTHkkB1yqvN3aWs7461LNEmp1\n" + + "bGlldEBleGFtcGxlLm9yZ8LAxAQTAQoAeAWCWkl6AAkQCK1RyuRw8AZHFAAAAAAA\n" + + "HgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3JnOkYsewniH1sJ2kI5N2wa\n" + + "5AImO40vTfrIbkXR2dICirICFQoCmwMCHgEWIQTjLLbaggKRt+dtsagIrVHK5HDw\n" + + "BgAAn/UIALMbXwG8hm7aH46107PZbChFrxoJNNn0mMioz28mkaoe9jJSJVF8KqtY\n" + + "odkyXN78BfGjVQ63G/Q5wWm3bdjNbyNz1Gnht9QZmpAv12QjQq22yZMnf73TC6sO\n" + + "6ay66dGrlTTYS2MTivbrF2wpTcZbqOIv5UhVaOQfWovp3tZCioqZc6stqqoXXqZa\n" + + "JnMBh2wdQpGdOA5gjG0khQBsWKlAv2wZtG6JQnm8PyiM/bBKIzSrepr7BTeu/4TG\n" + + "HiUtB1ZcMHOovIikswtg+d4ssIbb5HYihAl0Hlw3/czVwJ9cKStNUiydIooO3Axa\n" + + "7aKpHz2M2zXwtG7d+HzcfYs98PWhB/HOwE0EWkrLgAEIALucmrvabJbZlolJ+37E\n" + + "Uqm0CJztIlp7uAyvSFwd4ITWDHIotySRIx84CMRn9xoiRI87m8kUGl+Sf6e8gdXz\n" + + "h/M+xWFLmsdbGhn/XNf29NjfYMlzZR2pt9YTWmi933xXMyPeaezDa07a6E7eaGar\n" + + "HPovqCi2Z+19GACOLRGMIUp1EGAfxe2KpJCOHlfuwsWTwPKQYV4gDiv85+Nej7Ge\n" + + "iUucLDOucgrTh3AACAZyg5wvm0Ivn9VmXrEqHMv618d0BEJqHQ7t6I4UvlcXGBnm\n" + + "QlHBRdBcmQSJBoxyFUC8jn4z9xUSeKhVzM/f2CFaDOGOoLkxETExI/ygxuAT+0Xy\n" + + "R00AEQEAAcLCPAQYAQoB8AWCXgvhAAkQCK1RyuRw8AZHFAAAAAAAHgAgc2FsdEBu\n" + + "b3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3Jn3AGtWT1k7YOtMNzqOHbeBWvHChWG2WLK\n" + + "g0h1eacBHzMCmwLAvKAEGQEKAG8Fgl4L4QAJEBD8vP8OjqeRRxQAAAAAAB4AIHNh\n" + + "bHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZy+iNvlcjeU9RaFYI93HZzC2AqXA\n" + + "eYvxUUglSsm7i864FiEEzqYQ0IT6UfIR4cRsEPy8/w6Op5EAAK5PB/wIYzPZam33\n" + + "xS+kUUeB043pbKcuAN58k4nApY6w7lw1Idtxny72o00eYdemQagBe3KW/a65c9Qt\n" + + "VnEuSS1cc1wHu3/ijn17vnsi4aU82fFU96St4RxmmMJVZV6wWT9CV4C/IZuoQ0l2\n" + + "UGbXKbJ0NbiBwvTjcVAeJYjRYU6kAkGHUCRYhbNbplG6PwuCnc5QyNPGzNwqhCmr\n" + + "fb1BbhhuvJg4NAq0WRFrfeOi+YvJGZgVJEkoSJtpOXtqhP5rmHjOqikDbMZcd1SH\n" + + "+XlIbcQovX4O0o7x5HVEhbLWHMQHWqIVghQhLAySNdoc3CkGs0o77SheATQSoF/8\n" + + "C7G1UJ2C3fYIFiEE4yy22oICkbfnbbGoCK1RyuRw8AYAADYzB/9TGOwycsZIk43P\n" + + "485p1carRzmQwkplKpNHof+gR7PqLLVqpBguvu3X8Q56bcHKmp3WHsuChdmo7eJz\n" + + "sLtMUMPzRBd4vNYeyInsGOxvmE+vQ1Hfg71VEHpnyjWFTqzKqB+0FOaOGKI3SYg3\n" + + "iKdnfycia6sqH+/CRQB5zWYBwtk9s6PROeHZzk2PVTVDQjlHLeUW8tBl40yFETtH\n" + + "+POXhrmcVVnS0ZZQ2Dogq0Bz0h4a8R1V1TG2CaK6D8viMmiWp1aAFoMoqQZpiA1f\n" + + "GiDTNkSzLBpLj00bSEyNmZRjkDe8YMuC6ls4z568zF38ARA8f568HRusxBjCvAJF\n" + + "ZDE+biSbwsI8BBgBCgHwBYJa6P+ACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5v\n" + + "dGF0aW9ucy5zZXF1b2lhLXBncC5vcmf0NGelgx9vvPxdcRBLogKbI559pRjWdg3i\n" + + "GpJSc3akDgKbAsC8oAQZAQoAbwWCWuj/gAkQEPy8/w6Op5FHFAAAAAAAHgAgc2Fs\n" + + "dEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3Jn61QE8l97YHDNs+NX6mKrsVYSUWrz\n" + + "evsNklOMRBvvkqgWIQTOphDQhPpR8hHhxGwQ/Lz/Do6nkQAARlYIALAfDNiiOXMV\n" + + "yioFRy9XRH84PYWpVWr5LX3E+mVQv/mg6feLbwQi9ehroauHHDewwE61seN9Pxnn\n" + + "GOhO+6r4Q85gnJUm3S24mZrK1V/ZApk36ycxUOuCn7yEuRoGy9tfmSfqSlthzjAR\n" + + "p+rIAD5k6jOVLAwqbBCg7eQiXCa97E3PA/TYRJ3NHSrEPdfp/ZrN1ubcshOq/acj\n" + + "Ok4QQjIW0JEe4RPV1gEHjtSC0hRp4ntGhXE1NDqNMC9TGoksgP/F6Sqtt8X8dZDU\n" + + "vYUJHatGlnoTaEyXQrdTatXFgActq0EdMfqoRlqMH7AI5wWrrcb3rdvLdpDwgCDJ\n" + + "4mKVnPPQcH4WIQTjLLbaggKRt+dtsagIrVHK5HDwBgAAqtYH/0Ox/UXuUlpPlDp/\n" + + "zUD0XnX+eOGCf2HUJ73v4Umjxi993FM3+MscxSC5ytfSK3eX/P5k09aYPfS94sRN\n" + + "zedN9SSSsBaQgevUbMrIPPGSwy9lS3N8XbAEHVG1WgqnkRysLTLaQb2wBbxfaZcG\n" + + "ptEklxx6/yZGJubn1zeiPIm/58K9WxW3/0ntFrpPURuJ3vSVAQqxsWpMlXfjoCy4\n" + + "b8zpiWu3wwtLlGYUyhW4zMS4WmrOBxWIkW389k9Mc/YMg8rQ1rBBTPl6Ch5RB/Bc\n" + + "f1Ngef/DdEPqSBaBLjpgTvuRD7zyJcTQch4ImjSLirdTLvlAG9kqZeg+c2w31/97\n" + + "6sXYWB8=\n" + + "=13Sf\n" + + "-----END PGP PUBLIC KEY BLOCK-----\n"; + TestSignature t0 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJYaEaACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmeoPMfalw2oS7uyOKnOXJSN8Gx7pr/BMlo3Xn8nTgx6\n" + + "ORYhBOMsttqCApG3522xqAitUcrkcPAGAABXbAf/WfWaQYNuATAKwxYrJx4fd5kt\n" + + "0M6sn1q7wK1MIxursG2+FuKafV25O9+pde8Nog77OEgegwk+HokOVFpVXfOzHQjs\n" + + "8dwWTtTQlX5NIBNvtqS7cvCKhjsqaHKgmzsenMjCEbpDZ3C5CoqcYicykqEU/Ia0\n" + + "ZGC4lzRByrgNy/w+/iLN748S707bzBLVc/sE73k9N5pANAlE+cA/sHI1Gp2WxJR9\n" + + "t2Fk4x6/85PEnF1RHI16p/wSEeuRaBpyw9QGZBbVDVt5wvgttxZjteGGSwBM3WI/\n" + + "gPfC0LW+JQ2W+dwY0PN/7yuARVRhXpKiBI4xqp7x3OanQX6quU77g3B8nXAt3A==\n" + + "=StqT\n" + + "-----END PGP SIGNATURE-----\n", false, "Signature predates primary key"); + TestSignature t1 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJa564ACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmfM0EN4Ei0bQv6UO9BRq2wtUfV948cRynRMBb8TSGCG\n" + + "tBYhBOMsttqCApG3522xqAitUcrkcPAGAAAlNwf+L0KQK9i/xmYKOMV2EX13QUoZ\n" + + "vvb/pHGZaCQ9JtvEF2l2DT0DqByZ+tOv5Y4isU+un7CraoyvyajAwR0Yqk937B6C\n" + + "HQHKMkmIl+5R4/xqSoWYmOidbrgilojPMBEhB3INQ8/THjjFijtLzitVhnWBd7+u\n" + + "s0kcqnWnOdx2By4aDe+UEiyCfSE02e/0tIsM71RqiU91zH6dl6+q8nml7PsYuTFV\n" + + "V09oQTbBuuvUe+YgN/uvyKVIsA64lQ+YhqEeIA8Quek7fHhW+du9OIhSPsbYodyx\n" + + "VWMTXwSWKGNvZNAkpmgUYqFjS2Cx5ZUWblZLjrNKBwnnmt50qvUN7+o2pjlnfA==\n" + + "=UuXb\n" + + "-----END PGP SIGNATURE-----\n", false, "Hard revocations invalidate key at all times"); + TestSignature t2 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJdP4iACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmfFzYGoiuSjN+gz1IDD4ZvRXGuPTHks0/pIiGY90mrZ\n" + + "WxYhBOMsttqCApG3522xqAitUcrkcPAGAABGPAf/ck7tJAFoPIDd9fTPZANpNGoW\n" + + "Fq6VuNfy/nLjz2gkHFX/lLAxQ0N3McIdRA++Ik/omb0lis3R2DVNgwqNm2OF34HE\n" + + "qxmPmrQHBgk2q0fDH4NCE0XnYQjQT65V99IfiaQu+oS3Mq8MuYsDYvRVvRKMwt49\n" + + "fcDnvFtAtCqEETdv6wV5cUZmdQ3L9NU9bApJ0jk+EHVdpfTUIbOYYGnsIe/4Aa0d\n" + + "jgzu4Em79ynosOn//953XJ7OO8LCDi1EKt+nFuZARUlt/Jwwull6zzp7HUPw6HPt\n" + + "Upp7os8TIPC4STwoSeEKaxEkrbMGFnDcoDajnKKRt5+MkB24Oq7PHvnzgnPpVg==\n" + + "=Ljv7\n" + + "-----END PGP SIGNATURE-----\n", false, "Hard revocations invalidate key at all times"); + TestSignature t3 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJmhTYiCRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmfbjQf/zfoJQT0hhna4RDjOESBLgGaCbc5HLeo751F4\n" + + "NxYhBOMsttqCApG3522xqAitUcrkcPAGAABqBQgAkkNmYf6yLPvox+ZayrLtMb9D\n" + + "ghgt0nau72DSazsJ6SAq2QqIdr0RRhRa2gCETkp4PpeoDWmIvoVj35ZnfyeO/jqy\n" + + "HECvRwO0WPA5FXQM6uG7s40vDTRFjlJMpPyHWnn2igcR64iDxBGmc40xi9CcmJP9\n" + + "tmA26+1Nzj1LcfNvknKZ2UIOmnXiZY0QssIdyqsmJrdFpXs4UCLUzdXkfFLoxksU\n" + + "mk4B6hig2IKMj5mnbWy/JQSXtjjI+HHmtzgWfXs7d9iQ61CklbtCOiPeWxvoqlGG\n" + + "oK1wV1olcSar/RPKTlMmQpAg9dztQgrNs1oF7EF3i9kwNP7I5JzekPiOLH6oMw==\n" + + "=5KMU\n" + + "-----END PGP SIGNATURE-----\n", false, "Hard revocations invalidate key at all times"); + + signatureValidityTest(api, cert, t0, t1, t2, t3); + } + + private void testSKSignsPKRevokedNoSubpacket(OpenPGPApi api) + throws IOException + { + // https://sequoia-pgp.gitlab.io/openpgp-interoperability-test-suite/results.html#Key_revocation_test__subkey_signs__primary_key_is_revoked__revoked__no_subpacket + String cert = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + + "\n" + + "xsBNBFpJegABCACzr1V+GxVkrtfDjihYK+HtyEIcO52uw7O2kd7JbduYp4RK17jy\n" + + "75N3EnsgmiIkSxXCWr+rTtonNs1zCJeUa/gwnNfs7mVgjL2rMOZU/KZ4MP0yOYU5\n" + + "u5FjNPWz8hpFQ9GKqfdj0Op61h1pCQO45IjUQ3dCDj9Rfn44zHMB1ZrbmIH9nTR1\n" + + "YIGHWmdm0LItb2WxIkwzWBAJ5acTlsmLyZZEQ1+8NDqktyzwFoQqTJvLU4StY2k6\n" + + "h18ZKZdPyrdLoEyOuWkvjxmbhDk1Gt5KiS/yy7mrzIPLr0dmJe4vc8WLV+bXoyNE\n" + + "x3H8o9CFcYehLfyqsy40lg92d6Kp96ww8dZ5ABEBAAHCwLsEIAEKAG8FglwqrYAJ\n" + + "EAitUcrkcPAGRxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9y\n" + + "Z4KjdWVHTHye8HeUynibpgE5TYfFnnBt9bbOj99oplaTFiEE4yy22oICkbfnbbGo\n" + + "CK1RyuRw8AYAAMxeB/4+QAncX1+678HeO1fweQ0Zkf4O6+Ew6EgCp4I2UZu+a5H8\n" + + "ryI3B4WNShCDoV3CfOcUtUSUA8EOyrpYSW/3jPVfb01uxDNsZpf9piZG7DelIAef\n" + + "wvQaZHJeytchv5+Wo+Jo6qg26BgvUlXW2x5NNcScGvCZt1RQ712PRDAfUnppRXBj\n" + + "+IXWzOs52uYGFDFzJSLEUy6dtTdNCJk78EMoHsOwC7g5uUyHbjSfrdQncxgMwikl\n" + + "C2LFSS7xYZwDgkkb70AT10Ot2jL6rLIT/1ChQZ0oRGJLBHiz3FUpanDQIDD49+dp\n" + + "6FUmUUsubwwFkxBHyCbQ8cdbfBILNiD1pEo31dPTwsDEBB8BCgB4BYJeC+EACRAI\n" + + "rVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmeH\n" + + "LGXtWodbY9gI8X3QzLB9sL0hMGY2/+9yAip5uwckkAIVCgKbAwIeARYhBOMsttqC\n" + + "ApG3522xqAitUcrkcPAGAABmBQgAoipwm9jQWWvyY9WiXuEdq8T2Y9hEV1nt2ySj\n" + + "Tyk+ytK1Q5E8NSUYk3wrLgGNpWPbCiXYUGZfms15uuL703OoRBkUP/l7LA5RNgyJ\n" + + "/At+Bw3OPeWZ68hzQfA3eZdR3Y6sXxiGOhwTyVHcdHXncD+NjorIPbeSrAvM5Xf/\n" + + "jCEYM5Kfg4NC1yVZw7sFhD6KNjeloQK+UXi718QC1+YbfS295T9AwEmbwCsvQTv8\n" + + "EQq9veCfHYPwqMAH5aMn9CqPiY8o2p5mZ92nMuQhpFTdpnPjxVHpBmQw8uaKGJIF\n" + + "zvwpgKbkzb2m3LfgOyFVXVljOUlm/dCb2lfUlo4up0KYVZu0rcLAxAQfAQoAeAWC\n" + + "Wkl6AAkQCK1RyuRw8AZHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1w\n" + + "Z3Aub3Jn1WXYy2GcQ19ob8t2hq7BOItGrywzM393vZFR5mg+jwICFQoCmwMCHgEW\n" + + "IQTjLLbaggKRt+dtsagIrVHK5HDwBgAAUGMIAK3yEcaveZ6VCgDj17NuZ2Zb8vsU\n" + + "G65rE8R4QGFvHhhXM/NkMLpqKq0fFX66I8TPngmXUyPOZzOZM852A1NvnDIbGVZu\n" + + "flYRmct3t0B+CfxN9Q+7daKQr4+YNXkSeC4MsAfnGBnGQWKf20E/UlGLoWR9jlwk\n" + + "dOKkm6VVAiAKZ4QR8SjbTpaowJB3mjnVv/F3j7G3767VTixmIK2V32Ozast/ls23\n" + + "ZvFL1TxVx/rhxM04Mr2G5yQWJIzkZgqlCrPOtDy/HpHoPrC+Dx0kY9VFH8HEA+ea\n" + + "tJt1bXsNioiFIuMCouS3Hg7aa46DubrVP9WHxAIjTHkkB1yqvN3aWs7461LNEmp1\n" + + "bGlldEBleGFtcGxlLm9yZ8LAxAQTAQoAeAWCWkl6AAkQCK1RyuRw8AZHFAAAAAAA\n" + + "HgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3JnOkYsewniH1sJ2kI5N2wa\n" + + "5AImO40vTfrIbkXR2dICirICFQoCmwMCHgEWIQTjLLbaggKRt+dtsagIrVHK5HDw\n" + + "BgAAn/UIALMbXwG8hm7aH46107PZbChFrxoJNNn0mMioz28mkaoe9jJSJVF8KqtY\n" + + "odkyXN78BfGjVQ63G/Q5wWm3bdjNbyNz1Gnht9QZmpAv12QjQq22yZMnf73TC6sO\n" + + "6ay66dGrlTTYS2MTivbrF2wpTcZbqOIv5UhVaOQfWovp3tZCioqZc6stqqoXXqZa\n" + + "JnMBh2wdQpGdOA5gjG0khQBsWKlAv2wZtG6JQnm8PyiM/bBKIzSrepr7BTeu/4TG\n" + + "HiUtB1ZcMHOovIikswtg+d4ssIbb5HYihAl0Hlw3/czVwJ9cKStNUiydIooO3Axa\n" + + "7aKpHz2M2zXwtG7d+HzcfYs98PWhB/HOwE0EWkrLgAEIALucmrvabJbZlolJ+37E\n" + + "Uqm0CJztIlp7uAyvSFwd4ITWDHIotySRIx84CMRn9xoiRI87m8kUGl+Sf6e8gdXz\n" + + "h/M+xWFLmsdbGhn/XNf29NjfYMlzZR2pt9YTWmi933xXMyPeaezDa07a6E7eaGar\n" + + "HPovqCi2Z+19GACOLRGMIUp1EGAfxe2KpJCOHlfuwsWTwPKQYV4gDiv85+Nej7Ge\n" + + "iUucLDOucgrTh3AACAZyg5wvm0Ivn9VmXrEqHMv618d0BEJqHQ7t6I4UvlcXGBnm\n" + + "QlHBRdBcmQSJBoxyFUC8jn4z9xUSeKhVzM/f2CFaDOGOoLkxETExI/ygxuAT+0Xy\n" + + "R00AEQEAAcLCPAQYAQoB8AWCXgvhAAkQCK1RyuRw8AZHFAAAAAAAHgAgc2FsdEBu\n" + + "b3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3Jn3AGtWT1k7YOtMNzqOHbeBWvHChWG2WLK\n" + + "g0h1eacBHzMCmwLAvKAEGQEKAG8Fgl4L4QAJEBD8vP8OjqeRRxQAAAAAAB4AIHNh\n" + + "bHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZy+iNvlcjeU9RaFYI93HZzC2AqXA\n" + + "eYvxUUglSsm7i864FiEEzqYQ0IT6UfIR4cRsEPy8/w6Op5EAAK5PB/wIYzPZam33\n" + + "xS+kUUeB043pbKcuAN58k4nApY6w7lw1Idtxny72o00eYdemQagBe3KW/a65c9Qt\n" + + "VnEuSS1cc1wHu3/ijn17vnsi4aU82fFU96St4RxmmMJVZV6wWT9CV4C/IZuoQ0l2\n" + + "UGbXKbJ0NbiBwvTjcVAeJYjRYU6kAkGHUCRYhbNbplG6PwuCnc5QyNPGzNwqhCmr\n" + + "fb1BbhhuvJg4NAq0WRFrfeOi+YvJGZgVJEkoSJtpOXtqhP5rmHjOqikDbMZcd1SH\n" + + "+XlIbcQovX4O0o7x5HVEhbLWHMQHWqIVghQhLAySNdoc3CkGs0o77SheATQSoF/8\n" + + "C7G1UJ2C3fYIFiEE4yy22oICkbfnbbGoCK1RyuRw8AYAADYzB/9TGOwycsZIk43P\n" + + "485p1carRzmQwkplKpNHof+gR7PqLLVqpBguvu3X8Q56bcHKmp3WHsuChdmo7eJz\n" + + "sLtMUMPzRBd4vNYeyInsGOxvmE+vQ1Hfg71VEHpnyjWFTqzKqB+0FOaOGKI3SYg3\n" + + "iKdnfycia6sqH+/CRQB5zWYBwtk9s6PROeHZzk2PVTVDQjlHLeUW8tBl40yFETtH\n" + + "+POXhrmcVVnS0ZZQ2Dogq0Bz0h4a8R1V1TG2CaK6D8viMmiWp1aAFoMoqQZpiA1f\n" + + "GiDTNkSzLBpLj00bSEyNmZRjkDe8YMuC6ls4z568zF38ARA8f568HRusxBjCvAJF\n" + + "ZDE+biSbwsI8BBgBCgHwBYJa6P+ACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5v\n" + + "dGF0aW9ucy5zZXF1b2lhLXBncC5vcmf0NGelgx9vvPxdcRBLogKbI559pRjWdg3i\n" + + "GpJSc3akDgKbAsC8oAQZAQoAbwWCWuj/gAkQEPy8/w6Op5FHFAAAAAAAHgAgc2Fs\n" + + "dEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3Jn61QE8l97YHDNs+NX6mKrsVYSUWrz\n" + + "evsNklOMRBvvkqgWIQTOphDQhPpR8hHhxGwQ/Lz/Do6nkQAARlYIALAfDNiiOXMV\n" + + "yioFRy9XRH84PYWpVWr5LX3E+mVQv/mg6feLbwQi9ehroauHHDewwE61seN9Pxnn\n" + + "GOhO+6r4Q85gnJUm3S24mZrK1V/ZApk36ycxUOuCn7yEuRoGy9tfmSfqSlthzjAR\n" + + "p+rIAD5k6jOVLAwqbBCg7eQiXCa97E3PA/TYRJ3NHSrEPdfp/ZrN1ubcshOq/acj\n" + + "Ok4QQjIW0JEe4RPV1gEHjtSC0hRp4ntGhXE1NDqNMC9TGoksgP/F6Sqtt8X8dZDU\n" + + "vYUJHatGlnoTaEyXQrdTatXFgActq0EdMfqoRlqMH7AI5wWrrcb3rdvLdpDwgCDJ\n" + + "4mKVnPPQcH4WIQTjLLbaggKRt+dtsagIrVHK5HDwBgAAqtYH/0Ox/UXuUlpPlDp/\n" + + "zUD0XnX+eOGCf2HUJ73v4Umjxi993FM3+MscxSC5ytfSK3eX/P5k09aYPfS94sRN\n" + + "zedN9SSSsBaQgevUbMrIPPGSwy9lS3N8XbAEHVG1WgqnkRysLTLaQb2wBbxfaZcG\n" + + "ptEklxx6/yZGJubn1zeiPIm/58K9WxW3/0ntFrpPURuJ3vSVAQqxsWpMlXfjoCy4\n" + + "b8zpiWu3wwtLlGYUyhW4zMS4WmrOBxWIkW389k9Mc/YMg8rQ1rBBTPl6Ch5RB/Bc\n" + + "f1Ngef/DdEPqSBaBLjpgTvuRD7zyJcTQch4ImjSLirdTLvlAG9kqZeg+c2w31/97\n" + + "6sXYWB8=\n" + + "=13Sf\n" + + "-----END PGP PUBLIC KEY BLOCK-----\n"; + TestSignature t0 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJYaEaACRAQ/Lz/Do6nkUcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmdVa4OG6WfRoRlj5+Zb6avhJUIZFvcIFiLuvrJp8Hio\n" + + "iBYhBM6mENCE+lHyEeHEbBD8vP8OjqeRAAAbaQgAjhBh0dLO0Sqiqkb2M3KWc25V\n" + + "hJlcP3isFROJ0jikmXxkG9W04AvlA78tSxEP2n8a0CbxH/hT4g8mFb/qM5FKZcKf\n" + + "HQxjbjUxBmVHa3EfMkwT7u1mVRmoWtJ59oVsKoqRb/kZ14i6VZ9NzfK8MRlL0e24\n" + + "oNjkksZQ8ImjwwtvxSinxhezA6BtWi+dDnXAnG5Vva+6N/GRNPAAd8kFTPrlEqEz\n" + + "uRbpq76r4taPjRjzMNcwZJoRVHSahWhDcXxNTalVUwt0DZFAskZ3gI+0VgU11bK1\n" + + "QmIw2iR4itQY5f10HFNcl7uHLKnul0YyuvA5509HwCuEpdYUV/OxtlpVRaJ+yg==\n" + + "=Rc6K\n" + + "-----END PGP SIGNATURE-----\n", false, "Signature predates primary key"); + TestSignature t1 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJa564ACRAQ/Lz/Do6nkUcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmfcG7Iqn3OOKVjeJ61MlgERt08kcxh0x+BZFD7a8K7V\n" + + "VBYhBM6mENCE+lHyEeHEbBD8vP8OjqeRAACBIwf9EoS24IFeT3cPFf/nWxLFkbZK\n" + + "fiy9WzyK4wlpO3VTyWPbXi6zpC4I5Rbp2jDk/c7Q3DnOZqFDv6TriTwuLYTJGPxr\n" + + "U3dtDsFcKp4FcbgFyCDKIuLB+3kLaNpMXqdttEkY3Wd5m33XrBB7M0l5xZCk56Jm\n" + + "H5L1sGNNNkCzG6P44qu69o5fkWxbYuX22fyhdeyxucJHMztqiMQYDwT7eSA92A1v\n" + + "5OwA5D/k7GeyYFBFisxRijkdVtxstC9zkagC19VnZo7MRekA9gXj7kIna4XYRhfb\n" + + "uQnN47HXdiWQytwypLvZ8JEJpRruyMAaHjX5OBXh0SK11xYWb6wB93+QfOahtg==\n" + + "=UlUZ\n" + + "-----END PGP SIGNATURE-----\n", false, "Hard revocations invalidate key at all times"); + TestSignature t2 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJdP4iACRAQ/Lz/Do6nkUcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmcgkZw3ZSg8CZCKqJw2r4VqCpTuUhz6N0zX43d+1xop\n" + + "2hYhBM6mENCE+lHyEeHEbBD8vP8OjqeRAADnqAgAq+m6dDZpNOBaXH9nwv8/+HgR\n" + + "MvRjnuLoa6zB5tcUhGPPVS0gg1PW0wfxlo1GPmgW3QDlV1zvcfYAZmV9uEC61wn/\n" + + "+FkqN0Tceo487UvkWARE/mmRj5L8OgUTfqm1eebFQlMu/MeG9YOg+tXBy7XS7hy3\n" + + "UdntIbtsv5oRTcybTnn5oiU2OFDlFC6sBNzOQt7wpyB1TKp2BdcsAv1RwmyCCCK4\n" + + "bnmrpYH6woWMyVEVeMYfOHAx9vHD+od8Vf/v5L1M2N0nHzRWjjkobTVUr+xt/CyW\n" + + "nq8SoazKYu3ETpZLeWX6Bciuv9+pzUCeClOSmBB1MFyyrTgbkOacHgrYnLvvtQ==\n" + + "=WCKA\n" + + "-----END PGP SIGNATURE-----\n", false, "Hard revocations invalidate key at all times"); + TestSignature t3 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJmhTYiCRAQ/Lz/Do6nkUcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmdi3dCpJ4nZincNH5owv8+fJ5YpXljqtegtoBEnbbHP\n" + + "thYhBM6mENCE+lHyEeHEbBD8vP8OjqeRAAD0cQf/e8RHocRESJPbosqUuvC3ELnD\n" + + "oSsJomDMUDfSfgpS5EhkOyJhvcrHkCbsHH2xlUEQ+zjJWY/dwM3FUkoj+p3kb/JC\n" + + "Rn5cqQYlME+uJzjdHMyQCSOI1SvYwKCLCGPARDbCpeINrV++Oy29e6cv6/IcPlgo\n" + + "k/0A7XuNq0YNxC7oopCj5ye3yVUvUmSCG2iV4oiWW5GhhPRzMeW7MFQmS0NUkAI8\n" + + "hzJ8juTG4xP8SXnHCMakasZhJmtpMDd2BDZ7CrhWiWUQGrtd0eYkuyodreqVMGIF\n" + + "BN80YgTNFW2MrblhDRRmxAqWzD9FedBwwSdgYbtkDwjsSq0S1jQV6aPndJqiLw==\n" + + "=CIl0\n" + + "-----END PGP SIGNATURE-----\n", false, "Hard revocations invalidate key at all times"); + + signatureValidityTest(api, cert, t0, t1, t2, t3); + } + + private void testPKSignsPKRevocationSuperseded(OpenPGPApi api) + throws IOException + { + // https://sequoia-pgp.gitlab.io/openpgp-interoperability-test-suite/results.html#Key_revocation_test__primary_key_signs_and_is_revoked__revoked__superseded + String CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + + "\n" + + "xsBNBFpJegABCACzr1V+GxVkrtfDjihYK+HtyEIcO52uw7O2kd7JbduYp4RK17jy\n" + + "75N3EnsgmiIkSxXCWr+rTtonNs1zCJeUa/gwnNfs7mVgjL2rMOZU/KZ4MP0yOYU5\n" + + "u5FjNPWz8hpFQ9GKqfdj0Op61h1pCQO45IjUQ3dCDj9Rfn44zHMB1ZrbmIH9nTR1\n" + + "YIGHWmdm0LItb2WxIkwzWBAJ5acTlsmLyZZEQ1+8NDqktyzwFoQqTJvLU4StY2k6\n" + + "h18ZKZdPyrdLoEyOuWkvjxmbhDk1Gt5KiS/yy7mrzIPLr0dmJe4vc8WLV+bXoyNE\n" + + "x3H8o9CFcYehLfyqsy40lg92d6Kp96ww8dZ5ABEBAAHCwM8EIAEKAIMFglwqrYAJ\n" + + "EAitUcrkcPAGRxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9y\n" + + "Z1X0jZPeNNpSsn78ulDPJNHa0QaeI5oAUdBGbIKSOT0uEx0BS2V5IGlzIHN1cGVy\n" + + "c2VkZWQWIQTjLLbaggKRt+dtsagIrVHK5HDwBgAAr2QIAKAY5bHFbRkoItYBJBN1\n" + + "aV1jjrpYdwLM+0LHf8GcRCeO1Pt9I1J021crwTw14sTCxi6WH4qbQSBxRqAEej/A\n" + + "wfk1kmkm4WF7zTUT+fXIHDJxFJJXqFZ+LWldYYEVqSi02gpbYkyLm9hxoLDoAxS2\n" + + "bj/sFaH4Bxr/eUCqjOiEsGzdY1m65+cp5jv8cJK05jwqxO5/3KZcF/ShA7AN3dJi\n" + + "NAokoextBtXBWlGvrDIfFafOy/uCnsO6NeORWbgZ88TOXPD816ff5Y8kMwkDkIk2\n" + + "9dK4m0aL/MDI+Fgx78zRYwn5xHbTMaFz+hex+gjo4grx3KYXeoxBAchUuTsVNoo4\n" + + "kbfCwMQEHwEKAHgFgl4L4QAJEAitUcrkcPAGRxQAAAAAAB4AIHNhbHRAbm90YXRp\n" + + "b25zLnNlcXVvaWEtcGdwLm9yZ4csZe1ah1tj2AjxfdDMsH2wvSEwZjb/73ICKnm7\n" + + "BySQAhUKApsDAh4BFiEE4yy22oICkbfnbbGoCK1RyuRw8AYAAGYFCACiKnCb2NBZ\n" + + "a/Jj1aJe4R2rxPZj2ERXWe3bJKNPKT7K0rVDkTw1JRiTfCsuAY2lY9sKJdhQZl+a\n" + + "zXm64vvTc6hEGRQ/+XssDlE2DIn8C34HDc495ZnryHNB8Dd5l1HdjqxfGIY6HBPJ\n" + + "Udx0dedwP42Oisg9t5KsC8zld/+MIRgzkp+Dg0LXJVnDuwWEPoo2N6WhAr5ReLvX\n" + + "xALX5ht9Lb3lP0DASZvAKy9BO/wRCr294J8dg/CowAfloyf0Ko+JjyjanmZn3acy\n" + + "5CGkVN2mc+PFUekGZDDy5ooYkgXO/CmApuTNvabct+A7IVVdWWM5SWb90JvaV9SW\n" + + "ji6nQphVm7StwsDEBB8BCgB4BYJaSXoACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0\n" + + "QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfVZdjLYZxDX2hvy3aGrsE4i0avLDMz\n" + + "f3e9kVHmaD6PAgIVCgKbAwIeARYhBOMsttqCApG3522xqAitUcrkcPAGAABQYwgA\n" + + "rfIRxq95npUKAOPXs25nZlvy+xQbrmsTxHhAYW8eGFcz82QwumoqrR8VfrojxM+e\n" + + "CZdTI85nM5kzznYDU2+cMhsZVm5+VhGZy3e3QH4J/E31D7t1opCvj5g1eRJ4Lgyw\n" + + "B+cYGcZBYp/bQT9SUYuhZH2OXCR04qSbpVUCIApnhBHxKNtOlqjAkHeaOdW/8XeP\n" + + "sbfvrtVOLGYgrZXfY7Nqy3+Wzbdm8UvVPFXH+uHEzTgyvYbnJBYkjORmCqUKs860\n" + + "PL8ekeg+sL4PHSRj1UUfwcQD55q0m3Vtew2KiIUi4wKi5LceDtprjoO5utU/1YfE\n" + + "AiNMeSQHXKq83dpazvjrUs0SanVsaWV0QGV4YW1wbGUub3JnwsDEBBMBCgB4BYJa\n" + + "SXoACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBn\n" + + "cC5vcmc6Rix7CeIfWwnaQjk3bBrkAiY7jS9N+shuRdHZ0gKKsgIVCgKbAwIeARYh\n" + + "BOMsttqCApG3522xqAitUcrkcPAGAACf9QgAsxtfAbyGbtofjrXTs9lsKEWvGgk0\n" + + "2fSYyKjPbyaRqh72MlIlUXwqq1ih2TJc3vwF8aNVDrcb9DnBabdt2M1vI3PUaeG3\n" + + "1BmakC/XZCNCrbbJkyd/vdMLqw7prLrp0auVNNhLYxOK9usXbClNxluo4i/lSFVo\n" + + "5B9ai+ne1kKKiplzqy2qqhdeplomcwGHbB1CkZ04DmCMbSSFAGxYqUC/bBm0bolC\n" + + "ebw/KIz9sEojNKt6mvsFN67/hMYeJS0HVlwwc6i8iKSzC2D53iywhtvkdiKECXQe\n" + + "XDf9zNXAn1wpK01SLJ0iig7cDFrtoqkfPYzbNfC0bt34fNx9iz3w9aEH8c7ATQRa\n" + + "SsuAAQgAu5yau9psltmWiUn7fsRSqbQInO0iWnu4DK9IXB3ghNYMcii3JJEjHzgI\n" + + "xGf3GiJEjzubyRQaX5J/p7yB1fOH8z7FYUuax1saGf9c1/b02N9gyXNlHam31hNa\n" + + "aL3ffFczI95p7MNrTtroTt5oZqsc+i+oKLZn7X0YAI4tEYwhSnUQYB/F7YqkkI4e\n" + + "V+7CxZPA8pBhXiAOK/zn416PsZ6JS5wsM65yCtOHcAAIBnKDnC+bQi+f1WZesSoc\n" + + "y/rXx3QEQmodDu3ojhS+VxcYGeZCUcFF0FyZBIkGjHIVQLyOfjP3FRJ4qFXMz9/Y\n" + + "IVoM4Y6guTERMTEj/KDG4BP7RfJHTQARAQABwsI8BBgBCgHwBYJeC+EACRAIrVHK\n" + + "5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfcAa1Z\n" + + "PWTtg60w3Oo4dt4Fa8cKFYbZYsqDSHV5pwEfMwKbAsC8oAQZAQoAbwWCXgvhAAkQ\n" + + "EPy8/w6Op5FHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3Jn\n" + + "L6I2+VyN5T1FoVgj3cdnMLYCpcB5i/FRSCVKybuLzrgWIQTOphDQhPpR8hHhxGwQ\n" + + "/Lz/Do6nkQAArk8H/AhjM9lqbffFL6RRR4HTjelspy4A3nyTicCljrDuXDUh23Gf\n" + + "LvajTR5h16ZBqAF7cpb9rrlz1C1WcS5JLVxzXAe7f+KOfXu+eyLhpTzZ8VT3pK3h\n" + + "HGaYwlVlXrBZP0JXgL8hm6hDSXZQZtcpsnQ1uIHC9ONxUB4liNFhTqQCQYdQJFiF\n" + + "s1umUbo/C4KdzlDI08bM3CqEKat9vUFuGG68mDg0CrRZEWt946L5i8kZmBUkSShI\n" + + "m2k5e2qE/muYeM6qKQNsxlx3VIf5eUhtxCi9fg7SjvHkdUSFstYcxAdaohWCFCEs\n" + + "DJI12hzcKQazSjvtKF4BNBKgX/wLsbVQnYLd9ggWIQTjLLbaggKRt+dtsagIrVHK\n" + + "5HDwBgAANjMH/1MY7DJyxkiTjc/jzmnVxqtHOZDCSmUqk0eh/6BHs+ostWqkGC6+\n" + + "7dfxDnptwcqandYey4KF2ajt4nOwu0xQw/NEF3i81h7IiewY7G+YT69DUd+DvVUQ\n" + + "emfKNYVOrMqoH7QU5o4YojdJiDeIp2d/JyJrqyof78JFAHnNZgHC2T2zo9E54dnO\n" + + "TY9VNUNCOUct5Rby0GXjTIURO0f485eGuZxVWdLRllDYOiCrQHPSHhrxHVXVMbYJ\n" + + "oroPy+IyaJanVoAWgyipBmmIDV8aINM2RLMsGkuPTRtITI2ZlGOQN7xgy4LqWzjP\n" + + "nrzMXfwBEDx/nrwdG6zEGMK8AkVkMT5uJJvCwjwEGAEKAfAFglro/4AJEAitUcrk\n" + + "cPAGRxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZ/Q0Z6WD\n" + + "H2+8/F1xEEuiApsjnn2lGNZ2DeIaklJzdqQOApsCwLygBBkBCgBvBYJa6P+ACRAQ\n" + + "/Lz/Do6nkUcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfr\n" + + "VATyX3tgcM2z41fqYquxVhJRavN6+w2SU4xEG++SqBYhBM6mENCE+lHyEeHEbBD8\n" + + "vP8OjqeRAABGVggAsB8M2KI5cxXKKgVHL1dEfzg9halVavktfcT6ZVC/+aDp94tv\n" + + "BCL16Guhq4ccN7DATrWx430/GecY6E77qvhDzmCclSbdLbiZmsrVX9kCmTfrJzFQ\n" + + "64KfvIS5GgbL21+ZJ+pKW2HOMBGn6sgAPmTqM5UsDCpsEKDt5CJcJr3sTc8D9NhE\n" + + "nc0dKsQ91+n9ms3W5tyyE6r9pyM6ThBCMhbQkR7hE9XWAQeO1ILSFGnie0aFcTU0\n" + + "Oo0wL1MaiSyA/8XpKq23xfx1kNS9hQkdq0aWehNoTJdCt1Nq1cWABy2rQR0x+qhG\n" + + "WowfsAjnBautxvet28t2kPCAIMniYpWc89BwfhYhBOMsttqCApG3522xqAitUcrk\n" + + "cPAGAACq1gf/Q7H9Re5SWk+UOn/NQPRedf544YJ/YdQnve/hSaPGL33cUzf4yxzF\n" + + "ILnK19Ird5f8/mTT1pg99L3ixE3N5031JJKwFpCB69Rsysg88ZLDL2VLc3xdsAQd\n" + + "UbVaCqeRHKwtMtpBvbAFvF9plwam0SSXHHr/JkYm5ufXN6I8ib/nwr1bFbf/Se0W\n" + + "uk9RG4ne9JUBCrGxakyVd+OgLLhvzOmJa7fDC0uUZhTKFbjMxLhaas4HFYiRbfz2\n" + + "T0xz9gyDytDWsEFM+XoKHlEH8Fx/U2B5/8N0Q+pIFoEuOmBO+5EPvPIlxNByHgia\n" + + "NIuKt1Mu+UAb2Spl6D5zbDfX/3vqxdhYHw==\n" + + "=9epL\n" + + "-----END PGP PUBLIC KEY BLOCK-----\n"; + TestSignature t0 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJYaEaACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmeoPMfalw2oS7uyOKnOXJSN8Gx7pr/BMlo3Xn8nTgx6\n" + + "ORYhBOMsttqCApG3522xqAitUcrkcPAGAABXbAf/WfWaQYNuATAKwxYrJx4fd5kt\n" + + "0M6sn1q7wK1MIxursG2+FuKafV25O9+pde8Nog77OEgegwk+HokOVFpVXfOzHQjs\n" + + "8dwWTtTQlX5NIBNvtqS7cvCKhjsqaHKgmzsenMjCEbpDZ3C5CoqcYicykqEU/Ia0\n" + + "ZGC4lzRByrgNy/w+/iLN748S707bzBLVc/sE73k9N5pANAlE+cA/sHI1Gp2WxJR9\n" + + "t2Fk4x6/85PEnF1RHI16p/wSEeuRaBpyw9QGZBbVDVt5wvgttxZjteGGSwBM3WI/\n" + + "gPfC0LW+JQ2W+dwY0PN/7yuARVRhXpKiBI4xqp7x3OanQX6quU77g3B8nXAt3A==\n" + + "=StqT\n" + + "-----END PGP SIGNATURE-----\n", false, "Signature predates primary key"); + TestSignature t1 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJa564ACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmfM0EN4Ei0bQv6UO9BRq2wtUfV948cRynRMBb8TSGCG\n" + + "tBYhBOMsttqCApG3522xqAitUcrkcPAGAAAlNwf+L0KQK9i/xmYKOMV2EX13QUoZ\n" + + "vvb/pHGZaCQ9JtvEF2l2DT0DqByZ+tOv5Y4isU+un7CraoyvyajAwR0Yqk937B6C\n" + + "HQHKMkmIl+5R4/xqSoWYmOidbrgilojPMBEhB3INQ8/THjjFijtLzitVhnWBd7+u\n" + + "s0kcqnWnOdx2By4aDe+UEiyCfSE02e/0tIsM71RqiU91zH6dl6+q8nml7PsYuTFV\n" + + "V09oQTbBuuvUe+YgN/uvyKVIsA64lQ+YhqEeIA8Quek7fHhW+du9OIhSPsbYodyx\n" + + "VWMTXwSWKGNvZNAkpmgUYqFjS2Cx5ZUWblZLjrNKBwnnmt50qvUN7+o2pjlnfA==\n" + + "=UuXb\n" + + "-----END PGP SIGNATURE-----\n", true); + TestSignature t2 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJdP4iACRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmfFzYGoiuSjN+gz1IDD4ZvRXGuPTHks0/pIiGY90mrZ\n" + + "WxYhBOMsttqCApG3522xqAitUcrkcPAGAABGPAf/ck7tJAFoPIDd9fTPZANpNGoW\n" + + "Fq6VuNfy/nLjz2gkHFX/lLAxQ0N3McIdRA++Ik/omb0lis3R2DVNgwqNm2OF34HE\n" + + "qxmPmrQHBgk2q0fDH4NCE0XnYQjQT65V99IfiaQu+oS3Mq8MuYsDYvRVvRKMwt49\n" + + "fcDnvFtAtCqEETdv6wV5cUZmdQ3L9NU9bApJ0jk+EHVdpfTUIbOYYGnsIe/4Aa0d\n" + + "jgzu4Em79ynosOn//953XJ7OO8LCDi1EKt+nFuZARUlt/Jwwull6zzp7HUPw6HPt\n" + + "Upp7os8TIPC4STwoSeEKaxEkrbMGFnDcoDajnKKRt5+MkB24Oq7PHvnzgnPpVg==\n" + + "=Ljv7\n" + + "-----END PGP SIGNATURE-----\n", false, "Key is revoked at this time"); + TestSignature t3 = new TestSignature("-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsC7BAABCgBvBYJmhTYiCRAIrVHK5HDwBkcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmfbjQf/zfoJQT0hhna4RDjOESBLgGaCbc5HLeo751F4\n" + + "NxYhBOMsttqCApG3522xqAitUcrkcPAGAABqBQgAkkNmYf6yLPvox+ZayrLtMb9D\n" + + "ghgt0nau72DSazsJ6SAq2QqIdr0RRhRa2gCETkp4PpeoDWmIvoVj35ZnfyeO/jqy\n" + + "HECvRwO0WPA5FXQM6uG7s40vDTRFjlJMpPyHWnn2igcR64iDxBGmc40xi9CcmJP9\n" + + "tmA26+1Nzj1LcfNvknKZ2UIOmnXiZY0QssIdyqsmJrdFpXs4UCLUzdXkfFLoxksU\n" + + "mk4B6hig2IKMj5mnbWy/JQSXtjjI+HHmtzgWfXs7d9iQ61CklbtCOiPeWxvoqlGG\n" + + "oK1wV1olcSar/RPKTlMmQpAg9dztQgrNs1oF7EF3i9kwNP7I5JzekPiOLH6oMw==\n" + + "=5KMU\n" + + "-----END PGP SIGNATURE-----\n", true); + + signatureValidityTest(api, CERT, t0, t1, t2, t3); + } + + private void signatureValidityTest(OpenPGPApi api, String cert, TestSignature... testSignatures) + throws IOException + { + OpenPGPCertificate certificate = api.readKeyOrCertificate().parseCertificate(cert); + + for (int i = 0; i != testSignatures.length; i++) + { + TestSignature test = testSignatures[i]; + PGPSignature signature = test.getSignature(); + OpenPGPCertificate.OpenPGPComponentKey signingKey = certificate.getSigningKeyFor(signature); + + boolean valid = signingKey.isBoundAt(signature.getCreationTime()); + if (valid != test.isExpectValid()) + { + StringBuilder sb = new StringBuilder("Key validity mismatch. Expected " + signingKey.toString() + + (test.isExpectValid() ? (" to be valid at ") : (" to be invalid at ")) + UTCUtil.format(signature.getCreationTime())); + if (test.getMsg() != null) + { + sb.append(" because:\n").append(test.getMsg()); + } + sb.append("\n").append(signingKey.getSignatureChains()); + fail(sb.toString()); + } + } + } + + private void testGetPrimaryUserId(OpenPGPApi api) + throws PGPException + { + final Date now = new Date((new Date().getTime() / 1000) * 1000); + Date oneHourAgo = new Date(now.getTime() - 1000 * 60 * 60); + + OpenPGPKeyGenerator gen = api.generateKey(oneHourAgo); + OpenPGPKey key = gen.withPrimaryKey() + .addUserId("Old non-primary ") + .addUserId("New primary ", + SignatureParameters.Callback.Util.modifyHashedSubpackets(new SignatureSubpacketsFunction() + { + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.removePacketsOfType(SignatureSubpacketTags.CREATION_TIME); + subpackets.setSignatureCreationTime(now); + subpackets.setPrimaryUserID(false, true); + return subpackets; + } + })) + .build(null); + isEquals("Expect to find valid, explicit primary user ID", + key.getUserId("New primary "), + key.getPrimaryUserId()); + + isEquals("Explicit primary UserID is not yet valid, so return implicit UID", + key.getUserId("Old non-primary "), + key.getPrimaryUserId(oneHourAgo)); + } + + public static class TestSignature + { + private final PGPSignature signature; + private final boolean expectValid; + private final String msg; + + public TestSignature(String armoredSignature, boolean expectValid) + throws IOException + { + this(armoredSignature, expectValid, null); + } + + public TestSignature(String armoredSignature, boolean expectValid, String msg) + throws IOException + { + this.signature = parseSignature(armoredSignature); + this.expectValid = expectValid; + this.msg = msg; + } + + private static PGPSignature parseSignature(String armoredSignature) + throws IOException + { + ByteArrayInputStream bIn = new ByteArrayInputStream(Strings.toUTF8ByteArray(armoredSignature)); + ArmoredInputStream aIn = new ArmoredInputStream(bIn); + BCPGInputStream pIn = new BCPGInputStream(aIn); + PGPObjectFactory objFac = new BcPGPObjectFactory(pIn); + + PGPSignatureList sigs = (PGPSignatureList) objFac.nextObject(); + + pIn.close(); + aIn.close(); + bIn.close(); + + return sigs.get(0); + } + + public PGPSignature getSignature() + { + return signature; + } + + public boolean isExpectValid() + { + return expectValid; + } + + public String getMsg() + { + return msg; + } + } + + public static void main(String[] args) + { + runTest(new OpenPGPCertificateTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPDetachedSignatureProcessorTest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPDetachedSignatureProcessorTest.java new file mode 100644 index 0000000000..1d86ee630d --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPDetachedSignatureProcessorTest.java @@ -0,0 +1,276 @@ +package org.bouncycastle.openpgp.api.test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Date; +import java.util.List; + +import org.bouncycastle.bcpg.SignatureSubpacketTags; +import org.bouncycastle.bcpg.sig.KeyFlags; +import org.bouncycastle.openpgp.OpenPGPTestKeys; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPKeyPair; +import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.bouncycastle.openpgp.api.KeyPairGeneratorCallback; +import org.bouncycastle.openpgp.api.OpenPGPApi; +import org.bouncycastle.openpgp.api.OpenPGPDetachedSignatureGenerator; +import org.bouncycastle.openpgp.api.OpenPGPDetachedSignatureProcessor; +import org.bouncycastle.openpgp.api.OpenPGPKey; +import org.bouncycastle.openpgp.api.OpenPGPSignature; +import org.bouncycastle.openpgp.api.SignatureParameters; +import org.bouncycastle.openpgp.api.SignatureSubpacketsFunction; +import org.bouncycastle.openpgp.operator.PGPKeyPairGenerator; +import org.bouncycastle.util.Strings; + +public class OpenPGPDetachedSignatureProcessorTest + extends APITest +{ + @Override + public String getName() + { + return "OpenPGPDetachedSignatureProcessorTest"; + } + + protected void performTestWith(OpenPGPApi api) + throws PGPException, IOException + { + String javaVersion = System.getProperty("java.version"); + boolean oldJDK = javaVersion.startsWith("1.5") || javaVersion.startsWith("1.6"); + + createVerifyV4Signature(api); + createVerifyV6Signature(api); + + keyPassphrasesArePairedUpProperly_keyAddedFirst(api); + keyPassphrasesArePairedUpProperly_passphraseAddedFirst(api); + + missingPassphraseThrows(api); + + if (!oldJDK) + { + wrongPassphraseThrows(api); + } + + withoutSigningSubkeyFails(api); + nonSigningSubkeyFails(api); + } + + private void createVerifyV4Signature(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPDetachedSignatureGenerator gen = api.createDetachedSignature(); + gen.addSigningKey( + api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.ALICE_KEY)); + + byte[] plaintext = Strings.toUTF8ByteArray("Hello, World!\n"); + ByteArrayInputStream plaintextIn = new ByteArrayInputStream(plaintext); + + List signatures = gen.sign(plaintextIn); + isEquals(1, signatures.size()); + OpenPGPSignature.OpenPGPDocumentSignature signature = signatures.get(0); + isEquals(4, signature.getSignature().getVersion()); + String armored = signature.toAsciiArmoredString(); + isTrue(armored.startsWith("-----BEGIN PGP SIGNATURE-----" + Strings.lineSeparator())); + + // Verify detached signatures + OpenPGPDetachedSignatureProcessor processor = api.verifyDetachedSignature(); + processor.addSignature(signature.getSignature()); + processor.addVerificationCertificate(api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.ALICE_CERT)); + + List verified = processor.process(new ByteArrayInputStream(plaintext)); + isEquals(1, verified.size()); + isTrue(verified.get(0).isValid()); + } + + private void createVerifyV6Signature(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPDetachedSignatureGenerator gen = api.createDetachedSignature(); + gen.addSigningKey( + api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY)); + + byte[] plaintext = Strings.toUTF8ByteArray("Hello, World!\n"); + ByteArrayInputStream plaintextIn = new ByteArrayInputStream(plaintext); + + List signatures = gen.sign(plaintextIn); + isEquals(1, signatures.size()); + OpenPGPSignature.OpenPGPDocumentSignature signature = signatures.get(0); + isEquals(6, signature.getSignature().getVersion()); + String armored = signature.toAsciiArmoredString(); + isTrue(armored.startsWith("-----BEGIN PGP SIGNATURE-----" + Strings.lineSeparator())); + + // Verify detached signatures + OpenPGPDetachedSignatureProcessor processor = api.verifyDetachedSignature(); + processor.addSignature(signature.getSignature()); + processor.addVerificationCertificate(api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.V6_CERT)); + + List verified = processor.process(new ByteArrayInputStream(plaintext)); + isEquals(1, verified.size()); + isTrue(verified.get(0).isValid()); + } + + private void missingPassphraseThrows(final OpenPGPApi api) + { + isNotNull(testException( + "Cannot unlock primary key CB186C4F0609A697E4D52DFA6C722B0C1F1E27C18A56708F6525EC27BAD9ACC9: Exception decrypting key", + "KeyPassphraseException", + new TestExceptionOperation() + { + public void operation() + throws Exception + { + api.createDetachedSignature() + .addSigningKey(api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY_LOCKED)) + .sign(new ByteArrayInputStream(Strings.toUTF8ByteArray("Test Data"))); + } + })); + } + + private void wrongPassphraseThrows(final OpenPGPApi api) + { + isNotNull(testException( + "Cannot unlock primary key CB186C4F0609A697E4D52DFA6C722B0C1F1E27C18A56708F6525EC27BAD9ACC9: Exception decrypting key", + "KeyPassphraseException", + new TestExceptionOperation() + { + public void operation() + throws Exception + { + api.createDetachedSignature() + .addKeyPassphrase("thisIsWrong".toCharArray()) + .addSigningKey(api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY_LOCKED)) + .sign(new ByteArrayInputStream(Strings.toUTF8ByteArray("Test Data"))); + } + })); + } + + private void keyPassphrasesArePairedUpProperly_keyAddedFirst(OpenPGPApi api) + throws PGPException, IOException + { + OpenPGPKey key = api.generateKey(new Date(), false) + .signOnlyKey() + .build("password".toCharArray()); + + OpenPGPDetachedSignatureGenerator gen = api.createDetachedSignature(); + gen.addSigningKey(key); + + gen.addKeyPassphrase("penguin".toCharArray()); + gen.addKeyPassphrase("password".toCharArray()); + gen.addKeyPassphrase("beluga".toCharArray()); + + byte[] plaintext = Strings.toUTF8ByteArray("arctic\ndeep sea\nice field\n"); + InputStream plaintextIn = new ByteArrayInputStream(plaintext); + + List signatures = gen.sign(plaintextIn); + isEquals(1, signatures.size()); + } + + private void keyPassphrasesArePairedUpProperly_passphraseAddedFirst(OpenPGPApi api) + throws PGPException, IOException + { + OpenPGPKey key = api.generateKey(new Date(), false) + .signOnlyKey() + .build("password".toCharArray()); + + OpenPGPDetachedSignatureGenerator gen = api.createDetachedSignature(); + + gen.addKeyPassphrase("sloth".toCharArray()); + gen.addKeyPassphrase("password".toCharArray()); + gen.addKeyPassphrase("tapir".toCharArray()); + + gen.addSigningKey(key); + + byte[] plaintext = Strings.toUTF8ByteArray("jungle\ntropics\nswamp\n"); + InputStream plaintextIn = new ByteArrayInputStream(plaintext); + + List signatures = gen.sign(plaintextIn); + isEquals(1, signatures.size()); + } + + private void withoutSigningSubkeyFails(final OpenPGPApi api) + throws PGPException + { + final OpenPGPKey noSigningKey = api.generateKey() + .withPrimaryKey( + new KeyPairGeneratorCallback() { + @Override + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException { + return generator.generatePrimaryKey(); + } + }, + SignatureParameters.Callback.Util.modifyHashedSubpackets( + new SignatureSubpacketsFunction() + { + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS); + // No SIGN_DATA key flag + subpackets.setKeyFlags(KeyFlags.CERTIFY_OTHER); + return subpackets; + } + } + ) + ).build(); + + isNotNull(testException( + "The key " + noSigningKey.getKeyIdentifier() + " does not contain any usable component keys capable of signing.", + "InvalidSigningKeyException", + new TestExceptionOperation() + { + public void operation() + throws Exception + { + api.createDetachedSignature() + .addSigningKey(noSigningKey) + .sign(new ByteArrayInputStream(Strings.toUTF8ByteArray("Test Data"))); + } + })); + } + + private void nonSigningSubkeyFails(final OpenPGPApi api) + throws PGPException + { + final OpenPGPKey noSigningKey = api.generateKey() + .withPrimaryKey( + new KeyPairGeneratorCallback() { + @Override + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException { + return generator.generatePrimaryKey(); + } + }, + SignatureParameters.Callback.Util.modifyHashedSubpackets( + new SignatureSubpacketsFunction() + { + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS); + // No SIGN_DATA key flag + subpackets.setKeyFlags(KeyFlags.CERTIFY_OTHER); + return subpackets; + } + } + ) + ).build(); + + isNotNull(testException( + "The primary key " + noSigningKey.getPrimaryKey().getKeyIdentifier() + " is not usable for signing.", + "InvalidSigningKeyException", + new TestExceptionOperation() + { + public void operation() + throws Exception + { + api.createDetachedSignature() + .addSigningKey(noSigningKey.getPrimarySecretKey(), (char[])null, null) + .sign(new ByteArrayInputStream(Strings.toUTF8ByteArray("Test Data"))); + } + })); + } + + public static void main(String[] args) + { + runTest(new OpenPGPDetachedSignatureProcessorTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPKeyEditorTest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPKeyEditorTest.java new file mode 100644 index 0000000000..90e28f9b32 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPKeyEditorTest.java @@ -0,0 +1,281 @@ +package org.bouncycastle.openpgp.api.test; + +import java.io.IOException; +import java.util.Date; + +import org.bouncycastle.bcpg.SecretKeyPacket; +import org.bouncycastle.bcpg.sig.RevocationReasonTags; +import org.bouncycastle.openpgp.OpenPGPTestKeys; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.bouncycastle.openpgp.api.OpenPGPApi; +import org.bouncycastle.openpgp.api.OpenPGPCertificate; +import org.bouncycastle.openpgp.api.OpenPGPKey; +import org.bouncycastle.openpgp.api.SignatureParameters; +import org.bouncycastle.openpgp.api.SignatureSubpacketsFunction; + +public class OpenPGPKeyEditorTest + extends APITest +{ + + @Override + public String getName() + { + return "OpenPGPKeyEditorTest"; + } + + protected void performTestWith(OpenPGPApi api) + throws PGPException, IOException + { + doNothingTest(api); + + addUserIdTest(api); + softRevokeUserIdTest(api); + hardRevokeUserIdTest(api); + + addEncryptionSubkeyTest(api); + revokeEncryptionSubkeyTest(api); + + addSigningSubkeyTest(api); + revokeSigningSubkeyTest(api); + + extendExpirationTimeTest(api); + revokeCertificateTest(api); + + changePassphraseUnprotectedToCFBTest(api); + changePassphraseUnprotectedToAEADTest(api); + } + + private void doNothingTest(OpenPGPApi api) + throws PGPException + { + OpenPGPKey key = api.generateKey() + .ed25519x25519Key("Alice ") + .build(); + OpenPGPKey editedKey = api.editKey(key) + .done(); + + isTrue("Key was not changed, so the reference MUST be the same", + key == editedKey); + } + + private void addUserIdTest(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate() + .parseKey(OpenPGPTestKeys.V6_KEY); + isNull("Expect primary user-id to be null", key.getPrimaryUserId()); + + key = api.editKey(key) + .addUserId("Alice ") + .done(); + + isEquals("Expect the new user-id to be primary now", + "Alice ", key.getPrimaryUserId().getUserId()); + } + + private void softRevokeUserIdTest(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate() + .parseKey(OpenPGPTestKeys.ALICE_KEY); + final Date now = currentTimeRounded(); + Date oneHourAgo = new Date(now.getTime() - (1000 * 60 * 60)); + OpenPGPCertificate.OpenPGPUserId userId = key.getPrimaryUserId(now); + isNotNull(userId); + isTrue(userId.isBound()); + isEquals("Alice Lovelace ", userId.getUserId()); + + key = api.editKey(key) + .revokeIdentity(userId, new SignatureParameters.Callback() + { + @Override + public SignatureParameters apply(SignatureParameters parameters) + { + parameters.setSignatureCreationTime(now); + parameters.setHashedSubpacketsFunction(new SignatureSubpacketsFunction() + { + @Override + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.setRevocationReason(true, RevocationReasonTags.USER_NO_LONGER_VALID, ""); + return subpackets; + } + }); + return parameters; + } + }) + .done(); + isTrue(key.getPrimaryUserId().isBoundAt(oneHourAgo)); + isFalse(key.getPrimaryUserId().isBoundAt(now)); + } + + private void hardRevokeUserIdTest(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate() + .parseKey(OpenPGPTestKeys.ALICE_KEY); + final Date now = currentTimeRounded(); + Date oneHourAgo = new Date(now.getTime() - (1000 * 60 * 60)); + OpenPGPCertificate.OpenPGPUserId userId = key.getPrimaryUserId(now); + isNotNull(userId); + isTrue(userId.isBound()); + isEquals("Alice Lovelace ", userId.getUserId()); + + key = api.editKey(key) + .revokeIdentity(userId, new SignatureParameters.Callback() + { + @Override + public SignatureParameters apply(SignatureParameters parameters) + { + parameters.setSignatureCreationTime(now); + // no reason -> hard revocation + return parameters; + } + }) + .done(); + isFalse(key.getPrimaryUserId().isBoundAt(oneHourAgo)); + isFalse(key.getPrimaryUserId().isBoundAt(now)); + } + + private void addEncryptionSubkeyTest(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY); + isEquals(1, key.getEncryptionKeys().size()); + + key = api.editKey(key) + .addEncryptionSubkey() + .done(); + + isEquals(2, key.getEncryptionKeys().size()); + } + + private void revokeEncryptionSubkeyTest(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY); + OpenPGPCertificate.OpenPGPComponentKey encryptionSubkey = key.getEncryptionKeys().get(0); + + key = api.editKey(key) + .revokeComponentKey(encryptionSubkey) + .done(); + + isEquals(0, key.getEncryptionKeys().size()); + } + + private void addSigningSubkeyTest(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY); + isEquals(1, key.getSigningKeys().size()); + + key = api.editKey(key) + .addSigningSubkey() + .done(); + + isEquals(2, key.getSigningKeys().size()); + } + + private void revokeSigningSubkeyTest(OpenPGPApi api) + throws PGPException + { + OpenPGPKey key = api.generateKey() + .classicKey(null) + .build(); + isEquals(1, key.getSigningKeys().size()); + + OpenPGPCertificate.OpenPGPComponentKey signingKey = key.getSigningKeys().get(0); + key = api.editKey(key) + .revokeComponentKey(signingKey) + .done(); + isEquals(0, key.getSigningKeys().size()); + } + + private void extendExpirationTimeTest(OpenPGPApi api) + throws PGPException + { + Date n0 = currentTimeRounded(); + OpenPGPKey key = api.generateKey(n0, false) + .classicKey(null) + .build(); + isEquals("Default key generation MUST set expiration time of +5years", + key.getExpirationTime().getTime(), n0.getTime() + 5L * 31536000 * 1000); + + final Date n1 = new Date(n0.getTime() + 1000); // 1 sec later + + key = api.editKey(key) + .addDirectKeySignature(new SignatureParameters.Callback() + { + @Override + public SignatureParameters apply(SignatureParameters parameters) + { + parameters.setSignatureCreationTime(n1); + parameters.setHashedSubpacketsFunction(new SignatureSubpacketsFunction() + { + @Override + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.setKeyExpirationTime(8L * 31536000); + return subpackets; + } + }); + return parameters; + } + }) + .done(); + + isEquals("At n1, the expiration time of the key MUST have changed to n0+8years", + key.getExpirationTime(n1).getTime(), n0.getTime() + 8L * 31536000 * 1000); + } + + private void revokeCertificateTest(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY); + + key = api.editKey(key) + .revokeKey() + .done(); + + isEquals(0, key.getEncryptionKeys().size()); + } + + private void changePassphraseUnprotectedToCFBTest(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY); + isFalse(key.getPrimarySecretKey().isLocked()); + + key = api.editKey(key) + .changePassphrase(key.getPrimaryKey().getKeyIdentifier(), null, "sw0rdf1sh".toCharArray(), false) + .done(); + isTrue("Expect key to be locked", key.getPrimarySecretKey().isLocked()); + isTrue("Expect sw0rdf1sh to be the correct passphrase", + key.getPrimarySecretKey().isPassphraseCorrect("sw0rdf1sh".toCharArray())); + isEquals("Expect use of USAGE_CHECKSUM for key protection", + SecretKeyPacket.USAGE_SHA1, key.getPrimarySecretKey().getPGPSecretKey().getS2KUsage()); + } + + private void changePassphraseUnprotectedToAEADTest(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY); + isFalse("Expect key to be unprotected", key.getPrimarySecretKey().isLocked()); + + key = api.editKey(key) + .changePassphrase(key.getPrimaryKey().getKeyIdentifier(), null, "sw0rdf1sh".toCharArray(), true) + .done(); + isTrue("Expect key to be locked after changing passphrase", + key.getPrimarySecretKey().isLocked()); + isTrue("Expect sw0rdf1sh to be the correct passphrase using AEAD", + key.getPrimarySecretKey().isPassphraseCorrect("sw0rdf1sh".toCharArray())); + isEquals("Expect use of AEAD for key protection", + SecretKeyPacket.USAGE_AEAD, key.getPrimarySecretKey().getPGPSecretKey().getS2KUsage()); + } + + public static void main(String[] args) + { + runTest(new OpenPGPKeyEditorTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPKeyReaderTest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPKeyReaderTest.java new file mode 100644 index 0000000000..e89be77bee --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPKeyReaderTest.java @@ -0,0 +1,91 @@ +package org.bouncycastle.openpgp.api.test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; + +import org.bouncycastle.bcpg.ArmoredOutputStream; +import org.bouncycastle.bcpg.BCPGOutputStream; +import org.bouncycastle.bcpg.PacketFormat; +import org.bouncycastle.openpgp.OpenPGPTestKeys; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.api.OpenPGPApi; +import org.bouncycastle.openpgp.api.OpenPGPCertificate; +import org.bouncycastle.openpgp.api.OpenPGPKey; + +public class OpenPGPKeyReaderTest + extends APITest +{ + @Override + public String getName() + { + return "OpenPGPKeyReaderTest"; + } + + @Override + protected void performTestWith(OpenPGPApi api) + throws PGPException, IOException + { + testParseEmptyCollection(api); + testParse2CertsCertificateCollection(api); + testParseCertAndKeyToCertificateCollection(api); + } + + private void testParseEmptyCollection(OpenPGPApi api) + throws IOException + { + byte[] empty = new byte[0]; + List certs = api.readKeyOrCertificate().parseKeysOrCertificates(empty); + isTrue(certs.isEmpty()); + } + + private void testParse2CertsCertificateCollection(OpenPGPApi api) + throws IOException + { + OpenPGPCertificate alice = api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.ALICE_CERT); + OpenPGPCertificate bob = api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.BOB_CERT); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ArmoredOutputStream aOut = ArmoredOutputStream.builder().clearHeaders().build(bOut); + BCPGOutputStream pOut = new BCPGOutputStream(aOut, PacketFormat.CURRENT); + alice.getPGPPublicKeyRing().encode(pOut); + bob.getPGPPublicKeyRing().encode(pOut); + pOut.close(); + aOut.close(); + + List certs = api.readKeyOrCertificate().parseKeysOrCertificates(bOut.toByteArray()); + isEquals("Collection MUST contain both items", 2, certs.size()); + + isEquals(alice.getKeyIdentifier(), certs.get(0).getKeyIdentifier()); + isEquals(bob.getKeyIdentifier(), certs.get(1).getKeyIdentifier()); + } + + private void testParseCertAndKeyToCertificateCollection(OpenPGPApi api) + throws IOException + { + OpenPGPCertificate alice = api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.ALICE_CERT); + OpenPGPKey bob = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.BOB_KEY); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ArmoredOutputStream aOut = ArmoredOutputStream.builder().clearHeaders().build(bOut); + BCPGOutputStream pOut = new BCPGOutputStream(aOut, PacketFormat.CURRENT); + alice.getPGPPublicKeyRing().encode(pOut); + bob.getPGPSecretKeyRing().encode(pOut); + pOut.close(); + aOut.close(); + + List certs = api.readKeyOrCertificate().parseKeysOrCertificates(bOut.toByteArray()); + isEquals("Collection MUST contain both items", 2, certs.size()); + + isEquals(alice.getKeyIdentifier(), certs.get(0).getKeyIdentifier()); + isFalse(certs.get(0).isSecretKey()); + + isEquals(bob.getKeyIdentifier(), certs.get(1).getKeyIdentifier()); + isTrue(certs.get(1).isSecretKey()); + } + + public static void main(String[] args) + { + runTest(new OpenPGPKeyReaderTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPMessageGeneratorTest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPMessageGeneratorTest.java new file mode 100644 index 0000000000..bd709d7355 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPMessageGeneratorTest.java @@ -0,0 +1,193 @@ +package org.bouncycastle.openpgp.api.test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.bouncycastle.bcpg.CompressionAlgorithmTags; +import org.bouncycastle.openpgp.OpenPGPTestKeys; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.api.OpenPGPApi; +import org.bouncycastle.openpgp.api.OpenPGPCertificate; +import org.bouncycastle.openpgp.api.OpenPGPKey; +import org.bouncycastle.openpgp.api.OpenPGPMessageGenerator; +import org.bouncycastle.openpgp.api.OpenPGPMessageOutputStream; +import org.bouncycastle.openpgp.api.OpenPGPPolicy; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Hex; + +public class OpenPGPMessageGeneratorTest + extends APITest +{ + @Override + public String getName() + { + return "OpenPGPMessageGeneratorTest"; + } + + protected void performTestWith(OpenPGPApi api) + throws PGPException, IOException + { + armoredLiteralDataPacket(api); + unarmoredLiteralDataPacket(api); + + armoredCompressedLiteralDataPacket(api); + unarmoredCompressedLiteralDataPacket(api); + + seipd1EncryptedMessage(api); + seipd2EncryptedMessage(api); + + seipd2EncryptedSignedMessage(api); + } + + private void armoredLiteralDataPacket(OpenPGPApi api) + throws PGPException, IOException + { + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage() + .setAllowPadding(false); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OpenPGPMessageOutputStream msgOut = gen.open(bOut); + + // Only write a LiteralData packet with "Hello, World!" as content + msgOut.write(Strings.toUTF8ByteArray("Hello, World!")); + + msgOut.close(); + + String nl = Strings.lineSeparator(); + String expected = + "-----BEGIN PGP MESSAGE-----" + nl + + nl + + "yxNiAAAAAABIZWxsbywgV29ybGQh" + nl + + "-----END PGP MESSAGE-----" + nl; + isEquals(expected, bOut.toString()); + } + + private void unarmoredLiteralDataPacket(OpenPGPApi api) + throws PGPException, IOException + { + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage() + .setArmored(false) // disable ASCII armor + .setAllowPadding(false); // disable padding + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OpenPGPMessageOutputStream msgOut = gen.open(bOut); + + // Only write a LiteralData packet with "Hello, World!" as content + msgOut.write(Strings.toUTF8ByteArray("Hello, World!")); + + msgOut.close(); + + isEncodingEqual(Hex.decode("cb1362000000000048656c6c6f2c20576f726c6421"), bOut.toByteArray()); + } + + private void armoredCompressedLiteralDataPacket(OpenPGPApi api) + throws PGPException, IOException + { + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage() + .setAllowPadding(false) + .setCompressionNegotiator(new OpenPGPMessageGenerator.CompressionNegotiator() + { + public int negotiateCompression(OpenPGPMessageGenerator messageGenerator, OpenPGPPolicy policy) + { + return CompressionAlgorithmTags.ZIP; + } + }); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OpenPGPMessageOutputStream msgOut = gen.open(bOut); + + // Only write a LiteralData packet with "Hello, World!" as content + msgOut.write(Strings.toUTF8ByteArray("Hello, World!")); + + msgOut.close(); + + String nl = Strings.lineSeparator(); + String expected = + "-----BEGIN PGP MESSAGE-----" + nl + + nl + + "yBUBOy2cxAACHqk5Ofk6CuH5RTkpigA=" + nl + + "-----END PGP MESSAGE-----" + nl; + isEquals(expected, bOut.toString()); + } + + private void unarmoredCompressedLiteralDataPacket(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage() + .setArmored(false) // no armor + .setAllowPadding(false) + .setCompressionNegotiator(new OpenPGPMessageGenerator.CompressionNegotiator() + { + public int negotiateCompression(OpenPGPMessageGenerator messageGenerator, OpenPGPPolicy policy) + { + return CompressionAlgorithmTags.ZIP; + } + }); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OpenPGPMessageOutputStream msgOut = gen.open(bOut); + + // Only write a LiteralData packet with "Hello, World!" as content + msgOut.write(Strings.toUTF8ByteArray("Hello, World!")); + + msgOut.close(); + + isEncodingEqual(Hex.decode("c815013b2d9cc400021ea93939f93a0ae1f94539298a00"), bOut.toByteArray()); + } + + private void seipd2EncryptedMessage(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPCertificate cert = api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.V6_CERT); + + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage(); + gen.addEncryptionCertificate(cert); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream encOut = gen.open(bOut); + encOut.write(Strings.toUTF8ByteArray("Hello, World!")); + encOut.close(); + + System.out.println(bOut); + } + + private void seipd1EncryptedMessage(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.BOB_KEY); + + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage(); + gen.addEncryptionCertificate(key); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream encOut = gen.open(bOut); + encOut.write(Strings.toUTF8ByteArray("Hello, World!")); + encOut.close(); + + System.out.println(bOut); + } + + private void seipd2EncryptedSignedMessage(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY); + + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage() + .setAllowPadding(true) + .setArmored(true) + .addSigningKey(key) + .addEncryptionCertificate(key); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream encOut = gen.open(bOut); + encOut.write("Hello, World!\n".getBytes()); + encOut.close(); + + System.out.println(bOut); + } + + public static void main(String[] args) + { + runTest(new OpenPGPMessageGeneratorTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPMessageProcessorTest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPMessageProcessorTest.java new file mode 100644 index 0000000000..159960393a --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPMessageProcessorTest.java @@ -0,0 +1,707 @@ +package org.bouncycastle.openpgp.api.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; + +import org.bouncycastle.bcpg.AEADAlgorithmTags; +import org.bouncycastle.bcpg.CompressionAlgorithmTags; +import org.bouncycastle.bcpg.KeyIdentifier; +import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; +import org.bouncycastle.openpgp.OpenPGPTestKeys; +import org.bouncycastle.openpgp.PGPEncryptedDataGenerator; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPSessionKey; +import org.bouncycastle.openpgp.api.KeyPassphraseProvider; +import org.bouncycastle.openpgp.api.MessageEncryptionMechanism; +import org.bouncycastle.openpgp.api.OpenPGPApi; +import org.bouncycastle.openpgp.api.OpenPGPCertificate; +import org.bouncycastle.openpgp.api.OpenPGPEncryptionNegotiator; +import org.bouncycastle.openpgp.api.OpenPGPKey; +import org.bouncycastle.openpgp.api.OpenPGPKeyMaterialProvider; +import org.bouncycastle.openpgp.api.OpenPGPMessageGenerator; +import org.bouncycastle.openpgp.api.OpenPGPMessageInputStream; +import org.bouncycastle.openpgp.api.OpenPGPMessageOutputStream; +import org.bouncycastle.openpgp.api.OpenPGPMessageProcessor; +import org.bouncycastle.openpgp.api.OpenPGPPolicy; +import org.bouncycastle.openpgp.api.OpenPGPSignature; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.io.Streams; + +public class OpenPGPMessageProcessorTest + extends APITest +{ + private static final byte[] PLAINTEXT = Strings.toUTF8ByteArray("Hello, World!\n"); + + private PGPSessionKey encryptionSessionKey; + + @Override + public String getName() + { + return "OpenPGPMessageProcessorTest"; + } + + protected void performTestWith(OpenPGPApi api) + throws PGPException, IOException + { + String javaVersion = System.getProperty("java.version"); + boolean oldJDK = javaVersion.startsWith("1.5") || javaVersion.startsWith("1.6"); + + testVerificationOfSEIPD1MessageWithTamperedCiphertext(api); + + roundtripUnarmoredPlaintextMessage(api); + roundtripArmoredPlaintextMessage(api); + roundTripCompressedMessage(api); + roundTripCompressedSymEncMessageMessage(api); + + roundTripSymEncMessageWithMultiplePassphrases(api); + + roundTripV4KeyEncryptedMessageAlice(api); + roundTripV4KeyEncryptedMessageBob(api); + + roundTripV6KeyEncryptedMessage(api); + encryptWithV4V6KeyDecryptWithV4(api); + encryptWithV4V6KeyDecryptWithV6(api); + + if (!oldJDK) + { + encryptDecryptWithLockedKey(api); + encryptDecryptWithMissingKey(api); + } + + inlineSignWithV4KeyAlice(api); + inlineSignWithV4KeyBob(api); + inlineSignWithV6Key(api); + + verifyMessageByRevokedKey(api); + incompleteMessageProcessing(api); + } + + private void roundtripUnarmoredPlaintextMessage(OpenPGPApi api) + throws PGPException, IOException + { + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage() + .setArmored(false) + .setAllowPadding(false) + .setCompressionNegotiator(new OpenPGPMessageGenerator.CompressionNegotiator() + { + public int negotiateCompression(OpenPGPMessageGenerator messageGenerator, OpenPGPPolicy policy) + { + return CompressionAlgorithmTags.UNCOMPRESSED; + } + }); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream msgOut = gen.open(bOut); + msgOut.write(PLAINTEXT); + msgOut.close(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage(); + OpenPGPMessageInputStream plainIn = processor.process(bIn); + ByteArrayOutputStream plainOut = new ByteArrayOutputStream(); + Streams.pipeAll(plainIn, plainOut); + plainIn.close(); + isEquals(MessageEncryptionMechanism.unencrypted(), plainIn.getResult().getEncryptionMethod()); + + isEncodingEqual(PLAINTEXT, plainOut.toByteArray()); + } + + private void roundtripArmoredPlaintextMessage(OpenPGPApi api) + throws PGPException, IOException + { + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage() + .setArmored(true) + .setAllowPadding(false) + .setCompressionNegotiator(new OpenPGPMessageGenerator.CompressionNegotiator() + { + public int negotiateCompression(OpenPGPMessageGenerator messageGenerator, OpenPGPPolicy policy) + { + return CompressionAlgorithmTags.UNCOMPRESSED; + } + }); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream msgOut = gen.open(bOut); + msgOut.write(PLAINTEXT); + msgOut.close(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage(); + OpenPGPMessageInputStream plainIn = processor.process(bIn); + ByteArrayOutputStream plainOut = new ByteArrayOutputStream(); + Streams.pipeAll(plainIn, plainOut); + plainIn.close(); + OpenPGPMessageInputStream.Result result = plainIn.getResult(); + isEquals(MessageEncryptionMechanism.unencrypted(), result.getEncryptionMethod()); + + isEncodingEqual(PLAINTEXT, plainOut.toByteArray()); + } + + private void roundTripCompressedMessage(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage() + .setArmored(true) + .setAllowPadding(false) + .setCompressionNegotiator(new OpenPGPMessageGenerator.CompressionNegotiator() + { + public int negotiateCompression(OpenPGPMessageGenerator messageGenerator, OpenPGPPolicy policy) + { + return CompressionAlgorithmTags.ZIP; + } + }); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream msgOut = gen.open(bOut); + msgOut.write(PLAINTEXT); + msgOut.close(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage(); + InputStream plainIn = processor.process(bIn); + ByteArrayOutputStream plainOut = new ByteArrayOutputStream(); + Streams.pipeAll(plainIn, plainOut); + plainIn.close(); + + isEncodingEqual(PLAINTEXT, plainOut.toByteArray()); + } + + private void roundTripCompressedSymEncMessageMessage(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage() + .setArmored(true) + .addEncryptionPassphrase("lal".toCharArray()) + .setSessionKeyExtractionCallback(new PGPEncryptedDataGenerator.SessionKeyExtractionCallback() + { + public void extractSessionKey(PGPSessionKey sessionKey) + { + OpenPGPMessageProcessorTest.this.encryptionSessionKey = sessionKey; + } + }) + .setAllowPadding(false) + .setPasswordBasedEncryptionNegotiator(new OpenPGPEncryptionNegotiator() + { + @Override + public MessageEncryptionMechanism negotiateEncryption(OpenPGPMessageGenerator configuration) + { + return MessageEncryptionMechanism.integrityProtected(SymmetricKeyAlgorithmTags.AES_256); + } + }) + .setCompressionNegotiator(new OpenPGPMessageGenerator.CompressionNegotiator() + { + public int negotiateCompression(OpenPGPMessageGenerator messageGenerator, OpenPGPPolicy policy) + { + return CompressionAlgorithmTags.ZIP; + } + }); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream msgOut = gen.open(bOut); + msgOut.write(PLAINTEXT); + msgOut.close(); + isNotNull(encryptionSessionKey); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + OpenPGPMessageInputStream plainIn = api.decryptAndOrVerifyMessage() + .addMessagePassphrase("lal".toCharArray()) + .process(bIn); + ByteArrayOutputStream plainOut = new ByteArrayOutputStream(); + Streams.pipeAll(plainIn, plainOut); + plainIn.close(); + OpenPGPMessageInputStream.Result result = plainIn.getResult(); + isEquals(CompressionAlgorithmTags.ZIP, result.getCompressionAlgorithm()); + isTrue(Arrays.areEqual("lal".toCharArray(), result.getDecryptionPassphrase())); + isEncodingEqual(encryptionSessionKey.getKey(), result.getSessionKey().getKey()); + + isEncodingEqual(PLAINTEXT, plainOut.toByteArray()); + } + + private void roundTripSymEncMessageWithMultiplePassphrases(OpenPGPApi api) + throws PGPException, IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage() + .addEncryptionPassphrase("orange".toCharArray()) + .addEncryptionPassphrase("violet".toCharArray()) + .setSessionKeyExtractionCallback(new PGPEncryptedDataGenerator.SessionKeyExtractionCallback() + { + public void extractSessionKey(PGPSessionKey sessionKey) + { + OpenPGPMessageProcessorTest.this.encryptionSessionKey = sessionKey; + } + }) + .setPasswordBasedEncryptionNegotiator( + new OpenPGPEncryptionNegotiator() + { + @Override + public MessageEncryptionMechanism negotiateEncryption(OpenPGPMessageGenerator configuration) + { + return MessageEncryptionMechanism.aead(SymmetricKeyAlgorithmTags.AES_128, AEADAlgorithmTags.OCB); + } + } + ); + + OutputStream encOut = gen.open(bOut); + encOut.write(PLAINTEXT); + encOut.close(); + + byte[] ciphertext = bOut.toByteArray(); + ByteArrayInputStream bIn = new ByteArrayInputStream(ciphertext); + bOut = new ByteArrayOutputStream(); + + // Try decryption with explicitly set message passphrase + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage(); + processor.addMessagePassphrase("violet".toCharArray()); + OpenPGPMessageInputStream decIn = processor.process(bIn); + Streams.pipeAll(decIn, bOut); + decIn.close(); + OpenPGPMessageInputStream.Result result = decIn.getResult(); + isTrue(Arrays.areEqual("violet".toCharArray(), result.getDecryptionPassphrase())); + isEncodingEqual(encryptionSessionKey.getKey(), result.getSessionKey().getKey()); + isEncodingEqual(PLAINTEXT, bOut.toByteArray()); + isEquals(result.getEncryptionMethod(), + MessageEncryptionMechanism.aead(SymmetricKeyAlgorithmTags.AES_128, AEADAlgorithmTags.OCB)); + + // Try decryption with wrong passphrase and then request proper one dynamically + bOut = new ByteArrayOutputStream(); + bIn = new ByteArrayInputStream(ciphertext); + processor = api.decryptAndOrVerifyMessage(); + decIn = processor.setMissingMessagePassphraseCallback(new StackMessagePassphraseCallback("orange".toCharArray())) + // wrong passphrase, so missing callback is invoked + .addMessagePassphrase("yellow".toCharArray()) + .process(bIn); + + Streams.pipeAll(decIn, bOut); + decIn.close(); + result = decIn.getResult(); + isTrue(Arrays.areEqual("orange".toCharArray(), result.getDecryptionPassphrase())); + isEncodingEqual(encryptionSessionKey.getKey(), result.getSessionKey().getKey()); + isEncodingEqual(PLAINTEXT, bOut.toByteArray()); + } + + private void roundTripV4KeyEncryptedMessageAlice(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage(); + gen.addEncryptionCertificate(api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.ALICE_CERT)); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream enc = gen.open(bOut); + enc.write(PLAINTEXT); + enc.close(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage(); + processor.addDecryptionKey(api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.ALICE_KEY)); + + OpenPGPMessageInputStream decIn = processor.process(bIn); + + bOut = new ByteArrayOutputStream(); + Streams.pipeAll(decIn, bOut); + isEncodingEqual(bOut.toByteArray(), PLAINTEXT); + OpenPGPMessageInputStream.Result result = decIn.getResult(); + isEquals(MessageEncryptionMechanism.integrityProtected(SymmetricKeyAlgorithmTags.AES_256), + result.getEncryptionMethod()); + } + + private void roundTripV4KeyEncryptedMessageBob(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage(); + gen.addEncryptionCertificate(api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.BOB_CERT)); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream enc = gen.open(bOut); + enc.write(PLAINTEXT); + enc.close(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage(); + processor.addDecryptionKey(api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.BOB_KEY)); + + OpenPGPMessageInputStream decIn = processor.process(bIn); + + bOut = new ByteArrayOutputStream(); + Streams.pipeAll(decIn, bOut); + decIn.close(); + OpenPGPMessageInputStream.Result result = decIn.getResult(); + isEquals(MessageEncryptionMechanism.integrityProtected(SymmetricKeyAlgorithmTags.AES_256), + result.getEncryptionMethod()); + isEncodingEqual(bOut.toByteArray(), PLAINTEXT); + } + + private void roundTripV6KeyEncryptedMessage(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY); + + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage() + .setArmored(true) + .addEncryptionCertificate(key) + .setAllowPadding(false); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream msgOut = gen.open(bOut); + msgOut.write(PLAINTEXT); + msgOut.close(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage() + .addDecryptionKey(key); + + OpenPGPMessageInputStream plainIn = processor.process(bIn); + ByteArrayOutputStream plainOut = new ByteArrayOutputStream(); + Streams.pipeAll(plainIn, plainOut); + plainIn.close(); + OpenPGPMessageInputStream.Result result = plainIn.getResult(); + isEquals(MessageEncryptionMechanism.aead(SymmetricKeyAlgorithmTags.AES_256, AEADAlgorithmTags.OCB), + result.getEncryptionMethod()); + + isEncodingEqual(PLAINTEXT, plainOut.toByteArray()); + } + + private void encryptWithV4V6KeyDecryptWithV4(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage(); + gen.addEncryptionCertificate(api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.ALICE_CERT)); + gen.addEncryptionCertificate(api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.V6_CERT)); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream enc = gen.open(bOut); + enc.write(PLAINTEXT); + enc.close(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage() + .addDecryptionKey(api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.ALICE_KEY)); + + OpenPGPMessageInputStream decIn = processor.process(bIn); + + bOut = new ByteArrayOutputStream(); + Streams.pipeAll(decIn, bOut); + decIn.close(); + isEncodingEqual(bOut.toByteArray(), PLAINTEXT); + OpenPGPMessageInputStream.Result result = decIn.getResult(); + isEquals(MessageEncryptionMechanism.integrityProtected(SymmetricKeyAlgorithmTags.AES_256), + result.getEncryptionMethod()); + } + + private void encryptWithV4V6KeyDecryptWithV6(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage(); + gen.addEncryptionCertificate(api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.ALICE_CERT)); + gen.addEncryptionCertificate(api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.V6_CERT)); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OutputStream enc = gen.open(bOut); + enc.write(PLAINTEXT); + enc.close(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage() + .addDecryptionKey(api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY)); + + OpenPGPMessageInputStream decIn = processor.process(bIn); + + bOut = new ByteArrayOutputStream(); + Streams.pipeAll(decIn, bOut); + isEncodingEqual(bOut.toByteArray(), PLAINTEXT); + OpenPGPMessageInputStream.Result result = decIn.getResult(); + isEquals(MessageEncryptionMechanism.integrityProtected(SymmetricKeyAlgorithmTags.AES_256), + result.getEncryptionMethod()); + } + + private void encryptDecryptWithLockedKey(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY_LOCKED); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + OpenPGPMessageOutputStream encOut = api.signAndOrEncryptMessage() + .addEncryptionCertificate(key) + .open(bOut); + + encOut.write(PLAINTEXT); + encOut.close(); + + byte[] ciphertext = bOut.toByteArray(); + + // Provide passphrase and key together + ByteArrayInputStream bIn = new ByteArrayInputStream(ciphertext); + bOut = new ByteArrayOutputStream(); + OpenPGPMessageInputStream decIn = api.decryptAndOrVerifyMessage() + .addDecryptionKey(key, OpenPGPTestKeys.V6_KEY_LOCKED_PASSPHRASE.toCharArray()) + .process(bIn); + Streams.pipeAll(decIn, bOut); + decIn.close(); + isEncodingEqual(PLAINTEXT, bOut.toByteArray()); + OpenPGPMessageInputStream.Result result = decIn.getResult(); + PGPSessionKey sk = result.getSessionKey(); + + // Provide passphrase and key separate from another + bIn = new ByteArrayInputStream(ciphertext); + bOut = new ByteArrayOutputStream(); + decIn = api.decryptAndOrVerifyMessage() + .addDecryptionKey(key) + .addDecryptionKeyPassphrase(OpenPGPTestKeys.V6_KEY_LOCKED_PASSPHRASE.toCharArray()) + .process(bIn); + Streams.pipeAll(decIn, bOut); + decIn.close(); + isEncodingEqual(PLAINTEXT, bOut.toByteArray()); + result = decIn.getResult(); + isEncodingEqual(sk.getKey(), result.getSessionKey().getKey()); + + // Provide passphrase dynamically + bIn = new ByteArrayInputStream(ciphertext); + bOut = new ByteArrayOutputStream(); + decIn = api.decryptAndOrVerifyMessage() + .addDecryptionKey(key) + .setMissingOpenPGPKeyPassphraseProvider(new KeyPassphraseProvider() + { + public char[] getKeyPassword(OpenPGPKey.OpenPGPSecretKey key) + { + return OpenPGPTestKeys.V6_KEY_LOCKED_PASSPHRASE.toCharArray(); + } + }) + .process(bIn); + Streams.pipeAll(decIn, bOut); + decIn.close(); + isEncodingEqual(PLAINTEXT, bOut.toByteArray()); + + result = decIn.getResult(); + isEncodingEqual(sk.getKey(), result.getSessionKey().getKey()); + } + + private void encryptDecryptWithMissingKey(OpenPGPApi api) + throws IOException, PGPException + { + final OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + OutputStream encOut = api.signAndOrEncryptMessage() + .addEncryptionCertificate(key) + .open(bOut); + + encOut.write(PLAINTEXT); + encOut.close(); + + byte[] ciphertext = bOut.toByteArray(); + + // Provide passphrase and key together + ByteArrayInputStream bIn = new ByteArrayInputStream(ciphertext); + bOut = new ByteArrayOutputStream(); + OpenPGPMessageInputStream decIn = api.decryptAndOrVerifyMessage() + .setMissingOpenPGPKeyProvider(new OpenPGPKeyMaterialProvider.OpenPGPKeyProvider() + { + public OpenPGPKey provide(KeyIdentifier componentKeyIdentifier) + { + return key; + } + }) + .process(bIn); + Streams.pipeAll(decIn, bOut); + decIn.close(); + isEncodingEqual(PLAINTEXT, bOut.toByteArray()); + + OpenPGPMessageInputStream.Result result = decIn.getResult(); + isEquals(key, result.getDecryptionKey().getCertificate()); + isNotNull(result.getSessionKey()); + } + + private void inlineSignWithV4KeyAlice(OpenPGPApi api) + throws IOException, PGPException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage(); + OpenPGPKey aliceKey = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.ALICE_KEY); + gen.addSigningKey(aliceKey); + + OutputStream signOut = gen.open(bOut); + signOut.write(PLAINTEXT); + signOut.close(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + bOut = new ByteArrayOutputStream(); + + OpenPGPCertificate aliceCert = api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.ALICE_CERT); + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage() + .addVerificationCertificate(aliceCert); + + OpenPGPMessageInputStream verifIn = processor.process(bIn); + Streams.pipeAll(verifIn, bOut); + verifIn.close(); + OpenPGPMessageInputStream.Result result = verifIn.getResult(); + isEquals(MessageEncryptionMechanism.unencrypted(), result.getEncryptionMethod()); + List signatures = result.getSignatures(); + isEquals(1, signatures.size()); + OpenPGPSignature.OpenPGPDocumentSignature sig = signatures.get(0); + isEquals(aliceCert, sig.getIssuerCertificate()); + + isEncodingEqual(PLAINTEXT, bOut.toByteArray()); + } + + private void inlineSignWithV4KeyBob(OpenPGPApi api) + throws IOException, PGPException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage(); + OpenPGPKey bobKey = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.BOB_KEY); + gen.addSigningKey(bobKey); + + OutputStream signOut = gen.open(bOut); + signOut.write(PLAINTEXT); + signOut.close(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + bOut = new ByteArrayOutputStream(); + + OpenPGPCertificate bobCert = api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.BOB_CERT); + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage() + .addVerificationCertificate(bobCert); + + OpenPGPMessageInputStream verifIn = processor.process(bIn); + Streams.pipeAll(verifIn, bOut); + verifIn.close(); + OpenPGPMessageInputStream.Result result = verifIn.getResult(); + List signatures = result.getSignatures(); + isEquals(1, signatures.size()); + OpenPGPSignature.OpenPGPDocumentSignature sig = signatures.get(0); + isEquals(bobCert, sig.getIssuerCertificate()); + + isEncodingEqual(PLAINTEXT, bOut.toByteArray()); + } + + private void inlineSignWithV6Key(OpenPGPApi api) + throws PGPException, IOException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage(); + OpenPGPKey v6Key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.V6_KEY); + gen.addSigningKey(v6Key); + + OutputStream signOut = gen.open(bOut); + signOut.write(PLAINTEXT); + signOut.close(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + bOut = new ByteArrayOutputStream(); + + OpenPGPCertificate v6Cert = api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.V6_CERT); + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage() + .addVerificationCertificate(v6Cert); + + OpenPGPMessageInputStream verifIn = processor.process(bIn); + Streams.pipeAll(verifIn, bOut); + verifIn.close(); + OpenPGPMessageInputStream.Result result = verifIn.getResult(); + List signatures = result.getSignatures(); + isEquals(1, signatures.size()); + OpenPGPSignature.OpenPGPDocumentSignature sig = signatures.get(0); + isEquals(v6Cert, sig.getIssuerCertificate()); + + isEncodingEqual(PLAINTEXT, bOut.toByteArray()); + } + + private void verifyMessageByRevokedKey(OpenPGPApi api) + throws PGPException, IOException + { + // Create a minimal signed message + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.ALICE_KEY); + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage(); + gen.addSigningKey(key); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OpenPGPMessageOutputStream oOut = gen.open(bOut); + oOut.write("Hello, World!\n".getBytes()); + oOut.close(); + + // Load the certificate and import its revocation signature + OpenPGPCertificate cert = api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.ALICE_CERT); + cert = OpenPGPCertificate.join(cert, OpenPGPTestKeys.ALICE_REVOCATION_CERT); + + // Process the signed message using the revoked key + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage(); + processor.addVerificationCertificate(cert); + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + OpenPGPMessageInputStream oIn = processor.process(bIn); + Streams.drain(oIn); + oIn.close(); + + OpenPGPMessageInputStream.Result result = oIn.getResult(); + OpenPGPSignature.OpenPGPDocumentSignature sig = result.getSignatures().get(0); + // signature is no valid + isFalse(sig.isValid()); + } + + private void incompleteMessageProcessing(OpenPGPApi api) + throws IOException, PGPException + { + OpenPGPMessageGenerator gen = api.signAndOrEncryptMessage() + .addEncryptionCertificate(api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.ALICE_CERT)) + .addSigningKey(api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.BOB_KEY)); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OpenPGPMessageOutputStream out = gen.open(bOut); + + out.write(Strings.toUTF8ByteArray("Some Data")); + out.close(); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage() + .addVerificationCertificate(api.readKeyOrCertificate().parseCertificate(OpenPGPTestKeys.BOB_CERT)) + .addDecryptionKey(api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.ALICE_KEY)); + OpenPGPMessageInputStream in = processor.process(bIn); + + // read a single byte (not the entire message) + in.read(); + + in.close(); + OpenPGPMessageInputStream.Result result = in.getResult(); + OpenPGPSignature.OpenPGPDocumentSignature sig = result.getSignatures().get(0); + isFalse(sig.isValid()); + } + + private void testVerificationOfSEIPD1MessageWithTamperedCiphertext(OpenPGPApi api) + throws IOException, PGPException + { + String MSG = "-----BEGIN PGP MESSAGE-----\n" + + "\n" + + "wcDMA3wvqk35PDeyAQv/c0eFDZud8YCzKu0qzq7xOUeF0KiFFv58RSAookfyce9B\n" + + "LSXH7g/F/3Pdp9EHcrtBsxYRXUdWmZHvwFRvAiwCl9unjUgRendopmuNJ5zNgB2w\n" + + "DkuMA2J2J5HGTicvCwGrWALDG6Dc56UEFTwCsip8uKNG+Q3X5IwpU7Vztqywkt4/\n" + + "RNp8+neu+oJELWn3mC3oZrMzYIaD2SlyVaW5Vpksjz32VGKXCm4/hGC/03tGuE1i\n" + + "5sOZicHpeN24BD2tr3MMOdHKPXKxVPPx5T1MIJYUoYjMp7Tnml6F4Obhf+VllAli\n" + + "mkQHj6vevbEkLcJX67pvD04PJiQqm5ea1GwOZDW/nPLih80AJWHpXME36WBzk4X2\n" + + "bHaK3qQxyxqfpvMvWcargI3neWNLaSzqY/2eCrY/OEbAcj18W+9u7phkEoVRmrC7\n" + + "mqIeEUXtGjWSywtJXF8tIcxOU3+IqekXLW9yFIzRrHWEzRVKzP2P5q7mwOp2ddjg\n" + + "8vqe/DOz1r8VxN6orUue0kwBJVHfkYpW8cwX2AtIPYk90ct2qCTbCtNQul+txpRY\n" + + "IwBVELjaaSGpdOuIHkETYssCNfqPSv0rNmaTDq78xItvhjuc4lRaKkpF9DdE\n" + + "=I5BA\n" + + "-----END PGP MESSAGE-----"; + OpenPGPKey key = api.readKeyOrCertificate().parseKey(OpenPGPTestKeys.BOB_KEY); + OpenPGPMessageProcessor processor = api.decryptAndOrVerifyMessage(); + processor.addDecryptionKey(key); + OpenPGPMessageInputStream oIn = processor.process(new ByteArrayInputStream(Strings.toUTF8ByteArray(MSG))); + Streams.drain(oIn); + try + { + oIn.close(); + } + catch (IOException e) + { + // expected + } + } + + public static void main(String[] args) + { + runTest(new OpenPGPMessageProcessorTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPV4KeyGenerationTest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPV4KeyGenerationTest.java new file mode 100644 index 0000000000..b8456e63c4 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPV4KeyGenerationTest.java @@ -0,0 +1,64 @@ +package org.bouncycastle.openpgp.api.test; + +import org.bouncycastle.bcpg.PublicKeyPacket; +import org.bouncycastle.bcpg.SignatureSubpacketTags; +import org.bouncycastle.bcpg.sig.KeyFlags; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPKeyPair; +import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.bouncycastle.openpgp.api.KeyPairGeneratorCallback; +import org.bouncycastle.openpgp.api.OpenPGPApi; +import org.bouncycastle.openpgp.api.OpenPGPKey; +import org.bouncycastle.openpgp.api.SignatureParameters; +import org.bouncycastle.openpgp.api.SignatureSubpacketsFunction; +import org.bouncycastle.openpgp.operator.PGPKeyPairGenerator; + +public class OpenPGPV4KeyGenerationTest + extends APITest +{ + @Override + public String getName() + { + return "OpenPGPV4KeyGenerationTest"; + } + + @Override + protected void performTestWith(OpenPGPApi api) + throws PGPException + { + generateRSAKey(api); + } + + private void generateRSAKey(OpenPGPApi api) + throws PGPException + { + OpenPGPKey key = api.generateKey(PublicKeyPacket.VERSION_4) + .withPrimaryKey(new KeyPairGeneratorCallback() + { + @Override + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException + { + return generator.generateRsaKeyPair(3072); + } + }, SignatureParameters.Callback.Util.modifyHashedSubpackets(new SignatureSubpacketsFunction() + { + @Override + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS); + subpackets.setKeyFlags(KeyFlags.CERTIFY_OTHER | KeyFlags.SIGN_DATA | KeyFlags.ENCRYPT_STORAGE | KeyFlags.ENCRYPT_COMMS); + return subpackets; + } + })) + .addUserId("Alice ") + .build(); + + isEquals(PublicKeyPacket.VERSION_4, key.getPrimaryKey().getVersion()); + } + + public static void main(String[] args) + { + runTest(new OpenPGPV4KeyGenerationTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPV6KeyGeneratorTest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPV6KeyGeneratorTest.java index e69954ee6c..87a3dd5b8b 100644 --- a/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPV6KeyGeneratorTest.java +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/OpenPGPV6KeyGeneratorTest.java @@ -12,29 +12,30 @@ import org.bouncycastle.bcpg.SignatureSubpacketTags; import org.bouncycastle.bcpg.sig.Features; import org.bouncycastle.bcpg.sig.KeyFlags; -import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPKeyPair; import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; import org.bouncycastle.openpgp.api.KeyPairGeneratorCallback; -import org.bouncycastle.openpgp.api.OpenPGPV6KeyGenerator; +import org.bouncycastle.openpgp.api.OpenPGPApi; +import org.bouncycastle.openpgp.api.OpenPGPCertificate; +import org.bouncycastle.openpgp.api.OpenPGPKey; +import org.bouncycastle.openpgp.api.OpenPGPKeyGenerator; +import org.bouncycastle.openpgp.api.SignatureParameters; import org.bouncycastle.openpgp.api.SignatureSubpacketsFunction; -import org.bouncycastle.openpgp.api.bc.BcOpenPGPV6KeyGenerator; -import org.bouncycastle.openpgp.api.jcajce.JcaOpenPGPV6KeyGenerator; import org.bouncycastle.openpgp.operator.PGPKeyPairGenerator; import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder; import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPairGeneratorProvider; -import org.bouncycastle.openpgp.test.AbstractPgpKeyPairTest; public class OpenPGPV6KeyGeneratorTest - extends AbstractPgpKeyPairTest + extends APITest { @Override public String getName() @@ -43,59 +44,32 @@ public String getName() } @Override - public void performTest() - throws Exception - { - // Run tests using the BC implementation - performTests(new APIProvider() - { - @Override - public OpenPGPV6KeyGenerator getKeyGenerator(int signatureHashAlgorithm, - Date creationTime, - boolean aeadProtection) - { - return new BcOpenPGPV6KeyGenerator(signatureHashAlgorithm, creationTime, aeadProtection); - } - }); - - // Run tests using the JCA/JCE implementation - performTests(new APIProvider() - { - @Override - public OpenPGPV6KeyGenerator getKeyGenerator(int signatureHashAlgorithm, - Date creationTime, - boolean aeadProtection) - throws PGPException - { - return new JcaOpenPGPV6KeyGenerator(signatureHashAlgorithm, creationTime, aeadProtection, - new BouncyCastleProvider()); - } - }); - } - - private void performTests(APIProvider apiProvider) + protected void performTestWith(OpenPGPApi api) throws PGPException, IOException { - testGenerateCustomKey(apiProvider); + testGenerateCustomKey(api); + testGenerateMinimalKey(api); - testGenerateSignOnlyKeyBaseCase(apiProvider); - testGenerateAEADProtectedSignOnlyKey(apiProvider); - testGenerateCFBProtectedSignOnlyKey(apiProvider); + testGenerateSignOnlyKeyBaseCase(api); + testGenerateAEADProtectedSignOnlyKey(api); + testGenerateCFBProtectedSignOnlyKey(api); - testGenerateClassicKeyBaseCase(apiProvider); - testGenerateProtectedTypicalKey(apiProvider); + testGenerateClassicKeyBaseCase(api); + testGenerateProtectedTypicalKey(api); - testGenerateEd25519x25519Key(apiProvider); - testGenerateEd448x448Key(apiProvider); + testGenerateEd25519x25519Key(api); + testGenerateEd448x448Key(api); - testEnforcesPrimaryOrSubkeyType(apiProvider); + testEnforcesPrimaryOrSubkeyType(api); + testGenerateKeyWithoutSignatures(api); } - private void testGenerateSignOnlyKeyBaseCase(APIProvider apiProvider) + private void testGenerateSignOnlyKeyBaseCase(OpenPGPApi api) throws PGPException { - OpenPGPV6KeyGenerator generator = apiProvider.getKeyGenerator(); - PGPSecretKeyRing secretKeys = generator.signOnlyKey(null); + OpenPGPKeyGenerator generator = api.generateKey(); + OpenPGPKey key = generator.signOnlyKey().build(); + PGPSecretKeyRing secretKeys = key.getPGPKeyRing(); Iterator it = secretKeys.getSecretKeys(); PGPSecretKey primaryKey = (PGPSecretKey)it.next(); @@ -118,11 +92,12 @@ private void testGenerateSignOnlyKeyBaseCase(APIProvider apiProvider) isEquals("Key MUST be unprotected", SecretKeyPacket.USAGE_NONE, primaryKey.getS2KUsage()); } - private void testGenerateAEADProtectedSignOnlyKey(APIProvider apiProvider) + private void testGenerateAEADProtectedSignOnlyKey(OpenPGPApi api) throws PGPException { - OpenPGPV6KeyGenerator generator = apiProvider.getKeyGenerator(true); - PGPSecretKeyRing secretKeys = generator.signOnlyKey("passphrase".toCharArray()); + OpenPGPKeyGenerator generator = api.generateKey(new Date(), true); + OpenPGPKey key = generator.signOnlyKey().build("passphrase".toCharArray()); + PGPSecretKeyRing secretKeys = key.getPGPKeyRing(); Iterator it = secretKeys.getSecretKeys(); PGPSecretKey primaryKey = (PGPSecretKey)it.next(); @@ -135,11 +110,12 @@ private void testGenerateAEADProtectedSignOnlyKey(APIProvider apiProvider) .build("passphrase".toCharArray()))); } - private void testGenerateCFBProtectedSignOnlyKey(APIProvider apiProvider) + private void testGenerateCFBProtectedSignOnlyKey(OpenPGPApi api) throws PGPException { - OpenPGPV6KeyGenerator generator = apiProvider.getKeyGenerator(false); - PGPSecretKeyRing secretKeys = generator.signOnlyKey("passphrase".toCharArray()); + OpenPGPKeyGenerator generator = api.generateKey(new Date(), false); + OpenPGPKey key = generator.signOnlyKey().build("passphrase".toCharArray()); + PGPSecretKeyRing secretKeys = key.getPGPKeyRing(); Iterator it = secretKeys.getSecretKeys(); PGPSecretKey primaryKey = (PGPSecretKey)it.next(); @@ -152,13 +128,14 @@ private void testGenerateCFBProtectedSignOnlyKey(APIProvider apiProvider) .build("passphrase".toCharArray()))); } - private void testGenerateClassicKeyBaseCase(APIProvider apiProvider) + private void testGenerateClassicKeyBaseCase(OpenPGPApi api) throws PGPException { Date creationTime = currentTimeRounded(); - OpenPGPV6KeyGenerator generator = apiProvider.getKeyGenerator(creationTime); - PGPSecretKeyRing secretKeys = generator - .classicKey("Alice ", null); + OpenPGPKeyGenerator generator = api.generateKey(creationTime); + OpenPGPKey key = generator + .classicKey("Alice ").build(); + PGPSecretKeyRing secretKeys = key.getPGPKeyRing(); Iterator keys = secretKeys.getSecretKeys(); PGPSecretKey primaryKey = (PGPSecretKey)keys.next(); @@ -207,25 +184,26 @@ private void testGenerateClassicKeyBaseCase(APIProvider apiProvider) // Test all keys are unprotected for (Iterator it = secretKeys.getSecretKeys(); it.hasNext();) { - PGPSecretKey key = (PGPSecretKey)it.next(); - isEquals("(Sub-)keys MUST be unprotected", SecretKeyPacket.USAGE_NONE, key.getS2KUsage()); + PGPSecretKey k = (PGPSecretKey)it.next(); + isEquals("(Sub-)keys MUST be unprotected", SecretKeyPacket.USAGE_NONE, k.getS2KUsage()); } } - private void testGenerateProtectedTypicalKey(APIProvider apiProvider) + private void testGenerateProtectedTypicalKey(OpenPGPApi api) throws PGPException { Date creationTime = currentTimeRounded(); - OpenPGPV6KeyGenerator generator = apiProvider.getKeyGenerator(creationTime); - PGPSecretKeyRing secretKeys = generator - .classicKey("Alice ", "passphrase".toCharArray()); + OpenPGPKeyGenerator generator = api.generateKey(creationTime); + OpenPGPKey key = generator + .classicKey("Alice ").build("passphrase".toCharArray()); + PGPSecretKeyRing secretKeys = key.getPGPKeyRing(); // Test creation time for (Iterator it = secretKeys.toCertificate().iterator(); it.hasNext();) { - PGPPublicKey key = (PGPPublicKey)it.next(); - isEquals(creationTime, key.getCreationTime()); - for (Iterator its = key.getSignatures(); its.hasNext(); ) + PGPPublicKey k = (PGPPublicKey)it.next(); + isEquals(creationTime, k.getCreationTime()); + for (Iterator its = k.getSignatures(); its.hasNext(); ) { PGPSignature sig = (PGPSignature)its.next(); isEquals(creationTime, sig.getCreationTime()); @@ -240,19 +218,21 @@ private void testGenerateProtectedTypicalKey(APIProvider apiProvider) for (Iterator it = secretKeys.getSecretKeys(); it.hasNext();) { - PGPSecretKey key = (PGPSecretKey)it.next(); - isEquals("(Sub-)keys MUST be protected", SecretKeyPacket.USAGE_AEAD, key.getS2KUsage()); + PGPSecretKey k = (PGPSecretKey)it.next(); + isEquals("(Sub-)keys MUST be protected", SecretKeyPacket.USAGE_AEAD, k.getS2KUsage()); + } } - private void testGenerateEd25519x25519Key(APIProvider apiProvider) + private void testGenerateEd25519x25519Key(OpenPGPApi api) throws PGPException { Date currentTime = currentTimeRounded(); String userId = "Foo "; - OpenPGPV6KeyGenerator generator = apiProvider.getKeyGenerator(currentTime); + OpenPGPKeyGenerator generator = api.generateKey(currentTime); - PGPSecretKeyRing secretKey = generator.ed25519x25519Key(userId, null); + OpenPGPKey key = generator.ed25519x25519Key(userId).build(); + PGPSecretKeyRing secretKey = key.getPGPKeyRing(); Iterator iterator = secretKey.getSecretKeys(); PGPSecretKey primaryKey = (PGPSecretKey)iterator.next(); @@ -292,14 +272,15 @@ private void testGenerateEd25519x25519Key(APIProvider apiProvider) isEquals(KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, hashedSubpackets.getKeyFlags()); } - private void testGenerateEd448x448Key(APIProvider apiProvider) + private void testGenerateEd448x448Key(OpenPGPApi api) throws PGPException { Date currentTime = currentTimeRounded(); String userId = "Foo "; - OpenPGPV6KeyGenerator generator = apiProvider.getKeyGenerator(currentTime); + OpenPGPKeyGenerator generator = api.generateKey(currentTime); - PGPSecretKeyRing secretKey = generator.ed448x448Key(userId, null); + OpenPGPKey key = generator.ed448x448Key(userId).build(); + PGPSecretKeyRing secretKey = key.getPGPKeyRing(); Iterator iterator = secretKey.getSecretKeys(); PGPSecretKey primaryKey = (PGPSecretKey)iterator.next(); @@ -339,61 +320,61 @@ private void testGenerateEd448x448Key(APIProvider apiProvider) isEquals(KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE, hashedSubpackets.getKeyFlags()); } - private void testGenerateCustomKey(APIProvider apiProvider) + private void testGenerateCustomKey(OpenPGPApi api) throws PGPException { Date creationTime = currentTimeRounded(); - OpenPGPV6KeyGenerator generator = apiProvider.getKeyGenerator(creationTime); + OpenPGPKeyGenerator generator = api.generateKey(creationTime, false); - PGPSecretKeyRing secretKey = generator + OpenPGPKey key = generator .withPrimaryKey( - new KeyPairGeneratorCallback() - { - public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) - throws PGPException + new KeyPairGeneratorCallback() { - return generator.generateRsaKeyPair(4096); - } - }, - new SignatureSubpacketsFunction() - { - public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException + { + return generator.generateRsaKeyPair(4096); + } + }, + SignatureParameters.Callback.Util.modifyHashedSubpackets(new SignatureSubpacketsFunction() { - subpackets.removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS); - subpackets.setKeyFlags(KeyFlags.CERTIFY_OTHER); + @Override + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.removePacketsOfType(SignatureSubpacketTags.KEY_FLAGS); + subpackets.setKeyFlags(KeyFlags.CERTIFY_OTHER); - subpackets.removePacketsOfType(SignatureSubpacketTags.FEATURES); - subpackets.setFeature(false, Features.FEATURE_SEIPD_V2); + subpackets.removePacketsOfType(SignatureSubpacketTags.FEATURES); + subpackets.setFeature(false, Features.FEATURE_SEIPD_V2); - subpackets.addNotationData(false, true, - "notation@example.com", "CYBER"); + subpackets.addNotationData(false, true, + "notation@example.com", "CYBER"); - subpackets.setPreferredKeyServer(false, "https://example.com/openpgp/cert.asc"); - return subpackets; - } - }, - "primary-key-passphrase".toCharArray()) - .addUserId("Alice ", PGPSignature.DEFAULT_CERTIFICATION, null) + subpackets.setPreferredKeyServer(false, "https://example.com/openpgp/cert.asc"); + return subpackets; + } + })) + .addUserId("Alice ") .addSigningSubkey( - new KeyPairGeneratorCallback() - { - public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) - throws PGPException + new KeyPairGeneratorCallback() { - return generator.generateEd448KeyPair(); - } - }, - new SignatureSubpacketsFunction() - { - public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator bindingSubpackets) + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException + { + return generator.generateEd448KeyPair(); + } + }, + SignatureParameters.Callback.Util.modifyHashedSubpackets(new SignatureSubpacketsFunction() { - bindingSubpackets.addNotationData(false, true, - "notation@example.com", "ZAUBER"); - return bindingSubpackets; - } - }, - null, - "signing-key-passphrase".toCharArray()) + @Override + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.addNotationData(false, true, + "notation@example.com", "ZAUBER"); + return subpackets; + } + }), + null) .addEncryptionSubkey( new KeyPairGeneratorCallback() { @@ -402,10 +383,22 @@ public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) { return generator.generateX448KeyPair(); } - }, - "encryption-key-passphrase".toCharArray()) - .build(); - + }) + .build("primary-key-passphrase".toCharArray()); + OpenPGPCertificate.OpenPGPComponentKey encryptionKey = key.getEncryptionKeys().get(0); + OpenPGPCertificate.OpenPGPComponentKey signingKey = key.getSigningKeys().get(0); + key = api.editKey(key, "primary-key-passphrase".toCharArray()) + .changePassphrase(encryptionKey.getKeyIdentifier(), + "primary-key-passphrase".toCharArray(), + "encryption-key-passphrase".toCharArray(), + false) + .changePassphrase(signingKey.getKeyIdentifier(), + "primary-key-passphrase".toCharArray(), + "signing-key-passphrase".toCharArray(), + false) + .done(); + + PGPSecretKeyRing secretKey = key.getPGPKeyRing(); Iterator keyIt = secretKey.getSecretKeys(); PGPSecretKey primaryKey = (PGPSecretKey)keyIt.next(); isEquals("Primary key MUST be RSA_GENERAL", @@ -428,7 +421,7 @@ public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) isFalse("Unexpected additional UID", uids.hasNext()); PGPSignature uidSig = (PGPSignature)primaryKey.getPublicKey().getSignaturesForID(uid).next(); isEquals("UID binding sig type mismatch", - PGPSignature.DEFAULT_CERTIFICATION, uidSig.getSignatureType()); + PGPSignature.POSITIVE_CERTIFICATION, uidSig.getSignatureType()); PGPSecretKey signingSubkey = (PGPSecretKey)keyIt.next(); isEquals("Subkey MUST be Ed448", @@ -469,7 +462,55 @@ public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) encryptionSubkey.extractPrivateKey(keyDecryptorBuilder.build("encryption-key-passphrase".toCharArray()))); } - private void testEnforcesPrimaryOrSubkeyType(final APIProvider apiProvider) + private void testGenerateMinimalKey(OpenPGPApi api) + throws PGPException + { + Date creationTime = currentTimeRounded(); + OpenPGPKeyGenerator gen = api.generateKey(creationTime, false); + OpenPGPKey key = gen.withPrimaryKey( + new KeyPairGeneratorCallback() + { + @Override + public PGPKeyPair generateFrom(PGPKeyPairGenerator generator) + throws PGPException + { + return generator.generateEd25519KeyPair(); + } + }, + SignatureParameters.Callback.Util.modifyHashedSubpackets(new SignatureSubpacketsFunction() + { + @Override + public PGPSignatureSubpacketGenerator apply(PGPSignatureSubpacketGenerator subpackets) + { + subpackets.addNotationData(false, true, "foo@bouncycastle.org", "bar"); + return subpackets; + } + })) + .addUserId("Alice ") + .addEncryptionSubkey() + .addSigningSubkey() + .build(); + PGPSecretKeyRing secretKeys = key.getPGPKeyRing(); + + // Test creation time + for(Iterator it = secretKeys.toCertificate().iterator(); it.hasNext(); ) + { + PGPPublicKey k = (PGPPublicKey)it.next(); + isEquals(creationTime, k.getCreationTime()); + for (Iterator itSign = k.getSignatures(); itSign.hasNext(); ) { + PGPSignature sig = itSign.next(); + isEquals(creationTime, sig.getCreationTime()); + } + } + + PGPPublicKey primaryKey = secretKeys.getPublicKey(); + // Test UIDs + Iterator uids = primaryKey.getUserIDs(); + isEquals("Alice ", uids.next()); + isFalse(uids.hasNext()); + } + + private void testEnforcesPrimaryOrSubkeyType(final OpenPGPApi api) throws PGPException { isNotNull(testException( @@ -481,7 +522,7 @@ private void testEnforcesPrimaryOrSubkeyType(final APIProvider apiProvider) public void operation() throws Exception { - apiProvider.getKeyGenerator().withPrimaryKey( + api.generateKey().withPrimaryKey( new KeyPairGeneratorCallback() { public PGPKeyPair generateFrom(PGPKeyPairGenerator keyGenCallback) @@ -504,10 +545,12 @@ public PGPKeyPair generateFrom(PGPKeyPairGenerator keyGenCallback) public void operation() throws Exception { - apiProvider.getKeyGenerator().withPrimaryKey() - .addEncryptionSubkey(new BcPGPKeyPairGeneratorProvider() - .get(6, new Date()) - .generateX25519KeyPair(), null, null); // primary key as subkey is illegal + api.generateKey().withPrimaryKey() + .addEncryptionSubkey( + new BcPGPKeyPairGeneratorProvider() + .get(6, new Date()) + .generateX25519KeyPair(), + null); // primary key as subkey is illegal } } )); @@ -521,37 +564,76 @@ public void operation() public void operation() throws Exception { - apiProvider.getKeyGenerator().withPrimaryKey() - .addSigningSubkey(new BcPGPKeyPairGeneratorProvider() - .get(6, new Date()) - .generateEd25519KeyPair(), null, null, null); // primary key as subkey is illegal + api.generateKey().withPrimaryKey() + .addSigningSubkey( + new BcPGPKeyPairGeneratorProvider() + .get(6, new Date()) + .generateEd25519KeyPair(), + null, + null); // primary key as subkey is illegal } } )); } - private abstract static class APIProvider - { - public OpenPGPV6KeyGenerator getKeyGenerator() + private void testGenerateKeyWithoutSignatures(OpenPGPApi api) throws PGPException - { - return getKeyGenerator(new Date()); - } + { + OpenPGPKey key = api.generateKey() + .withPrimaryKey( + KeyPairGeneratorCallback.Util.primaryKey(), + // No direct-key sig + new SignatureParameters.Callback() + { + @Override + public SignatureParameters apply(SignatureParameters parameters) { + return null; + } + }) + .addSigningSubkey( + KeyPairGeneratorCallback.Util.signingKey(), + // No subkey binding sig + new SignatureParameters.Callback() + { + @Override + public SignatureParameters apply(SignatureParameters parameters) + { + return null; + } + }, + // No primary key binding sig + new SignatureParameters.Callback() + { + @Override + public SignatureParameters apply(SignatureParameters parameters) + { + return null; + } + }) + .addEncryptionSubkey( + KeyPairGeneratorCallback.Util.encryptionKey(), + // No subkey binding sig + new SignatureParameters.Callback() + { + @Override + public SignatureParameters apply(SignatureParameters parameters) + { + return null; + } + }) + .build(); - public OpenPGPV6KeyGenerator getKeyGenerator(Date creationTime) - throws PGPException - { - return getKeyGenerator(OpenPGPV6KeyGenerator.DEFAULT_SIGNATURE_HASH_ALGORITHM, creationTime, true); - } + PGPPublicKeyRing publicKeys = key.getPGPPublicKeyRing(); + Iterator it = publicKeys.getPublicKeys(); - public OpenPGPV6KeyGenerator getKeyGenerator(boolean aeadProtection) - throws PGPException - { - return getKeyGenerator(OpenPGPV6KeyGenerator.DEFAULT_SIGNATURE_HASH_ALGORITHM, new Date(), aeadProtection); - } + PGPPublicKey primaryKey = it.next(); + isFalse(primaryKey.getSignatures().hasNext()); + + PGPPublicKey signingSubkey = it.next(); + isFalse(signingSubkey.getSignatures().hasNext()); - public abstract OpenPGPV6KeyGenerator getKeyGenerator(int signatureHashAlgorithm, Date creationTime, boolean aeadProtection) - throws PGPException; + PGPPublicKey encryptionSubkey = it.next(); + isFalse(encryptionSubkey.getSignatures().hasNext()); } public static void main(String[] args) diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/RegressionTest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/RegressionTest.java new file mode 100644 index 0000000000..76d37d3f1d --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/RegressionTest.java @@ -0,0 +1,30 @@ +package org.bouncycastle.openpgp.api.test; + +import java.security.Security; + +import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.Test; + +public class RegressionTest +{ + public static Test[] tests = { + new ChangeKeyPassphraseTest(), + new DoubleBufferedInputStreamTest(), + new OpenPGPCertificateTest(), + new OpenPGPDetachedSignatureProcessorTest(), + new OpenPGPKeyEditorTest(), + new OpenPGPKeyReaderTest(), + new OpenPGPMessageGeneratorTest(), + new OpenPGPMessageProcessorTest(), + new OpenPGPV4KeyGenerationTest(), + new OpenPGPV6KeyGeneratorTest(), + new StaticV6OpenPGPMessageGeneratorTest(), + }; + + public static void main(String[] args) + { + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + + SimpleTest.runTests(tests); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/StackMessagePassphraseCallback.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/StackMessagePassphraseCallback.java new file mode 100644 index 0000000000..6cd042fc1b --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/StackMessagePassphraseCallback.java @@ -0,0 +1,37 @@ +package org.bouncycastle.openpgp.api.test; + +import java.util.Collection; +import java.util.Collections; +import java.util.Stack; + +import org.bouncycastle.openpgp.api.MissingMessagePassphraseCallback; + +/** + * Test implementation of {@link MissingMessagePassphraseCallback} which provides passphrases by popping + * them from a provided {@link Stack}. + */ +public class StackMessagePassphraseCallback + implements MissingMessagePassphraseCallback +{ + private final Stack passphases; + + public StackMessagePassphraseCallback(char[] passphrase) + { + this(Collections.singleton(passphrase)); + } + + public StackMessagePassphraseCallback(Collection passphrases) + { + this.passphases = new Stack(); + this.passphases.addAll(passphrases); + } + + public char[] getMessagePassphrase() + { + if (passphases.isEmpty()) + { + return null; + } + return passphases.pop(); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/StaticV6OpenPGPMessageGeneratorTest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/StaticV6OpenPGPMessageGeneratorTest.java new file mode 100644 index 0000000000..a42709331b --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/StaticV6OpenPGPMessageGeneratorTest.java @@ -0,0 +1,109 @@ +package org.bouncycastle.openpgp.api.test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +import org.bouncycastle.bcpg.KeyIdentifier; +import org.bouncycastle.bcpg.test.AbstractPacketTest; +import org.bouncycastle.openpgp.OpenPGPTestKeys; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.api.OpenPGPCertificate; +import org.bouncycastle.openpgp.api.OpenPGPKey; +import org.bouncycastle.openpgp.api.OpenPGPKeyReader; +import org.bouncycastle.openpgp.api.OpenPGPMessageGenerator; +import org.bouncycastle.openpgp.api.OpenPGPMessageOutputStream; +import org.bouncycastle.openpgp.api.OpenPGPPolicy; +import org.bouncycastle.openpgp.api.SubkeySelector; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Hex; + +public class StaticV6OpenPGPMessageGeneratorTest + extends AbstractPacketTest +{ + private final OpenPGPKeyReader reader = new OpenPGPKeyReader(); + + KeyIdentifier signingKeyIdentifier = new KeyIdentifier( + Hex.decode("CB186C4F0609A697E4D52DFA6C722B0C1F1E27C18A56708F6525EC27BAD9ACC9")); + KeyIdentifier encryptionKeyIdentifier = new KeyIdentifier( + Hex.decode("12C83F1E706F6308FE151A417743A1F033790E93E9978488D1DB378DA9930885")); + + @Override + public String getName() + { + return "StaticV6OpenPGPMessageGeneratorTest"; + } + + @Override + public void performTest() + throws Exception + { + staticEncryptedMessage(); + staticSignedMessage(); + } + + private void staticEncryptedMessage() + throws IOException, PGPException + { + OpenPGPKey key = reader.parseKey(OpenPGPTestKeys.V6_KEY); + + OpenPGPMessageGenerator gen = getStaticGenerator() + .addEncryptionCertificate(key); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OpenPGPMessageOutputStream pgOut = (OpenPGPMessageOutputStream) gen.open(bOut); + pgOut.write(Strings.toUTF8ByteArray("Hello, World!\n")); + pgOut.close(); + + System.out.println(bOut); + } + + private void staticSignedMessage() + throws IOException, PGPException + { + OpenPGPKey key = reader.parseKey(OpenPGPTestKeys.V6_KEY); + OpenPGPMessageGenerator gen = getStaticGenerator() + .addSigningKey(key); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + OpenPGPMessageOutputStream pgOut = (OpenPGPMessageOutputStream) gen.open(bOut); + pgOut.write(Strings.toUTF8ByteArray("Hello, World!\n")); + pgOut.close(); + + System.out.println(bOut); + } + + /** + * Return a pre-configured {@link OpenPGPMessageGenerator} which has the complex logic of evaluating + * recipient keys to determine suitable subkeys, algorithms etc. swapped out for static configuration + * tailored to the V6 test key. + * + * @return static message generator + */ + public OpenPGPMessageGenerator getStaticGenerator() + { + OpenPGPMessageGenerator gen = new OpenPGPMessageGenerator() + .setSigningKeySelector(new SubkeySelector() + { + public List select( + OpenPGPCertificate certificate, OpenPGPPolicy policy) + { + return Collections.singletonList(certificate.getKey(signingKeyIdentifier)); + } + }) + .setEncryptionKeySelector( + new SubkeySelector() { + public List select(OpenPGPCertificate certificate, OpenPGPPolicy policy) { + return Collections.singletonList(certificate.getKey(encryptionKeyIdentifier)); + } + }); + + return gen; + } + + public static void main(String[] args) + { + runTest(new StaticV6OpenPGPMessageGeneratorTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/api/test/StrippedOpenPGPKeyTest.java b/pg/src/test/java/org/bouncycastle/openpgp/api/test/StrippedOpenPGPKeyTest.java new file mode 100644 index 0000000000..75da232dae --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/api/test/StrippedOpenPGPKeyTest.java @@ -0,0 +1,53 @@ +package org.bouncycastle.openpgp.api.test; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.api.OpenPGPApi; +import org.bouncycastle.openpgp.api.OpenPGPKey; +import org.bouncycastle.openpgp.api.OpenPGPKeyReader; + +import java.io.IOException; + +public class StrippedOpenPGPKeyTest + extends APITest +{ + + @Override + protected void performTestWith(OpenPGPApi api) + throws PGPException, IOException + { + // Adapted test case from https://github.com/bcgit/bc-java/issues/2173 + // Credit for test vectors to @agrahn + OpenPGPKeyReader reader = api.readKeyOrCertificate(); + OpenPGPKey strippedKey = reader.parseKey( + "-----BEGIN PGP PRIVATE KEY BLOCK-----\n\n" + + "lDsEaNz9VhYJKwYBBAHaRw8BAQdANvkQp6G9vVPUtxHplmw44lclTAm2vSqREnfi\n" + + "bsqmDDP/AGUAR05VAbQfQm9iIFVzZXIgPGJvYi51c2VyQGV4YW1wbGUub3JnPoiT\n" + + "BBMWCgA7FiEE81kLNGDerGMA7okHMcFP0Qqg/SwFAmjc/VYCGwEFCwkIBwICIgIG\n" + + "FQoJCAsCBBYCAwECHgcCF4AACgkQMcFP0Qqg/Szv3AEA5Q0S6UrHI6YC9IqCV86Z\n" + + "xF7zegeUJiTGfbIMmp+7qk4BAIJBZyfpsutfdnLBmXMQmPPvdlfNZ0H781sm4vq4\n" + + "1KkFnIsEaNz9pRIKKwYBBAGXVQEFAQEHQLilfhrcbzI6XI7a+HbOfqNj/9cwZk8s\n" + + "O4H/4IMhY7ZZAwEIB/4HAwIpPDPOpRpcw//ZZTsMuT5ZRDGnSA+3i34NWnhv50ex\n" + + "yf51MgrvY+E3NaE9ObFfvEJILF8kub206yaQRbHWPrj7fU1C+DKJ9AbDcXZmzu/U\n" + + "iHgEGBYKACAWIQTzWQs0YN6sYwDuiQcxwU/RCqD9LAUCaNz9pQIbDAAKCRAxwU/R\n" + + "CqD9LCNSAP9v7GminBOFV8XkMsL4T+0P0woGjTZxUrYKKVR98NhXswEAhDfkQh0n\n" + + "IyhOyHwzLuoGJ31M7a1rtB44tcJNtnP6XQQ=\n" + + "=jquc\n" + + "-----END PGP PRIVATE KEY BLOCK-----\n"); + + OpenPGPKey.OpenPGPSecretKey secKey = strippedKey.getPrimarySecretKey(); + + boolean isCorrect = secKey.isPassphraseCorrect(("12345678").toCharArray()); + isFalse("Expected false when checking passphrase of stripped secret key", isCorrect); + } + + @Override + public String getName() + { + return "StrippedOpenPGPKeyTest"; + } + + public static void main(String[] args) + { + runTest(new StrippedOpenPGPKeyTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/AEADProtectedPGPSecretKeyTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/AEADProtectedPGPSecretKeyTest.java index c9eb712af7..df48813c75 100644 --- a/pg/src/test/java/org/bouncycastle/openpgp/test/AEADProtectedPGPSecretKeyTest.java +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/AEADProtectedPGPSecretKeyTest.java @@ -20,6 +20,7 @@ import org.bouncycastle.bcpg.SecretKeyPacket; import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator; import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters; import org.bouncycastle.jce.provider.BouncyCastleProvider; @@ -45,6 +46,7 @@ import org.bouncycastle.openpgp.operator.jcajce.JcePBEProtectionRemoverFactory; import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.bouncycastle.util.Strings; +import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; import org.bouncycastle.util.encoders.Hex; public class AEADProtectedPGPSecretKeyTest @@ -365,14 +367,57 @@ private void lockUnlockKeyJca( keyPair.getPrivateKey().getPrivateKeyDataPacket().getEncoded(), dec.getPrivateKeyDataPacket().getEncoded()); } - private void reencryptKey() throws PGPException { + private void reencryptKey() + throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException + { reencryptKeyBc(); reencryptKeyJca(); } private void reencryptKeyJca() + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, PGPException { + BouncyCastleProvider prov = new BouncyCastleProvider(); + KeyPairGenerator eddsaGen = KeyPairGenerator.getInstance("EdDSA", prov); + eddsaGen.initialize(new ECNamedCurveGenParameterSpec("ed25519")); + KeyPair kp = eddsaGen.generateKeyPair(); + Date creationTime = currentTimeRounded(); + String passphrase = "recycle"; + + PGPKeyPair keyPair = new JcaPGPKeyPair(PublicKeyPacket.VERSION_6, PublicKeyAlgorithmTags.Ed25519, kp, creationTime); + PBESecretKeyEncryptor cfbEncBuilder = new JcePBESecretKeyEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_128) + .setProvider(prov) + .setSecureRandom(CryptoServicesRegistrar.getSecureRandom()) + .build(passphrase.toCharArray()); + PGPDigestCalculatorProvider digestProv = new JcaPGPDigestCalculatorProviderBuilder() + .setProvider(prov) + .build(); + + // Encrypt key using CFB mode + PGPSecretKey cfbEncKey = new PGPSecretKey( + keyPair.getPrivateKey(), + keyPair.getPublicKey(), + digestProv.get(HashAlgorithmTags.SHA1), + true, + cfbEncBuilder); + + PBESecretKeyDecryptor cfbDecryptor = new JcePBESecretKeyDecryptorBuilder(digestProv) + .setProvider(prov) + .build(passphrase.toCharArray()); + + JcaAEADSecretKeyEncryptorBuilder aeadEncBuilder = new JcaAEADSecretKeyEncryptorBuilder( + AEADAlgorithmTags.OCB, SymmetricKeyAlgorithmTags.AES_128, S2K.Argon2Params.memoryConstrainedParameters()) + .setProvider(prov); + + PGPSecretKey aeadEncKey = PGPSecretKey.copyWithNewPassword( + cfbEncKey, + cfbDecryptor, + aeadEncBuilder.build(passphrase.toCharArray(), cfbEncKey.getPublicKey().getPublicKeyPacket())); + PBESecretKeyDecryptor aeadDecryptor = new JcePBESecretKeyDecryptorBuilder(digestProv) + .setProvider(prov) + .build(passphrase.toCharArray()); + isNotNull(aeadEncKey.extractPrivateKey(aeadDecryptor)); } private void reencryptKeyBc() diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/ArmorCRCTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/ArmorCRCTest.java index a2aca2ad3c..7aa5e7fafb 100644 --- a/pg/src/test/java/org/bouncycastle/openpgp/test/ArmorCRCTest.java +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/ArmorCRCTest.java @@ -19,17 +19,17 @@ public class ArmorCRCTest extends SimpleTest { - + private static final String NL = Strings.lineSeparator(); private static final String WITHOUT_CRC = "" + - "-----BEGIN PGP MESSAGE-----\n" + - "\n" + - "yxR0AAAAAABIZWxsbywgV29ybGQhCg==\n" + - "-----END PGP MESSAGE-----\n"; + "-----BEGIN PGP MESSAGE-----" + NL + + NL + + "yxR0AAAAAABIZWxsbywgV29ybGQhCg==" + NL + + "-----END PGP MESSAGE-----" + NL; private static final String FAULTY_CRC = "" + - "-----BEGIN PGP MESSAGE-----\n" + - "\n" + - "yxR0AAAAAABIZWxsbywgV29ybGQhCg==\n" + - "=TRA9\n" + + "-----BEGIN PGP MESSAGE-----" + NL + + NL + + "yxR0AAAAAABIZWxsbywgV29ybGQhCg==" + NL + + "=TRA9" + NL + "-----END PGP MESSAGE-----"; @Override diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/ArmoredInputStreamTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/ArmoredInputStreamTest.java index 8e575bb6c9..60836c11e7 100644 --- a/pg/src/test/java/org/bouncycastle/openpgp/test/ArmoredInputStreamTest.java +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/ArmoredInputStreamTest.java @@ -5,8 +5,11 @@ import java.security.Security; import org.bouncycastle.bcpg.ArmoredInputStream; +import org.bouncycastle.bcpg.BCPGInputStream; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openpgp.PGPObjectFactory; +import org.bouncycastle.openpgp.PGPSignatureList; +import org.bouncycastle.openpgp.bc.BcPGPObjectFactory; import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; @@ -39,22 +42,22 @@ public class ArmoredInputStreamTest "bc2af032d2a59e36be6467bc23456b4ac178d36cf9f45df5e833a1981ed1a1032679ea0a"); private static final String badHeaderData1 = - "-----BEGIN PGP MESSAGE-----\n" - + "Version: BCPG v1.32\n" - + "Comment: A dummy message\n" - + "Comment actually not really as there is no colon" - + " \t \t\n" - + "SGVsbG8gV29ybGQh\n" - + "=d9Xi\n" - + "-----END PGP MESSAGE-----\n"; + "-----BEGIN PGP MESSAGE-----\n" + + "Version: BCPG v1.32\n" + + "Comment: A dummy message\n" + + "Comment actually not really as there is no colon" + + " \t \t\n" + + "SGVsbG8gV29ybGQh\n" + + "=d9Xi\n" + + "-----END PGP MESSAGE-----\n"; private static final String badHeaderData2 = - "-----BEGIN PGP MESSAGE-----\n" - + "Comment actually not really as there is no colon" - + " \t \t\n" - + "SGVsbG8gV29ybGQh\n" - + "=d9Xi\n" - + "-----END PGP MESSAGE-----\n"; + "-----BEGIN PGP MESSAGE-----\n" + + "Comment actually not really as there is no colon" + + " \t \t\n" + + "SGVsbG8gV29ybGQh\n" + + "=d9Xi\n" + + "-----END PGP MESSAGE-----\n"; public String getName() { @@ -63,12 +66,18 @@ public String getName() public void performTest() throws Exception + { + bogusHeadersTest(); + unknownClearsignedMessageHeadersTest(); + } + + private void bogusHeadersTest() { try { PGPObjectFactory pgpObjectFactoryOfTestFile = new PGPObjectFactory( new ArmoredInputStream(new ByteArrayInputStream(Arrays.concatenate(Strings.toByteArray("-----BEGIN PGP MESSAGE-----\n" - + "Version: BCPG v1.32\n\n"), bogusData))), new JcaKeyFingerprintCalculator()); + + "Version: BCPG v1.32\n\n"), bogusData))), new JcaKeyFingerprintCalculator()); pgpObjectFactoryOfTestFile.nextObject(); // <-- EXCEPTION HERE fail("no exception"); } @@ -100,6 +109,90 @@ public void performTest() } } + private void unknownClearsignedMessageHeadersTest() + throws IOException + { + // https://sequoia-pgp.gitlab.io/openpgp-interoperability-test-suite/results.html#Mangled_message_using_the_Cleartext_Signature_Framework_ + String armor = "-----BEGIN PGP SIGNED MESSAGE-----\n" + + "Hello: this is totally part of the signed text\n" + + "Hash: SHA512\n" + + "\n" + + "- From the grocery store we need:\n" + + "\n" + + "- - tofu\n" + + "- - vegetables\n" + + "- - noodles\n" + + "\n" + + "\n" + + "-----BEGIN PGP SIGNATURE-----\n" + + "\n" + + "wsE7BAEBCgBvBYJoMZ08CRD7/MgqAV5zMEcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmeO1uFIMk5ydOB8SNGi9ZkD0sHEoFRZM20v669ghBur\n" + + "KBYhBNGmbhojsYLJmA94jPv8yCoBXnMwAACffQwArOoXVWEF/Yii182hZPqE6t/E\n" + + "ZEyJcZLwsJXQ00ctno0TjXY9iDS0l1i0cWVIIcgkoutd+Gn8XI30EQEJivAs8uvE\n" + + "yCDFRQgkag2kOn+QtawyQ3LO+Xd5oZDbcy9Jvf4sG5YobBs7kfTb2NQgXDViM+k3\n" + + "69je5Mj+oKhtckM3BROYxq+B8DPgPT9UJuz0UgFQVYm5Mjj9jnFlUbMVl7UnsZwP\n" + + "0RNnbW8jtuQn7ehePzAOB94bzkvJL8/obPw2LsDfC0gWTovpJo0JibPZD/zaTA4y\n" + + "7yLnRvEM+8PilR6eIY40Us9oJerpjYsA16WMyIEvRfgHrYITpqHEzpJa7/vnMF2g\n" + + "t2PjcdtFeBsmJZrLwaJWB5Tku6wMsVL8Rmit8qecnVg9qYL3FrRUweEGo/dAH49M\n" + + "udZeck+sMaXdIhJnwy4HnH0tUiEGnHQ5mnBtTvKFR98paDVIW/xS+o95hUfmAXA8\n" + + "rmMglLYQkIXAZayAquW+VrxSxglNqXYxZNIxuHT6\n" + + "=yj77\n" + + "-----END PGP SIGNATURE-----"; + + // Test validation is not enabled by default + ByteArrayInputStream bIn = new ByteArrayInputStream(Strings.toUTF8ByteArray(armor)); + ArmoredInputStream aIn = ArmoredInputStream.builder() + .build(bIn); + // Skip over cleartext + isTrue(aIn.isClearText()); + while (aIn.isClearText()) + { + aIn.read(); + } + BCPGInputStream pIn = new BCPGInputStream(aIn); + PGPObjectFactory objFac = new BcPGPObjectFactory(pIn); + PGPSignatureList sigs = (PGPSignatureList)objFac.nextObject(); + isTrue(sigs != null); + + + // Test validation enabled + bIn = new ByteArrayInputStream(Strings.toUTF8ByteArray(armor)); + final ByteArrayInputStream finalBIn = bIn; + isTrue(null != testException( + "Illegal ASCII armor header line in clearsigned message encountered: Hello: this is totally part of the signed text", + "ArmoredInputException", + new TestExceptionOperation() + { + public void operation() + throws Exception + { + ArmoredInputStream.builder() + .setValidateClearsignedMessageHeaders(true) + .build(finalBIn); + } + }) + ); + + + // Test validation enabled, but custom header allowed + bIn = new ByteArrayInputStream(Strings.toUTF8ByteArray(armor)); + aIn = ArmoredInputStream.builder() + .setValidateClearsignedMessageHeaders(true) + .addAllowedArmorHeader("Hello") + .build(bIn); + // Skip over cleartext + isTrue(aIn.isClearText()); + while (aIn.isClearText()) + { + aIn.read(); + } + pIn = new BCPGInputStream(aIn); + objFac = new BcPGPObjectFactory(pIn); + sigs = (PGPSignatureList)objFac.nextObject(); + isTrue(sigs != null); + } + public static void main( String[] args) { diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/ArmoredOutputStreamTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/ArmoredOutputStreamTest.java index 1436460c7a..3c37db4dda 100644 --- a/pg/src/test/java/org/bouncycastle/openpgp/test/ArmoredOutputStreamTest.java +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/ArmoredOutputStreamTest.java @@ -71,7 +71,7 @@ public void performTest() aOut.close(); byte[] res = bOut.toByteArray(); - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); byte lastC = 0; for (int i = 0; i != res.length; i++) { diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/KeyIdentifierTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/KeyIdentifierTest.java index 4f19aa6ed6..b61b29f149 100644 --- a/pg/src/test/java/org/bouncycastle/openpgp/test/KeyIdentifierTest.java +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/KeyIdentifierTest.java @@ -37,8 +37,11 @@ public void performTest() throws Exception { testWildcardIdentifier(); + testWildcardMatches(); testIdentifierFromKeyId(); + testIdentifierFromLongKeyId(); + testIdentifierFromV4Fingerprint(); testIdentifierFromV6Fingerprint(); @@ -57,6 +60,20 @@ private void testWildcardIdentifier() wildcard.isWildcard()); isEquals("*", wildcard.toString()); + + KeyIdentifier id = new KeyIdentifier(0L); + isTrue(id.isWildcard()); + } + + private void testWildcardMatches() { + KeyIdentifier wildcard = KeyIdentifier.wildcard(); + KeyIdentifier nonWildcard = new KeyIdentifier(123L); + + isTrue(wildcard.matches(nonWildcard)); + isTrue(nonWildcard.matches(wildcard)); + + isTrue(!wildcard.matchesExplicit(nonWildcard)); + isTrue(!nonWildcard.matchesExplicit(wildcard)); } private void testIdentifierFromKeyId() @@ -70,6 +87,17 @@ private void testIdentifierFromKeyId() isEquals("1234", identifier.toString()); } + private void testIdentifierFromLongKeyId() + { + isEquals(5145070902336167606L, new KeyIdentifier("4766F6B9D5F21EB6").getKeyId()); + isEquals(5145070902336167606L, new KeyIdentifier("4766f6b9d5f21eb6").getKeyId()); + + isEquals(5507497285755629956L, new KeyIdentifier("4C6E8F99F6E47184").getKeyId()); + isEquals(1745434690267590572L, new KeyIdentifier("1839079A640B2FAC").getKeyId()); + + isTrue(new KeyIdentifier("1839079A640B2FAC").getFingerprint() == null); + } + private void testIdentifierFromV4Fingerprint() { String hexFingerprint = "D1A66E1A23B182C9980F788CFBFCC82A015E7330"; diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java index 2fadb77a55..210df8bf84 100644 --- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java @@ -507,7 +507,7 @@ public void testJcaAEADSecretKeyEncryptorBuilder() } } - private class NullProvider + private static final class NullProvider extends Provider { NullProvider() @@ -516,7 +516,7 @@ private class NullProvider } } - private class NonDashProvider + private static final class NonDashProvider extends Provider { NonDashProvider() @@ -527,7 +527,7 @@ private class NonDashProvider } } - private class DashProvider + private static final class DashProvider extends Provider { DashProvider() diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java index bc03498760..afd421d860 100644 --- a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java @@ -30,6 +30,7 @@ import org.bouncycastle.bcpg.SignatureSubpacketTags; import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; import org.bouncycastle.bcpg.attr.ImageAttribute; +import org.bouncycastle.bcpg.sig.Exportable; import org.bouncycastle.bcpg.sig.Features; import org.bouncycastle.bcpg.sig.IntendedRecipientFingerprint; import org.bouncycastle.bcpg.sig.KeyFlags; @@ -37,6 +38,7 @@ import org.bouncycastle.bcpg.sig.PolicyURI; import org.bouncycastle.bcpg.sig.PreferredAEADCiphersuites; import org.bouncycastle.bcpg.sig.RegularExpression; +import org.bouncycastle.bcpg.sig.Revocable; import org.bouncycastle.bcpg.sig.RevocationKey; import org.bouncycastle.bcpg.sig.RevocationKeyTags; import org.bouncycastle.bcpg.sig.RevocationReason; @@ -2169,7 +2171,7 @@ public void testPGPSignatureSubpacketVector() isTrue("Trust should be null", trustSignature != null); isTrue("Trust level depth should be " + depth, trustSignature.getDepth() == depth); isTrue("Trust amount should be " + trustAmount, trustSignature.getTrustAmount() == trustAmount); - isTrue("Exporable should be false", !hashedPcks.isExportable()); + isTrue("Exportable should be false", !hashedPcks.isExportable()); isTrue(hashedPcks.getIssuerFingerprint().getKeyVersion() == publicKey.getVersion()); isTrue("isPrimaryUserID should be true", hashedPcks.isPrimaryUserID()); @@ -2195,7 +2197,7 @@ public void testPGPSignatureSubpacketVector() isTrue("Trust should be null", trustSignature != null); isTrue("Trust level depth should be " + depth, trustSignature.getDepth() == depth); isTrue("Trust amount should be " + trustAmount, trustSignature.getTrustAmount() == trustAmount); - isTrue("Exporable should be false", !hashedPcks.isExportable()); + isTrue("Exportable should be false", !hashedPcks.isExportable()); isTrue(hashedPcks.getIssuerFingerprint().getKeyVersion() == publicKey.getVersion()); isTrue("isPrimaryUserID should be true", hashedPcks.isPrimaryUserID()); @@ -2207,27 +2209,20 @@ public void testPGPSignatureSubpacketVector() hashedGen = new PGPSignatureSubpacketGenerator(); hashedGen.setExportable(false, true); - try - { - hashedGen.setExportable(false, false); - fail("Duplicated settings for Exportable"); - } - catch (IllegalStateException e) - { - isTrue("Exportable Certification exists in the Signature Subpacket Generator", - messageIs(e.getMessage(), "Exportable Certification exists in the Signature Subpacket Generator")); - } + hashedGen.setExportable(false, false); + isEquals("Calling setExportable multiple times MUST NOT introduce duplicates", + 1, hashedGen.getSubpackets(SignatureSubpacketTags.EXPORTABLE).length); + Exportable exportable = (Exportable) hashedGen.getSubpackets(SignatureSubpacketTags.EXPORTABLE)[0]; + isTrue("Last invocation of setExportable MUST take precedence.", + !exportable.isExportable()); + hashedGen.setRevocable(false, true); - try - { - hashedGen.setRevocable(false, false); - fail("Duplicated settings for Revocable"); - } - catch (IllegalStateException e) - { - isTrue("Revocable exists in the Signature Subpacket Generator", - messageIs(e.getMessage(), "Revocable exists in the Signature Subpacket Generator")); - } + hashedGen.setRevocable(false, false); + isEquals("Calling setRevocable multiple times MUST NOT introduce duplicates.", + 1, hashedGen.getSubpackets(SignatureSubpacketTags.REVOCABLE).length); + Revocable revocable = (Revocable) hashedGen.getSubpackets(SignatureSubpacketTags.REVOCABLE)[0]; + isTrue("Last invocation of setRevocable MUST take precedence.", + !revocable.isRevocable()); try { @@ -2273,13 +2268,13 @@ public void testPGPSignatureSubpacketVector() hashedPcks = sig.getHashedSubPackets(); isTrue("URL should be " + url, hashedPcks.getPolicyURI().getURI().equals(url)); isTrue(areEqual(hashedPcks.getPolicyURI().getRawURI(), Strings.toUTF8ByteArray(url))); - isTrue("Exporable should be true", hashedPcks.isExportable()); - isTrue("Test Singner User ID", hashedPcks.getSignerUserID().equals("")); + isTrue("Exportable should be false", !hashedPcks.isExportable()); + isTrue("Test Signer User ID", hashedPcks.getSignerUserID().equals("")); isTrue("Test for empty description", hashedPcks.getRevocationReason().getRevocationDescription().equals("")); Features features = hashedPcks.getFeatures(); isTrue(features.supportsSEIPDv2()); isTrue(features.getFeatures() == Features.FEATURE_SEIPD_V2); - isTrue(hashedPcks.getRevocable().isRevocable()); + isTrue("Revocable should be false", !hashedPcks.getRevocable().isRevocable()); } public void testECNistCurves() diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPKeyPairGeneratorTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPKeyPairGeneratorTest.java index 1c16c272d8..a0f71064f0 100644 --- a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPKeyPairGeneratorTest.java +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPKeyPairGeneratorTest.java @@ -1,5 +1,8 @@ package org.bouncycastle.openpgp.test; +import org.bouncycastle.asn1.sec.SECObjectIdentifiers; +import org.bouncycastle.bcpg.ECDHPublicBCPGKey; +import org.bouncycastle.bcpg.ECDSAPublicBCPGKey; import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; import org.bouncycastle.bcpg.PublicKeyPacket; import org.bouncycastle.jce.provider.BouncyCastleProvider; @@ -70,6 +73,25 @@ private void performWith(Factory factory) testGenerateV6LegacyX25519KeyFails(factory); testGenerateV4LegacyX215519Key(factory); + + // NIST + testGenerateV4P256ECDHKey(factory); + testGenerateV6P256ECDHKey(factory); + + testGenerateV4P384ECDHKey(factory); + testGenerateV6P384ECDHKey(factory); + + testGenerateV4P521ECDHKey(factory); + testGenerateV6P521ECDHKey(factory); + + testGenerateV4P256ECDSAKey(factory); + testGenerateV6P256ECDSAKey(factory); + + testGenerateV4P384ECDSAKey(factory); + testGenerateV6P384ECDSAKey(factory); + + testGenerateV4P521ECDSAKey(factory); + testGenerateV6P521ECDSAKey(factory); } private void testGenerateV4RsaKey(Factory factory) @@ -318,6 +340,222 @@ private void testGenerateV4LegacyX215519Key(Factory factory) kp.getPublicKey().getCreationTime(), creationTime); } + private void testGenerateV4P256ECDHKey(Factory factory) + throws PGPException + { + Date creationTime = currentTimeRounded(); + PGPKeyPairGenerator gen = factory.create(PublicKeyPacket.VERSION_4, creationTime); + + PGPKeyPair kp = gen.generateNistP256ECDHKeyPair(); + + isEquals("Key version mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getVersion(), PublicKeyPacket.VERSION_4); + isEquals("Key algorithm mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getAlgorithm(), PublicKeyAlgorithmTags.ECDH); + ECDHPublicBCPGKey k = (ECDHPublicBCPGKey) kp.getPublicKey().getPublicKeyPacket().getKey(); + isEquals(SECObjectIdentifiers.secp256r1, k.getCurveOID()); + isEquals("Key creation time mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getCreationTime(), creationTime); + } + + private void testGenerateV4P384ECDHKey(Factory factory) + throws PGPException + { + Date creationTime = currentTimeRounded(); + PGPKeyPairGenerator gen = factory.create(PublicKeyPacket.VERSION_4, creationTime); + + PGPKeyPair kp = gen.generateNistP384ECDHKeyPair(); + + isEquals("Key version mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getVersion(), PublicKeyPacket.VERSION_4); + isEquals("Key algorithm mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getAlgorithm(), PublicKeyAlgorithmTags.ECDH); + ECDHPublicBCPGKey k = (ECDHPublicBCPGKey) kp.getPublicKey().getPublicKeyPacket().getKey(); + isEquals(SECObjectIdentifiers.secp384r1, k.getCurveOID()); + isEquals("Key creation time mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getCreationTime(), creationTime); + } + + private void testGenerateV4P521ECDHKey(Factory factory) + throws PGPException + { + Date creationTime = currentTimeRounded(); + PGPKeyPairGenerator gen = factory.create(PublicKeyPacket.VERSION_4, creationTime); + + PGPKeyPair kp = gen.generateNistP521ECDHKeyPair(); + + isEquals("Key version mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getVersion(), PublicKeyPacket.VERSION_4); + isEquals("Key algorithm mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getAlgorithm(), PublicKeyAlgorithmTags.ECDH); + ECDHPublicBCPGKey k = (ECDHPublicBCPGKey) kp.getPublicKey().getPublicKeyPacket().getKey(); + isEquals(SECObjectIdentifiers.secp521r1, k.getCurveOID()); + isEquals("Key creation time mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getCreationTime(), creationTime); + } + + private void testGenerateV4P256ECDSAKey(Factory factory) + throws PGPException + { + Date creationTime = currentTimeRounded(); + PGPKeyPairGenerator gen = factory.create(PublicKeyPacket.VERSION_4, creationTime); + + PGPKeyPair kp = gen.generateNistP256ECDSAKeyPair(); + + isEquals("Key version mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getVersion(), PublicKeyPacket.VERSION_4); + isEquals("Key algorithm mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getAlgorithm(), PublicKeyAlgorithmTags.ECDSA); + ECDSAPublicBCPGKey k = (ECDSAPublicBCPGKey) kp.getPublicKey().getPublicKeyPacket().getKey(); + isEquals(SECObjectIdentifiers.secp256r1, k.getCurveOID()); + isEquals("Key creation time mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getCreationTime(), creationTime); + } + + private void testGenerateV4P384ECDSAKey(Factory factory) + throws PGPException + { + Date creationTime = currentTimeRounded(); + PGPKeyPairGenerator gen = factory.create(PublicKeyPacket.VERSION_4, creationTime); + + PGPKeyPair kp = gen.generateNistP384ECDSAKeyPair(); + + isEquals("Key version mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getVersion(), PublicKeyPacket.VERSION_4); + isEquals("Key algorithm mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getAlgorithm(), PublicKeyAlgorithmTags.ECDSA); + ECDSAPublicBCPGKey k = (ECDSAPublicBCPGKey) kp.getPublicKey().getPublicKeyPacket().getKey(); + isEquals(SECObjectIdentifiers.secp384r1, k.getCurveOID()); + isEquals("Key creation time mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getCreationTime(), creationTime); + } + + private void testGenerateV4P521ECDSAKey(Factory factory) + throws PGPException + { + Date creationTime = currentTimeRounded(); + PGPKeyPairGenerator gen = factory.create(PublicKeyPacket.VERSION_4, creationTime); + + PGPKeyPair kp = gen.generateNistP521ECDSAKeyPair(); + + isEquals("Key version mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getVersion(), PublicKeyPacket.VERSION_4); + isEquals("Key algorithm mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getAlgorithm(), PublicKeyAlgorithmTags.ECDSA); + ECDSAPublicBCPGKey k = (ECDSAPublicBCPGKey) kp.getPublicKey().getPublicKeyPacket().getKey(); + isEquals(SECObjectIdentifiers.secp521r1, k.getCurveOID()); + isEquals("Key creation time mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getCreationTime(), creationTime); + } + + private void testGenerateV6P256ECDHKey(Factory factory) + throws PGPException + { + Date creationTime = currentTimeRounded(); + PGPKeyPairGenerator gen = factory.create(PublicKeyPacket.VERSION_6, creationTime); + + PGPKeyPair kp = gen.generateNistP256ECDHKeyPair(); + + isEquals("Key version mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getVersion(), PublicKeyPacket.VERSION_6); + isEquals("Key algorithm mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getAlgorithm(), PublicKeyAlgorithmTags.ECDH); + ECDHPublicBCPGKey k = (ECDHPublicBCPGKey) kp.getPublicKey().getPublicKeyPacket().getKey(); + isEquals(SECObjectIdentifiers.secp256r1, k.getCurveOID()); + isEquals("Key creation time mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getCreationTime(), creationTime); + } + + private void testGenerateV6P384ECDHKey(Factory factory) + throws PGPException + { + Date creationTime = currentTimeRounded(); + PGPKeyPairGenerator gen = factory.create(PublicKeyPacket.VERSION_6, creationTime); + + PGPKeyPair kp = gen.generateNistP384ECDHKeyPair(); + + isEquals("Key version mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getVersion(), PublicKeyPacket.VERSION_6); + isEquals("Key algorithm mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getAlgorithm(), PublicKeyAlgorithmTags.ECDH); + ECDHPublicBCPGKey k = (ECDHPublicBCPGKey) kp.getPublicKey().getPublicKeyPacket().getKey(); + isEquals(SECObjectIdentifiers.secp384r1, k.getCurveOID()); + isEquals("Key creation time mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getCreationTime(), creationTime); + } + + private void testGenerateV6P521ECDHKey(Factory factory) + throws PGPException + { + Date creationTime = currentTimeRounded(); + PGPKeyPairGenerator gen = factory.create(PublicKeyPacket.VERSION_6, creationTime); + + PGPKeyPair kp = gen.generateNistP521ECDHKeyPair(); + + isEquals("Key version mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getVersion(), PublicKeyPacket.VERSION_6); + isEquals("Key algorithm mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getAlgorithm(), PublicKeyAlgorithmTags.ECDH); + ECDHPublicBCPGKey k = (ECDHPublicBCPGKey) kp.getPublicKey().getPublicKeyPacket().getKey(); + isEquals(SECObjectIdentifiers.secp521r1, k.getCurveOID()); + isEquals("Key creation time mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getCreationTime(), creationTime); + } + + private void testGenerateV6P256ECDSAKey(Factory factory) + throws PGPException + { + Date creationTime = currentTimeRounded(); + PGPKeyPairGenerator gen = factory.create(PublicKeyPacket.VERSION_6, creationTime); + + PGPKeyPair kp = gen.generateNistP256ECDSAKeyPair(); + + isEquals("Key version mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getVersion(), PublicKeyPacket.VERSION_6); + isEquals("Key algorithm mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getAlgorithm(), PublicKeyAlgorithmTags.ECDSA); + ECDSAPublicBCPGKey k = (ECDSAPublicBCPGKey) kp.getPublicKey().getPublicKeyPacket().getKey(); + isEquals(SECObjectIdentifiers.secp256r1, k.getCurveOID()); + isEquals("Key creation time mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getCreationTime(), creationTime); + } + + private void testGenerateV6P384ECDSAKey(Factory factory) + throws PGPException + { + Date creationTime = currentTimeRounded(); + PGPKeyPairGenerator gen = factory.create(PublicKeyPacket.VERSION_6, creationTime); + + PGPKeyPair kp = gen.generateNistP384ECDSAKeyPair(); + + isEquals("Key version mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getVersion(), PublicKeyPacket.VERSION_6); + isEquals("Key algorithm mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getAlgorithm(), PublicKeyAlgorithmTags.ECDSA); + ECDSAPublicBCPGKey k = (ECDSAPublicBCPGKey) kp.getPublicKey().getPublicKeyPacket().getKey(); + isEquals(SECObjectIdentifiers.secp384r1, k.getCurveOID()); + isEquals("Key creation time mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getCreationTime(), creationTime); + } + + private void testGenerateV6P521ECDSAKey(Factory factory) + throws PGPException + { + Date creationTime = currentTimeRounded(); + PGPKeyPairGenerator gen = factory.create(PublicKeyPacket.VERSION_6, creationTime); + + PGPKeyPair kp = gen.generateNistP521ECDSAKeyPair(); + + isEquals("Key version mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getVersion(), PublicKeyPacket.VERSION_6); + isEquals("Key algorithm mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getAlgorithm(), PublicKeyAlgorithmTags.ECDSA); + ECDSAPublicBCPGKey k = (ECDSAPublicBCPGKey) kp.getPublicKey().getPublicKeyPacket().getKey(); + isEquals(SECObjectIdentifiers.secp521r1, k.getCurveOID()); + isEquals("Key creation time mismatch (" + gen.getClass().getName() + ")", + kp.getPublicKey().getCreationTime(), creationTime); + } + public static void main(String[] args) { runTest(new PGPKeyPairGeneratorTest()); diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPSessionKeyTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPSessionKeyTest.java index eeceef671d..2f73b433ea 100644 --- a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPSessionKeyTest.java +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPSessionKeyTest.java @@ -88,9 +88,9 @@ public class PGPSessionKeyTest public static void main(String[] args) throws Exception { - PGPSessionKeyTest test = new PGPSessionKeyTest(); Security.addProvider(new BouncyCastleProvider()); - test.performTest(); + + runTest(new PGPSessionKeyTest()); } public String getName() diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java index 270336aec4..0856437688 100644 --- a/pg/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java @@ -3,7 +3,6 @@ import java.security.Security; import org.bouncycastle.bcpg.test.SignatureSubpacketsTest; -import org.bouncycastle.openpgp.api.test.OpenPGPV6KeyGeneratorTest; import org.bouncycastle.util.test.SimpleTest; import org.bouncycastle.util.test.Test; @@ -87,8 +86,7 @@ public class RegressionTest new PGPv5MessageDecryptionTest(), new PGPv6SignatureTest(), new PGPKeyPairGeneratorTest(), - new OpenPGPV6KeyGeneratorTest(), - new PGPKeyRingGeneratorTest() + new PGPKeyRingGeneratorTest(), }; public static void main(String[] args) diff --git a/pkix/build.gradle b/pkix/build.gradle index 013eeb31c3..fcfe540494 100644 --- a/pkix/build.gradle +++ b/pkix/build.gradle @@ -1,6 +1,6 @@ plugins { - id "biz.aQute.bnd.builder" version "7.0.0" + id "biz.aQute.bnd.builder" version "7.1.0" } sourceSets { @@ -79,6 +79,11 @@ jar { manifest.attributes('Export-Package': "${packages};version=${v}") manifest.attributes('Import-Package': "java.*;resolution:=optional,javax.*;resolution:=optional,!${packages},org.bouncycastle.*;version=\"[${v},${maxVersion})\"") manifest.attributes('Bundle-Version': "${v}") + manifest.attributes('Permissions': 'all-permissions') + manifest.attributes('Codebase': '*') + manifest.attributes('Application-Library-Allowable-Codebase': '*') + manifest.attributes('Caller-Allowable-Codebase': '*') + manifest.attributes('Trusted-Library': 'true') } @@ -114,4 +119,4 @@ publishing { } } -} \ No newline at end of file +} diff --git a/pkix/src/main/java/org/bouncycastle/cert/X509ExtensionUtils.java b/pkix/src/main/java/org/bouncycastle/cert/X509ExtensionUtils.java index fa8cb1edb9..f67498104c 100644 --- a/pkix/src/main/java/org/bouncycastle/cert/X509ExtensionUtils.java +++ b/pkix/src/main/java/org/bouncycastle/cert/X509ExtensionUtils.java @@ -113,23 +113,16 @@ public SubjectKeyIdentifier createTruncatedSubjectKeyIdentifier(SubjectPublicKey private byte[] getSubjectKeyIdentifier(X509CertificateHolder certHolder) { - if (certHolder.getVersionNumber() != 3) - { - return calculateIdentifier(certHolder.getSubjectPublicKeyInfo()); - } - else + if (certHolder.getVersionNumber() == 3) { Extension ext = certHolder.getExtension(Extension.subjectKeyIdentifier); - if (ext != null) { return ASN1OctetString.getInstance(ext.getParsedValue()).getOctets(); } - else - { - return calculateIdentifier(certHolder.getSubjectPublicKeyInfo()); - } } + + return calculateIdentifier(certHolder.getSubjectPublicKeyInfo()); } private byte[] calculateIdentifier(SubjectPublicKeyInfo publicKeyInfo) diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/CMPChallengeFailedException.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/CMPChallengeFailedException.java new file mode 100644 index 0000000000..65c2c48d61 --- /dev/null +++ b/pkix/src/main/java/org/bouncycastle/cert/cmp/CMPChallengeFailedException.java @@ -0,0 +1,10 @@ +package org.bouncycastle.cert.cmp; + +public class CMPChallengeFailedException + extends CMPException +{ + public CMPChallengeFailedException(String msg) + { + super(msg); + } +} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/ChallengeContent.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/ChallengeContent.java new file mode 100644 index 0000000000..20199e1d6c --- /dev/null +++ b/pkix/src/main/java/org/bouncycastle/cert/cmp/ChallengeContent.java @@ -0,0 +1,71 @@ +package org.bouncycastle.cert.cmp; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collection; + +import org.bouncycastle.asn1.cmp.Challenge; +import org.bouncycastle.asn1.cmp.PKIHeader; +import org.bouncycastle.asn1.cms.ContentInfo; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.cms.CMSEnvelopedData; +import org.bouncycastle.cms.CMSException; +import org.bouncycastle.cms.Recipient; +import org.bouncycastle.cms.RecipientInformation; +import org.bouncycastle.operator.DigestCalculator; +import org.bouncycastle.util.Arrays; + +public class ChallengeContent +{ + private final Challenge challenge; + private final DigestCalculator owfCalc; + + ChallengeContent(Challenge challenge, DigestCalculator owfCalc) + { + this.challenge = challenge; + this.owfCalc = owfCalc; + } + + public byte[] extractChallenge(PKIHeader sourceMessageHdr, Recipient recipient) + throws CMPException + { + try + { + CMSEnvelopedData cmsEnvelopedData = new CMSEnvelopedData(new ContentInfo(PKCSObjectIdentifiers.envelopedData, challenge.getEncryptedRand())); + + Collection c = cmsEnvelopedData.getRecipientInfos().getRecipients(); + + RecipientInformation recInfo = (RecipientInformation)c.iterator().next(); + + byte[] recData = recInfo.getContent(recipient); + + Challenge.Rand rand = Challenge.Rand.getInstance(recData); + + if (!Arrays.constantTimeAreEqual(rand.getSender().getEncoded(), sourceMessageHdr.getSender().getEncoded())) + { + throw new CMPChallengeFailedException("incorrect sender found"); + } + + OutputStream digOut = owfCalc.getOutputStream(); + + digOut.write(rand.getInt().getEncoded()); + + digOut.close(); + + if (!Arrays.constantTimeAreEqual(challenge.getWitness(), owfCalc.getDigest())) + { + throw new CMPChallengeFailedException("corrupted challenge found"); + } + + return rand.getInt().getValue().toByteArray(); + } + catch (CMSException e) + { + throw new CMPException(e.getMessage(), e); + } + catch (IOException e) + { + throw new CMPException(e.getMessage(), e); + } + } +} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/POPODecryptionKeyChallengeContent.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/POPODecryptionKeyChallengeContent.java new file mode 100644 index 0000000000..c927051e57 --- /dev/null +++ b/pkix/src/main/java/org/bouncycastle/cert/cmp/POPODecryptionKeyChallengeContent.java @@ -0,0 +1,67 @@ +package org.bouncycastle.cert.cmp; + +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.cmp.Challenge; +import org.bouncycastle.asn1.cmp.PKIBody; +import org.bouncycastle.asn1.cmp.POPODecKeyChallContent; +import org.bouncycastle.operator.DigestCalculator; +import org.bouncycastle.operator.DigestCalculatorProvider; +import org.bouncycastle.operator.OperatorCreationException; + +/** + * POPODecKeyChallContent ::= SEQUENCE OF Challenge + * -- One Challenge per encryption key certification request (in the + * -- same order as these requests appear in CertReqMessages). + */ +public class POPODecryptionKeyChallengeContent +{ + private final ASN1Sequence content; + private final DigestCalculatorProvider owfCalcProvider; + + POPODecryptionKeyChallengeContent(POPODecKeyChallContent challenges, DigestCalculatorProvider owfCalcProvider) + { + this.content = ASN1Sequence.getInstance(challenges.toASN1Primitive()); + this.owfCalcProvider = owfCalcProvider; + } + + public ChallengeContent[] toChallengeArray() + throws CMPException + { + ChallengeContent[] result = new ChallengeContent[content.size()]; + DigestCalculator owfCalc = null; + + for (int i = 0; i != result.length; i++) + { + Challenge c = Challenge.getInstance(content.getObjectAt(i)); + if (c.getOwf() != null) + { + try + { + owfCalc = owfCalcProvider.get(c.getOwf()); + } + catch (OperatorCreationException e) + { + throw new CMPException(e.getMessage(), e); + } + } + result[i] = new ChallengeContent(Challenge.getInstance(content.getObjectAt(i)), owfCalc); + } + + return result; + } + + public static POPODecryptionKeyChallengeContent fromPKIBody(PKIBody pkiBody, DigestCalculatorProvider owfProvider) + { + if (pkiBody.getType() != PKIBody.TYPE_POPO_CHALL) + { + throw new IllegalArgumentException("content of PKIBody wrong type: " + pkiBody.getType()); + } + + return new POPODecryptionKeyChallengeContent(POPODecKeyChallContent.getInstance(pkiBody.getContent()), owfProvider); + } + + public POPODecKeyChallContent toASN1Structure() + { + return POPODecKeyChallContent.getInstance(content); + } +} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/POPODecryptionKeyChallengeContentBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/POPODecryptionKeyChallengeContentBuilder.java new file mode 100644 index 0000000000..430cb745a6 --- /dev/null +++ b/pkix/src/main/java/org/bouncycastle/cert/cmp/POPODecryptionKeyChallengeContentBuilder.java @@ -0,0 +1,101 @@ +package org.bouncycastle.cert.cmp; + +import java.io.IOException; +import java.io.OutputStream; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.cmp.Challenge; +import org.bouncycastle.asn1.cmp.POPODecKeyChallContent; +import org.bouncycastle.asn1.cms.EnvelopedData; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.cms.CMSEnvelopedData; +import org.bouncycastle.cms.CMSEnvelopedDataGenerator; +import org.bouncycastle.cms.CMSProcessableByteArray; +import org.bouncycastle.cms.RecipientInfoGenerator; +import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder; +import org.bouncycastle.operator.DigestCalculator; +import org.bouncycastle.operator.DigestCalculatorProvider; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.util.Arrays; + +/** + * POPODecKeyChallContent ::= SEQUENCE OF Challenge + * -- One Challenge per encryption key certification request (in the + * -- same order as these requests appear in CertReqMessages). + */ +public class POPODecryptionKeyChallengeContentBuilder +{ + private final DigestCalculator owfCalculator; + private final ASN1ObjectIdentifier challengeEncAlg; + private ASN1EncodableVector challenges = new ASN1EncodableVector(); + + public POPODecryptionKeyChallengeContentBuilder(DigestCalculator owfCalculator, ASN1ObjectIdentifier challengeEncAlg) + { + this.owfCalculator = owfCalculator; + this.challengeEncAlg = challengeEncAlg; + } + + public POPODecryptionKeyChallengeContentBuilder addChallenge(RecipientInfoGenerator recipientInfGenerator, GeneralName recipient, byte[] A) + throws CMPException + { + byte[] integer = Arrays.clone(A); + + try + { + OutputStream dOut = owfCalculator.getOutputStream(); + + dOut.write(new ASN1Integer(integer).getEncoded()); + + dOut.close(); + } + catch (IOException e) + { + throw new CMPException("unable to calculate witness", e); + } + + CMSEnvelopedData encryptedChallenge; + try + { + CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator(); + + edGen.addRecipientInfoGenerator(recipientInfGenerator); + + encryptedChallenge = edGen.generate( + new CMSProcessableByteArray(new Challenge.Rand(A, recipient).getEncoded()), + new JceCMSContentEncryptorBuilder(challengeEncAlg).setProvider("BC").build()); + } + catch (Exception e) + { + throw new CMPException("unable to encrypt challenge", e); + } + + EnvelopedData encryptedRand = EnvelopedData.getInstance(encryptedChallenge.toASN1Structure().getContent()); + + if (this.challenges.size() == 0) + { + this.challenges.add(new Challenge(owfCalculator.getAlgorithmIdentifier(), owfCalculator.getDigest(), encryptedRand)); + } + else + { + this.challenges.add(new Challenge(owfCalculator.getDigest(), encryptedRand)); + } + return this; + } + + public POPODecryptionKeyChallengeContent build() + { + return new POPODecryptionKeyChallengeContent(POPODecKeyChallContent.getInstance(new DERSequence(challenges)), new DigestCalculatorProvider() + { + @Override + public DigestCalculator get(AlgorithmIdentifier digestAlgorithmIdentifier) + throws OperatorCreationException + { + return owfCalculator; + } + }); + } +} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/POPODecryptionKeyResponseContent.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/POPODecryptionKeyResponseContent.java new file mode 100644 index 0000000000..2a89a6403c --- /dev/null +++ b/pkix/src/main/java/org/bouncycastle/cert/cmp/POPODecryptionKeyResponseContent.java @@ -0,0 +1,43 @@ +package org.bouncycastle.cert.cmp; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.cmp.PKIBody; +import org.bouncycastle.asn1.cmp.POPODecKeyRespContent; + +public class POPODecryptionKeyResponseContent +{ + private final POPODecKeyRespContent respContent; + + POPODecryptionKeyResponseContent(POPODecKeyRespContent respContent) + { + this.respContent = respContent; + } + + public byte[][] getResponses() + { + ASN1Integer[] resps = respContent.toASN1IntegerArray(); + byte[][] rv = new byte[resps.length][]; + + for (int i = 0; i != resps.length; i++) + { + rv[i] = resps[i].getValue().toByteArray(); + } + + return rv; + } + + public static POPODecryptionKeyResponseContent fromPKIBody(PKIBody pkiBody) + { + if (pkiBody.getType() != PKIBody.TYPE_POPO_REP) + { + throw new IllegalArgumentException("content of PKIBody wrong type: " + pkiBody.getType()); + } + + return new POPODecryptionKeyResponseContent(POPODecKeyRespContent.getInstance(pkiBody.getContent())); + } + + public POPODecKeyRespContent toASN1Structure() + { + return respContent; + } +} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/POPODecryptionKeyResponseContentBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/POPODecryptionKeyResponseContentBuilder.java new file mode 100644 index 0000000000..b208827643 --- /dev/null +++ b/pkix/src/main/java/org/bouncycastle/cert/cmp/POPODecryptionKeyResponseContentBuilder.java @@ -0,0 +1,25 @@ +package org.bouncycastle.cert.cmp; + +import java.math.BigInteger; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.cmp.POPODecKeyRespContent; + +public class POPODecryptionKeyResponseContentBuilder +{ + private ASN1EncodableVector v = new ASN1EncodableVector(); + + public POPODecryptionKeyResponseContentBuilder addChallengeResponse(byte[] response) + { + v.add(new ASN1Integer(new BigInteger(response))); + + return this; + } + + public POPODecryptionKeyResponseContent build() + { + return new POPODecryptionKeyResponseContent(POPODecKeyRespContent.getInstance(new DERSequence(v))); + } +} diff --git a/pkix/src/main/java/org/bouncycastle/cert/cmp/ProtectedPKIMessageBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/cmp/ProtectedPKIMessageBuilder.java index 1ef57d331e..6059a64ab0 100644 --- a/pkix/src/main/java/org/bouncycastle/cert/cmp/ProtectedPKIMessageBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/cert/cmp/ProtectedPKIMessageBuilder.java @@ -212,6 +212,20 @@ public ProtectedPKIMessageBuilder setBody(int bodyType, CertificateConfirmationC return this; } + public ProtectedPKIMessageBuilder setBody(POPODecryptionKeyChallengeContent popoDecKeyChallContent) + { + this.body = new PKIBody(PKIBody.TYPE_POPO_CHALL, popoDecKeyChallContent.toASN1Structure()); + + return this; + } + + public ProtectedPKIMessageBuilder setBody(POPODecryptionKeyResponseContent popoDecKeyRespContent) + { + this.body = new PKIBody(PKIBody.TYPE_POPO_REP, popoDecKeyRespContent.toASN1Structure()); + + return this; + } + /** * Add an "extra certificate" to the message. * diff --git a/pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRepMessageBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRepMessageBuilder.java index e6eabf140e..0b913218e5 100644 --- a/pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRepMessageBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/cert/crmf/CertificateRepMessageBuilder.java @@ -30,6 +30,7 @@ public CertificateRepMessageBuilder(X509CertificateHolder... caCerts) this.caCerts[i] = new CMPCertificate(caCerts[i].toASN1Structure()); } } + public CertificateRepMessageBuilder addCertificateResponse(CertificateResponse response) { responses.add(response.toASN1Structure()); diff --git a/pkix/src/main/java/org/bouncycastle/cert/dane/fetcher/JndiDANEFetcherFactory.java b/pkix/src/main/java/org/bouncycastle/cert/dane/fetcher/JndiDANEFetcherFactory.java index fa0d462449..d7eadada10 100644 --- a/pkix/src/main/java/org/bouncycastle/cert/dane/fetcher/JndiDANEFetcherFactory.java +++ b/pkix/src/main/java/org/bouncycastle/cert/dane/fetcher/JndiDANEFetcherFactory.java @@ -72,7 +72,7 @@ public DANEEntryFetcher build(final String domainName) if (dnsServerList.size() > 0) { - StringBuffer dnsServers = new StringBuffer(); + StringBuilder dnsServers = new StringBuilder(); for (Iterator it = dnsServerList.iterator(); it.hasNext(); ) { diff --git a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509v3CertificateBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509v3CertificateBuilder.java index d26f404a55..1e8e90ac86 100644 --- a/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509v3CertificateBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/cert/jcajce/JcaX509v3CertificateBuilder.java @@ -23,11 +23,11 @@ public class JcaX509v3CertificateBuilder /** * Initialise the builder using a PublicKey. * - * @param issuer X500Name representing the issuer of this certificate. - * @param serial the serial number for the certificate. + * @param issuer X500Name representing the issuer of this certificate. + * @param serial the serial number for the certificate. * @param notBefore date before which the certificate is not valid. - * @param notAfter date after which the certificate is not valid. - * @param subject X500Name representing the subject of this certificate. + * @param notAfter date after which the certificate is not valid. + * @param subject X500Name representing the subject of this certificate. * @param publicKey the public key to be associated with the certificate. */ public JcaX509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, SubjectPublicKeyInfo publicKey) @@ -38,46 +38,46 @@ public JcaX509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notB /** * Initialise the builder using a PublicKey. * - * @param issuer X500Name representing the issuer of this certificate. - * @param serial the serial number for the certificate. + * @param issuer X500Name representing the issuer of this certificate. + * @param serial the serial number for the certificate. * @param notBefore date before which the certificate is not valid. - * @param notAfter date after which the certificate is not valid. - * @param subject X500Name representing the subject of this certificate. + * @param notAfter date after which the certificate is not valid. + * @param subject X500Name representing the subject of this certificate. * @param publicKey the public key to be associated with the certificate. */ public JcaX509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey) { - super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + super(issuer, serial, notBefore, notAfter, subject, getSubjectPublicKeyInfo(publicKey)); } /** * Initialise the builder using a PublicKey. * - * @param issuer X500Name representing the issuer of this certificate. - * @param serial the serial number for the certificate. + * @param issuer X500Name representing the issuer of this certificate. + * @param serial the serial number for the certificate. * @param notBefore Time before which the certificate is not valid. - * @param notAfter Time after which the certificate is not valid. - * @param subject X500Name representing the subject of this certificate. + * @param notAfter Time after which the certificate is not valid. + * @param subject X500Name representing the subject of this certificate. * @param publicKey the public key to be associated with the certificate. */ public JcaX509v3CertificateBuilder(X500Name issuer, BigInteger serial, Time notBefore, Time notAfter, X500Name subject, PublicKey publicKey) { - super(issuer, serial, notBefore, notAfter, subject, SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + super(issuer, serial, notBefore, notAfter, subject, getSubjectPublicKeyInfo(publicKey)); } /** * Initialise the builder using X500Principal objects and a PublicKey. * - * @param issuer principal representing the issuer of this certificate. - * @param serial the serial number for the certificate. + * @param issuer principal representing the issuer of this certificate. + * @param serial the serial number for the certificate. * @param notBefore date before which the certificate is not valid. - * @param notAfter date after which the certificate is not valid. - * @param subject principal representing the subject of this certificate. + * @param notAfter date after which the certificate is not valid. + * @param subject principal representing the subject of this certificate. * @param publicKey the public key to be associated with the certificate. */ public JcaX509v3CertificateBuilder(X500Principal issuer, BigInteger serial, Date notBefore, Date notAfter, X500Principal subject, PublicKey publicKey) { - super(X500Name.getInstance(issuer.getEncoded()), serial, notBefore, notAfter, X500Name.getInstance(subject.getEncoded()), SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + super(X500Name.getInstance(issuer.getEncoded()), serial, notBefore, notAfter, X500Name.getInstance(subject.getEncoded()), getSubjectPublicKeyInfo(publicKey)); } /** @@ -85,11 +85,11 @@ public JcaX509v3CertificateBuilder(X500Principal issuer, BigInteger serial, Date * passing through and converting the other objects provided. * * @param issuerCert certificate who's subject is the issuer of the certificate we are building. - * @param serial the serial number for the certificate. - * @param notBefore date before which the certificate is not valid. - * @param notAfter date after which the certificate is not valid. - * @param subject principal representing the subject of this certificate. - * @param publicKey the public key to be associated with the certificate. + * @param serial the serial number for the certificate. + * @param notBefore date before which the certificate is not valid. + * @param notAfter date after which the certificate is not valid. + * @param subject principal representing the subject of this certificate. + * @param publicKey the public key to be associated with the certificate. */ public JcaX509v3CertificateBuilder(X509Certificate issuerCert, BigInteger serial, Date notBefore, Date notAfter, X500Principal subject, PublicKey publicKey) { @@ -101,11 +101,11 @@ public JcaX509v3CertificateBuilder(X509Certificate issuerCert, BigInteger serial * passing through and converting the other objects provided. * * @param issuerCert certificate who's subject is the issuer of the certificate we are building. - * @param serial the serial number for the certificate. - * @param notBefore date before which the certificate is not valid. - * @param notAfter date after which the certificate is not valid. - * @param subject principal representing the subject of this certificate. - * @param publicKey the public key to be associated with the certificate. + * @param serial the serial number for the certificate. + * @param notBefore date before which the certificate is not valid. + * @param notAfter date after which the certificate is not valid. + * @param subject principal representing the subject of this certificate. + * @param publicKey the public key to be associated with the certificate. */ public JcaX509v3CertificateBuilder(X509Certificate issuerCert, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, PublicKey publicKey) { @@ -120,15 +120,15 @@ public JcaX509v3CertificateBuilder(X509Certificate issuerCert, BigInteger serial public JcaX509v3CertificateBuilder(X509Certificate template) throws CertificateEncodingException { - super(new JcaX509CertificateHolder(template)); + super(new JcaX509CertificateHolder(template)); } /** * Add a given extension field for the standard extensions tag (tag 3) * copying the extension value from another certificate. * - * @param oid the type of the extension to be copied. - * @param critical true if the extension is to be marked critical, false otherwise. + * @param oid the type of the extension to be copied. + * @param critical true if the extension is to be marked critical, false otherwise. * @param certificate the source of the extension to be copied. * @return the builder instance. */ @@ -142,4 +142,9 @@ public JcaX509v3CertificateBuilder copyAndAddExtension( return this; } + + private static SubjectPublicKeyInfo getSubjectPublicKeyInfo(PublicKey publicKey) + { + return SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()); + } } diff --git a/pkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPRespBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPRespBuilder.java index 76b8df6ca2..89f86af09e 100644 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPRespBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/cert/ocsp/BasicOCSPRespBuilder.java @@ -43,7 +43,7 @@ private static class ResponseObject ASN1GeneralizedTime nextUpdate; Extensions extensions; - public ResponseObject( + ResponseObject( CertificateID certId, CertificateStatus certStatus, Date thisUpdate, @@ -90,7 +90,7 @@ else if (certStatus instanceof UnknownStatus) this.extensions = extensions; } - public SingleResponse toResponse() + SingleResponse toResponse() throws Exception { return new SingleResponse(certId.toASN1Primitive(), certStatus, thisUpdate, nextUpdate, extensions); diff --git a/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java b/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java index 389952cbb0..7a596d5ae2 100644 --- a/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/cert/ocsp/OCSPReqBuilder.java @@ -31,7 +31,7 @@ private static class RequestObject CertificateID certId; Extensions extensions; - public RequestObject( + RequestObject( CertificateID certId, Extensions extensions) { @@ -39,7 +39,7 @@ public RequestObject( this.extensions = extensions; } - public Request toRequest() + Request toRequest() throws Exception { return new Request(certId.toASN1Primitive(), extensions); diff --git a/pkix/src/main/java/org/bouncycastle/cert/selector/MSOutlookKeyIdCalculator.java b/pkix/src/main/java/org/bouncycastle/cert/selector/MSOutlookKeyIdCalculator.java index 8f6d119cc1..df8df1863a 100644 --- a/pkix/src/main/java/org/bouncycastle/cert/selector/MSOutlookKeyIdCalculator.java +++ b/pkix/src/main/java/org/bouncycastle/cert/selector/MSOutlookKeyIdCalculator.java @@ -44,7 +44,7 @@ private static abstract class GeneralDigest /** * Standard constructor */ - protected GeneralDigest() + GeneralDigest() { xBuf = new byte[4]; xBufOff = 0; @@ -55,14 +55,14 @@ protected GeneralDigest() * of the Object.clone() interface as this interface is not * supported by J2ME. */ - protected GeneralDigest(GeneralDigest t) + GeneralDigest(GeneralDigest t) { xBuf = new byte[t.xBuf.length]; copyIn(t); } - protected void copyIn(GeneralDigest t) + void copyIn(GeneralDigest t) { System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length); @@ -70,7 +70,7 @@ protected void copyIn(GeneralDigest t) byteCount = t.byteCount; } - public void update( + void update( byte in) { xBuf[xBufOff++] = in; @@ -84,7 +84,7 @@ public void update( byteCount++; } - public void update( + void update( byte[] in, int inOff, int len) @@ -124,7 +124,7 @@ public void update( } } - public void finish() + void finish() { long bitLength = (byteCount << 3); @@ -143,7 +143,7 @@ public void finish() processBlock(); } - public void reset() + void reset() { byteCount = 0; @@ -154,11 +154,11 @@ public void reset() } } - protected abstract void processWord(byte[] in, int inOff); + abstract void processWord(byte[] in, int inOff); - protected abstract void processLength(long bitLength); + abstract void processLength(long bitLength); - protected abstract void processBlock(); + abstract void processBlock(); } private static class SHA1Digest @@ -174,22 +174,22 @@ private static class SHA1Digest /** * Standard constructor */ - public SHA1Digest() + SHA1Digest() { reset(); } - public String getAlgorithmName() + String getAlgorithmName() { return "SHA-1"; } - public int getDigestSize() + int getDigestSize() { return DIGEST_LENGTH; } - protected void processWord( + void processWord( byte[] in, int inOff) { @@ -207,7 +207,7 @@ protected void processWord( } } - protected void processLength( + void processLength( long bitLength) { if (xOff > 14) @@ -219,7 +219,7 @@ protected void processLength( X[15] = (int)(bitLength & 0xffffffff); } - public int doFinal( + int doFinal( byte[] out, int outOff) { @@ -239,7 +239,7 @@ public int doFinal( /** * reset the chaining variables */ - public void reset() + void reset() { super.reset(); @@ -288,7 +288,7 @@ private int g( return ((u & v) | (u & w) | (v & w)); } - protected void processBlock() + void processBlock() { // // expand 16 word block into 80 word block. diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAlgorithm.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAlgorithm.java index 103659c424..f5296822d8 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAlgorithm.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSAlgorithm.java @@ -12,6 +12,7 @@ import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers; import org.bouncycastle.asn1.sec.SECObjectIdentifiers; import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; public class CMSAlgorithm @@ -46,6 +47,9 @@ public class CMSAlgorithm public static final ASN1ObjectIdentifier AES128_WRAP = NISTObjectIdentifiers.id_aes128_wrap.intern(); public static final ASN1ObjectIdentifier AES192_WRAP = NISTObjectIdentifiers.id_aes192_wrap.intern(); public static final ASN1ObjectIdentifier AES256_WRAP = NISTObjectIdentifiers.id_aes256_wrap.intern(); + public static final ASN1ObjectIdentifier AES128_WRAP_PAD = NISTObjectIdentifiers.id_aes128_wrap_pad.intern(); + public static final ASN1ObjectIdentifier AES192_WRAP_PAD = NISTObjectIdentifiers.id_aes192_wrap_pad.intern(); + public static final ASN1ObjectIdentifier AES256_WRAP_PAD = NISTObjectIdentifiers.id_aes256_wrap_pad.intern(); public static final ASN1ObjectIdentifier CAMELLIA128_WRAP = NTTObjectIdentifiers.id_camellia128_wrap.intern(); public static final ASN1ObjectIdentifier CAMELLIA192_WRAP = NTTObjectIdentifiers.id_camellia192_wrap.intern(); public static final ASN1ObjectIdentifier CAMELLIA256_WRAP = NTTObjectIdentifiers.id_camellia256_wrap.intern(); @@ -102,4 +106,7 @@ public class CMSAlgorithm public static final ASN1ObjectIdentifier SHAKE128_LEN = NISTObjectIdentifiers.id_shake128_len.intern(); public static final ASN1ObjectIdentifier SHAKE256_LEN = NISTObjectIdentifiers.id_shake256_len.intern(); + public static final ASN1ObjectIdentifier ChaCha20Poly1305 = PKCSObjectIdentifiers.id_alg_AEADChaCha20Poly1305.intern(); + + public static final AlgorithmIdentifier SHA256_HKDF = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_alg_hkdf_with_sha256); } diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedDataGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedDataGenerator.java index e84f2a69af..a1137bac62 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedDataGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedDataGenerator.java @@ -4,8 +4,11 @@ import java.io.IOException; import java.io.OutputStream; +import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.BEROctetString; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSet; import org.bouncycastle.asn1.cms.AuthEnvelopedData; @@ -36,10 +39,17 @@ private CMSAuthEnvelopedData doGenerate( try { OutputStream cOut = contentEncryptor.getOutputStream(bOut); - - content.write(cOut); - - authenticatedAttrSet = CMSUtils.processAuthAttrSet(authAttrsGenerator, contentEncryptor); + if (CMSAlgorithm.ChaCha20Poly1305.equals(contentEncryptor.getAlgorithmIdentifier().getAlgorithm())) + { + // AEAD Ciphers process AAD at first + authenticatedAttrSet = CMSUtils.processAuthAttrSet(authAttrsGenerator, contentEncryptor); + content.write(cOut); + } + else + { + content.write(cOut); + authenticatedAttrSet = CMSUtils.processAuthAttrSet(authAttrsGenerator, contentEncryptor); + } cOut.close(); } @@ -48,16 +58,18 @@ private CMSAuthEnvelopedData doGenerate( throw new CMSException("unable to process authenticated content: " + e.getMessage(), e); } - byte[] encryptedContent = bOut.toByteArray(); - byte[] mac = contentEncryptor.getMAC(); + ASN1OctetString encryptedContent = new BEROctetString(bOut.toByteArray()); + ASN1OctetString mac = new DEROctetString(contentEncryptor.getMAC()); - EncryptedContentInfo eci = CMSUtils.getEncryptedContentInfo(content, contentEncryptor, encryptedContent); + EncryptedContentInfo encryptedContentInfo = CMSUtils.getEncryptedContentInfo(content, contentEncryptor, + encryptedContent); ASN1Set unprotectedAttrSet = CMSUtils.getAttrDLSet(unauthAttrsGenerator); - ContentInfo contentInfo = new ContentInfo( - CMSObjectIdentifiers.authEnvelopedData, - new AuthEnvelopedData(originatorInfo, new DERSet(recipientInfos), eci, authenticatedAttrSet, new DEROctetString(mac), unprotectedAttrSet)); + ASN1Encodable authEnvelopedData = new AuthEnvelopedData(originatorInfo, new DERSet(recipientInfos), + encryptedContentInfo, authenticatedAttrSet, mac, unprotectedAttrSet); + + ContentInfo contentInfo = new ContentInfo(CMSObjectIdentifiers.authEnvelopedData, authEnvelopedData); return new CMSAuthEnvelopedData(contentInfo); } @@ -66,7 +78,7 @@ private CMSAuthEnvelopedData doGenerate( * generate an auth-enveloped object that contains an CMS Enveloped Data * object using the given provider. * - * @param content the content to be encrypted + * @param content the content to be encrypted * @param contentEncryptor the symmetric key based encryptor to encrypt the content with. */ public CMSAuthEnvelopedData generate( diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedDataParser.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedDataParser.java index 0d58f0c413..3f3c212ff6 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedDataParser.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedDataParser.java @@ -21,6 +21,16 @@ import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.util.Arrays; +/** + * Parser for authenticated enveloped CMS data structures. + *

    + * Important usage notes: + *

      + *
    • The constructor fully drains and closes the provided InputStream
    • + *
    • Plaintext content is buffered in memory and available via {@code RecipientInformation}
    • + *
    • Do not reuse the input stream after parsing
    • + *
    + */ public class CMSAuthEnvelopedDataParser extends CMSContentInfoParser { @@ -36,6 +46,13 @@ public class CMSAuthEnvelopedDataParser private boolean unauthAttrNotRead; private OriginatorInformation originatorInfo; + /** + * Create a parser from a byte array. + *

    + * Note: The input is fully consumed during parsing. Plaintext content is buffered in memory. + * + * @param envelopedData the CMS auth enveloped data bytes + */ public CMSAuthEnvelopedDataParser( byte[] envelopedData) throws CMSException, IOException @@ -43,6 +60,15 @@ public CMSAuthEnvelopedDataParser( this(new ByteArrayInputStream(envelopedData)); } + /** + * Create a parser from an input stream. + *

    + * Stream handling note: This constructor fully reads and closes the input stream + * before returning. The plaintext content is buffered in memory and accessible via + * {@link RecipientInformation#getContentStream}. + * + * @param envelopedData the CMS auth enveloped data stream + */ public CMSAuthEnvelopedDataParser( InputStream envelopedData) throws CMSException, IOException diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedDataStreamGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedDataStreamGenerator.java index 7c78c9078f..7de49e3daf 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedDataStreamGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedDataStreamGenerator.java @@ -2,7 +2,6 @@ import java.io.IOException; import java.io.OutputStream; -import java.util.Collections; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Integer; @@ -12,9 +11,18 @@ import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.operator.OutputAEADEncryptor; +/** + * Generate authenticated enveloped CMS data with streaming support. + *

    + * When using this generator, note: + *

      + *
    • The returned OutputStream must be closed to finalize encryption and authentication
    • + *
    • Closing the returned stream does not close the underlying OutputStream passed to {@code open()}
    • + *
    • Callers are responsible for closing the underlying OutputStream separately
    • + *
    + */ public class CMSAuthEnvelopedDataStreamGenerator extends CMSAuthEnvelopedGenerator { @@ -47,17 +55,6 @@ public void setBEREncodeRecipients( _berEncodeRecipientSet = berEncodeRecipientSet; } - private OutputStream doOpen( - ASN1ObjectIdentifier dataType, - OutputStream out, - OutputAEADEncryptor encryptor) - throws IOException, CMSException - { - ASN1EncodableVector recipientInfos = CMSUtils.getRecipentInfos(encryptor.getKey(), recipientInfoGenerators); - - return open(dataType, out, recipientInfos, encryptor); - } - protected OutputStream open( ASN1ObjectIdentifier dataType, OutputStream out, @@ -65,36 +62,25 @@ protected OutputStream open( OutputAEADEncryptor encryptor) throws IOException { - // // ContentInfo - // - BERSequenceGenerator cGen = new BERSequenceGenerator(out); - - cGen.addObject(CMSObjectIdentifiers.authEnvelopedData); - - // - // Encrypted Data - // - BERSequenceGenerator authEnvGen = new BERSequenceGenerator(cGen.getRawOutputStream(), 0, true); - - authEnvGen.addObject(new ASN1Integer(0)); - - CMSUtils.addOriginatorInfoToGenerator(authEnvGen, originatorInfo); - - CMSUtils.addRecipientInfosToGenerator(recipientInfos, authEnvGen, _berEncodeRecipientSet); + BERSequenceGenerator ciGen = new BERSequenceGenerator(out); + ciGen.addObject(CMSObjectIdentifiers.authEnvelopedData); - BERSequenceGenerator eiGen = new BERSequenceGenerator(authEnvGen.getRawOutputStream()); + // AuthEnvelopedData + BERSequenceGenerator aedGen = new BERSequenceGenerator(ciGen.getRawOutputStream(), 0, true); + aedGen.addObject(ASN1Integer.ZERO); + CMSUtils.addOriginatorInfoToGenerator(aedGen, originatorInfo); + CMSUtils.addRecipientInfosToGenerator(recipientInfos, aedGen, _berEncodeRecipientSet); - eiGen.addObject(dataType); + // EncryptedContentInfo + BERSequenceGenerator eciGen = new BERSequenceGenerator(aedGen.getRawOutputStream()); + eciGen.addObject(dataType); + eciGen.addObject(encryptor.getAlgorithmIdentifier()); - AlgorithmIdentifier encAlgId = encryptor.getAlgorithmIdentifier(); + // encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL (EncryptedContent ::= OCTET STRING) + OutputStream ecStream = CMSUtils.createBEROctetOutputStream(eciGen.getRawOutputStream(), 0, false, _bufferSize); - eiGen.getRawOutputStream().write(encAlgId.getEncoded()); - - OutputStream octetStream = CMSUtils.createBEROctetOutputStream( - eiGen.getRawOutputStream(), 0, true, _bufferSize); - - return new CMSAuthEnvelopedDataOutputStream(encryptor, octetStream, cGen, authEnvGen, eiGen); + return new CMSAuthEnvelopedDataOutputStream(encryptor, ecStream, ciGen, aedGen, eciGen); } protected OutputStream open( @@ -113,17 +99,42 @@ protected OutputStream open( } } + /** + * Generate authenticated-enveloped-data using the given encryptor, and marking the encapsulated + * bytes as being of type DATA. + *

    + * Stream handling note: Closing the returned stream finalizes the CMS structure but does + * not close the underlying output stream. The caller remains responsible for managing the + * lifecycle of {@code out}. + * + * @param out the output stream to write the CMS structure to + * @param encryptor the cipher to use for encryption + * @return an output stream that writes encrypted and authenticated content + */ + public OutputStream open(OutputStream out, OutputAEADEncryptor encryptor) throws CMSException, IOException + { + return open(CMSObjectIdentifiers.data, out, encryptor); + } /** - * generate an enveloped object that contains an CMS Enveloped Data - * object using the given encryptor. + * Generate authenticated-enveloped-data using the given encryptor, and marking the encapsulated + * bytes as being of the passed in type. + *

    + * Stream handling note: Closing the returned stream finalizes the CMS structure but + * does not close the underlying output stream. The caller remains responsible for + * managing the lifecycle of {@code out}. + * + * @param dataType the type of the data being written to the object. + * @param out the output stream to write the CMS structure to + * @param encryptor the cipher to use for encryption + * @return an output stream that writes encrypted and authenticated content */ - public OutputStream open( - OutputStream out, - OutputAEADEncryptor encryptor) + public OutputStream open(ASN1ObjectIdentifier dataType, OutputStream out, OutputAEADEncryptor encryptor) throws CMSException, IOException { - return doOpen(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), out, encryptor); + ASN1EncodableVector recipientInfos = CMSUtils.getRecipentInfos(encryptor.getKey(), recipientInfoGenerators); + + return open(dataType, out, recipientInfos, encryptor); } private class CMSAuthEnvelopedDataOutputStream @@ -190,7 +201,7 @@ public void close() _envGen.addObject(new DEROctetString(_encryptor.getMAC())); - CMSUtils.addAttriSetToGenerator(_envGen, unauthAttrsGenerator, 2, Collections.EMPTY_MAP); + CMSUtils.addAttriSetToGenerator(_envGen, unauthAttrsGenerator, 2, CMSUtils.getEmptyParameters()); _envGen.close(); _cGen.close(); diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedGenerator.java index f7de40cf35..e756627f20 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthEnvelopedGenerator.java @@ -1,10 +1,6 @@ package org.bouncycastle.cms; -import java.util.ArrayList; -import java.util.List; - import org.bouncycastle.asn1.cms.OriginatorInfo; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; /** * General class for generating a CMS enveloped-data message. @@ -12,9 +8,13 @@ public class CMSAuthEnvelopedGenerator extends CMSEnvelopedGenerator { - public static final String AES128_GCM = NISTObjectIdentifiers.id_aes128_GCM.getId(); - public static final String AES192_GCM = NISTObjectIdentifiers.id_aes192_GCM.getId(); - public static final String AES256_GCM = NISTObjectIdentifiers.id_aes256_GCM.getId(); + public static final String AES128_CCM = CMSAlgorithm.AES128_CCM.getId(); + public static final String AES192_CCM = CMSAlgorithm.AES192_CCM.getId(); + public static final String AES256_CCM = CMSAlgorithm.AES256_CCM.getId(); + public static final String AES128_GCM = CMSAlgorithm.AES128_GCM.getId(); + public static final String AES192_GCM = CMSAlgorithm.AES192_GCM.getId(); + public static final String AES256_GCM = CMSAlgorithm.AES256_GCM.getId(); + public static final String ChaCha20Poly1305 = CMSAlgorithm.ChaCha20Poly1305.getId(); protected CMSAttributeTableGenerator authAttrsGenerator = null; protected CMSAttributeTableGenerator unauthAttrsGenerator = null; @@ -43,14 +43,4 @@ public void setOriginatorInfo(OriginatorInformation originatorInfo) { this.originatorInfo = originatorInfo.toASN1Structure(); } - - /** - * Add a generator to produce the recipient info required. - * - * @param recipientGenerator a generator of a recipient info object. - */ - public void addRecipientInfoGenerator(RecipientInfoGenerator recipientGenerator) - { - recipientInfoGenerators.add(recipientGenerator); - } } diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedDataStreamGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedDataStreamGenerator.java index 93f56c197d..972b84a43c 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedDataStreamGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSAuthenticatedDataStreamGenerator.java @@ -47,7 +47,6 @@ public class CMSAuthenticatedDataStreamGenerator // private Object _unprotectedAttributes = null; private int bufferSize; private boolean berEncodeRecipientSet; - private MacCalculator macCalculator; /** * base constructor @@ -133,58 +132,44 @@ public OutputStream open( DigestCalculator digestCalculator) throws CMSException { - this.macCalculator = macCalculator; - try { ASN1EncodableVector recipientInfos = CMSUtils.getRecipentInfos(macCalculator.getKey(), recipientInfoGenerators); - // // ContentInfo - // BERSequenceGenerator cGen = new BERSequenceGenerator(out); - cGen.addObject(CMSObjectIdentifiers.authenticatedData); - // - // Authenticated Data - // + // AuthenticatedData BERSequenceGenerator authGen = new BERSequenceGenerator(cGen.getRawOutputStream(), 0, true); - - authGen.addObject(new ASN1Integer(AuthenticatedData.calculateVersion(originatorInfo))); - + authGen.addObject(ASN1Integer.valueOf(AuthenticatedData.calculateVersion(originatorInfo))); CMSUtils.addOriginatorInfoToGenerator(authGen, originatorInfo); - CMSUtils.addRecipientInfosToGenerator(recipientInfos, authGen, berEncodeRecipientSet); - - AlgorithmIdentifier macAlgId = macCalculator.getAlgorithmIdentifier(); - - authGen.getRawOutputStream().write(macAlgId.getEncoded()); + authGen.addObject(macCalculator.getAlgorithmIdentifier()); if (digestCalculator != null) { authGen.addObject(new DERTaggedObject(false, 1, digestCalculator.getAlgorithmIdentifier())); } - - BERSequenceGenerator eiGen = new BERSequenceGenerator(authGen.getRawOutputStream()); - eiGen.addObject(dataType); + // EncapsulatedContentInfo + BERSequenceGenerator eciGen = new BERSequenceGenerator(authGen.getRawOutputStream()); + eciGen.addObject(dataType); - OutputStream octetStream = CMSUtils.createBEROctetOutputStream( - eiGen.getRawOutputStream(), 0, true, bufferSize); + // eContent [0] EXPLICIT OCTET STRING OPTIONAL + OutputStream ecStream = CMSUtils.createBEROctetOutputStream(eciGen.getRawOutputStream(), 0, true, bufferSize); OutputStream mOut; - if (digestCalculator != null) { - mOut = new TeeOutputStream(octetStream, digestCalculator.getOutputStream()); + mOut = new TeeOutputStream(ecStream, digestCalculator.getOutputStream()); } else { - mOut = new TeeOutputStream(octetStream, macCalculator.getOutputStream()); + mOut = new TeeOutputStream(ecStream, macCalculator.getOutputStream()); } - return new CmsAuthenticatedDataOutputStream(macCalculator, digestCalculator, dataType, mOut, cGen, authGen, eiGen); + return new CmsAuthenticatedDataOutputStream(macCalculator, digestCalculator, dataType, mOut, cGen, authGen, eciGen); } catch (IOException e) { @@ -254,7 +239,11 @@ public void close() if (digestCalculator != null) { - parameters = Collections.unmodifiableMap(getBaseParameters(contentType, digestCalculator.getAlgorithmIdentifier(), macCalculator.getAlgorithmIdentifier(), digestCalculator.getDigest())); + AlgorithmIdentifier digestAlgID = digestCalculator.getAlgorithmIdentifier(); + AlgorithmIdentifier macAlgID = macCalculator.getAlgorithmIdentifier(); + + parameters = Collections.unmodifiableMap( + getBaseParameters(contentType, digestAlgID, macAlgID, digestCalculator.getDigest())); if (authGen == null) { @@ -273,7 +262,7 @@ public void close() } else { - parameters = Collections.EMPTY_MAP; + parameters = CMSUtils.getEmptyParameters(); } envGen.addObject(new DEROctetString(macCalculator.getMac())); diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedDataStreamGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedDataStreamGenerator.java index 02b5129113..17b96c42b9 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedDataStreamGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSCompressedDataStreamGenerator.java @@ -79,34 +79,23 @@ public OutputStream open( OutputCompressor compressor) throws IOException { + // ContentInfo BERSequenceGenerator sGen = new BERSequenceGenerator(out); - sGen.addObject(CMSObjectIdentifiers.compressedData); - // - // Compressed Data - // + // CompressedData BERSequenceGenerator cGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true); - - cGen.addObject(new ASN1Integer(0)); - - // - // AlgorithmIdentifier - // + cGen.addObject(ASN1Integer.ZERO); cGen.addObject(compressor.getAlgorithmIdentifier()); - // - // Encapsulated ContentInfo - // - BERSequenceGenerator eiGen = new BERSequenceGenerator(cGen.getRawOutputStream()); - - eiGen.addObject(contentOID); + // EncapsulatedContentInfo + BERSequenceGenerator eciGen = new BERSequenceGenerator(cGen.getRawOutputStream()); + eciGen.addObject(contentOID); - OutputStream octetStream = CMSUtils.createBEROctetOutputStream( - eiGen.getRawOutputStream(), 0, true, _bufferSize); + // eContent [0] EXPLICIT OCTET STRING OPTIONAL + OutputStream ecStream = CMSUtils.createBEROctetOutputStream(eciGen.getRawOutputStream(), 0, true, _bufferSize); - return new CmsCompressedOutputStream( - compressor.getOutputStream(octetStream), sGen, cGen, eiGen); + return new CmsCompressedOutputStream(compressor.getOutputStream(ecStream), sGen, cGen, eciGen); } private static class CmsCompressedOutputStream diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedDataGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedDataGenerator.java index dac06a1732..fb069122ed 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedDataGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedDataGenerator.java @@ -11,7 +11,6 @@ import org.bouncycastle.asn1.cms.ContentInfo; import org.bouncycastle.asn1.cms.EncryptedContentInfo; import org.bouncycastle.asn1.cms.EncryptedData; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.operator.OutputEncryptor; /** @@ -46,9 +45,6 @@ private CMSEncryptedData doGenerate( OutputEncryptor contentEncryptor) throws CMSException { - AlgorithmIdentifier encAlgId; - ASN1OctetString encContent; - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); try @@ -64,22 +60,16 @@ private CMSEncryptedData doGenerate( throw new CMSException(""); } - byte[] encryptedContent = bOut.toByteArray(); - - encAlgId = contentEncryptor.getAlgorithmIdentifier(); + ASN1OctetString encryptedContent = new BEROctetString(bOut.toByteArray()); - encContent = new BEROctetString(encryptedContent); - - EncryptedContentInfo eci = CMSUtils.getEncryptedContentInfo( - content.getContentType(), - encAlgId, - encryptedContent); + EncryptedContentInfo encryptedContentInfo = CMSUtils.getEncryptedContentInfo(content, contentEncryptor, + encryptedContent); ASN1Set unprotectedAttrSet = CMSUtils.getAttrBERSet(unprotectedAttributeGenerator); - ContentInfo contentInfo = new ContentInfo( - CMSObjectIdentifiers.encryptedData, - new EncryptedData(eci, unprotectedAttrSet)); + EncryptedData encryptedData = new EncryptedData(encryptedContentInfo, unprotectedAttrSet); + + ContentInfo contentInfo = new ContentInfo(CMSObjectIdentifiers.encryptedData, encryptedData); return new CMSEncryptedData(contentInfo); } diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataGenerator.java index 24c925a650..2680fd1091 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataGenerator.java @@ -5,7 +5,9 @@ import java.io.OutputStream; import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.BEROctetString; import org.bouncycastle.asn1.DERSet; import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; import org.bouncycastle.asn1.cms.ContentInfo; @@ -72,15 +74,17 @@ private CMSEnvelopedData doGenerate( throw new CMSException(""); } - byte[] encryptedContent = bOut.toByteArray(); + ASN1OctetString encryptedContent = new BEROctetString(bOut.toByteArray()); - EncryptedContentInfo eci = CMSUtils.getEncryptedContentInfo(content, contentEncryptor, encryptedContent); + EncryptedContentInfo encryptedContentInfo = CMSUtils.getEncryptedContentInfo(content, contentEncryptor, + encryptedContent); ASN1Set unprotectedAttrSet = CMSUtils.getAttrBERSet(unprotectedAttributeGenerator); - ContentInfo contentInfo = new ContentInfo( - CMSObjectIdentifiers.envelopedData, - new EnvelopedData(originatorInfo, new DERSet(recipientInfos), eci, unprotectedAttrSet)); + EnvelopedData envelopedData = new EnvelopedData(originatorInfo, new DERSet(recipientInfos), + encryptedContentInfo, unprotectedAttrSet); + + ContentInfo contentInfo = new ContentInfo(CMSObjectIdentifiers.envelopedData, envelopedData); return new CMSEnvelopedData(contentInfo); } diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataStreamGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataStreamGenerator.java index 0dc648160a..fde239f28c 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataStreamGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSEnvelopedDataStreamGenerator.java @@ -2,7 +2,6 @@ import java.io.IOException; import java.io.OutputStream; -import java.util.Collections; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Integer; @@ -72,20 +71,9 @@ private ASN1Integer getVersion(ASN1EncodableVector recipientInfos) if (unprotectedAttributeGenerator != null) { // mark unprotected attributes as non-null. - return new ASN1Integer(EnvelopedData.calculateVersion(originatorInfo, new DLSet(recipientInfos), new DLSet())); + return ASN1Integer.valueOf(EnvelopedData.calculateVersion(originatorInfo, new DLSet(recipientInfos), new DLSet())); } - return new ASN1Integer(EnvelopedData.calculateVersion(originatorInfo, new DLSet(recipientInfos), null)); - } - - private OutputStream doOpen( - ASN1ObjectIdentifier dataType, - OutputStream out, - OutputEncryptor encryptor) - throws IOException, CMSException - { - ASN1EncodableVector recipientInfos = CMSUtils.getRecipentInfos(encryptor.getKey(), recipientInfoGenerators); - - return open(dataType, out, recipientInfos, encryptor); + return ASN1Integer.valueOf(EnvelopedData.calculateVersion(originatorInfo, new DLSet(recipientInfos), null)); } protected OutputStream open( @@ -95,36 +83,25 @@ protected OutputStream open( OutputEncryptor encryptor) throws IOException { - // // ContentInfo - // BERSequenceGenerator cGen = new BERSequenceGenerator(out); - cGen.addObject(CMSObjectIdentifiers.envelopedData); - // - // Encrypted Data - // + // EnvelopedData BERSequenceGenerator envGen = new BERSequenceGenerator(cGen.getRawOutputStream(), 0, true); - envGen.addObject(getVersion(recipientInfos)); - CMSUtils.addOriginatorInfoToGenerator(envGen, originatorInfo); - CMSUtils.addRecipientInfosToGenerator(recipientInfos, envGen, _berEncodeRecipientSet); - BERSequenceGenerator eiGen = new BERSequenceGenerator(envGen.getRawOutputStream()); - - eiGen.addObject(dataType); - - AlgorithmIdentifier encAlgId = encryptor.getAlgorithmIdentifier(); + // EncryptedContentInfo + BERSequenceGenerator eciGen = new BERSequenceGenerator(envGen.getRawOutputStream()); + eciGen.addObject(dataType); + eciGen.addObject(encryptor.getAlgorithmIdentifier()); - eiGen.getRawOutputStream().write(encAlgId.getEncoded()); + // encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL (EncryptedContent ::= OCTET STRING) + OutputStream ecStream = CMSUtils.createBEROctetOutputStream(eciGen.getRawOutputStream(), 0, false, _bufferSize); - OutputStream octetStream = CMSUtils.createBEROctetOutputStream( - eiGen.getRawOutputStream(), 0, false, _bufferSize); - - return new CmsEnvelopedDataOutputStream(encryptor, octetStream, cGen, envGen, eiGen); + return new CmsEnvelopedDataOutputStream(encryptor, ecStream, cGen, envGen, eciGen); } protected OutputStream open( @@ -147,12 +124,9 @@ protected OutputStream open( * generate an enveloped object that contains an CMS Enveloped Data * object using the given encryptor. */ - public OutputStream open( - OutputStream out, - OutputEncryptor encryptor) - throws CMSException, IOException + public OutputStream open(OutputStream out, OutputEncryptor encryptor) throws CMSException, IOException { - return doOpen(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), out, encryptor); + return open(CMSObjectIdentifiers.data, out, encryptor); } /** @@ -160,13 +134,12 @@ public OutputStream open( * object using the given encryptor and marking the data as being of the passed * in type. */ - public OutputStream open( - ASN1ObjectIdentifier dataType, - OutputStream out, - OutputEncryptor encryptor) + public OutputStream open(ASN1ObjectIdentifier dataType, OutputStream out, OutputEncryptor encryptor) throws CMSException, IOException { - return doOpen(dataType, out, encryptor); + ASN1EncodableVector recipientInfos = CMSUtils.getRecipentInfos(encryptor.getKey(), recipientInfoGenerators); + + return open(dataType, out, recipientInfos, encryptor); } private class CmsEnvelopedDataOutputStream @@ -229,7 +202,7 @@ public void close() } _eiGen.close(); - CMSUtils.addAttriSetToGenerator(_envGen, unprotectedAttributeGenerator, 1, Collections.EMPTY_MAP); + CMSUtils.addAttriSetToGenerator(_envGen, unprotectedAttributeGenerator, 1, CMSUtils.getEmptyParameters()); _envGen.close(); _cGen.close(); diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java index 59fc2d8d6b..c9754aac4c 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataGenerator.java @@ -138,7 +138,7 @@ public CMSSignedData generate( ASN1EncodableVector signerInfos = new ASN1EncodableVector(); digests.clear(); // clear the current preserved digest state - + digestAlgs.addAll(extraDigestAlgorithms); // // add the precalculated SignerInfo objects. // diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataParser.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataParser.java index 56acf89016..c6f7c2b116 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataParser.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataParser.java @@ -28,6 +28,7 @@ import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERSet; import org.bouncycastle.asn1.DERTaggedObject; +import org.bouncycastle.asn1.DLSet; import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; import org.bouncycastle.asn1.cms.ContentInfoParser; import org.bouncycastle.asn1.cms.SignedDataParser; @@ -438,27 +439,17 @@ public static OutputStream replaceSigners( // digests signedData.getDigestAlgorithms().toASN1Primitive(); // skip old ones - ASN1EncodableVector digestAlgs = new ASN1EncodableVector(); - - for (Iterator it = signerInformationStore.getSigners().iterator(); it.hasNext();) + Set digestAlgs = new HashSet(); + for (Iterator it = signerInformationStore.getSigners().iterator(); it.hasNext(); ) { SignerInformation signer = (SignerInformation)it.next(); + CMSUtils.addDigestAlgs(digestAlgs, signer, dgstAlgFinder); digestAlgs.add(HELPER.fixDigestAlgID(signer.getDigestAlgorithmID(), dgstAlgFinder)); } + AlgorithmIdentifier[] newDigestAlgIds = (AlgorithmIdentifier[])digestAlgs.toArray(new AlgorithmIdentifier[digestAlgs.size()]); + sigGen.addObject(new DLSet(newDigestAlgIds)); - sigGen.getRawOutputStream().write(new DERSet(digestAlgs).getEncoded()); - - // encap content info - ContentInfoParser encapContentInfo = signedData.getEncapContentInfo(); - - BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream()); - - eiGen.addObject(encapContentInfo.getContentType()); - - pipeEncapsulatedOctetString(encapContentInfo, eiGen.getRawOutputStream()); - - eiGen.close(); - + writeEncapContentInfoToGenerator(signedData, sigGen); writeSetToGeneratorTagged(sigGen, signedData.getCertificates(), 0); writeSetToGeneratorTagged(sigGen, signedData.getCrls(), 1); @@ -472,7 +463,7 @@ public static OutputStream replaceSigners( signerInfos.add(signer.toASN1Structure()); } - sigGen.getRawOutputStream().write(new DERSet(signerInfos).getEncoded()); + sigGen.addObject(new DERSet(signerInfos)); sigGen.close(); @@ -517,18 +508,9 @@ public static OutputStream replaceCertificatesAndCRLs( sigGen.addObject(signedData.getVersion()); // digests - sigGen.getRawOutputStream().write(signedData.getDigestAlgorithms().toASN1Primitive().getEncoded()); + sigGen.addObject(signedData.getDigestAlgorithms()); - // encap content info - ContentInfoParser encapContentInfo = signedData.getEncapContentInfo(); - - BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream()); - - eiGen.addObject(encapContentInfo.getContentType()); - - pipeEncapsulatedOctetString(encapContentInfo, eiGen.getRawOutputStream()); - - eiGen.close(); + writeEncapContentInfoToGenerator(signedData, sigGen); // // skip existing certs and CRLs @@ -556,7 +538,7 @@ public static OutputStream replaceCertificatesAndCRLs( if (asn1Certs.size() > 0) { - sigGen.getRawOutputStream().write(new DERTaggedObject(false, 0, asn1Certs).getEncoded()); + sigGen.addObject(new DERTaggedObject(false, 0, asn1Certs)); } } @@ -566,11 +548,11 @@ public static OutputStream replaceCertificatesAndCRLs( if (asn1Crls.size() > 0) { - sigGen.getRawOutputStream().write(new DERTaggedObject(false, 1, asn1Crls).getEncoded()); + sigGen.addObject(new DERTaggedObject(false, 1, asn1Crls)); } } - sigGen.getRawOutputStream().write(signedData.getSignerInfos().toASN1Primitive().getEncoded()); + sigGen.addObject(signedData.getSignerInfos()); sigGen.close(); @@ -579,7 +561,7 @@ public static OutputStream replaceCertificatesAndCRLs( return out; } - private static void writeSetToGeneratorTagged( + static void writeSetToGeneratorTagged( ASN1Generator asn1Gen, ASN1SetParser asn1SetParser, int tagNo) @@ -591,11 +573,11 @@ private static void writeSetToGeneratorTagged( { if (asn1SetParser instanceof BERSetParser) { - asn1Gen.getRawOutputStream().write(new BERTaggedObject(false, tagNo, asn1Set).getEncoded()); + new BERTaggedObject(false, tagNo, asn1Set).encodeTo(asn1Gen.getRawOutputStream()); } else { - asn1Gen.getRawOutputStream().write(new DERTaggedObject(false, tagNo, asn1Set).getEncoded()); + new DERTaggedObject(false, tagNo, asn1Set).encodeTo(asn1Gen.getRawOutputStream()); } } } @@ -661,4 +643,18 @@ private static void pipeOctetString( // ASN1OctetStringParser octs = (ASN1OctetStringParser)sp.readObject(); // Streams.drain(octs.getOctetStream()); // } + + static void writeEncapContentInfoToGenerator(SignedDataParser signedData, BERSequenceGenerator sigGen) + throws IOException + { + // encap content info + ContentInfoParser encapContentInfo = signedData.getEncapContentInfo(); + + BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream()); + eiGen.addObject(encapContentInfo.getContentType()); + + pipeEncapsulatedOctetString(encapContentInfo, eiGen.getRawOutputStream()); + + eiGen.close(); + } } diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataStreamEditor.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataStreamEditor.java new file mode 100644 index 0000000000..395a186841 --- /dev/null +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataStreamEditor.java @@ -0,0 +1,116 @@ +package org.bouncycastle.cms; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1SequenceParser; +import org.bouncycastle.asn1.ASN1StreamParser; +import org.bouncycastle.asn1.BERSequenceGenerator; +import org.bouncycastle.asn1.BERTags; +import org.bouncycastle.asn1.DERSet; +import org.bouncycastle.asn1.DLSet; +import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; +import org.bouncycastle.asn1.cms.ContentInfoParser; +import org.bouncycastle.asn1.cms.SignedDataParser; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; +import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder; +import org.bouncycastle.operator.DigestCalculator; +import org.bouncycastle.operator.DigestCalculatorProvider; +import org.bouncycastle.operator.OperatorCreationException; + +public class CMSSignedDataStreamEditor +{ + private static final CMSSignedHelper HELPER = CMSSignedHelper.INSTANCE; + private static final DefaultDigestAlgorithmIdentifierFinder dgstAlgFinder = new DefaultDigestAlgorithmIdentifierFinder(); + /** + * Add the specified digest algorithm to the signed data contained in the input stream and write + * the updated signed data to the provided output stream. This ensures that the output signed data + * includes the specified digest algorithm. Uses the provided DigestAlgorithmIdentifierFinder to + * create the digest sets and the DigestCalculatorProvider for computing the required digests. + *

    + * The output stream is returned unclosed. + *

    + * + * @param out the output stream where the updated signed data object will be written. + * @param original the input stream containing the original signed data to be modified. + * @param digestAlgorithm the digest algorithm to be added to the signed data. + * @param digestAlgIdFinder the DigestAlgorithmIdentifierFinder used to create the digest sets. + * @param digestCalculatorProvider the DigestCalculatorProvider used to compute the digests. + * @return the output stream containing the updated signed data. + */ + public static OutputStream addDigestAlgorithm(OutputStream out, InputStream original, + AlgorithmIdentifier digestAlgorithm, + DigestAlgorithmIdentifierFinder digestAlgIdFinder, + DigestCalculatorProvider digestCalculatorProvider) + throws IOException, CMSException + { + ContentInfoParser contentInfo = new ContentInfoParser((ASN1SequenceParser)new ASN1StreamParser(original).readObject()); + SignedDataParser signedData = SignedDataParser.getInstance(contentInfo.getContent(BERTags.SEQUENCE)); + BERSequenceGenerator sGen = new BERSequenceGenerator(out); + + sGen.addObject(CMSObjectIdentifiers.signedData); + + BERSequenceGenerator sigGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true); + + // version number + sigGen.addObject(signedData.getVersion()); + // digests + ASN1EncodableVector digestAlgs = new ASN1EncodableVector(); + Map digests = new LinkedHashMap(); + try + { + for (Iterator it = ((DLSet)signedData.getDigestAlgorithms().toASN1Primitive()).iterator(); it.hasNext(); ) + { + AlgorithmIdentifier oid = AlgorithmIdentifier.getInstance(it.next()); + digestAlgs.add(HELPER.fixDigestAlgID(oid, digestAlgIdFinder)); + digests.put(oid, digestCalculatorProvider.get(oid)); + } + if (!digests.containsKey(digestAlgorithm)) + { + digestAlgs.add(HELPER.fixDigestAlgID(digestAlgorithm, digestAlgIdFinder)); + digests.put(digestAlgorithm, digestCalculatorProvider.get(digestAlgorithm)); + } + } + catch (OperatorCreationException e) + { + throw new CMSException("unable to find digest algorithm"); + } + sigGen.addObject(new DERSet(digestAlgs)); + + CMSSignedDataParser.writeEncapContentInfoToGenerator(signedData, sigGen); + + CMSSignedDataParser.writeSetToGeneratorTagged(sigGen, signedData.getCertificates(), 0); + CMSSignedDataParser.writeSetToGeneratorTagged(sigGen, signedData.getCrls(), 1); + sigGen.addObject(signedData.getSignerInfos()); + + sigGen.close(); + sGen.close(); + + return out; + } + + /** + * Add the specified digest algorithm to the signed data contained in the input stream and write + * the updated signed data to the provided output stream. This ensures that the output signed data + * includes the specified digest algorithm. + *

    + * The output stream is returned unclosed. + *

    + * + * @param out the output stream where the updated signed data object will be written. + * @param original the input stream containing the original signed data to be modified. + * @param digestAlgorithm the digest algorithm to be added to the signed data. + * @return the output stream containing the updated signed data. + */ + public static OutputStream addDigestAlgorithm(OutputStream out, InputStream original, AlgorithmIdentifier digestAlgorithm, DigestCalculatorProvider digestCalculatorProvider) + throws IOException, CMSException + { + return addDigestAlgorithm(out, original, digestAlgorithm, dgstAlgFinder, digestCalculatorProvider); + } +} diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataStreamGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataStreamGenerator.java index 3b45edb06b..2b2ae30ea9 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataStreamGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedDataStreamGenerator.java @@ -186,21 +186,16 @@ public OutputStream open( // // TODO signedAttrs must be present for all signers // } - // // ContentInfo - // BERSequenceGenerator sGen = new BERSequenceGenerator(out); - sGen.addObject(CMSObjectIdentifiers.signedData); - // - // Signed Data - // + // SignedData BERSequenceGenerator sigGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true); - sigGen.addObject(calculateVersion(eContentType)); Set digestAlgs = new HashSet(); + digestAlgs.addAll(extraDigestAlgorithms); // // add the precalculated SignerInfo digest algorithms. @@ -219,27 +214,28 @@ public OutputStream open( for (Iterator it = signerGens.iterator(); it.hasNext();) { SignerInfoGenerator signerGen = (SignerInfoGenerator)it.next(); - - digestAlgs.add(signerGen.getDigestAlgorithm()); + digestAlgs.add(CMSSignedHelper.INSTANCE.fixDigestAlgID(signerGen.getDigestAlgorithm(), digestAlgIdFinder)); } - sigGen.getRawOutputStream().write(CMSUtils.convertToDlSet(digestAlgs).getEncoded()); - - BERSequenceGenerator eiGen = new BERSequenceGenerator(sigGen.getRawOutputStream()); - eiGen.addObject(eContentType); - // If encapsulating, add the data as an octet string in the sequence - OutputStream encapStream = encapsulate - ? CMSUtils.createBEROctetOutputStream(eiGen.getRawOutputStream(), 0, true, _bufferSize) + sigGen.addObject(CMSUtils.convertToDlSet(digestAlgs)); + + // EncapsulatedContentInfo + BERSequenceGenerator eciGen = new BERSequenceGenerator(sigGen.getRawOutputStream()); + eciGen.addObject(eContentType); + + // eContent [0] EXPLICIT OCTET STRING OPTIONAL + OutputStream ecStream = encapsulate + ? CMSUtils.createBEROctetOutputStream(eciGen.getRawOutputStream(), 0, true, _bufferSize) : null; // Also send the data to 'dataOutputStream' if necessary - OutputStream contentStream = CMSUtils.getSafeTeeOutputStream(dataOutputStream, encapStream); + OutputStream contentStream = CMSUtils.getSafeTeeOutputStream(dataOutputStream, ecStream); // Let all the signers see the data as it is written OutputStream sigStream = CMSUtils.attachSignersToOutputStream(signerGens, contentStream); - return new CmsSignedDataOutputStream(sigStream, eContentType, sGen, sigGen, eiGen); + return new CmsSignedDataOutputStream(sigStream, eContentType, sGen, sigGen, eciGen); } /** @@ -329,7 +325,7 @@ else if (tagged.getTagNo() == 3) if (otherCert) { - return new ASN1Integer(5); + return ASN1Integer.FIVE; } if (crls != null) // no need to check if otherCert is true @@ -346,39 +342,39 @@ else if (tagged.getTagNo() == 3) if (otherCrl) { - return new ASN1Integer(5); + return ASN1Integer.FIVE; } if (attrCertV2Found) { - return new ASN1Integer(4); + return ASN1Integer.FOUR; } if (attrCertV1Found) { - return new ASN1Integer(3); + return ASN1Integer.THREE; } if (checkForVersion3(_signers, signerGens)) { - return new ASN1Integer(3); + return ASN1Integer.THREE; } if (!CMSObjectIdentifiers.data.equals(contentOid)) { - return new ASN1Integer(3); + return ASN1Integer.THREE; } - return new ASN1Integer(1); + return ASN1Integer.ONE; } - private boolean checkForVersion3(List signerInfos, List signerInfoGens) + private static boolean checkForVersion3(List signerInfos, List signerInfoGens) { for (Iterator it = signerInfos.iterator(); it.hasNext();) { - SignerInfo s = SignerInfo.getInstance(((SignerInformation)it.next()).toASN1Structure()); + SignerInfo s = ((SignerInformation)it.next()).toASN1Structure(); - if (s.getVersion().intValueExact() == 3) + if (s.getVersion().hasValue(3)) { return true; } @@ -455,14 +451,14 @@ public void close() { ASN1Set certSet = CMSUtils.createBerSetFromList(certs); - _sigGen.getRawOutputStream().write(new BERTaggedObject(false, 0, certSet).getEncoded()); + _sigGen.addObject(new BERTaggedObject(false, 0, certSet)); } if (crls.size() != 0) { ASN1Set crlSet = CMSUtils.createBerSetFromList(crls); - _sigGen.getRawOutputStream().write(new BERTaggedObject(false, 1, crlSet).getEncoded()); + _sigGen.addObject(new BERTaggedObject(false, 1, crlSet)); } // @@ -524,8 +520,8 @@ public void close() signerInfos.add(signer.toASN1Structure()); } } - - _sigGen.getRawOutputStream().write(new DERSet(signerInfos).getEncoded()); + + _sigGen.addObject(new DERSet(signerInfos)); _sigGen.close(); _sGen.close(); diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedGenerator.java index 36b4c4529f..161d20e588 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSSignedGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSSignedGenerator.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -90,6 +91,8 @@ public class CMSSignedGenerator protected DigestAlgorithmIdentifierFinder digestAlgIdFinder; + protected Set extraDigestAlgorithms = new LinkedHashSet(); + /** * base constructor */ @@ -251,4 +254,13 @@ public Map getGeneratedDigests() { return new HashMap(digests); } + + /** + * Add extra digest algorithm identifiers to the digest algorithm set in resulting SignedData object. + * @param digestAlgorithmIDs a set of extra digest algorithms + * */ + public void addDigestAlgorithms(Set digestAlgorithmIDs) + { + extraDigestAlgorithms.addAll(digestAlgorithmIDs); + } } diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSUtils.java b/pkix/src/main/java/org/bouncycastle/cms/CMSUtils.java index 80cdb1fa3b..539102c901 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/CMSUtils.java +++ b/pkix/src/main/java/org/bouncycastle/cms/CMSUtils.java @@ -61,18 +61,16 @@ class CMSUtils { - private static final Set des = new HashSet(); + private static final Set desAlgs = new HashSet(); private static final Set mqvAlgs = new HashSet(); private static final Set ecAlgs = new HashSet(); private static final Set gostAlgs = new HashSet(); static { - des.add("DES"); - des.add("DESEDE"); - des.add(OIWObjectIdentifiers.desCBC.getId()); - des.add(PKCSObjectIdentifiers.des_EDE3_CBC.getId()); - des.add(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId()); + desAlgs.add(OIWObjectIdentifiers.desCBC); + desAlgs.add(PKCSObjectIdentifiers.des_EDE3_CBC); + desAlgs.add(PKCSObjectIdentifiers.id_alg_CMS3DESwrap); mqvAlgs.add(X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme); mqvAlgs.add(SECObjectIdentifiers.mqvSinglePass_sha224kdf_scheme); @@ -113,14 +111,13 @@ static boolean isGOST(ASN1ObjectIdentifier algorithm) static boolean isRFC2631(ASN1ObjectIdentifier algorithm) { - return algorithm.equals(PKCSObjectIdentifiers.id_alg_ESDH) || algorithm.equals(PKCSObjectIdentifiers.id_alg_SSDH); + return PKCSObjectIdentifiers.id_alg_ESDH.equals(algorithm) + || PKCSObjectIdentifiers.id_alg_SSDH.equals(algorithm); } - static boolean isDES(String algorithmID) + static boolean isDES(ASN1ObjectIdentifier algorithm) { - String name = Strings.toUpperCase(algorithmID); - - return des.contains(name); + return desAlgs.contains(algorithm); } static boolean isEquivalent(AlgorithmIdentifier algId1, AlgorithmIdentifier algId2) @@ -422,24 +419,13 @@ static OutputStream getSafeTeeOutputStream(OutputStream s1, s1, s2); } - static EncryptedContentInfo getEncryptedContentInfo(CMSTypedData content, OutputEncryptor contentEncryptor, byte[] encryptedContent) + static EncryptedContentInfo getEncryptedContentInfo(CMSTypedData content, OutputEncryptor contentEncryptor, + ASN1OctetString encryptedContent) { - return getEncryptedContentInfo( - content.getContentType(), - contentEncryptor.getAlgorithmIdentifier(), + return new EncryptedContentInfo(content.getContentType(), contentEncryptor.getAlgorithmIdentifier(), encryptedContent); } - static EncryptedContentInfo getEncryptedContentInfo(ASN1ObjectIdentifier encryptedContentType, AlgorithmIdentifier encAlgId, byte[] encryptedContent) - { - ASN1OctetString encContent = new BEROctetString(encryptedContent); - - return new EncryptedContentInfo( - encryptedContentType, - encAlgId, - encContent); - } - static ASN1EncodableVector getRecipentInfos(GenericKey encKey, List recipientInfoGenerators) throws CMSException { @@ -460,11 +446,11 @@ static void addRecipientInfosToGenerator(ASN1EncodableVector recipientInfos, BER { if (berEncodeRecipientSet) { - authGen.getRawOutputStream().write(new BERSet(recipientInfos).getEncoded()); + new BERSet(recipientInfos).encodeTo(authGen.getRawOutputStream()); } else { - authGen.getRawOutputStream().write(new DERSet(recipientInfos).getEncoded()); + new DERSet(recipientInfos).encodeTo(authGen.getRawOutputStream()); } } @@ -492,7 +478,7 @@ static ASN1Set processAuthAttrSet(CMSAttributeTableGenerator authAttrsGenerator, ASN1Set authenticatedAttrSet = null; if (authAttrsGenerator != null) { - AttributeTable attrTable = authAttrsGenerator.getAttributes(Collections.EMPTY_MAP); + AttributeTable attrTable = authAttrsGenerator.getAttributes(getEmptyParameters()); authenticatedAttrSet = new DERSet(attrTable.toASN1EncodableVector()); encryptor.getAADStream().write(authenticatedAttrSet.getEncoded(ASN1Encoding.DER)); @@ -521,12 +507,12 @@ static AttributeTable getAttributesTable(ASN1SetParser set) static ASN1Set getAttrDLSet(CMSAttributeTableGenerator gen) { - return (gen != null) ? new DLSet(gen.getAttributes(Collections.EMPTY_MAP).toASN1EncodableVector()) : null; + return (gen != null) ? new DLSet(gen.getAttributes(getEmptyParameters()).toASN1EncodableVector()) : null; } static ASN1Set getAttrBERSet(CMSAttributeTableGenerator gen) { - return (gen != null) ? new BERSet(gen.getAttributes(Collections.EMPTY_MAP).toASN1EncodableVector()) : null; + return (gen != null) ? new BERSet(gen.getAttributes(getEmptyParameters()).toASN1EncodableVector()) : null; } static byte[] encodeObj( @@ -540,4 +526,9 @@ static byte[] encodeObj( return null; } + + static Map getEmptyParameters() + { + return Collections.EMPTY_MAP; + } } diff --git a/pkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java index 32e399ca28..677a83aac5 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/DefaultCMSSignatureAlgorithmNameGenerator.java @@ -10,6 +10,7 @@ import org.bouncycastle.asn1.eac.EACObjectIdentifiers; import org.bouncycastle.asn1.edec.EdECObjectIdentifiers; import org.bouncycastle.asn1.gm.GMObjectIdentifiers; +import org.bouncycastle.asn1.iana.IANAObjectIdentifiers; import org.bouncycastle.asn1.misc.MiscObjectIdentifiers; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; @@ -247,6 +248,25 @@ public DefaultCMSSignatureAlgorithmNameGenerator() addSimpleAlg(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256, "SLH-DSA-SHAKE-256S-WITH-SHAKE256"); addSimpleAlg(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256, "SLH-DSA-SHAKE-256F-WITH-SHAKE256"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, "MLDSA44-RSA2048-PSS-SHA256"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, "MLDSA44-RSA2048-PKCS15-SHA256"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, "MLDSA44-Ed25519-SHA512"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, "MLDSA44-ECDSA-P256-SHA256"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, "MLDSA65-RSA3072-PSS-SHA512"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512, "MLDSA65-RSA3072-PKCS15-SHA512"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, "MLDSA65-RSA4096-PSS-SHA512"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512, "MLDSA65-RSA4096-PKCS15-SHA512"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512, "MLDSA65-ECDSA-P256-SHA512"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512, "MLDSA65-ECDSA-P384-SHA512"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512, "MLDSA65-ECDSA-brainpoolP256r1-SHA512"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, "MLDSA65-Ed25519-SHA512"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512, "MLDSA87-ECDSA-P384-SHA512"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512, "MLDSA87-ECDSA-brainpoolP384r1-SHA512"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256, "MLDSA87-Ed448-SHAKE256"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, "MLDSA87-RSA3072-PSS-SHA512"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, "MLDSA87-RSA4096-PSS-SHA512"); + addSimpleAlg(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512, "MLDSA87-ECDSA-P521-SHA512"); + addSimpleAlg(BCObjectIdentifiers.picnic_signature, "Picnic"); } diff --git a/pkix/src/main/java/org/bouncycastle/cms/KEMRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/KEMRecipientInfoGenerator.java index 7bc013ac70..34c60351ad 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/KEMRecipientInfoGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/KEMRecipientInfoGenerator.java @@ -55,7 +55,7 @@ public final RecipientInfo generate(GenericKey contentEncryptionKey) } return new RecipientInfo(new OtherRecipientInfo(CMSObjectIdentifiers.id_ori_kem, - new KEMRecipientInfo(recipId, wrapper.getAlgorithmIdentifier(), new DEROctetString(wrapper.getEncapsulation()), wrapper.getKdfAlgorithmIdentifier(), new ASN1Integer(wrapper.getKekLength()), null, wrapper.getWrapAlgorithmIdentifier(), + new KEMRecipientInfo(recipId, wrapper.getAlgorithmIdentifier(), new DEROctetString(wrapper.getEncapsulation()), wrapper.getKdfAlgorithmIdentifier(), ASN1Integer.valueOf(wrapper.getKekLength()), null, wrapper.getWrapAlgorithmIdentifier(), new DEROctetString(encryptedKeyBytes)))); } } \ No newline at end of file diff --git a/pkix/src/main/java/org/bouncycastle/cms/KEMRecipientInformation.java b/pkix/src/main/java/org/bouncycastle/cms/KEMRecipientInformation.java index e61ba4cbab..bf9984386c 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/KEMRecipientInformation.java +++ b/pkix/src/main/java/org/bouncycastle/cms/KEMRecipientInformation.java @@ -27,13 +27,13 @@ public class KEMRecipientInformation { ASN1OctetString octs = ASN1OctetString.getInstance(r.getId()); - rid = new KEMRecipientId(octs.getOctets()); // TODO: should be KEM + rid = new KEMRecipientId(octs.getOctets()); } else { IssuerAndSerialNumber iAnds = IssuerAndSerialNumber.getInstance(r.getId()); - rid = new KEMRecipientId(iAnds.getName(), iAnds.getSerialNumber().getValue()); // TODO: + rid = new KEMRecipientId(iAnds.getName(), iAnds.getSerialNumber().getValue()); } } diff --git a/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipientInfoGenerator.java index a7bf36e5d0..009d9d9023 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipientInfoGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/KeyAgreeRecipientInfoGenerator.java @@ -1,6 +1,8 @@ package org.bouncycastle.cms; +import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DEROctetString; @@ -18,64 +20,50 @@ public abstract class KeyAgreeRecipientInfoGenerator implements RecipientInfoGenerator { - private ASN1ObjectIdentifier keyAgreementOID; - private ASN1ObjectIdentifier keyEncryptionOID; - private SubjectPublicKeyInfo originatorKeyInfo; + private final ASN1ObjectIdentifier keyAgreementOID; + private final ASN1ObjectIdentifier keyEncryptionOID; + private final SubjectPublicKeyInfo originatorKeyInfo; - protected KeyAgreeRecipientInfoGenerator(ASN1ObjectIdentifier keyAgreementOID, SubjectPublicKeyInfo originatorKeyInfo, ASN1ObjectIdentifier keyEncryptionOID) + protected KeyAgreeRecipientInfoGenerator(ASN1ObjectIdentifier keyAgreementOID, + SubjectPublicKeyInfo originatorKeyInfo, ASN1ObjectIdentifier keyEncryptionOID) { this.originatorKeyInfo = originatorKeyInfo; this.keyAgreementOID = keyAgreementOID; this.keyEncryptionOID = keyEncryptionOID; } - public RecipientInfo generate(GenericKey contentEncryptionKey) - throws CMSException + public RecipientInfo generate(GenericKey contentEncryptionKey) throws CMSException { - OriginatorIdentifierOrKey originator = new OriginatorIdentifierOrKey( - createOriginatorPublicKey(originatorKeyInfo)); + OriginatorPublicKey originatorPublicKey = createOriginatorPublicKey(originatorKeyInfo); + OriginatorIdentifierOrKey originator = new OriginatorIdentifierOrKey(originatorPublicKey); - AlgorithmIdentifier keyEncAlg; - if (CMSUtils.isDES(keyEncryptionOID.getId()) || keyEncryptionOID.equals(PKCSObjectIdentifiers.id_alg_CMSRC2wrap)) + ASN1Encodable keyEncAlgParams = null; + if (CMSUtils.isDES(keyEncryptionOID) || PKCSObjectIdentifiers.id_alg_CMSRC2wrap.equals(keyEncryptionOID)) { - keyEncAlg = new AlgorithmIdentifier(keyEncryptionOID, DERNull.INSTANCE); + keyEncAlgParams = DERNull.INSTANCE; } else if (CMSUtils.isGOST(keyAgreementOID)) { - keyEncAlg = new AlgorithmIdentifier(keyEncryptionOID, new Gost2814789KeyWrapParameters(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_A_ParamSet)); - } - else - { - keyEncAlg = new AlgorithmIdentifier(keyEncryptionOID); + keyEncAlgParams = new Gost2814789KeyWrapParameters(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_A_ParamSet); } - AlgorithmIdentifier keyAgreeAlg = new AlgorithmIdentifier(keyAgreementOID, keyEncAlg); + AlgorithmIdentifier keyEncAlgorithm = new AlgorithmIdentifier(keyEncryptionOID, keyEncAlgParams); + AlgorithmIdentifier keyAgreeAlgorithm = new AlgorithmIdentifier(keyAgreementOID, keyEncAlgorithm); - ASN1Sequence recipients = generateRecipientEncryptedKeys(keyAgreeAlg, keyEncAlg, contentEncryptionKey); - byte[] userKeyingMaterial = getUserKeyingMaterial(keyAgreeAlg); + ASN1Sequence recipients = generateRecipientEncryptedKeys(keyAgreeAlgorithm, keyEncAlgorithm, contentEncryptionKey); - if (userKeyingMaterial != null) - { - return new RecipientInfo(new KeyAgreeRecipientInfo(originator, new DEROctetString(userKeyingMaterial), - keyAgreeAlg, recipients)); - } - else - { - return new RecipientInfo(new KeyAgreeRecipientInfo(originator, null, keyAgreeAlg, recipients)); - } + ASN1OctetString ukm = DEROctetString.fromContentsOptional(getUserKeyingMaterial(keyAgreeAlgorithm)); + + return new RecipientInfo(new KeyAgreeRecipientInfo(originator, ukm, keyAgreeAlgorithm, recipients)); } protected OriginatorPublicKey createOriginatorPublicKey(SubjectPublicKeyInfo originatorKeyInfo) { - return new OriginatorPublicKey( - originatorKeyInfo.getAlgorithm(), - originatorKeyInfo.getPublicKeyData().getBytes()); + return new OriginatorPublicKey(originatorKeyInfo.getAlgorithm(), originatorKeyInfo.getPublicKeyData()); } - protected abstract ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeAlgorithm, AlgorithmIdentifier keyEncAlgorithm, GenericKey contentEncryptionKey) - throws CMSException; - - protected abstract byte[] getUserKeyingMaterial(AlgorithmIdentifier keyAgreeAlgorithm) - throws CMSException; + protected abstract ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeAlgorithm, + AlgorithmIdentifier keyEncAlgorithm, GenericKey contentEncryptionKey) throws CMSException; -} \ No newline at end of file + protected abstract byte[] getUserKeyingMaterial(AlgorithmIdentifier keyAgreeAlgorithm) throws CMSException; +} diff --git a/pkix/src/main/java/org/bouncycastle/cms/SignerInformation.java b/pkix/src/main/java/org/bouncycastle/cms/SignerInformation.java index b2451b5262..3fdf3ff3bf 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/SignerInformation.java +++ b/pkix/src/main/java/org/bouncycastle/cms/SignerInformation.java @@ -341,6 +341,8 @@ private boolean doVerify( SignerInformationVerifier verifier) throws CMSException { + // TODO[cms] For pure signature algorithms, restrict digest algorithm to permitted set + String encName = CMSSignedHelper.INSTANCE.getEncryptionAlgName(this.getEncryptionAlgOID()); AlgorithmIdentifier realDigestAlgorithm = signedAttributeSet != null ? info.getDigestAlgorithm() : translateBrokenRSAPkcs7(encryptionAlgorithm, info.getDigestAlgorithm()); diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/BcCMSContentEncryptorBuilder.java b/pkix/src/main/java/org/bouncycastle/cms/bc/BcCMSContentEncryptorBuilder.java index 675ce1dce7..4e6f8e83e3 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/BcCMSContentEncryptorBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/cms/bc/BcCMSContentEncryptorBuilder.java @@ -73,14 +73,59 @@ public BcCMSContentEncryptorBuilder setSecureRandom(SecureRandom random) return this; } + /** + * Build the OutputEncryptor with an internally generated key. + * + * @return an OutputEncryptor configured to use an internal key. + * @throws CMSException + */ public OutputEncryptor build() throws CMSException { + if (random == null) + { + random = new SecureRandom(); + } + + CipherKeyGenerator keyGen = helper.createKeyGenerator(encryptionOID, keySize, random); + + return build(keyGen.generateKey()); + } + + /** + * Build the OutputEncryptor using a pre-generated key. + * + * @param rawEncKey a raw byte encoding of the key to be used for encryption. + * @return an OutputEncryptor configured to use rawEncKey. + * @throws CMSException + */ + public OutputEncryptor build(byte[] rawEncKey) + throws CMSException + { + if (random == null) + { + random = new SecureRandom(); + } + + // fixed key size defined + if (this.keySize > 0) + { + if (((this.keySize + 7) / 8) != rawEncKey.length) + { + if ((this.keySize != 56 && rawEncKey.length != 8) + && (this.keySize != 168 && rawEncKey.length != 24)) + { + throw new IllegalArgumentException("attempt to create encryptor with the wrong sized key"); + } + } + } + if (helper.isAuthEnveloped(encryptionOID)) { - return new CMSAuthOutputEncryptor(encryptionOID, keySize, random); + return new CMSAuthOutputEncryptor(encryptionOID, new KeyParameter(rawEncKey), random); } - return new CMSOutputEncryptor(encryptionOID, keySize, random); + + return new CMSOutputEncryptor(encryptionOID, new KeyParameter(rawEncKey), random); } private class CMSOutputEncryptor @@ -90,21 +135,12 @@ private class CMSOutputEncryptor private AlgorithmIdentifier algorithmIdentifier; protected Object cipher; - CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random) + CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, KeyParameter encKey, SecureRandom random) throws CMSException { - if (random == null) - { - random = new SecureRandom(); - } - - CipherKeyGenerator keyGen = helper.createKeyGenerator(encryptionOID, keySize, random); - - encKey = new KeyParameter(keyGen.generateKey()); - - algorithmIdentifier = helper.generateEncryptionAlgID(encryptionOID, encKey, random); - - cipher = EnvelopedDataHelper.createContentCipher(true, encKey, algorithmIdentifier); + this.algorithmIdentifier = helper.generateEncryptionAlgID(encryptionOID, encKey, random); + this.encKey = encKey; + this.cipher = EnvelopedDataHelper.createContentCipher(true, encKey, algorithmIdentifier); } public AlgorithmIdentifier getAlgorithmIdentifier() @@ -130,10 +166,10 @@ private class CMSAuthOutputEncryptor private AEADBlockCipher aeadCipher; private MacCaptureStream macOut; - CMSAuthOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random) + CMSAuthOutputEncryptor(ASN1ObjectIdentifier encryptionOID, KeyParameter encKey, SecureRandom random) throws CMSException { - super(encryptionOID, keySize, random); + super(encryptionOID, encKey, random); aeadCipher = getCipher(); } diff --git a/pkix/src/main/java/org/bouncycastle/cms/bc/EnvelopedDataHelper.java b/pkix/src/main/java/org/bouncycastle/cms/bc/EnvelopedDataHelper.java index 987b38b2df..bb6dbd4ffd 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/bc/EnvelopedDataHelper.java +++ b/pkix/src/main/java/org/bouncycastle/cms/bc/EnvelopedDataHelper.java @@ -99,12 +99,13 @@ public ExtendedDigest get(AlgorithmIdentifier digestAlgorithmIdentifier) MAC_ALG_NAMES.put(CMSAlgorithm.AES256_CBC, "AESMac"); MAC_ALG_NAMES.put(CMSAlgorithm.RC2_CBC, "RC2Mac"); - authEnvelopedAlgorithms.add(NISTObjectIdentifiers.id_aes128_GCM); - authEnvelopedAlgorithms.add(NISTObjectIdentifiers.id_aes192_GCM); - authEnvelopedAlgorithms.add(NISTObjectIdentifiers.id_aes256_GCM); - authEnvelopedAlgorithms.add(NISTObjectIdentifiers.id_aes128_CCM); - authEnvelopedAlgorithms.add(NISTObjectIdentifiers.id_aes192_CCM); - authEnvelopedAlgorithms.add(NISTObjectIdentifiers.id_aes256_CCM); + authEnvelopedAlgorithms.add(CMSAlgorithm.AES128_GCM); + authEnvelopedAlgorithms.add(CMSAlgorithm.AES192_GCM); + authEnvelopedAlgorithms.add(CMSAlgorithm.AES256_GCM); + authEnvelopedAlgorithms.add(CMSAlgorithm.AES128_CCM); + authEnvelopedAlgorithms.add(CMSAlgorithm.AES192_CCM); + authEnvelopedAlgorithms.add(CMSAlgorithm.AES256_CCM); + authEnvelopedAlgorithms.add(CMSAlgorithm.ChaCha20Poly1305); } EnvelopedDataHelper() diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/CMSUtils.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/CMSUtils.java index 9d9584f0bd..4d79bec90b 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/CMSUtils.java +++ b/pkix/src/main/java/org/bouncycastle/cms/jcajce/CMSUtils.java @@ -52,6 +52,9 @@ class CMSUtils wrapAlgNames.put(CMSAlgorithm.AES128_WRAP, "AESWRAP"); wrapAlgNames.put(CMSAlgorithm.AES192_WRAP, "AESWRAP"); wrapAlgNames.put(CMSAlgorithm.AES256_WRAP, "AESWRAP"); + wrapAlgNames.put(CMSAlgorithm.AES128_WRAP_PAD, "AES-KWP"); + wrapAlgNames.put(CMSAlgorithm.AES192_WRAP_PAD, "AES-KWP"); + wrapAlgNames.put(CMSAlgorithm.AES256_WRAP_PAD, "AES-KWP"); } static @@ -264,15 +267,15 @@ static Cipher createAsymmetricWrapper(JcaJceHelper helper, ASN1ObjectIdentifier public static int getKekSize(ASN1ObjectIdentifier symWrapAlg) { // TODO: add table - if (symWrapAlg.equals(CMSAlgorithm.AES256_WRAP)) + if (symWrapAlg.equals(CMSAlgorithm.AES256_WRAP) || symWrapAlg.equals(CMSAlgorithm.AES256_WRAP_PAD)) { return 32; } - else if (symWrapAlg.equals(CMSAlgorithm.AES128_WRAP)) + else if (symWrapAlg.equals(CMSAlgorithm.AES128_WRAP) || symWrapAlg.equals(CMSAlgorithm.AES128_WRAP_PAD)) { return 16; } - else if (symWrapAlg.equals(CMSAlgorithm.AES192_WRAP)) + else if (symWrapAlg.equals(CMSAlgorithm.AES192_WRAP) || symWrapAlg.equals(CMSAlgorithm.AES192_WRAP_PAD)) { return 24; } diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java index 65aa3fba4b..b55690dfb4 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java +++ b/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java @@ -41,7 +41,6 @@ import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PBKDF2Params; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.RC2CBCParameter; @@ -110,6 +109,7 @@ 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"); + MAC_ALG_NAMES.put(CMSAlgorithm.ChaCha20Poly1305, "ChaCha20Poly1305Mac"); PBKDF2_ALG_NAMES.put(PasswordRecipient.PRF.HMacSHA1.getAlgorithmID(), "PBKDF2WITHHMACSHA1"); PBKDF2_ALG_NAMES.put(PasswordRecipient.PRF.HMacSHA224.getAlgorithmID(), "PBKDF2WITHHMACSHA224"); @@ -117,12 +117,13 @@ public class EnvelopedDataHelper PBKDF2_ALG_NAMES.put(PasswordRecipient.PRF.HMacSHA384.getAlgorithmID(), "PBKDF2WITHHMACSHA384"); PBKDF2_ALG_NAMES.put(PasswordRecipient.PRF.HMacSHA512.getAlgorithmID(), "PBKDF2WITHHMACSHA512"); - authEnvelopedAlgorithms.add(NISTObjectIdentifiers.id_aes128_GCM); - authEnvelopedAlgorithms.add(NISTObjectIdentifiers.id_aes192_GCM); - authEnvelopedAlgorithms.add(NISTObjectIdentifiers.id_aes256_GCM); - authEnvelopedAlgorithms.add(NISTObjectIdentifiers.id_aes128_CCM); - authEnvelopedAlgorithms.add(NISTObjectIdentifiers.id_aes192_CCM); - authEnvelopedAlgorithms.add(NISTObjectIdentifiers.id_aes256_CCM); + authEnvelopedAlgorithms.add(CMSAlgorithm.AES128_GCM); + authEnvelopedAlgorithms.add(CMSAlgorithm.AES192_GCM); + authEnvelopedAlgorithms.add(CMSAlgorithm.AES256_GCM); + authEnvelopedAlgorithms.add(CMSAlgorithm.AES128_CCM); + authEnvelopedAlgorithms.add(CMSAlgorithm.AES192_CCM); + authEnvelopedAlgorithms.add(CMSAlgorithm.AES256_CCM); + authEnvelopedAlgorithms.add(CMSAlgorithm.ChaCha20Poly1305); } private static final short[] rc2Table = { @@ -485,7 +486,6 @@ public Object doInJCE() { Mac mac = createMac(macAlgId.getAlgorithm()); ASN1Encodable sParams = macAlgId.getParameters(); - String macAlg = macAlgId.getAlgorithm().getId(); if (sParams != null && !(sParams instanceof ASN1Null)) { diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java index 0a589ecad5..16e57ce274 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcaSimpleSignerInfoVerifierBuilder.java @@ -18,6 +18,7 @@ public class JcaSimpleSignerInfoVerifierBuilder { private Helper helper = new Helper(); + private DigestCalculatorProvider digestCalculatorProvider = null; public JcaSimpleSignerInfoVerifierBuilder setProvider(Provider provider) { @@ -33,22 +34,42 @@ public JcaSimpleSignerInfoVerifierBuilder setProvider(String providerName) return this; } + public JcaSimpleSignerInfoVerifierBuilder setDigestCalculatorProvider(DigestCalculatorProvider digestCalculatorProvider) + { + this.digestCalculatorProvider = digestCalculatorProvider; + + return this; + } + public SignerInformationVerifier build(X509CertificateHolder certHolder) throws OperatorCreationException, CertificateException { - return new SignerInformationVerifier(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), helper.createContentVerifierProvider(certHolder), helper.createDigestCalculatorProvider()); + return new SignerInformationVerifier(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), helper.createContentVerifierProvider(certHolder), getDigestCalculatorProvider()); } public SignerInformationVerifier build(X509Certificate certificate) throws OperatorCreationException { - return new SignerInformationVerifier(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), helper.createContentVerifierProvider(certificate), helper.createDigestCalculatorProvider()); + return new SignerInformationVerifier(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), helper.createContentVerifierProvider(certificate), getDigestCalculatorProvider()); } public SignerInformationVerifier build(PublicKey pubKey) throws OperatorCreationException { - return new SignerInformationVerifier(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), helper.createContentVerifierProvider(pubKey), helper.createDigestCalculatorProvider()); + return new SignerInformationVerifier(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), helper.createContentVerifierProvider(pubKey), getDigestCalculatorProvider()); + } + + private DigestCalculatorProvider getDigestCalculatorProvider() + throws OperatorCreationException + { + if (digestCalculatorProvider != null) + { + return digestCalculatorProvider; + } + else + { + return helper.createDigestCalculatorProvider(); + } } private static class Helper diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java index 91b4ae4047..b19b840800 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java @@ -23,6 +23,7 @@ import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.cms.CMSAlgorithm; import org.bouncycastle.cms.CMSException; import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.digests.SHA256Digest; @@ -180,16 +181,63 @@ public JceCMSContentEncryptorBuilder setAlgorithmParameters(AlgorithmParameters return this; } + /** + * Build the OutputEncryptor with an internally generated key. + * + * @return an OutputEncryptor configured to use an internal key. + * @throws CMSException + */ public OutputEncryptor build() throws CMSException + { + KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID); + + random = CryptoServicesRegistrar.getSecureRandom(random); + + if (keySize < 0) + { + keyGen.init(random); + } + else + { + keyGen.init(keySize, random); + } + + return build(keyGen.generateKey()); + } + + /** + * Build the OutputEncryptor using a pre-generated key given as a raw encoding. + * + * @param rawEncKey a raw byte encoding of the key to be used for encryption. + * @return an OutputEncryptor configured to use rawEncKey. + * @throws CMSException + */ + public OutputEncryptor build(byte[] rawEncKey) + throws CMSException + { + SecretKey encKey = new SecretKeySpec(rawEncKey, helper.getBaseCipherName(encryptionOID)); + + return build(encKey); + } + + /** + * Build the OutputEncryptor using a pre-generated key. + * + * @param encKey a pre-generated key to be used for encryption. + * @return an OutputEncryptor configured to use encKey. + * @throws CMSException + */ + public OutputEncryptor build(SecretKey encKey) + throws CMSException { if (algorithmParameters != null) { if (helper.isAuthEnveloped(encryptionOID)) { - return new CMSAuthOutputEncryptor(kdfAlgorithm, encryptionOID, keySize, algorithmParameters, random); + return new CMSAuthOutputEncryptor(kdfAlgorithm, encryptionOID, encKey, algorithmParameters, random); } - return new CMSOutputEncryptor(kdfAlgorithm, encryptionOID, keySize, algorithmParameters, random); + return new CMSOutputEncryptor(kdfAlgorithm, encryptionOID, encKey, algorithmParameters, random); } if (algorithmIdentifier != null) { @@ -211,9 +259,9 @@ public OutputEncryptor build() if (helper.isAuthEnveloped(encryptionOID)) { - return new CMSAuthOutputEncryptor(kdfAlgorithm, encryptionOID, keySize, algorithmParameters, random); + return new CMSAuthOutputEncryptor(kdfAlgorithm, encryptionOID, encKey, algorithmParameters, random); } - return new CMSOutputEncryptor(kdfAlgorithm, encryptionOID, keySize, algorithmParameters, random); + return new CMSOutputEncryptor(kdfAlgorithm, encryptionOID, encKey, algorithmParameters, random); } private class CMSOutEncryptor @@ -251,24 +299,14 @@ private void applyKdf(ASN1ObjectIdentifier kdfAlgorithm, AlgorithmParameters par algorithmIdentifier = new AlgorithmIdentifier(kdfAlgorithm, algorithmIdentifier); } - protected void init(ASN1ObjectIdentifier kdfAlgorithm, ASN1ObjectIdentifier encryptionOID, int keySize, AlgorithmParameters params, SecureRandom random) + protected void init(ASN1ObjectIdentifier kdfAlgorithm, ASN1ObjectIdentifier encryptionOID, SecretKey encKey, AlgorithmParameters params, SecureRandom random) throws CMSException { - KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID); + this.encKey = encKey; random = CryptoServicesRegistrar.getSecureRandom(random); - if (keySize < 0) - { - keyGen.init(random); - } - else - { - keyGen.init(keySize, random); - } - - cipher = helper.createCipher(encryptionOID); - encKey = keyGen.generateKey(); + this.cipher = helper.createCipher(encryptionOID); if (params == null) { @@ -326,10 +364,10 @@ private class CMSOutputEncryptor extends CMSOutEncryptor implements OutputEncryptor { - CMSOutputEncryptor(ASN1ObjectIdentifier kdfAlgorithm, ASN1ObjectIdentifier encryptionOID, int keySize, AlgorithmParameters params, SecureRandom random) + CMSOutputEncryptor(ASN1ObjectIdentifier kdfAlgorithm, ASN1ObjectIdentifier encryptionOID, SecretKey encKey, AlgorithmParameters params, SecureRandom random) throws CMSException { - init(kdfAlgorithm, encryptionOID, keySize, params, random); + init(kdfAlgorithm, encryptionOID, encKey, params, random); } public AlgorithmIdentifier getAlgorithmIdentifier() @@ -354,10 +392,10 @@ private class CMSAuthOutputEncryptor { private MacCaptureStream macOut; - CMSAuthOutputEncryptor(ASN1ObjectIdentifier kdfAlgorithm, ASN1ObjectIdentifier encryptionOID, int keySize, AlgorithmParameters params, SecureRandom random) + CMSAuthOutputEncryptor(ASN1ObjectIdentifier kdfAlgorithm, ASN1ObjectIdentifier encryptionOID, SecretKey encKey, AlgorithmParameters params, SecureRandom random) throws CMSException { - init(kdfAlgorithm, encryptionOID, keySize, params, random); + init(kdfAlgorithm, encryptionOID, encKey, params, random); } public AlgorithmIdentifier getAlgorithmIdentifier() @@ -376,10 +414,17 @@ public OutputStream getOutputStream(OutputStream dOut) { algId = algorithmIdentifier; } - - // TODO: works for CCM too, but others will follow. - GCMParameters p = GCMParameters.getInstance(algId.getParameters()); - macOut = new MacCaptureStream(dOut, p.getIcvLen()); + + if (CMSAlgorithm.ChaCha20Poly1305.equals(algorithmIdentifier.getAlgorithm())) + { + macOut = new MacCaptureStream(dOut, 16); + } + else + { + // TODO: works for CCM too, but others will follow. + GCMParameters p = GCMParameters.getInstance(algId.getParameters()); + macOut = new MacCaptureStream(dOut, p.getIcvLen()); + } return new CipherOutputStream(macOut, cipher); } diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipient.java index 5c499edeab..c21ec9a0fa 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipient.java +++ b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipient.java @@ -253,8 +253,8 @@ protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, Algor { try { - AlgorithmIdentifier wrapAlg = - AlgorithmIdentifier.getInstance(keyEncryptionAlgorithm.getParameters()); + AlgorithmIdentifier wrapAlgID = AlgorithmIdentifier.getInstance(keyEncryptionAlgorithm.getParameters()); + ASN1ObjectIdentifier wrapAlgOID = wrapAlgID.getAlgorithm(); X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(senderKey.getEncoded()); KeyFactory fact = helper.createKeyFactory(senderKey.getAlgorithm().getAlgorithm()); @@ -262,43 +262,50 @@ protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, Algor try { - SecretKey agreedWrapKey = calculateAgreedWrapKey(keyEncryptionAlgorithm, wrapAlg, - senderPublicKey, userKeyingMaterial, recipientKey, ecc_cms_Generator); + SecretKey agreedWrapKey = calculateAgreedWrapKey(keyEncryptionAlgorithm, wrapAlgID, senderPublicKey, + userKeyingMaterial, recipientKey, ecc_cms_Generator); - if (wrapAlg.getAlgorithm().equals(CryptoProObjectIdentifiers.id_Gost28147_89_None_KeyWrap) - || wrapAlg.getAlgorithm().equals(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_KeyWrap)) + if (CryptoProObjectIdentifiers.id_Gost28147_89_None_KeyWrap.equals(wrapAlgOID) || + CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_KeyWrap.equals(wrapAlgOID)) { Gost2814789EncryptedKey encKey = Gost2814789EncryptedKey.getInstance(encryptedContentEncryptionKey); - Gost2814789KeyWrapParameters wrapParams = Gost2814789KeyWrapParameters.getInstance(wrapAlg.getParameters()); + Gost2814789KeyWrapParameters wrapParams = Gost2814789KeyWrapParameters.getInstance( + wrapAlgID.getParameters()); - Cipher keyCipher = helper.createCipher(wrapAlg.getAlgorithm()); + Cipher keyCipher = helper.createCipher(wrapAlgOID); - keyCipher.init(Cipher.UNWRAP_MODE, agreedWrapKey, new GOST28147WrapParameterSpec(wrapParams.getEncryptionParamSet(), userKeyingMaterial.getOctets())); + keyCipher.init(Cipher.UNWRAP_MODE, agreedWrapKey, + new GOST28147WrapParameterSpec(wrapParams.getEncryptionParamSet(), userKeyingMaterial.getOctets())); - return keyCipher.unwrap(Arrays.concatenate(encKey.getEncryptedKey(), encKey.getMacKey()), helper.getBaseCipherName(contentEncryptionAlgorithm.getAlgorithm()), Cipher.SECRET_KEY); + byte[] wrappedKey = Arrays.concatenate(encKey.getEncryptedKey(), encKey.getMacKey()); + return keyCipher.unwrap(wrappedKey, helper.getBaseCipherName(contentEncryptionAlgorithm.getAlgorithm()), + Cipher.SECRET_KEY); } - return unwrapSessionKey(wrapAlg.getAlgorithm(), agreedWrapKey, contentEncryptionAlgorithm.getAlgorithm(), encryptedContentEncryptionKey); + return unwrapSessionKey(wrapAlgOID, agreedWrapKey, contentEncryptionAlgorithm.getAlgorithm(), + encryptedContentEncryptionKey); } catch (InvalidKeyException e) { // might be a pre-RFC 5753 message if (possibleOldMessages.contains(keyEncryptionAlgorithm.getAlgorithm())) { - SecretKey agreedWrapKey = calculateAgreedWrapKey(keyEncryptionAlgorithm, wrapAlg, + SecretKey agreedWrapKey = calculateAgreedWrapKey(keyEncryptionAlgorithm, wrapAlgID, senderPublicKey, userKeyingMaterial, recipientKey, old_ecc_cms_Generator); - return unwrapSessionKey(wrapAlg.getAlgorithm(), agreedWrapKey, contentEncryptionAlgorithm.getAlgorithm(), encryptedContentEncryptionKey); + return unwrapSessionKey(wrapAlgOID, agreedWrapKey, contentEncryptionAlgorithm.getAlgorithm(), + encryptedContentEncryptionKey); } // one last try - people do actually do this it turns out if (userKeyingMaterial != null) { try { - SecretKey agreedWrapKey = calculateAgreedWrapKey(keyEncryptionAlgorithm, wrapAlg, + SecretKey agreedWrapKey = calculateAgreedWrapKey(keyEncryptionAlgorithm, wrapAlgID, senderPublicKey, userKeyingMaterial, recipientKey, simple_ecc_cmsGenerator); - return unwrapSessionKey(wrapAlg.getAlgorithm(), agreedWrapKey, contentEncryptionAlgorithm.getAlgorithm(), encryptedContentEncryptionKey); + return unwrapSessionKey(wrapAlgOID, agreedWrapKey, contentEncryptionAlgorithm.getAlgorithm(), + encryptedContentEncryptionKey); } catch (InvalidKeyException ex) { diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java index d2dc76a569..c35c6578ec 100644 --- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyAgreeRecipientInfoGenerator.java @@ -146,19 +146,19 @@ public JceKeyAgreeRecipientInfoGenerator addRecipient(byte[] subjectKeyID, Publi return this; } - public ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeAlgorithm, AlgorithmIdentifier keyEncryptionAlgorithm, GenericKey contentEncryptionKey) - throws CMSException + public ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeAlgorithm, + AlgorithmIdentifier keyEncryptionAlgorithm, GenericKey contentEncryptionKey) throws CMSException { if (recipientIDs.isEmpty()) { throw new CMSException("No recipients associated with generator - use addRecipient()"); } - init(keyAgreeAlgorithm.getAlgorithm()); + ASN1ObjectIdentifier keyAgreementOID = keyAgreeAlgorithm.getAlgorithm(); - PrivateKey senderPrivateKey = this.senderPrivateKey; + init(keyAgreementOID); - ASN1ObjectIdentifier keyAgreementOID = keyAgreeAlgorithm.getAlgorithm(); + PrivateKey senderPrivateKey = this.senderPrivateKey; ASN1EncodableVector recipientEncryptedKeys = new ASN1EncodableVector(); for (int i = 0; i != recipientIDs.size(); i++) @@ -169,7 +169,7 @@ public ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeA try { AlgorithmParameterSpec agreementParamSpec; - ASN1ObjectIdentifier keyEncAlg = keyEncryptionAlgorithm.getAlgorithm(); + ASN1ObjectIdentifier keyEncryptionOID = keyEncryptionAlgorithm.getAlgorithm(); if (CMSUtils.isMQV(keyAgreementOID)) { @@ -177,7 +177,8 @@ public ASN1Sequence generateRecipientEncryptedKeys(AlgorithmIdentifier keyAgreeA } else if (CMSUtils.isEC(keyAgreementOID)) { - byte[] ukmKeyingMaterial = ecc_cms_Generator.generateKDFMaterial(keyEncryptionAlgorithm, keySizeProvider.getKeySize(keyEncAlg), userKeyingMaterial); + byte[] ukmKeyingMaterial = ecc_cms_Generator.generateKDFMaterial(keyEncryptionAlgorithm, + keySizeProvider.getKeySize(keyEncryptionOID), userKeyingMaterial); agreementParamSpec = new UserKeyingMaterialSpec(ukmKeyingMaterial); } @@ -217,18 +218,19 @@ else if (CMSUtils.isGOST(keyAgreementOID)) keyAgreement.init(senderPrivateKey, agreementParamSpec, random); keyAgreement.doPhase(recipientPublicKey, true); - SecretKey keyEncryptionKey = keyAgreement.generateSecret(keyEncAlg.getId()); + SecretKey keyEncryptionKey = keyAgreement.generateSecret(keyEncryptionOID.getId()); EnvelopedDataHelper keyWrapHelper = (wrappingHelper != null) ? wrappingHelper : helper; // Wrap the content encryption key with the agreement key - Cipher keyEncryptionCipher = keyWrapHelper.createCipher(keyEncAlg); - ASN1OctetString encryptedKey; + Cipher keyEncryptionCipher = keyWrapHelper.createCipher(keyEncryptionOID); - if (keyEncAlg.equals(CryptoProObjectIdentifiers.id_Gost28147_89_None_KeyWrap) - || keyEncAlg.equals(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_KeyWrap)) + byte[] encryptedKeyOctets; + if (CryptoProObjectIdentifiers.id_Gost28147_89_None_KeyWrap.equals(keyEncryptionOID) || + CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_KeyWrap.equals(keyEncryptionOID)) { - keyEncryptionCipher.init(Cipher.WRAP_MODE, keyEncryptionKey, new GOST28147WrapParameterSpec(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_A_ParamSet, userKeyingMaterial)); + keyEncryptionCipher.init(Cipher.WRAP_MODE, keyEncryptionKey, + new GOST28147WrapParameterSpec(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_A_ParamSet, userKeyingMaterial)); byte[] encKeyBytes = keyEncryptionCipher.wrap(keyWrapHelper.getJceKey(contentEncryptionKey)); @@ -236,18 +238,16 @@ else if (CMSUtils.isGOST(keyAgreementOID)) Arrays.copyOfRange(encKeyBytes, 0, encKeyBytes.length - 4), Arrays.copyOfRange(encKeyBytes, encKeyBytes.length - 4, encKeyBytes.length)); - encryptedKey = new DEROctetString(encKey.getEncoded(ASN1Encoding.DER)); + encryptedKeyOctets = encKey.getEncoded(ASN1Encoding.DER); } else { keyEncryptionCipher.init(Cipher.WRAP_MODE, keyEncryptionKey, random); - byte[] encryptedKeyBytes = keyEncryptionCipher.wrap(keyWrapHelper.getJceKey(contentEncryptionKey)); - - encryptedKey = new DEROctetString(encryptedKeyBytes); + encryptedKeyOctets = keyEncryptionCipher.wrap(keyWrapHelper.getJceKey(contentEncryptionKey)); } - recipientEncryptedKeys.add(new RecipientEncryptedKey(karId, encryptedKey)); + recipientEncryptedKeys.add(new RecipientEncryptedKey(karId, new DEROctetString(encryptedKeyOctets))); } catch (GeneralSecurityException e) { @@ -269,18 +269,14 @@ protected byte[] getUserKeyingMaterial(AlgorithmIdentifier keyAgreeAlg) if (ephemeralKP != null) { - OriginatorPublicKey originatorPublicKey = createOriginatorPublicKey(SubjectPublicKeyInfo.getInstance(ephemeralKP.getPublic().getEncoded())); + OriginatorPublicKey originatorPublicKey = createOriginatorPublicKey( + SubjectPublicKeyInfo.getInstance(ephemeralKP.getPublic().getEncoded())); try { - if (userKeyingMaterial != null) - { - return new MQVuserKeyingMaterial(originatorPublicKey, new DEROctetString(userKeyingMaterial)).getEncoded(); - } - else - { - return new MQVuserKeyingMaterial(originatorPublicKey, null).getEncoded(); - } + ASN1OctetString addedukm = DEROctetString.fromContentsOptional(userKeyingMaterial); + + return new MQVuserKeyingMaterial(originatorPublicKey, addedukm).getEncoded(); } catch (IOException e) { diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordAuthEnvelopedRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordAuthEnvelopedRecipient.java new file mode 100644 index 0000000000..42f2e14297 --- /dev/null +++ b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JcePasswordAuthEnvelopedRecipient.java @@ -0,0 +1,31 @@ +package org.bouncycastle.cms.jcajce; + +import java.security.Key; + +import javax.crypto.Cipher; + +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.cms.CMSException; +import org.bouncycastle.cms.RecipientOperator; + +public class JcePasswordAuthEnvelopedRecipient + extends JcePasswordRecipient +{ + public JcePasswordAuthEnvelopedRecipient(char[] password) + { + super(password); + } + + public RecipientOperator getRecipientOperator(AlgorithmIdentifier keyEncryptionAlgorithm, + final AlgorithmIdentifier contentMacAlgorithm, + byte[] derivedKey, + byte[] encryptedContentEncryptionKey) + throws CMSException + { + Key secretKey = extractSecretKey(keyEncryptionAlgorithm, contentMacAlgorithm, derivedKey, encryptedContentEncryptionKey); + + final Cipher dataCipher = helper.createContentCipher(secretKey, contentMacAlgorithm); + + return new RecipientOperator(new CMSInputAEADDecryptor(contentMacAlgorithm, dataCipher)); + } +} diff --git a/pkix/src/main/java/org/bouncycastle/est/HttpUtil.java b/pkix/src/main/java/org/bouncycastle/est/HttpUtil.java index 9aa187811f..1fbe8694c0 100644 --- a/pkix/src/main/java/org/bouncycastle/est/HttpUtil.java +++ b/pkix/src/main/java/org/bouncycastle/est/HttpUtil.java @@ -173,9 +173,6 @@ private void discard(int i) static class Headers extends HashMap { - private static final String EMPTY = ""; - - public Headers() { super(); @@ -198,7 +195,7 @@ public String getFirstValueOrEmpty(String key) { return j[0]; } - return EMPTY; + return ""; } public String[] getValues(String key) diff --git a/pkix/src/main/java/org/bouncycastle/est/jcajce/JcaJceUtils.java b/pkix/src/main/java/org/bouncycastle/est/jcajce/JcaJceUtils.java index d581c55aea..3f6024e21b 100644 --- a/pkix/src/main/java/org/bouncycastle/est/jcajce/JcaJceUtils.java +++ b/pkix/src/main/java/org/bouncycastle/est/jcajce/JcaJceUtils.java @@ -35,6 +35,7 @@ public class JcaJceUtils { + @SuppressWarnings("TrustAllX509TrustManager") public static X509TrustManager getTrustAllTrustManager() { diff --git a/pkix/src/main/java/org/bouncycastle/est/jcajce/JsseDefaultHostnameAuthorizer.java b/pkix/src/main/java/org/bouncycastle/est/jcajce/JsseDefaultHostnameAuthorizer.java index 17533b341e..f2a4eac7ca 100644 --- a/pkix/src/main/java/org/bouncycastle/est/jcajce/JsseDefaultHostnameAuthorizer.java +++ b/pkix/src/main/java/org/bouncycastle/est/jcajce/JsseDefaultHostnameAuthorizer.java @@ -3,6 +3,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.InetAddress; +import java.net.UnknownHostException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Collection; @@ -13,12 +14,17 @@ import java.util.logging.Logger; import javax.net.ssl.SSLSession; +import javax.security.auth.x500.X500Principal; +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.ASN1String; import org.bouncycastle.asn1.x500.AttributeTypeAndValue; import org.bouncycastle.asn1.x500.RDN; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.est.ESTException; +import org.bouncycastle.util.IPAddress; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; @@ -77,6 +83,17 @@ public boolean verified(String name, SSLSession context) public boolean verify(String name, X509Certificate cert) throws IOException { + if (name == null) + { + throw new NullPointerException("'name' cannot be null"); + } + + boolean foundAnyDNSNames = false; + + boolean nameIsIPv4 = IPAddress.isValidIPv4(name); + boolean nameIsIPv6 = !nameIsIPv4 && IPAddress.isValidIPv6(name); + boolean nameIsIPAddress = nameIsIPv4 || nameIsIPv6; + // // Test against san. // @@ -85,25 +102,59 @@ public boolean verify(String name, X509Certificate cert) Collection n = cert.getSubjectAlternativeNames(); if (n != null) { + InetAddress nameInetAddress = null; + for (Iterator it = n.iterator(); it.hasNext();) { List l = (List)it.next(); - int type = ((Number)l.get(0)).intValue(); + int type = ((Integer)l.get(0)).intValue(); switch (type) { - case 2: - if (isValidNameMatch(name, l.get(1).toString(), knownSuffixes)) + case GeneralName.dNSName: + { + if (!nameIsIPAddress && + isValidNameMatch(name, (String)l.get(1), knownSuffixes)) { return true; } + foundAnyDNSNames = true; break; - case 7: - if (InetAddress.getByName(name).equals(InetAddress.getByName(l.get(1).toString()))) + } + case GeneralName.iPAddress: + { + if (nameIsIPAddress) { - return true; + String ipAddress = (String)l.get(1); + + if (name.equalsIgnoreCase(ipAddress)) + { + return true; + } + + // In case of IPv6 addresses, convert to InetAddress to handle abbreviated forms correctly + if (nameIsIPv6 && IPAddress.isValidIPv6(ipAddress)) + { + try + { + if (nameInetAddress == null) + { + nameInetAddress = InetAddress.getByName(name); + } + if (nameInetAddress.equals(InetAddress.getByName(ipAddress))) + { + return true; + } + } + catch (UnknownHostException e) + { + // Ignore + } + } } break; + } default: + { // ignore, maybe log if (LOG.isLoggable(Level.INFO)) { @@ -121,13 +172,8 @@ public boolean verify(String name, X509Certificate cert) LOG.log(Level.INFO, "ignoring type " + type + " value = " + value); } } + } } - - // - // As we had subject alternative names, we must not attempt to match against the CN. - // - - return false; } } catch (Exception ex) @@ -135,24 +181,33 @@ public boolean verify(String name, X509Certificate cert) throw new ESTException(ex.getMessage(), ex); } + // If we found any DNS names in the subject alternative names, we must not attempt to match against the CN. + if (nameIsIPAddress || foundAnyDNSNames) + { + return false; + } + + X500Principal subject = cert.getSubjectX500Principal(); + // can't match - would need to check subjectAltName - if (cert.getSubjectX500Principal() == null) + if (subject == null) { return false; } // Common Name match only. - RDN[] rdNs = X500Name.getInstance(cert.getSubjectX500Principal().getEncoded()).getRDNs(); - for (int i = rdNs.length - 1; i >= 0; --i) + RDN[] rdns = X500Name.getInstance(subject.getEncoded()).getRDNs(); + for (int i = rdns.length - 1; i >= 0; --i) { - RDN rdn = rdNs[i]; - AttributeTypeAndValue[] typesAndValues = rdn.getTypesAndValues(); + AttributeTypeAndValue[] typesAndValues = rdns[i].getTypesAndValues(); for (int j = 0; j != typesAndValues.length; j++) { - AttributeTypeAndValue atv = typesAndValues[j]; - if (atv.getType().equals(BCStyle.CN)) + AttributeTypeAndValue typeAndValue = typesAndValues[j]; + if (BCStyle.CN.equals(typeAndValue.getType())) { - return isValidNameMatch(name, atv.getValue().toString(), knownSuffixes); + ASN1Primitive commonName = typeAndValue.getValue().toASN1Primitive(); + return commonName instanceof ASN1String + && isValidNameMatch(name, ((ASN1String)commonName).getString(), knownSuffixes); } } } diff --git a/pkix/src/main/java/org/bouncycastle/mime/smime/SMIMESignedWriter.java b/pkix/src/main/java/org/bouncycastle/mime/smime/SMIMESignedWriter.java index 8be6715d53..0cb093cf4a 100644 --- a/pkix/src/main/java/org/bouncycastle/mime/smime/SMIMESignedWriter.java +++ b/pkix/src/main/java/org/bouncycastle/mime/smime/SMIMESignedWriter.java @@ -185,7 +185,7 @@ public SMIMESignedWriter build(OutputStream mimeOut) boundary = generateBoundary(); // handle Content-Type specially - StringBuffer contValue = new StringBuffer(detValues[0]); + StringBuilder contValue = new StringBuilder(detValues[0]); addHashHeader(contValue, sigGen.getDigestAlgorithms()); @@ -208,7 +208,7 @@ public SMIMESignedWriter build(OutputStream mimeOut) } private void addHashHeader( - StringBuffer header, + StringBuilder header, List signers) { int count = 0; @@ -272,7 +272,7 @@ private void addHashHeader( } private void addBoundary( - StringBuffer header, + StringBuilder header, String boundary) { header.append(";\r\n\tboundary=\""); diff --git a/pkix/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java b/pkix/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java index f6deeab2ca..bcc1e5302b 100644 --- a/pkix/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/openssl/MiscPEMGenerator.java @@ -108,9 +108,9 @@ else if (algOID.equals(dsaOids[0]) || algOID.equals(dsaOids[1])) type = "DSA PRIVATE KEY"; DSAParameter p = DSAParameter.getInstance(info.getPrivateKeyAlgorithm().getParameters()); - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(6); - v.add(new ASN1Integer(0)); + v.add(ASN1Integer.ZERO); v.add(new ASN1Integer(p.getP())); v.add(new ASN1Integer(p.getQ())); v.add(new ASN1Integer(p.getG())); diff --git a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java b/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java index d5288df787..0c298faacc 100644 --- a/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/openssl/jcajce/JceOpenSSLPKCS8EncryptorBuilder.java @@ -208,7 +208,7 @@ else if (PEMUtilities.isPKCS12(algOID)) random.nextBytes(salt); v.add(new DEROctetString(salt)); - v.add(new ASN1Integer(iterationCount)); + v.add(ASN1Integer.valueOf(iterationCount)); algID = new AlgorithmIdentifier(algOID, PKCS12PBEParams.getInstance(new DERSequence(v))); diff --git a/pkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java index c70677df51..e48dbeae88 100644 --- a/pkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java +++ b/pkix/src/main/java/org/bouncycastle/operator/DefaultDigestAlgorithmIdentifierFinder.java @@ -14,6 +14,7 @@ import org.bouncycastle.asn1.eac.EACObjectIdentifiers; import org.bouncycastle.asn1.edec.EdECObjectIdentifiers; import org.bouncycastle.asn1.gm.GMObjectIdentifiers; +import org.bouncycastle.asn1.iana.IANAObjectIdentifiers; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; @@ -161,13 +162,32 @@ public class DefaultDigestAlgorithmIdentifierFinder digestOids.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256, NISTObjectIdentifiers.id_shake256); digestOids.put(NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256, NISTObjectIdentifiers.id_shake256); - digestOids.put(NISTObjectIdentifiers.id_ml_dsa_44, NISTObjectIdentifiers.id_shake256); - digestOids.put(NISTObjectIdentifiers.id_ml_dsa_65, NISTObjectIdentifiers.id_shake256); - digestOids.put(NISTObjectIdentifiers.id_ml_dsa_87, NISTObjectIdentifiers.id_shake256); + digestOids.put(NISTObjectIdentifiers.id_ml_dsa_44, NISTObjectIdentifiers.id_sha512); + digestOids.put(NISTObjectIdentifiers.id_ml_dsa_65, NISTObjectIdentifiers.id_sha512); + digestOids.put(NISTObjectIdentifiers.id_ml_dsa_87, NISTObjectIdentifiers.id_sha512); digestOids.put(NISTObjectIdentifiers.id_hash_ml_dsa_44_with_sha512, NISTObjectIdentifiers.id_sha512); digestOids.put(NISTObjectIdentifiers.id_hash_ml_dsa_65_with_sha512, NISTObjectIdentifiers.id_sha512); digestOids.put(NISTObjectIdentifiers.id_hash_ml_dsa_87_with_sha512, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, NISTObjectIdentifiers.id_sha512); + digestOids.put(BCObjectIdentifiers.falcon, NISTObjectIdentifiers.id_shake256); digestOids.put(BCObjectIdentifiers.falcon_512, NISTObjectIdentifiers.id_shake256); digestOids.put(BCObjectIdentifiers.falcon_1024, NISTObjectIdentifiers.id_shake256); @@ -311,7 +331,7 @@ public AlgorithmIdentifier find(AlgorithmIdentifier sigAlgId) return new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256); } - return new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256_len, new ASN1Integer(512)); + return new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256_len, ASN1Integer.valueOf(512)); } ASN1ObjectIdentifier digAlgOid; diff --git a/pkix/src/main/java/org/bouncycastle/operator/DefaultKemEncapsulationLengthProvider.java b/pkix/src/main/java/org/bouncycastle/operator/DefaultKemEncapsulationLengthProvider.java index 9d279ef64d..477cf866a3 100644 --- a/pkix/src/main/java/org/bouncycastle/operator/DefaultKemEncapsulationLengthProvider.java +++ b/pkix/src/main/java/org/bouncycastle/operator/DefaultKemEncapsulationLengthProvider.java @@ -7,8 +7,6 @@ import org.bouncycastle.asn1.bc.BCObjectIdentifiers; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.jcajce.spec.MLKEMParameterSpec; -import org.bouncycastle.pqc.jcajce.spec.NTRUParameterSpec; import org.bouncycastle.util.Integers; /** diff --git a/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java index dab046e35d..9ddc41414f 100644 --- a/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java +++ b/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java @@ -15,6 +15,7 @@ import org.bouncycastle.asn1.eac.EACObjectIdentifiers; import org.bouncycastle.asn1.edec.EdECObjectIdentifiers; import org.bouncycastle.asn1.gm.GMObjectIdentifiers; +import org.bouncycastle.asn1.iana.IANAObjectIdentifiers; import org.bouncycastle.asn1.isara.IsaraObjectIdentifiers; import org.bouncycastle.asn1.misc.MiscObjectIdentifiers; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; @@ -76,14 +77,12 @@ private static RSASSAPSSparams createPSSParams(AlgorithmIdentifier hashAlgId, in return new RSASSAPSSparams( hashAlgId, new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId), - new ASN1Integer(saltSize), - new ASN1Integer(1)); + ASN1Integer.valueOf(saltSize), + RSASSAPSSparams.DEFAULT_TRAILER_FIELD); } static { - addAlgorithm("COMPOSITE", MiscObjectIdentifiers.id_alg_composite); - addAlgorithm("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption); addAlgorithm("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption); addAlgorithm("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption); @@ -309,22 +308,7 @@ private static RSASSAPSSparams createPSSParams(AlgorithmIdentifier hashAlgId, in addAlgorithm("SHA512WITHPICNIC", BCObjectIdentifiers.picnic_with_sha512); addAlgorithm("SHA3-512WITHPICNIC", BCObjectIdentifiers.picnic_with_sha3_512); addAlgorithm("SHAKE256WITHPICNIC", BCObjectIdentifiers.picnic_with_shake256); - - addAlgorithm("MLDSA44-RSA2048-PSS-SHA256", MiscObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256); - addAlgorithm("MLDSA44-RSA2048-PKCS15-SHA256", MiscObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256); - addAlgorithm("MLDSA44-ED25519-SHA512", MiscObjectIdentifiers.id_MLDSA44_Ed25519_SHA512); - addAlgorithm("MLDSA44-ECDSA-P256-SHA256", MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256); - addAlgorithm("MLDSA65-RSA3072-PSS-SHA256", MiscObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA256); - addAlgorithm("MLDSA65-RSA3072-PKCS15-SHA256", MiscObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA256); - addAlgorithm("MLDSA65-RSA4096-PSS-SHA384", MiscObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA384); - addAlgorithm("MLDSA65-RSA4096-PKCS15-SHA384", MiscObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA384); - addAlgorithm("MLDSA65-ECDSA-P384-SHA384", MiscObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA384); - addAlgorithm("MLDSA65-ECDSA-BRAINPOOLP256R1-SHA256", MiscObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA256); - addAlgorithm("MLDSA65-ED25519-SHA512", MiscObjectIdentifiers.id_MLDSA65_Ed25519_SHA512); - addAlgorithm("MLDSA87-ECDSA-P384-SHA384", MiscObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA384); - addAlgorithm("MLDSA87-ECDSA-BRAINPOOLP384R1-SHA384", MiscObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA384); - addAlgorithm("MLDSA87-ED448-SHA512", MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512); - + addAlgorithm("HASHMLDSA44-RSA2048-PSS-SHA256", MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PSS_SHA256); addAlgorithm("HASHMLDSA44-RSA2048-PKCS15-SHA256", MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PKCS15_SHA256); addAlgorithm("HASHMLDSA44-ED25519-SHA512", MiscObjectIdentifiers.id_HashMLDSA44_Ed25519_SHA512); @@ -340,6 +324,25 @@ private static RSASSAPSSparams createPSSParams(AlgorithmIdentifier hashAlgId, in addAlgorithm("HASHMLDSA87-ECDSA-BRAINPOOLP384R1-SHA512", MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_brainpoolP384r1_SHA512); addAlgorithm("HASHMLDSA87-ED448-SHA512", MiscObjectIdentifiers.id_HashMLDSA87_Ed448_SHA512); + addAlgorithm("MLDSA44-RSA2048-PSS-SHA256", IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256); + addAlgorithm("MLDSA44-RSA2048-PKCS15-SHA256", IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256); + addAlgorithm("MLDSA44-ED25519-SHA512", IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512); + addAlgorithm("MLDSA44-ECDSA-P256-SHA256", IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256); + addAlgorithm("MLDSA65-RSA3072-PSS-SHA512", IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512); + addAlgorithm("MLDSA65-RSA3072-PKCS15-SHA512", IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512); + addAlgorithm("MLDSA65-RSA4096-PSS-SHA512", IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512); + addAlgorithm("MLDSA65-RSA4096-PKCS15-SHA512", IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512); + addAlgorithm("MLDSA65-ECDSA-P256-SHA512", IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512); + addAlgorithm("MLDSA65-ECDSA-P384-SHA512", IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512); + addAlgorithm("MLDSA65-ECDSA-BRAINPOOLP256R1-SHA512", IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512); + addAlgorithm("MLDSA65-ED25519-SHA512", IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512); + addAlgorithm("MLDSA87-ECDSA-P384-SHA512", IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512); + addAlgorithm("MLDSA87-ECDSA-BRAINPOOLP384R1-SHA512", IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512); + addAlgorithm("MLDSA87-ED448-SHAKE256", IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256); + addAlgorithm("MLDSA87-RSA4096-PSS-SHA512", IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512); + addAlgorithm("MLDSA87-ECDSA-P521-SHA512", IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512); + addAlgorithm("MLDSA87-RSA3072-PSS-SHA512", IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_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. @@ -535,21 +538,6 @@ private static RSASSAPSSparams createPSSParams(AlgorithmIdentifier hashAlgId, in // // Composite - Draft 13 // - noParams.add(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256); - noParams.add(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256); - noParams.add(MiscObjectIdentifiers.id_MLDSA44_Ed25519_SHA512); - noParams.add(MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256); - noParams.add(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA256); - noParams.add(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA256); - noParams.add(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA384); - noParams.add(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA384); - noParams.add(MiscObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA384); - noParams.add(MiscObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA256); - noParams.add(MiscObjectIdentifiers.id_MLDSA65_Ed25519_SHA512); - noParams.add(MiscObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA384); - noParams.add(MiscObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA384); - noParams.add(MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512); - noParams.add(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PSS_SHA256); noParams.add(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PKCS15_SHA256); noParams.add(MiscObjectIdentifiers.id_HashMLDSA44_Ed25519_SHA512); @@ -565,6 +553,27 @@ private static RSASSAPSSparams createPSSParams(AlgorithmIdentifier hashAlgId, in noParams.add(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_brainpoolP384r1_SHA512); noParams.add(MiscObjectIdentifiers.id_HashMLDSA87_Ed448_SHA512); + // + // ML-DSA Composite version 7 + // + noParams.add(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256); + noParams.add(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256); + noParams.add(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512); + noParams.add(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256); + noParams.add(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512); + noParams.add(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512); + noParams.add(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512); + noParams.add(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512); + noParams.add(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512); + noParams.add(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512); + noParams.add(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512); + noParams.add(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512); + noParams.add(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512); + noParams.add(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512); + noParams.add(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256); + noParams.add(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512); + noParams.add(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512); + noParams.add(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512); // // PKCS 1.5 encrypted algorithms // diff --git a/pkix/src/main/java/org/bouncycastle/operator/DigestCalculator.java b/pkix/src/main/java/org/bouncycastle/operator/DigestCalculator.java index 203e876f31..5648476bb7 100644 --- a/pkix/src/main/java/org/bouncycastle/operator/DigestCalculator.java +++ b/pkix/src/main/java/org/bouncycastle/operator/DigestCalculator.java @@ -2,6 +2,7 @@ import java.io.OutputStream; +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; /** @@ -10,6 +11,9 @@ */ public interface DigestCalculator { + static final AlgorithmIdentifier SHA_256 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256); + static final AlgorithmIdentifier SHA_512 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512); + /** * Return the algorithm identifier representing the digest implemented by * this calculator. diff --git a/pkix/src/main/java/org/bouncycastle/operator/NoSignatureContentSigner.java b/pkix/src/main/java/org/bouncycastle/operator/NoSignatureContentSigner.java new file mode 100644 index 0000000000..7683e5bcdc --- /dev/null +++ b/pkix/src/main/java/org/bouncycastle/operator/NoSignatureContentSigner.java @@ -0,0 +1,47 @@ +package org.bouncycastle.operator; + +import java.io.IOException; +import java.io.OutputStream; + +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; + +/** + * ContentSigner for "Unsigned X.509 Certificates" + */ +public class NoSignatureContentSigner + implements ContentSigner +{ + @Override + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return new AlgorithmIdentifier(X509ObjectIdentifiers.id_alg_unsigned); + } + + @Override + public OutputStream getOutputStream() + { + return new OutputStream() + { + @Override + public void write(byte[] buf, int off, int len) + throws IOException + { + // do nothing + } + + @Override + public void write(int i) + throws IOException + { + // do nothing + } + }; + } + + @Override + public byte[] getSignature() + { + return new byte[0]; + } +} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcHssLmsContentSignerBuilder.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcHssLmsContentSignerBuilder.java new file mode 100644 index 0000000000..ac31c39883 --- /dev/null +++ b/pkix/src/main/java/org/bouncycastle/operator/bc/BcHssLmsContentSignerBuilder.java @@ -0,0 +1,106 @@ +package org.bouncycastle.operator.bc; + +import java.io.ByteArrayOutputStream; + +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.CryptoException; +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.crypto.Signer; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.pqc.crypto.MessageSigner; +import org.bouncycastle.pqc.crypto.lms.HSSPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.lms.HSSPublicKeyParameters; +import org.bouncycastle.pqc.crypto.lms.HSSSigner; +import org.bouncycastle.pqc.crypto.lms.LMSPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.lms.LMSPublicKeyParameters; +import org.bouncycastle.pqc.crypto.lms.LMSSigner; + +/** + * Builder for creating content signers that use the HSS/LMS Hash-Based Signature Algorithm. + * + * Reference: Use of the HSS/LMS Hash-Based Signature Algorithm in the Cryptographic Message Syntax (CMS) + * RFC 9708. + */ +public class BcHssLmsContentSignerBuilder + extends BcContentSignerBuilder +{ + private static final AlgorithmIdentifier sigAlgId = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_alg_hss_lms_hashsig); + + public BcHssLmsContentSignerBuilder() + { + super(sigAlgId, null); + } + + protected Signer createSigner(AlgorithmIdentifier sigAlgId, AlgorithmIdentifier digAlgId) + throws OperatorCreationException + { + return new HssSigner(); + } + + static class HssSigner + implements Signer + { + private MessageSigner signer; + private final ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + public HssSigner() + { + } + + @Override + public void init(boolean forSigning, CipherParameters param) + { + if (param instanceof HSSPublicKeyParameters || param instanceof HSSPrivateKeyParameters) + { + signer = new HSSSigner(); + } + else if (param instanceof LMSPublicKeyParameters || param instanceof LMSPrivateKeyParameters) + { + signer = new LMSSigner(); + } + else + { + throw new IllegalArgumentException("Incorrect Key Parameters"); + } + + signer.init(forSigning, param); + } + + @Override + public void update(byte b) + { + stream.write(b); + } + + @Override + public void update(byte[] in, int off, int len) + { + stream.write(in, off, len); + } + + @Override + public byte[] generateSignature() + throws CryptoException, DataLengthException + { + byte[] msg = stream.toByteArray(); + stream.reset(); + return signer.generateSignature(msg); + } + + @Override + public boolean verifySignature(byte[] signature) + { + byte[] msg = stream.toByteArray(); + stream.reset(); + return signer.verifySignature(msg, signature); + } + + @Override + public void reset() + { + stream.reset(); + } + } +} diff --git a/pkix/src/main/java/org/bouncycastle/operator/bc/BcHssLmsContentVerifierProviderBuilder.java b/pkix/src/main/java/org/bouncycastle/operator/bc/BcHssLmsContentVerifierProviderBuilder.java new file mode 100644 index 0000000000..e552ffa6d8 --- /dev/null +++ b/pkix/src/main/java/org/bouncycastle/operator/bc/BcHssLmsContentVerifierProviderBuilder.java @@ -0,0 +1,37 @@ +package org.bouncycastle.operator.bc; + +import java.io.IOException; + +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.crypto.Signer; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.pqc.crypto.util.PublicKeyFactory; + +/** + * Builder for creating content verifier providers that support the HSS/LMS Hash-Based Signature Algorithm. + * + * Reference: Use of the HSS/LMS Hash-Based Signature Algorithm in the Cryptographic Message Syntax (CMS) + * RFC 9708. + *

    + */ +public class BcHssLmsContentVerifierProviderBuilder + extends BcContentVerifierProviderBuilder +{ + public BcHssLmsContentVerifierProviderBuilder() + { + } + + protected Signer createSigner(AlgorithmIdentifier sigAlgId) + throws OperatorCreationException + { + return new BcHssLmsContentSignerBuilder.HssSigner(); + } + + protected AsymmetricKeyParameter extractKeyParameters(SubjectPublicKeyInfo publicKeyInfo) + throws IOException + { + return PublicKeyFactory.createKey(publicKeyInfo); + } +} diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java index 3e0b121c22..a7c27b642e 100644 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java @@ -58,6 +58,7 @@ public class JcaContentSignerBuilder static { + isAlgIdFromPrivate.add("COMPOSITE"); isAlgIdFromPrivate.add("DILITHIUM"); isAlgIdFromPrivate.add("SPHINCS+"); isAlgIdFromPrivate.add("SPHINCSPlus"); @@ -200,7 +201,7 @@ public ContentSigner build(PrivateKey privateKey) throws OperatorCreationException { //Use this legacy method only for composite private keys (they have that identifier) - if (privateKey instanceof CompositePrivateKey && ((CompositePrivateKey)privateKey).getAlgorithmIdentifier().equals(MiscObjectIdentifiers.id_composite_key)) + if (privateKey instanceof CompositePrivateKey && ((CompositePrivateKey)privateKey).getAlgorithmIdentifier().getAlgorithm().equals(MiscObjectIdentifiers.id_composite_key)) { return buildComposite((CompositePrivateKey)privateKey); } @@ -399,8 +400,8 @@ private static RSASSAPSSparams createPSSParams(PSSParameterSpec pssSpec) return new RSASSAPSSparams( digId, new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, mgfDig), - new ASN1Integer(pssSpec.getSaltLength()), - new ASN1Integer(pssSpec.getTrailerField())); + ASN1Integer.valueOf(pssSpec.getSaltLength()), + ASN1Integer.valueOf(pssSpec.getTrailerField())); } private static ASN1Sequence createCompParams(CompositeAlgorithmSpec compSpec) diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java index 0c28215d3c..b2dc7abe59 100644 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java @@ -144,7 +144,8 @@ public ContentVerifier get(AlgorithmIdentifier algorithm) } //Use this legacy method only for composite public keys (they have that identifier) - if (publicKey instanceof CompositePublicKey && ((CompositePublicKey)publicKey).getAlgorithmIdentifier().equals(MiscObjectIdentifiers.id_composite_key)) + if (publicKey instanceof CompositePublicKey + && ((CompositePublicKey)publicKey).getAlgorithmIdentifier().getAlgorithm().equals(MiscObjectIdentifiers.id_composite_key)) { List keys = ((CompositePublicKey)publicKey).getPublicKeys(); diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java index 4e5e6de399..364086c521 100644 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java +++ b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyUnwrapper.java @@ -97,7 +97,7 @@ public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm { Key sKey = null; - Cipher keyCipher = helper.createAsymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm(), extraMappings); + Cipher keyCipher = helper.createAsymmetricWrapper(this.getAlgorithmIdentifier(), extraMappings); AlgorithmParameters algParams = helper.createAlgorithmParameters(this.getAlgorithmIdentifier()); try diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java index a597e7d5b2..bf9a8884fc 100644 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java +++ b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java @@ -235,7 +235,7 @@ public byte[] generateWrappedKey(GenericKey encryptionKey) } else { - Cipher keyEncryptionCipher = helper.createAsymmetricWrapper(getAlgorithmIdentifier().getAlgorithm(), extraMappings); + Cipher keyEncryptionCipher = helper.createAsymmetricWrapper(getAlgorithmIdentifier(), extraMappings); AlgorithmParameters algParams = null; try diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceKTSKeyUnwrapper.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceKTSKeyUnwrapper.java index 3e1908399a..090d6baa73 100644 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceKTSKeyUnwrapper.java +++ b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceKTSKeyUnwrapper.java @@ -57,7 +57,7 @@ public GenericKey generateUnwrappedKey(AlgorithmIdentifier encryptedKeyAlgorithm throws OperatorException { GenericHybridParameters params = GenericHybridParameters.getInstance(this.getAlgorithmIdentifier().getParameters()); - Cipher keyCipher = helper.createAsymmetricWrapper(this.getAlgorithmIdentifier().getAlgorithm(), extraMappings); + Cipher keyCipher = helper.createAsymmetricWrapper(this.getAlgorithmIdentifier(), extraMappings); String symmetricWrappingAlg = helper.getWrappingAlgorithmName(params.getDem().getAlgorithm()); RsaKemParameters kemParameters = RsaKemParameters.getInstance(params.getKem().getParameters()); int keySizeInBits = kemParameters.getKeyLength().intValue() * 8; diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceKTSKeyWrapper.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceKTSKeyWrapper.java index 63194404f1..7821721c58 100644 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceKTSKeyWrapper.java +++ b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceKTSKeyWrapper.java @@ -77,7 +77,7 @@ public JceKTSKeyWrapper setSecureRandom(SecureRandom random) public byte[] generateWrappedKey(GenericKey encryptionKey) throws OperatorException { - Cipher keyEncryptionCipher = helper.createAsymmetricWrapper(getAlgorithmIdentifier().getAlgorithm(), new HashMap()); + Cipher keyEncryptionCipher = helper.createAsymmetricWrapper(getAlgorithmIdentifier(), new HashMap()); try { diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceSymmetricKeyWrapper.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceSymmetricKeyWrapper.java index 5e9bbee3b6..8fbba69852 100644 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceSymmetricKeyWrapper.java +++ b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JceSymmetricKeyWrapper.java @@ -90,8 +90,7 @@ static AlgorithmIdentifier determineKeyEncAlg(String algorithm, int keySizeInBit } else if (algorithm.startsWith("RC2")) { - return new AlgorithmIdentifier(new ASN1ObjectIdentifier( - "1.2.840.113549.1.9.16.3.7"), new ASN1Integer(58)); + return new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7"), ASN1Integer.valueOf(58)); } else if (algorithm.startsWith("AES") || algorithm.startsWith(NISTObjectIdentifiers.aes.getId())) { diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java index cd6c268dd4..52bedc75ca 100644 --- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java +++ b/pkix/src/main/java/org/bouncycastle/operator/jcajce/OperatorHelper.java @@ -23,15 +23,18 @@ import javax.crypto.Cipher; import javax.crypto.KeyAgreement; +import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1Integer; 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.kisa.KISAObjectIdentifiers; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.RSAESOAEPparams; import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; @@ -43,6 +46,7 @@ import org.bouncycastle.jcajce.util.MessageDigestUtils; import org.bouncycastle.operator.DefaultSignatureNameFinder; import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Integers; class OperatorHelper @@ -52,6 +56,8 @@ class OperatorHelper private static final Map symmetricWrapperAlgNames = new HashMap(); private static final Map symmetricKeyAlgNames = new HashMap(); private static final Map symmetricWrapperKeySizes = new HashMap(); + // ASN1ObjectIdentifier -> OAEPParamsValue + private static final Map oaepParamsMap = new HashMap(); private static DefaultSignatureNameFinder sigFinder = new DefaultSignatureNameFinder(); @@ -99,6 +105,12 @@ class OperatorHelper symmetricKeyAlgNames.put(NISTObjectIdentifiers.id_aes256_CBC, "AES"); symmetricKeyAlgNames.put(PKCSObjectIdentifiers.des_EDE3_CBC, "DESede"); symmetricKeyAlgNames.put(PKCSObjectIdentifiers.RC2_CBC, "RC2"); + + OAEPParamsValue.add(oaepParamsMap, "RSA/ECB/OAEPWithSHA-1AndMGF1Padding", OIWObjectIdentifiers.idSHA1); + OAEPParamsValue.add(oaepParamsMap, "RSA/ECB/OAEPWithSHA-224AndMGF1Padding", NISTObjectIdentifiers.id_sha224); + OAEPParamsValue.add(oaepParamsMap, "RSA/ECB/OAEPWithSHA-256AndMGF1Padding", NISTObjectIdentifiers.id_sha256); + OAEPParamsValue.add(oaepParamsMap, "RSA/ECB/OAEPWithSHA-384AndMGF1Padding", NISTObjectIdentifiers.id_sha384); + OAEPParamsValue.add(oaepParamsMap, "RSA/ECB/OAEPWithSHA-512AndMGF1Padding", NISTObjectIdentifiers.id_sha512); } private JcaJceHelper helper; @@ -185,25 +197,54 @@ KeyAgreement createKeyAgreement(ASN1ObjectIdentifier algorithm) } } - Cipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm, Map extraAlgNames) + Cipher createAsymmetricWrapper(AlgorithmIdentifier algorithmID, Map extraAlgNames) throws OperatorCreationException { + if (algorithmID == null) + { + throw new NullPointerException("'algorithmID' cannot be null"); + } + + ASN1ObjectIdentifier algOID = algorithmID.getAlgorithm(); try { String cipherName = null; - if (!extraAlgNames.isEmpty()) + if (extraAlgNames != null && !extraAlgNames.isEmpty()) { - cipherName = (String)extraAlgNames.get(algorithm); + cipherName = (String)extraAlgNames.get(algOID); } if (cipherName == null) { - cipherName = (String)asymmetricWrapperAlgNames.get(algorithm); + cipherName = (String)asymmetricWrapperAlgNames.get(algOID); } if (cipherName != null) { + if (cipherName.indexOf("OAEPPadding") > 0) + { + try + { + RSAESOAEPparams oaepParams = RSAESOAEPparams.getInstance(algorithmID.getParameters()); + if (oaepParams != null) + { + ASN1ObjectIdentifier digestOID = oaepParams.getHashAlgorithm().getAlgorithm(); + OAEPParamsValue oaepParamsValue = (OAEPParamsValue)oaepParamsMap.get(digestOID); + + // Note that the original pSourceAlgorithm is ignored for this comparison + if (oaepParamsValue != null && oaepParamsValue.matches(oaepParams.withDefaultPSource())) + { + cipherName = oaepParamsValue.getCipherName(); + } + } + } + catch (Exception e) + { + // Ignore + } + } + try { // this is reversed as the Sun policy files now allow unlimited strength RSA @@ -223,11 +264,23 @@ Cipher createAsymmetricWrapper(ASN1ObjectIdentifier algorithm, Map extraAlgNames // Ignore } } + else if (cipherName.indexOf("ECB/OAEPWith") > 0) + { + int start = cipherName.indexOf("ECB"); + try + { + return helper.createCipher(cipherName.substring(0, start) + "NONE" + cipherName.substring(start + 3)); + } + catch (NoSuchAlgorithmException ex) + { + // Ignore + } + } // Ignore } } - return helper.createCipher(algorithm.getId()); + return helper.createCipher(algOID.getId()); } catch (GeneralSecurityException e) { @@ -565,4 +618,52 @@ private boolean notDefaultPSSParams(ASN1Sequence seq) return pssParams.getSaltLength().intValue() != digest.getDigestLength(); } + + private static class OAEPParamsValue + { + static void add(Map oaepParamsMap, String cipherName, ASN1ObjectIdentifier digestOID) + { + try + { + RSAESOAEPparams oaepParams = createOAEPParams(digestOID); + byte[] derEncoding = getDEREncoding(oaepParams); + oaepParamsMap.put(digestOID, new OAEPParamsValue(cipherName, derEncoding)); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + + private String cipherName; + private byte[] derEncoding; + + private OAEPParamsValue(String cipherName, byte[] derEncoding) + { + this.cipherName = cipherName; + this.derEncoding = derEncoding; + } + + String getCipherName() + { + return cipherName; + } + + boolean matches(RSAESOAEPparams oaepParams) throws IOException + { + return Arrays.areEqual(derEncoding, getDEREncoding(oaepParams)); + } + + private static RSAESOAEPparams createOAEPParams(ASN1ObjectIdentifier digestOID) + { + AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(digestOID, DERNull.INSTANCE); + AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgorithm); + return new RSAESOAEPparams(hashAlgorithm, maskGenAlgorithm, RSAESOAEPparams.DEFAULT_P_SOURCE_ALGORITHM); + } + + private static byte[] getDEREncoding(RSAESOAEPparams oaepParams) throws IOException + { + return oaepParams.getEncoded(ASN1Encoding.DER); + } + } } diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12PBMac1CalculatorBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12PBMac1CalculatorBuilder.java index d1deb1445b..bc3480cf46 100644 --- a/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12PBMac1CalculatorBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/pkcs/bc/BcPKCS12PBMac1CalculatorBuilder.java @@ -1,5 +1,7 @@ package org.bouncycastle.pkcs.bc; +import java.io.IOException; + import org.bouncycastle.asn1.pkcs.PBKDF2Params; import org.bouncycastle.asn1.pkcs.PBMAC1Params; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; @@ -8,8 +10,6 @@ import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.pkcs.PKCS12MacCalculatorBuilder; -import java.io.IOException; - public class BcPKCS12PBMac1CalculatorBuilder implements PKCS12MacCalculatorBuilder { @@ -27,7 +27,11 @@ public BcPKCS12PBMac1CalculatorBuilder(PBMAC1Params pbeMacParams) throws IOExcep throw new IOException("Key length must be present when using PBMAC1."); } } - // TODO handle other cases + else + { + // TODO: add scrypt support. + throw new IllegalArgumentException("unrecognised PBKDF"); + } } @Override diff --git a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePBMac1CalculatorBuilder.java b/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePBMac1CalculatorBuilder.java index 2869097e8d..18d47405cb 100644 --- a/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePBMac1CalculatorBuilder.java +++ b/pkix/src/main/java/org/bouncycastle/pkcs/jcajce/JcePBMac1CalculatorBuilder.java @@ -187,6 +187,7 @@ public MacCalculator build(final char[] password) salt = pbeParams.getSalt(); iterationCount = BigIntegers.intValueExact(pbeParams.getIterationCount()); keySize = BigIntegers.intValueExact(pbeParams.getKeyLength()) * 8; + prf = pbeParams.getPrf(); } SecretKeyFactory secFact = helper.createSecretKeyFactory("PBKDF2"); diff --git a/pkix/src/main/java/org/bouncycastle/pkix/jcajce/PKIXCRLUtil.java b/pkix/src/main/java/org/bouncycastle/pkix/jcajce/PKIXCRLUtil.java index 6e55b79cbd..99eec6ba57 100644 --- a/pkix/src/main/java/org/bouncycastle/pkix/jcajce/PKIXCRLUtil.java +++ b/pkix/src/main/java/org/bouncycastle/pkix/jcajce/PKIXCRLUtil.java @@ -7,7 +7,6 @@ import java.security.cert.X509Certificate; import java.util.Date; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Set; @@ -60,9 +59,9 @@ static Set findCRLs(PKIXCRLStoreSelector crlselect, Date validityDate, List cert Set finalSet = new HashSet(); // based on RFC 5280 6.3.3 - for (Iterator it = initialSet.iterator(); it.hasNext();) + for (Object o : initialSet) { - X509CRL crl = (X509CRL)it.next(); + X509CRL crl = (X509CRL)o; Date nextUpdate = crl.getNextUpdate(); if (nextUpdate == null || nextUpdate.after(validityDate)) @@ -90,15 +89,13 @@ static Set findCRLs(PKIXCRLStoreSelector crlselect, Date validityDate, List cert * @param crlStores * a List containing only {@link Store} objects. These are used to search for CRLs */ - private static void findCRLs(HashSet crls, PKIXCRLStoreSelector crlSelect, List crlStores) throws AnnotatedException + private static void findCRLs(Set crls, PKIXCRLStoreSelector crlSelect, List crlStores) throws AnnotatedException { AnnotatedException lastException = null; boolean foundValidStore = false; - Iterator iter = crlStores.iterator(); - while (iter.hasNext()) + for (Object obj : crlStores) { - Object obj = iter.next(); if (obj instanceof Store) { Store store = (Store)obj; diff --git a/pkix/src/main/java/org/bouncycastle/pkix/jcajce/PKIXCertPathReviewer.java b/pkix/src/main/java/org/bouncycastle/pkix/jcajce/PKIXCertPathReviewer.java index 2234ca031e..95548c4d2d 100644 --- a/pkix/src/main/java/org/bouncycastle/pkix/jcajce/PKIXCertPathReviewer.java +++ b/pkix/src/main/java/org/bouncycastle/pkix/jcajce/PKIXCertPathReviewer.java @@ -38,6 +38,7 @@ import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1Enumerated; import org.bouncycastle.asn1.ASN1IA5String; import org.bouncycastle.asn1.ASN1InputStream; @@ -47,7 +48,6 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.x509.AccessDescription; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.AuthorityInformationAccess; @@ -66,6 +66,7 @@ import org.bouncycastle.asn1.x509.qualified.Iso4217CurrencyCode; import org.bouncycastle.asn1.x509.qualified.MonetaryValue; import org.bouncycastle.asn1.x509.qualified.QCStatement; +import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; import org.bouncycastle.pkix.PKIXNameConstraintValidator; import org.bouncycastle.pkix.PKIXNameConstraintValidatorException; import org.bouncycastle.pkix.util.ErrorBundle; @@ -858,11 +859,11 @@ else if (isSelfIssued(cert)) { ErrorBundle msg = createErrorBundle("CertPathReviewer.NoIssuerPublicKey"); // if there is an authority key extension add the serial and issuer of the missing certificate - byte[] akiBytes = cert.getExtensionValue(Extension.authorityKeyIdentifier.getId()); - if (akiBytes != null) + byte[] akiExtValue = cert.getExtensionValue(Extension.authorityKeyIdentifier.getId()); + if (akiExtValue != null) { AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance( - DEROctetString.getInstance(akiBytes).getOctets()); + ASN1OctetString.getInstance(akiExtValue).getOctets()); GeneralNames issuerNames = aki.getAuthorityCertIssuer(); if (issuerNames != null) { @@ -1958,7 +1959,7 @@ private String IPtoString(byte[] ip) } catch (Exception e) { - StringBuffer b = new StringBuffer(); + StringBuilder b = new StringBuilder(); for (int i = 0; i != ip.length; i++) { @@ -2441,25 +2442,25 @@ protected Collection getTrustAnchors(X509Certificate cert, Set trustanchors) thr try { certSelectX509.setSubject(getEncodedIssuerPrincipal(cert).getEncoded()); - byte[] ext = cert.getExtensionValue(Extension.authorityKeyIdentifier.getId()); - if (ext != null) + byte[] akiExtValue = cert.getExtensionValue(Extension.authorityKeyIdentifier.getId()); + if (akiExtValue != null) { - ASN1OctetString oct = (ASN1OctetString)ASN1Primitive.fromByteArray(ext); - AuthorityKeyIdentifier authID = AuthorityKeyIdentifier.getInstance(ASN1Primitive.fromByteArray(oct.getOctets())); + AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance( + JcaX509ExtensionUtils.parseExtensionValue(akiExtValue)); // we ignore key identifier as if set, selector expects parent to have subjectKeyID - BigInteger serial = authID.getAuthorityCertSerialNumber(); + BigInteger serial = aki.getAuthorityCertSerialNumber(); if (serial != null) { - certSelectX509.setSerialNumber(authID.getAuthorityCertSerialNumber()); + certSelectX509.setSerialNumber(aki.getAuthorityCertSerialNumber()); } else { - byte[] keyID = authID.getKeyIdentifier(); - if (keyID != null) + ASN1OctetString keyIdentifier = aki.getKeyIdentifierObject(); + if (keyIdentifier != null) { - certSelectX509.setSubjectKeyIdentifier(new DEROctetString(keyID).getEncoded()); + certSelectX509.setSubjectKeyIdentifier(keyIdentifier.getEncoded(ASN1Encoding.DER)); } } } diff --git a/pkix/src/main/java/org/bouncycastle/pkix/jcajce/RevocationUtilities.java b/pkix/src/main/java/org/bouncycastle/pkix/jcajce/RevocationUtilities.java index 13548619bd..daa23b32b4 100644 --- a/pkix/src/main/java/org/bouncycastle/pkix/jcajce/RevocationUtilities.java +++ b/pkix/src/main/java/org/bouncycastle/pkix/jcajce/RevocationUtilities.java @@ -108,14 +108,11 @@ private static ASN1Primitive getObject(ASN1ObjectIdentifier oid, byte[] ext) thr * @return a Collection of all found {@link X509Certificate} May be empty but never * null. */ - protected static void findCertificates(LinkedHashSet certs, PKIXCertStoreSelector certSelect, List certStores) + protected static void findCertificates(Set certs, PKIXCertStoreSelector certSelect, List certStores) throws AnnotatedException { - Iterator iter = certStores.iterator(); - while (iter.hasNext()) + for (Object obj : certStores) { - Object obj = iter.next(); - if (obj instanceof Store) { Store certStore = (Store)obj; @@ -163,17 +160,17 @@ static List getAdditionalStoresFromCRLDistributionPoint(CRLDistPoi List stores = new ArrayList(); - for (int i = 0; i < dps.length; i++) + for (DistributionPoint dp : dps) { - DistributionPointName dpn = dps[i].getDistributionPoint(); + DistributionPointName dpn = dp.getDistributionPoint(); // look for URIs in fullName if (dpn != null && dpn.getType() == DistributionPointName.FULL_NAME) { GeneralName[] genNames = GeneralNames.getInstance(dpn.getName()).getNames(); - for (int j = 0; j < genNames.length; j++) + for (GeneralName genName : genNames) { - PKIXCRLStore store = namedCRLStoreMap.get(genNames[j]); + PKIXCRLStore store = namedCRLStoreMap.get(genName); if (store != null) { stores.add(store); diff --git a/pkix/src/main/java/org/bouncycastle/pkix/util/LocalizedMessage.java b/pkix/src/main/java/org/bouncycastle/pkix/util/LocalizedMessage.java index 9abedd151c..1b29acb339 100644 --- a/pkix/src/main/java/org/bouncycastle/pkix/util/LocalizedMessage.java +++ b/pkix/src/main/java/org/bouncycastle/pkix/util/LocalizedMessage.java @@ -39,7 +39,7 @@ public class LocalizedMessage * @param id the id of the corresponding bundle in the resource file * @throws NullPointerException if resource or id is null */ - public LocalizedMessage(String resource,String id) throws NullPointerException + public LocalizedMessage(String resource, String id) throws NullPointerException { if (resource == null || id == null) { @@ -59,7 +59,7 @@ public LocalizedMessage(String resource,String id) throws NullPointerException * @throws NullPointerException if resource or id is null * @throws UnsupportedEncodingException if the encoding is not supported */ - public LocalizedMessage(String resource,String id, String encoding) throws NullPointerException, UnsupportedEncodingException + public LocalizedMessage(String resource, String id, String encoding) throws NullPointerException, UnsupportedEncodingException { if (resource == null || id == null) { @@ -126,10 +126,10 @@ public LocalizedMessage(String resource, String id, String encoding, Object[] ar * @param key second part of the entry id * @param loc the used {@link Locale} * @param timezone the used {@link TimeZone} - * @return a Strng containing the localized message + * @return a String containing the localized message * @throws MissingEntryException if the resource file is not available or the entry does not exist. */ - public String getEntry(String key,Locale loc, TimeZone timezone) throws MissingEntryException + public String getEntry(String key, Locale loc, TimeZone timezone) throws MissingEntryException { String entry = id; if (key != null) @@ -204,7 +204,7 @@ protected String addExtraArgs(String msg, Locale locale) { if (extraArgs != null) { - StringBuffer sb = new StringBuffer(msg); + StringBuilder sb = new StringBuilder(msg); Object[] filteredArgs = extraArgs.getFilteredArgs(locale); for (int i = 0; i < filteredArgs.length; i++) { @@ -460,7 +460,7 @@ public void setFilter(Filter filter) public String toString() { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append("Resource: \"").append(resource); sb.append("\" Id: \"").append(id).append("\""); sb.append(" Arguments: ").append(arguments.getArguments().length).append(" normal"); diff --git a/pkix/src/main/java/org/bouncycastle/pkix/util/filter/HTMLFilter.java b/pkix/src/main/java/org/bouncycastle/pkix/util/filter/HTMLFilter.java index dd7bc962da..09cc4f01ee 100644 --- a/pkix/src/main/java/org/bouncycastle/pkix/util/filter/HTMLFilter.java +++ b/pkix/src/main/java/org/bouncycastle/pkix/util/filter/HTMLFilter.java @@ -9,7 +9,7 @@ public class HTMLFilter implements Filter public String doFilter(String input) { - StringBuffer buf = new StringBuffer(input); + StringBuilder buf = new StringBuilder(input); int i = 0; while (i < buf.length()) { diff --git a/pkix/src/main/java/org/bouncycastle/pkix/util/filter/SQLFilter.java b/pkix/src/main/java/org/bouncycastle/pkix/util/filter/SQLFilter.java index 5161fe7fe7..610be6085e 100644 --- a/pkix/src/main/java/org/bouncycastle/pkix/util/filter/SQLFilter.java +++ b/pkix/src/main/java/org/bouncycastle/pkix/util/filter/SQLFilter.java @@ -11,7 +11,7 @@ public class SQLFilter implements Filter public String doFilter(String input) { - StringBuffer buf = new StringBuffer(input); + StringBuilder buf = new StringBuilder(input); int i = 0; while (i < buf.length()) { diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampRequest.java b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampRequest.java index 4152a02fb6..8760188d13 100644 --- a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampRequest.java +++ b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampRequest.java @@ -1,6 +1,5 @@ package org.bouncycastle.tsp; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; @@ -15,6 +14,7 @@ import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.cmp.PKIFailureInfo; +import org.bouncycastle.asn1.tsp.MessageImprint; import org.bouncycastle.asn1.tsp.TimeStampReq; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.Extension; @@ -27,6 +27,40 @@ public class TimeStampRequest { private static Set EMPTY_SET = Collections.unmodifiableSet(new HashSet()); + private static TimeStampReq parseTimeStampReq(byte[] encoding) + throws IOException + { + try + { + return TimeStampReq.getInstance(encoding); + } + catch (ClassCastException e) + { + throw new IOException("malformed request: " + e); + } + catch (IllegalArgumentException e) + { + throw new IOException("malformed request: " + e); + } + } + + private static TimeStampReq parseTimeStampReq(InputStream in) + throws IOException + { + try + { + return TimeStampReq.getInstance(new ASN1InputStream(in).readObject()); + } + catch (ClassCastException e) + { + throw new IOException("malformed request: " + e); + } + catch (IllegalArgumentException e) + { + throw new IOException("malformed request: " + e); + } + } + private TimeStampReq req; private Extensions extensions; @@ -45,7 +79,7 @@ public TimeStampRequest(TimeStampReq req) public TimeStampRequest(byte[] req) throws IOException { - this(new ByteArrayInputStream(req)); + this(parseTimeStampReq(req)); } /** @@ -57,24 +91,12 @@ public TimeStampRequest(byte[] req) public TimeStampRequest(InputStream in) throws IOException { - this(loadRequest(in)); + this(parseTimeStampReq(in)); } - private static TimeStampReq loadRequest(InputStream in) - throws IOException + public TimeStampReq toASN1Structure() { - try - { - return TimeStampReq.getInstance(new ASN1InputStream(in).readObject()); - } - catch (ClassCastException e) - { - throw new IOException("malformed request: " + e); - } - catch (IllegalArgumentException e) - { - throw new IOException("malformed request: " + e); - } + return req; } public int getVersion() @@ -82,6 +104,11 @@ public int getVersion() return req.getVersion().intValueExact(); } + public MessageImprint getMessageImprint() + { + return req.getMessageImprint(); + } + public ASN1ObjectIdentifier getMessageImprintAlgOID() { return req.getMessageImprint().getHashAlgorithm().getAlgorithm(); @@ -152,6 +179,11 @@ public void validate( policies = convert(policies); extensions = convert(extensions); + if (algorithms == null) + { + throw new TSPValidationException("no algorithms associated with request", PKIFailureInfo.badAlg); + } + if (!algorithms.contains(this.getMessageImprintAlgOID())) { throw new TSPValidationException("request contains unknown algorithm", PKIFailureInfo.badAlg); @@ -167,7 +199,7 @@ public void validate( Enumeration en = this.getExtensions().oids(); while(en.hasMoreElements()) { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)en.nextElement(); + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)en.nextElement(); if (!extensions.contains(oid)) { throw new TSPValidationException("request contains unknown extension", PKIFailureInfo.unacceptedExtension); @@ -177,7 +209,7 @@ public void validate( int digestLength = TSPUtil.getDigestLength(this.getMessageImprintAlgOID().getId()); - if (digestLength != this.getMessageImprintDigest().length) + if (digestLength != this.getMessageImprint().getHashedMessageLength()) { throw new TSPValidationException("imprint digest the wrong length", PKIFailureInfo.badDataFormat); } diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampResponse.java b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampResponse.java index 9d399b00a1..f330738653 100644 --- a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampResponse.java +++ b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampResponse.java @@ -1,12 +1,11 @@ package org.bouncycastle.tsp; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.DLSequence; import org.bouncycastle.asn1.cmp.PKIFailureInfo; import org.bouncycastle.asn1.cmp.PKIFreeText; @@ -22,18 +21,50 @@ */ public class TimeStampResponse { - TimeStampResp resp; - TimeStampToken timeStampToken; + private static TimeStampResp parseTimeStampResp(byte[] encoding) + throws IOException, TSPException + { + try + { + return TimeStampResp.getInstance(encoding); + } + catch (IllegalArgumentException e) + { + throw new TSPException("malformed timestamp response: " + e, e); + } + catch (ClassCastException e) + { + throw new TSPException("malformed timestamp response: " + e, e); + } + } + + private static TimeStampResp parseTimeStampResp(InputStream in) + throws IOException, TSPException + { + try + { + return TimeStampResp.getInstance(new ASN1InputStream(in).readObject()); + } + catch (IllegalArgumentException e) + { + throw new TSPException("malformed timestamp response: " + e, e); + } + catch (ClassCastException e) + { + throw new TSPException("malformed timestamp response: " + e, e); + } + } + + private final TimeStampResp resp; + private final TimeStampToken timeStampToken; public TimeStampResponse(TimeStampResp resp) throws TSPException, IOException { this.resp = resp; - - if (resp.getTimeStampToken() != null) - { - timeStampToken = new TimeStampToken(resp.getTimeStampToken()); - } + + ContentInfo timeStampToken = resp.getTimeStampToken(); + this.timeStampToken = timeStampToken == null ? null : new TimeStampToken(timeStampToken); } /** @@ -46,7 +77,7 @@ public TimeStampResponse(TimeStampResp resp) public TimeStampResponse(byte[] resp) throws TSPException, IOException { - this(new ByteArrayInputStream(resp)); + this(parseTimeStampResp(resp)); } /** @@ -59,7 +90,7 @@ public TimeStampResponse(byte[] resp) public TimeStampResponse(InputStream in) throws TSPException, IOException { - this(readTimeStampResp(in)); + this(parseTimeStampResp(in)); } TimeStampResponse(DLSequence dlSequence) @@ -80,45 +111,25 @@ public TimeStampResponse(InputStream in) } } - private static TimeStampResp readTimeStampResp( - InputStream in) - throws IOException, TSPException - { - try - { - return TimeStampResp.getInstance(new ASN1InputStream(in).readObject()); - } - catch (IllegalArgumentException e) - { - throw new TSPException("malformed timestamp response: " + e, e); - } - catch (ClassCastException e) - { - throw new TSPException("malformed timestamp response: " + e, e); - } - } - public int getStatus() { - return resp.getStatus().getStatus().intValue(); + return resp.getStatus().getStatusObject().intValueExact(); } public String getStatusString() { - if (resp.getStatus().getStatusString() != null) + if (resp.getStatus().getStatusString() == null) { - StringBuffer statusStringBuf = new StringBuffer(); - PKIFreeText text = resp.getStatus().getStatusString(); - for (int i = 0; i != text.size(); i++) - { - statusStringBuf.append(text.getStringAtUTF8(i).getString()); - } - return statusStringBuf.toString(); + return null; } - else + + StringBuilder statusStringBuf = new StringBuilder(); + PKIFreeText text = resp.getStatus().getStatusString(); + for (int i = 0; i != text.size(); i++) { - return null; + statusStringBuf.append(text.getStringAtUTF8(i).getString()); } + return statusStringBuf.toString(); } public PKIFailureInfo getFailInfo() @@ -152,7 +163,7 @@ public void validate( if (tok != null) { - TimeStampTokenInfo tstInfo = tok.getTimeStampInfo(); + TimeStampTokenInfo tstInfo = tok.getTimeStampInfo(); if (request.getNonce() != null && !request.getNonce().equals(tstInfo.getNonce())) { @@ -163,17 +174,18 @@ public void validate( { throw new TSPValidationException("time stamp token found in failed request."); } - - if (!Arrays.constantTimeAreEqual(request.getMessageImprintDigest(), tstInfo.getMessageImprintDigest())) - { - throw new TSPValidationException("response for different message imprint digest."); - } - + + // TODO Should be (absent-parameters-flexible) equality of the whole AlgorithmIdentifier? if (!tstInfo.getMessageImprintAlgOID().equals(request.getMessageImprintAlgOID())) { throw new TSPValidationException("response for different message imprint algorithm."); } + if (!Arrays.constantTimeAreEqual(request.getMessageImprintDigest(), tstInfo.getMessageImprintDigest())) + { + throw new TSPValidationException("response for different message imprint digest."); + } + Attribute scV1 = tok.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificate); Attribute scV2 = tok.getSignedAttributes().get(PKCSObjectIdentifiers.id_aa_signingCertificateV2); @@ -216,16 +228,13 @@ public byte[] getEncoded() throws IOException */ public byte[] getEncoded(String encoding) throws IOException { + ASN1Object asn1Object = resp; if (ASN1Encoding.DL.equals(encoding)) { - if (timeStampToken == null) - { - return new DLSequence(resp.getStatus()).getEncoded(encoding); - } - - return new DLSequence(new ASN1Encodable[] { resp.getStatus(), - timeStampToken.toCMSSignedData().toASN1Structure() }).getEncoded(encoding); + asn1Object = timeStampToken == null + ? new DLSequence(resp.getStatus()) + : new DLSequence(resp.getStatus(), timeStampToken.toCMSSignedData().toASN1Structure()); } - return resp.getEncoded(encoding); + return asn1Object.getEncoded(encoding); } } diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampResponseGenerator.java b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampResponseGenerator.java index 05a2e4e261..9c1528936c 100644 --- a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampResponseGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampResponseGenerator.java @@ -122,7 +122,7 @@ private PKIStatusInfo getPKIStatusInfo() { ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new ASN1Integer(status)); + v.add(ASN1Integer.valueOf(status)); if (statusStrings.size() > 0) { diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampToken.java b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampToken.java index 6a7f197aad..d6713cf427 100644 --- a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampToken.java +++ b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampToken.java @@ -195,7 +195,7 @@ public void validate( cOut.write(certHolder.getEncoded()); cOut.close(); - if (!Arrays.constantTimeAreEqual(certID.getCertHash(), calc.getDigest())) + if (!Arrays.constantTimeAreEqual(certID.getCertHashObject().getOctets(), calc.getDigest())) { throw new TSPValidationException("certificate hash does not match certID hash."); } diff --git a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenGenerator.java b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenGenerator.java index e670c194d3..8ea96190e7 100644 --- a/pkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenGenerator.java +++ b/pkix/src/main/java/org/bouncycastle/tsp/TimeStampTokenGenerator.java @@ -32,6 +32,7 @@ import org.bouncycastle.asn1.tsp.Accuracy; import org.bouncycastle.asn1.tsp.MessageImprint; import org.bouncycastle.asn1.tsp.TSTInfo; +import org.bouncycastle.asn1.tsp.TimeStampReq; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.Extensions; import org.bouncycastle.asn1.x509.ExtensionsGenerator; @@ -218,6 +219,7 @@ public AttributeTable getAttributes(Map parameters) } else { + // NB: The ASN.1 default for ESSCertIDv2.hashAlgorithm has absent parameters (rather than NULL) digestAlgID = new AlgorithmIdentifier(digestAlgOid); final ESSCertIDv2 essCertIDv2 = new ESSCertIDv2(digestAlgID, certHash, issuerSerial); @@ -371,8 +373,9 @@ public TimeStampToken generate( Extensions additionalExtensions) throws TSPException { - AlgorithmIdentifier algID = request.getMessageImprintAlgID(); - MessageImprint messageImprint = new MessageImprint(algID, request.getMessageImprintDigest()); + TimeStampReq timeStampReq = request.toASN1Structure(); + + MessageImprint messageImprint = timeStampReq.getMessageImprint(); Accuracy accuracy = null; if (accuracySeconds > 0 || accuracyMillis > 0 || accuracyMicros > 0) @@ -380,19 +383,19 @@ public TimeStampToken generate( ASN1Integer seconds = null; if (accuracySeconds > 0) { - seconds = new ASN1Integer(accuracySeconds); + seconds = ASN1Integer.valueOf(accuracySeconds); } ASN1Integer millis = null; if (accuracyMillis > 0) { - millis = new ASN1Integer(accuracyMillis); + millis = ASN1Integer.valueOf(accuracyMillis); } ASN1Integer micros = null; if (accuracyMicros > 0) { - micros = new ASN1Integer(accuracyMicros); + micros = ASN1Integer.valueOf(accuracyMicros); } accuracy = new Accuracy(seconds, millis, micros); @@ -404,16 +407,12 @@ public TimeStampToken generate( derOrdering = ASN1Boolean.getInstance(ordering); } - ASN1Integer nonce = null; - if (request.getNonce() != null) - { - nonce = new ASN1Integer(request.getNonce()); - } + ASN1Integer nonce = timeStampReq.getNonce(); - ASN1ObjectIdentifier tsaPolicy = tsaPolicyOID; - if (request.getReqPolicy() != null) + ASN1ObjectIdentifier tsaPolicy = timeStampReq.getReqPolicy(); + if (tsaPolicy == null) { - tsaPolicy = request.getReqPolicy(); + tsaPolicy = this.tsaPolicyOID; } Extensions respExtensions = request.getExtensions(); diff --git a/pkix/src/main/jdk1.1/org/bouncycastle/cms/CMSAbsentContent.java b/pkix/src/main/jdk1.1/org/bouncycastle/cms/CMSAbsentContent.java index d23fc8c04e..ac932ff1ee 100644 --- a/pkix/src/main/jdk1.1/org/bouncycastle/cms/CMSAbsentContent.java +++ b/pkix/src/main/jdk1.1/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/pkix/src/main/jdk1.1/org/bouncycastle/cms/CMSProcessableByteArray.java b/pkix/src/main/jdk1.1/org/bouncycastle/cms/CMSProcessableByteArray.java index 8342df21b5..40b22ae000 100644 --- a/pkix/src/main/jdk1.1/org/bouncycastle/cms/CMSProcessableByteArray.java +++ b/pkix/src/main/jdk1.1/org/bouncycastle/cms/CMSProcessableByteArray.java @@ -21,7 +21,7 @@ public class CMSProcessableByteArray public CMSProcessableByteArray( byte[] bytes) { - this(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), bytes); + this(CMSObjectIdentifiers.data, bytes); } public CMSProcessableByteArray( diff --git a/pkix/src/main/jdk1.2/org/bouncycastle/cms/CMSAuthEnvelopedDataStreamGenerator.java b/pkix/src/main/jdk1.2/org/bouncycastle/cms/CMSAuthEnvelopedDataStreamGenerator.java deleted file mode 100644 index bae9303f34..0000000000 --- a/pkix/src/main/jdk1.2/org/bouncycastle/cms/CMSAuthEnvelopedDataStreamGenerator.java +++ /dev/null @@ -1,202 +0,0 @@ -package org.bouncycastle.cms; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Collections; -import java.util.HashMap; - -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.BERSequenceGenerator; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERTaggedObject; -import org.bouncycastle.asn1.cms.AuthenticatedData; -import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.operator.OutputAEADEncryptor; - -public class CMSAuthEnvelopedDataStreamGenerator - extends CMSAuthEnvelopedGenerator -{ - - private int _bufferSize; - private boolean _berEncodeRecipientSet; - - public CMSAuthEnvelopedDataStreamGenerator() - { - - } - - /** - * Set the underlying string size for encapsulated data - * - * @param bufferSize length of octet strings to buffer the data. - */ - public void setBufferSize( - int bufferSize) - { - _bufferSize = bufferSize; - } - - /** - * Use a BER Set to store the recipient information - */ - public void setBEREncodeRecipients( - boolean berEncodeRecipientSet) - { - _berEncodeRecipientSet = berEncodeRecipientSet; - } - - private OutputStream doOpen( - ASN1ObjectIdentifier dataType, - OutputStream out, - OutputAEADEncryptor encryptor) - throws IOException, CMSException - { - ASN1EncodableVector recipientInfos = CMSUtils.getRecipentInfos(encryptor.getKey(), recipientInfoGenerators); - - return open(dataType, out, recipientInfos, encryptor); - } - - protected OutputStream open( - ASN1ObjectIdentifier dataType, - OutputStream out, - ASN1EncodableVector recipientInfos, - OutputAEADEncryptor encryptor) - throws IOException - { - // - // ContentInfo - // - BERSequenceGenerator cGen = new BERSequenceGenerator(out); - - cGen.addObject(CMSObjectIdentifiers.authEnvelopedData); - - // - // Encrypted Data - // - BERSequenceGenerator authEnvGen = new BERSequenceGenerator(cGen.getRawOutputStream(), 0, true); - - authEnvGen.addObject(new ASN1Integer(AuthenticatedData.calculateVersion(originatorInfo))); - - CMSUtils.addOriginatorInfoToGenerator(authEnvGen, originatorInfo); - - CMSUtils.addRecipientInfosToGenerator(recipientInfos, authEnvGen, _berEncodeRecipientSet); - - BERSequenceGenerator eiGen = new BERSequenceGenerator(authEnvGen.getRawOutputStream()); - - eiGen.addObject(dataType); - - AlgorithmIdentifier encAlgId = encryptor.getAlgorithmIdentifier(); - - eiGen.getRawOutputStream().write(encAlgId.getEncoded()); - - OutputStream octetStream = CMSUtils.createBEROctetOutputStream( - eiGen.getRawOutputStream(), 0, true, _bufferSize); - - return new CMSAuthEnvelopedDataOutputStream(encryptor, octetStream, cGen, authEnvGen, eiGen); - } - - protected OutputStream open( - OutputStream out, - ASN1EncodableVector recipientInfos, - OutputAEADEncryptor encryptor) - throws CMSException - { - try - { - return open(CMSObjectIdentifiers.data, out, recipientInfos, encryptor); - } - catch (IOException e) - { - throw new CMSException("exception decoding algorithm parameters.", e); - } - } - - - /** - * generate an enveloped object that contains an CMS Enveloped Data - * object using the given encryptor. - */ - public OutputStream open( - OutputStream out, - OutputAEADEncryptor encryptor) - throws CMSException, IOException - { - return doOpen(new ASN1ObjectIdentifier(CMSObjectIdentifiers.data.getId()), out, encryptor); - } - - private class CMSAuthEnvelopedDataOutputStream - extends OutputStream - { - private final OutputAEADEncryptor _encryptor; - private final OutputStream _cOut; - private final OutputStream _octetStream; - private final BERSequenceGenerator _cGen; - private final BERSequenceGenerator _envGen; - private final BERSequenceGenerator _eiGen; - - public CMSAuthEnvelopedDataOutputStream( - OutputAEADEncryptor encryptor, - OutputStream octetStream, - BERSequenceGenerator cGen, - BERSequenceGenerator envGen, - BERSequenceGenerator eiGen) - { - _encryptor = encryptor; - _octetStream = octetStream; - _cOut = encryptor.getOutputStream(octetStream); - _cGen = cGen; - _envGen = envGen; - _eiGen = eiGen; - } - - public void write( - int b) - throws IOException - { - _cOut.write(b); - } - - public void write( - byte[] bytes, - int off, - int len) - throws IOException - { - _cOut.write(bytes, off, len); - } - - public void write( - byte[] bytes) - throws IOException - { - _cOut.write(bytes); - } - - public void close() - throws IOException - { - ASN1Set authenticatedAttrSet = CMSUtils.processAuthAttrSet(authAttrsGenerator, _encryptor); - - _cOut.close(); - _octetStream.close(); - _eiGen.close(); - - if (authenticatedAttrSet != null) - { - _envGen.addObject(new DERTaggedObject(false, 1, authenticatedAttrSet)); - } - - _envGen.addObject(new DEROctetString(_encryptor.getMAC())); - - CMSUtils.addAttriSetToGenerator(_envGen, unauthAttrsGenerator, 2, new HashMap()); - - _envGen.close(); - _cGen.close(); - } - } - -} diff --git a/pkix/src/main/jdk1.2/org/bouncycastle/cms/CMSUtils.java b/pkix/src/main/jdk1.2/org/bouncycastle/cms/CMSUtils.java index 078864f4f2..196bad58ed 100644 --- a/pkix/src/main/jdk1.2/org/bouncycastle/cms/CMSUtils.java +++ b/pkix/src/main/jdk1.2/org/bouncycastle/cms/CMSUtils.java @@ -5,7 +5,6 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashSet; import java.util.HashMap; import java.util.Iterator; @@ -493,7 +492,7 @@ static ASN1Set processAuthAttrSet(CMSAttributeTableGenerator authAttrsGenerator, ASN1Set authenticatedAttrSet = null; if (authAttrsGenerator != null) { - AttributeTable attrTable = authAttrsGenerator.getAttributes(new HashMap()); + AttributeTable attrTable = authAttrsGenerator.getAttributes(getEmptyParameters()); authenticatedAttrSet = new DERSet(attrTable.toASN1EncodableVector()); encryptor.getAADStream().write(authenticatedAttrSet.getEncoded(ASN1Encoding.DER)); @@ -522,12 +521,12 @@ static AttributeTable getAttributesTable(ASN1SetParser set) static ASN1Set getAttrDLSet(CMSAttributeTableGenerator gen) { - return (gen != null) ? new DLSet(gen.getAttributes(new HashMap()).toASN1EncodableVector()) : null; + return (gen != null) ? new DLSet(gen.getAttributes(getEmptyParameters()).toASN1EncodableVector()) : null; } static ASN1Set getAttrBERSet(CMSAttributeTableGenerator gen) { - return (gen != null) ? new BERSet(gen.getAttributes(new HashMap()).toASN1EncodableVector()) : null; + return (gen != null) ? new BERSet(gen.getAttributes(getEmptyParameters()).toASN1EncodableVector()) : null; } static byte[] encodeObj( @@ -541,4 +540,9 @@ static byte[] encodeObj( return null; } + + static Map getEmptyParameters() + { + return new HashMap(); + } } diff --git a/pkix/src/main/jdk1.4/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java b/pkix/src/main/jdk1.4/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java index abeee40648..013e775b3c 100644 --- a/pkix/src/main/jdk1.4/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java +++ b/pkix/src/main/jdk1.4/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java @@ -1,5 +1,6 @@ package org.bouncycastle.cms.jcajce; +import java.io.IOException; import java.io.OutputStream; import java.security.AccessController; import java.security.AlgorithmParameters; @@ -11,16 +12,23 @@ import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; import org.bouncycastle.asn1.cms.GCMParameters; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.cms.CMSAlgorithm; import org.bouncycastle.cms.CMSException; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.generators.HKDFBytesGenerator; +import org.bouncycastle.crypto.params.HKDFParameters; import org.bouncycastle.jcajce.io.CipherOutputStream; import org.bouncycastle.operator.DefaultSecretKeySizeProvider; import org.bouncycastle.operator.GenericKey; @@ -29,6 +37,7 @@ import org.bouncycastle.operator.OutputEncryptor; import org.bouncycastle.operator.SecretKeySizeProvider; import org.bouncycastle.operator.jcajce.JceGenericKey; +import org.bouncycastle.util.Strings; /** * Builder for the content encryptor in EnvelopedData - used to encrypt the actual transmitted content. @@ -36,6 +45,7 @@ public class JceCMSContentEncryptorBuilder { private static final SecretKeySizeProvider KEY_SIZE_PROVIDER = DefaultSecretKeySizeProvider.INSTANCE; + private static final byte[] hkdfSalt = Strings.toByteArray("The Cryptographic Message Syntax"); private final ASN1ObjectIdentifier encryptionOID; private final int keySize; @@ -44,6 +54,7 @@ public class JceCMSContentEncryptorBuilder private SecureRandom random; private AlgorithmIdentifier algorithmIdentifier; private AlgorithmParameters algorithmParameters; + private ASN1ObjectIdentifier kdfAlgorithm; public JceCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID) { @@ -93,6 +104,31 @@ public JceCMSContentEncryptorBuilder(AlgorithmIdentifier encryptionAlgId) this.algorithmIdentifier = encryptionAlgId; } + public JceCMSContentEncryptorBuilder setEnableSha256HKdf(boolean useSha256Hkdf) + { + if (useSha256Hkdf) + { + // eventually this will be the default. + this.kdfAlgorithm = CMSObjectIdentifiers.id_alg_cek_hkdf_sha256; + } + else + { + if (this.kdfAlgorithm != null) + { + if (this.kdfAlgorithm.equals(CMSObjectIdentifiers.id_alg_cek_hkdf_sha256)) + { + this.kdfAlgorithm = null; + } + else + { + throw new IllegalStateException("SHA256 HKDF not enabled"); + } + } + } + + return this; + } + /** * Set the provider to use for content encryption. * @@ -145,16 +181,63 @@ public JceCMSContentEncryptorBuilder setAlgorithmParameters(AlgorithmParameters return this; } + /** + * Build the OutputEncryptor with an internally generated key. + * + * @return an OutputEncryptor configured to use an internal key. + * @throws CMSException + */ public OutputEncryptor build() throws CMSException + { + KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID); + + random = CryptoServicesRegistrar.getSecureRandom(random); + + if (keySize < 0) + { + keyGen.init(random); + } + else + { + keyGen.init(keySize, random); + } + + return build(keyGen.generateKey()); + } + + /** + * Build the OutputEncryptor using a pre-generated key given as a raw encoding. + * + * @param rawEncKey a raw byte encoding of the key to be used for encryption. + * @return an OutputEncryptor configured to use rawEncKey. + * @throws CMSException + */ + public OutputEncryptor build(byte[] rawEncKey) + throws CMSException + { + SecretKey encKey = new SecretKeySpec(rawEncKey, helper.getBaseCipherName(encryptionOID)); + + return build(encKey); + } + + /** + * Build the OutputEncryptor using a pre-generated key. + * + * @param encKey a pre-generated key to be used for encryption. + * @return an OutputEncryptor configured to use encKey. + * @throws CMSException + */ + public OutputEncryptor build(SecretKey encKey) + throws CMSException { if (algorithmParameters != null) { if (helper.isAuthEnveloped(encryptionOID)) { - return new CMSAuthOutputEncryptor(encryptionOID, keySize, algorithmParameters, random); + return new CMSAuthOutputEncryptor(kdfAlgorithm, encryptionOID, encKey, algorithmParameters, random); } - return new CMSOutputEncryptor(encryptionOID, keySize, algorithmParameters, random); + return new CMSOutputEncryptor(kdfAlgorithm, encryptionOID, encKey, algorithmParameters, random); } if (algorithmIdentifier != null) { @@ -176,61 +259,115 @@ public OutputEncryptor build() if (helper.isAuthEnveloped(encryptionOID)) { - return new CMSAuthOutputEncryptor(encryptionOID, keySize, algorithmParameters, random); + return new CMSAuthOutputEncryptor(kdfAlgorithm, encryptionOID, encKey, algorithmParameters, random); } - return new CMSOutputEncryptor(encryptionOID, keySize, algorithmParameters, random); + return new CMSOutputEncryptor(kdfAlgorithm, encryptionOID, encKey, algorithmParameters, random); } - private class CMSOutputEncryptor - implements OutputEncryptor + private class CMSOutEncryptor { - private SecretKey encKey; - private AlgorithmIdentifier algorithmIdentifier; - private Cipher cipher; + protected SecretKey encKey; + protected AlgorithmIdentifier algorithmIdentifier; + protected Cipher cipher; - CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, AlgorithmParameters params, SecureRandom random) + private void applyKdf(ASN1ObjectIdentifier kdfAlgorithm, AlgorithmParameters params, SecureRandom random) throws CMSException { - KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID); - - random = CryptoServicesRegistrar.getSecureRandom(random); - - if (keySize < 0) + // TODO: at the moment assumes HKDF with SHA256 + HKDFBytesGenerator kdf = new HKDFBytesGenerator(new SHA256Digest()); + byte[] encKeyEncoded = encKey.getEncoded(); + try { - keyGen.init(random); + kdf.init(new HKDFParameters(encKeyEncoded, hkdfSalt, algorithmIdentifier.getEncoded(ASN1Encoding.DER))); } - else + catch (IOException e) { - keyGen.init(keySize, random); + throw new CMSException("unable to encode enc algorithm parameters", e); } - cipher = helper.createCipher(encryptionOID); - encKey = keyGen.generateKey(); - - if (params == null) - { - params = helper.generateParameters(encryptionOID, encKey, random); - } + kdf.generateBytes(encKeyEncoded, 0, encKeyEncoded.length); + SecretKeySpec derivedKey = new SecretKeySpec(encKeyEncoded, encKey.getAlgorithm()); try { - cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random); + cipher.init(Cipher.ENCRYPT_MODE, derivedKey, params, random); } catch (GeneralSecurityException e) { throw new CMSException("unable to initialize cipher: " + e.getMessage(), e); } + algorithmIdentifier = new AlgorithmIdentifier(kdfAlgorithm, algorithmIdentifier); + } + + protected void init(ASN1ObjectIdentifier kdfAlgorithm, ASN1ObjectIdentifier encryptionOID, SecretKey encKey, AlgorithmParameters params, SecureRandom random) + throws CMSException + { + this.encKey = encKey; + + random = CryptoServicesRegistrar.getSecureRandom(random); + + this.cipher = helper.createCipher(encryptionOID); - // - // If params are null we try and second guess on them as some providers don't provide - // algorithm parameter generation explicitly but instead generate them under the hood. - // if (params == null) { + params = helper.generateParameters(encryptionOID, encKey, random); + } + + if (params != null) + { + algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params); + + if (kdfAlgorithm != null) + { + applyKdf(kdfAlgorithm, params, random); + } + else + { + try + { + cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random); + } + catch (GeneralSecurityException e) + { + throw new CMSException("unable to initialize cipher: " + e.getMessage(), e); + } + } + } + else + { + // + // If params are null we try and second guess on them as some providers don't provide + // algorithm parameter generation explicitly but instead generate them under the hood. + // + try + { + cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random); + } + catch (GeneralSecurityException e) + { + throw new CMSException("unable to initialize cipher: " + e.getMessage(), e); + } + params = cipher.getParameters(); + + algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params); + + if (kdfAlgorithm != null) + { + applyKdf(kdfAlgorithm, params, random); + } } + } + } - algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params); + private class CMSOutputEncryptor + extends CMSOutEncryptor + implements OutputEncryptor + { + CMSOutputEncryptor(ASN1ObjectIdentifier kdfAlgorithm, ASN1ObjectIdentifier encryptionOID, SecretKey encKey, AlgorithmParameters params, SecureRandom random) + throws CMSException + { + init(kdfAlgorithm, encryptionOID, encKey, params, random); } public AlgorithmIdentifier getAlgorithmIdentifier() @@ -250,69 +387,44 @@ public GenericKey getKey() } private class CMSAuthOutputEncryptor + extends CMSOutEncryptor implements OutputAEADEncryptor { - private SecretKey encKey; - private AlgorithmIdentifier algorithmIdentifier; - private Cipher cipher; private MacCaptureStream macOut; - CMSAuthOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, AlgorithmParameters params, SecureRandom random) + CMSAuthOutputEncryptor(ASN1ObjectIdentifier kdfAlgorithm, ASN1ObjectIdentifier encryptionOID, SecretKey encKey, AlgorithmParameters params, SecureRandom random) throws CMSException { - KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID); + init(kdfAlgorithm, encryptionOID, encKey, params, random); + } - random = CryptoServicesRegistrar.getSecureRandom(random); + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algorithmIdentifier; + } - if (keySize < 0) + public OutputStream getOutputStream(OutputStream dOut) + { + AlgorithmIdentifier algId; + if (kdfAlgorithm != null) { - keyGen.init(random); + algId = AlgorithmIdentifier.getInstance(algorithmIdentifier.getParameters()); } else { - keyGen.init(keySize, random); - } - - cipher = helper.createCipher(encryptionOID); - encKey = keyGen.generateKey(); - - if (params == null) - { - params = helper.generateParameters(encryptionOID, encKey, random); + algId = algorithmIdentifier; } - try + if (CMSAlgorithm.ChaCha20Poly1305.equals(algorithmIdentifier.getAlgorithm())) { - cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random); + macOut = new MacCaptureStream(dOut, 16); } - catch (GeneralSecurityException e) + else { - throw new CMSException("unable to initialize cipher: " + e.getMessage(), e); + // TODO: works for CCM too, but others will follow. + GCMParameters p = GCMParameters.getInstance(algId.getParameters()); + macOut = new MacCaptureStream(dOut, p.getIcvLen()); } - - // - // If params are null we try and second guess on them as some providers don't provide - // algorithm parameter generation explicitly but instead generate them under the hood. - // - if (params == null) - { - params = cipher.getParameters(); - } - - algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params); - } - - public AlgorithmIdentifier getAlgorithmIdentifier() - { - return algorithmIdentifier; - } - - public OutputStream getOutputStream(OutputStream dOut) - { - // TODO: works for CCM too, but others will follow. - GCMParameters p = GCMParameters.getInstance(algorithmIdentifier.getParameters()); - - macOut = new MacCaptureStream(dOut, p.getIcvLen()); return new CipherOutputStream(macOut, cipher); } @@ -323,7 +435,7 @@ public GenericKey getKey() public OutputStream getAADStream() { - return null; // TODO: could delay cipher init and use old style + return null; // TODO: okay this is awful, we could use AEADParameterSpec for earlier JDKs. } public byte[] getMAC() @@ -331,4 +443,9 @@ public byte[] getMAC() return macOut.getMac(); } } + + private static boolean checkForAEAD() + { + return false; + } } diff --git a/pkix/src/main/jdk1.4/org/bouncycastle/eac/jcajce/JcaPublicKeyConverter.java b/pkix/src/main/jdk1.4/org/bouncycastle/eac/jcajce/JcaPublicKeyConverter.java index f412e8e009..a156d107e3 100644 --- a/pkix/src/main/jdk1.4/org/bouncycastle/eac/jcajce/JcaPublicKeyConverter.java +++ b/pkix/src/main/jdk1.4/org/bouncycastle/eac/jcajce/JcaPublicKeyConverter.java @@ -128,11 +128,13 @@ public PublicKeyDataObject getPublicKeyDataObject(ASN1ObjectIdentifier usage, Pu ECPublicKey pubKey = (ECPublicKey)publicKey; ECParameterSpec params = pubKey.getParameters(); + ECCurve.AbstractFp curve = (ECCurve.AbstractFp)params.getCurve(); + return new ECDSAPublicKey( usage, - ((ECCurve.Fp)params.getCurve()).getQ(), - ((ECFieldElement.Fp)params.getCurve().getA()).toBigInteger(), - ((ECFieldElement.Fp)params.getCurve().getB()).toBigInteger(), + curve.getQ(), + curve.getA().toBigInteger(), + curve.getB().toBigInteger(), params.getG().getEncoded(false), params.getN(), pubKey.getQ().getEncoded(false), diff --git a/pkix/src/main/jdk1.4/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java b/pkix/src/main/jdk1.4/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java index 80e099fe11..0d67eb07a0 100644 --- a/pkix/src/main/jdk1.4/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java +++ b/pkix/src/main/jdk1.4/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java @@ -5,16 +5,32 @@ import java.security.GeneralSecurityException; import java.security.PrivateKey; import java.security.Provider; +import java.security.PublicKey; import java.security.SecureRandom; import java.security.Signature; import java.security.SignatureException; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.PSSParameterSpec; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERBitString; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.misc.MiscObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.jcajce.CompositePrivateKey; +import org.bouncycastle.jcajce.io.OutputStreamFactory; +import org.bouncycastle.jcajce.spec.CompositeAlgorithmSpec; import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; import org.bouncycastle.jcajce.util.NamedJcaJceHelper; import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; @@ -22,28 +38,77 @@ import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; import org.bouncycastle.operator.DigestAlgorithmIdentifierFinder; +import org.bouncycastle.operator.ExtendedContentSigner; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.OperatorStreamException; import org.bouncycastle.operator.RuntimeOperatorException; +import org.bouncycastle.operator.SignatureAlgorithmIdentifierFinder; +import org.bouncycastle.util.Pack; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.io.TeeOutputStream; public class JcaContentSignerBuilder { + private static final Set isAlgIdFromPrivate = new HashSet(); + private static final DefaultSignatureAlgorithmIdentifierFinder SIGNATURE_ALGORITHM_IDENTIFIER_FINDER = new DefaultSignatureAlgorithmIdentifierFinder(); + + static + { + isAlgIdFromPrivate.add("DILITHIUM"); + isAlgIdFromPrivate.add("SPHINCS+"); + isAlgIdFromPrivate.add("SPHINCSPlus"); + isAlgIdFromPrivate.add("ML-DSA"); + isAlgIdFromPrivate.add("SLH-DSA"); + isAlgIdFromPrivate.add("HASH-ML-DSA"); + isAlgIdFromPrivate.add("HASH-SLH-DSA"); + } + + private final String signatureAlgorithm; + private final AlgorithmIdentifier signatureDigestAlgorithm; + private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); private SecureRandom random; - private String signatureAlgorithm; + private AlgorithmIdentifier sigAlgId; private AlgorithmParameterSpec sigAlgSpec; + /** + * Construct a basic content signer where the signature algorithm name + * tells us all we need to know. + * + * @param signatureAlgorithm the signature algorithm we perform. + */ public JcaContentSignerBuilder(String signatureAlgorithm) + { + this(signatureAlgorithm, (AlgorithmIdentifier)null); + } + + /** + * Constructor which includes the digest algorithm identifier used. + *

    + * Some PKIX operations, such as CMS signing, require the digest algorithm used for in the + * signature, this constructor allows the digest algorithm identifier to + * be explicitly specified. + *

    + * + * @param signatureAlgorithm the signature algorithm we perform. + * @param signatureDigestAlgorithmID the public key associated with our private key. + */ + public JcaContentSignerBuilder(String signatureAlgorithm, AlgorithmIdentifier signatureDigestAlgorithmID) { this.signatureAlgorithm = signatureAlgorithm; - this.sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgorithm); - this.sigAlgSpec = null; + this.signatureDigestAlgorithm = signatureDigestAlgorithmID; } public JcaContentSignerBuilder(String signatureAlgorithm, AlgorithmParameterSpec sigParamSpec) + { + this(signatureAlgorithm, sigParamSpec, null); + } + + public JcaContentSignerBuilder(String signatureAlgorithm, AlgorithmParameterSpec sigParamSpec, AlgorithmIdentifier signatureDigestAlgorithmID) { this.signatureAlgorithm = signatureAlgorithm; + this.signatureDigestAlgorithm = signatureDigestAlgorithmID; if (sigParamSpec instanceof PSSParameterSpec) { @@ -51,12 +116,20 @@ public JcaContentSignerBuilder(String signatureAlgorithm, AlgorithmParameterSpec this.sigAlgSpec = pssSpec; this.sigAlgId = new AlgorithmIdentifier( - PKCSObjectIdentifiers.id_RSASSA_PSS, createPSSParams(signatureAlgorithm, pssSpec)); + PKCSObjectIdentifiers.id_RSASSA_PSS, createPSSParams(signatureAlgorithm, pssSpec)); + } + else if (sigParamSpec instanceof CompositeAlgorithmSpec) + { + CompositeAlgorithmSpec compSpec = (CompositeAlgorithmSpec)sigParamSpec; + + this.sigAlgSpec = compSpec; + this.sigAlgId = new AlgorithmIdentifier( + MiscObjectIdentifiers.id_alg_composite, createCompParams(compSpec)); } else { throw new IllegalArgumentException("unknown sigParamSpec: " - + ((sigParamSpec == null) ? "null" : sigParamSpec.getClass().getName())); + + ((sigParamSpec == null) ? "null" : sigParamSpec.getClass().getName())); } } @@ -86,6 +159,11 @@ public ContentSigner build(PrivateKey privateKey) { try { + if (sigAlgSpec == null) + { + this.sigAlgId = getSigAlgId(privateKey); + } + final Signature sig = helper.createSignature(sigAlgId); final AlgorithmIdentifier signatureAlgId = sigAlgId; @@ -131,6 +209,23 @@ public byte[] getSignature() } } + private AlgorithmIdentifier getSigAlgId(PrivateKey privateKey) + { + if (isAlgIdFromPrivate.contains(Strings.toUpperCase(signatureAlgorithm))) + { + AlgorithmIdentifier sigAlgId = SIGNATURE_ALGORITHM_IDENTIFIER_FINDER.find(privateKey.getAlgorithm()); + if (sigAlgId == null) + { + return PrivateKeyInfo.getInstance(privateKey.getEncoded()).getPrivateKeyAlgorithm(); + } + return sigAlgId; + } + else + { + return SIGNATURE_ALGORITHM_IDENTIFIER_FINDER.find(signatureAlgorithm); + } + } + private class SignatureOutputStream extends OutputStream { @@ -190,8 +285,8 @@ byte[] getSignature() private static RSASSAPSSparams createPSSParams(String signatureAlgorithm, PSSParameterSpec pssSpec) { DigestAlgorithmIdentifierFinder digFinder = new DefaultDigestAlgorithmIdentifierFinder(); - AlgorithmIdentifier digId = digFinder.find(signatureAlgorithm.substring(0, signatureAlgorithm.indexOf("w"))); - AlgorithmIdentifier mgfDig = digFinder.find(signatureAlgorithm.substring(0, signatureAlgorithm.indexOf("w"))); + AlgorithmIdentifier digId = digFinder.find(signatureAlgorithm.substring(0, signatureAlgorithm.indexOf("w"))); + AlgorithmIdentifier mgfDig = digFinder.find(signatureAlgorithm.substring(0, signatureAlgorithm.indexOf("w"))); return new RSASSAPSSparams( digId, @@ -199,4 +294,32 @@ private static RSASSAPSSparams createPSSParams(String signatureAlgorithm, PSSPar new ASN1Integer(pssSpec.getSaltLength()), RSASSAPSSparams.DEFAULT_TRAILER_FIELD); } + + private static ASN1Sequence createCompParams(CompositeAlgorithmSpec compSpec) + { + SignatureAlgorithmIdentifierFinder algFinder = new DefaultSignatureAlgorithmIdentifierFinder(); + ASN1EncodableVector v = new ASN1EncodableVector(); + + List algorithmNames = compSpec.getAlgorithmNames(); + List algorithmSpecs = compSpec.getParameterSpecs(); + + for (int i = 0; i != algorithmNames.size(); i++) + { + AlgorithmParameterSpec sigSpec = (AlgorithmParameterSpec)algorithmSpecs.get(i); + if (sigSpec == null) + { + v.add(algFinder.find((String)algorithmNames.get(i))); + } + else if (sigSpec instanceof PSSParameterSpec) + { + v.add(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_RSASSA_PSS, createPSSParams((String)algorithmNames.get(i), (PSSParameterSpec)sigSpec))); + } + else + { + throw new IllegalArgumentException("unrecognized parameterSpec"); + } + } + + return new DERSequence(v); + } } diff --git a/pkix/src/main/jdk1.4/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java b/pkix/src/main/jdk1.4/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java index 82b18e81c3..a023ad648e 100644 --- a/pkix/src/main/jdk1.4/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java +++ b/pkix/src/main/jdk1.4/org/bouncycastle/operator/jcajce/JceAsymmetricKeyWrapper.java @@ -104,7 +104,7 @@ public JceAsymmetricKeyWrapper setAlgorithmMapping(ASN1ObjectIdentifier algorith public byte[] generateWrappedKey(GenericKey encryptionKey) throws OperatorException { - Cipher keyEncryptionCipher = helper.createAsymmetricWrapper(getAlgorithmIdentifier().getAlgorithm(), extraMappings); + Cipher keyEncryptionCipher = helper.createAsymmetricWrapper(getAlgorithmIdentifier(), extraMappings); AlgorithmParameters algParams = helper.createAlgorithmParameters(this.getAlgorithmIdentifier()); byte[] encryptedKeyBytes = null; diff --git a/pkix/src/test/java/org/bouncycastle/cert/cmp/test/AllTests.java b/pkix/src/test/java/org/bouncycastle/cert/cmp/test/AllTests.java index 038320aac4..c7dff3d38e 100644 --- a/pkix/src/test/java/org/bouncycastle/cert/cmp/test/AllTests.java +++ b/pkix/src/test/java/org/bouncycastle/cert/cmp/test/AllTests.java @@ -295,7 +295,7 @@ public void testServerSideKey() CertRepMessage msg = new CertRepMessage(null, new CertResponse[] { new CertResponse( - new ASN1Integer(2), + ASN1Integer.TWO, new PKIStatusInfo(PKIStatus.granted), new CertifiedKeyPair( new CertOrEncCert(CMPCertificate.getInstance(cert.getEncoded())), diff --git a/pkix/src/test/java/org/bouncycastle/cert/cmp/test/PQCTest.java b/pkix/src/test/java/org/bouncycastle/cert/cmp/test/PQCTest.java index 4f0541ba1a..d3cbe90a5b 100644 --- a/pkix/src/test/java/org/bouncycastle/cert/cmp/test/PQCTest.java +++ b/pkix/src/test/java/org/bouncycastle/cert/cmp/test/PQCTest.java @@ -1,18 +1,18 @@ package org.bouncycastle.cert.cmp.test; +import java.io.FileWriter; import java.math.BigInteger; 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.io.FileWriter; import java.util.Arrays; import java.util.Collection; import java.util.Date; import junit.framework.TestCase; -import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.bc.BCObjectIdentifiers; import org.bouncycastle.asn1.cmp.CMPCertificate; @@ -22,7 +22,6 @@ import org.bouncycastle.asn1.crmf.CertTemplate; import org.bouncycastle.asn1.crmf.SubsequentMessage; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.util.ASN1Dump; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.BasicConstraints; @@ -36,6 +35,11 @@ import org.bouncycastle.cert.cmp.CMSProcessableCMPCertificate; import org.bouncycastle.cert.cmp.CertificateConfirmationContent; import org.bouncycastle.cert.cmp.CertificateConfirmationContentBuilder; +import org.bouncycastle.cert.cmp.ChallengeContent; +import org.bouncycastle.cert.cmp.POPODecryptionKeyChallengeContent; +import org.bouncycastle.cert.cmp.POPODecryptionKeyChallengeContentBuilder; +import org.bouncycastle.cert.cmp.POPODecryptionKeyResponseContent; +import org.bouncycastle.cert.cmp.POPODecryptionKeyResponseContentBuilder; import org.bouncycastle.cert.cmp.ProtectedPKIMessage; import org.bouncycastle.cert.cmp.ProtectedPKIMessageBuilder; import org.bouncycastle.cert.crmf.CertificateRepMessage; @@ -59,15 +63,18 @@ import org.bouncycastle.jcajce.spec.MLDSAParameterSpec; import org.bouncycastle.jcajce.spec.MLKEMParameterSpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; +import org.bouncycastle.openssl.jcajce.JcaPEMWriter; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.ContentVerifierProvider; +import org.bouncycastle.operator.DigestCalculator; +import org.bouncycastle.operator.DigestCalculatorProvider; import org.bouncycastle.operator.MacCalculator; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.PBEMacCalculatorProvider; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder; import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; -import org.bouncycastle.openssl.jcajce.JcaPEMWriter; import org.bouncycastle.pkcs.jcajce.JcePBMac1CalculatorBuilder; import org.bouncycastle.pkcs.jcajce.JcePBMac1CalculatorProviderBuilder; import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; @@ -252,6 +259,164 @@ public void testMlKemRequestWithMlDsaCA() assertTrue(recContent.getStatusMessages()[0].isVerified(receivedCert, new JcaDigestCalculatorProviderBuilder().build())); } + public void testMlKemRequestWithMlDsaCADirect() + throws Exception + { + char[] senderMacPassword = "secret".toCharArray(); + GeneralName client = new GeneralName(new X500Name("CN=ML-KEM Subject")); + GeneralName issuerCA = new GeneralName(new X500Name("CN=ML-DSA Issuer")); + + KeyPairGenerator dilKpGen = KeyPairGenerator.getInstance("ML-DSA", "BC"); + + dilKpGen.initialize(MLDSAParameterSpec.ml_dsa_65); + + KeyPair dilKp = dilKpGen.generateKeyPair(); + + X509CertificateHolder caCert = makeV3Certificate("CN=ML-DSA Issuer", dilKp); + + KeyPairGenerator kybKpGen = KeyPairGenerator.getInstance("ML-KEM", "BC"); + + kybKpGen.initialize(MLKEMParameterSpec.ml_kem_768); + + KeyPair mlKemKp = kybKpGen.generateKeyPair(); + + // initial request + + JcaCertificateRequestMessageBuilder certReqBuild = new JcaCertificateRequestMessageBuilder(BigIntegers.ONE); + + certReqBuild + .setPublicKey(mlKemKp.getPublic()) + .setSubject(X500Name.getInstance(client.getName())) + .setProofOfPossessionSubsequentMessage(SubsequentMessage.challengeResp); + + CertificateReqMessagesBuilder certReqMsgsBldr = new CertificateReqMessagesBuilder(); + + certReqMsgsBldr.addRequest(certReqBuild.build()); + + MacCalculator senderMacCalculator = new JcePBMac1CalculatorBuilder("HmacSHA256", 256).setProvider("BC").build(senderMacPassword); + + ProtectedPKIMessage message = new ProtectedPKIMessageBuilder(client, issuerCA) + .setBody(PKIBody.TYPE_INIT_REQ, certReqMsgsBldr.build()) + .build(senderMacCalculator); + + // extract + + assertTrue(message.getProtectionAlgorithm().equals(senderMacCalculator.getAlgorithmIdentifier())); + + PBEMacCalculatorProvider macCalcProvider = new JcePBMac1CalculatorProviderBuilder().setProvider("BC").build(); + + assertTrue(message.verify(macCalcProvider, senderMacPassword)); + + assertEquals(PKIBody.TYPE_INIT_REQ, message.getBody().getType()); + + CertificateReqMessages requestMessages = CertificateReqMessages.fromPKIBody(message.getBody()); + CertificateRequestMessage senderReqMessage = requestMessages.getRequests()[0]; + CertTemplate certTemplate = senderReqMessage.getCertTemplate(); + + SecureRandom rand = new SecureRandom(); + CertificateRepMessageBuilder repMessageBuilder = new CertificateRepMessageBuilder(caCert); + + // + // Send back an encryptedChallenge + // + // note: use cert req ID as key ID, don't want to use issuer/serial in this case! + DigestCalculator owfCalc = new JcaDigestCalculatorProviderBuilder().build().get(DigestCalculator.SHA_256); + JceKEMRecipientInfoGenerator recipientGenerator = new JceKEMRecipientInfoGenerator(senderReqMessage.getCertReqId().getEncoded(), + new JcaPEMKeyConverter().setProvider("BC").getPublicKey(certTemplate.getPublicKey()), CMSAlgorithm.AES256_WRAP).setKDF( + new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256)); + + byte[] A = new byte[32]; + rand.nextBytes(A); + + POPODecryptionKeyChallengeContentBuilder popoBldr = new POPODecryptionKeyChallengeContentBuilder(owfCalc, CMSAlgorithm.AES128_CBC); + + popoBldr.addChallenge(recipientGenerator, issuerCA, A); + + ContentSigner signer = new JcaContentSignerBuilder("ML-DSA").setProvider("BC").build(dilKp.getPrivate()); + ProtectedPKIMessage challengePkixMessage = new ProtectedPKIMessageBuilder(issuerCA, client) + .setBody(popoBldr.build()) + .build(signer); + + assertEquals(PKIBody.TYPE_POPO_CHALL, challengePkixMessage.getBody().getType()); + assertTrue(challengePkixMessage.verify(new JcaContentVerifierProviderBuilder().setProvider("BC").build(dilKp.getPublic()))); + + // + // send back the decrypted challenge + // + DigestCalculatorProvider owfProvider = new JcaDigestCalculatorProviderBuilder().setProvider("BC").build(); + POPODecryptionKeyChallengeContent popoDecKeyChallContent = POPODecryptionKeyChallengeContent.fromPKIBody(challengePkixMessage.getBody(), owfProvider); + + ChallengeContent[] challenges = popoDecKeyChallContent.toChallengeArray(); + + byte[] challengeValue = challenges[0].extractChallenge( + challengePkixMessage.getHeader(), new JceKEMEnvelopedRecipient(mlKemKp.getPrivate()).setProvider("BC")); + + POPODecryptionKeyResponseContentBuilder popoRespBldr = new POPODecryptionKeyResponseContentBuilder(); + + popoRespBldr.addChallengeResponse(challengeValue); + + ProtectedPKIMessage challengeResponseMessage = new ProtectedPKIMessageBuilder(client, issuerCA) + .setBody(popoRespBldr.build()) + .build(senderMacCalculator); + + assertEquals(PKIBody.TYPE_POPO_REP, challengeResponseMessage.getBody().getType()); + assertTrue(message.verify(macCalcProvider, senderMacPassword)); + assertTrue(Arrays.equals(A, POPODecryptionKeyResponseContent.fromPKIBody(challengeResponseMessage.getBody()).getResponses()[0])); + + // + // So far so good, we'll produce and send the certificate + // + X509CertificateHolder cert = makeV3Certificate(certTemplate.getPublicKey(), certTemplate.getSubject(), dilKp, "CN=ML-DSA Issuer"); + + CertificateResponseBuilder certRespBuilder = new CertificateResponseBuilder(senderReqMessage.getCertReqId(), new PKIStatusInfo(PKIStatus.granted)); + + certRespBuilder.withCertificate(cert); + + repMessageBuilder = new CertificateRepMessageBuilder(caCert); + + repMessageBuilder.addCertificateResponse(certRespBuilder.build()); + + signer = new JcaContentSignerBuilder("ML-DSA").setProvider("BC").build(dilKp.getPrivate()); + + ProtectedPKIMessage responsePkixMessage = new ProtectedPKIMessageBuilder(issuerCA, client) + .setBody(PKIBody.TYPE_INIT_REP, repMessageBuilder.build()) + .build(signer); + + assertEquals(PKIBody.TYPE_INIT_REP, responsePkixMessage.getBody().getType()); + assertTrue(responsePkixMessage.verify(new JcaContentVerifierProviderBuilder().setProvider("BC").build(dilKp.getPublic()))); + + CertificateRepMessage certRepMessage = CertificateRepMessage.fromPKIBody(responsePkixMessage.getBody()); + + CertificateResponse certResp = certRepMessage.getResponses()[0]; + + assertEquals(false, certResp.hasEncryptedCertificate()); + + X509CertificateHolder receivedCert = new X509CertificateHolder(certResp.getCertificate().getX509v3PKCert()); + byte[] recData = certResp.getCertificate().getEncoded(); + + assertEquals(true, Arrays.equals(new CMPCertificate(cert.toASN1Structure()).getEncoded(), recData)); + + // confirmation message calculation - this isn't actually required as part of the protocol, other than + // to allow the user to confirm they received the certificate. A CA could have published prior to this point. + + CertificateConfirmationContent content = new CertificateConfirmationContentBuilder() + .addAcceptedCertificate(cert, BigInteger.ONE) + .build(new JcaDigestCalculatorProviderBuilder().build()); + + message = new ProtectedPKIMessageBuilder(client, issuerCA) + .setBody(PKIBody.TYPE_CERT_CONFIRM, content) + .build(senderMacCalculator); + + assertTrue(content.getStatusMessages()[0].isVerified(receivedCert, new JcaDigestCalculatorProviderBuilder().build())); + assertEquals(PKIBody.TYPE_CERT_CONFIRM, message.getBody().getType()); + + // confirmation receiving + + CertificateConfirmationContent recContent = CertificateConfirmationContent.fromPKIBody(message.getBody()); + + assertTrue(recContent.getStatusMessages()[0].isVerified(receivedCert, new JcaDigestCalculatorProviderBuilder().build())); + } + public void testNTRURequestWithMlDsaCA() throws Exception { diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/AllTests.java b/pkix/src/test/java/org/bouncycastle/cert/test/AllTests.java index 4034d9d018..f71b205e71 100644 --- a/pkix/src/test/java/org/bouncycastle/cert/test/AllTests.java +++ b/pkix/src/test/java/org/bouncycastle/cert/test/AllTests.java @@ -23,8 +23,21 @@ public void setUp() public void testSimpleTests() { - org.bouncycastle.util.test.Test[] tests = new org.bouncycastle.util.test.Test[] { new CertTest(), new DANETest(), new PKCS10Test(), new AttrCertSelectorTest(), new AttrCertTest(), new X509ExtensionUtilsTest(), - new CertPathLoopTest(), new GOST3410_2012CMSTest(), new ExternalKeyTest() }; + org.bouncycastle.util.test.Test[] tests = new org.bouncycastle.util.test.Test[] + { + new AttrCertSelectorTest(), + new AttrCertTest(), + new CertPathLoopTest(), + new CertTest(), + new DANETest(), + new ExternalKeyTest(), + new GOST3410_2012CMSTest(), + new GOSTR3410_2012_256GenerateCertificate(), + new MLDSACredentialsTest(), + new PKCS10Test(), + new SLHDSACredentialsTest(), + new X509ExtensionUtilsTest(), + }; for (int i = 0; i != tests.length; i++) { @@ -61,6 +74,7 @@ public static Test suite() suite.addTestSuite(BcAttrCertTest.class); suite.addTestSuite(BcCertTest.class); suite.addTestSuite(BcPKCS10Test.class); + suite.addTestSuite(PQCPKCS10Test.class); suite.addTest(ConverterTest.suite()); return new BCTestSetup(suite); diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/BcCertTest.java b/pkix/src/test/java/org/bouncycastle/cert/test/BcCertTest.java index 249b56f190..156ad273a6 100644 --- a/pkix/src/test/java/org/bouncycastle/cert/test/BcCertTest.java +++ b/pkix/src/test/java/org/bouncycastle/cert/test/BcCertTest.java @@ -24,6 +24,7 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x500.X500Name; @@ -848,8 +849,8 @@ public void checkCreation3() try { ContentSigner sigGen = new BcECContentSignerBuilder( - new AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA1), - new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1)).build(privKey); + new AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA256), + new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256)).build(privKey); BcX509v3CertificateBuilder certGen = new BcX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubKey); X509CertificateHolder cert = certGen.build(sigGen); diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java b/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java index ef23bd1ce5..af0759bacb 100644 --- a/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java +++ b/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java @@ -77,6 +77,7 @@ import org.bouncycastle.asn1.x509.KeyPurposeId; import org.bouncycastle.asn1.x509.SubjectAltPublicKeyInfo; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; @@ -100,6 +101,7 @@ import org.bouncycastle.crypto.params.DSAValidationParameters; import org.bouncycastle.crypto.params.RSAKeyParameters; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers; import org.bouncycastle.jcajce.CompositePrivateKey; import org.bouncycastle.jcajce.CompositePublicKey; import org.bouncycastle.jcajce.spec.CompositeAlgorithmSpec; @@ -114,10 +116,12 @@ import org.bouncycastle.jce.spec.ECPublicKeySpec; import org.bouncycastle.jce.spec.GOST3410ParameterSpec; import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.operator.BufferingContentSigner; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.ContentVerifierProvider; import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; +import org.bouncycastle.operator.NoSignatureContentSigner; import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder; import org.bouncycastle.operator.bc.BcRSAContentVerifierProviderBuilder; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; @@ -2862,7 +2866,7 @@ public void checkCRLCreation5() { ASN1Enumerated reasonCode = (ASN1Enumerated)fromExtensionValue(ext); - if (reasonCode.intValueExact() != CRLReason.privilegeWithdrawn) + if (!reasonCode.hasValue(CRLReason.privilegeWithdrawn)) { fail("CRL entry reasonCode wrong"); } @@ -2888,14 +2892,11 @@ public void checkCRLCompositeCreation() PrivateKey ecPriv = ecKp.getPrivate(); PublicKey ecPub = ecKp.getPublic(); - KeyPairGenerator lmsKpg = KeyPairGenerator.getInstance("LMS", "BCPQC"); - - lmsKpg.initialize(new LMSKeyGenParameterSpec(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w1)); + KeyPairGenerator mlDsaKpg = KeyPairGenerator.getInstance("ML-DSA", "BC"); - KeyPair lmsKp = lmsKpg.generateKeyPair(); + mlDsaKpg.initialize(MLDSAParameterSpec.ml_dsa_65); - PrivateKey lmsPriv = lmsKp.getPrivate(); - PublicKey lmsPub = lmsKp.getPublic(); + KeyPair mlDsaKp = mlDsaKpg.generateKeyPair(); // // distinguished name table. @@ -2905,14 +2906,16 @@ public void checkCRLCompositeCreation() // // create the certificate - version 3 // - CompositeAlgorithmSpec compAlgSpec = new CompositeAlgorithmSpec.Builder() - .add("SHA256withECDSA") - .add("LMS") + CompositePublicKey compPub = CompositePublicKey.builder(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512) + .addPublicKey(mlDsaKp.getPublic(), "BC") + .addPublicKey(ecPub) + .build(); + CompositePrivateKey compPrivKey = CompositePrivateKey.builder(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512) + .addPrivateKey(mlDsaKp.getPrivate(), "BC") + .addPrivateKey(ecPriv) .build(); - CompositePublicKey compPub = new CompositePublicKey(ecPub, lmsPub); - CompositePrivateKey compPrivKey = new CompositePrivateKey(ecPriv, lmsPriv); - ContentSigner sigGen = new JcaContentSignerBuilder("Composite", compAlgSpec).setProvider(BC).build(compPrivKey); + ContentSigner sigGen = new JcaContentSignerBuilder("COMPOSITE").setProvider(BC).build(compPrivKey); Date now = new Date(); @@ -2945,6 +2948,8 @@ public void checkCRLCompositeCreation() X509CRLHolder crlHolder = crlGen.build(sigGen); + isTrue(crlHolder.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(compPub))); + X509CRL crl = new JcaX509CRLConverter().setProvider(BC).getCRL(crlHolder); // comp test @@ -2954,14 +2959,15 @@ public void checkCRLCompositeCreation() try { crl.verify(new CompositePublicKey(new PublicKey[]{null, null})); + fail("no exception"); } catch (InvalidKeyException e) { - isTrue(e.getMessage().equals("no matching key found")); + isTrue(e.getMessage().equals("provided composite public key cannot be used with the composite signature algorithm")); } // single key test - crl.verify(ecPub, BC); +// crl.verify(ecPub, BC); no longer supported... possibly TODO if (!crl.getIssuerX500Principal().equals(new X500Principal("CN=Test CA"))) { @@ -3010,14 +3016,14 @@ public void checkCRLCompositeCreation() fail("CRL entry reasonCode not found"); } - sigGen = new JcaContentSignerBuilder("SHA256withECDSA", compAlgSpec).setProvider(BC).build(compPrivKey); - - crlHolder = crlGen.build(sigGen); - - crl = new JcaX509CRLConverter().setProvider(BC).getCRL(crlHolder); - - // comp test - single key - crl.verify(compPub); +// sigGen = new JcaContentSignerBuilder("SHA256withECDSA", compAlgSpec).setProvider(BC).build(compPrivKey); +// +// crlHolder = crlGen.build(sigGen); +// +// crl = new JcaX509CRLConverter().setProvider(BC).getCRL(crlHolder); +// +// // comp test - single key +// crl.verify(compPub); } public void checkCrlECDSAwithDilithiumCreation() @@ -3144,6 +3150,44 @@ public void checkCrlECDSAwithDilithiumCreation() } } + public void checkMixedCompositionCreation() + throws Exception + { + if (Security.getProvider("SunEC") == null) + { + return; + } + KeyPairGenerator mldsaKpGen = KeyPairGenerator.getInstance("ML-DSA", "BC"); + + mldsaKpGen.initialize(MLDSAParameterSpec.ml_dsa_44); + + KeyPair mldsaKp = mldsaKpGen.generateKeyPair(); + + KeyPairGenerator ecKpGen = KeyPairGenerator.getInstance("EC", "SunEC"); + + ecKpGen.initialize(new ECGenParameterSpec("secp256r1")); + + KeyPair ecKp = ecKpGen.generateKeyPair(); + + CompositePublicKey compPublicKey = CompositePublicKey.builder(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256) + .addPublicKey(mldsaKp.getPublic(), "BC") + .addPublicKey(ecKp.getPublic(), "BC") + .build(); + CompositePrivateKey compPrivateKey = CompositePrivateKey.builder(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256) + .addPrivateKey(mldsaKp.getPrivate(), "BC") + .addPrivateKey(ecKp.getPrivate(), "SunEC") + .build(); + + // First sign (and verify) a certificate + final ContentSigner certsigner = new BufferingContentSigner(new JcaContentSignerBuilder("MLDSA44-ECDSA-P256-SHA256").setProvider("BC").build(compPrivateKey), 4096); + final SubjectPublicKeyInfo pkinfo = SubjectPublicKeyInfo.getInstance(compPublicKey.getEncoded()); + final X509v3CertificateBuilder certbuilder = new X509v3CertificateBuilder(new X500Name("CN=issuer"), new BigInteger("12345678"), new Date(), new Date(), new X500Name("CN=subject"), pkinfo); + final X509CertificateHolder certHolder = certbuilder.build(certsigner); + //Assert.assertNotNull("signing must have created a certificate", certHolder); + final ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().setProvider("BC").build(compPublicKey); + isTrue("Certificate signature must verify", certHolder.isSignatureValid(verifier)); + } + /* * we generate a self signed certificate for the sake of testing - GOST3410 */ @@ -3973,6 +4017,60 @@ public void checkCreationRSAPSS() isTrue(null == crt.getSubjectPublicKeyInfo().getAlgorithm().getParameters()); } + public void checkCreationNoSignature() + throws Exception + { + // + // set up the keys + // + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSASSA-PSS", BC); + + KeyPair kp = kpg.generateKeyPair(); + + PrivateKey privKey = kp.getPrivate(); + PublicKey pubKey = kp.getPublic(); + + // + // distinguished name table. + // + X500NameBuilder builder = createStdBuilder(); + + // + // create the certificate - version 3 + // + ContentSigner sigGen = new NoSignatureContentSigner(); + X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubKey); + + X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen)); + + cert.checkValidity(new Date()); + + // + // check fails on verify + // + try + { + cert.verify(pubKey); + fail("no exception"); + } + catch (InvalidKeyException e) + { + isEquals(e.getMessage(), "attempt to pass public key to NoSig"); + } + + // convert and check components. + ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded()); + CertificateFactory fact = CertificateFactory.getInstance("X.509", BC); + + cert = (X509Certificate)fact.generateCertificate(bIn); + + org.bouncycastle.asn1.x509.Certificate crt = org.bouncycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()); + + isTrue(new AlgorithmIdentifier(X509ObjectIdentifiers.id_alg_unsigned).equals(crt.getTBSCertificate().getSignature())); + isTrue(new AlgorithmIdentifier(X509ObjectIdentifiers.id_alg_unsigned).equals(crt.getSignatureAlgorithm())); + isTrue(0 == cert.getSignature().length); + } + /* * we generate a self signed certificate across the range of ECDSA algorithms */ @@ -5414,61 +5512,76 @@ private void checkSerialisation() // TESTS REGARDING COMPOSITES https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html private static String[] compositeSignaturesOIDs = { - "2.16.840.1.114027.80.8.1.21", //id-MLDSA44-RSA2048-PSS-SHA256 - "2.16.840.1.114027.80.8.1.22", //id-MLDSA44-RSA2048-PKCS15-SHA256 - "2.16.840.1.114027.80.8.1.23", //id-MLDSA44-Ed25519-SHA512 - "2.16.840.1.114027.80.8.1.24", //id-MLDSA44-ECDSA-P256-SHA256 - "2.16.840.1.114027.80.8.1.26", //id-MLDSA65-RSA3072-PSS-SHA512 - "2.16.840.1.114027.80.8.1.27", //id-MLDSA65-RSA3072-PKCS15-SHA512 - "2.16.840.1.114027.80.8.1.30", //id-MLDSA65-Ed25519-SHA512 - "2.16.840.1.114027.80.8.1.31", //id-MLDSA87-ECDSA-P384-SHA512 - "2.16.840.1.114027.80.8.1.32", //id-MLDSA87-ECDSA-brainpoolP384r1-SHA512 - "2.16.840.1.114027.80.8.1.33", //id-MLDSA87-Ed448-SHA512 - }; - - private static String[] compositeSignaturesIDs = { + "1.3.6.1.5.5.7.6.37", // id_MLDSA44_RSA2048_PSS_SHA256 + "1.3.6.1.5.5.7.6.38", // id_MLDSA44_RSA2048_PKCS15_SHA256 + "1.3.6.1.5.5.7.6.39", // id_MLDSA44_Ed25519_SHA512 + "1.3.6.1.5.5.7.6.40", // id_MLDSA44_ECDSA_P256_SHA256 + "1.3.6.1.5.5.7.6.41", // id_MLDSA65_RSA3072_PSS_SHA512 + "1.3.6.1.5.5.7.6.42", // id_MLDSA65_RSA3072_PKCS15_SHA512 + "1.3.6.1.5.5.7.6.43", // id_MLDSA65_RSA4096_PSS_SHA512 + "1.3.6.1.5.5.7.6.44", // id_MLDSA65_RSA4096_PKCS15_SHA512 + "1.3.6.1.5.5.7.6.45", // id_MLDSA65_ECDSA_P256_SHA512 + "1.3.6.1.5.5.7.6.46", // id_MLDSA65_ECDSA_P384_SHA512 + "1.3.6.1.5.5.7.6.47", // id_MLDSA65_ECDSA_brainpoolP256r1_SHA512 + "1.3.6.1.5.5.7.6.48", // id_MLDSA65_Ed25519_SHA512 + "1.3.6.1.5.5.7.6.49", // id_MLDSA87_ECDSA_P384_SHA512 + "1.3.6.1.5.5.7.6.50", // id_MLDSA87_ECDSA_brainpoolP384r1_SHA512 + "1.3.6.1.5.5.7.6.51", // id_MLDSA87_Ed448_SHAKE256 + "1.3.6.1.5.5.7.6.52", // id_MLDSA87_RSA3072_PSS_SHA512 + "1.3.6.1.5.5.7.6.53", // id_MLDSA87_RSA4096_PSS_SHA512 + "1.3.6.1.5.5.7.6.54" // id_MLDSA87_ECDSA_P521_SHA512 + }; + + private static final String[] compositeSignaturesIDs = { "MLDSA44-RSA2048-PSS-SHA256", "MLDSA44-RSA2048-PKCS15-SHA256", "MLDSA44-ED25519-SHA512", "MLDSA44-ECDSA-P256-SHA256", - "MLDSA65-RSA3072-PSS-SHA256", - "MLDSA65-RSA3072-PKCS15-SHA256", - "MLDSA65-ED25519-SHA512", - "MLDSA87-ECDSA-P384-SHA384", - "MLDSA87-ECDSA-brainpoolP384r1-SHA384", - "MLDSA87-ED448-SHA512", + "MLDSA65-RSA3072-PSS-SHA512", + "MLDSA65-RSA3072-PKCS15-SHA512", + "MLDSA65-RSA4096-PSS-SHA512", + "MLDSA65-RSA4096-PKCS15-SHA512", + "MLDSA65-ECDSA-P256-SHA512", + "MLDSA65-ECDSA-P384-SHA512", + "MLDSA65-ECDSA-brainpoolP256r1-SHA512", + "MLDSA65-ED25519-SHA512", + "MLDSA87-ECDSA-P384-SHA512", + "MLDSA87-ECDSA-brainpoolP384r1-SHA512", + "MLDSA87-ED448-SHAKE256", + "MLDSA87-RSA3072-PSS-SHA512", + "MLDSA87-RSA4096-PSS-SHA512", + "MLDSA87-ECDSA-P521-SHA512", }; private void checkCompositeSignatureCertificateCreation() throws Exception { - int index = 0; - for (String oid : compositeSignaturesOIDs) - { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(oid, "BC"); - KeyPair keyPair = keyPairGenerator.generateKeyPair(); - - String subjectName = "CN=ROOT CA"; - X500Name issuer = new X500Name(subjectName); - BigInteger serial = BigInteger.valueOf(5); - Date notBefore = new Date(); - Date notAfter = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 365L); - X500Name subject = new X500Name(subjectName); + int index = 0; + for (String oid : compositeSignaturesOIDs) + { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(oid, "BC"); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); - JcaX509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, keyPair.getPublic()); - X509CertificateHolder certHolder = certificateBuilder.build(new JcaContentSignerBuilder(compositeSignaturesIDs[index]).build(keyPair.getPrivate())); - X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder); + String subjectName = "CN=ROOT CA"; + X500Name issuer = new X500Name(subjectName); + BigInteger serial = BigInteger.valueOf(5); + Date notBefore = new Date(); + Date notAfter = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 365L); + X500Name subject = new X500Name(subjectName); + JcaX509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, keyPair.getPublic()); + X509CertificateHolder certHolder = certificateBuilder.build(new JcaContentSignerBuilder(compositeSignaturesIDs[index]).build(keyPair.getPrivate())); + X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder); - isEquals(oid, cert.getSigAlgOID()); - CompositePublicKey compositePublicKey = (CompositePublicKey)cert.getPublicKey(); + isEquals(oid, cert.getSigAlgOID()); + CompositePublicKey compositePublicKey = (CompositePublicKey)cert.getPublicKey(); - // isEquals(CompositeSignaturesConstants.ASN1IdentifierAlgorithmNameMap.get(new ASN1ObjectIdentifier(oid)).getId(), compositePublicKey.getAlgorithm()); + // isEquals(CompositeSignaturesConstants.ASN1IdentifierAlgorithmNameMap.get(new ASN1ObjectIdentifier(oid)).getId(), compositePublicKey.getAlgorithm()); - isEquals(subjectName, cert.getSubjectX500Principal().getName()); + isEquals(subjectName, cert.getSubjectX500Principal().getName()); - cert.verify(cert.getPublicKey()); - index++; - } + cert.verify(cert.getPublicKey(), "BC"); + index++; + } } private void checkParseCompositePublicKey() @@ -5478,7 +5591,7 @@ private void checkParseCompositePublicKey() // //compositePublicKeyExampleRFC.pem contains the sample public key from https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html // PEMParser pemParser = new PEMParser(new InputStreamReader(TestResourceFinder.findTestResource("pqc/composite", "compositePublicKeyExampleRFC.pem"))); // SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo)pemParser.readObject(); -// isEquals(subjectPublicKeyInfo.getAlgorithm().getAlgorithm(), MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256); +// isEquals(subjectPublicKeyInfo.getAlgorithm().getAlgorithm(), IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256); // // CompositePublicKey compositePublicKey = new CompositePublicKey(subjectPublicKeyInfo); // @@ -5502,7 +5615,7 @@ private void checkParseCompositePublicKey() // PEMParser pemParser = new PEMParser(new InputStreamReader(TestResourceFinder.findTestResource("pqc/composite", "compositePrivateKeyExample.pem"))); // PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo)pemParser.readObject(); // -// isEquals(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm(), MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256); +// isEquals(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm(), IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256); // // CompositePrivateKey compositePrivateKey = new CompositePrivateKey(privateKeyInfo); // @@ -5525,7 +5638,7 @@ private void checkParseAndVerifyCompositeCertificate() // JcaX509CertificateConverter x509Converter = new JcaX509CertificateConverter().setProvider("BC"); // X509Certificate certificate = x509Converter.getCertificate(certificateHolder); // -// isEquals(certificate.getSigAlgOID(), MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.toString()); +// isEquals(certificate.getSigAlgOID(), IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.toString()); // // CompositePublicKey compositePublicKey = (CompositePublicKey)certificate.getPublicKey(); // @@ -5536,7 +5649,8 @@ private void checkParseAndVerifyCompositeCertificate() //certificate.verify(compositePublicKey); } catch (Exception e) - { e.printStackTrace(); + { + e.printStackTrace(); fail("checkParseAndVerifyCompositeCertificate failed: " + e.getMessage()); } } @@ -5644,6 +5758,7 @@ public void performTest() checkCreationECDSA(); checkCreationRSA(); checkCreationRSAPSS(); + checkCreationNoSignature(); checkCreationFalcon(); checkCreationDilithium(); @@ -5655,6 +5770,7 @@ public void performTest() checkCreationDilithiumSigWithECDSASig(); checkCreationComposite(); + checkMixedCompositionCreation(); checkCompositeCertificateVerify(); createECCert("SHA1withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1); diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/GOSTR3410_2012_256GenerateCertificate.java b/pkix/src/test/java/org/bouncycastle/cert/test/GOSTR3410_2012_256GenerateCertificate.java index 8ef1842940..ac2e486f79 100644 --- a/pkix/src/test/java/org/bouncycastle/cert/test/GOSTR3410_2012_256GenerateCertificate.java +++ b/pkix/src/test/java/org/bouncycastle/cert/test/GOSTR3410_2012_256GenerateCertificate.java @@ -9,7 +9,6 @@ import java.security.Provider; import java.security.Security; import java.security.spec.ECGenParameterSpec; -import java.time.ZonedDateTime; import java.util.Date; import org.bouncycastle.asn1.ASN1Sequence; @@ -60,14 +59,14 @@ private static X509CertificateHolder generateSelfSignedCertificate() X500Name subject = new X500Name("CN=TEST"); X500Name issuer = subject; BigInteger serial = BigInteger.ONE; - ZonedDateTime notBefore = ZonedDateTime.now(); - ZonedDateTime notAfter = notBefore.plusYears(1); + Date notBefore = new Date(); + Date notAfter = new Date(notBefore.getTime() + 1000L * 60 * 60 * 24 * 365); X509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder( issuer, serial, - Date.from(notBefore.toInstant()), - Date.from(notAfter.toInstant()), + notBefore, + notAfter, subject, keyPair.getPublic() ); diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/MLDSACredentialsTest.java b/pkix/src/test/java/org/bouncycastle/cert/test/MLDSACredentialsTest.java new file mode 100644 index 0000000000..09a3f70f38 --- /dev/null +++ b/pkix/src/test/java/org/bouncycastle/cert/test/MLDSACredentialsTest.java @@ -0,0 +1,41 @@ +package org.bouncycastle.cert.test; + +import java.security.GeneralSecurityException; +import java.security.PublicKey; +import java.security.Security; +import java.security.cert.X509Certificate; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.test.SimpleTest; + +public class MLDSACredentialsTest + extends SimpleTest +{ + public String getName() + { + return "MLDSACredentials"; + } + + public void performTest() + throws Exception + { + checkSampleCredentials(SampleCredentials.ML_DSA_44); + checkSampleCredentials(SampleCredentials.ML_DSA_65); + checkSampleCredentials(SampleCredentials.ML_DSA_87); + } + + private static void checkSampleCredentials(SampleCredentials creds) + throws GeneralSecurityException + { + X509Certificate cert = creds.getCertificate(); + PublicKey pubKey = cert.getPublicKey(); + cert.verify(pubKey, BouncyCastleProvider.PROVIDER_NAME); + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new MLDSACredentialsTest()); + } +} diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/MLKEMCredentialsTest.java b/pkix/src/test/java/org/bouncycastle/cert/test/MLKEMCredentialsTest.java new file mode 100644 index 0000000000..29b2c1dac1 --- /dev/null +++ b/pkix/src/test/java/org/bouncycastle/cert/test/MLKEMCredentialsTest.java @@ -0,0 +1,37 @@ +package org.bouncycastle.cert.test; + +import java.security.GeneralSecurityException; +import java.security.Security; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.test.SimpleTest; + +public class MLKEMCredentialsTest + extends SimpleTest +{ + public String getName() + { + return "MLKEMCredentials"; + } + + public void performTest() + throws Exception + { + checkSampleCredentials(SampleCredentials.ML_KEM_512, SampleCredentials.ML_DSA_44); + checkSampleCredentials(SampleCredentials.ML_KEM_768, SampleCredentials.ML_DSA_65); + checkSampleCredentials(SampleCredentials.ML_KEM_1024, SampleCredentials.ML_DSA_87); + } + + private static void checkSampleCredentials(SampleCredentials subject, SampleCredentials issuer) + throws GeneralSecurityException + { + subject.getCertificate().verify(issuer.getCertificate().getPublicKey(), BouncyCastleProvider.PROVIDER_NAME); + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new MLKEMCredentialsTest()); + } +} diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/PQCPKCS10Test.java b/pkix/src/test/java/org/bouncycastle/cert/test/PQCPKCS10Test.java new file mode 100644 index 0000000000..c81c84123b --- /dev/null +++ b/pkix/src/test/java/org/bouncycastle/cert/test/PQCPKCS10Test.java @@ -0,0 +1,147 @@ +package org.bouncycastle.cert.test; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.Date; + +import javax.security.auth.x500.X500Principal; + +import junit.framework.TestCase; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.jcajce.spec.MLDSAParameterSpec; +import org.bouncycastle.jcajce.spec.MLKEMParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder; +import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest; +import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; +import org.bouncycastle.util.Arrays; + +/** + **/ +public class PQCPKCS10Test + extends TestCase +{ + private static final String BC = BouncyCastleProvider.PROVIDER_NAME; + + public String getName() + { + return "PKCS10CertRequest"; + } + + public void setUp() + { + if (Security.getProvider("BC") == null) + { + Security.addProvider(new BouncyCastleProvider()); + } + } + + public void testMLDsa() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-DSA", "BC"); + + kpg.initialize(MLDSAParameterSpec.ml_dsa_65); + + KeyPair kp = kpg.genKeyPair(); + + X500Name subject = getSubjectName(); + + PKCS10CertificationRequestBuilder requestBuilder = new JcaPKCS10CertificationRequestBuilder(subject, kp.getPublic()); + + PKCS10CertificationRequest req1 = requestBuilder.build(new JcaContentSignerBuilder("ML-DSA").setProvider(BC).build(kp.getPrivate())); + + JcaPKCS10CertificationRequest req2 = new JcaPKCS10CertificationRequest(req1.getEncoded()).setProvider(BC); + + if (!req2.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(kp.getPublic()))) + { + fail("ML-DSA: Failed verify check."); + } + + if (!Arrays.areEqual(req2.getPublicKey().getEncoded(), req1.getSubjectPublicKeyInfo().getEncoded())) + { + fail("ML-DSA: Failed public key check."); + } + } + + /** + * ML-KEM basesd PKCS#10 request using ML-DSA signing key. + */ + public void testMLKem() + throws Exception + { + KeyPairGenerator signKpg = KeyPairGenerator.getInstance("ML-DSA", "BC"); + + signKpg.initialize(MLDSAParameterSpec.ml_dsa_65); + + KeyPair signKp = signKpg.genKeyPair(); + X509Certificate signCert = getMLDSACertificate(signKp); + + KeyPairGenerator kemKpg = KeyPairGenerator.getInstance("ML-KEM", "BC"); + + kemKpg.initialize(MLKEMParameterSpec.ml_kem_768); + + KeyPair kemKp = kemKpg.genKeyPair(); + + X500Principal subject = signCert.getSubjectX500Principal(); + + PKCS10CertificationRequestBuilder requestBuilder = new JcaPKCS10CertificationRequestBuilder(subject, kemKp.getPublic()); + + PKCS10CertificationRequest req1 = requestBuilder.build(new JcaContentSignerBuilder("ML-DSA").setProvider(BC).build(signKp.getPrivate())); + + JcaPKCS10CertificationRequest req2 = new JcaPKCS10CertificationRequest(req1.getEncoded()).setProvider(BC); + + if (!req2.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider(BC).build(signCert.getPublicKey()))) + { + fail("ML-KEM: Failed verify check."); + } + + if (!Arrays.areEqual(req2.getPublicKey().getEncoded(), req1.getSubjectPublicKeyInfo().getEncoded())) + { + fail("ML-KEM: Failed public key check."); + } + } + + private X500Name getSubjectName() + { + X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE); + + x500NameBld.addRDN(BCStyle.C, "AU"); + x500NameBld.addRDN(BCStyle.O, "The Legion of the Bouncy Castle"); + x500NameBld.addRDN(BCStyle.L, "Melbourne"); + x500NameBld.addRDN(BCStyle.ST, "Victoria"); + x500NameBld.addRDN(BCStyle.EmailAddress, "feedback-crypto@bouncycastle.org"); + + X500Name subject = x500NameBld.build(); + return subject; + } + + private X509Certificate getMLDSACertificate(KeyPair kp) + throws Exception + { + X500Name issuer = getSubjectName(); // self signed + X509v3CertificateBuilder v3certBldr = new JcaX509v3CertificateBuilder(issuer, + BigInteger.valueOf(System.currentTimeMillis()), + new Date(System.currentTimeMillis() - 5000L), + new Date(System.currentTimeMillis() + 15000L), + issuer, kp.getPublic()).addExtension(Extension.basicConstraints, true, new BasicConstraints(false)); + + ContentSigner signer = new JcaContentSignerBuilder("ML-DSA").setProvider(BC).build(kp.getPrivate()); + + return new JcaX509CertificateConverter().setProvider(BC).getCertificate(v3certBldr.build(signer)); + } +} diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/SLHDSACredentialsTest.java b/pkix/src/test/java/org/bouncycastle/cert/test/SLHDSACredentialsTest.java new file mode 100644 index 0000000000..c11a5a8131 --- /dev/null +++ b/pkix/src/test/java/org/bouncycastle/cert/test/SLHDSACredentialsTest.java @@ -0,0 +1,39 @@ +package org.bouncycastle.cert.test; + +import java.security.GeneralSecurityException; +import java.security.PublicKey; +import java.security.Security; +import java.security.cert.X509Certificate; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.test.SimpleTest; + +public class SLHDSACredentialsTest + extends SimpleTest +{ + public String getName() + { + return "SLHDSACredentials"; + } + + public void performTest() + throws Exception + { + checkSampleCredentials(SampleCredentials.SLH_DSA_SHA2_128S); + } + + private static void checkSampleCredentials(SampleCredentials creds) + throws GeneralSecurityException + { + X509Certificate cert = creds.getCertificate(); + PublicKey pubKey = cert.getPublicKey(); + cert.verify(pubKey, BouncyCastleProvider.PROVIDER_NAME); + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new SLHDSACredentialsTest()); + } +} diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/SampleCredentials.java b/pkix/src/test/java/org/bouncycastle/cert/test/SampleCredentials.java new file mode 100644 index 0000000000..919d198956 --- /dev/null +++ b/pkix/src/test/java/org/bouncycastle/cert/test/SampleCredentials.java @@ -0,0 +1,107 @@ +package org.bouncycastle.cert.test; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.test.TestResourceFinder; +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemReader; + +public class SampleCredentials +{ + public static final SampleCredentials ML_DSA_44 = load("ML-DSA-44", "pkix/cert/mldsa", "ML-DSA-44.pem"); + public static final SampleCredentials ML_DSA_65 = load("ML-DSA-65", "pkix/cert/mldsa", "ML-DSA-65.pem"); + public static final SampleCredentials ML_DSA_87 = load("ML-DSA-87", "pkix/cert/mldsa", "ML-DSA-87.pem"); + + public static final SampleCredentials ML_KEM_512 = load("ML-KEM-512", "pkix/cert/mlkem", "ML-KEM-512.pem"); + public static final SampleCredentials ML_KEM_768 = load("ML-KEM-768", "pkix/cert/mlkem", "ML-KEM-768.pem"); + public static final SampleCredentials ML_KEM_1024 = load("ML-KEM-1024", "pkix/cert/mlkem", "ML-KEM-1024.pem"); + + public static final SampleCredentials SLH_DSA_SHA2_128S = load("SLH-DSA-SHA2-128S", "pkix/cert/slhdsa", + "SLH-DSA-SHA2-128S.pem"); + + private static PemObject expectPemObject(PemReader pemReader, String type) + throws IOException + { + PemObject result = pemReader.readPemObject(); + if (!type.equals(result.getType())) + { + throw new IllegalStateException(); + } + return result; + } + + private static SampleCredentials load(String algorithm, String path, String name) + { + try + { + if (Security.getProvider("BC") == null) + { + Security.addProvider(new BouncyCastleProvider()); + } + + InputStream input = new BufferedInputStream(TestResourceFinder.findTestResource(path, name)); + Reader reader = new InputStreamReader(input); + + PemReader pemReader = new PemReader(reader); + PemObject pemPriv = expectPemObject(pemReader, "PRIVATE KEY"); + PemObject pemPub = expectPemObject(pemReader, "PUBLIC KEY"); + PemObject pemCert = expectPemObject(pemReader, "CERTIFICATE"); + pemReader.close(); + + KeyFactory kf = KeyFactory.getInstance(algorithm, BouncyCastleProvider.PROVIDER_NAME); + CertificateFactory cf = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); + + PrivateKey privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(pemPriv.getContent())); + PublicKey publicKey = kf.generatePublic(new X509EncodedKeySpec(pemPub .getContent())); + KeyPair keyPair = new KeyPair(publicKey, privateKey); + + X509Certificate certificate = (X509Certificate)cf.generateCertificate( + new ByteArrayInputStream(pemCert.getContent())); + + if (!publicKey.equals(certificate.getPublicKey())) + { + throw new IllegalStateException("public key mismatch"); + } + + return new SampleCredentials(keyPair, certificate); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + + private final KeyPair keyPair; + private final X509Certificate certificate; + + private SampleCredentials(KeyPair keyPair, X509Certificate certificate) + { + this.keyPair = keyPair; + this.certificate = certificate; + } + + public X509Certificate getCertificate() + { + return certificate; + } + + public KeyPair getKeyPair() + { + return keyPair; + } +} diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/X509ExtensionUtilsTest.java b/pkix/src/test/java/org/bouncycastle/cert/test/X509ExtensionUtilsTest.java index 2333846812..d2b2226ee6 100644 --- a/pkix/src/test/java/org/bouncycastle/cert/test/X509ExtensionUtilsTest.java +++ b/pkix/src/test/java/org/bouncycastle/cert/test/X509ExtensionUtilsTest.java @@ -78,7 +78,11 @@ public void basicTest() { fail("v0 issuer not matched"); } - if (!Arrays.areEqual(Hex.decode("f0d46a0a97e24c20ec857ee6831e0be8a797c49d"), authKeyId.getKeyIdentifier())) + if (!Arrays.areEqual(Hex.decode("f0d46a0a97e24c20ec857ee6831e0be8a797c49d"), authKeyId.getKeyIdentifierOctets())) + { + fail("v0 keyID not matched"); + } + if (!Arrays.areEqual(Hex.decode("f0d46a0a97e24c20ec857ee6831e0be8a797c49d"), authKeyId.getKeyIdentifierObject().getOctets())) { fail("v0 keyID not matched"); } @@ -92,7 +96,11 @@ public void basicTest() { fail("v3 issuer not matched"); } - if (!Arrays.areEqual(Hex.decode("c4733fe7e5fdd51bdd98d75b345674d85ba0f76c"), authKeyId.getKeyIdentifier())) + if (!Arrays.areEqual(Hex.decode("c4733fe7e5fdd51bdd98d75b345674d85ba0f76c"), authKeyId.getKeyIdentifierOctets())) + { + fail("v3 keyID not matched"); + } + if (!Arrays.areEqual(Hex.decode("c4733fe7e5fdd51bdd98d75b345674d85ba0f76c"), authKeyId.getKeyIdentifierObject().getOctets())) { fail("v3 keyID not matched"); } @@ -133,7 +141,11 @@ public void jcaTest() { fail("v0 issuer not matched"); } - if (!Arrays.areEqual(Hex.decode("f0d46a0a97e24c20ec857ee6831e0be8a797c49d"), authKeyId.getKeyIdentifier())) + if (!Arrays.areEqual(Hex.decode("f0d46a0a97e24c20ec857ee6831e0be8a797c49d"), authKeyId.getKeyIdentifierOctets())) + { + fail("v0 keyID not matched"); + } + if (!Arrays.areEqual(Hex.decode("f0d46a0a97e24c20ec857ee6831e0be8a797c49d"), authKeyId.getKeyIdentifierObject().getOctets())) { fail("v0 keyID not matched"); } @@ -147,7 +159,11 @@ public void jcaTest() { fail("v3 issuer not matched"); } - if (!Arrays.areEqual(Hex.decode("c4733fe7e5fdd51bdd98d75b345674d85ba0f76c"), authKeyId.getKeyIdentifier())) + if (!Arrays.areEqual(Hex.decode("c4733fe7e5fdd51bdd98d75b345674d85ba0f76c"), authKeyId.getKeyIdentifierOctets())) + { + fail("v3 keyID not matched"); + } + if (!Arrays.areEqual(Hex.decode("c4733fe7e5fdd51bdd98d75b345674d85ba0f76c"), authKeyId.getKeyIdentifierObject().getOctets())) { fail("v3 keyID not matched"); } @@ -162,7 +178,11 @@ public void jcaTest() { fail("v3 issuer not matched"); } - if (!Arrays.areEqual(Hex.decode("c4733fe7e5fdd51bdd98d75b345674d85ba0f76c"), authKeyId.getKeyIdentifier())) + if (!Arrays.areEqual(Hex.decode("c4733fe7e5fdd51bdd98d75b345674d85ba0f76c"), authKeyId.getKeyIdentifierOctets())) + { + fail("v3 keyID not matched"); + } + if (!Arrays.areEqual(Hex.decode("c4733fe7e5fdd51bdd98d75b345674d85ba0f76c"), authKeyId.getKeyIdentifierObject().getOctets())) { fail("v3 keyID not matched"); } diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/AuthEnvelopedDataTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/AuthEnvelopedDataTest.java index 1f6736766a..4615b98d69 100644 --- a/pkix/src/test/java/org/bouncycastle/cms/test/AuthEnvelopedDataTest.java +++ b/pkix/src/test/java/org/bouncycastle/cms/test/AuthEnvelopedDataTest.java @@ -23,6 +23,7 @@ import org.bouncycastle.asn1.cms.Time; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.cms.CMSAlgorithm; import org.bouncycastle.cms.CMSAttributeTableGenerationException; import org.bouncycastle.cms.CMSAttributeTableGenerator; import org.bouncycastle.cms.CMSAuthEnvelopedData; @@ -207,6 +208,53 @@ public AttributeTable getAttributes(Map parameters) assertEquals("Hello, world!", Strings.fromByteArray(recData)); } + public void testChacha20Poly1305() + throws Exception + { + if (!CMSTestUtil.isAeadAvailable()) + { + return; + } + byte[] message = Strings.toByteArray("Hello, world!"); + OutputEncryptor candidate = new JceCMSContentEncryptorBuilder(CMSAlgorithm.ChaCha20Poly1305).setProvider(BC).build(); + + assertEquals(CMSAlgorithm.ChaCha20Poly1305, candidate.getAlgorithmIdentifier().getAlgorithm()); + //assertNotNull(GCMParameters.getInstance(candidate.getAlgorithmIdentifier().getParameters())); + + assertTrue(candidate instanceof OutputAEADEncryptor); + + OutputAEADEncryptor macProvider = (OutputAEADEncryptor)candidate; + + CMSAuthEnvelopedDataGenerator authGen = new CMSAuthEnvelopedDataGenerator(); + + authGen.setAuthenticatedAttributeGenerator(new CMSAttributeTableGenerator() + { + public AttributeTable getAttributes(Map parameters) + throws CMSAttributeTableGenerationException + { + Hashtable attrs = new Hashtable(); + Attribute testAttr = new Attribute(CMSAttributes.signingTime, + new DERSet(new Time(new Date()))); + attrs.put(testAttr.getAttrType(), testAttr); + return new AttributeTable(attrs); + } + }); + + authGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert)); + + CMSAuthEnvelopedData authData = authGen.generate(new CMSProcessableByteArray(message), macProvider); + + CMSAuthEnvelopedData encAuthData = new CMSAuthEnvelopedData(authData.getEncoded()); + + RecipientInformationStore recipients = encAuthData.getRecipientInfos(); + + RecipientInformation recipient = (RecipientInformation)recipients.getRecipients().iterator().next(); + + byte[] recData = recipient.getContent(new JceKeyTransAuthEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC)); + + assertEquals("Hello, world!", Strings.fromByteArray(recData)); + } + public void testGCMwithHKDF() throws Exception { diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/BcSignedDataTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/BcSignedDataTest.java index b2aeea711c..699d510273 100644 --- a/pkix/src/test/java/org/bouncycastle/cms/test/BcSignedDataTest.java +++ b/pkix/src/test/java/org/bouncycastle/cms/test/BcSignedDataTest.java @@ -1001,7 +1001,7 @@ public void testSHA1WithRSAEncapsulated() public void testEd448() throws Exception { - encapsulatedTest(_signEd448KP, _signEd448Cert, "ED448", new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256_len, new ASN1Integer(512))); + encapsulatedTest(_signEd448KP, _signEd448Cert, "ED448", new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256_len, ASN1Integer.valueOf(512))); } public void testSHA1WithRSAEncapsulatedSubjectKeyID() diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/CMSAuthEnvelopedDataStreamGeneratorTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/CMSAuthEnvelopedDataStreamGeneratorTest.java index 1a73d5fad3..85e91d89ad 100644 --- a/pkix/src/test/java/org/bouncycastle/cms/test/CMSAuthEnvelopedDataStreamGeneratorTest.java +++ b/pkix/src/test/java/org/bouncycastle/cms/test/CMSAuthEnvelopedDataStreamGeneratorTest.java @@ -1,6 +1,7 @@ package org.bouncycastle.cms.test; import java.io.ByteArrayOutputStream; +import java.io.InputStream; import java.io.OutputStream; import java.security.KeyPair; import java.security.cert.X509Certificate; @@ -24,8 +25,8 @@ import org.bouncycastle.cms.CMSAlgorithm; import org.bouncycastle.cms.CMSAttributeTableGenerationException; import org.bouncycastle.cms.CMSAttributeTableGenerator; -import org.bouncycastle.cms.CMSAuthEnvelopedDataStreamGenerator; import org.bouncycastle.cms.CMSAuthEnvelopedDataParser; +import org.bouncycastle.cms.CMSAuthEnvelopedDataStreamGenerator; import org.bouncycastle.cms.CMSTypedStream; import org.bouncycastle.cms.RecipientInformation; import org.bouncycastle.cms.RecipientInformationStore; @@ -111,6 +112,16 @@ public void setUp() init(); } + public void testGCMCCMZeroLength() + throws Exception + { + GCMCCMtest(CMSAlgorithm.AES128_GCM, false, new byte[0]); + GCMCCMtest(CMSAlgorithm.AES128_GCM, true, new byte[0]); + + GCMCCMtest(CMSAlgorithm.AES128_CCM, false, new byte[0]); + GCMCCMtest(CMSAlgorithm.AES128_CCM, true, new byte[0]); + } + public void testGCMCCM() throws Exception { @@ -129,14 +140,19 @@ public void testGCMCCM() GCMCCMtest(CMSAlgorithm.AES256_CCM, true); } - public void GCMCCMtest(ASN1ObjectIdentifier oid, boolean berEncodeRecipientSet) + private void GCMCCMtest(ASN1ObjectIdentifier oid, boolean berEncodeRecipientSet) + throws Exception + { + GCMCCMtest(oid, berEncodeRecipientSet, Strings.toByteArray("Hello, world!")); + } + + private void GCMCCMtest(ASN1ObjectIdentifier oid, boolean berEncodeRecipientSet, byte[] message) throws Exception { if (!CMSTestUtil.isAeadAvailable()) { return; } - byte[] message = Strings.toByteArray("Hello, world!"); OutputEncryptor candidate = new JceCMSContentEncryptorBuilder(oid).setProvider(BC).build(); @@ -209,6 +225,35 @@ public AttributeTable getAttributes(Map parameters) assertEquals(1, ep.getUnauthAttrs().size()); } ep.close(); + + // alternate read approach + ep = new CMSAuthEnvelopedDataParser(bOut.toByteArray()); + + recipients = ep.getRecipientInfos(); + + c = recipients.getRecipients(); + + it = c.iterator(); + + while (it.hasNext()) + { + RecipientInformation recipient = (RecipientInformation)it.next(); + + assertEquals(recipient.getKeyEncryptionAlgOID(), "1.2.840.113549.1.1.1"); + + CMSTypedStream recData = recipient.getContentStream(new JceKeyTransAuthEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC)); + + byte[] buf = new byte[message.length]; + + InputStream contentStream = recData.getContentStream(); + + contentStream.read(buf); + contentStream.close(); + + assertEquals(true, Arrays.equals(message, buf)); + assertTrue(Arrays.equals(ep.getMac(), recipient.getMac())); + } + ep.close(); } public void testNoAuthAttributes() diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java b/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java index 41b04336fa..787b7dcd48 100644 --- a/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java +++ b/pkix/src/test/java/org/bouncycastle/cms/test/CMSTestUtil.java @@ -53,6 +53,7 @@ public class CMSTestUtil { public static SecureRandom rand; public static KeyPairGenerator kpg; + public static KeyPairGenerator kpg_2048; public static KeyPairGenerator gostKpg; public static KeyPairGenerator dsaKpg; @@ -61,8 +62,25 @@ public class CMSTestUtil public static KeyPairGenerator ecDsaKpg; public static KeyPairGenerator ed25519Kpg; public static KeyPairGenerator ed448Kpg; - public static KeyPairGenerator mlKemKpg; + public static KeyPairGenerator mlDsa44Kpg; + public static KeyPairGenerator mlDsa65Kpg; + public static KeyPairGenerator mlDsa87Kpg; + public static KeyPairGenerator mlKem512Kpg; + public static KeyPairGenerator mlKem768Kpg; + public static KeyPairGenerator mlKem1024Kpg; public static KeyPairGenerator ntruKpg; + public static KeyPairGenerator slhDsa_Sha2_128f_Kpg; + public static KeyPairGenerator slhDsa_Sha2_128s_Kpg; + public static KeyPairGenerator slhDsa_Sha2_192f_Kpg; + public static KeyPairGenerator slhDsa_Sha2_192s_Kpg; + public static KeyPairGenerator slhDsa_Sha2_256f_Kpg; + public static KeyPairGenerator slhDsa_Sha2_256s_Kpg; + public static KeyPairGenerator slhDsa_Shake_128f_Kpg; + public static KeyPairGenerator slhDsa_Shake_128s_Kpg; + public static KeyPairGenerator slhDsa_Shake_192f_Kpg; + public static KeyPairGenerator slhDsa_Shake_192s_Kpg; + public static KeyPairGenerator slhDsa_Shake_256f_Kpg; + public static KeyPairGenerator slhDsa_Shake_256s_Kpg; public static KeyGenerator aes192kg; public static KeyGenerator desede128kg; public static KeyGenerator desede192kg; @@ -139,8 +157,8 @@ public class CMSTestUtil kpg = KeyPairGenerator.getInstance("RSA", "BC"); kpg.initialize(1024, rand); - kpg = KeyPairGenerator.getInstance("RSA", "BC"); - kpg.initialize(1024, rand); + kpg_2048 = KeyPairGenerator.getInstance("RSA", "BC"); + kpg_2048.initialize(2048, rand); gostKpg = KeyPairGenerator.getInstance("GOST3410", "BC"); GOST3410ParameterSpec gost3410P = new GOST3410ParameterSpec(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_A.getId()); @@ -168,7 +186,27 @@ public class CMSTestUtil ed448Kpg = KeyPairGenerator.getInstance("Ed448", "BC"); ntruKpg = KeyPairGenerator.getInstance(BCObjectIdentifiers.ntruhps2048509.getId(), "BC"); - mlKemKpg = KeyPairGenerator.getInstance("ML-KEM-768", "BC"); + + mlDsa44Kpg = KeyPairGenerator.getInstance("ML-DSA-44", "BC"); + mlDsa65Kpg = KeyPairGenerator.getInstance("ML-DSA-65", "BC"); + mlDsa87Kpg = KeyPairGenerator.getInstance("ML-DSA-87", "BC"); + + mlKem512Kpg = KeyPairGenerator.getInstance("ML-KEM-512", "BC"); + mlKem768Kpg = KeyPairGenerator.getInstance("ML-KEM-768", "BC"); + mlKem1024Kpg = KeyPairGenerator.getInstance("ML-KEM-1024", "BC"); + + slhDsa_Sha2_128f_Kpg = KeyPairGenerator.getInstance("SLH-DSA-SHA2-128F", "BC"); + slhDsa_Sha2_128s_Kpg = KeyPairGenerator.getInstance("SLH-DSA-SHA2-128S", "BC"); + slhDsa_Sha2_192f_Kpg = KeyPairGenerator.getInstance("SLH-DSA-SHA2-192F", "BC"); + slhDsa_Sha2_192s_Kpg = KeyPairGenerator.getInstance("SLH-DSA-SHA2-192S", "BC"); + slhDsa_Sha2_256f_Kpg = KeyPairGenerator.getInstance("SLH-DSA-SHA2-256F", "BC"); + slhDsa_Sha2_256s_Kpg = KeyPairGenerator.getInstance("SLH-DSA-SHA2-256S", "BC"); + slhDsa_Shake_128f_Kpg = KeyPairGenerator.getInstance("SLH-DSA-SHAKE-128F", "BC"); + slhDsa_Shake_128s_Kpg = KeyPairGenerator.getInstance("SLH-DSA-SHAKE-128S", "BC"); + slhDsa_Shake_192f_Kpg = KeyPairGenerator.getInstance("SLH-DSA-SHAKE-192F", "BC"); + slhDsa_Shake_192s_Kpg = KeyPairGenerator.getInstance("SLH-DSA-SHAKE-192S", "BC"); + slhDsa_Shake_256f_Kpg = KeyPairGenerator.getInstance("SLH-DSA-SHAKE-256F", "BC"); + slhDsa_Shake_256s_Kpg = KeyPairGenerator.getInstance("SLH-DSA-SHAKE-256S", "BC"); aes192kg = KeyGenerator.getInstance("AES", "BC"); aes192kg.init(192, rand); @@ -210,7 +248,7 @@ public static boolean isAeadAvailable() public static String dumpBase64( byte[] data) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); data = Base64.encode(data); @@ -241,6 +279,11 @@ public static KeyPair makeKeyPair() return kpg.generateKeyPair(); } + public static KeyPair makeKeyPair_2048() + { + return kpg_2048.generateKeyPair(); + } + public static KeyPair makeGostKeyPair() { return gostKpg.generateKeyPair(); @@ -281,9 +324,94 @@ public static KeyPair makeNtruKeyPair() return ntruKpg.generateKeyPair(); } - public static KeyPair makeMLKemKeyPair() + public static KeyPair makeMLKem512KeyPair() + { + return mlKem512Kpg.generateKeyPair(); + } + + public static KeyPair makeMLKem768KeyPair() + { + return mlKem768Kpg.generateKeyPair(); + } + + public static KeyPair makeMLKem1024KeyPair() { - return mlKemKpg.generateKeyPair(); + return mlKem1024Kpg.generateKeyPair(); + } + + public static KeyPair makeMLDsa44KeyPair() + { + return mlDsa44Kpg.generateKeyPair(); + } + + public static KeyPair makeMLDsa65KeyPair() + { + return mlDsa65Kpg.generateKeyPair(); + } + + public static KeyPair makeMLDsa87KeyPair() + { + return mlDsa87Kpg.generateKeyPair(); + } + + public static KeyPair makeSlhDsa_Sha2_128f_KeyPair() + { + return slhDsa_Sha2_128f_Kpg.generateKeyPair(); + } + + public static KeyPair makeSlhDsa_Sha2_128s_KeyPair() + { + return slhDsa_Sha2_128s_Kpg.generateKeyPair(); + } + + public static KeyPair makeSlhDsa_Sha2_192f_KeyPair() + { + return slhDsa_Sha2_192f_Kpg.generateKeyPair(); + } + + public static KeyPair makeSlhDsa_Sha2_192s_KeyPair() + { + return slhDsa_Sha2_192s_Kpg.generateKeyPair(); + } + + public static KeyPair makeSlhDsa_Sha2_256f_KeyPair() + { + return slhDsa_Sha2_256f_Kpg.generateKeyPair(); + } + + public static KeyPair makeSlhDsa_Sha2_256s_KeyPair() + { + return slhDsa_Sha2_256s_Kpg.generateKeyPair(); + } + + public static KeyPair makeSlhDsa_Shake_128f_KeyPair() + { + return slhDsa_Shake_128f_Kpg.generateKeyPair(); + } + + public static KeyPair makeSlhDsa_Shake_128s_KeyPair() + { + return slhDsa_Shake_128s_Kpg.generateKeyPair(); + } + + public static KeyPair makeSlhDsa_Shake_192f_KeyPair() + { + return slhDsa_Shake_192f_Kpg.generateKeyPair(); + } + + public static KeyPair makeSlhDsa_Shake_192s_KeyPair() + { + return slhDsa_Shake_192s_Kpg.generateKeyPair(); + } + + public static KeyPair makeSlhDsa_Shake_256f_KeyPair() + { + return slhDsa_Shake_256f_Kpg.generateKeyPair(); + } + + public static KeyPair makeSlhDsa_Shake_256s_KeyPair() + { + return slhDsa_Shake_256s_Kpg.generateKeyPair(); } public static SecretKey makeDesede128Key() @@ -504,6 +632,10 @@ public static X509Certificate makeOaepCertificate(KeyPair subKP, String _subDN, private static JcaContentSignerBuilder makeContentSignerBuilder(PublicKey issPub) { + /* + * NOTE: Current ALL test certificates are issued under a SHA1withRSA root, so this list is mostly + * redundant (and also incomplete in that it doesn't handle EdDSA or ML-DSA issuers). + */ JcaContentSignerBuilder contentSignerBuilder; if (issPub instanceof RSAPublicKey) { @@ -521,10 +653,14 @@ else if (issPub.getAlgorithm().equals("ECGOST3410")) { contentSignerBuilder = new JcaContentSignerBuilder("GOST3411withECGOST3410"); } - else + else if (issPub.getAlgorithm().equals("GOST3410")) { contentSignerBuilder = new JcaContentSignerBuilder("GOST3411WithGOST3410"); } + else + { + throw new UnsupportedOperationException("Algorithm handlers incomplete"); + } contentSignerBuilder.setProvider(BouncyCastleProvider.PROVIDER_NAME); diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/GOSTR3410_2012_256CmsSignVerifyDetached.java b/pkix/src/test/java/org/bouncycastle/cms/test/GOSTR3410_2012_256CmsSignVerifyDetached.java index a82ea627cd..91918de68b 100644 --- a/pkix/src/test/java/org/bouncycastle/cms/test/GOSTR3410_2012_256CmsSignVerifyDetached.java +++ b/pkix/src/test/java/org/bouncycastle/cms/test/GOSTR3410_2012_256CmsSignVerifyDetached.java @@ -9,6 +9,7 @@ import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; +import java.util.Date; import java.util.HashSet; import java.util.List; @@ -121,9 +122,13 @@ private static boolean verifyDetached(byte[] data, byte[] detachedCms, // Validate signer's certificate chain X509CertSelector constraints = new X509CertSelector(); - constraints.setCertificate(getX509Certificate(signerCert)); + X509Certificate x509Certificate = getX509Certificate(signerCert); + constraints.setCertificate(x509Certificate); + PKIXBuilderParameters params = new PKIXBuilderParameters(trustAnchors, constraints); + params.setDate(new Date(x509Certificate.getNotAfter().getTime() - 5000L)); + JcaCertStoreBuilder certStoreBuilder = new JcaCertStoreBuilder(); certStoreBuilder.addCertificate(signerCert); diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/NewAuthEnvelopedDataStreamTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/NewAuthEnvelopedDataStreamTest.java index bb6911e39f..1ab81dbfa5 100644 --- a/pkix/src/test/java/org/bouncycastle/cms/test/NewAuthEnvelopedDataStreamTest.java +++ b/pkix/src/test/java/org/bouncycastle/cms/test/NewAuthEnvelopedDataStreamTest.java @@ -8,8 +8,10 @@ import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Collection; +import java.util.Date; import java.util.Hashtable; import java.util.Iterator; +import java.util.Map; import javax.crypto.SecretKey; @@ -23,16 +25,26 @@ import org.bouncycastle.asn1.DERUTF8String; import org.bouncycastle.asn1.cms.Attribute; import org.bouncycastle.asn1.cms.AttributeTable; +import org.bouncycastle.asn1.cms.CMSAttributes; +import org.bouncycastle.asn1.cms.Time; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cms.CMSAlgorithm; +import org.bouncycastle.cms.CMSAttributeTableGenerationException; +import org.bouncycastle.cms.CMSAttributeTableGenerator; +import org.bouncycastle.cms.CMSAuthEnvelopedData; +import org.bouncycastle.cms.CMSAuthEnvelopedDataGenerator; import org.bouncycastle.cms.CMSAuthEnvelopedDataParser; import org.bouncycastle.cms.CMSAuthEnvelopedDataStreamGenerator; +import org.bouncycastle.cms.CMSAuthenticatedDataGenerator; import org.bouncycastle.cms.CMSEnvelopedDataParser; import org.bouncycastle.cms.CMSEnvelopedDataStreamGenerator; +import org.bouncycastle.cms.CMSProcessableByteArray; import org.bouncycastle.cms.CMSTypedStream; import org.bouncycastle.cms.KEKRecipientId; import org.bouncycastle.cms.OriginatorInfoGenerator; +import org.bouncycastle.cms.PasswordRecipient; +import org.bouncycastle.cms.PasswordRecipientInformation; import org.bouncycastle.cms.RecipientId; import org.bouncycastle.cms.RecipientInformation; import org.bouncycastle.cms.RecipientInformationStore; @@ -46,8 +58,12 @@ import org.bouncycastle.cms.jcajce.JceKeyTransAuthEnvelopedRecipient; import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient; import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator; +import org.bouncycastle.cms.jcajce.JcePasswordAuthEnvelopedRecipient; +import org.bouncycastle.cms.jcajce.JcePasswordRecipientInfoGenerator; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.operator.OutputAEADEncryptor; +import org.bouncycastle.operator.OutputEncryptor; +import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; public class NewAuthEnvelopedDataStreamTest @@ -212,7 +228,7 @@ public void testKeyTransAES128GCM() ByteArrayOutputStream bOut = new ByteArrayOutputStream(); JceCMSContentEncryptorBuilder encryptorBuilder = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_GCM); - OutputStream out = edGen.open(bOut, (OutputAEADEncryptor) encryptorBuilder.setProvider(BC).build()); + OutputStream out = edGen.open(bOut, (OutputAEADEncryptor)encryptorBuilder.setProvider(BC).build()); for (int i = 0; i != 2000; i++) { @@ -234,7 +250,7 @@ public void testKeyTransAES128GCM() bOut = new ByteArrayOutputStream(); - out = edGen.open(bOut, (OutputAEADEncryptor) encryptorBuilder.setProvider(BC).build()); + out = edGen.open(bOut, (OutputAEADEncryptor)encryptorBuilder.setProvider(BC).build()); BufferedOutputStream bfOut = new BufferedOutputStream(out, 300); @@ -267,7 +283,7 @@ public void testKeyTransAES128Der() ByteArrayOutputStream bOut = new ByteArrayOutputStream(); JceCMSContentEncryptorBuilder encryptorBuilder = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_GCM); - OutputStream out = edGen.open(bOut, (OutputAEADEncryptor) encryptorBuilder.setProvider(BC).build()); + OutputStream out = edGen.open(bOut, (OutputAEADEncryptor)encryptorBuilder.setProvider(BC).build()); for (int i = 0; i != 2000; i++) { @@ -308,7 +324,7 @@ public void testKeyTransAES128Throughput() ByteArrayOutputStream bOut = new ByteArrayOutputStream(); JceCMSContentEncryptorBuilder encryptorBuilder = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_GCM); - OutputStream out = edGen.open(bOut, (OutputAEADEncryptor) encryptorBuilder.setProvider(BC).build()); + OutputStream out = edGen.open(bOut, (OutputAEADEncryptor)encryptorBuilder.setProvider(BC).build()); for (int i = 0; i != data.length; i++) { @@ -329,7 +345,7 @@ public void testKeyTransAES128Throughput() assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId()); CMSTypedStream recData = recipient.getContentStream( - new JceKeyTransAuthEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC)); + new JceKeyTransAuthEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC)); InputStream dataStream = recData.getContentStream(); ByteArrayOutputStream dataOut = new ByteArrayOutputStream(); @@ -372,7 +388,7 @@ public void testKeyTransAES128AndOriginatorInfo() ByteArrayOutputStream bOut = new ByteArrayOutputStream(); JceCMSContentEncryptorBuilder encryptorBuilder = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_GCM); - OutputStream out = edGen.open(bOut, (OutputAEADEncryptor) encryptorBuilder.setProvider(BC).build()); + OutputStream out = edGen.open(bOut, (OutputAEADEncryptor)encryptorBuilder.setProvider(BC).build()); out.write(data); @@ -396,7 +412,7 @@ public void testKeyTransAES128AndOriginatorInfo() assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId()); CMSTypedStream recData = recipient.getContentStream( - new JceKeyTransAuthEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC)); + new JceKeyTransAuthEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC)); assertTrue(Arrays.equals(data, CMSTestUtil.streamToByteArray(recData.getContentStream()))); } @@ -416,7 +432,7 @@ public void testKeyTransAES128() ByteArrayOutputStream bOut = new ByteArrayOutputStream(); JceCMSContentEncryptorBuilder encryptorBuilder = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_GCM); - OutputStream out = edGen.open(bOut, (OutputAEADEncryptor) encryptorBuilder.setProvider(BC).build()); + OutputStream out = edGen.open(bOut, (OutputAEADEncryptor)encryptorBuilder.setProvider(BC).build()); out.write(data); @@ -460,7 +476,7 @@ public void testAESKEK() ByteArrayOutputStream bOut = new ByteArrayOutputStream(); JceCMSContentEncryptorBuilder encryptorBuilder = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_GCM); - OutputStream out = edGen.open(bOut, (OutputAEADEncryptor) encryptorBuilder.setProvider(BC).build()); + OutputStream out = edGen.open(bOut, (OutputAEADEncryptor)encryptorBuilder.setProvider(BC).build()); out.write(data); @@ -487,6 +503,48 @@ public void testAESKEK() ep.close(); } + public void testChaCha20Poly1305KEK() + throws Exception + { + byte[] data = "WallaWallaWashington".getBytes(); + SecretKey kek = CMSTestUtil.makeAES192Key(); + + CMSAuthEnvelopedDataStreamGenerator edGen = new CMSAuthEnvelopedDataStreamGenerator(); + + byte[] kekId = new byte[]{1, 2, 3, 4, 5}; + + edGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId, kek).setProvider(BC)); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + JceCMSContentEncryptorBuilder encryptorBuilder = new JceCMSContentEncryptorBuilder(CMSAlgorithm.ChaCha20Poly1305); + OutputStream out = edGen.open(bOut, (OutputAEADEncryptor)encryptorBuilder.setProvider(BC).build()); + + out.write(data); + + out.close(); + + CMSAuthEnvelopedDataParser ep = new CMSAuthEnvelopedDataParser(bOut.toByteArray()); + + RecipientInformationStore recipients = ep.getRecipientInfos(); + + assertEquals(ep.getEncAlgOID(), CMSAlgorithm.ChaCha20Poly1305.getId()); + + Collection c = recipients.getRecipients(); + Iterator it = c.iterator(); + + while (it.hasNext()) + { + RecipientInformation recipient = it.next(); + + CMSTypedStream recData = recipient.getContentStream(new JceKEKAuthEnvelopedRecipient(kek).setProvider(BC)); + + assertTrue(Arrays.equals(data, CMSTestUtil.streamToByteArray(recData.getContentStream()))); + } + + ep.close(); + } + public void testTwoAESKEK() throws Exception { @@ -505,7 +563,7 @@ public void testTwoAESKEK() ByteArrayOutputStream bOut = new ByteArrayOutputStream(); JceCMSContentEncryptorBuilder encryptorBuilder = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES192_GCM); - OutputStream out = edGen.open(bOut, (OutputAEADEncryptor) encryptorBuilder.setProvider(BC).build()); + OutputStream out = edGen.open(bOut, (OutputAEADEncryptor)encryptorBuilder.setProvider(BC).build()); out.write(data); out.close(); @@ -535,8 +593,8 @@ public void testECKeyAgree() CMSAuthEnvelopedDataStreamGenerator edGen = new CMSAuthEnvelopedDataStreamGenerator(); JceKeyAgreeRecipientInfoGenerator recipientGenerator = new JceKeyAgreeRecipientInfoGenerator( - CMSAlgorithm.ECDH_SHA1KDF, _origEcKP.getPrivate(), _origEcKP.getPublic(), - CMSAlgorithm.AES128_WRAP).setProvider(BC); + CMSAlgorithm.ECDH_SHA1KDF, _origEcKP.getPrivate(), _origEcKP.getPublic(), + CMSAlgorithm.AES128_WRAP).setProvider(BC); recipientGenerator.addRecipient(_reciEcCert); @@ -545,7 +603,7 @@ public void testECKeyAgree() ByteArrayOutputStream bOut = new ByteArrayOutputStream(); JceCMSContentEncryptorBuilder encryptorBuilder = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_GCM); - OutputStream out = edGen.open(bOut, (OutputAEADEncryptor) encryptorBuilder.setProvider(BC).build()); + OutputStream out = edGen.open(bOut, (OutputAEADEncryptor)encryptorBuilder.setProvider(BC).build()); out.write(data); out.close(); @@ -561,16 +619,129 @@ public void testECKeyAgree() RecipientInformation recipient = recipients.get(recSel); CMSTypedStream recData = recipient.getContentStream( - new JceKeyAgreeAuthEnvelopedRecipient(_reciEcKP.getPrivate()).setProvider(BC)); + new JceKeyAgreeAuthEnvelopedRecipient(_reciEcKP.getPrivate()).setProvider(BC)); + + assertEquals(true, Arrays.equals(data, CMSTestUtil.streamToByteArray(recData.getContentStream()))); + + ep.close(); + } + + public void testECKeyAgreeChacha20Poly1305() + throws Exception + { + byte[] data = Hex.decode("504b492d4320434d5320456e76656c6f706564446174612053616d706c65"); + + CMSAuthEnvelopedDataStreamGenerator edGen = new CMSAuthEnvelopedDataStreamGenerator(); + + JceKeyAgreeRecipientInfoGenerator recipientGenerator = new JceKeyAgreeRecipientInfoGenerator( + CMSAlgorithm.ECDH_SHA1KDF, _origEcKP.getPrivate(), _origEcKP.getPublic(), + CMSAlgorithm.AES128_WRAP).setProvider(BC); + + recipientGenerator.addRecipient(_reciEcCert); + + edGen.addRecipientInfoGenerator(recipientGenerator); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + JceCMSContentEncryptorBuilder encryptorBuilder = new JceCMSContentEncryptorBuilder(CMSAlgorithm.ChaCha20Poly1305); + OutputStream out = edGen.open(bOut, (OutputAEADEncryptor)encryptorBuilder.setProvider(BC).build()); + out.write(data); + + out.close(); + + CMSAuthEnvelopedDataParser ep = new CMSAuthEnvelopedDataParser(bOut.toByteArray()); + + RecipientInformationStore recipients = ep.getRecipientInfos(); + + assertEquals(ep.getEncAlgOID(), CMSAlgorithm.ChaCha20Poly1305.getId()); + + RecipientId recSel = new JceKeyAgreeRecipientId(_reciEcCert); + + RecipientInformation recipient = recipients.get(recSel); + + CMSTypedStream recData = recipient.getContentStream( + new JceKeyAgreeAuthEnvelopedRecipient(_reciEcKP.getPrivate()).setProvider(BC)); assertEquals(true, Arrays.equals(data, CMSTestUtil.streamToByteArray(recData.getContentStream()))); ep.close(); } + public void testPasswordChaCha20Poly1305() + throws Exception + { + if (!CMSTestUtil.isAeadAvailable()) + { + return; + } + byte[] message = Strings.toByteArray("Hello, world!"); + OutputEncryptor candidate = new JceCMSContentEncryptorBuilder(CMSAlgorithm.ChaCha20Poly1305).setProvider(BC).build(); + + assertEquals(CMSAlgorithm.ChaCha20Poly1305, candidate.getAlgorithmIdentifier().getAlgorithm()); + //assertNotNull(GCMParameters.getInstance(candidate.getAlgorithmIdentifier().getParameters())); + + assertTrue(candidate instanceof OutputAEADEncryptor); + + OutputAEADEncryptor macProvider = (OutputAEADEncryptor)candidate; + + CMSAuthEnvelopedDataGenerator authGen = new CMSAuthEnvelopedDataGenerator(); + + authGen.setAuthenticatedAttributeGenerator(new CMSAttributeTableGenerator() + { + public AttributeTable getAttributes(Map parameters) + throws CMSAttributeTableGenerationException + { + Hashtable attrs = new Hashtable(); + Attribute testAttr = new Attribute(CMSAttributes.signingTime, + new DERSet(new Time(new Date()))); + attrs.put(testAttr.getAttrType(), testAttr); + return new AttributeTable(attrs); + } + }); + + authGen.addRecipientInfoGenerator(new JcePasswordRecipientInfoGenerator(new ASN1ObjectIdentifier(CMSAuthenticatedDataGenerator.AES256_CBC), + "password".toCharArray()).setProvider(BC).setSaltAndIterationCount(new byte[20], 5)); + + CMSAuthEnvelopedData authData = authGen.generate(new CMSProcessableByteArray(message), macProvider); + + CMSAuthEnvelopedData encAuthData = new CMSAuthEnvelopedData(authData.getEncoded()); + + RecipientInformationStore recipients = encAuthData.getRecipientInfos(); + + Collection c = recipients.getRecipients(); + Iterator it = c.iterator(); + + if (it.hasNext()) + { + PasswordRecipientInformation recipient = (PasswordRecipientInformation)it.next(); + + PasswordRecipient pbeRep = new JcePasswordAuthEnvelopedRecipient("password".toCharArray()).setProvider(BC); + + byte[] recData = recipient.getContent(pbeRep); + + assertTrue(Arrays.equals(message, recData)); + assertTrue(Arrays.equals(authData.getMac(), recipient.getMac())); + } + else + { + fail("no recipient found"); + } + } + public static Test suite() throws Exception { return new CMSTestSetup(new TestSuite(NewAuthEnvelopedDataStreamTest.class)); } + +// public static void main(String[] args) +// throws Exception +// { +// NewAuthEnvelopedDataStreamTest test = new NewAuthEnvelopedDataStreamTest(); +// test.setUp(); +// test.testPasswordChaCha20Poly1305(); +// test.testECKeyAgreeChacha20Poly1305(); +// test.testChaCha20Poly1305KEK(); +// System.out.println("OK"); +// } } diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataStreamTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataStreamTest.java index 4786f62f30..eb265f17fb 100644 --- a/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataStreamTest.java +++ b/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataStreamTest.java @@ -22,6 +22,7 @@ import junit.framework.TestSuite; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERSet; import org.bouncycastle.asn1.DERUTF8String; import org.bouncycastle.asn1.cms.Attribute; @@ -253,6 +254,24 @@ public void testUnprotectedAttributes() public void testKeyTransAES128GCM() throws Exception + { + implTestKeyTrans(CMSAlgorithm.AES128_GCM); + } + + public void testKeyTransAES192GCM() + throws Exception + { + implTestKeyTrans(CMSAlgorithm.AES192_GCM); + } + + public void testKeyTransAES256GCM() + throws Exception + { + implTestKeyTrans(CMSAlgorithm.AES256_GCM); + } + + private void implTestKeyTrans(ASN1ObjectIdentifier contentEncryptionOID) + throws Exception { byte[] data = new byte[2000]; @@ -271,7 +290,7 @@ public void testKeyTransAES128GCM() ByteArrayOutputStream bOut = new ByteArrayOutputStream(); OutputStream out = edGen.open( - bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_GCM).setProvider(BC).build()); + bOut, new JceCMSContentEncryptorBuilder(contentEncryptionOID).setProvider(BC).build()); for (int i = 0; i != 2000; i++) { @@ -280,7 +299,7 @@ public void testKeyTransAES128GCM() out.close(); - verifyData(bOut, CMSAlgorithm.AES128_GCM.getId(), data); + verifyData(bOut, contentEncryptionOID.getId(), data); int unbufferedLength = bOut.toByteArray().length; @@ -293,7 +312,7 @@ public void testKeyTransAES128GCM() bOut = new ByteArrayOutputStream(); - out = edGen.open(bOut, new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_GCM).setProvider(BC).build()); + out = edGen.open(bOut, new JceCMSContentEncryptorBuilder(contentEncryptionOID).setProvider(BC).build()); BufferedOutputStream bfOut = new BufferedOutputStream(out, 300); @@ -304,7 +323,7 @@ public void testKeyTransAES128GCM() bfOut.close(); - verifyData(bOut, CMSAlgorithm.AES128_GCM.getId(), data); + verifyData(bOut, contentEncryptionOID.getId(), data); assertTrue(bOut.toByteArray().length == unbufferedLength); } @@ -756,6 +775,49 @@ public void testTwoAESKEK() ep.close(); } + public void testTwoAESKEKWithPrecomputedContentKey() + throws Exception + { + byte[] data = "WallaWallaWashington".getBytes(); + SecretKey kek1 = CMSTestUtil.makeAES192Key(); + SecretKey kek2 = CMSTestUtil.makeAES192Key(); + + CMSEnvelopedDataStreamGenerator edGen = new CMSEnvelopedDataStreamGenerator(); + + byte[] kekId1 = new byte[]{1, 2, 3, 4, 5}; + byte[] kekId2 = new byte[]{5, 4, 3, 2, 1}; + + edGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId1, kek1).setProvider(BC)); + edGen.addRecipientInfoGenerator(new JceKEKRecipientInfoGenerator(kekId2, kek2).setProvider(BC)); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + OutputStream out = edGen.open( + bOut, + new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES128_CBC).setProvider(BC).build(Hex.decode("000102030405060708090a0b0c0d0e0f"))); + out.write(data); + + out.close(); + + CMSEnvelopedDataParser ep = new CMSEnvelopedDataParser(bOut.toByteArray()); + + RecipientInformationStore recipients = ep.getRecipientInfos(); + + assertEquals(ep.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES128_CBC); + + RecipientId recSel = new KEKRecipientId(kekId2); + + RecipientInformation recipient = recipients.get(recSel); + + assertEquals(recipient.getKeyEncryptionAlgOID(), "2.16.840.1.101.3.4.1.25"); + + CMSTypedStream recData = recipient.getContentStream(new JceKEKEnvelopedRecipient(kek2).setProvider(BC)); + + assertEquals(true, Arrays.equals(data, CMSTestUtil.streamToByteArray(recData.getContentStream()))); + + ep.close(); + } + public void testECKeyAgree() throws Exception { diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java index b973fe8f3f..ca85c988a0 100644 --- a/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java +++ b/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java @@ -130,8 +130,10 @@ public class NewEnvelopedDataTest private static String _reciDN; private static String _reciDN2; private static KeyPair _reciKP; + private static KeyPair _reciKP_2048; private static KeyPair _reciOaepKP; private static X509Certificate _reciCert; + private static X509Certificate _reciCert_2048; private static X509Certificate _reciCertOaep; private static KeyPair _origEcKP; @@ -143,8 +145,12 @@ public class NewEnvelopedDataTest private static X509Certificate _reciKemsCert; private static KeyPair _reciNtruKP; private static X509Certificate _reciNtruCert; - private static KeyPair _reciMLKemKP; - private static X509Certificate _reciMLKemCert; + private static KeyPair _reciMLKem512KP; + private static X509Certificate _reciMLKem512Cert; + private static KeyPair _reciMLKem768KP; + private static X509Certificate _reciMLKem768Cert; + private static KeyPair _reciMLKem1024KP; + private static X509Certificate _reciMLKem1024Cert; private static KeyPair _origDhKP; private static KeyPair _reciDhKP; @@ -590,7 +596,9 @@ private static void init() _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU"; _reciDN2 = "CN=Fred, OU=Sales, O=Bouncy Castle, C=AU"; _reciKP = CMSTestUtil.makeKeyPair(); + _reciKP_2048 = CMSTestUtil.makeKeyPair_2048(); _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN); + _reciCert_2048 = CMSTestUtil.makeCertificate(_reciKP_2048, _reciDN, _signKP, _signDN); _reciCertOaep = CMSTestUtil.makeOaepCertificate(_reciKP, _reciDN, _signKP, _signDN); _origEcKP = CMSTestUtil.makeEcDsaKeyPair(); @@ -609,8 +617,14 @@ private static void init() _reciNtruKP = CMSTestUtil.makeNtruKeyPair(); _reciNtruCert = CMSTestUtil.makeCertificate(_reciNtruKP, _reciDN, _signKP, _signDN); - _reciMLKemKP = CMSTestUtil.makeMLKemKeyPair(); - _reciMLKemCert = CMSTestUtil.makeCertificate(_reciMLKemKP, _reciDN, _signKP, _signDN); + _reciMLKem512KP = CMSTestUtil.makeMLKem512KeyPair(); + _reciMLKem512Cert = CMSTestUtil.makeCertificate(_reciMLKem512KP, _reciDN, _signKP, _signDN); + + _reciMLKem768KP = CMSTestUtil.makeMLKem768KeyPair(); + _reciMLKem768Cert = CMSTestUtil.makeCertificate(_reciMLKem768KP, _reciDN, _signKP, _signDN); + + _reciMLKem1024KP = CMSTestUtil.makeMLKem1024KeyPair(); + _reciMLKem1024Cert = CMSTestUtil.makeCertificate(_reciMLKem1024KP, _reciDN, _signKP, _signDN); } } @@ -716,7 +730,7 @@ public void testContentType() } } - public void testMLKem() + public void testMLKem512() throws Exception { byte[] data = "WallaWallaWashington".getBytes(); @@ -725,8 +739,8 @@ public void testMLKem() CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator(); // note: use cert req ID as key ID, don't want to use issuer/serial in this case! - edGen.addRecipientInfoGenerator(new JceKEMRecipientInfoGenerator(_reciMLKemCert, CMSAlgorithm.AES256_WRAP).setKDF( - new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256))); + edGen.addRecipientInfoGenerator(new JceKEMRecipientInfoGenerator(_reciMLKem512Cert, CMSAlgorithm.AES128_WRAP) + .setKDF(CMSAlgorithm.SHA256_HKDF)); CMSEnvelopedData ed = edGen.generate( new CMSProcessableByteArray(data), @@ -743,17 +757,108 @@ public void testMLKem() Iterator it = c.iterator(); int expectedLength = new DefaultKemEncapsulationLengthProvider().getEncapsulationLength( - SubjectPublicKeyInfo.getInstance(_reciMLKemKP.getPublic().getEncoded()).getAlgorithm()); + SubjectPublicKeyInfo.getInstance(_reciMLKem512KP.getPublic().getEncoded()).getAlgorithm()); + + while (it.hasNext()) + { + KEMRecipientInformation recipient = (KEMRecipientInformation)it.next(); + + assertEquals(expectedLength, recipient.getEncapsulation().length); + + assertEquals(NISTObjectIdentifiers.id_alg_ml_kem_512.getId(), recipient.getKeyEncryptionAlgOID()); + + CMSTypedStream contentStream = recipient.getContentStream( + new JceKEMEnvelopedRecipient(_reciMLKem512KP.getPrivate()).setProvider(BC)); + + assertEquals(PKCSObjectIdentifiers.data, contentStream.getContentType()); + assertEquals(true, Arrays.equals(data, Streams.readAll(contentStream.getContentStream()))); + } + } + + public void testMLKem768() + throws Exception + { + byte[] data = "WallaWallaWashington".getBytes(); + + // Send response with encrypted certificate + CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator(); + + // note: use cert req ID as key ID, don't want to use issuer/serial in this case! + edGen.addRecipientInfoGenerator(new JceKEMRecipientInfoGenerator(_reciMLKem768Cert, CMSAlgorithm.AES256_WRAP) + .setKDF(CMSAlgorithm.SHA256_HKDF)); + + CMSEnvelopedData ed = edGen.generate( + new CMSProcessableByteArray(data), + new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES256_CBC).setProvider("BC").build()); + + RecipientInformationStore recipients = ed.getRecipientInfos(); + + assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES256_CBC); + + Collection c = recipients.getRecipients(); + + assertEquals(1, c.size()); + + Iterator it = c.iterator(); + + int expectedLength = new DefaultKemEncapsulationLengthProvider().getEncapsulationLength( + SubjectPublicKeyInfo.getInstance(_reciMLKem768KP.getPublic().getEncoded()).getAlgorithm()); while (it.hasNext()) { KEMRecipientInformation recipient = (KEMRecipientInformation)it.next(); assertEquals(expectedLength, recipient.getEncapsulation().length); - + assertEquals(NISTObjectIdentifiers.id_alg_ml_kem_768.getId(), recipient.getKeyEncryptionAlgOID()); - CMSTypedStream contentStream = recipient.getContentStream(new JceKEMEnvelopedRecipient(_reciMLKemKP.getPrivate()).setProvider(BC)); + CMSTypedStream contentStream = recipient.getContentStream( + new JceKEMEnvelopedRecipient(_reciMLKem768KP.getPrivate()).setProvider(BC)); + + assertEquals(PKCSObjectIdentifiers.data, contentStream.getContentType()); + assertEquals(true, Arrays.equals(data, Streams.readAll(contentStream.getContentStream()))); + } + } + + public void testMLKem1024() + throws Exception + { + byte[] data = "WallaWallaWashington".getBytes(); + + // Send response with encrypted certificate + CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator(); + + // note: use cert req ID as key ID, don't want to use issuer/serial in this case! + edGen.addRecipientInfoGenerator(new JceKEMRecipientInfoGenerator(_reciMLKem1024Cert, CMSAlgorithm.AES256_WRAP) + .setKDF(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_alg_hkdf_with_sha256))); + + CMSEnvelopedData ed = edGen.generate( + new CMSProcessableByteArray(data), + new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES256_CBC).setProvider("BC").build()); + + RecipientInformationStore recipients = ed.getRecipientInfos(); + + assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.AES256_CBC); + + Collection c = recipients.getRecipients(); + + assertEquals(1, c.size()); + + Iterator it = c.iterator(); + + int expectedLength = new DefaultKemEncapsulationLengthProvider().getEncapsulationLength( + SubjectPublicKeyInfo.getInstance(_reciMLKem1024KP.getPublic().getEncoded()).getAlgorithm()); + + while (it.hasNext()) + { + KEMRecipientInformation recipient = (KEMRecipientInformation)it.next(); + + assertEquals(expectedLength, recipient.getEncapsulation().length); + + assertEquals(NISTObjectIdentifiers.id_alg_ml_kem_1024.getId(), recipient.getKeyEncryptionAlgOID()); + + CMSTypedStream contentStream = recipient.getContentStream( + new JceKEMEnvelopedRecipient(_reciMLKem1024KP.getPrivate()).setProvider(BC)); assertEquals(PKCSObjectIdentifiers.data, contentStream.getContentType()); assertEquals(true, Arrays.equals(data, Streams.readAll(contentStream.getContentStream()))); @@ -1012,19 +1117,25 @@ public void testKeyTransOAEPSHA256() doTestKeyTransOAEPDefaultNamed("SHA-256"); } - public void testKeyTransOAEPSHA1AndSHA256() + public void testKeyTransOAEPSHA384() throws Exception { - doTestKeyTransOAEPDefaultNamed("SHA-1", "SHA-256"); + doTestKeyTransOAEPDefaultNamed("SHA-384"); } - private void doTestKeyTransOAEPDefaultNamed(String digest) + public void testKeyTransOAEPSHA512() throws Exception { - doTestKeyTransOAEPDefaultNamed(digest, digest); + doTestKeyTransOAEPDefaultNamed_2048("SHA-512"); } - private void doTestKeyTransOAEPDefaultNamed(String digest, String mgfDigest) + public void testKeyTransOAEPSHA1AndSHA256() + throws Exception + { + doTestKeyTransOAEPDefaultNamed("SHA-1", "SHA-256"); + } + + private void doTestKeyTransOAEPDefaultNamed(String digest, String mgfDigest, X509Certificate reciCert, KeyPair reciKP) throws Exception { byte[] data = "WallaWallaWashington".getBytes(); @@ -1035,8 +1146,8 @@ private void doTestKeyTransOAEPDefaultNamed(String digest, String mgfDigest) 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); - edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert, oaepAlgId).setProvider(BC)); - edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCert.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), oaepAlgId, _reciCert.getPublicKey()).setProvider(BC)); + edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(reciCert, oaepAlgId).setProvider(BC)); + 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), @@ -1059,12 +1170,12 @@ private void doTestKeyTransOAEPDefaultNamed(String digest, String mgfDigest) 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)); } - RecipientId id = new JceKeyTransRecipientId(_reciCert); + RecipientId id = new JceKeyTransRecipientId(reciCert); Collection collection = recipients.getRecipients(id); if (collection.size() != 2) @@ -1074,6 +1185,30 @@ private void doTestKeyTransOAEPDefaultNamed(String digest, String mgfDigest) assertTrue(collection.iterator().next() instanceof RecipientInformation); } + private void doTestKeyTransOAEPDefaultNamed(String digest) + throws Exception + { + doTestKeyTransOAEPDefaultNamed(digest, digest); + } + + private void doTestKeyTransOAEPDefaultNamed(String digest, String mgfDigest) + throws Exception + { + doTestKeyTransOAEPDefaultNamed(digest, digest, _reciCert, _reciKP); + } + + private void doTestKeyTransOAEPDefaultNamed_2048(String digest) + throws Exception + { + doTestKeyTransOAEPDefaultNamed_2048(digest, digest); + } + + private void doTestKeyTransOAEPDefaultNamed_2048(String digest, String mgfDigest) + throws Exception + { + doTestKeyTransOAEPDefaultNamed(digest, digest, _reciCert_2048, _reciKP_2048); + } + public void testKeyTransOAEPInCert() throws Exception { @@ -1670,18 +1805,22 @@ public void testAES128KEK() { tryKekAlgorithm(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap); - tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES128_GCM, NISTObjectIdentifiers.id_aes128_GCM); - 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); + tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES128_GCM, CMSAlgorithm.AES128_GCM); + tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES192_GCM, CMSAlgorithm.AES192_GCM); + tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES256_GCM, CMSAlgorithm.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_GCM, CMSAlgorithm.AES128_GCM, new GCMParameters(nonce, 11).getEncoded()); + tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES192_GCM, CMSAlgorithm.AES192_GCM, new GCMParameters(nonce, 11).getEncoded()); + tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES256_GCM, CMSAlgorithm.AES256_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, CMSAlgorithm.AES128_CCM); + tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES192_CCM, CMSAlgorithm.AES192_CCM); + tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES256_CCM, CMSAlgorithm.AES256_CCM); - tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES128_CCM, NISTObjectIdentifiers.id_aes128_CCM, new CCMParameters(nonce, 14).getEncoded()); + tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES128_CCM, CMSAlgorithm.AES128_CCM, new CCMParameters(nonce, 14).getEncoded()); + tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES192_CCM, CMSAlgorithm.AES192_CCM, new CCMParameters(nonce, 14).getEncoded()); + tryKekAlgorithmAEAD(CMSTestUtil.makeAESKey(128), NISTObjectIdentifiers.id_aes128_wrap, CMSAlgorithm.AES256_CCM, CMSAlgorithm.AES256_CCM, new CCMParameters(nonce, 14).getEncoded()); } public void testAES192KEK() diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataStreamTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataStreamTest.java index b11de46a3f..d2814fe2ee 100644 --- a/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataStreamTest.java +++ b/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataStreamTest.java @@ -32,6 +32,8 @@ import org.bouncycastle.asn1.cms.CMSAttributes; import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; import org.bouncycastle.asn1.ocsp.OCSPResponse; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.cert.X509AttributeCertificateHolder; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaCRLStore; @@ -209,8 +211,45 @@ private void verifySignatures(CMSSignedDataParser sp, byte[] contentDigest) assertEquals(certStore.getMatches(null).size(), sp.getCertificates().getMatches(null).size()); assertEquals(crlStore.getMatches(null).size(), sp.getCRLs().getMatches(null).size()); } - - private void verifySignatures(CMSSignedDataParser sp) + + private void verifySignatures(CMSSignedDataParser sp, byte[] contentDigest, boolean ignoreCounterSig) + throws Exception + { + Store certStore = sp.getCertificates(); + Store crlStore = sp.getCRLs(); + SignerInformationStore signers = sp.getSignerInfos(); + + Set digestIDs = new HashSet(sp.getDigestAlgorithmIDs()); + + assertTrue(digestIDs.size() > 0); + + Collection c = signers.getSigners(); + Iterator it = c.iterator(); + + while (it.hasNext()) + { + SignerInformation signer = (SignerInformation)it.next(); + Collection certCollection = certStore.getMatches(signer.getSID()); + + Iterator certIt = certCollection.iterator(); + X509CertificateHolder cert = (X509CertificateHolder)certIt.next(); + + assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert))); + + digestIDs.remove(signer.getDigestAlgorithmID()); + + if (contentDigest != null) + { + assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest())); + } + } + + assertTrue(digestIDs.size() > 0); + assertEquals(certStore.getMatches(null).size(), sp.getCertificates().getMatches(null).size()); + assertEquals(crlStore.getMatches(null).size(), sp.getCRLs().getMatches(null).size()); + } + + private void verifySignatures(CMSSignedDataParser sp) throws Exception { verifySignatures(sp, null); @@ -364,7 +403,126 @@ public void testDSANoAttributes() verifySignatures(sp, md.digest(TEST_MESSAGE.getBytes())); } - + + public void testAddDigestAlgorithm() + throws Exception + { + List certList = new ArrayList(); + List crlList = new ArrayList(); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + certList.add(_origCert); + certList.add(_signCert); + + crlList.add(_signCrl); + crlList.add(_origCrl); + + Store certs = new JcaCertStore(certList); + Store crls = new JcaCRLStore(crlList); + + CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator(); + + ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(BC).build(_origKP.getPrivate()); + + gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(sha1Signer, _origCert)); + gen.addCertificates(certs); + + gen.addCRLs(crls); + + Set oids = new HashSet(); + oids.add(new AlgorithmIdentifier(PKCSObjectIdentifiers.sha256WithRSAEncryption)); + gen.addDigestAlgorithms(oids); + + OutputStream sigOut = gen.open(bOut); + + sigOut.write(TEST_MESSAGE.getBytes()); + + sigOut.close(); + + checkSigParseable(bOut.toByteArray()); + + CMSSignedDataParser sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), + new CMSTypedStream(new ByteArrayInputStream(TEST_MESSAGE.getBytes())), bOut.toByteArray()); + + sp.getSignedContent().drain(); + + // + // compute expected content digest + // + MessageDigest md1 = MessageDigest.getInstance("SHA1", BC); + verifySignatures(sp, md1.digest(TEST_MESSAGE.getBytes()), true); + + + // + // try using existing signer + // + gen = new CMSSignedDataStreamGenerator(); + + gen.addSigners(sp.getSignerInfos()); + + gen.addCertificates(sp.getCertificates()); + gen.addCRLs(sp.getCRLs()); + + bOut.reset(); + + sigOut = gen.open(bOut, true); + + sigOut.write(TEST_MESSAGE.getBytes()); + + sigOut.close(); + + verifyEncodedData(bOut); + sp = new CMSSignedDataParser(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(), + new CMSTypedStream(new ByteArrayInputStream(TEST_MESSAGE.getBytes())), bOut.toByteArray()); + + sp.getSignedContent().drain(); + + // + // look for the CRLs + // + Collection col = sp.getCRLs().getMatches(null); + + assertEquals(2, col.size()); + assertTrue(col.contains(new JcaX509CRLHolder(_signCrl))); + assertTrue(col.contains(new JcaX509CRLHolder(_origCrl))); + } + + private void verifySignatures2(CMSSignedDataParser sp, byte[] contentDigest1, byte[] contentDigest2) + throws Exception + { + Store certStore = sp.getCertificates(); + Store crlStore = sp.getCRLs(); + SignerInformationStore signers = sp.getSignerInfos(); + + Set digestIDs = new HashSet(sp.getDigestAlgorithmIDs()); + + assertTrue(digestIDs.size() > 0); + + Collection c = signers.getSigners(); + Iterator it = c.iterator(); + + while (it.hasNext()) + { + SignerInformation signer = (SignerInformation)it.next(); + Collection certCollection = certStore.getMatches(signer.getSID()); + + Iterator certIt = certCollection.iterator(); + X509CertificateHolder cert = (X509CertificateHolder)certIt.next(); + + assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert))); + + digestIDs.remove(signer.getDigestAlgorithmID()); + + assertTrue(MessageDigest.isEqual(contentDigest1, signer.getContentDigest()) || + MessageDigest.isEqual(contentDigest2, signer.getContentDigest())); + + } + + assertTrue(digestIDs.size() == 0); + assertEquals(certStore.getMatches(null).size(), sp.getCertificates().getMatches(null).size()); + assertEquals(crlStore.getMatches(null).size(), sp.getCRLs().getMatches(null).size()); + } + public void testSHA1WithRSA() throws Exception { diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java index 948d194eb5..1b0a8133a9 100644 --- a/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java +++ b/pkix/src/test/java/org/bouncycastle/cms/test/NewSignedDataTest.java @@ -1,8 +1,11 @@ package org.bouncycastle.cms.test; -import java.io.ByteArrayInputStream; +import java.io.BufferedInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; +import java.io.Reader; import java.security.KeyFactory; import java.security.KeyPair; import java.security.MessageDigest; @@ -28,7 +31,6 @@ 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.ASN1OctetString; @@ -68,6 +70,7 @@ import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; import org.bouncycastle.cert.ocsp.OCSPResp; +import org.bouncycastle.cert.test.SampleCredentials; import org.bouncycastle.cms.CMSAbsentContent; import org.bouncycastle.cms.CMSAlgorithm; import org.bouncycastle.cms.CMSAttributeTableGenerationException; @@ -106,10 +109,13 @@ import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; +import org.bouncycastle.test.TestResourceFinder; import org.bouncycastle.util.CollectionStore; import org.bouncycastle.util.Store; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.io.Streams; +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemReader; public class NewSignedDataTest extends TestCase @@ -144,6 +150,38 @@ public class NewSignedDataTest private static KeyPair _signEd448KP; private static X509Certificate _signEd448Cert; + private static KeyPair _signMLDsa44KP; + private static X509Certificate _signMLDsa44Cert; + private static KeyPair _signMLDsa65KP; + private static X509Certificate _signMLDsa65Cert; + private static KeyPair _signMLDsa87KP; + private static X509Certificate _signMLDsa87Cert; + + private static KeyPair _signSlhDsa_Sha2_128f_KP; + private static X509Certificate _signSlhDsa_Sha2_128f_Cert; + private static KeyPair _signSlhDsa_Sha2_128s_KP; + private static X509Certificate _signSlhDsa_Sha2_128s_Cert; + private static KeyPair _signSlhDsa_Sha2_192f_KP; + private static X509Certificate _signSlhDsa_Sha2_192f_Cert; + private static KeyPair _signSlhDsa_Sha2_192s_KP; + private static X509Certificate _signSlhDsa_Sha2_192s_Cert; + private static KeyPair _signSlhDsa_Sha2_256f_KP; + private static X509Certificate _signSlhDsa_Sha2_256f_Cert; + private static KeyPair _signSlhDsa_Sha2_256s_KP; + private static X509Certificate _signSlhDsa_Sha2_256s_Cert; + private static KeyPair _signSlhDsa_Shake_128f_KP; + private static X509Certificate _signSlhDsa_Shake_128f_Cert; + private static KeyPair _signSlhDsa_Shake_128s_KP; + private static X509Certificate _signSlhDsa_Shake_128s_Cert; + private static KeyPair _signSlhDsa_Shake_192f_KP; + private static X509Certificate _signSlhDsa_Shake_192f_Cert; + private static KeyPair _signSlhDsa_Shake_192s_KP; + private static X509Certificate _signSlhDsa_Shake_192s_Cert; + private static KeyPair _signSlhDsa_Shake_256f_KP; + private static X509Certificate _signSlhDsa_Shake_256f_Cert; + private static KeyPair _signSlhDsa_Shake_256s_KP; + private static X509Certificate _signSlhDsa_Shake_256s_Cert; + private static String _reciDN; private static KeyPair _reciKP; private static X509Certificate _reciCert; @@ -682,6 +720,29 @@ public class NewSignedDataTest "CiwhMCLDeeEBOdxWZHVbIiFnnRTQqyIDGAOSSIUmjE/pMPKpPvumkCGq2r9GxPV9\n" + "YlpnThaYbDCnWg8tbWYAAAAAAAA="); + private static byte[] signedData_mldsa44 = loadPemContents("pkix/cms/mldsa", "SignedData_ML-DSA-44.pem"); + private static byte[] signedData_mldsa65 = loadPemContents("pkix/cms/mldsa", "SignedData_ML-DSA-65.pem"); + private static byte[] signedData_mldsa87 = loadPemContents("pkix/cms/mldsa", "SignedData_ML-DSA-87.pem"); + + private static byte[] loadPemContents(String path, String name) + { + try + { + InputStream input = new BufferedInputStream(TestResourceFinder.findTestResource(path, name)); + Reader reader = new InputStreamReader(input); + + PemReader pemReader = new PemReader(reader); + PemObject pemObject = pemReader.readPemObject(); + pemReader.close(); + + return pemObject.getContent(); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + static { noParams.add(X9ObjectIdentifiers.ecdsa_with_SHA1); @@ -704,8 +765,23 @@ public class NewSignedDataTest noParams.add(NISTObjectIdentifiers.id_ecdsa_with_sha3_512); noParams.add(EdECObjectIdentifiers.id_Ed25519); noParams.add(EdECObjectIdentifiers.id_Ed448); + noParams.add(NISTObjectIdentifiers.id_ml_dsa_44); + noParams.add(NISTObjectIdentifiers.id_ml_dsa_65); + noParams.add(NISTObjectIdentifiers.id_ml_dsa_87); + noParams.add(NISTObjectIdentifiers.id_slh_dsa_sha2_128f); + noParams.add(NISTObjectIdentifiers.id_slh_dsa_sha2_128s); + noParams.add(NISTObjectIdentifiers.id_slh_dsa_sha2_192f); + noParams.add(NISTObjectIdentifiers.id_slh_dsa_sha2_192s); + noParams.add(NISTObjectIdentifiers.id_slh_dsa_sha2_256f); + noParams.add(NISTObjectIdentifiers.id_slh_dsa_sha2_256s); + noParams.add(NISTObjectIdentifiers.id_slh_dsa_shake_128f); + noParams.add(NISTObjectIdentifiers.id_slh_dsa_shake_128s); + noParams.add(NISTObjectIdentifiers.id_slh_dsa_shake_192f); + noParams.add(NISTObjectIdentifiers.id_slh_dsa_shake_192s); + noParams.add(NISTObjectIdentifiers.id_slh_dsa_shake_256f); + noParams.add(NISTObjectIdentifiers.id_slh_dsa_shake_256s); } - + public NewSignedDataTest(String name) { super(name); @@ -776,6 +852,51 @@ private static void init() _signEd448KP = CMSTestUtil.makeEd448KeyPair(); _signEd448Cert = CMSTestUtil.makeCertificate(_signEd448KP, _signDN, _origKP, _origDN); + _signMLDsa44KP = CMSTestUtil.makeMLDsa44KeyPair(); + _signMLDsa44Cert = CMSTestUtil.makeCertificate(_signMLDsa44KP, _signDN, _origKP, _origDN); + + _signMLDsa65KP = CMSTestUtil.makeMLDsa65KeyPair(); + _signMLDsa65Cert = CMSTestUtil.makeCertificate(_signMLDsa65KP, _signDN, _origKP, _origDN); + + _signMLDsa87KP = CMSTestUtil.makeMLDsa87KeyPair(); + _signMLDsa87Cert = CMSTestUtil.makeCertificate(_signMLDsa87KP, _signDN, _origKP, _origDN); + + _signSlhDsa_Sha2_128f_KP = CMSTestUtil.makeSlhDsa_Sha2_128f_KeyPair(); + _signSlhDsa_Sha2_128f_Cert = CMSTestUtil.makeCertificate(_signSlhDsa_Sha2_128f_KP, _signDN, _origKP, _origDN); + + _signSlhDsa_Sha2_128s_KP = CMSTestUtil.makeSlhDsa_Sha2_128s_KeyPair(); + _signSlhDsa_Sha2_128s_Cert = CMSTestUtil.makeCertificate(_signSlhDsa_Sha2_128s_KP, _signDN, _origKP, _origDN); + + _signSlhDsa_Sha2_192f_KP = CMSTestUtil.makeSlhDsa_Sha2_192f_KeyPair(); + _signSlhDsa_Sha2_192f_Cert = CMSTestUtil.makeCertificate(_signSlhDsa_Sha2_192f_KP, _signDN, _origKP, _origDN); + + _signSlhDsa_Sha2_192s_KP = CMSTestUtil.makeSlhDsa_Sha2_192s_KeyPair(); + _signSlhDsa_Sha2_192s_Cert = CMSTestUtil.makeCertificate(_signSlhDsa_Sha2_192s_KP, _signDN, _origKP, _origDN); + + _signSlhDsa_Sha2_256f_KP = CMSTestUtil.makeSlhDsa_Sha2_256f_KeyPair(); + _signSlhDsa_Sha2_256f_Cert = CMSTestUtil.makeCertificate(_signSlhDsa_Sha2_256f_KP, _signDN, _origKP, _origDN); + + _signSlhDsa_Sha2_256s_KP = CMSTestUtil.makeSlhDsa_Sha2_256s_KeyPair(); + _signSlhDsa_Sha2_256s_Cert = CMSTestUtil.makeCertificate(_signSlhDsa_Sha2_256s_KP, _signDN, _origKP, _origDN); + + _signSlhDsa_Shake_128f_KP = CMSTestUtil.makeSlhDsa_Shake_128f_KeyPair(); + _signSlhDsa_Shake_128f_Cert = CMSTestUtil.makeCertificate(_signSlhDsa_Shake_128f_KP, _signDN, _origKP, _origDN); + + _signSlhDsa_Shake_128s_KP = CMSTestUtil.makeSlhDsa_Shake_128s_KeyPair(); + _signSlhDsa_Shake_128s_Cert = CMSTestUtil.makeCertificate(_signSlhDsa_Shake_128s_KP, _signDN, _origKP, _origDN); + + _signSlhDsa_Shake_192f_KP = CMSTestUtil.makeSlhDsa_Shake_192f_KeyPair(); + _signSlhDsa_Shake_192f_Cert = CMSTestUtil.makeCertificate(_signSlhDsa_Shake_192f_KP, _signDN, _origKP, _origDN); + + _signSlhDsa_Shake_192s_KP = CMSTestUtil.makeSlhDsa_Shake_192s_KeyPair(); + _signSlhDsa_Shake_192s_Cert = CMSTestUtil.makeCertificate(_signSlhDsa_Shake_192s_KP, _signDN, _origKP, _origDN); + + _signSlhDsa_Shake_256f_KP = CMSTestUtil.makeSlhDsa_Shake_256f_KeyPair(); + _signSlhDsa_Shake_256f_Cert = CMSTestUtil.makeCertificate(_signSlhDsa_Shake_256f_KP, _signDN, _origKP, _origDN); + + _signSlhDsa_Shake_256s_KP = CMSTestUtil.makeSlhDsa_Shake_256s_KeyPair(); + _signSlhDsa_Shake_256s_Cert = CMSTestUtil.makeCertificate(_signSlhDsa_Shake_256s_KP, _signDN, _origKP, _origDN); + _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU"; _reciKP = CMSTestUtil.makeKeyPair(); _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN); @@ -935,10 +1056,7 @@ public void testSHA1AndMD5WithRSAEncapsulatedRepeated() CMSSignedData s = gen.generate(msg, true); - ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded()); - ASN1InputStream aIn = new ASN1InputStream(bIn); - - s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject())); + s = new CMSSignedData(s.getEncoded()); certs = s.getCertificates(); @@ -991,10 +1109,7 @@ public void testSHA1AndMD5WithRSAEncapsulatedRepeated() s = gen.generate(msg, true); - bIn = new ByteArrayInputStream(s.getEncoded()); - aIn = new ASN1InputStream(bIn); - - s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject())); + s = new CMSSignedData(s.getEncoded()); certs = s.getCertificates(); @@ -1385,6 +1500,9 @@ public void testSHA1WithRSAAndAttributeTable() // compute expected content digest // + assertTrue(s.isDetachedSignature()); + assertFalse(s.isCertificateManagementMessage()); + verifySignatures(s, md.digest("Hello world!".getBytes())); verifyRSASignatures(s, md.digest("Hello world!".getBytes())); } @@ -1789,25 +1907,36 @@ public void testSHA512_256ithRSADigest() public void testEd25519() throws Exception { - encapsulatedTest(_signEd25519KP, _signEd25519Cert, "Ed25519", EdECObjectIdentifiers.id_Ed25519, new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512)); + /* + * RFC 8419 3.1. When signing with Ed25519, the digestAlgorithm MUST be id-sha512, and the algorithm + * parameters field MUST be absent. + * + * We confirm here that our implementation defaults to SHA-512 for the digest algorithm. + */ + AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512); + + detachedTest(_signEd25519KP, _signEd25519Cert, "Ed25519", EdECObjectIdentifiers.id_Ed25519, expectedDigAlgId); + + encapsulatedTest(_signEd25519KP, _signEd25519Cert, "Ed25519", EdECObjectIdentifiers.id_Ed25519, + expectedDigAlgId); } public void testEd448() throws Exception { - encapsulatedTest(_signEd448KP, _signEd448Cert, "Ed448", EdECObjectIdentifiers.id_Ed448, new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256_len, new ASN1Integer(512))); - } + /* + * RFC 8419 3.1. When signing with Ed448, the digestAlgorithm MUST be id-shake256-len, the algorithm + * parameters field MUST be present, and the parameter MUST contain 512, encoded as a positive integer + * value. + * + * We confirm here that our implementation defaults to id-shake256-len/512 for the digest algorithm. + */ + AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256_len, + ASN1Integer.valueOf(512)); - public void testDetachedEd25519() - throws Exception - { - detachedTest(_signEd25519KP, _signEd25519Cert, "Ed25519", EdECObjectIdentifiers.id_Ed25519, new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512)); - } + detachedTest(_signEd448KP, _signEd448Cert, "Ed448", EdECObjectIdentifiers.id_Ed448, expectedDigAlgId); - public void testEdDetached448() - throws Exception - { - detachedTest(_signEd448KP, _signEd448Cert, "Ed448", EdECObjectIdentifiers.id_Ed448, new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256_len, new ASN1Integer(512))); + encapsulatedTest(_signEd448KP, _signEd448Cert, "Ed448", EdECObjectIdentifiers.id_Ed448, expectedDigAlgId); } public void testEd25519WithNoAttr() @@ -1938,6 +2067,17 @@ public void testECDSASHA512Encapsulated() encapsulatedTest(_signEcDsaKP, _signEcDsaCert, "SHA512withECDSA"); } + public void testECDSASHA512EncapsulatedWithKeyFactoryAsEC() + throws Exception + { + X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(_signEcDsaKP.getPublic().getEncoded()); + PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(_signEcDsaKP.getPrivate().getEncoded()); + KeyFactory keyFact = KeyFactory.getInstance("EC", BC); + KeyPair kp = new KeyPair(keyFact.generatePublic(pubSpec), keyFact.generatePrivate(privSpec)); + + encapsulatedTest(kp, _signEcDsaCert, "SHA512withECDSA"); + } + public void testECDSASHA3_224Encapsulated() throws Exception { @@ -2010,17 +2150,6 @@ public void testPLAIN_ECDSASHA3_512Encapsulated() encapsulatedTest(_signEcDsaKP, _signEcDsaCert, "SHA3-512withPLAIN-ECDSA"); } - public void testECDSASHA512EncapsulatedWithKeyFactoryAsEC() - throws Exception - { - X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(_signEcDsaKP.getPublic().getEncoded()); - PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(_signEcDsaKP.getPrivate().getEncoded()); - KeyFactory keyFact = KeyFactory.getInstance("EC", BC); - KeyPair kp = new KeyPair(keyFact.generatePublic(pubSpec), keyFact.generatePrivate(privSpec)); - - encapsulatedTest(kp, _signEcDsaCert, "SHA512withECDSA"); - } - public void testDSAEncapsulated() throws Exception { @@ -2270,6 +2399,270 @@ public SignerInformationVerifier get(SignerId signerId) assertTrue(digAlgs.contains(new AlgorithmIdentifier(TeleTrusTObjectIdentifiers.ripemd160, DERNull.INSTANCE))); } +// public void testMLDsa44() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-ml-dsa-02 3.3. SHA-512 [FIPS180] MUST be supported for use with the variants +// * of ML-DSA in this document; however, other hash functions MAY also be supported. When SHA-512 is +// * used, the id-sha512 [RFC5754] digest algorithm identifier is used and the parameters field MUST be +// * omitted. +// * +// * We confirm here that our implementation defaults to SHA-512 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512); +// +// detachedTest(_signMLDsa44KP, _signMLDsa44Cert, "ML-DSA-44", NISTObjectIdentifiers.id_ml_dsa_44, +// expectedDigAlgId); +// +// encapsulatedTest(_signMLDsa44KP, _signMLDsa44Cert, "ML-DSA-44", NISTObjectIdentifiers.id_ml_dsa_44, +// expectedDigAlgId); +// } +// +// public void testMLDsa65() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-ml-dsa-02 3.3. SHA-512 [FIPS180] MUST be supported for use with the variants +// * of ML-DSA in this document; however, other hash functions MAY also be supported. When SHA-512 is +// * used, the id-sha512 [RFC5754] digest algorithm identifier is used and the parameters field MUST be +// * omitted. +// * +// * We confirm here that our implementation defaults to SHA-512 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512); +// +// detachedTest(_signMLDsa65KP, _signMLDsa65Cert, "ML-DSA-65", NISTObjectIdentifiers.id_ml_dsa_65, +// expectedDigAlgId); +// +// encapsulatedTest(_signMLDsa65KP, _signMLDsa65Cert, "ML-DSA-65", NISTObjectIdentifiers.id_ml_dsa_65, +// expectedDigAlgId); +// } +// +// public void testMLDsa87() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-ml-dsa-02 3.3. SHA-512 [FIPS180] MUST be supported for use with the variants +// * of ML-DSA in this document; however, other hash functions MAY also be supported. When SHA-512 is +// * used, the id-sha512 [RFC5754] digest algorithm identifier is used and the parameters field MUST be +// * omitted. +// * +// * We confirm here that our implementation defaults to SHA-512 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512); +// +// detachedTest(_signMLDsa87KP, _signMLDsa87Cert, "ML-DSA-87", NISTObjectIdentifiers.id_ml_dsa_87, +// expectedDigAlgId); +// +// encapsulatedTest(_signMLDsa87KP, _signMLDsa87Cert, "ML-DSA-87", NISTObjectIdentifiers.id_ml_dsa_87, +// expectedDigAlgId); +// } + +// public void testSlhDsa_Sha2_128f() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-sphincs-plus-19 4. (we initially only support the MUST-support algorithm) +// * +// * We confirm here that our implementation defaults to SHA-256 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256); +// +// detachedTest(_signSlhDsa_Sha2_128f_KP, _signSlhDsa_Sha2_128f_Cert, "SLH-DSA-SHA2-128F", +// NISTObjectIdentifiers.id_slh_dsa_sha2_128f, expectedDigAlgId); +// +// encapsulatedTest(_signSlhDsa_Sha2_128f_KP, _signSlhDsa_Sha2_128f_Cert, "SLH-DSA-SHA2-128F", +// NISTObjectIdentifiers.id_slh_dsa_sha2_128f, expectedDigAlgId); +// } +// +// public void testSlhDsa_Sha2_128s() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-sphincs-plus-19 4. (we initially only support the MUST-support algorithm) +// * +// * We confirm here that our implementation defaults to SHA-256 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256); +// +// detachedTest(_signSlhDsa_Sha2_128s_KP, _signSlhDsa_Sha2_128s_Cert, "SLH-DSA-SHA2-128S", +// NISTObjectIdentifiers.id_slh_dsa_sha2_128s, expectedDigAlgId); +// +// encapsulatedTest(_signSlhDsa_Sha2_128s_KP, _signSlhDsa_Sha2_128s_Cert, "SLH-DSA-SHA2-128S", +// NISTObjectIdentifiers.id_slh_dsa_sha2_128s, expectedDigAlgId); +// } +// +// public void testSlhDsa_Sha2_192f() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-sphincs-plus-19 4. (we initially only support the MUST-support algorithm) +// * +// * We confirm here that our implementation defaults to SHA-512 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512); +// +// detachedTest(_signSlhDsa_Sha2_192f_KP, _signSlhDsa_Sha2_192f_Cert, "SLH-DSA-SHA2-192F", +// NISTObjectIdentifiers.id_slh_dsa_sha2_192f, expectedDigAlgId); +// +// encapsulatedTest(_signSlhDsa_Sha2_192f_KP, _signSlhDsa_Sha2_192f_Cert, "SLH-DSA-SHA2-192F", +// NISTObjectIdentifiers.id_slh_dsa_sha2_192f, expectedDigAlgId); +// } +// +// public void testSlhDsa_Sha2_192s() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-sphincs-plus-19 4. (we initially only support the MUST-support algorithm) +// * +// * We confirm here that our implementation defaults to SHA-512 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512); +// +// detachedTest(_signSlhDsa_Sha2_192s_KP, _signSlhDsa_Sha2_192s_Cert, "SLH-DSA-SHA2-192S", +// NISTObjectIdentifiers.id_slh_dsa_sha2_192s, expectedDigAlgId); +// +// encapsulatedTest(_signSlhDsa_Sha2_192s_KP, _signSlhDsa_Sha2_192s_Cert, "SLH-DSA-SHA2-192S", +// NISTObjectIdentifiers.id_slh_dsa_sha2_192s, expectedDigAlgId); +// } +// +// public void testSlhDsa_Sha2_256f() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-sphincs-plus-19 4. (we initially only support the MUST-support algorithm) +// * +// * We confirm here that our implementation defaults to SHA-512 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512); +// +// detachedTest(_signSlhDsa_Sha2_256f_KP, _signSlhDsa_Sha2_256f_Cert, "SLH-DSA-SHA2-256F", +// NISTObjectIdentifiers.id_slh_dsa_sha2_256f, expectedDigAlgId); +// +// encapsulatedTest(_signSlhDsa_Sha2_256f_KP, _signSlhDsa_Sha2_256f_Cert, "SLH-DSA-SHA2-256F", +// NISTObjectIdentifiers.id_slh_dsa_sha2_256f, expectedDigAlgId); +// } +// +// public void testSlhDsa_Sha2_256s() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-sphincs-plus-19 4. (we initially only support the MUST-support algorithm) +// * +// * We confirm here that our implementation defaults to SHA-512 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512); +// +// detachedTest(_signSlhDsa_Sha2_256s_KP, _signSlhDsa_Sha2_256s_Cert, "SLH-DSA-SHA2-256S", +// NISTObjectIdentifiers.id_slh_dsa_sha2_256s, expectedDigAlgId); +// +// encapsulatedTest(_signSlhDsa_Sha2_256s_KP, _signSlhDsa_Sha2_256s_Cert, "SLH-DSA-SHA2-256S", +// NISTObjectIdentifiers.id_slh_dsa_sha2_256s, expectedDigAlgId); +// } +// +// public void testSlhDsa_Shake_128f() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-sphincs-plus-19 4. (we initially only support the MUST-support algorithm) +// * +// * We confirm here that our implementation defaults to SHAKE-128 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake128); +// +// detachedTest(_signSlhDsa_Shake_128f_KP, _signSlhDsa_Shake_128f_Cert, "SLH-DSA-SHAKE-128F", +// NISTObjectIdentifiers.id_slh_dsa_shake_128f, expectedDigAlgId); +// +// encapsulatedTest(_signSlhDsa_Shake_128f_KP, _signSlhDsa_Shake_128f_Cert, "SLH-DSA-SHAKE-128F", +// NISTObjectIdentifiers.id_slh_dsa_shake_128f, expectedDigAlgId); +// } +// +// public void testSlhDsa_Shake_128s() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-sphincs-plus-19 4. (we initially only support the MUST-support algorithm) +// * +// * We confirm here that our implementation defaults to SHAKE-128 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake128); +// +// detachedTest(_signSlhDsa_Shake_128s_KP, _signSlhDsa_Shake_128s_Cert, "SLH-DSA-SHAKE-128S", +// NISTObjectIdentifiers.id_slh_dsa_shake_128s, expectedDigAlgId); +// +// encapsulatedTest(_signSlhDsa_Shake_128s_KP, _signSlhDsa_Shake_128s_Cert, "SLH-DSA-SHAKE-128S", +// NISTObjectIdentifiers.id_slh_dsa_shake_128s, expectedDigAlgId); +// } +// +// public void testSlhDsa_Shake_192f() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-sphincs-plus-19 4. (we initially only support the MUST-support algorithm) +// * +// * We confirm here that our implementation defaults to SHAKE-256 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256); +// +// detachedTest(_signSlhDsa_Shake_192f_KP, _signSlhDsa_Shake_192f_Cert, "SLH-DSA-SHAKE-192F", +// NISTObjectIdentifiers.id_slh_dsa_shake_192f, expectedDigAlgId); +// +// encapsulatedTest(_signSlhDsa_Shake_192f_KP, _signSlhDsa_Shake_192f_Cert, "SLH-DSA-SHAKE-192F", +// NISTObjectIdentifiers.id_slh_dsa_shake_192f, expectedDigAlgId); +// } +// +// public void testSlhDsa_Shake_192s() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-sphincs-plus-19 4. (we initially only support the MUST-support algorithm) +// * +// * We confirm here that our implementation defaults to SHAKE-256 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256); +// +// detachedTest(_signSlhDsa_Shake_192s_KP, _signSlhDsa_Shake_192s_Cert, "SLH-DSA-SHAKE-192S", +// NISTObjectIdentifiers.id_slh_dsa_shake_192s, expectedDigAlgId); +// +// encapsulatedTest(_signSlhDsa_Shake_192s_KP, _signSlhDsa_Shake_192s_Cert, "SLH-DSA-SHAKE-192S", +// NISTObjectIdentifiers.id_slh_dsa_shake_192s, expectedDigAlgId); +// } +// +// public void testSlhDsa_Shake_256f() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-sphincs-plus-19 4. (we initially only support the MUST-support algorithm) +// * +// * We confirm here that our implementation defaults to SHAKE-256 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256); +// +// detachedTest(_signSlhDsa_Shake_256f_KP, _signSlhDsa_Shake_256f_Cert, "SLH-DSA-SHAKE-256F", +// NISTObjectIdentifiers.id_slh_dsa_shake_256f, expectedDigAlgId); +// +// encapsulatedTest(_signSlhDsa_Shake_256f_KP, _signSlhDsa_Shake_256f_Cert, "SLH-DSA-SHAKE-256F", +// NISTObjectIdentifiers.id_slh_dsa_shake_256f, expectedDigAlgId); +// } +// +// public void testSlhDsa_Shake_256s() +// throws Exception +// { +// /* +// * draft-ietf-lamps-cms-sphincs-plus-19 4. (we initially only support the MUST-support algorithm) +// * +// * We confirm here that our implementation defaults to SHAKE-256 for the digest algorithm. +// */ +// AlgorithmIdentifier expectedDigAlgId = new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256); +// +// detachedTest(_signSlhDsa_Shake_256s_KP, _signSlhDsa_Shake_256s_Cert, "SLH-DSA-SHAKE-256S", +// NISTObjectIdentifiers.id_slh_dsa_shake_256s, expectedDigAlgId); +// +// encapsulatedTest(_signSlhDsa_Shake_256s_KP, _signSlhDsa_Shake_256s_Cert, "SLH-DSA-SHAKE-256S", +// NISTObjectIdentifiers.id_slh_dsa_shake_256s, expectedDigAlgId); +// } + private void rsaPSSTest(String signatureAlgorithmName) throws Exception { @@ -2399,11 +2792,8 @@ private void subjectKeyIDTest( CMSSignedData s = gen.generate(msg, true); assertEquals(3, s.getVersion()); - - ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded()); - ASN1InputStream aIn = new ASN1InputStream(bIn); - s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject())); + s = new CMSSignedData(s.getEncoded()); certStore = s.getCertificates(); @@ -2443,10 +2833,7 @@ private void subjectKeyIDTest( s = gen.generate(msg, true); - bIn = new ByteArrayInputStream(s.getEncoded()); - aIn = new ASN1InputStream(bIn); - - s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject())); + s = new CMSSignedData(s.getEncoded()); certStore = s.getCertificates(); @@ -2492,47 +2879,49 @@ private void encapsulatedTest( X509Certificate signatureCert, String signatureAlgorithm, ASN1ObjectIdentifier sigAlgOid, - AlgorithmIdentifier digAlgId) + AlgorithmIdentifier expectedDigAlgId) throws Exception { - List certList = new ArrayList(); - List crlList = new ArrayList(); - CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes()); - + CMSTypedData msg = new CMSProcessableByteArray("Hello World!".getBytes()); + + List certList = new ArrayList(); + List crlList = new ArrayList(); + certList.add(signatureCert); certList.add(_origCert); crlList.add(_signCrl); - Store certs = new JcaCertStore(certList); - Store crlStore = new JcaCRLStore(crlList); + Store certStore = new JcaCertStore(certList); + Store crlStore = new JcaCRLStore(crlList); CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).setProvider(BC).build(signaturePair.getPrivate()); - gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build()).build(contentSigner, signatureCert)); + DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build(); - gen.addCertificates(certs); - - CMSSignedData s = gen.generate(msg, true); + gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(digCalcProv).build(contentSigner, signatureCert)); + + gen.addCertificates(certStore); + gen.addCRLs(crlStore); - ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded()); - ASN1InputStream aIn = new ASN1InputStream(bIn); + CMSSignedData s = gen.generate(msg, true); - s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject())); + s = new CMSSignedData(s.getEncoded()); Set digestAlgorithms = new HashSet(s.getDigestAlgorithmIDs()); assertTrue(digestAlgorithms.size() > 0); - if (digAlgId != null) + if (expectedDigAlgId != null) { - assertTrue(digestAlgorithms.contains(digAlgId)); + assertTrue(digestAlgorithms.contains(expectedDigAlgId)); } - certs = s.getCertificates(); - + certStore = s.getCertificates(); + crlStore = s.getCRLs(); + SignerInformationStore signers = s.getSignerInfos(); Collection c = signers.getSigners(); Iterator it = c.iterator(); @@ -2540,7 +2929,7 @@ private void encapsulatedTest( while (it.hasNext()) { SignerInformation signer = (SignerInformation)it.next(); - Collection certCollection = certs.getMatches(signer.getSID()); + Collection certCollection = certStore.getMatches(signer.getSID()); Iterator certIt = certCollection.iterator(); X509CertificateHolder cert = (X509CertificateHolder)certIt.next(); @@ -2592,18 +2981,17 @@ private void encapsulatedTest( gen = new CMSSignedDataGenerator(); gen.addSigners(s.getSignerInfos()); - + gen.addCertificates(s.getCertificates()); - + gen.addCRLs(s.getCRLs()); + s = gen.generate(msg, true); - - bIn = new ByteArrayInputStream(s.getEncoded()); - aIn = new ASN1InputStream(bIn); - - s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject())); - - certs = s.getCertificates(); - + + s = new CMSSignedData(s.getEncoded()); + + certStore = s.getCertificates(); + crlStore = s.getCRLs(); + signers = s.getSignerInfos(); c = signers.getSigners(); it = c.iterator(); @@ -2611,7 +2999,7 @@ private void encapsulatedTest( while (it.hasNext()) { SignerInformation signer = (SignerInformation)it.next(); - Collection certCollection = certs.getMatches(signer.getSID()); + Collection certCollection = certStore.getMatches(signer.getSID()); Iterator certIt = certCollection.iterator(); X509CertificateHolder cert = (X509CertificateHolder)certIt.next(); @@ -2655,12 +3043,9 @@ private void detachedTest( gen.addCertificates(certs); - CMSSignedData s = gen.generate(msg, true); - - ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded()); - ASN1InputStream aIn = new ASN1InputStream(bIn); + CMSSignedData s = gen.generate(msg); - s = new CMSSignedData(msg, ContentInfo.getInstance(aIn.readObject())); + s = new CMSSignedData(msg, s.getEncoded()); Set digestAlgorithms = new HashSet(s.getDigestAlgorithmIDs()); @@ -2827,10 +3212,7 @@ public void testNullContentWithSigner() CMSSignedData s = gen.generate(new CMSAbsentContent(), false); - ByteArrayInputStream bIn = new ByteArrayInputStream(s.getEncoded()); - ASN1InputStream aIn = new ASN1InputStream(bIn); - - s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject())); + s = new CMSSignedData(s.getEncoded()); verifySignatures(s); } @@ -3174,11 +3556,14 @@ public void testCertificateManagement() CMSSignedData sData = sGen.generate(new CMSAbsentContent(), true); - CMSSignedData rsData = new CMSSignedData(sData.getEncoded()); - assertTrue(sData.isCertificateManagementMessage()); assertFalse(sData.isDetachedSignature()); + CMSSignedData rsData = new CMSSignedData(sData.getEncoded()); + + assertTrue(rsData.isCertificateManagementMessage()); + assertFalse(rsData.isDetachedSignature()); + assertEquals(2, rsData.getCertificates().getMatches(null).size()); } @@ -3357,6 +3742,24 @@ public void testForMultipleCounterSignatures() } } + public void testVerifySignedDataMLDsa44() + throws Exception + { + implTestVerifySignedData(signedData_mldsa44, SampleCredentials.ML_DSA_44); + } + + public void testVerifySignedDataMLDsa65() + throws Exception + { + implTestVerifySignedData(signedData_mldsa65, SampleCredentials.ML_DSA_65); + } + + public void testVerifySignedDataMLDsa87() + throws Exception + { + implTestVerifySignedData(signedData_mldsa87, SampleCredentials.ML_DSA_87); + } + private void verifySignatures(CMSSignedDataParser sp) throws Exception { @@ -3378,6 +3781,40 @@ private void verifySignatures(CMSSignedDataParser sp) } } + private static void implTestVerifySignedData(byte[] signedData, final SampleCredentials credentials) + throws Exception + { + CMSSignedData sd = new CMSSignedData(signedData); + + // Verify using the certificate from the supplied credentials + SignerInformationVerifierProvider verifierProvider = new SignerInformationVerifierProvider() + { + public SignerInformationVerifier get(SignerId signerId) + throws OperatorCreationException + { + return new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(credentials.getCertificate()); + } + }; + + // External signer verification + { + SignerInformationStore signers = sd.getSignerInfos(); + + Iterator it = signers.getSigners().iterator(); + while (it.hasNext()) + { + SignerInformation signer = (SignerInformation)it.next(); + + SignerInformationVerifier verifier = verifierProvider.get(signer.getSID()); + + assertTrue(signer.verify(verifier)); + } + } + + // Built-in signer verification + assertTrue(sd.verifySignatures(verifierProvider)); + } + private static class TestCMSSignatureAlgorithmNameGenerator extends DefaultCMSSignatureAlgorithmNameGenerator { diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/PQCSignedDataTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/PQCSignedDataTest.java index 4383e9813d..86d4921cee 100644 --- a/pkix/src/test/java/org/bouncycastle/cms/test/PQCSignedDataTest.java +++ b/pkix/src/test/java/org/bouncycastle/cms/test/PQCSignedDataTest.java @@ -2,13 +2,19 @@ import java.io.ByteArrayInputStream; import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyFactory; import java.security.KeyPair; import java.security.MessageDigest; +import java.security.SecureRandom; import java.security.Security; import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.Collection; +import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -27,8 +33,14 @@ import org.bouncycastle.asn1.cms.SignerInfo; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x500.style.RFC4519Style; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.X509v1CertificateBuilder; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.bc.BcX509v1CertificateBuilder; +import org.bouncycastle.cert.bc.BcX509v3CertificateBuilder; import org.bouncycastle.cert.jcajce.JcaCertStore; import org.bouncycastle.cms.CMSException; import org.bouncycastle.cms.CMSProcessableByteArray; @@ -40,11 +52,25 @@ import org.bouncycastle.cms.SignerInformationStore; import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.DigestCalculatorProvider; import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.bc.BcHssLmsContentSignerBuilder; +import org.bouncycastle.operator.bc.BcHssLmsContentVerifierProviderBuilder; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; +import org.bouncycastle.pqc.crypto.lms.HSSKeyGenerationParameters; +import org.bouncycastle.pqc.crypto.lms.HSSKeyPairGenerator; +import org.bouncycastle.pqc.crypto.lms.HSSPublicKeyParameters; +import org.bouncycastle.pqc.crypto.lms.LMOtsParameters; +import org.bouncycastle.pqc.crypto.lms.LMSKeyGenerationParameters; +import org.bouncycastle.pqc.crypto.lms.LMSKeyPairGenerator; +import org.bouncycastle.pqc.crypto.lms.LMSParameters; +import org.bouncycastle.pqc.crypto.lms.LMSigParameters; import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; import org.bouncycastle.util.Store; @@ -104,7 +130,7 @@ public static void main(String args[]) throws Exception { init(); - + //checkCreationHssLms(); junit.textui.TestRunner.run(PQCSignedDataTest.class); } @@ -321,7 +347,7 @@ public void testLmsEncapsulated() assertTrue(digAlgIds.contains(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256))); assertTrue(digAlgIds.size() == 1); - + certs = s.getCertificates(); SignerInformationStore signers = s.getSignerInfos(); @@ -337,7 +363,7 @@ public void testLmsEncapsulated() Iterator certIt = certCollection.iterator(); X509CertificateHolder cert = (X509CertificateHolder)certIt.next(); - assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().build(cert))); + assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert))); // // check content digest @@ -352,6 +378,152 @@ public void testLmsEncapsulated() } } + public void testCheckCreationHss() + throws Exception + { + // + // set up the keys + // + AsymmetricKeyParameter privKey; + AsymmetricKeyParameter pubKey; + + AsymmetricCipherKeyPairGenerator kpg = new HSSKeyPairGenerator(); + + kpg.init(new HSSKeyGenerationParameters( + new LMSParameters[]{new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w4), + new LMSParameters(LMSigParameters.lms_sha256_n24_h5, LMOtsParameters.sha256_n24_w4)}, new SecureRandom())); + + AsymmetricCipherKeyPair pair = kpg.generateKeyPair(); + + privKey = (AsymmetricKeyParameter)pair.getPrivate(); + pubKey = (AsymmetricKeyParameter)pair.getPublic(); + + // + // distinguished name table. + // + X500NameBuilder builder = new X500NameBuilder(RFC4519Style.INSTANCE); + + builder.addRDN(RFC4519Style.c, "AU"); + builder.addRDN(RFC4519Style.o, "The Legion of the Bouncy Castle"); + builder.addRDN(RFC4519Style.l, "Melbourne"); + builder.addRDN(RFC4519Style.st, "Victoria"); + builder.addRDN(PKCSObjectIdentifiers.pkcs_9_at_emailAddress, "feedback-crypto@bouncycastle.org"); + + // + // extensions + // + + // + // create the certificate - version 3 + // + ContentSigner sigGen = new BcHssLmsContentSignerBuilder().build(privKey); + X509v3CertificateBuilder certGen = new BcX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubKey); + + + X509CertificateHolder cert = certGen.build(sigGen); + + assertTrue(cert.isValidOn(new Date())); + + assertTrue(cert.isSignatureValid(new BcHssLmsContentVerifierProviderBuilder().build(pubKey))); + + + // + // create the certificate - version 1 + // + sigGen = new BcHssLmsContentSignerBuilder().build(privKey); + X509v1CertificateBuilder certGen1 = new BcX509v1CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubKey); + + cert = certGen1.build(sigGen); + + assertTrue(cert.isValidOn(new Date())); + + assertTrue(cert.isSignatureValid(new BcHssLmsContentVerifierProviderBuilder().build(pubKey))); + + AsymmetricKeyParameter certPubKey = org.bouncycastle.pqc.crypto.util.PublicKeyFactory.createKey(cert.getSubjectPublicKeyInfo()); + + assertTrue(cert.isSignatureValid(new BcHssLmsContentVerifierProviderBuilder().build(certPubKey))); + + ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded()); + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + + X509Certificate x509cert = (X509Certificate)fact.generateCertificate(bIn); + + //System.out.println(cert); + } + + public void testCheckCreationLms() + throws Exception + { + // + // set up the keys + // + AsymmetricKeyParameter privKey; + AsymmetricKeyParameter pubKey; + + AsymmetricCipherKeyPairGenerator kpg = new LMSKeyPairGenerator(); + + kpg.init(new LMSKeyGenerationParameters( + new LMSParameters(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w4), new SecureRandom())); + + AsymmetricCipherKeyPair pair = kpg.generateKeyPair(); + + privKey = (AsymmetricKeyParameter)pair.getPrivate(); + pubKey = (AsymmetricKeyParameter)pair.getPublic(); + + // + // distinguished name table. + // + X500NameBuilder builder = new X500NameBuilder(RFC4519Style.INSTANCE); + + builder.addRDN(RFC4519Style.c, "AU"); + builder.addRDN(RFC4519Style.o, "The Legion of the Bouncy Castle"); + builder.addRDN(RFC4519Style.l, "Melbourne"); + builder.addRDN(RFC4519Style.st, "Victoria"); + builder.addRDN(PKCSObjectIdentifiers.pkcs_9_at_emailAddress, "feedback-crypto@bouncycastle.org"); + + // + // extensions + // + + // + // create the certificate - version 3 + // + ContentSigner sigGen = new BcHssLmsContentSignerBuilder().build(privKey); + X509v3CertificateBuilder certGen = new BcX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubKey); + + + X509CertificateHolder cert = certGen.build(sigGen); + + assertTrue(cert.isValidOn(new Date())); + + assertTrue(cert.isSignatureValid(new BcHssLmsContentVerifierProviderBuilder().build(pubKey))); + + + // + // create the certificate - version 1 + // + + sigGen = new BcHssLmsContentSignerBuilder().build(privKey); + X509v1CertificateBuilder certGen1 = new BcX509v1CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubKey); + + cert = certGen1.build(sigGen); + + assertTrue(cert.isValidOn(new Date())); + + assertTrue(cert.isSignatureValid(new BcHssLmsContentVerifierProviderBuilder().build(pubKey))); + + AsymmetricKeyParameter certPubKey = ((HSSPublicKeyParameters)org.bouncycastle.pqc.crypto.util.PublicKeyFactory.createKey(cert.getSubjectPublicKeyInfo())).getLMSPublicKey(); + + assertTrue(cert.isSignatureValid(new BcHssLmsContentVerifierProviderBuilder().build(certPubKey))); + + ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded()); + CertificateFactory fact = CertificateFactory.getInstance("X.509"); + + X509Certificate x509cert = (X509Certificate)fact.generateCertificate(bIn); + + //System.out.println(new String(cert.getEncoded())); + } + public void testTryLmsSettings() throws Exception { @@ -416,6 +588,11 @@ public void testMLDSAEncapsulated() CMSSignedData s = gen.generate(msg, true); + AlgorithmIdentifier digestAlgorithmID = s.getSignerInfos().getSigners().iterator().next().getDigestAlgorithmID(); + // CNSA compliance requires SHA-384 or SHA-512. We now default to SHA-512 + assertEquals(NISTObjectIdentifiers.id_sha512, digestAlgorithmID.getAlgorithm()); + assertNull(digestAlgorithmID.getParameters()); + checkSignature(s, gen); } diff --git a/pkix/src/test/java/org/bouncycastle/dvcs/test/DVCSParseTest.java b/pkix/src/test/java/org/bouncycastle/dvcs/test/DVCSParseTest.java index 1680039c57..72024067ef 100644 --- a/pkix/src/test/java/org/bouncycastle/dvcs/test/DVCSParseTest.java +++ b/pkix/src/test/java/org/bouncycastle/dvcs/test/DVCSParseTest.java @@ -90,7 +90,7 @@ public class DVCSParseTest REQ_CCPD_TOMSK = new DVCSRequest(INFO_CCPD_TOMSK.build(), new Data(DIGEST_CCPD_TOMSK), ID_CCPD_TOMSK); - DVCSCertInfoBuilder certInfoBldr = new DVCSCertInfoBuilder(INFO_CCPD_TOMSK.build(), DIGEST_CCPD_TOMSK, new ASN1Integer(6256), new DVCSTime(new ASN1GeneralizedTime("20121204040643Z"))); + DVCSCertInfoBuilder certInfoBldr = new DVCSCertInfoBuilder(INFO_CCPD_TOMSK.build(), DIGEST_CCPD_TOMSK, ASN1Integer.valueOf(6256), new DVCSTime(new ASN1GeneralizedTime("20121204040643Z"))); certInfoBldr.setDvStatus(new PKIStatusInfo(PKIStatus.granted)); RES_CCPD_TOMSK = new DVCSResponse(certInfoBldr.build()); @@ -107,7 +107,7 @@ public class DVCSParseTest REQ_CPD_TOMSK = new DVCSRequest(INFO_CPD_TOMSK.build(), new Data(Hex.decode(CPD_DATA_TOMSK)), ID_CPD_TOMSK); - certInfoBldr = new DVCSCertInfoBuilder(INFO_CPD_TOMSK2.build(), DIGEST_CPD_TOMSK, new ASN1Integer(6329), new DVCSTime(new ASN1GeneralizedTime("20121205065720Z"))); + certInfoBldr = new DVCSCertInfoBuilder(INFO_CPD_TOMSK2.build(), DIGEST_CPD_TOMSK, ASN1Integer.valueOf(6329), new DVCSTime(new ASN1GeneralizedTime("20121205065720Z"))); certInfoBldr.setDvStatus(new PKIStatusInfo(PKIStatus.granted)); RES_CPD_TOMSK = new DVCSResponse(certInfoBldr.build()); @@ -126,7 +126,7 @@ public class DVCSParseTest REQ_VPKC_TOMSK = new DVCSRequest(INFO_VPKC_TOMSK.build(), new Data(REQ_CERTS), ID_VPKC_TOMSK); - certInfoBldr = new DVCSCertInfoBuilder(INFO_VPKC_TOMSK.build(), DIGEST_VPKC_TOMSK, new ASN1Integer(6257), new DVCSTime(new ASN1GeneralizedTime("20121204040753Z"))); + certInfoBldr = new DVCSCertInfoBuilder(INFO_VPKC_TOMSK.build(), DIGEST_VPKC_TOMSK, ASN1Integer.valueOf(6257), new DVCSTime(new ASN1GeneralizedTime("20121204040753Z"))); certInfoBldr.setDvStatus(new PKIStatusInfo(PKIStatus.granted)); certInfoBldr.setCerts(RES_CERTS); diff --git a/pkix/src/test/java/org/bouncycastle/openssl/test/CompositeKeyTest.java b/pkix/src/test/java/org/bouncycastle/openssl/test/CompositeKeyTest.java index ae198ed68a..23d7f72fb6 100644 --- a/pkix/src/test/java/org/bouncycastle/openssl/test/CompositeKeyTest.java +++ b/pkix/src/test/java/org/bouncycastle/openssl/test/CompositeKeyTest.java @@ -23,6 +23,7 @@ import junit.framework.TestCase; import org.bouncycastle.asn1.cms.ContentInfo; +import org.bouncycastle.asn1.iana.IANAObjectIdentifiers; import org.bouncycastle.asn1.misc.MiscObjectIdentifiers; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; @@ -474,7 +475,7 @@ public void testMLDSA44andP256() PrivateKey mldsaPriv = mldsaKp.getPrivate(); PublicKey mldsaPub = mldsaKp.getPublic(); - CompositePrivateKey mlecPriv = new CompositePrivateKey(MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, mldsaPriv, ecPriv); + CompositePrivateKey mlecPriv = new CompositePrivateKey(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, mldsaPriv, ecPriv); StringWriter sWrt = new StringWriter(); JcaPEMWriter pWrt = new JcaPEMWriter(sWrt); @@ -519,7 +520,7 @@ public void testMLDSA44andEd25519() PrivateKey mldsaPriv = mldsaKp.getPrivate(); PublicKey mldsaPub = mldsaKp.getPublic(); - CompositePrivateKey mlecPriv = new CompositePrivateKey(MiscObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, mldsaPriv, ecPriv); + CompositePrivateKey mlecPriv = new CompositePrivateKey(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, mldsaPriv, ecPriv); StringWriter sWrt = new StringWriter(); JcaPEMWriter pWrt = new JcaPEMWriter(sWrt); @@ -564,7 +565,7 @@ public void testMLDSA87andEd448() PrivateKey mldsaPriv = mldsaKp.getPrivate(); PublicKey mldsaPub = mldsaKp.getPublic(); - CompositePrivateKey mlecPriv = new CompositePrivateKey(MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512, mldsaPriv, ecPriv); + CompositePrivateKey mlecPriv = new CompositePrivateKey(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256, mldsaPriv, ecPriv); StringWriter sWrt = new StringWriter(); JcaPEMWriter pWrt = new JcaPEMWriter(sWrt); diff --git a/pkix/src/test/java/org/bouncycastle/pkcs/test/PBETest.java b/pkix/src/test/java/org/bouncycastle/pkcs/test/PBETest.java index e213c9f4d2..9c23affedf 100644 --- a/pkix/src/test/java/org/bouncycastle/pkcs/test/PBETest.java +++ b/pkix/src/test/java/org/bouncycastle/pkcs/test/PBETest.java @@ -3,9 +3,16 @@ import java.security.Security; import junit.framework.TestCase; +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PBKDF2Params; +import org.bouncycastle.asn1.pkcs.PBMAC1Params; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.operator.MacCalculator; +import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.pkcs.jcajce.JcePBMac1CalculatorBuilder; +import org.bouncycastle.pkcs.jcajce.JcePBMac1CalculatorProviderBuilder; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; @@ -29,4 +36,21 @@ public void testPBESHA256() assertEquals("55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc", Hex.toHexString((byte[])pbCalculator.getKey().getRepresentation())); } + + public void testPbmac1PrfPropagation() throws OperatorCreationException { + AlgorithmIdentifier prf = new AlgorithmIdentifier(NISTObjectIdentifiers.id_hmacWithSHA3_512, null);; + AlgorithmIdentifier protectionAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBMAC1, + new PBMAC1Params( + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params("salt".getBytes(), 1234, 64, prf)), + new AlgorithmIdentifier(NISTObjectIdentifiers.id_hmacWithSHA3_512, null) + ) + ); + MacCalculator calculator = new JcePBMac1CalculatorProviderBuilder() + .setProvider(new BouncyCastleProvider()).build().get(protectionAlgorithm, "foobar123".toCharArray()); + AlgorithmIdentifier actualPrf = PBKDF2Params.getInstance( + PBMAC1Params.getInstance(calculator.getKey().getAlgorithmIdentifier().getParameters()).getKeyDerivationFunc().getParameters() + ).getPrf(); + assertTrue(prf.equals(actualPrf)); + } + } diff --git a/pkix/src/test/java/org/bouncycastle/pkcs/test/PQCPKCS10Test.java b/pkix/src/test/java/org/bouncycastle/pkcs/test/PQCPKCS10Test.java new file mode 100644 index 0000000000..f5b76ad888 --- /dev/null +++ b/pkix/src/test/java/org/bouncycastle/pkcs/test/PQCPKCS10Test.java @@ -0,0 +1,97 @@ +package org.bouncycastle.pkcs.test; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.util.Date; + +import junit.framework.TestCase; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.PrivateKeyPossessionStatement; +import org.bouncycastle.asn1.x509.X509AttributeIdentifiers; +import org.bouncycastle.cert.CertException; +import org.bouncycastle.cert.CertIOException; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.jcajce.spec.MLDSAParameterSpec; +import org.bouncycastle.jcajce.spec.MLKEMParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.ContentVerifierProvider; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.bouncycastle.pkcs.PKCS10CertificationRequestBuilder; +import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; + +public class PQCPKCS10Test + extends TestCase +{ + public void setUp() + { + Security.addProvider(new BouncyCastleProvider()); + } + + public void testKEMPKCS10() + throws Exception + { + KeyPairGenerator dilKpGen = KeyPairGenerator.getInstance("ML-DSA", "BC"); + + dilKpGen.initialize(MLDSAParameterSpec.ml_dsa_65); + + KeyPair dilKp = dilKpGen.generateKeyPair(); + + X509CertificateHolder sigCert = makeV3Certificate("CN=ML-KEM Client", dilKp); + + KeyPairGenerator kemKpGen = KeyPairGenerator.getInstance("ML-KEM", "BC"); + + kemKpGen.initialize(MLKEMParameterSpec.ml_kem_768); + + KeyPair kemKp = kemKpGen.generateKeyPair(); + + PKCS10CertificationRequestBuilder pkcs10Builder = new JcaPKCS10CertificationRequestBuilder( + new X500Name("CN=ML-KEM Client"), kemKp.getPublic()); + + pkcs10Builder.addAttribute(X509AttributeIdentifiers.id_at_statementOfPossession, + new PrivateKeyPossessionStatement(sigCert.toASN1Structure())); + + PKCS10CertificationRequest request = pkcs10Builder.build( + new JcaContentSignerBuilder("ML-DSA").setProvider("BC").build(dilKp.getPrivate())); + + assertTrue(request.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("BC").build(sigCert.getSubjectPublicKeyInfo()))); + } + + private static X509CertificateHolder makeV3Certificate(String _subDN, KeyPair issKP) + throws OperatorCreationException, CertException, CertIOException + { + PrivateKey issPriv = issKP.getPrivate(); + PublicKey issPub = issKP.getPublic(); + + X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder( + new X500Name(_subDN), + BigInteger.valueOf(System.currentTimeMillis()), + new Date(System.currentTimeMillis() - 5000L), + new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)), + new X500Name(_subDN), + issKP.getPublic()); + + certGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0)); + + ContentSigner signer = new JcaContentSignerBuilder("ML-DSA").build(issPriv); + + X509CertificateHolder certHolder = certGen.build(signer); + + ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().build(issPub); + + assertTrue(certHolder.isSignatureValid(verifier)); + + return certHolder; + } +} diff --git a/pkix/src/test/java/org/bouncycastle/pkcs/test/PfxPduTest.java b/pkix/src/test/java/org/bouncycastle/pkcs/test/PfxPduTest.java index 7486ef6df6..4468002dd7 100644 --- a/pkix/src/test/java/org/bouncycastle/pkcs/test/PfxPduTest.java +++ b/pkix/src/test/java/org/bouncycastle/pkcs/test/PfxPduTest.java @@ -35,11 +35,14 @@ import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.Attribute; import org.bouncycastle.asn1.pkcs.ContentInfo; +import org.bouncycastle.asn1.pkcs.PBKDF2Params; +import org.bouncycastle.asn1.pkcs.PBMAC1Params; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.X500NameBuilder; import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.BasicConstraints; import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; @@ -71,6 +74,7 @@ import org.bouncycastle.pkcs.bc.BcPKCS12MacCalculatorBuilderProvider; import org.bouncycastle.pkcs.bc.BcPKCS12PBEInputDecryptorProviderBuilder; import org.bouncycastle.pkcs.bc.BcPKCS12PBEOutputEncryptorBuilder; +import org.bouncycastle.pkcs.bc.BcPKCS12PBMac1CalculatorBuilder; import org.bouncycastle.pkcs.bc.BcPKCS12PBMac1CalculatorBuilderProvider; import org.bouncycastle.pkcs.jcajce.JcaPKCS12SafeBagBuilder; import org.bouncycastle.pkcs.jcajce.JcaPKCS8EncryptedPrivateKeyInfoBuilder; @@ -79,6 +83,7 @@ import org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder; import org.bouncycastle.pkcs.jcajce.JcePKCSPBEOutputEncryptorBuilder; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Base64; import org.junit.function.ThrowingRunnable; @@ -1136,6 +1141,29 @@ public void testPfxPduMac() assertFalse(pfx.isMacValid(new BcPKCS12MacCalculatorBuilderProvider(BcDefaultDigestProvider.INSTANCE), "not right".toCharArray())); } + public void testPfxPduMac1() + throws Exception + { + // + // set up the keys + // + KeyFactory fact = KeyFactory.getInstance("RSA", BC); + PrivateKey privKey = fact.generatePrivate(privKeySpec); + PublicKey pubKey = fact.generatePublic(pubKeySpec); + + X509Certificate[] chain = createCertChain(fact, pubKey); + + PKCS12PfxPdu pfx = createPfxMac1(privKey, pubKey, chain); + + assertTrue(pfx.hasMac()); + assertTrue(pfx.isMacValid(new BcPKCS12PBMac1CalculatorBuilderProvider(), passwd)); + assertFalse(pfx.isMacValid(new BcPKCS12PBMac1CalculatorBuilderProvider(), "not right".toCharArray())); + + KeyStore pkcs12 = KeyStore.getInstance("PKCS12", "BC"); + + pkcs12.load(new ByteArrayInputStream(pfx.getEncoded()), passwd); + } + public void testPfxPduPBMac1PBKdf2() throws Exception { @@ -1750,4 +1778,47 @@ private PKCS12PfxPdu createPfx(PrivateKey privKey, PublicKey pubKey, X509Certifi return pfxPduBuilder.build(new BcPKCS12MacCalculatorBuilder(), passwd); } + + private PKCS12PfxPdu createPfxMac1(PrivateKey privKey, PublicKey pubKey, X509Certificate[] chain) + throws NoSuchAlgorithmException, IOException, PKCSException + { + JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils(); + + PKCS12SafeBagBuilder taCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[2]); + + taCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Bouncy Primary Certificate")); + + PKCS12SafeBagBuilder caCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[1]); + + caCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Bouncy Intermediate Certificate")); + + PKCS12SafeBagBuilder eeCertBagBuilder = new JcaPKCS12SafeBagBuilder(chain[0]); + + eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Eric's Key")); + eeCertBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(pubKey)); + + PKCS12SafeBagBuilder keyBagBuilder = new JcaPKCS12SafeBagBuilder(privKey, new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC, new CBCBlockCipher(new DESedeEngine())).build(passwd)); + + keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName, new DERBMPString("Eric's Key")); + keyBagBuilder.addBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId, extUtils.createSubjectKeyIdentifier(pubKey)); + + // + // construct the actual key store + // + PKCS12PfxPduBuilder pfxPduBuilder = new PKCS12PfxPduBuilder(); + + PKCS12SafeBag[] certs = new PKCS12SafeBag[3]; + + certs[0] = eeCertBagBuilder.build(); + certs[1] = caCertBagBuilder.build(); + certs[2] = taCertBagBuilder.build(); + + pfxPduBuilder.addEncryptedData(new BcPKCS12PBEOutputEncryptorBuilder(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC, new CBCBlockCipher(new RC2Engine())).build(passwd), certs); + + pfxPduBuilder.addData(keyBagBuilder.build()); + + return pfxPduBuilder.build(new BcPKCS12PBMac1CalculatorBuilder(new PBMAC1Params( + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(Strings.toByteArray("saltsalt"), 1024, 256, new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA256))), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA512))), passwd); + } } diff --git a/pkix/src/test/java/org/bouncycastle/pkix/test/CheckNameConstraintsTest.java b/pkix/src/test/java/org/bouncycastle/pkix/test/CheckNameConstraintsTest.java index f3055dbdad..e24392b6ca 100644 --- a/pkix/src/test/java/org/bouncycastle/pkix/test/CheckNameConstraintsTest.java +++ b/pkix/src/test/java/org/bouncycastle/pkix/test/CheckNameConstraintsTest.java @@ -83,7 +83,7 @@ public void testPKIXCertPathBuilder() PKIXBuilderParameters buildParams = new PKIXBuilderParameters(Collections.singleton(new TrustAnchor(rootCert, null)), pathConstraints); buildParams.addCertStore(store); - buildParams.setDate(new Date()); + buildParams.setDate(new Date(1744869361113L)); // 17th April 2025 buildParams.setRevocationEnabled(false); PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult)builder.build(buildParams); @@ -116,6 +116,7 @@ public void testPKIXCertPathValidator() CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC"); PKIXParameters param = new PKIXParameters(trust); param.setRevocationEnabled(false); + param.setDate(new Date(1744869361113L)); // 17th April 2025 cpv.validate(certPath, param); } diff --git a/pkix/src/test/java/org/bouncycastle/tsp/test/GenTimeAccuracyUnitTest.java b/pkix/src/test/java/org/bouncycastle/tsp/test/GenTimeAccuracyUnitTest.java index 40ff9400db..a3f07d3bf5 100644 --- a/pkix/src/test/java/org/bouncycastle/tsp/test/GenTimeAccuracyUnitTest.java +++ b/pkix/src/test/java/org/bouncycastle/tsp/test/GenTimeAccuracyUnitTest.java @@ -8,34 +8,29 @@ public class GenTimeAccuracyUnitTest extends TestCase { - private static final ASN1Integer ZERO_VALUE = new ASN1Integer(0); - private static final ASN1Integer ONE_VALUE = new ASN1Integer(1); - private static final ASN1Integer TWO_VALUE = new ASN1Integer(2); - private static final ASN1Integer THREE_VALUE = new ASN1Integer(3); - public void testOneTwoThree() { - GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ONE_VALUE, TWO_VALUE, THREE_VALUE)); + GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ASN1Integer.ONE, ASN1Integer.TWO, ASN1Integer.THREE)); - checkValues(accuracy, ONE_VALUE, TWO_VALUE, THREE_VALUE); + checkValues(accuracy, ASN1Integer.ONE, ASN1Integer.TWO, ASN1Integer.THREE); checkToString(accuracy, "1.002003"); } public void testThreeTwoOne() { - GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(THREE_VALUE, TWO_VALUE, ONE_VALUE)); + GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ASN1Integer.THREE, ASN1Integer.TWO, ASN1Integer.ONE)); - checkValues(accuracy, THREE_VALUE, TWO_VALUE, ONE_VALUE); + checkValues(accuracy, ASN1Integer.THREE, ASN1Integer.TWO, ASN1Integer.ONE); checkToString(accuracy, "3.002001"); } public void testTwoThreeTwo() { - GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(TWO_VALUE, THREE_VALUE, TWO_VALUE)); + GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ASN1Integer.TWO, ASN1Integer.THREE, ASN1Integer.TWO)); - checkValues(accuracy, TWO_VALUE, THREE_VALUE, TWO_VALUE); + checkValues(accuracy, ASN1Integer.TWO, ASN1Integer.THREE, ASN1Integer.TWO); checkToString(accuracy, "2.003002"); } @@ -43,36 +38,36 @@ public void testTwoThreeTwo() public void testZeroTwoThree() { - GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ZERO_VALUE, TWO_VALUE, THREE_VALUE)); + GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ASN1Integer.ZERO, ASN1Integer.TWO, ASN1Integer.THREE)); - checkValues(accuracy, ZERO_VALUE, TWO_VALUE, THREE_VALUE); + checkValues(accuracy, ASN1Integer.ZERO, ASN1Integer.TWO, ASN1Integer.THREE); checkToString(accuracy, "0.002003"); } public void testThreeTwoNull() { - GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(THREE_VALUE, TWO_VALUE, null)); + GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ASN1Integer.THREE, ASN1Integer.TWO, null)); - checkValues(accuracy, THREE_VALUE, TWO_VALUE, ZERO_VALUE); + checkValues(accuracy, ASN1Integer.THREE, ASN1Integer.TWO, ASN1Integer.ZERO); checkToString(accuracy, "3.002000"); } public void testOneNullOne() { - GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ONE_VALUE, null, ONE_VALUE)); + GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ASN1Integer.ONE, null, ASN1Integer.ONE)); - checkValues(accuracy, ONE_VALUE, ZERO_VALUE, ONE_VALUE); + checkValues(accuracy, ASN1Integer.ONE, ASN1Integer.ZERO, ASN1Integer.ONE); checkToString(accuracy, "1.000001"); } public void testZeroNullNull() { - GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ZERO_VALUE, null, null)); + GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(ASN1Integer.ZERO, null, null)); - checkValues(accuracy, ZERO_VALUE, ZERO_VALUE, ZERO_VALUE); + checkValues(accuracy, ASN1Integer.ZERO, ASN1Integer.ZERO, ASN1Integer.ZERO); checkToString(accuracy, "0.000000"); } @@ -81,7 +76,7 @@ public void testNullNullNull() { GenTimeAccuracy accuracy = new GenTimeAccuracy(new Accuracy(null, null, null)); - checkValues(accuracy, ZERO_VALUE, ZERO_VALUE, ZERO_VALUE); + checkValues(accuracy, ASN1Integer.ZERO, ASN1Integer.ZERO, ASN1Integer.ZERO); checkToString(accuracy, "0.000000"); } diff --git a/pkix/src/test/java/org/bouncycastle/tsp/test/PQCTSPTest.java b/pkix/src/test/java/org/bouncycastle/tsp/test/PQCTSPTest.java index 7b208598b9..acb9102678 100644 --- a/pkix/src/test/java/org/bouncycastle/tsp/test/PQCTSPTest.java +++ b/pkix/src/test/java/org/bouncycastle/tsp/test/PQCTSPTest.java @@ -8,6 +8,7 @@ import java.security.Security; import java.security.cert.X509Certificate; import java.util.Date; +import java.util.Iterator; import junit.framework.TestCase; import org.bouncycastle.asn1.ASN1ObjectIdentifier; @@ -23,6 +24,7 @@ import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; import org.bouncycastle.cms.jcajce.JcaSignerInfoVerifierBuilder; +import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeIndex; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; @@ -194,4 +196,238 @@ public void testSPHINCSPlus() assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate)); } + + public void testSLHDSA() + throws Exception + { + // + // set up the keys + // + PrivateKey privKey; + PublicKey pubKey; + + try + { + KeyPairGenerator g = KeyPairGenerator.getInstance("SLH-DSA", BC); + + KeyPair p = g.generateKeyPair(); + + privKey = p.getPrivate(); + pubKey = p.getPublic(); + } + catch (Exception e) + { + fail("error setting up keys - " + e); + return; + } + + // + // extensions + // + + // + // create the certificate - version 1 + // + + ContentSigner sigGen = new JcaContentSignerBuilder("SLH-DSA") + .setProvider(BC).build(privKey); + JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder( + new X500Name("CN=Test"), + BigInteger.valueOf(1), + new Date(System.currentTimeMillis() - 50000), + new Date(System.currentTimeMillis() + 50000), + new X500Name("CN=Test"), + pubKey); + + certGen.addExtension(Extension.extendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.id_kp_timeStamping)); + + X509Certificate cert = new JcaX509CertificateConverter() + .setProvider("BC").getCertificate(certGen.build(sigGen)); + + ContentSigner signer = new JcaContentSignerBuilder("SLH-DSA").setProvider(BC).build(privKey); + + TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator( + new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()) + .setContentDigest(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512)) + .build(signer, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2")); + + // tsTokenGen.addCertificates(certs); + + TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator(); + TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA3_256, new byte[32], BigInteger.valueOf(100)); + + 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 JcaSignerInfoVerifierBuilder(new JcaDigestCalculatorProviderBuilder().build()) + .setProvider(BC).build(cert)); + + AttributeTable table = tsToken.getSignedAttributes(); + + assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate)); + } + + public void testMLDSA() + throws Exception + { + // + // set up the keys + // + PrivateKey privKey; + PublicKey pubKey; + + try + { + KeyPairGenerator g = KeyPairGenerator.getInstance("ML-DSA", BC); + + KeyPair p = g.generateKeyPair(); + + privKey = p.getPrivate(); + pubKey = p.getPublic(); + } + catch (Exception e) + { + fail("error setting up keys - " + e); + return; + } + + // + // extensions + // + + // + // create the certificate - version 1 + // + + ContentSigner sigGen = new JcaContentSignerBuilder("SLH-DSA") + .setProvider(BC).build(privKey); + JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder( + new X500Name("CN=Test"), + BigInteger.valueOf(1), + new Date(System.currentTimeMillis() - 50000), + new Date(System.currentTimeMillis() + 50000), + new X500Name("CN=Test"), + pubKey); + + certGen.addExtension(Extension.extendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.id_kp_timeStamping)); + + X509Certificate cert = new JcaX509CertificateConverter() + .setProvider("BC").getCertificate(certGen.build(sigGen)); + + ContentSigner signer = new JcaContentSignerBuilder("ML-DSA").setProvider(BC).build(privKey); + + TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator( + new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()) + .setContentDigest(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512)) + .build(signer, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2")); + + // tsTokenGen.addCertificates(certs); + + TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator(); + TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA3_256, new byte[32], BigInteger.valueOf(100)); + + 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 JcaSignerInfoVerifierBuilder(new JcaDigestCalculatorProviderBuilder().build()) + .setProvider(BC).build(cert)); + + AttributeTable table = tsToken.getSignedAttributes(); + + assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate)); + } + + public void testComposite() + throws Exception + { + for (Iterator it = CompositeIndex.getSupportedIdentifiers().iterator(); it.hasNext(); ) + { + String name = CompositeIndex.getAlgorithmName((ASN1ObjectIdentifier)it.next()); + doTestComposite(name); + } + } + + private void doTestComposite(String algorithmName) + throws Exception + { + // + // set up the keys + // + PrivateKey privKey; + PublicKey pubKey; + + try + { + KeyPairGenerator g = KeyPairGenerator.getInstance(algorithmName, BC); + + KeyPair p = g.generateKeyPair(); + + privKey = p.getPrivate(); + pubKey = p.getPublic(); + } + catch (Exception e) + { + fail("error setting up keys - " + e); + return; + } + + // + // extensions + // + + // + // create the certificate - version 1 + // + + ContentSigner sigGen = new JcaContentSignerBuilder(algorithmName) + .setProvider(BC).build(privKey); + JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder( + new X500Name("CN=Test"), + BigInteger.valueOf(1), + new Date(System.currentTimeMillis() - 50000), + new Date(System.currentTimeMillis() + 50000), + new X500Name("CN=Test"), + pubKey); + + certGen.addExtension(Extension.extendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.id_kp_timeStamping)); + + X509Certificate cert = new JcaX509CertificateConverter() + .setProvider("BC").getCertificate(certGen.build(sigGen)); + + ContentSigner signer = new JcaContentSignerBuilder(algorithmName).setProvider(BC).build(privKey); + + TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator( + new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()) + .build(signer, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2")); + + // tsTokenGen.addCertificates(certs); + + TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator(); + TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA3_256, new byte[32], BigInteger.valueOf(100)); + + 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 JcaSignerInfoVerifierBuilder(new JcaDigestCalculatorProviderBuilder().build()) + .setProvider(BC).build(cert)); + + AttributeTable table = tsToken.getSignedAttributes(); + + assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate)); + } } diff --git a/pkix/src/test/jdk1.4/org/bouncycastle/cert/test/AllTests.java b/pkix/src/test/jdk1.4/org/bouncycastle/cert/test/AllTests.java new file mode 100644 index 0000000000..55c6c6c946 --- /dev/null +++ b/pkix/src/test/jdk1.4/org/bouncycastle/cert/test/AllTests.java @@ -0,0 +1,101 @@ +package org.bouncycastle.cert.test; + +import java.security.Security; + +import junit.extensions.TestSetup; +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.test.PrintTestResult; +import org.bouncycastle.util.test.SimpleTestResult; + +public class AllTests + extends TestCase +{ + public void setUp() + { + if (Security.getProvider("BC") == null) + { + Security.addProvider(new BouncyCastleProvider()); + } + } + + public void testSimpleTests() + { + org.bouncycastle.util.test.Test[] tests = new org.bouncycastle.util.test.Test[] + { + new AttrCertSelectorTest(), + new AttrCertTest(), + new CertPathLoopTest(), + new CertTest(), + new DANETest(), + new ExternalKeyTest(), + new GOST3410_2012CMSTest(), + new MLDSACredentialsTest(), + new PKCS10Test(), + new SLHDSACredentialsTest(), + new X509ExtensionUtilsTest(), + }; + + for (int i = 0; i != tests.length; i++) + { + SimpleTestResult result = (SimpleTestResult)tests[i].perform(); + + if (!result.isSuccessful()) + { + if (result.getException() != null) + { + result.getException().printStackTrace(); + } + fail(result.toString()); + } + } + } + + public static void main (String[] args) + { + PrintTestResult.printResult(junit.textui.TestRunner.run(suite())); + } + + public static Test suite() + { + TestSuite suite = new TestSuite("Cert Tests"); + + if (Security.getProvider("BC") == null) + { + Security.addProvider(new BouncyCastleProvider()); + } + + suite.addTestSuite(AllTests.class); + suite.addTestSuite(BcAttrCertSelectorTest.class); + suite.addTestSuite(BcAttrCertSelectorTest.class); + suite.addTestSuite(BcAttrCertTest.class); + suite.addTestSuite(BcCertTest.class); + suite.addTestSuite(BcPKCS10Test.class); + suite.addTestSuite(PQCPKCS10Test.class); + suite.addTest(ConverterTest.suite()); + + return new BCTestSetup(suite); + } + + static class BCTestSetup + extends TestSetup + { + public BCTestSetup(Test test) + { + super(test); + } + + protected void setUp() + { + Security.addProvider(new BouncyCastleProvider()); + } + + protected void tearDown() + { + Security.removeProvider("BC"); + } + } + +} \ No newline at end of file diff --git a/pkix/src/test/jdk1.4/org/bouncycastle/tsp/test/PQCTSPTest.java b/pkix/src/test/jdk1.4/org/bouncycastle/tsp/test/PQCTSPTest.java new file mode 100644 index 0000000000..697805e5d1 --- /dev/null +++ b/pkix/src/test/jdk1.4/org/bouncycastle/tsp/test/PQCTSPTest.java @@ -0,0 +1,348 @@ +package org.bouncycastle.tsp.test; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.Iterator; + +import junit.framework.TestCase; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.cms.AttributeTable; +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.ExtendedKeyUsage; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.KeyPurposeId; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; +import org.bouncycastle.cms.jcajce.JcaSignerInfoVerifierBuilder; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; +import org.bouncycastle.tsp.TSPAlgorithms; +import org.bouncycastle.tsp.TimeStampRequest; +import org.bouncycastle.tsp.TimeStampRequestGenerator; +import org.bouncycastle.tsp.TimeStampResponse; +import org.bouncycastle.tsp.TimeStampResponseGenerator; +import org.bouncycastle.tsp.TimeStampToken; +import org.bouncycastle.tsp.TimeStampTokenGenerator; + +public class PQCTSPTest + extends TestCase +{ + private static final String BC = BouncyCastleProvider.PROVIDER_NAME; + + public void setUp() + { + Security.addProvider(new BouncyCastleProvider()); + } + + public void testLMS() + throws Exception + { + // + // set up the keys + // + PrivateKey privKey; + PublicKey pubKey; + + try + { + KeyPairGenerator g = KeyPairGenerator.getInstance("LMS", BC); + + KeyPair p = g.generateKeyPair(); + + privKey = p.getPrivate(); + pubKey = p.getPublic(); + } + catch (Exception e) + { + fail("error setting up keys - " + e); + return; + } + + // + // extensions + // + + // + // create the certificate - version 1 + // + + ContentSigner sigGen = new JcaContentSignerBuilder("LMS") + .setProvider(BC).build(privKey); + JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder( + new X500Name("CN=Test"), + BigInteger.valueOf(1), + new Date(System.currentTimeMillis() - 50000), + new Date(System.currentTimeMillis() + 50000), + new X500Name("CN=Test"), + pubKey); + + certGen.addExtension(Extension.extendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.id_kp_timeStamping)); + + X509Certificate cert = new JcaX509CertificateConverter() + .setProvider("BC").getCertificate(certGen.build(sigGen)); + + ContentSigner signer = new JcaContentSignerBuilder("LMS").setProvider(BC).build(privKey); + + TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator( + new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()) + .setContentDigest(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha3_512)) + .build(signer, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2")); + + // tsTokenGen.addCertificates(certs); + + TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator(); + TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA3_512, new byte[64], BigInteger.valueOf(100)); + + 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 JcaSignerInfoVerifierBuilder(new JcaDigestCalculatorProviderBuilder().build()) + .setProvider(BC).build(cert)); + + AttributeTable table = tsToken.getSignedAttributes(); + + assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate)); + } + + public void testSPHINCSPlus() + throws Exception + { + // + // set up the keys + // + PrivateKey privKey; + PublicKey pubKey; + + try + { + KeyPairGenerator g = KeyPairGenerator.getInstance("SLH-DSA", BC); + + KeyPair p = g.generateKeyPair(); + + privKey = p.getPrivate(); + pubKey = p.getPublic(); + } + catch (Exception e) + { + fail("error setting up keys - " + e); + return; + } + + // + // extensions + // + + // + // create the certificate - version 1 + // + + ContentSigner sigGen = new JcaContentSignerBuilder("SLH-DSA-SHA2-128F") + .setProvider(BC).build(privKey); + JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder( + new X500Name("CN=Test"), + BigInteger.valueOf(1), + new Date(System.currentTimeMillis() - 50000), + new Date(System.currentTimeMillis() + 50000), + new X500Name("CN=Test"), + pubKey); + + certGen.addExtension(Extension.extendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.id_kp_timeStamping)); + + X509Certificate cert = new JcaX509CertificateConverter() + .setProvider("BC").getCertificate(certGen.build(sigGen)); + + ContentSigner signer = new JcaContentSignerBuilder("SLH-DSA-SHA2-128F").setProvider(BC).build(privKey); + + TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator( + new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()) + .setContentDigest(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha3_256)) + .build(signer, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2")); + + // tsTokenGen.addCertificates(certs); + + TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator(); + TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA3_256, new byte[32], BigInteger.valueOf(100)); + + 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 JcaSignerInfoVerifierBuilder(new JcaDigestCalculatorProviderBuilder().build()) + .setProvider(BC).build(cert)); + + AttributeTable table = tsToken.getSignedAttributes(); + + assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate)); + } + + public void testSLHDSA() + throws Exception + { + // + // set up the keys + // + PrivateKey privKey; + PublicKey pubKey; + + try + { + KeyPairGenerator g = KeyPairGenerator.getInstance("SLH-DSA", BC); + + KeyPair p = g.generateKeyPair(); + + privKey = p.getPrivate(); + pubKey = p.getPublic(); + } + catch (Exception e) + { + fail("error setting up keys - " + e); + return; + } + + // + // extensions + // + + // + // create the certificate - version 1 + // + + ContentSigner sigGen = new JcaContentSignerBuilder("SLH-DSA") + .setProvider(BC).build(privKey); + JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder( + new X500Name("CN=Test"), + BigInteger.valueOf(1), + new Date(System.currentTimeMillis() - 50000), + new Date(System.currentTimeMillis() + 50000), + new X500Name("CN=Test"), + pubKey); + + certGen.addExtension(Extension.extendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.id_kp_timeStamping)); + + X509Certificate cert = new JcaX509CertificateConverter() + .setProvider("BC").getCertificate(certGen.build(sigGen)); + + ContentSigner signer = new JcaContentSignerBuilder("SLH-DSA").setProvider(BC).build(privKey); + + TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator( + new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()) + .setContentDigest(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512)) + .build(signer, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2")); + + // tsTokenGen.addCertificates(certs); + + TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator(); + TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA3_256, new byte[32], BigInteger.valueOf(100)); + + 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 JcaSignerInfoVerifierBuilder(new JcaDigestCalculatorProviderBuilder().build()) + .setProvider(BC).build(cert)); + + AttributeTable table = tsToken.getSignedAttributes(); + + assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate)); + } + + public void testMLDSA() + throws Exception + { + // + // set up the keys + // + PrivateKey privKey; + PublicKey pubKey; + + try + { + KeyPairGenerator g = KeyPairGenerator.getInstance("ML-DSA", BC); + + KeyPair p = g.generateKeyPair(); + + privKey = p.getPrivate(); + pubKey = p.getPublic(); + } + catch (Exception e) + { + fail("error setting up keys - " + e); + return; + } + + // + // extensions + // + + // + // create the certificate - version 1 + // + + ContentSigner sigGen = new JcaContentSignerBuilder("SLH-DSA") + .setProvider(BC).build(privKey); + JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder( + new X500Name("CN=Test"), + BigInteger.valueOf(1), + new Date(System.currentTimeMillis() - 50000), + new Date(System.currentTimeMillis() + 50000), + new X500Name("CN=Test"), + pubKey); + + certGen.addExtension(Extension.extendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.id_kp_timeStamping)); + + X509Certificate cert = new JcaX509CertificateConverter() + .setProvider("BC").getCertificate(certGen.build(sigGen)); + + ContentSigner signer = new JcaContentSignerBuilder("ML-DSA").setProvider(BC).build(privKey); + + TimeStampTokenGenerator tsTokenGen = new TimeStampTokenGenerator( + new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()) + .setContentDigest(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512)) + .build(signer, cert), new SHA1DigestCalculator(), new ASN1ObjectIdentifier("1.2")); + + // tsTokenGen.addCertificates(certs); + + TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator(); + TimeStampRequest request = reqGen.generate(TSPAlgorithms.SHA3_256, new byte[32], BigInteger.valueOf(100)); + + 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 JcaSignerInfoVerifierBuilder(new JcaDigestCalculatorProviderBuilder().build()) + .setProvider(BC).build(cert)); + + AttributeTable table = tsToken.getSignedAttributes(); + + assertNotNull("no signingCertificate attribute found", table.get(PKCSObjectIdentifiers.id_aa_signingCertificate)); + } +} diff --git a/prov/build.gradle b/prov/build.gradle index c0b531d054..d411b7f54d 100644 --- a/prov/build.gradle +++ b/prov/build.gradle @@ -1,8 +1,10 @@ plugins { - id "biz.aQute.bnd.builder" version "7.0.0" + id "biz.aQute.bnd.builder" version "7.1.0" } dependencies { + implementation project(':core') + testImplementation project(':core') testImplementation files('../libs/unboundid-ldapsdk-6.0.8.jar') } @@ -11,13 +13,14 @@ evaluationDependsOn(":core") sourceSets { main { java { - srcDirs "${project(":core").projectDir}/src/main/java" + srcDirs = ["${projectDir}/../core/src/main/java","src/main/java"] } resources { - srcDirs "${project(":core").projectDir}/src/main/resources" + srcDirs= ["${projectDir}/../core/src/main/resources","src/main/resources"] } } + java9 { java { srcDirs = ['src/main/jdk1.9'] @@ -33,9 +36,14 @@ sourceSets { srcDirs = ['src/main/jdk1.15'] } } - java21 { + java17 { + java { + srcDirs = ['src/main/jdk17'] + } + } + java25 { java { - srcDirs = ['src/main/jdk21'] + srcDirs = ['src/main/jdk25'] } } @@ -60,13 +68,22 @@ dependencies { builtBy compileJava11Java } - java21Implementation files([ + java17Implementation files([ sourceSets.main.output.classesDirs, sourceSets.java9.output.classesDirs, sourceSets.java11.output.classesDirs, sourceSets.java15.output.classesDirs]) { builtBy compileJava15Java } + + java25Implementation files([ + sourceSets.main.output.classesDirs, + sourceSets.java9.output.classesDirs, + sourceSets.java11.output.classesDirs, + sourceSets.java15.output.classesDirs, + sourceSets.java17.output.classesDirs]) { + builtBy compileJava17Java + } } @@ -89,9 +106,15 @@ compileJava15Java { options.sourcepath = files(['src/main/java', 'src/main/jdk1.15']) } -compileJava21Java { - options.release = 21 - options.sourcepath = files(['src/main/java', 'src/main/jdk21']) +compileJava17Java { + targetCompatibility = 17 + sourceCompatibility = 17 + options.sourcepath = files(['src/main/java', 'src/main/jdk17']) +} + +compileJava25Java { + options.release = 25 + options.sourcepath = files(['src/main/java', 'src/main/jdk25']) } @@ -110,8 +133,11 @@ task sourcesJar(type: Jar) { into('META-INF/versions/15') { from sourceSets.java15.allSource } - into('META-INF/versions/21') { - from sourceSets.java21.allSource + into('META-INF/versions/17') { + from sourceSets.java17.allSource + } + into('META-INF/versions/25') { + from sourceSets.java25.allSource } } @@ -129,8 +155,11 @@ jar { into('META-INF/versions/15') { from sourceSets.java15.output } - into('META-INF/versions/21') { - from sourceSets.java21.output + into('META-INF/versions/17') { + from sourceSets.java17.output + } + into('META-INF/versions/25') { + from sourceSets.java25.output } String v = "${rootProject.extensions.ext.bundle_version}" manifest.attributes('Multi-Release': 'true') @@ -140,7 +169,11 @@ jar { manifest.attributes('Export-Package': "!org.bouncycastle.internal.*,org.bouncycastle.*;version=${v}") manifest.attributes('Import-Package': 'java.*;resolution:=optional,javax.*;resolution:=optional') manifest.attributes('Bundle-Version': "${v}") - + manifest.attributes('Permissions': 'all-permissions') + manifest.attributes('Codebase': '*') + manifest.attributes('Application-Library-Allowable-Codebase': '*') + manifest.attributes('Caller-Allowable-Codebase': '*') + manifest.attributes('Trusted-Library': 'true') } @@ -176,25 +209,47 @@ sourceSets { } } - test21 { + test17 { java { compileClasspath += main.output + test.output runtimeClasspath += test.output - srcDir(files("src/test/jdk21")) + srcDir(files("src/test/jdk17")) + } + } + + test25 { + java { + compileClasspath += main.output + test.output + runtimeClasspath += test.output + srcDir(files("src/test/jdk25")) } } } +dependencies { + java9Implementation project(':core') + java11Implementation project(':core') + java15Implementation project(':core') + java17Implementation project(':core') + java25Implementation project(':core') +} + dependencies { test11Implementation group: 'junit', name: 'junit', version: '4.13.2' test15Implementation group: 'junit', name: 'junit', version: '4.13.2' - test21Implementation group: 'junit', name: 'junit', version: '4.13.2' + test17Implementation group: 'junit', name: 'junit', version: '4.13.2' + test25Implementation group: 'junit', name: 'junit', version: '4.13.2' test11Implementation files('../libs/unboundid-ldapsdk-6.0.8.jar') test15Implementation files('../libs/unboundid-ldapsdk-6.0.8.jar') - test21Implementation files('../libs/unboundid-ldapsdk-6.0.8.jar') + test17Implementation files('../libs/unboundid-ldapsdk-6.0.8.jar') + test25Implementation files('../libs/unboundid-ldapsdk-6.0.8.jar') test11Implementation(project(":core")) test15Implementation(project(":core")) - test21Implementation(project(":core")) + test17Implementation(project(":core")) + test25Implementation(project(":core")) + test25Implementation sourceSets.java25.output + + } @@ -210,9 +265,15 @@ compileTest15Java { options.sourcepath = files(['src/test/java', 'src/test/jdk1.15']) } -compileTest21Java { - options.release = 21 - options.sourcepath = files(['src/test/java', 'src/test/jdk21']) +compileTest17Java { + targetCompatibility = 17 + sourceCompatibility = 17 + options.sourcepath = files(['src/test/java', 'src/test/jdk17']) +} + +compileTest25Java { + options.release = 25 + options.sourcepath = files(['src/test/java', 'src/test/jdk25']) } publishing { @@ -229,6 +290,13 @@ publishing { } } +configurations { + test11Implementation.extendsFrom testImplementation + test15Implementation.extendsFrom testImplementation + test17Implementation.extendsFrom testImplementation + test25Implementation.extendsFrom testImplementation +} + test { jvmArgs = ['-Dtest.java.version.prefix=any'] @@ -330,14 +398,14 @@ task test15(type: Test) { } } -task test21(type: Test) { +task test17(type: Test) { - // This is testing the 21 code base - onlyIf {System.getenv("BC_JDK21") != null} + // This is testing the 17 code base + onlyIf {System.getenv("BC_JDK17") != null} dependsOn jar - testClassesDirs = sourceSets.test21.output.classesDirs - classpath = sourceSets.test21.runtimeClasspath + files(jar.archiveFile) + testClassesDirs = sourceSets.test17.output.classesDirs + classpath = sourceSets.test17.runtimeClasspath + files(jar.archiveFile) forkEvery = 1; maxParallelForks = 8; @@ -347,10 +415,43 @@ task test21(type: Test) { testLogging.showStandardStreams = false javaLauncher = javaToolchains.launcherFor { - languageVersion = JavaLanguageVersion.of(21) + languageVersion = JavaLanguageVersion.of(17) } - jvmArgs = ['-Dtest.java.version.prefix=21'] + jvmArgs = ['-Dtest.java.version.prefix=17'] + + + finalizedBy jacocoTestReport + + filter { + includeTestsMatching "AllTest*" + if (project.hasProperty('excludeTests')) { + excludeTestsMatching "${excludeTests}" + } + } +} + +task test25(type: Test) { + + // This is testing the 25 code base + onlyIf {System.getenv("BC_JDK25") != null} + dependsOn jar + + testClassesDirs = sourceSets.test25.output.classesDirs + classpath = sourceSets.test25.runtimeClasspath + files(jar.archiveFile) + + forkEvery = 1; + maxParallelForks = 8; + + systemProperty 'bc.test.data.home', bcTestDataHome + maxHeapSize = "1536m" + testLogging.showStandardStreams = false + + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(25) + } + + jvmArgs = ['-Dtest.java.version.prefix=25'] finalizedBy jacocoTestReport @@ -378,11 +479,14 @@ if (System.getenv("BC_JDK17") != null) { test.dependsOn("test15") } -if (System.getenv("BC_JDK21") != null) { - System.out.println("${project.name}: Adding test21 as dependency for test task because BC_JDK21 is defined") - test.dependsOn("test21") +if (System.getenv("BC_JDK17") != null) { + System.out.println("${project.name}: Adding test17 as dependency for test task because BC_JDK17 is defined") + test.dependsOn("test17") +} +if (System.getenv("BC_JDK25") != null) { + System.out.println("${project.name}: Adding test25 as dependency for test task because BC_JDK25 is defined") + test.dependsOn("test25") } - diff --git a/prov/src/main/ext-jdk1.9/module-info.java b/prov/src/main/ext-jdk1.9/module-info.java index 97a1f88810..b4f0ba7462 100644 --- a/prov/src/main/ext-jdk1.9/module-info.java +++ b/prov/src/main/ext-jdk1.9/module-info.java @@ -8,6 +8,9 @@ opens org.bouncycastle.jcajce.provider.asymmetric.edec to java.base; opens org.bouncycastle.pqc.jcajce.provider.lms to java.base; + opens org.bouncycastle.jcajce.provider.asymmetric.mldsa to java.base; + opens org.bouncycastle.jcajce.provider.asymmetric.mlkem to java.base; + opens org.bouncycastle.jcajce.provider.asymmetric.slhdsa to java.base; exports org.bouncycastle; exports org.bouncycastle.asn1; @@ -110,20 +113,22 @@ exports org.bouncycastle.pqc.crypto.bike; exports org.bouncycastle.pqc.crypto.cmce; exports org.bouncycastle.pqc.crypto.crystals.dilithium; + exports org.bouncycastle.pqc.crypto.mldsa; exports org.bouncycastle.pqc.crypto.mlkem; exports org.bouncycastle.pqc.crypto.falcon; exports org.bouncycastle.pqc.crypto.frodo; - exports org.bouncycastle.pqc.crypto.gemss; + exports org.bouncycastle.pqc.legacy.crypto.gemss; exports org.bouncycastle.pqc.crypto.hqc; exports org.bouncycastle.pqc.crypto.lms; + exports org.bouncycastle.pqc.crypto.mayo; exports org.bouncycastle.pqc.crypto.newhope; exports org.bouncycastle.pqc.crypto.ntru; exports org.bouncycastle.pqc.crypto.ntruprime; exports org.bouncycastle.pqc.crypto.picnic; - exports org.bouncycastle.pqc.crypto.rainbow; exports org.bouncycastle.pqc.crypto.saber; exports org.bouncycastle.pqc.crypto.sphincs; exports org.bouncycastle.pqc.crypto.sphincsplus; + exports org.bouncycastle.pqc.crypto.snova; exports org.bouncycastle.pqc.crypto.util; exports org.bouncycastle.pqc.crypto.xmss; exports org.bouncycastle.pqc.math.ntru; diff --git a/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java index 4abe0d3a4a..da219bb1e3 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java @@ -2,17 +2,24 @@ import java.io.IOException; import java.security.PrivateKey; +import java.security.Provider; +import java.security.Security; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.bouncycastle.asn1.ASN1BitString; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.sec.ECPrivateKey; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers; import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers; +import org.bouncycastle.jcajce.interfaces.MLDSAPrivateKey; import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeIndex; import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.KeyFactorySpi; import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; @@ -22,11 +29,70 @@ /** * A composite private key class. */ -public class CompositePrivateKey implements PrivateKey +public class CompositePrivateKey + implements PrivateKey { + public static class Builder + { + private final AlgorithmIdentifier algorithmIdentifier; + private final PrivateKey[] keys = new PrivateKey[2]; + private final Provider[] providers = new Provider[2]; + + private int count = 0; + + private Builder(AlgorithmIdentifier algorithmIdentifier) + { + this.algorithmIdentifier = algorithmIdentifier; + } + + public Builder addPrivateKey(PrivateKey key) + { + return addPrivateKey(key, (Provider)null); + } + + public Builder addPrivateKey(PrivateKey key, String providerName) + { + return addPrivateKey(key, Security.getProvider(providerName)); + } + + public Builder addPrivateKey(PrivateKey key, Provider provider) + { + if (count == keys.length) + { + throw new IllegalStateException("only " + keys.length + " allowed in composite"); + } + + keys[count] = key; + providers[count++] = provider; + + return this; + } + + public CompositePrivateKey build() + { + if (providers[0] == null && providers[1] == null) + { + return new CompositePrivateKey(algorithmIdentifier, keys, null); + } + + return new CompositePrivateKey(algorithmIdentifier, keys, providers); + } + } + + public static Builder builder(ASN1ObjectIdentifier compAlgOid) + { + return new Builder(new AlgorithmIdentifier(compAlgOid)); + } + + public static Builder builder(String algorithmName) + { + return builder(CompositeUtil.getOid(algorithmName)); + } + private final List keys; + private final List providers; - private ASN1ObjectIdentifier algorithmIdentifier; + private AlgorithmIdentifier algorithmIdentifier; /** * Create a composite private key from an array of PublicKeys. @@ -39,6 +105,11 @@ public CompositePrivateKey(PrivateKey... keys) this(MiscObjectIdentifiers.id_composite_key, keys); } + public CompositePrivateKey(ASN1ObjectIdentifier algorithm, PrivateKey... keys) + { + this(new AlgorithmIdentifier(algorithm), keys); + } + /** * Create a composite private key which corresponds to a composite signature algorithm in algorithmIdentifier. * The component private keys are not checked if they satisfy the composite definition at this point, @@ -47,7 +118,7 @@ public CompositePrivateKey(PrivateKey... keys) * @param algorithmIdentifier * @param keys */ - public CompositePrivateKey(ASN1ObjectIdentifier algorithmIdentifier, PrivateKey... keys) + public CompositePrivateKey(AlgorithmIdentifier algorithmIdentifier, PrivateKey... keys) { this.algorithmIdentifier = algorithmIdentifier; @@ -59,9 +130,63 @@ public CompositePrivateKey(ASN1ObjectIdentifier algorithmIdentifier, PrivateKey. List keyList = new ArrayList(keys.length); for (int i = 0; i < keys.length; i++) { - keyList.add(keys[i]); + keyList.add(processKey(keys[i])); + } + this.keys = Collections.unmodifiableList(keyList); + this.providers = null; + } + + private PrivateKey processKey(PrivateKey key) + { + // we assume this also means BCKey + if (key instanceof MLDSAPrivateKey) + { + // TODO: we don't insist on seed but we try to accommodate it - the debate continues + try + { + return ((MLDSAPrivateKey)key).getPrivateKey(true); + } + catch (Exception e) + { + return key; + } + } + else + { + return key; + } + } + + private CompositePrivateKey(AlgorithmIdentifier algorithmIdentifier, PrivateKey[] keys, Provider[] providers) + { + this.algorithmIdentifier = algorithmIdentifier; + + if (keys.length != 2) + { + throw new IllegalArgumentException("two keys required for composite private key"); + } + + List keyList = new ArrayList(keys.length); + if (providers == null) + { + for (int i = 0; i < keys.length; i++) + { + keyList.add(processKey(keys[i])); + } + this.providers = null; + } + else + { + List providerList = new ArrayList(providers.length); + for (int i = 0; i < keys.length; i++) + { + providerList.add(providers[i]); + keyList.add(processKey(keys[i])); + } + this.providers = Collections.unmodifiableList(providerList); } this.keys = Collections.unmodifiableList(keyList); + } /** @@ -80,7 +205,7 @@ public CompositePrivateKey(PrivateKeyInfo keyInfo) throw new IllegalStateException("Unable to create CompositePrivateKey from PrivateKeyInfo"); } AsymmetricKeyInfoConverter keyInfoConverter = new KeyFactorySpi(); - privateKeyFromFactory = (CompositePrivateKey) keyInfoConverter.generatePrivate(keyInfo); + privateKeyFromFactory = (CompositePrivateKey)keyInfoConverter.generatePrivate(keyInfo); if (privateKeyFromFactory == null) { @@ -93,6 +218,7 @@ public CompositePrivateKey(PrivateKeyInfo keyInfo) } this.keys = privateKeyFromFactory.getPrivateKeys(); + this.providers = null; this.algorithmIdentifier = privateKeyFromFactory.getAlgorithmIdentifier(); } @@ -106,12 +232,22 @@ public List getPrivateKeys() return keys; } + /** + * Return a list of the providers supporting the component private keys. + * + * @return an immutable list of Provider objects. + */ + public List getProviders() + { + return providers; + } + public String getAlgorithm() { - return CompositeIndex.getAlgorithmName(this.algorithmIdentifier); + return CompositeIndex.getAlgorithmName(this.algorithmIdentifier.getAlgorithm()); } - public ASN1ObjectIdentifier getAlgorithmIdentifier() + public AlgorithmIdentifier getAlgorithmIdentifier() { return algorithmIdentifier; } @@ -123,26 +259,80 @@ public String getFormat() /** * Returns the encoding of the composite private key. - * It is compliant with https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html#name-compositesignatureprivateke + * It is compliant with + * Composite ML-DSA for use in X.509 Public Key Infrastructure * as each component is encoded as a PrivateKeyInfo (older name for OneAsymmetricKey). * * @return */ public byte[] getEncoded() { + ASN1ObjectIdentifier algOid = algorithmIdentifier.getAlgorithm(); + + if (algOid.on(IANAObjectIdentifiers.id_alg)) + { + try + { + PrivateKey key0 = keys.get(0); + PrivateKey key1 = keys.get(1); + + byte[] mldsaSeed = ((MLDSAPrivateKey)key0).getSeed(); + + PrivateKeyInfo pki = PrivateKeyInfo.getInstance(key1.getEncoded()); + + byte[] tradSK; + String key1Algorithm = key1.getAlgorithm(); + if (key1Algorithm.contains("Ed")) + { + tradSK = ASN1OctetString.getInstance(pki.parsePrivateKey()).getOctets(); + } + else if (key1Algorithm.contains("EC")) + { + ECPrivateKey ecPrivateKey = ECPrivateKey.getInstance(pki.parsePrivateKey()); + + /* + * TODO + * - Confirm pki.privateKeyAlgorithm is id_ecPublicKey with X9.62 Parameters namedCurve OID. + * - If ecPrivateKey.parameters are present, must match pki.privateKeyAlgorithm + * The private key MUST be encoded as ECPrivateKey specified in [RFC5915] with the 'NamedCurve' + * parameter set to the OID of the curve, but without the 'publicKey' field. + */ + // TODO Also need to ensure that ECPrivateKey.parameters are present + ASN1BitString publicKey = ecPrivateKey.getPublicKey(); + if (publicKey != null) + { + ecPrivateKey = new ECPrivateKey(ecPrivateKey.getPrivateKey(), ecPrivateKey.getParametersObject(), null); + } + + tradSK = ecPrivateKey.getEncoded(ASN1Encoding.DER); + } + else + { + tradSK = pki.getPrivateKey().getOctets(); + } + + return new PrivateKeyInfo(algorithmIdentifier, Arrays.concatenate(mldsaSeed, tradSK)).getEncoded(); + } + catch (IOException e) + { + throw new IllegalStateException("unable to encode composite public key: " + e.getMessage()); + } + } + ASN1EncodableVector v = new ASN1EncodableVector(); - if (algorithmIdentifier.equals(MiscObjectIdentifiers.id_composite_key)) + if (MiscObjectIdentifiers.id_composite_key.equals(algOid)) { for (int i = 0; i < keys.size(); i++) { - PrivateKeyInfo info = PrivateKeyInfo.getInstance(keys.get(i).getEncoded()); - v.add(info); + PrivateKeyInfo pki = PrivateKeyInfo.getInstance(keys.get(i).getEncoded()); + + v.add(pki); } try { - return new PrivateKeyInfo(new AlgorithmIdentifier(this.algorithmIdentifier), new DERSequence(v)).getEncoded(ASN1Encoding.DER); + return new PrivateKeyInfo(this.algorithmIdentifier, new DERSequence(v)).getEncoded(ASN1Encoding.DER); } catch (IOException e) { @@ -154,13 +344,14 @@ public byte[] getEncoded() byte[] keyEncoding = null; for (int i = 0; i < keys.size(); i++) { - PrivateKeyInfo info = PrivateKeyInfo.getInstance(keys.get(i).getEncoded()); - keyEncoding = Arrays.concatenate(keyEncoding, info.getPrivateKey().getOctets()); + PrivateKeyInfo pki = PrivateKeyInfo.getInstance(keys.get(i).getEncoded()); + + keyEncoding = Arrays.concatenate(keyEncoding, pki.getPrivateKey().getOctets()); } try { - return new PrivateKeyInfo(new AlgorithmIdentifier(this.algorithmIdentifier), keyEncoding).getEncoded(ASN1Encoding.DER); + return new PrivateKeyInfo(this.algorithmIdentifier, keyEncoding).getEncoded(ASN1Encoding.DER); } catch (IOException e) { @@ -184,7 +375,7 @@ public boolean equals(Object o) if (o instanceof CompositePrivateKey) { boolean isEqual = true; - CompositePrivateKey comparedKey = (CompositePrivateKey) o; + CompositePrivateKey comparedKey = (CompositePrivateKey)o; if (!comparedKey.getAlgorithmIdentifier().equals(this.algorithmIdentifier) || !this.keys.equals(comparedKey.keys)) { isEqual = false; diff --git a/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java index 39e4564fa0..15175454f0 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java @@ -1,7 +1,9 @@ package org.bouncycastle.jcajce; import java.io.IOException; +import java.security.Provider; import java.security.PublicKey; +import java.security.Security; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -12,19 +14,80 @@ import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers; import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers; import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeIndex; import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.KeyFactorySpi; import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; +import org.bouncycastle.util.Arrays; /** * A composite key class. */ -public class CompositePublicKey implements PublicKey +public class CompositePublicKey + implements PublicKey { + public static class Builder + { + private final AlgorithmIdentifier algorithmIdentifier; + private final PublicKey[] keys = new PublicKey[2]; + private final Provider[] providers = new Provider[2]; + + private int count = 0; + + private Builder(AlgorithmIdentifier algorithmIdentifier) + { + this.algorithmIdentifier = algorithmIdentifier; + } + + public Builder addPublicKey(PublicKey key) + { + return addPublicKey(key, (Provider)null); + } + + public Builder addPublicKey(PublicKey key, String providerName) + { + return addPublicKey(key, Security.getProvider(providerName)); + } + + public Builder addPublicKey(PublicKey key, Provider provider) + { + if (count == keys.length) + { + throw new IllegalStateException("only " + keys.length + " allowed in composite"); + } + + keys[count] = key; + providers[count++] = provider; + + return this; + } + + public CompositePublicKey build() + { + if (providers[0] == null && providers[1] == null) + { + return new CompositePublicKey(algorithmIdentifier, keys, null); + } + + return new CompositePublicKey(algorithmIdentifier, keys, providers); + } + } + + public static Builder builder(ASN1ObjectIdentifier compAlgOid) + { + return new Builder(new AlgorithmIdentifier(compAlgOid)); + } + + public static Builder builder(String algorithmName) + { + return builder(CompositeUtil.getOid(algorithmName)); + } + private final List keys; + private final List providers; - private final ASN1ObjectIdentifier algorithmIdentifier; + private final AlgorithmIdentifier algorithmIdentifier; /** * Create a composite public key from an array of PublicKeys. @@ -37,6 +100,11 @@ public CompositePublicKey(PublicKey... keys) this(MiscObjectIdentifiers.id_composite_key, keys); } + public CompositePublicKey(ASN1ObjectIdentifier algorithmIdentifier, PublicKey... keys) + { + this(new AlgorithmIdentifier(algorithmIdentifier), keys); + } + /** * Create a composite public key which corresponds to a composite signature algorithm in algorithmIdentifier. * The component public keys are not checked if they satisfy the composite definition at this point, @@ -45,7 +113,7 @@ public CompositePublicKey(PublicKey... keys) * @param algorithmIdentifier * @param keys */ - public CompositePublicKey(ASN1ObjectIdentifier algorithmIdentifier, PublicKey... keys) + public CompositePublicKey(AlgorithmIdentifier algorithmIdentifier, PublicKey... keys) { this.algorithmIdentifier = algorithmIdentifier; @@ -60,6 +128,7 @@ public CompositePublicKey(ASN1ObjectIdentifier algorithmIdentifier, PublicKey... keyList.add(keys[i]); } this.keys = Collections.unmodifiableList(keyList); + this.providers = null; } /** @@ -79,7 +148,7 @@ public CompositePublicKey(SubjectPublicKeyInfo keyInfo) throw new IllegalStateException("unable to create CompositePublicKey from SubjectPublicKeyInfo"); } AsymmetricKeyInfoConverter keyInfoConverter = new KeyFactorySpi(); - publicKeyFromFactory = (CompositePublicKey) keyInfoConverter.generatePublic(keyInfo); + publicKeyFromFactory = (CompositePublicKey)keyInfoConverter.generatePublic(keyInfo); if (publicKeyFromFactory == null) { @@ -93,6 +162,38 @@ public CompositePublicKey(SubjectPublicKeyInfo keyInfo) this.keys = publicKeyFromFactory.getPublicKeys(); this.algorithmIdentifier = publicKeyFromFactory.getAlgorithmIdentifier(); + this.providers = null; + } + + private CompositePublicKey(AlgorithmIdentifier algorithmIdentifier, PublicKey[] keys, Provider[] providers) + { + this.algorithmIdentifier = algorithmIdentifier; + + if (keys.length != 2) + { + throw new IllegalArgumentException("two keys required for composite private key"); + } + + List keyList = new ArrayList(keys.length); + if (providers == null) + { + for (int i = 0; i < keys.length; i++) + { + keyList.add(keys[i]); + } + this.providers = null; + } + else + { + List providerList = new ArrayList(providers.length); + for (int i = 0; i < keys.length; i++) + { + providerList.add(providers[i]); + keyList.add(keys[i]); + } + this.providers = Collections.unmodifiableList(providerList); + } + this.keys = Collections.unmodifiableList(keyList); } /** @@ -105,12 +206,22 @@ public List getPublicKeys() return keys; } + /** + * Return a list of the providers supporting the component private keys. + * + * @return an immutable list of Provider objects. + */ + public List getProviders() + { + return providers; + } + public String getAlgorithm() { - return CompositeIndex.getAlgorithmName(this.algorithmIdentifier); + return CompositeIndex.getAlgorithmName(this.algorithmIdentifier.getAlgorithm()); } - public ASN1ObjectIdentifier getAlgorithmIdentifier() + public AlgorithmIdentifier getAlgorithmIdentifier() { return algorithmIdentifier; } @@ -124,7 +235,9 @@ public String getFormat() * Returns the composite public key encoded as a SubjectPublicKeyInfo. * If the composite public key is legacy (MiscObjectIdentifiers.id_composite_key), * it each component public key is wrapped in its own SubjectPublicKeyInfo. - * Other composite public keys are encoded according to https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html#name-compositesignaturepublickey + * Other composite public keys are encoded according to + * + * Composite ML-DSA for use in X.509 Public Key Infrastructure * where each component public key is a BIT STRING which contains the result of calling * getEncoded() for each component public key. * @@ -133,25 +246,43 @@ public String getFormat() @Override public byte[] getEncoded() { + ASN1ObjectIdentifier algOid = algorithmIdentifier.getAlgorithm(); + + if (algOid.on(IANAObjectIdentifiers.id_alg)) + { + try + { + byte[] mldsaPK = SubjectPublicKeyInfo.getInstance(keys.get(0).getEncoded()).getPublicKeyData().getOctets(); + byte[] tradPK = SubjectPublicKeyInfo.getInstance(keys.get(1).getEncoded()).getPublicKeyData().getOctets(); + return new SubjectPublicKeyInfo(algorithmIdentifier, Arrays.concatenate(mldsaPK, tradPK)).getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + throw new IllegalStateException("unable to encode composite public key: " + e.getMessage()); + } + } + ASN1EncodableVector v = new ASN1EncodableVector(); for (int i = 0; i < keys.size(); i++) { - if (this.algorithmIdentifier.equals(MiscObjectIdentifiers.id_composite_key)) + SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(keys.get(i).getEncoded()); + + if (MiscObjectIdentifiers.id_composite_key.equals(algOid)) { //Legacy, component is the whole SubjectPublicKeyInfo - v.add(SubjectPublicKeyInfo.getInstance(keys.get(i).getEncoded())); + v.add(spki); } else { //component is the value of subjectPublicKey from SubjectPublicKeyInfo - SubjectPublicKeyInfo keyInfo = SubjectPublicKeyInfo.getInstance(keys.get(i).getEncoded()); - v.add(keyInfo.getPublicKeyData()); + v.add(spki.getPublicKeyData()); } } + try { - return new SubjectPublicKeyInfo(new AlgorithmIdentifier(this.algorithmIdentifier), new DERSequence(v)).getEncoded(ASN1Encoding.DER); + return new SubjectPublicKeyInfo(this.algorithmIdentifier, new DERSequence(v)).getEncoded(ASN1Encoding.DER); } catch (IOException e) { @@ -159,31 +290,26 @@ public byte[] getEncoded() } } - public int hashCode() { - return keys.hashCode(); + return algorithmIdentifier.hashCode() ^ keys.hashCode(); } - public boolean equals(Object o) + public boolean equals(Object obj) { - if (o == this) + if (obj == this) { return true; } - if (o instanceof CompositePublicKey) + if (!(obj instanceof CompositePublicKey)) { - boolean isEqual = true; - CompositePublicKey comparedKey = (CompositePublicKey) o; - if (!comparedKey.getAlgorithmIdentifier().equals(this.algorithmIdentifier) || !this.keys.equals(comparedKey.keys)) - { - isEqual = false; - } - - return isEqual; + return false; } - return false; + CompositePublicKey that = (CompositePublicKey)obj; + + return this.algorithmIdentifier.equals(that.algorithmIdentifier) + && this.keys.equals(that.keys); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/CompositeUtil.java b/prov/src/main/java/org/bouncycastle/jcajce/CompositeUtil.java new file mode 100644 index 0000000000..a5df9e781b --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/jcajce/CompositeUtil.java @@ -0,0 +1,46 @@ +package org.bouncycastle.jcajce; + +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers; +import org.bouncycastle.util.Strings; + +class CompositeUtil +{ + private static final Map algorithmOids = new HashMap(); + + static + { + algorithmOids.put("MLDSA44-RSA2048-PSS-SHA256", IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256); + algorithmOids.put("MLDSA44-RSA2048-PKCS15-SHA256", IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256); + algorithmOids.put("MLDSA44-ED25519-SHA512", IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512); + algorithmOids.put("MLDSA44-ECDSA-P256-SHA256", IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256); + algorithmOids.put("MLDSA65-RSA3072-PSS-SHA512", IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512); + algorithmOids.put("MLDSA65-RSA3072-PKCS15-SHA512", IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512); + algorithmOids.put("MLDSA65-RSA4096-PSS-SHA512", IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512); + algorithmOids.put("MLDSA65-RSA4096-PKCS15-SHA512", IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512); + algorithmOids.put("MLDSA65-ECDSA-P256-SHA512", IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512); + algorithmOids.put("MLDSA65-ECDSA-P384-SHA512", IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512); + algorithmOids.put("MLDSA65-ECDSA-BRAINPOOLP256R1-SHA512", IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512); + algorithmOids.put("MLDSA65-ED25519-SHA512", IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512); + algorithmOids.put("MLDSA87-ECDSA-P384-SHA512", IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512); + algorithmOids.put("MLDSA87-ECDSA-BRAINPOOLP384R1-SHA512", IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512); + algorithmOids.put("MLDSA87-ED448-SHAKE256", IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256); + algorithmOids.put("MLDSA87-RSA4096-PSS-SHA512", IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512); + algorithmOids.put("MLDSA87-ECDSA-P521-SHA512", IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512); + algorithmOids.put("MLDSA87-RSA3072-PSS-SHA512", IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512); + } + + static ASN1ObjectIdentifier getOid(String name) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)algorithmOids.get(Strings.toUpperCase(name)); + if (oid == null) + { + throw new IllegalArgumentException("name " + name + " not recognized"); + } + + return oid; + } +} diff --git a/prov/src/main/java/org/bouncycastle/jcajce/MLDSAProxyPrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/MLDSAProxyPrivateKey.java new file mode 100644 index 0000000000..9074b56723 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/jcajce/MLDSAProxyPrivateKey.java @@ -0,0 +1,73 @@ +package org.bouncycastle.jcajce; + +import java.security.PublicKey; + +import org.bouncycastle.jcajce.interfaces.MLDSAPrivateKey; +import org.bouncycastle.jcajce.interfaces.MLDSAPublicKey; +import org.bouncycastle.jcajce.spec.MLDSAParameterSpec; + +/** + * An ML-DSA private key wrapper which acts as a proxy to allow an ML-DSA public key + * to be passed in for external-mu calculation. + */ +public class MLDSAProxyPrivateKey + implements MLDSAPrivateKey +{ + private final MLDSAPublicKey publicKey; + + public MLDSAProxyPrivateKey(PublicKey publicKey) + { + if (!(publicKey instanceof MLDSAPublicKey)) + { + throw new IllegalArgumentException("public key must be an ML-DSA public key"); + } + this.publicKey = (MLDSAPublicKey)publicKey; + } + + public MLDSAPublicKey getPublicKey() + { + return publicKey; + } + + @Override + public String getAlgorithm() + { + return publicKey.getAlgorithm(); + } + + @Override + public String getFormat() + { + return null; + } + + @Override + public byte[] getEncoded() + { + return new byte[0]; + } + + @Override + public MLDSAParameterSpec getParameterSpec() + { + return publicKey.getParameterSpec(); + } + + @Override + public byte[] getPrivateData() + { + return new byte[0]; + } + + @Override + public byte[] getSeed() + { + return new byte[0]; + } + + @Override + public MLDSAPrivateKey getPrivateKey(boolean preferSeedOnly) + { + return null; + } +} diff --git a/prov/src/main/java/org/bouncycastle/jcajce/PKCS12StoreParameter.java b/prov/src/main/java/org/bouncycastle/jcajce/PKCS12StoreParameter.java index 2541e65e0a..7f37be8f6a 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/PKCS12StoreParameter.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/PKCS12StoreParameter.java @@ -5,6 +5,15 @@ import java.security.KeyStore.LoadStoreParameter; import java.security.KeyStore.ProtectionParameter; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERNull; +import org.bouncycastle.asn1.pkcs.PBKDF2Params; +import org.bouncycastle.asn1.pkcs.PBMAC1Params; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers; +import org.bouncycastle.util.Arrays; + /** * LoadStoreParameter to allow for additional config with PKCS12 files. *

    @@ -18,6 +27,123 @@ public class PKCS12StoreParameter private final ProtectionParameter protectionParameter; private final boolean forDEREncoding; private final boolean overwriteFriendlyName; + private final AlgorithmIdentifier macAlgorithm; + + public static class PBMAC1WithPBKDF2Builder + { + private int iterationCount = 16384; + private byte[] salt = null; + private int keySizeinBits = 256; + private ASN1ObjectIdentifier prf = PKCSObjectIdentifiers.id_hmacWithSHA256; + private ASN1ObjectIdentifier mac = PKCSObjectIdentifiers.id_hmacWithSHA512; + + PBMAC1WithPBKDF2Builder() + { + + } + + public PBMAC1WithPBKDF2Builder setIterationCount(int iterationCount) + { + this.iterationCount = iterationCount; + + return this; + } + + public PBMAC1WithPBKDF2Builder setSalt(byte[] salt) + { + this.salt = Arrays.clone(salt); + + return this; + } + + public PBMAC1WithPBKDF2Builder setKeySize(int keySizeinBits) + { + this.keySizeinBits = keySizeinBits; + + return this; + } + + public PBMAC1WithPBKDF2Builder setPrf(ASN1ObjectIdentifier prf) + { + this.prf = prf; + + return this; + } + + public PBMAC1WithPBKDF2Builder setMac(ASN1ObjectIdentifier mac) + { + this.mac = mac; + + return this; + } + + public AlgorithmIdentifier build() + { + if (salt != null) + { + throw new IllegalStateException("salt must be non-null"); + } + + return new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBMAC1, new PBMAC1Params(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, new PBKDF2Params(salt, iterationCount, keySizeinBits, new AlgorithmIdentifier(prf))), + new AlgorithmIdentifier(mac))); + } + } + + public static PBMAC1WithPBKDF2Builder pbmac1WithPBKDF2Builder() + { + return new PBMAC1WithPBKDF2Builder(); + } + + public static class Builder + { + private final OutputStream out; + private final ProtectionParameter protectionParameter; + private boolean forDEREncoding = true; + private boolean overwriteFriendlyName = true; + private AlgorithmIdentifier macAlgorithm = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE); + + private Builder(OutputStream out, ProtectionParameter protectionParameter) + { + this.out = out; + this.protectionParameter = protectionParameter; + } + + public Builder setDEREncoding(boolean enable) + { + this.forDEREncoding = enable; + + return this; + } + + public Builder setOverwriteFriendlyName(boolean enable) + { + this.overwriteFriendlyName = enable; + + return this; + } + + public Builder setMacAlgorithm(AlgorithmIdentifier macAlgorithm) + { + this.macAlgorithm = macAlgorithm; + + return this; + } + + public PKCS12StoreParameter build() + { + return new PKCS12StoreParameter(out, protectionParameter, forDEREncoding, overwriteFriendlyName, macAlgorithm); + } + } + + public static Builder builder(OutputStream out, char[] password) + { + return builder(out, new KeyStore.PasswordProtection(password)); + } + + public static Builder builder(OutputStream out, ProtectionParameter protectionParameter) + { + return new Builder(out, protectionParameter); + } public PKCS12StoreParameter(OutputStream out, char[] password) { @@ -33,6 +159,7 @@ public PKCS12StoreParameter(OutputStream out, char[] password, boolean forDEREnc { this(out, new KeyStore.PasswordProtection(password), forDEREncoding, true); } + public PKCS12StoreParameter(OutputStream out, ProtectionParameter protectionParameter, boolean forDEREncoding) { this(out, protectionParameter, forDEREncoding, true); @@ -44,11 +171,17 @@ public PKCS12StoreParameter(OutputStream out, char[] password, boolean forDEREnc } public PKCS12StoreParameter(OutputStream out, ProtectionParameter protectionParameter, boolean forDEREncoding, boolean overwriteFriendlyName) + { + this(out, protectionParameter, forDEREncoding, overwriteFriendlyName, new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE)); + } + + private PKCS12StoreParameter(OutputStream out, ProtectionParameter protectionParameter, boolean forDEREncoding, boolean overwriteFriendlyName, AlgorithmIdentifier macAlgorithm) { this.out = out; this.protectionParameter = protectionParameter; this.forDEREncoding = forDEREncoding; this.overwriteFriendlyName = overwriteFriendlyName; + this.macAlgorithm = macAlgorithm; } public OutputStream getOutputStream() @@ -81,4 +214,9 @@ public boolean isOverwriteFriendlyName() { return overwriteFriendlyName; } + + public AlgorithmIdentifier getMacAlgorithm() + { + return macAlgorithm; + } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/PKIXCRLStoreSelector.java b/prov/src/main/java/org/bouncycastle/jcajce/PKIXCRLStoreSelector.java index e7dbcce0f8..b82b7ca616 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/PKIXCRLStoreSelector.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/PKIXCRLStoreSelector.java @@ -185,45 +185,44 @@ public boolean match(CRL obj) } X509CRL crl = (X509CRL)obj; - ASN1Integer dci = null; - try + + // TODO[pkix] Do we always need to parse the Delta CRL Indicator extension? { - byte[] bytes = crl - .getExtensionValue(Extension.deltaCRLIndicator.getId()); - if (bytes != null) + ASN1Integer baseCRLNumber = null; + try { - dci = ASN1Integer.getInstance(ASN1OctetString.getInstance(bytes).getOctets()); + byte[] dci = crl.getExtensionValue(Extension.deltaCRLIndicator.getId()); + if (dci != null) + { + baseCRLNumber = ASN1Integer.getInstance(ASN1OctetString.getInstance(dci).getOctets()); + } } - } - catch (Exception e) - { - return false; - } - if (isDeltaCRLIndicatorEnabled()) - { - if (dci == null) + catch (Exception e) { return false; } - } - if (isCompleteCRLEnabled()) - { - if (dci != null) + + if (baseCRLNumber == null) { - return false; + if (isDeltaCRLIndicatorEnabled()) + { + return false; + } } - } - if (dci != null) - { - - if (maxBaseCRLNumber != null) + else { - if (dci.getPositiveValue().compareTo(maxBaseCRLNumber) == 1) + if (isCompleteCRLEnabled()) + { + return false; + } + + if (maxBaseCRLNumber != null && baseCRLNumber.getPositiveValue().compareTo(maxBaseCRLNumber) == 1) { return false; } } } + if (issuingDistributionPointEnabled) { byte[] idp = crl diff --git a/prov/src/main/java/org/bouncycastle/jcajce/interfaces/BCKey.java b/prov/src/main/java/org/bouncycastle/jcajce/interfaces/BCKey.java new file mode 100644 index 0000000000..b030f6207f --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/jcajce/interfaces/BCKey.java @@ -0,0 +1,8 @@ +package org.bouncycastle.jcajce.interfaces; + +/** + * Marker interface for key implementations that are implemented inside Bouncy Castle. + */ +public interface BCKey +{ +} diff --git a/prov/src/main/java/org/bouncycastle/jcajce/interfaces/MLDSAPrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/interfaces/MLDSAPrivateKey.java index d7ee863f26..1f4224e461 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/interfaces/MLDSAPrivateKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/interfaces/MLDSAPrivateKey.java @@ -25,4 +25,12 @@ public interface MLDSAPrivateKey * @return the seed for the private key, null if not available. */ byte[] getSeed(); + + /** + * Return a privateKey which will encode as seed-only or as an expanded-key. + * + * @param preferSeedOnly if true, return a privateKey which will encode to seed-only if possible. + * @return a new MLDSAPrivateKey which encodes to either seed-only or expanded-key. + */ + MLDSAPrivateKey getPrivateKey(boolean preferSeedOnly); } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/interfaces/MLKEMPrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/interfaces/MLKEMPrivateKey.java index 7c8d7b6f34..38ecf2bf06 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/interfaces/MLKEMPrivateKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/interfaces/MLKEMPrivateKey.java @@ -25,4 +25,12 @@ public interface MLKEMPrivateKey * @return the seed for the private key, null if not available. */ byte[] getSeed(); + + /** + * Return a privateKey which will encode as seed-only or as an expanded-key. + * + * @param preferSeedOnly if true, return a privateKey which will encode to seed-only if possible. + * @return a new MLKEMPrivateKey which encodes to either seed-only or expanded-key. + */ + MLKEMPrivateKey getPrivateKey(boolean preferSeedOnly); } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/io/CipherInputStream.java b/prov/src/main/java/org/bouncycastle/jcajce/io/CipherInputStream.java index a9af942471..e3c407be3e 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/io/CipherInputStream.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/io/CipherInputStream.java @@ -31,6 +31,7 @@ public class CipherInputStream private final Cipher cipher; private final byte[] inputBuffer = new byte[512]; private boolean finalized = false; + private boolean nextChunkCalled = false; private byte[] buf; private int maxBuf; private int bufOff; @@ -58,6 +59,7 @@ private int nextChunk() return -1; } + nextChunkCalled = true; bufOff = 0; maxBuf = 0; @@ -86,10 +88,16 @@ private int nextChunk() } private byte[] finaliseCipher() - throws InvalidCipherTextIOException + throws InvalidCipherTextIOException, IOException { try { + // for an AEAD cipher with 0 encrypted Data nextChunk may not have been + // called - we still need to read the MAC though! + if (!nextChunkCalled) + { + nextChunk(); + } if (!finalized) { finalized = true; diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java index d804b196bf..c0f2d9dd22 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java @@ -33,6 +33,8 @@ public Mappings() public void configure(ConfigurableProvider provider) { + provider.addAlgorithm("Signature.COMPOSITE", PREFIX + "SignatureSpi$COMPOSITE"); + for (ASN1ObjectIdentifier oid : CompositeIndex.getSupportedIdentifiers()) { String algorithmName = CompositeIndex.getAlgorithmName(oid); @@ -47,6 +49,9 @@ public void configure(ConfigurableProvider provider) provider.addAlgorithm("Signature." + algorithmName, PREFIX + "SignatureSpi$" + className); provider.addAlgorithm("Alg.Alias.Signature", oid, algorithmName); + // add pre-hash versions + provider.addAlgorithm("Signature." + algorithmName + "-PREHASH", PREFIX + "SignatureSpi$" + className + "_PREHASH"); + provider.addKeyInfoConverter(oid, new KeyFactorySpi()); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java index d9e4f8e465..820a8a5eea 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java @@ -1,11 +1,16 @@ package org.bouncycastle.jcajce.provider.asymmetric; +import java.util.Enumeration; import java.util.HashMap; +import java.util.Hashtable; import java.util.Map; +import java.util.Vector; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.sec.SECObjectIdentifiers; import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.internal.asn1.bsi.BSIObjectIdentifiers; import org.bouncycastle.internal.asn1.cms.CMSObjectIdentifiers; @@ -13,6 +18,7 @@ import org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi; import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; import org.bouncycastle.util.Properties; public class EC @@ -20,11 +26,102 @@ public class EC private static final String PREFIX = "org.bouncycastle.jcajce.provider.asymmetric" + ".ec."; private static final Map generalEcAttributes = new HashMap(); + private static final Map ecSupportCurves = new HashMap(); static { generalEcAttributes.put("SupportedKeyClasses", "java.security.interfaces.ECPublicKey|java.security.interfaces.ECPrivateKey"); generalEcAttributes.put("SupportedKeyFormats", "PKCS#8|X.509"); + Enumeration names = ECNamedCurveTable.getNames(); + Hashtable oidToNames = new Hashtable(); + + // 1. Group names by OID + while (names.hasMoreElements()) + { + String name = (String)names.nextElement(); + ECNamedCurveParameterSpec spec = org.bouncycastle.jce.ECNamedCurveTable.getParameterSpec(name); + if (spec == null) + { + continue; + } + + ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID(name); + if (oid == null) + { + continue; + } + + String oidStr = oid.getId(); + Vector v = (Vector)oidToNames.get(oidStr); + if (v == null) + { + v = new Vector(); + oidToNames.put(oidStr, v); + } + if (!v.contains(name)) + { + v.addElement(name); + } + } + + Enumeration oids = oidToNames.keys(); + Vector results = new Vector(); + + while (oids.hasMoreElements()) + { + String oidStr = (String)oids.nextElement(); + Vector namesForOid = (Vector)oidToNames.get(oidStr); + + StringBuffer sb = new StringBuffer(); + sb.append("["); + ASN1ObjectIdentifier oid = new ASN1ObjectIdentifier(oidStr); + + if (X9ObjectIdentifiers.prime256v1.equals(oid)) + { + sb.append("secp256r1,NIST P-256,X9.62 prime256v1"); + } + else if (X9ObjectIdentifiers.prime192v1.equals(oid)) + { + sb.append("secp192r1,NIST P-192,X9.62 prime192v1"); + } + else + { + if (oid.on(X9ObjectIdentifiers.primeCurve) || oid.on(X9ObjectIdentifiers.cTwoCurve)) + { + sb.append("X9.62 "); + } + // Append all curve names separated by commas + for (int i = 0; i < namesForOid.size(); i++) + { + if (i > 0) + { + sb.append(","); + } + String name = (String)namesForOid.elementAt(i); + if ((oid.on(SECObjectIdentifiers.ellipticCurve) || X9ObjectIdentifiers.prime256v1.equals(oid) || X9ObjectIdentifiers.prime192v1.equals(oid)) + && (name.startsWith("K-") || name.startsWith("B-") || (name.startsWith("P-")))) + { + sb.append("NIST "); + } + sb.append(name); + } + } + sb.append(",").append(oidStr).append("]"); + results.addElement(sb.toString()); + } + + // 3. Join all results with '|' + StringBuffer output = new StringBuffer(); + for (int i = 0; i < results.size(); i++) + { + if (i > 0) + { + output.append("|"); + } + output.append((String)results.elementAt(i)); + } + + ecSupportCurves.put("SupportedCurves", output.toString()); } public static class Mappings @@ -36,12 +133,12 @@ public Mappings() public void configure(ConfigurableProvider provider) { - provider.addAlgorithm("AlgorithmParameters.EC", PREFIX + "AlgorithmParametersSpi"); + provider.addAlgorithm("AlgorithmParameters.EC", PREFIX + "AlgorithmParametersSpi", ecSupportCurves); provider.addAlgorithm("KeyAgreement.ECDH", PREFIX + "KeyAgreementSpi$DH", generalEcAttributes); provider.addAlgorithm("KeyAgreement.ECDHC", PREFIX + "KeyAgreementSpi$DHC", generalEcAttributes); provider.addAlgorithm("KeyAgreement.ECCDH", PREFIX + "KeyAgreementSpi$DHC", generalEcAttributes); - + provider.addAlgorithm("KeyAgreement.ECCDHU", PREFIX + "KeyAgreementSpi$DHUC", generalEcAttributes); provider.addAlgorithm("KeyAgreement.ECDHWITHSHA1KDF", PREFIX + "KeyAgreementSpi$DHwithSHA1KDFAndSharedInfo", generalEcAttributes); @@ -267,7 +364,7 @@ public void configure(ConfigurableProvider provider) addSignatureAlgorithm(provider, "SHA3-512", "ECDSA", PREFIX + "SignatureSpi$ecDSASha3_512", NISTObjectIdentifiers.id_ecdsa_with_sha3_512, generalEcAttributes); addSignatureAlgorithm(provider, "SHAKE128", "ECDSA", PREFIX + "SignatureSpi$ecDSAShake128", CMSObjectIdentifiers.id_ecdsa_with_shake128, generalEcAttributes); addSignatureAlgorithm(provider, "SHAKE256", "ECDSA", PREFIX + "SignatureSpi$ecDSAShake256", CMSObjectIdentifiers.id_ecdsa_with_shake256, generalEcAttributes); - addSignatureAlgorithm(provider, "RIPEMD160", "ECDSA", PREFIX + "SignatureSpi$ecDSARipeMD160",TeleTrusTObjectIdentifiers.ecSignWithRipemd160, generalEcAttributes); + addSignatureAlgorithm(provider, "RIPEMD160", "ECDSA", PREFIX + "SignatureSpi$ecDSARipeMD160", TeleTrusTObjectIdentifiers.ecSignWithRipemd160, generalEcAttributes); provider.addAlgorithm("Signature.SHA1WITHECNR", PREFIX + "SignatureSpi$ecNR", generalEcAttributes); provider.addAlgorithm("Signature.SHA224WITHECNR", PREFIX + "SignatureSpi$ecNR224", generalEcAttributes); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/Falcon.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/Falcon.java index 0559c1c6a6..01588b6a3b 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/Falcon.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/Falcon.java @@ -3,7 +3,6 @@ import org.bouncycastle.asn1.bc.BCObjectIdentifiers; 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.jcajce.provider.falcon.FalconKeyFactorySpi; public class Falcon @@ -33,6 +32,10 @@ public void configure(ConfigurableProvider provider) addSignatureAlgorithm(provider, "FALCON-512", PREFIX + "SignatureSpi$Falcon512", BCObjectIdentifiers.falcon_512); addSignatureAlgorithm(provider, "FALCON-1024", PREFIX + "SignatureSpi$Falcon1024", BCObjectIdentifiers.falcon_1024); + provider.addAlgorithm("Alg.Alias.Signature." + BCObjectIdentifiers.old_falcon_512, "FALCON-512"); + provider.addAlgorithm("Alg.Alias.Signature.OID." + BCObjectIdentifiers.old_falcon_512, "FALCON-512"); + provider.addAlgorithm("Alg.Alias.Signature." + BCObjectIdentifiers.old_falcon_1024, "FALCON-1024"); + provider.addAlgorithm("Alg.Alias.Signature.OID." + BCObjectIdentifiers.old_falcon_1024, "FALCON-1024"); } } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/GM.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/GM.java index 86c143edc2..292b7b1412 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/GM.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/GM.java @@ -4,6 +4,7 @@ import java.util.Map; import org.bouncycastle.asn1.gm.GMObjectIdentifiers; +import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; @@ -28,6 +29,10 @@ public Mappings() public void configure(ConfigurableProvider provider) { + provider.addAlgorithm("KeyAgreement.SM2", PREFIX + "GMKeyExchangeSpi$SM2"); + provider.addAlgorithm("KeyAgreement", GMObjectIdentifiers.sm2exchange, PREFIX + "GMKeyExchangeSpi$SM2"); + + // provider.addAlgorithm("Signature.BLAKE2BWITHSM2", PREFIX + "GMSignatureSpi$blake2b512WithSM2"); // provider.addAlgorithm("Alg.Alias.Signature." + GMObjectIdentifiers.sm2sign_with_blake2b512, "BLAKE2BWITHSM2"); // provider.addAlgorithm("Signature.BLAKE2SWITHSM2", PREFIX + "GMSignatureSpi$blake2s256WithSM2"); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/MLDSA.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/MLDSA.java index 4f9424b029..79540890da 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/MLDSA.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/MLDSA.java @@ -49,6 +49,12 @@ public void configure(ConfigurableProvider provider) addSignatureAlgorithm(provider, "ML-DSA-87", PREFIX + "SignatureSpi$MLDSA87", NISTObjectIdentifiers.id_ml_dsa_87); provider.addAlgorithm("Alg.Alias.Signature.MLDSA", "ML-DSA"); + addSignatureAlgorithm(provider, "ML-DSA-CALCULATE-MU", PREFIX + "SignatureSpi$MLDSACalcMu", (ASN1ObjectIdentifier)null); + provider.addAlgorithm("Alg.Alias.Signature.MLDSA-CALCULATE-MU", "ML-DSA-CALCULATE-MU"); + + addSignatureAlgorithm(provider, "ML-DSA-EXTERNAL-MU", PREFIX + "SignatureSpi$MLDSAExtMu", (ASN1ObjectIdentifier)null); + provider.addAlgorithm("Alg.Alias.Signature.MLDSA-EXTERNAL-MU", "ML-DSA-EXTERNAL-MU"); + addSignatureAlgorithm(provider, "HASH-ML-DSA", PREFIX + "HashSignatureSpi$MLDSA", (ASN1ObjectIdentifier)null); addSignatureAlgorithm(provider, "ML-DSA-44-WITH-SHA512", PREFIX + "HashSignatureSpi$MLDSA44", NISTObjectIdentifiers.id_hash_ml_dsa_44_with_sha512); addSignatureAlgorithm(provider, "ML-DSA-65-WITH-SHA512", PREFIX + "HashSignatureSpi$MLDSA65", NISTObjectIdentifiers.id_hash_ml_dsa_65_with_sha512); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/MLKEM.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/MLKEM.java index 127c40f460..2c44f309dd 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/MLKEM.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/MLKEM.java @@ -1,11 +1,11 @@ package org.bouncycastle.jcajce.provider.asymmetric; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.jcajce.provider.asymmetric.mlkem.MLKEMKeyFactorySpi; import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; +import org.bouncycastle.jcajce.util.SpiUtil; public class MLKEM { @@ -48,10 +48,20 @@ public void configure(ConfigurableProvider provider) addCipherAlgorithm(provider, "ML-KEM-512", PREFIX + "MLKEMCipherSpi$MLKEM512", NISTObjectIdentifiers.id_alg_ml_kem_512); addCipherAlgorithm(provider, "ML-KEM-768", PREFIX + "MLKEMCipherSpi$MLKEM768", NISTObjectIdentifiers.id_alg_ml_kem_768); addCipherAlgorithm(provider, "ML-KEM-1024", PREFIX + "MLKEMCipherSpi$MLKEM1024", NISTObjectIdentifiers.id_alg_ml_kem_1024); - + provider.addKeyInfoConverter(NISTObjectIdentifiers.id_alg_ml_kem_512, keyFact); provider.addKeyInfoConverter(NISTObjectIdentifiers.id_alg_ml_kem_768, keyFact); provider.addKeyInfoConverter(NISTObjectIdentifiers.id_alg_ml_kem_1024, keyFact); + + if (SpiUtil.hasKEM()) + { + // "This algorithm supports keys with ML-KEM-512, ML-KEM-768, and ML-KEM-1024 parameter sets." + provider.addAlgorithm("KEM.ML-KEM", PREFIX + "MLKEMSpi$MLKEM"); + + addKEMAlgorithm(provider, "ML-KEM-512", PREFIX + "MLKEMSpi$MLKEM512", NISTObjectIdentifiers.id_alg_ml_kem_512); + addKEMAlgorithm(provider, "ML-KEM-768", PREFIX + "MLKEMSpi$MLKEM768", NISTObjectIdentifiers.id_alg_ml_kem_768); + addKEMAlgorithm(provider, "ML-KEM-1024", PREFIX + "MLKEMSpi$MLKEM1024", NISTObjectIdentifiers.id_alg_ml_kem_1024); + } } } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/NoSig.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/NoSig.java new file mode 100644 index 0000000000..fbb50cda7a --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/NoSig.java @@ -0,0 +1,91 @@ +package org.bouncycastle.jcajce.provider.asymmetric; + +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SignatureException; +import java.security.SignatureSpi; + +import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; + +public class NoSig +{ + private static final String PREFIX = "org.bouncycastle.jcajce.provider.asymmetric.NoSig$"; + + public static class SigSpi + extends SignatureSpi + { + @Override + protected void engineInitVerify(PublicKey publicKey) + throws InvalidKeyException + { + throw new InvalidKeyException("attempt to pass public key to NoSig"); + } + + @Override + protected void engineInitSign(PrivateKey privateKey) + throws InvalidKeyException + { + throw new InvalidKeyException("attempt to pass private key to NoSig"); + } + + @Override + protected void engineUpdate(byte b) + throws SignatureException + { + + } + + @Override + protected void engineUpdate(byte[] bytes, int i, int i1) + throws SignatureException + { + + } + + @Override + protected byte[] engineSign() + throws SignatureException + { + return new byte[0]; + } + + @Override + protected boolean engineVerify(byte[] bytes) + throws SignatureException + { + return false; + } + + @Override + protected void engineSetParameter(String s, Object o) + throws InvalidParameterException + { + + } + + @Override + protected Object engineGetParameter(String s) + throws InvalidParameterException + { + return null; + } + } + + public static class Mappings + extends AsymmetricAlgorithmProvider + { + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + provider.addAlgorithm("Signature." + X509ObjectIdentifiers.id_alg_noSignature, PREFIX + "SigSpi"); + provider.addAlgorithm("Signature." + X509ObjectIdentifiers.id_alg_unsigned, PREFIX + "SigSpi"); + } + } +} diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeIndex.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeIndex.java index 00f117cfa8..4dec16ae6e 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeIndex.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeIndex.java @@ -7,6 +7,12 @@ import java.util.Set; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA384Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.digests.SHAKEDigest; +import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers; import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers; import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; @@ -15,84 +21,63 @@ public class CompositeIndex private static Map pairings = new HashMap(); private static Map kpgInitSpecs = new HashMap(); private static Map algorithmNames = new HashMap(); - + static { - pairings.put(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, new String[] { "ML-DSA-44", "SHA256withRSAandMGF1"}); - pairings.put(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, new String[] { "ML-DSA-44", "SHA256withRSA"}); - pairings.put(MiscObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, new String[] { "ML-DSA-44", "Ed25519"}); - pairings.put(MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, new String[] { "ML-DSA-44", "SHA256withECDSA"}); - pairings.put(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA256, new String[] { "ML-DSA-65", "SHA256withRSAandMGF1"}); - pairings.put(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA256, new String[] { "ML-DSA-65", "SHA256withRSA"}); - pairings.put(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA384, new String[] { "ML-DSA-65", "SHA384withRSAandMGF1"}); - pairings.put(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA384, new String[] { "ML-DSA-65", "SHA384withRSA"}); - pairings.put(MiscObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA384, new String[] { "ML-DSA-65", "SHA384withECDSA"}); - pairings.put(MiscObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA256, new String[] { "ML-DSA-65", "SHA256withECDSA"}); - pairings.put(MiscObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, new String[] { "ML-DSA-65", "Ed25519"}); - pairings.put(MiscObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA384, new String[] { "ML-DSA-87", "SHA384withECDSA"}); - pairings.put(MiscObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA384, new String[] { "ML-DSA-87", "SHA384withECDSA"}); - pairings.put(MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512, new String[] { "ML-DSA-87", "Ed448"}); - - pairings.put(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PSS_SHA256, new String[] { "ML-DSA-44", "SHA256withRSAandMGF1"}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PKCS15_SHA256, new String[] { "ML-DSA-44", "SHA256withRSA"}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA44_Ed25519_SHA512, new String[] { "ML-DSA-44", "Ed25519"}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA44_ECDSA_P256_SHA256, new String[] { "ML-DSA-44", "SHA256withECDSA"}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA3072_PSS_SHA512, new String[] { "ML-DSA-65", "SHA256withRSAandMGF1"}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA3072_PKCS15_SHA512, new String[] { "ML-DSA-65", "SHA256withRSA"}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA4096_PSS_SHA512, new String[] { "ML-DSA-65", "SHA384withRSAandMGF1"}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA4096_PKCS15_SHA512, new String[] { "ML-DSA-65", "SHA384withRSA"}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA65_ECDSA_P384_SHA512, new String[] { "ML-DSA-65", "SHA384withECDSA"}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA65_ECDSA_brainpoolP256r1_SHA512, new String[] { "ML-DSA-65", "SHA256withECDSA"}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA65_Ed25519_SHA512, new String[] { "ML-DSA-65", "Ed25519"}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_P384_SHA512, new String[] { "ML-DSA-87", "SHA384withECDSA"}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_brainpoolP384r1_SHA512, new String[] { "ML-DSA-87", "SHA384withECDSA"}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA87_Ed448_SHA512, new String[] { "ML-DSA-87", "Ed448"}); - - kpgInitSpecs.put(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, new AlgorithmParameterSpec[] { null, new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4)}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, new AlgorithmParameterSpec[] { null, new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4)}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, new AlgorithmParameterSpec[] { null, null}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, new AlgorithmParameterSpec[] { null, new ECNamedCurveGenParameterSpec("P-256")}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA256, new AlgorithmParameterSpec[] { null, new RSAKeyGenParameterSpec(3072, RSAKeyGenParameterSpec.F4)}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA256, new AlgorithmParameterSpec[] { null, new RSAKeyGenParameterSpec(3072, RSAKeyGenParameterSpec.F4)}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA384, new AlgorithmParameterSpec[] { null, new RSAKeyGenParameterSpec(4096, RSAKeyGenParameterSpec.F4)}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA384, new AlgorithmParameterSpec[] { null, new RSAKeyGenParameterSpec(4096, RSAKeyGenParameterSpec.F4)}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA384, new AlgorithmParameterSpec[] { null, new ECNamedCurveGenParameterSpec("P-384")}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA256, new AlgorithmParameterSpec[] { null, new ECNamedCurveGenParameterSpec("brainpoolP256r1")}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, new AlgorithmParameterSpec[] { null, null}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA384, new AlgorithmParameterSpec[] { null, new ECNamedCurveGenParameterSpec("P-384")}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA384, new AlgorithmParameterSpec[] { null, new ECNamedCurveGenParameterSpec("brainpoolP384r1")}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512, new AlgorithmParameterSpec[] { null, null}); - - kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PSS_SHA256, new AlgorithmParameterSpec[] { null, new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4)}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PKCS15_SHA256, new AlgorithmParameterSpec[] { null, new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4)}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA44_Ed25519_SHA512, new AlgorithmParameterSpec[] { null, null}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA44_ECDSA_P256_SHA256, new AlgorithmParameterSpec[] { null, new ECNamedCurveGenParameterSpec("P-256")}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA3072_PSS_SHA512, new AlgorithmParameterSpec[] { null, new RSAKeyGenParameterSpec(3072, RSAKeyGenParameterSpec.F4)}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA3072_PKCS15_SHA512, new AlgorithmParameterSpec[] { null, new RSAKeyGenParameterSpec(3072, RSAKeyGenParameterSpec.F4)}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA4096_PSS_SHA512, new AlgorithmParameterSpec[] { null, new RSAKeyGenParameterSpec(4096, RSAKeyGenParameterSpec.F4)}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA4096_PKCS15_SHA512, new AlgorithmParameterSpec[] { null, new RSAKeyGenParameterSpec(4096, RSAKeyGenParameterSpec.F4)}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA65_ECDSA_P384_SHA512, new AlgorithmParameterSpec[] { null, new ECNamedCurveGenParameterSpec("P-384")}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA65_ECDSA_brainpoolP256r1_SHA512, new AlgorithmParameterSpec[] { null, new ECNamedCurveGenParameterSpec("brainpoolP256r1")}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA65_Ed25519_SHA512, new AlgorithmParameterSpec[] { null, null}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_P384_SHA512, new AlgorithmParameterSpec[] { null, new ECNamedCurveGenParameterSpec("P-384")}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_brainpoolP384r1_SHA512, new AlgorithmParameterSpec[] { null, new ECNamedCurveGenParameterSpec("brainpoolP384r1")}); - kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA87_Ed448_SHA512, new AlgorithmParameterSpec[] { null, null}); + pairings.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, new String[]{"ML-DSA-44", "RSASSA-PSS"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, new String[]{"ML-DSA-44", "SHA256withRSA"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, new String[]{"ML-DSA-44", "Ed25519"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, new String[]{"ML-DSA-44", "SHA256withECDSA"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, new String[]{"ML-DSA-65", "RSASSA-PSS"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512, new String[]{"ML-DSA-65", "SHA256withRSA"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, new String[]{"ML-DSA-65", "RSASSA-PSS"}); + // id_MLDSA65_RSA4096_PKCS15_SHA512 + pairings.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512, new String[]{"ML-DSA-65", "SHA384withRSA"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512, new String[]{"ML-DSA-65", "SHA256withECDSA"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512, new String[]{"ML-DSA-65", "SHA384withECDSA"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512, new String[]{"ML-DSA-65", "SHA256withECDSA"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, new String[]{"ML-DSA-65", "Ed25519"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512, new String[]{"ML-DSA-87", "SHA384withECDSA"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512, new String[]{"ML-DSA-87", "SHA384withECDSA"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256, new String[]{"ML-DSA-87", "Ed448"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, new String[]{"ML-DSA-87", "RSASSA-PSS"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, new String[]{"ML-DSA-87", "RSASSA-PSS"}); + pairings.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512, new String[]{"ML-DSA-87", "SHA512withECDSA"}); - algorithmNames.put(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, "MLDSA44-RSA2048-PSS-SHA256"); - algorithmNames.put(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, "MLDSA44-RSA2048-PKCS15-SHA256"); - algorithmNames.put(MiscObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, "MLDSA44-Ed25519-SHA512"); - algorithmNames.put(MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, "MLDSA44-ECDSA-P256-SHA256"); - algorithmNames.put(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA256, "MLDSA65-RSA3072-PSS-SHA256"); - algorithmNames.put(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA256, "MLDSA65-RSA3072-PKCS15-SHA256"); - algorithmNames.put(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA384, "MLDSA65-RSA4096-PSS-SHA384"); - algorithmNames.put(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA384, "MLDSA65-RSA4096-PKCS15-SHA384"); - algorithmNames.put(MiscObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA384, "MLDSA65-ECDSA-P384-SHA384"); - algorithmNames.put(MiscObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA256, "MLDSA65-ECDSA-brainpoolP256r1-SHA256"); - algorithmNames.put(MiscObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, "MLDSA65-Ed25519-SHA512"); - algorithmNames.put(MiscObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA384, "MLDSA87-ECDSA-P384-SHA384"); - algorithmNames.put(MiscObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA384, "MLDSA87-ECDSA-brainpoolP384r1-SHA384"); - algorithmNames.put(MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512, "MLDSA87-Ed448-SHA512"); - + kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PSS_SHA256, new AlgorithmParameterSpec[]{null, new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4)}); + kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PKCS15_SHA256, new AlgorithmParameterSpec[]{null, new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4)}); + kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA44_Ed25519_SHA512, new AlgorithmParameterSpec[]{null, null}); + kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA44_ECDSA_P256_SHA256, new AlgorithmParameterSpec[]{null, new ECNamedCurveGenParameterSpec("P-256")}); + kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA3072_PSS_SHA512, new AlgorithmParameterSpec[]{null, new RSAKeyGenParameterSpec(3072, RSAKeyGenParameterSpec.F4)}); + kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA3072_PKCS15_SHA512, new AlgorithmParameterSpec[]{null, new RSAKeyGenParameterSpec(3072, RSAKeyGenParameterSpec.F4)}); + kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA4096_PSS_SHA512, new AlgorithmParameterSpec[]{null, new RSAKeyGenParameterSpec(4096, RSAKeyGenParameterSpec.F4)}); + kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA4096_PKCS15_SHA512, new AlgorithmParameterSpec[]{null, new RSAKeyGenParameterSpec(4096, RSAKeyGenParameterSpec.F4)}); + kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA65_ECDSA_P384_SHA512, new AlgorithmParameterSpec[]{null, new ECNamedCurveGenParameterSpec("P-384")}); + kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA65_ECDSA_brainpoolP256r1_SHA512, new AlgorithmParameterSpec[]{null, new ECNamedCurveGenParameterSpec("brainpoolP256r1")}); + kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA65_Ed25519_SHA512, new AlgorithmParameterSpec[]{null, null}); + kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_P384_SHA512, new AlgorithmParameterSpec[]{null, new ECNamedCurveGenParameterSpec("P-384")}); + kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_brainpoolP384r1_SHA512, new AlgorithmParameterSpec[]{null, new ECNamedCurveGenParameterSpec("brainpoolP384r1")}); + kpgInitSpecs.put(MiscObjectIdentifiers.id_HashMLDSA87_Ed448_SHA512, new AlgorithmParameterSpec[]{null, null}); + + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, new AlgorithmParameterSpec[]{null, new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4)}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, new AlgorithmParameterSpec[]{null, new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4)}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, new AlgorithmParameterSpec[]{null, null}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, new AlgorithmParameterSpec[]{null, new ECNamedCurveGenParameterSpec("P-256")}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, new AlgorithmParameterSpec[]{null, new RSAKeyGenParameterSpec(3072, RSAKeyGenParameterSpec.F4)}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512, new AlgorithmParameterSpec[]{null, new RSAKeyGenParameterSpec(3072, RSAKeyGenParameterSpec.F4)}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, new AlgorithmParameterSpec[]{null, new RSAKeyGenParameterSpec(4096, RSAKeyGenParameterSpec.F4)}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512, new AlgorithmParameterSpec[]{null, new RSAKeyGenParameterSpec(4096, RSAKeyGenParameterSpec.F4)}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512, new AlgorithmParameterSpec[]{null, new ECNamedCurveGenParameterSpec("P-256")}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512, new AlgorithmParameterSpec[]{null, new ECNamedCurveGenParameterSpec("P-384")}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512, new AlgorithmParameterSpec[]{null, new ECNamedCurveGenParameterSpec("brainpoolP256r1")}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, new AlgorithmParameterSpec[]{null, null}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512, new AlgorithmParameterSpec[]{null, new ECNamedCurveGenParameterSpec("P-384")}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512, new AlgorithmParameterSpec[]{null, new ECNamedCurveGenParameterSpec("brainpoolP384r1")}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256, new AlgorithmParameterSpec[]{null, null}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, new AlgorithmParameterSpec[]{null, new RSAKeyGenParameterSpec(4096, RSAKeyGenParameterSpec.F4)}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512, new AlgorithmParameterSpec[]{null, new ECNamedCurveGenParameterSpec("P-521")}); + kpgInitSpecs.put(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, new AlgorithmParameterSpec[]{null, new RSAKeyGenParameterSpec(3072, RSAKeyGenParameterSpec.F4)}); + algorithmNames.put(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PSS_SHA256, "HashMLDSA44-RSA2048-PSS-SHA256"); algorithmNames.put(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PKCS15_SHA256, "HashMLDSA44-RSA2048-PKCS15-SHA256"); algorithmNames.put(MiscObjectIdentifiers.id_HashMLDSA44_Ed25519_SHA512, "HashMLDSA44-Ed25519-SHA512"); @@ -107,6 +92,25 @@ public class CompositeIndex algorithmNames.put(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_P384_SHA512, "HashMLDSA87-ECDSA-P384-SHA512"); algorithmNames.put(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_brainpoolP384r1_SHA512, "HashMLDSA87-ECDSA-brainpoolP384r1-SHA512"); algorithmNames.put(MiscObjectIdentifiers.id_HashMLDSA87_Ed448_SHA512, "HashMLDSA87-Ed448-SHA512"); + + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, "MLDSA44-RSA2048-PSS-SHA256"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, "MLDSA44-RSA2048-PKCS15-SHA256"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, "MLDSA44-Ed25519-SHA512"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, "MLDSA44-ECDSA-P256-SHA256"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, "MLDSA65-RSA3072-PSS-SHA512"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512, "MLDSA65-RSA3072-PKCS15-SHA512"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, "MLDSA65-RSA4096-PSS-SHA512"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512, "MLDSA65-RSA4096-PKCS15-SHA512"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512, "MLDSA65-ECDSA-P256-SHA512"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512, "MLDSA65-ECDSA-P384-SHA512"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512, "MLDSA65-ECDSA-brainpoolP256r1-SHA512"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, "MLDSA65-Ed25519-SHA512"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512, "MLDSA87-ECDSA-P384-SHA512"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512, "MLDSA87-ECDSA-brainpoolP384r1-SHA512"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256, "MLDSA87-Ed448-SHAKE256"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, "MLDSA87-RSA4096-PSS-SHA512"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512, "MLDSA87-ECDSA-P521-SHA512"); + algorithmNames.put(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, "MLDSA87-RSA3072-PSS-SHA512"); } public static boolean isAlgorithmSupported(ASN1ObjectIdentifier algorithm) @@ -134,6 +138,28 @@ static AlgorithmParameterSpec[] getKeyPairSpecs(ASN1ObjectIdentifier algorithm) return kpgInitSpecs.get(algorithm); } + static Digest getDigest(ASN1ObjectIdentifier algOid) + { + String algName = algorithmNames.get(algOid); + + if (algName.endsWith("SHA256")) + { + return new SHA256Digest(); + } + + if (algName.endsWith("SHA384")) + { + return new SHA384Digest(); + } + + if (algName.endsWith("SHA512")) + { + return new SHA512Digest(); + } + + return new SHAKEDigest(256); + } + static String getBaseName(String name) { if (name.indexOf("RSA") >= 0) diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java index 8379a8f293..1bf1360fe4 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java @@ -18,7 +18,6 @@ import java.util.Map; import org.bouncycastle.asn1.ASN1BitString; -import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; @@ -26,18 +25,17 @@ import org.bouncycastle.asn1.DERBitString; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; -import org.bouncycastle.asn1.bc.BCObjectIdentifiers; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.sec.SECObjectIdentifiers; import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; -import org.bouncycastle.asn1.util.ASN1Dump; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.X962Parameters; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers; +import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers; import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers; import org.bouncycastle.jcajce.CompositePrivateKey; import org.bouncycastle.jcajce.CompositePublicKey; @@ -57,84 +55,67 @@ public class KeyFactorySpi extends BaseKeyFactorySpi implements AsymmetricKeyInfoConverter { + private static AlgorithmIdentifier createECAlgID(ASN1ObjectIdentifier curveOid) + { + return new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, new X962Parameters(curveOid)); + } //Specific algorithm identifiers of all component signature algorithms for SubjectPublicKeyInfo. These do not need to be all initialized here but makes the code more readable IMHO. private static final AlgorithmIdentifier mlDsa44 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_44); private static final AlgorithmIdentifier mlDsa65 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_65); private static final AlgorithmIdentifier mlDsa87 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_87); - private static final AlgorithmIdentifier falcon512Identifier = new AlgorithmIdentifier(BCObjectIdentifiers.falcon_512); +// private static final AlgorithmIdentifier falcon512Identifier = new AlgorithmIdentifier(BCObjectIdentifiers.falcon_512); private static final AlgorithmIdentifier ed25519 = new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519); - private static final AlgorithmIdentifier ecDsaP256 = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, new X962Parameters(SECObjectIdentifiers.secp256r1)); - private static final AlgorithmIdentifier ecDsaBrainpoolP256r1 = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, new X962Parameters(TeleTrusTObjectIdentifiers.brainpoolP256r1)); - private static final AlgorithmIdentifier rsa = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption); private static final AlgorithmIdentifier ed448 = new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448); - private static final AlgorithmIdentifier ecDsaP384 = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, new X962Parameters(SECObjectIdentifiers.secp384r1)); - private static final AlgorithmIdentifier ecDsaBrainpoolP384r1 = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, new X962Parameters(TeleTrusTObjectIdentifiers.brainpoolP384r1)); + private static final AlgorithmIdentifier ecDsaP256 = createECAlgID(SECObjectIdentifiers.secp256r1); + private static final AlgorithmIdentifier ecDsaP384 = createECAlgID(SECObjectIdentifiers.secp384r1); + private static final AlgorithmIdentifier ecDsaP521 = createECAlgID(SECObjectIdentifiers.secp521r1); + private static final AlgorithmIdentifier ecDsaBrainpoolP256r1 = createECAlgID(TeleTrusTObjectIdentifiers.brainpoolP256r1); + private static final AlgorithmIdentifier ecDsaBrainpoolP384r1 = createECAlgID(TeleTrusTObjectIdentifiers.brainpoolP384r1); + private static final AlgorithmIdentifier rsa = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption); private static Map pairings = new HashMap(); private static Map componentKeySizes = new HashMap(); - + static { - pairings.put(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, new AlgorithmIdentifier[]{mlDsa44, rsa}); - pairings.put(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, new AlgorithmIdentifier[]{mlDsa44, rsa}); - pairings.put(MiscObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, new AlgorithmIdentifier[]{mlDsa44, ed25519}); - pairings.put(MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, new AlgorithmIdentifier[]{mlDsa44, ecDsaP256}); - pairings.put(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA256, new AlgorithmIdentifier[]{mlDsa65, rsa}); - pairings.put(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA256, new AlgorithmIdentifier[]{mlDsa65, rsa}); - pairings.put(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA384, new AlgorithmIdentifier[]{mlDsa65, rsa}); - pairings.put(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA384, new AlgorithmIdentifier[]{mlDsa65, rsa}); - pairings.put(MiscObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA384, new AlgorithmIdentifier[]{mlDsa65, ecDsaP384}); - pairings.put(MiscObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA256, new AlgorithmIdentifier[]{mlDsa65, ecDsaBrainpoolP256r1}); - pairings.put(MiscObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, new AlgorithmIdentifier[]{mlDsa65, ed25519}); - pairings.put(MiscObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA384, new AlgorithmIdentifier[]{mlDsa87, ecDsaP384}); - pairings.put(MiscObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA384, new AlgorithmIdentifier[]{mlDsa87, ecDsaBrainpoolP384r1}); - pairings.put(MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512, new AlgorithmIdentifier[]{mlDsa87, ed448}); - - pairings.put(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PSS_SHA256, new AlgorithmIdentifier[]{mlDsa44, rsa}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PKCS15_SHA256, new AlgorithmIdentifier[]{mlDsa44, rsa}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA44_Ed25519_SHA512, new AlgorithmIdentifier[]{mlDsa44, ed25519}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA44_ECDSA_P256_SHA256, new AlgorithmIdentifier[]{mlDsa44, ecDsaP256}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA3072_PSS_SHA512, new AlgorithmIdentifier[]{mlDsa65, rsa}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA3072_PKCS15_SHA512, new AlgorithmIdentifier[]{mlDsa65, rsa}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA4096_PSS_SHA512, new AlgorithmIdentifier[]{mlDsa65, rsa}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA4096_PKCS15_SHA512, new AlgorithmIdentifier[]{mlDsa65, rsa}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA65_ECDSA_P384_SHA512, new AlgorithmIdentifier[]{mlDsa65, ecDsaP384}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA65_ECDSA_brainpoolP256r1_SHA512, new AlgorithmIdentifier[]{mlDsa65, ecDsaBrainpoolP256r1}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA65_Ed25519_SHA512, new AlgorithmIdentifier[]{mlDsa65, ed25519}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_P384_SHA512, new AlgorithmIdentifier[]{mlDsa87, ecDsaP384}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_brainpoolP384r1_SHA512, new AlgorithmIdentifier[]{mlDsa87, ecDsaBrainpoolP384r1}); - pairings.put(MiscObjectIdentifiers.id_HashMLDSA87_Ed448_SHA512, new AlgorithmIdentifier[] { mlDsa87, ed448}); - - componentKeySizes.put(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, new int[]{1328, 268}); - componentKeySizes.put(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, new int[]{1312, 284}); - componentKeySizes.put(MiscObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, new int[]{1312, Ed25519.PUBLIC_KEY_SIZE}); - componentKeySizes.put(MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, new int[]{1312, 76}); - componentKeySizes.put(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA256, new int[]{1952, 256}); - componentKeySizes.put(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA256, new int[]{1952, 256}); - componentKeySizes.put(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA384, new int[]{1952, 542}); - componentKeySizes.put(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA384, new int[]{1952, 542}); - componentKeySizes.put(MiscObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA384, new int[]{1952, 87}); - componentKeySizes.put(MiscObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA256, new int[]{1952, 76}); - componentKeySizes.put(MiscObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, new int[]{1952, Ed25519.PUBLIC_KEY_SIZE}); - componentKeySizes.put(MiscObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA384, new int[]{2592, 87}); - componentKeySizes.put(MiscObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA384, new int[]{2592, 87}); - componentKeySizes.put(MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512, new int[]{2592, Ed448.PUBLIC_KEY_SIZE}); - - componentKeySizes.put(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PSS_SHA256, new int[]{1328, 268}); - componentKeySizes.put(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PKCS15_SHA256, new int[]{1312, 284}); - componentKeySizes.put(MiscObjectIdentifiers.id_HashMLDSA44_Ed25519_SHA512, new int[]{1312, Ed25519.PUBLIC_KEY_SIZE}); - componentKeySizes.put(MiscObjectIdentifiers.id_HashMLDSA44_ECDSA_P256_SHA256, new int[]{1312, 76}); - componentKeySizes.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA3072_PSS_SHA512, new int[]{1952, 256}); - componentKeySizes.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA3072_PKCS15_SHA512, new int[]{1952, 256}); - componentKeySizes.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA4096_PSS_SHA512, new int[]{1952, 542}); - componentKeySizes.put(MiscObjectIdentifiers.id_HashMLDSA65_RSA4096_PKCS15_SHA512, new int[]{1952, 542}); - componentKeySizes.put(MiscObjectIdentifiers.id_HashMLDSA65_ECDSA_P384_SHA512, new int[]{1952, 87}); - componentKeySizes.put(MiscObjectIdentifiers.id_HashMLDSA65_ECDSA_brainpoolP256r1_SHA512, new int[]{1952, 76}); - componentKeySizes.put(MiscObjectIdentifiers.id_HashMLDSA65_Ed25519_SHA512, new int[]{1952, Ed25519.PUBLIC_KEY_SIZE}); - componentKeySizes.put(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_P384_SHA512, new int[]{2592, 87}); - componentKeySizes.put(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_brainpoolP384r1_SHA512, new int[]{2592, 87}); - componentKeySizes.put(MiscObjectIdentifiers.id_HashMLDSA87_Ed448_SHA512, new int[] { 2592, Ed448.PUBLIC_KEY_SIZE}); + pairings.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, new AlgorithmIdentifier[]{mlDsa44, rsa}); + pairings.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, new AlgorithmIdentifier[]{mlDsa44, rsa}); + pairings.put(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, new AlgorithmIdentifier[]{mlDsa44, ed25519}); + pairings.put(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, new AlgorithmIdentifier[]{mlDsa44, ecDsaP256}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, new AlgorithmIdentifier[]{mlDsa65, rsa}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512, new AlgorithmIdentifier[]{mlDsa65, rsa}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, new AlgorithmIdentifier[]{mlDsa65, rsa}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512, new AlgorithmIdentifier[]{mlDsa65, rsa}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512, new AlgorithmIdentifier[]{mlDsa65, ecDsaP256}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512, new AlgorithmIdentifier[]{mlDsa65, ecDsaP384}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512, new AlgorithmIdentifier[]{mlDsa65, ecDsaBrainpoolP256r1}); + pairings.put(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, new AlgorithmIdentifier[]{mlDsa65, ed25519}); + pairings.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512, new AlgorithmIdentifier[]{mlDsa87, ecDsaP384}); + pairings.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512, new AlgorithmIdentifier[]{mlDsa87, ecDsaBrainpoolP384r1}); + pairings.put(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256, new AlgorithmIdentifier[]{mlDsa87, ed448}); + pairings.put(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, new AlgorithmIdentifier[]{mlDsa87, rsa}); + pairings.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512, new AlgorithmIdentifier[]{mlDsa87, ecDsaP521}); + pairings.put(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, new AlgorithmIdentifier[]{mlDsa87, rsa}); + + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, new int[]{1312, 268}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, new int[]{1312, 284}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, new int[]{1312, Ed25519.PUBLIC_KEY_SIZE}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, new int[]{1312, 76}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, new int[]{1952, 256}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512, new int[]{1952, 256}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, new int[]{1952, 542}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512, new int[]{1952, 542}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512, new int[]{1952, 76}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512, new int[]{1952, 87}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512, new int[]{1952, 76}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, new int[]{1952, Ed25519.PUBLIC_KEY_SIZE}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512, new int[]{2592, 87}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512, new int[]{2592, 87}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256, new int[]{2592, Ed448.PUBLIC_KEY_SIZE}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, new int[]{2592, 542}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, new int[]{2592, 256}); + componentKeySizes.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512, new int[]{2592, 93}); } private JcaJceHelper helper; @@ -224,39 +205,41 @@ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo) try { ASN1Sequence seq; + List factories = getKeyFactoriesFromIdentifier(keyIdentifier); //Get key factories for each component algorithm. + byte[] data; + ASN1EncodableVector v = new ASN1EncodableVector(); // TODO: backwards compatibility code - should be deleted after 1.84. try { - ASN1Encodable obj = keyInfo.parsePrivateKey(); - if (obj instanceof ASN1OctetString) - { - seq = DERSequence.getInstance(ASN1OctetString.getInstance(obj).getOctets()); - } - else - { - seq = DERSequence.getInstance(obj); - } + data = DEROctetString.getInstance(keyInfo.parsePrivateKey()).getOctets(); } catch (Exception e) { - // new raw encoding - we capitalise on the fact initial key is first 32 bytes. - ASN1EncodableVector v = new ASN1EncodableVector(); - byte[] data = keyInfo.getPrivateKey().getOctets(); - - v.add(new DEROctetString(Arrays.copyOfRange(data, 0, 32))); + data = keyInfo.getPrivateKey().getOctets(); + } + v.add(new DEROctetString(Arrays.copyOfRange(data, 0, 32))); + String traditionAlg = factories.get(1).getAlgorithm(); + if (traditionAlg.equals("Ed25519")) + { + v.add(new DEROctetString(Arrays.concatenate(new byte[]{0x04, 0x20}, Arrays.copyOfRange(data, 32, data.length)))); + } + else if (traditionAlg.equals("Ed448")) + { + v.add(new DEROctetString(Arrays.concatenate(new byte[]{0x04, 0x39}, Arrays.copyOfRange(data, 32, data.length)))); + } + else + { v.add(new DEROctetString(Arrays.copyOfRange(data, 32, data.length))); - - seq = new DERSequence(v); } + seq = new DERSequence(v); - List factories = getKeyFactoriesFromIdentifier(keyIdentifier); //Get key factories for each component algorithm. PrivateKey[] privateKeys = new PrivateKey[seq.size()]; AlgorithmIdentifier[] algIds = pairings.get(keyIdentifier); for (int i = 0; i < seq.size(); i++) { if (seq.getObjectAt(i) instanceof ASN1OctetString) { - ASN1EncodableVector v = new ASN1EncodableVector(3); + v = new ASN1EncodableVector(3); v.add(keyInfo.getVersion()); v.add(algIds[i]); @@ -303,23 +286,24 @@ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo) } ASN1ObjectIdentifier keyIdentifier = keyInfo.getAlgorithm().getAlgorithm(); - + ASN1Sequence seq = null; byte[][] componentKeys = new byte[2][]; - + try { - seq = DERSequence.getInstance(keyInfo.getPublicKeyData().getBytes()); + seq = ASN1Sequence.getInstance(keyInfo.getPublicKeyData().getOctets()); } catch (Exception e) { - componentKeys = split(keyIdentifier, keyInfo.getPublicKeyData()); + componentKeys = split(keyIdentifier, keyInfo.getPublicKeyData()); } - + if (MiscObjectIdentifiers.id_alg_composite.equals(keyIdentifier) || MiscObjectIdentifiers.id_composite_key.equals(keyIdentifier)) { - ASN1Sequence keySeq = ASN1Sequence.getInstance(keyInfo.getPublicKeyData().getBytes()); + // TODO This is redundant with 'seq' calculation above + ASN1Sequence keySeq = ASN1Sequence.getInstance(keyInfo.getPublicKeyData().getOctets()); PublicKey[] pubKeys = new PublicKey[keySeq.size()]; for (int i = 0; i != keySeq.size(); i++) @@ -387,11 +371,12 @@ byte[][] split(ASN1ObjectIdentifier algorithm, ASN1BitString publicKeyData) { int[] sizes = componentKeySizes.get(algorithm); byte[] keyData = publicKeyData.getOctets(); - byte[][] components = new byte[][] { new byte[sizes[0]], new byte[sizes[1]] }; - + byte[][] components = new byte[][]{new byte[sizes[0]], new byte[keyData.length - sizes[0]]}; + System.arraycopy(keyData, 0, components[0], 0, sizes[0]); + System.arraycopy(keyData, sizes[0], components[1], 0, components[1].length); return components; } - + /** * A helper method that returns a list of KeyFactory objects based on the composite signature OID. * diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java index 2fdaad28f3..bb35e83dc1 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java @@ -9,7 +9,7 @@ import java.security.spec.AlgorithmParameterSpec; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers; +import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers; import org.bouncycastle.jcajce.CompositePrivateKey; import org.bouncycastle.jcajce.CompositePublicKey; @@ -31,7 +31,7 @@ public class KeyPairGeneratorSpi this.algorithm = algorithm; String[] algorithms = CompositeIndex.getPairing(algorithm); - AlgorithmParameterSpec[] initSpecs = CompositeIndex.getKeyPairSpecs(algorithm); + AlgorithmParameterSpec[] initSpecs = CompositeIndex.getKeyPairSpecs(algorithm); this.generators = new KeyPairGenerator[algorithms.length]; for (int i = 0; i != algorithms.length; i++) @@ -84,7 +84,7 @@ public void initialize(AlgorithmParameterSpec paramSpec, SecureRandom secureRand throw new IllegalArgumentException("Use initialize only for custom SecureRandom. AlgorithmParameterSpec must be null because it is determined by algorithm name."); } - AlgorithmParameterSpec[] initSpecs = CompositeIndex.getKeyPairSpecs(algorithm); + AlgorithmParameterSpec[] initSpecs = CompositeIndex.getKeyPairSpecs(algorithm); for (int i = 0; i != initSpecs.length; i++) { AlgorithmParameterSpec initSpec = initSpecs[i]; @@ -120,256 +120,167 @@ private KeyPair getCompositeKeyPair() CompositePrivateKey compositePrivateKey = new CompositePrivateKey(this.algorithm, privateKeys); return new KeyPair(compositePublicKey, compositePrivateKey); } - - public static final class HashMLDSA44_ECDSA_P256_SHA256 - extends KeyPairGeneratorSpi - { - public HashMLDSA44_ECDSA_P256_SHA256() - { - super(MiscObjectIdentifiers.id_HashMLDSA44_ECDSA_P256_SHA256); - } - } - - public static final class HashMLDSA44_Ed25519_SHA512 - extends KeyPairGeneratorSpi - { - public HashMLDSA44_Ed25519_SHA512() - { - super(MiscObjectIdentifiers.id_HashMLDSA44_Ed25519_SHA512); - } - } - - public static final class HashMLDSA44_RSA2048_PKCS15_SHA256 - extends KeyPairGeneratorSpi - { - public HashMLDSA44_RSA2048_PKCS15_SHA256() - { - super(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PKCS15_SHA256); - } - } - public static final class HashMLDSA44_RSA2048_PSS_SHA256 - extends KeyPairGeneratorSpi - { - public HashMLDSA44_RSA2048_PSS_SHA256() - { - super(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PSS_SHA256); - } - } - - public static final class HashMLDSA65_ECDSA_brainpoolP256r1_SHA512 - extends KeyPairGeneratorSpi - { - public HashMLDSA65_ECDSA_brainpoolP256r1_SHA512() - { - super(MiscObjectIdentifiers.id_HashMLDSA65_ECDSA_brainpoolP256r1_SHA512); - } - } - - public static final class HashMLDSA65_ECDSA_P384_SHA512 - extends KeyPairGeneratorSpi - { - public HashMLDSA65_ECDSA_P384_SHA512() - { - super(MiscObjectIdentifiers.id_HashMLDSA65_ECDSA_P384_SHA512); - } - } - - public static final class HashMLDSA65_Ed25519_SHA512 - extends KeyPairGeneratorSpi - { - public HashMLDSA65_Ed25519_SHA512() - { - super(MiscObjectIdentifiers.id_HashMLDSA65_Ed25519_SHA512); - } - } - - public static final class HashMLDSA65_RSA3072_PKCS15_SHA512 - extends KeyPairGeneratorSpi - { - public HashMLDSA65_RSA3072_PKCS15_SHA512() - { - super(MiscObjectIdentifiers.id_HashMLDSA65_RSA3072_PKCS15_SHA512); - } - } - - public static final class HashMLDSA65_RSA3072_PSS_SHA512 + public static final class MLDSA44_ECDSA_P256_SHA256 extends KeyPairGeneratorSpi { - public HashMLDSA65_RSA3072_PSS_SHA512() + public MLDSA44_ECDSA_P256_SHA256() { - super(MiscObjectIdentifiers.id_HashMLDSA65_RSA3072_PSS_SHA512); + super(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256); } } - public static final class HashMLDSA65_RSA4096_PKCS15_SHA512 + public static final class MLDSA44_Ed25519_SHA512 extends KeyPairGeneratorSpi { - public HashMLDSA65_RSA4096_PKCS15_SHA512() + public MLDSA44_Ed25519_SHA512() { - super(MiscObjectIdentifiers.id_HashMLDSA65_RSA4096_PKCS15_SHA512); + super(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512); } } - public static final class HashMLDSA65_RSA4096_PSS_SHA512 + public static final class MLDSA44_RSA2048_PKCS15_SHA256 extends KeyPairGeneratorSpi { - public HashMLDSA65_RSA4096_PSS_SHA512() + public MLDSA44_RSA2048_PKCS15_SHA256() { - super(MiscObjectIdentifiers.id_HashMLDSA65_RSA4096_PSS_SHA512); + super(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256); } } - public static final class HashMLDSA87_ECDSA_brainpoolP384r1_SHA512 + public static final class MLDSA44_RSA2048_PSS_SHA256 extends KeyPairGeneratorSpi { - public HashMLDSA87_ECDSA_brainpoolP384r1_SHA512() + public MLDSA44_RSA2048_PSS_SHA256() { - super(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_brainpoolP384r1_SHA512); + super(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256); } } - public static final class HashMLDSA87_ECDSA_P384_SHA512 - extends KeyPairGeneratorSpi - { - public HashMLDSA87_ECDSA_P384_SHA512() - { - super(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_P384_SHA512); - } - } - - public static final class HashMLDSA87_Ed448_SHA512 + public static final class MLDSA65_Ed25519_SHA512 extends KeyPairGeneratorSpi { - public HashMLDSA87_Ed448_SHA512() + public MLDSA65_Ed25519_SHA512() { - super(MiscObjectIdentifiers.id_HashMLDSA87_Ed448_SHA512); + super(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512); } } - public static final class MLDSA44_ECDSA_P256_SHA256 + public static final class MLDSA65_RSA3072_PSS_SHA512 extends KeyPairGeneratorSpi { - public MLDSA44_ECDSA_P256_SHA256() + public MLDSA65_RSA3072_PSS_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256); + super(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512); } } - public static final class MLDSA44_Ed25519_SHA512 + public static final class MLDSA65_RSA3072_PKCS15_SHA512 extends KeyPairGeneratorSpi { - public MLDSA44_Ed25519_SHA512() + public MLDSA65_RSA3072_PKCS15_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA44_Ed25519_SHA512); + super(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512); } } - public static final class MLDSA44_RSA2048_PKCS15_SHA256 + public static final class MLDSA65_RSA4096_PSS_SHA512 extends KeyPairGeneratorSpi { - public MLDSA44_RSA2048_PKCS15_SHA256() + public MLDSA65_RSA4096_PSS_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256); + super(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512); } } - public static final class MLDSA44_RSA2048_PSS_SHA256 + public static final class MLDSA65_RSA4096_PKCS15_SHA512 extends KeyPairGeneratorSpi { - public MLDSA44_RSA2048_PSS_SHA256() + public MLDSA65_RSA4096_PKCS15_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256); + super(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512); } } - public static final class MLDSA65_ECDSA_brainpoolP256r1_SHA256 + public static final class MLDSA65_ECDSA_P256_SHA512 extends KeyPairGeneratorSpi { - public MLDSA65_ECDSA_brainpoolP256r1_SHA256() + public MLDSA65_ECDSA_P256_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA256); + super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512); } } - public static final class MLDSA65_ECDSA_P384_SHA384 + public static final class MLDSA65_ECDSA_P384_SHA512 extends KeyPairGeneratorSpi { - public MLDSA65_ECDSA_P384_SHA384() + public MLDSA65_ECDSA_P384_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA384); + super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512); } } - public static final class MLDSA65_Ed25519_SHA512 + public static final class MLDSA65_ECDSA_brainpoolP256r1_SHA512 extends KeyPairGeneratorSpi { - public MLDSA65_Ed25519_SHA512() + public MLDSA65_ECDSA_brainpoolP256r1_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA65_Ed25519_SHA512); + super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512); } } - public static final class MLDSA65_RSA3072_PKCS15_SHA256 + public static final class MLDSA87_ECDSA_P384_SHA512 extends KeyPairGeneratorSpi { - public MLDSA65_RSA3072_PKCS15_SHA256() + public MLDSA87_ECDSA_P384_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA256); + super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512); } } - public static final class MLDSA65_RSA3072_PSS_SHA256 + public static final class MLDSA87_ECDSA_brainpoolP384r1_SHA512 extends KeyPairGeneratorSpi { - public MLDSA65_RSA3072_PSS_SHA256() + public MLDSA87_ECDSA_brainpoolP384r1_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA256); + super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512); } } - public static final class MLDSA65_RSA4096_PKCS15_SHA384 + public static final class MLDSA87_Ed448_SHAKE256 extends KeyPairGeneratorSpi { - public MLDSA65_RSA4096_PKCS15_SHA384() + public MLDSA87_Ed448_SHAKE256() { - super(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA384); + super(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256); } } - public static final class MLDSA65_RSA4096_PSS_SHA384 + public static final class MLDSA87_RSA4096_PSS_SHA512 extends KeyPairGeneratorSpi { - public MLDSA65_RSA4096_PSS_SHA384() + public MLDSA87_RSA4096_PSS_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA384); + super(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512); } } - public static final class MLDSA87_ECDSA_brainpoolP384r1_SHA384 + public static final class MLDSA87_ECDSA_P521_SHA512 extends KeyPairGeneratorSpi { - public MLDSA87_ECDSA_brainpoolP384r1_SHA384() + public MLDSA87_ECDSA_P521_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA384); + super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512); } } - public static final class MLDSA87_ECDSA_P384_SHA384 + public static final class MLDSA87_RSA3072_PSS_SHA512 extends KeyPairGeneratorSpi { - public MLDSA87_ECDSA_P384_SHA384() + public MLDSA87_RSA3072_PSS_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA384); + super(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512); } } - public static final class MLDSA87_Ed448_SHA512 - extends KeyPairGeneratorSpi - { - public MLDSA87_Ed448_SHA512() - { - super(MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512); - } - } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java index 6fa7c0fd0c..7cb1e05a52 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java @@ -1,39 +1,48 @@ package org.bouncycastle.jcajce.provider.asymmetric.compositesignatures; -import java.io.IOException; +import java.io.ByteArrayOutputStream; import java.security.AlgorithmParameters; import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.InvalidParameterException; import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.security.PrivateKey; +import java.security.Provider; import java.security.PublicKey; +import java.security.SecureRandom; import java.security.Signature; import java.security.SignatureException; import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import org.bouncycastle.asn1.ASN1BitString; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.digests.SHA512Digest; -import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers; +import org.bouncycastle.crypto.digests.SHAKEDigest; +import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers; import org.bouncycastle.jcajce.CompositePrivateKey; import org.bouncycastle.jcajce.CompositePublicKey; +import org.bouncycastle.jcajce.interfaces.BCKey; +import org.bouncycastle.jcajce.spec.CompositeSignatureSpec; import org.bouncycastle.jcajce.spec.ContextParameterSpec; import org.bouncycastle.jcajce.util.BCJcaJceHelper; import org.bouncycastle.jcajce.util.JcaJceHelper; +import org.bouncycastle.jcajce.util.SpecUtil; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Exceptions; +import org.bouncycastle.util.encoders.Hex; /** * Signature class for composite signatures. Selected algorithm is set by the "subclasses" at the end of this file. @@ -41,12 +50,15 @@ public class SignatureSpi extends java.security.SignatureSpi { + //the byte encoding of the ASCII string "CompositeAlgorithmSignatures2025" + private static final byte[] prefix = Hex.decode("436f6d706f73697465416c676f726974686d5369676e61747572657332303235"); private static final Map canonicalNames = new HashMap(); - + private static final HashMap domainSeparators = new LinkedHashMap(); + private static final HashMap algorithmsParameterSpecs = new HashMap(); private static final String ML_DSA_44 = "ML-DSA-44"; private static final String ML_DSA_65 = "ML-DSA-65"; private static final String ML_DSA_87 = "ML-DSA-87"; - + private final SecureRandom random = CryptoServicesRegistrar.getSecureRandom(); private Key compositeKey; static @@ -57,69 +69,73 @@ public class SignatureSpi canonicalNames.put(NISTObjectIdentifiers.id_ml_dsa_44.getId(), ML_DSA_44); canonicalNames.put(NISTObjectIdentifiers.id_ml_dsa_65.getId(), ML_DSA_65); canonicalNames.put(NISTObjectIdentifiers.id_ml_dsa_87.getId(), ML_DSA_87); + + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, Hex.decode("434f4d505349472d4d4c44534134342d525341323034382d5053532d534841323536")); // COMPSIG-MLDSA44-RSA2048-PSS-SHA256 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, Hex.decode("434f4d505349472d4d4c44534134342d525341323034382d504b435331352d534841323536")); // COMPSIG-MLDSA44-RSA2048-PKCS15-SHA256 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, Hex.decode("434f4d505349472d4d4c44534134342d456432353531392d534841353132")); // COMPSIG-MLDSA44-Ed25519-SHA512 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, Hex.decode("434f4d505349472d4d4c44534134342d45434453412d503235362d534841323536")); // COMPSIG-MLDSA44-ECDSA-P256-SHA256 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d525341333037322d5053532d534841353132")); // COMPSIG-MLDSA65-RSA3072-PSS-SHA512 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d525341333037322d504b435331352d534841353132")); // COMPSIG-MLDSA65-RSA3072-PKCS15-SHA512 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d525341343039362d5053532d534841353132")); // COMPSIG-MLDSA65-RSA4096-PSS-SHA512 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d525341343039362d504b435331352d534841353132")); // COMPSIG-MLDSA65-RSA4096-PKCS15-SHA512 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d45434453412d503235362d534841353132")); // COMPSIG-MLDSA65-ECDSA-P256-SHA512 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d45434453412d503338342d534841353132")); // COMPSIG-MLDSA65-ECDSA-P384-SHA512 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d45434453412d42503235362d534841353132")); // COMPSIG-MLDSA65-ECDSA-BP256-SHA512 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, Hex.decode("434f4d505349472d4d4c44534136352d456432353531392d534841353132")); // COMPSIG-MLDSA65-Ed25519-SHA512 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512, Hex.decode("434f4d505349472d4d4c44534138372d45434453412d42503338342d534841353132")); // COMPSIG-MLDSA87-ECDSA-BP384-SHA512 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256, Hex.decode("434f4d505349472d4d4c44534138372d45643434382d5348414b45323536")); // COMPSIG-MLDSA87-Ed448-SHAKE256 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, Hex.decode("434f4d505349472d4d4c44534138372d525341333037322d5053532d534841353132")); // COMPSIG-MLDSA87-RSA3072-PSS-SHA512 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, Hex.decode("434f4d505349472d4d4c44534138372d525341343039362d5053532d534841353132")); // COMPSIG-MLDSA87-RSA4096-PSS-SHA512 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512, Hex.decode("434f4d505349472d4d4c44534138372d45434453412d503338342d534841353132")); // COMPSIG-MLDSA87-ECDSA-P384-SHA512 + domainSeparators.put(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512, Hex.decode("434f4d505349472d4d4c44534138372d45434453412d503532312d534841353132")); // COMPSIG-MLDSA87-ECDSA-P521-SHA512 + + algorithmsParameterSpecs.put(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, + new PSSParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), 32, 1)); + algorithmsParameterSpecs.put(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, + new PSSParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), 32, 1)); + algorithmsParameterSpecs.put(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, + new PSSParameterSpec("SHA-384", "MGF1", new MGF1ParameterSpec("SHA-384"), 48, 1)); + algorithmsParameterSpecs.put(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, + new PSSParameterSpec("SHA-384", "MGF1", new MGF1ParameterSpec("SHA-384"), 48, 1)); + algorithmsParameterSpecs.put(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, + new PSSParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), 32, 1)); } + //List of Signatures. Each entry corresponds to a component signature from the composite definition. - private final ASN1ObjectIdentifier algorithm; - private final Signature[] componentSignatures; - private final byte[] domain; - private final Digest preHashDigest; - private final byte[] hashOID; - private final JcaJceHelper helper = new BCJcaJceHelper(); - + + private final boolean isPrehash; + + private ASN1ObjectIdentifier algorithm; + private String[] algs; + private Signature[] componentSignatures; + private byte[] domain; + private Digest baseDigest; + private JcaJceHelper helper = new BCJcaJceHelper(); + + private Digest preHashDigest; private ContextParameterSpec contextSpec; private AlgorithmParameters engineParams = null; private boolean unprimed = true; - SignatureSpi(ASN1ObjectIdentifier algorithm) + SignatureSpi(ASN1ObjectIdentifier algorithm, Digest preHashDigest) { - this(algorithm, null, null); + this(algorithm, preHashDigest, false); } - SignatureSpi(ASN1ObjectIdentifier algorithm, Digest preHashDigest, ASN1ObjectIdentifier preHashOid) + SignatureSpi(ASN1ObjectIdentifier algorithm, Digest preHashDigest, boolean isPrehash) { this.algorithm = algorithm; - this.preHashDigest = preHashDigest; + this.isPrehash = isPrehash; - String[] algs = CompositeIndex.getPairing(algorithm); - - if (preHashDigest != null) + if (algorithm != null) { - try - { - this.hashOID = preHashOid.getEncoded(); - } - catch (IOException e) - { // if this happens, we're in real trouble! - throw new IllegalStateException("unable to encode domain value"); - } - } - else - { - hashOID = null; - } - - try - { - this.domain = algorithm.getEncoded(); - } - catch (IOException e) - { // if this happens, we're in real trouble! - throw new IllegalStateException("unable to encode domain value"); - } - - this.componentSignatures = new Signature[algs.length]; - try - { - for (int i = 0; i != componentSignatures.length; i++) - { - componentSignatures[i] = Signature.getInstance(algs[i], "BC"); - } - } - catch (GeneralSecurityException e) - { - throw Exceptions.illegalStateException(e.getMessage(), e); + this.baseDigest = preHashDigest; + this.preHashDigest = isPrehash ? new NullDigest(preHashDigest.getDigestSize()) : preHashDigest; + this.domain = domainSeparators.get(algorithm); + this.algs = CompositeIndex.getPairing(algorithm); + this.componentSignatures = new Signature[algs.length]; } } @@ -128,17 +144,34 @@ protected void engineInitVerify(PublicKey publicKey) { if (!(publicKey instanceof CompositePublicKey)) { - throw new InvalidKeyException("Public key is not composite."); + throw new InvalidKeyException("public key is not composite"); } this.compositeKey = publicKey; CompositePublicKey compositePublicKey = (CompositePublicKey)this.compositeKey; - if (!compositePublicKey.getAlgorithmIdentifier().equals(this.algorithm)) + + if (this.algorithm != null) { - throw new InvalidKeyException("Provided composite public key cannot be used with the composite signature algorithm."); + if (!compositePublicKey.getAlgorithmIdentifier().getAlgorithm().equals(this.algorithm)) + { + throw new InvalidKeyException("provided composite public key cannot be used with the composite signature algorithm"); + } + } + else + { + ASN1ObjectIdentifier sigAlgorithm = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()).getAlgorithm().getAlgorithm(); + + this.algorithm = sigAlgorithm; + this.baseDigest = CompositeIndex.getDigest(sigAlgorithm); + this.preHashDigest = isPrehash ? new NullDigest(baseDigest.getDigestSize()) : baseDigest; + this.domain = domainSeparators.get(sigAlgorithm); + this.algs = CompositeIndex.getPairing(sigAlgorithm); + this.componentSignatures = new Signature[algs.length]; } + createComponentSignatures(compositePublicKey.getPublicKeys(), compositePublicKey.getProviders()); + sigInitVerify(); } @@ -150,7 +183,6 @@ private void sigInitVerify() { this.componentSignatures[i].initVerify(compositePublicKey.getPublicKeys().get(i)); } - this.unprimed = true; } @@ -165,14 +197,76 @@ protected void engineInitSign(PrivateKey privateKey) this.compositeKey = privateKey; CompositePrivateKey compositePrivateKey = (CompositePrivateKey)privateKey; - if (!compositePrivateKey.getAlgorithmIdentifier().equals(this.algorithm)) + if (this.algorithm != null) { - throw new InvalidKeyException("Provided composite private key cannot be used with the composite signature algorithm."); + if (!compositePrivateKey.getAlgorithmIdentifier().getAlgorithm().equals(this.algorithm)) + { + throw new InvalidKeyException("provided composite public key cannot be used with the composite signature algorithm"); + } } + else + { + ASN1ObjectIdentifier sigAlgorithm = compositePrivateKey.getAlgorithmIdentifier().getAlgorithm(); + + this.algorithm = sigAlgorithm; + this.baseDigest = CompositeIndex.getDigest(sigAlgorithm); + this.preHashDigest = isPrehash ? new NullDigest(baseDigest.getDigestSize()) : baseDigest; + this.domain = domainSeparators.get(sigAlgorithm); + this.algs = CompositeIndex.getPairing(sigAlgorithm); + this.componentSignatures = new Signature[algs.length]; + } + + createComponentSignatures(compositePrivateKey.getPrivateKeys(), compositePrivateKey.getProviders()); sigInitSign(); } + private void createComponentSignatures(List keys, List providers) + { + try + { + if (providers == null) + { + for (int i = 0; i != componentSignatures.length; i++) + { + componentSignatures[i] = getDefaultSignature(algs[i], keys.get(i)); + } + } + else + { + for (int i = 0; i != componentSignatures.length; i++) + { + Provider prov = providers.get(i); + if (prov == null) + { + componentSignatures[i] = getDefaultSignature(algs[i], keys.get(i)); + } + else + { + componentSignatures[i] = Signature.getInstance(algs[i], providers.get(i)); + } + } + } + } + catch (GeneralSecurityException e) + { + throw Exceptions.illegalStateException(e.getMessage(), e); + } + } + + private Signature getDefaultSignature(String alg, Object key) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (key instanceof BCKey) + { + return helper.createSignature(alg); + } + else + { + return Signature.getInstance(alg); + } + } + private void sigInitSign() throws InvalidKeyException { @@ -191,32 +285,17 @@ private void baseSigInit() try { componentSignatures[0].setParameter(new ContextParameterSpec(domain)); + AlgorithmParameterSpec pssSpec = algorithmsParameterSpecs.get(this.algorithm); + if (pssSpec != null) + { + componentSignatures[1].setParameter(pssSpec); + } } catch (InvalidAlgorithmParameterException e) { throw new IllegalStateException("unable to set context on ML-DSA"); } - if (preHashDigest == null) - { - for (int i = 0; i < this.componentSignatures.length; i++) - { - Signature componentSig = this.componentSignatures[i]; - componentSig.update(domain); - if (contextSpec == null) - { - componentSig.update((byte)0); - } - else - { - byte[] ctx = contextSpec.getContext(); - - componentSig.update((byte)ctx.length); - componentSig.update(ctx); - } - } - } - this.unprimed = false; } @@ -276,39 +355,45 @@ protected void engineUpdate(byte[] bytes, int off, int len) protected byte[] engineSign() throws SignatureException { + byte[] r = new byte[32]; + random.nextBytes(r); // Secure random generator + if (preHashDigest != null) { - processPreHashedMessage(); + processPreHashedMessage(null); } - ASN1EncodableVector signatureSequence = new ASN1EncodableVector(); - try - { - for (int i = 0; i < this.componentSignatures.length; i++) - { - byte[] signatureValue = this.componentSignatures[i].sign(); - signatureSequence.add(new DERBitString(signatureValue)); - } + byte[] mldsaSig = this.componentSignatures[0].sign(); + byte[] tradSig = this.componentSignatures[1].sign(); - return new DERSequence(signatureSequence).getEncoded(ASN1Encoding.DER); - } - catch (IOException e) - { - throw new SignatureException(e.getMessage()); - } + // Concatenate: ML-DSA sig || Traditional sig + byte[] compositeSig = new byte[mldsaSig.length + tradSig.length]; + //System.arraycopy(r, 0, compositeSig, 0, 32); + System.arraycopy(mldsaSig, 0, compositeSig, 0, mldsaSig.length); + System.arraycopy(tradSig, 0, compositeSig, mldsaSig.length, tradSig.length); + + return compositeSig; } - private void processPreHashedMessage() + private void processPreHashedMessage(byte[] r) throws SignatureException { - byte[] dig = new byte[preHashDigest.getDigestSize()]; + byte[] dig = new byte[baseDigest.getDigestSize()]; - preHashDigest.doFinal(dig, 0); + try + { + preHashDigest.doFinal(dig, 0); + } + catch (IllegalStateException e) + { + throw new SignatureException(e.getMessage()); + } for (int i = 0; i < this.componentSignatures.length; i++) { Signature componentSig = this.componentSignatures[i]; - componentSig.update(domain, 0, domain.length); + componentSig.update(prefix); + componentSig.update(domain); if (contextSpec == null) { componentSig.update((byte)0); @@ -320,11 +405,27 @@ private void processPreHashedMessage() componentSig.update((byte)ctx.length); componentSig.update(ctx); } - componentSig.update(hashOID, 0, hashOID.length); + if (r != null) + { + componentSig.update(r, 0, r.length); + } componentSig.update(dig, 0, dig.length); } } + public static byte[][] splitCompositeSignature(byte[] compositeSignature, int mldsaSigLen) + { + //byte[] r = new byte[32]; + byte[] mldsaSig = new byte[mldsaSigLen]; + byte[] tradSig = new byte[compositeSignature.length - mldsaSigLen]; + + //System.arraycopy(compositeSignature, 0, r, 0, 32); + System.arraycopy(compositeSignature, 0, mldsaSig, 0, mldsaSigLen); + System.arraycopy(compositeSignature, mldsaSigLen, tradSig, 0, tradSig.length); + + return new byte[][]{mldsaSig, tradSig}; + } + /** * Corresponding verification method to the engineSign method. * The composite signature is valid if and only if all component signatures are valid. @@ -337,21 +438,26 @@ private void processPreHashedMessage() protected boolean engineVerify(byte[] signature) throws SignatureException { - ASN1Sequence signatureSequence = DERSequence.getInstance(signature); - //Check if the decoded sequence of component signatures has the expected size. - if (signatureSequence.size() != this.componentSignatures.length) + int mldsaSigLen = 0; + if (algs[0].indexOf("44") > 0) { - return false; + mldsaSigLen = 2420; } + else if (algs[0].indexOf("65") > 0) + { + mldsaSigLen = 3309; + } + else if (algs[0].indexOf("87") > 0) + { + mldsaSigLen = 4627; + } + byte[][] signatures = splitCompositeSignature(signature, mldsaSigLen); if (preHashDigest != null) { - if (preHashDigest != null) - { - processPreHashedMessage(); - } + processPreHashedMessage(null); } - + // Currently all signatures try to verify even if, e.g., the first is invalid. // If each component verify() is constant time, then this is also, otherwise it does not make sense to iterate over all if one of them already fails. // However, it is important that we do not provide specific error messages, e.g., "only the 2nd component failed to verify". @@ -359,7 +465,8 @@ protected boolean engineVerify(byte[] signature) for (int i = 0; i < this.componentSignatures.length; i++) { - if (!this.componentSignatures[i].verify(ASN1BitString.getInstance(signatureSequence.getObjectAt(i)).getOctets())) + //signatures[0] is 32-byte random number + if (!this.componentSignatures[i].verify(signatures[i])) { fail = true; } @@ -375,7 +482,7 @@ protected void engineSetParameter(AlgorithmParameterSpec algorithmParameterSpec) { throw new InvalidAlgorithmParameterException("attempt to set parameter after update"); } - + if (algorithmParameterSpec instanceof ContextParameterSpec) { contextSpec = (ContextParameterSpec)algorithmParameterSpec; @@ -395,23 +502,61 @@ protected void engineSetParameter(AlgorithmParameterSpec algorithmParameterSpec) throw new InvalidAlgorithmParameterException("keys invalid on reset: " + e.getMessage(), e); } } - else + else if (algorithmParameterSpec instanceof CompositeSignatureSpec) { - throw new InvalidAlgorithmParameterException("unknown parameterSpec passed to composite signature"); - } - } + CompositeSignatureSpec compositeSignatureSpec = (CompositeSignatureSpec)algorithmParameterSpec; - private void setSigParameter(Signature targetSig, String targetSigName, List names, List specs) - throws InvalidAlgorithmParameterException - { - for (int i = 0; i != names.size(); i++) - { - String canonicalName = getCanonicalName(names.get(i)); + if (compositeSignatureSpec.isPrehashMode()) + { + this.preHashDigest = new NullDigest(baseDigest.getDigestSize()); + } + else + { + this.preHashDigest = this.baseDigest; + } + AlgorithmParameterSpec secondarySpec = compositeSignatureSpec.getSecondarySpec(); - if (names.get(i).equals(targetSigName)) + if (secondarySpec == null || secondarySpec instanceof ContextParameterSpec) + { + this.contextSpec = (ContextParameterSpec)compositeSignatureSpec.getSecondarySpec(); + } + else { - targetSig.setParameter(specs.get(i)); + byte[] context = SpecUtil.getContextFrom(secondarySpec); + if (context != null) + { + contextSpec = new ContextParameterSpec(context); + } + else + { + throw new InvalidAlgorithmParameterException("unknown parameterSpec passed to composite signature"); + } + } + } + else + { + byte[] context = SpecUtil.getContextFrom(algorithmParameterSpec); + if (context != null) + { + contextSpec = new ContextParameterSpec(context); + try + { + if (compositeKey instanceof PublicKey) + { + sigInitVerify(); + } + else + { + sigInitSign(); + } + } + catch (InvalidKeyException e) + { + throw new InvalidAlgorithmParameterException("keys invalid on reset: " + e.getMessage(), e); + } } + + throw new InvalidAlgorithmParameterException("unknown parameterSpec passed to composite signature"); } } @@ -460,255 +605,417 @@ protected final AlgorithmParameters engineGetParameters() return engineParams; } - public static final class HashMLDSA44_ECDSA_P256_SHA256 + private static class NullDigest + implements Digest + { + private final int expectedSize; + private final OpenByteArrayOutputStream bOut = new OpenByteArrayOutputStream(); + + NullDigest(int expectedSize) + { + this.expectedSize = expectedSize; + } + + public String getAlgorithmName() + { + return "NULL"; + } + + public int getDigestSize() + { + return bOut.size(); + } + + public void update(byte in) + { + bOut.write(in); + } + + public void update(byte[] in, int inOff, int len) + { + bOut.write(in, inOff, len); + } + + public int doFinal(byte[] out, int outOff) + { + int size = bOut.size(); + if (size != expectedSize) + { + throw new IllegalStateException("provided pre-hash digest is the wrong length"); + } + + bOut.copy(out, outOff); + + reset(); + + return size; + } + + public void reset() + { + bOut.reset(); + } + + private static class OpenByteArrayOutputStream + extends ByteArrayOutputStream + { + public void reset() + { + super.reset(); + + Arrays.clear(buf); + } + + void copy(byte[] out, int outOff) + { + System.arraycopy(buf, 0, out, outOff, this.size()); + } + } + } + + public static final class MLDSA44_ECDSA_P256_SHA256 extends SignatureSpi { - public HashMLDSA44_ECDSA_P256_SHA256() + public MLDSA44_ECDSA_P256_SHA256() { - super(MiscObjectIdentifiers.id_HashMLDSA44_ECDSA_P256_SHA256, new SHA256Digest(), NISTObjectIdentifiers.id_sha256); + super(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, new SHA256Digest()); } } - public static final class HashMLDSA44_Ed25519_SHA512 + public static final class COMPOSITE extends SignatureSpi { - public HashMLDSA44_Ed25519_SHA512() + public COMPOSITE() { - super(MiscObjectIdentifiers.id_HashMLDSA44_Ed25519_SHA512, new SHA512Digest(), NISTObjectIdentifiers.id_sha512); + super(null, null, false); } } - public static final class HashMLDSA44_RSA2048_PKCS15_SHA256 + public static final class MLDSA44_ECDSA_P256_SHA256_PREHASH extends SignatureSpi { - public HashMLDSA44_RSA2048_PKCS15_SHA256() + public MLDSA44_ECDSA_P256_SHA256_PREHASH() { - super(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PKCS15_SHA256, new SHA256Digest(), NISTObjectIdentifiers.id_sha256); + super(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, new SHA256Digest(), true); } } - public static final class HashMLDSA44_RSA2048_PSS_SHA256 + public static final class MLDSA44_Ed25519_SHA512 extends SignatureSpi { - public HashMLDSA44_RSA2048_PSS_SHA256() + public MLDSA44_Ed25519_SHA512() { - super(MiscObjectIdentifiers.id_HashMLDSA44_RSA2048_PSS_SHA256, new SHA256Digest(), NISTObjectIdentifiers.id_sha256); + super(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, new SHA512Digest()); } } - public static final class HashMLDSA65_ECDSA_brainpoolP256r1_SHA512 + public static final class MLDSA44_Ed25519_SHA512_PREHASH extends SignatureSpi { - public HashMLDSA65_ECDSA_brainpoolP256r1_SHA512() + public MLDSA44_Ed25519_SHA512_PREHASH() { - super(MiscObjectIdentifiers.id_HashMLDSA65_ECDSA_brainpoolP256r1_SHA512, new SHA512Digest(), NISTObjectIdentifiers.id_sha512); + super(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512, new SHA512Digest(), true); } } - public static final class HashMLDSA65_ECDSA_P384_SHA512 + public static final class MLDSA44_RSA2048_PKCS15_SHA256 extends SignatureSpi { - public HashMLDSA65_ECDSA_P384_SHA512() + public MLDSA44_RSA2048_PKCS15_SHA256() { - super(MiscObjectIdentifiers.id_HashMLDSA65_ECDSA_P384_SHA512, new SHA512Digest(), NISTObjectIdentifiers.id_sha512); + super(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, new SHA256Digest()); } } - public static final class HashMLDSA65_Ed25519_SHA512 + public static final class MLDSA44_RSA2048_PKCS15_SHA256_PREHASH extends SignatureSpi { - public HashMLDSA65_Ed25519_SHA512() + public MLDSA44_RSA2048_PKCS15_SHA256_PREHASH() { - super(MiscObjectIdentifiers.id_HashMLDSA65_Ed25519_SHA512, new SHA512Digest(), NISTObjectIdentifiers.id_sha512); + super(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256, new SHA256Digest(), true); } } - public static final class HashMLDSA65_RSA3072_PKCS15_SHA512 + public static final class MLDSA44_RSA2048_PSS_SHA256 extends SignatureSpi { - public HashMLDSA65_RSA3072_PKCS15_SHA512() + public MLDSA44_RSA2048_PSS_SHA256() { - super(MiscObjectIdentifiers.id_HashMLDSA65_RSA3072_PKCS15_SHA512, new SHA512Digest(), NISTObjectIdentifiers.id_sha512); + super(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, new SHA256Digest()); } } - public static final class HashMLDSA65_RSA3072_PSS_SHA512 + public static final class MLDSA44_RSA2048_PSS_SHA256_PREHASH extends SignatureSpi { - public HashMLDSA65_RSA3072_PSS_SHA512() + public MLDSA44_RSA2048_PSS_SHA256_PREHASH() { - super(MiscObjectIdentifiers.id_HashMLDSA65_RSA3072_PSS_SHA512, new SHA512Digest(), NISTObjectIdentifiers.id_sha512); + super(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256, new SHA256Digest(), true); } } - public static final class HashMLDSA65_RSA4096_PKCS15_SHA512 + public static final class MLDSA65_Ed25519_SHA512 extends SignatureSpi { - public HashMLDSA65_RSA4096_PKCS15_SHA512() + public MLDSA65_Ed25519_SHA512() { - super(MiscObjectIdentifiers.id_HashMLDSA65_RSA4096_PKCS15_SHA512, new SHA512Digest(), NISTObjectIdentifiers.id_sha512); + super(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, new SHA512Digest()); } } - public static final class HashMLDSA65_RSA4096_PSS_SHA512 + public static final class MLDSA65_Ed25519_SHA512_PREHASH extends SignatureSpi { - public HashMLDSA65_RSA4096_PSS_SHA512() + public MLDSA65_Ed25519_SHA512_PREHASH() { - super(MiscObjectIdentifiers.id_HashMLDSA65_RSA4096_PSS_SHA512, new SHA512Digest(), NISTObjectIdentifiers.id_sha512); + super(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512, new SHA512Digest(), true); } } - public static final class HashMLDSA87_ECDSA_brainpoolP384r1_SHA512 + public static final class MLDSA65_RSA3072_PSS_SHA512 extends SignatureSpi { - public HashMLDSA87_ECDSA_brainpoolP384r1_SHA512() + public MLDSA65_RSA3072_PSS_SHA512() { - super(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_brainpoolP384r1_SHA512, new SHA512Digest(), NISTObjectIdentifiers.id_sha512); + super(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, new SHA512Digest()); } } - public static final class HashMLDSA87_ECDSA_P384_SHA512 + public static final class MLDSA65_RSA3072_PSS_SHA512_PREHASH extends SignatureSpi { - public HashMLDSA87_ECDSA_P384_SHA512() + public MLDSA65_RSA3072_PSS_SHA512_PREHASH() { - super(MiscObjectIdentifiers.id_HashMLDSA87_ECDSA_P384_SHA512, new SHA512Digest(), NISTObjectIdentifiers.id_sha512); + super(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512, new SHA512Digest(), true); } } - - public static final class HashMLDSA87_Ed448_SHA512 + + public static final class MLDSA65_RSA3072_PKCS15_SHA512 extends SignatureSpi { - public HashMLDSA87_Ed448_SHA512() + public MLDSA65_RSA3072_PKCS15_SHA512() { - super(MiscObjectIdentifiers.id_HashMLDSA87_Ed448_SHA512, new SHA512Digest(), NISTObjectIdentifiers.id_sha512); + super(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512, new SHA512Digest()); } } - public static final class MLDSA44_ECDSA_P256_SHA256 + public static final class MLDSA65_RSA3072_PKCS15_SHA512_PREHASH extends SignatureSpi { - public MLDSA44_ECDSA_P256_SHA256() + public MLDSA65_RSA3072_PKCS15_SHA512_PREHASH() { - super(MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256); + super(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512, new SHA512Digest(), true); } } - public static final class MLDSA44_Ed25519_SHA512 + public static final class MLDSA65_RSA4096_PSS_SHA512 extends SignatureSpi { - public MLDSA44_Ed25519_SHA512() + public MLDSA65_RSA4096_PSS_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA44_Ed25519_SHA512); + super(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, new SHA512Digest()); } } - public static final class MLDSA44_RSA2048_PKCS15_SHA256 + public static final class MLDSA65_RSA4096_PSS_SHA512_PREHASH extends SignatureSpi { - public MLDSA44_RSA2048_PKCS15_SHA256() + public MLDSA65_RSA4096_PSS_SHA512_PREHASH() { - super(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256); + super(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512, new SHA512Digest(), true); } } - public static final class MLDSA44_RSA2048_PSS_SHA256 + public static final class MLDSA65_RSA4096_PKCS15_SHA512 extends SignatureSpi { - public MLDSA44_RSA2048_PSS_SHA256() + public MLDSA65_RSA4096_PKCS15_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256); + super(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512, new SHA512Digest()); } } - public static final class MLDSA65_ECDSA_brainpoolP256r1_SHA256 + public static final class MLDSA65_RSA4096_PKCS15_SHA512_PREHASH extends SignatureSpi { - public MLDSA65_ECDSA_brainpoolP256r1_SHA256() + public MLDSA65_RSA4096_PKCS15_SHA512_PREHASH() { - super(MiscObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA256); + super(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512, new SHA512Digest(), true); } } - public static final class MLDSA65_ECDSA_P384_SHA384 + public static final class MLDSA65_ECDSA_P256_SHA512 extends SignatureSpi { - public MLDSA65_ECDSA_P384_SHA384() + public MLDSA65_ECDSA_P256_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA384); + super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512, new SHA512Digest()); } } - public static final class MLDSA65_Ed25519_SHA512 + public static final class MLDSA65_ECDSA_P256_SHA512_PREHASH extends SignatureSpi { - public MLDSA65_Ed25519_SHA512() + public MLDSA65_ECDSA_P256_SHA512_PREHASH() + { + super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512, new SHA512Digest(), true); + } + } + + public static final class MLDSA65_ECDSA_P384_SHA512 + extends SignatureSpi + { + public MLDSA65_ECDSA_P384_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA65_Ed25519_SHA512); + super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512, new SHA512Digest()); } } - public static final class MLDSA65_RSA3072_PKCS15_SHA256 + public static final class MLDSA65_ECDSA_P384_SHA512_PREHASH extends SignatureSpi { - public MLDSA65_RSA3072_PKCS15_SHA256() + public MLDSA65_ECDSA_P384_SHA512_PREHASH() { - super(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA256); + super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512, new SHA512Digest(), true); } } - public static final class MLDSA65_RSA3072_PSS_SHA256 + public static final class MLDSA65_ECDSA_brainpoolP256r1_SHA512 extends SignatureSpi { - public MLDSA65_RSA3072_PSS_SHA256() + public MLDSA65_ECDSA_brainpoolP256r1_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA256); + super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512, new SHA512Digest()); } } - public static final class MLDSA65_RSA4096_PKCS15_SHA384 + public static final class MLDSA65_ECDSA_brainpoolP256r1_SHA512_PREHASH extends SignatureSpi { - public MLDSA65_RSA4096_PKCS15_SHA384() + public MLDSA65_ECDSA_brainpoolP256r1_SHA512_PREHASH() { - super(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA384); + super(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512, new SHA512Digest(), true); } } - public static final class MLDSA65_RSA4096_PSS_SHA384 + public static final class MLDSA87_ECDSA_P384_SHA512 extends SignatureSpi { - public MLDSA65_RSA4096_PSS_SHA384() + public MLDSA87_ECDSA_P384_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA384); + super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512, new SHA512Digest()); } } - public static final class MLDSA87_ECDSA_brainpoolP384r1_SHA384 + public static final class MLDSA87_ECDSA_P384_SHA512_PREHASH extends SignatureSpi { - public MLDSA87_ECDSA_brainpoolP384r1_SHA384() + public MLDSA87_ECDSA_P384_SHA512_PREHASH() { - super(MiscObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA384); + super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512, new SHA512Digest(), true); } } - public static final class MLDSA87_ECDSA_P384_SHA384 + public static final class MLDSA87_ECDSA_brainpoolP384r1_SHA512 extends SignatureSpi { - public MLDSA87_ECDSA_P384_SHA384() + public MLDSA87_ECDSA_brainpoolP384r1_SHA512() { - super(MiscObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA384); + super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512, new SHA512Digest()); } } - public static final class MLDSA87_Ed448_SHA512 + public static final class MLDSA87_ECDSA_brainpoolP384r1_SHA512_PREHASH extends SignatureSpi { - public MLDSA87_Ed448_SHA512() + public MLDSA87_ECDSA_brainpoolP384r1_SHA512_PREHASH() + { + super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512, new SHA512Digest(), true); + } + } + + public static final class MLDSA87_Ed448_SHAKE256 + extends SignatureSpi + { + public MLDSA87_Ed448_SHAKE256() + { + super(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256, new SHAKEDigest(256)); + } + } + + public static final class MLDSA87_Ed448_SHAKE256_PREHASH + extends SignatureSpi + { + public MLDSA87_Ed448_SHAKE256_PREHASH() + { + super(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256, new SHAKEDigest(256), true); + } + } + + public static final class MLDSA87_RSA3072_PSS_SHA512 + extends SignatureSpi + { + public MLDSA87_RSA3072_PSS_SHA512() + { + super(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, new SHA512Digest()); + } + } + + public static final class MLDSA87_RSA3072_PSS_SHA512_PREHASH + extends SignatureSpi + { + public MLDSA87_RSA3072_PSS_SHA512_PREHASH() + { + super(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512, new SHA512Digest(), true); + } + } + + public static final class MLDSA87_RSA4096_PSS_SHA512 + extends SignatureSpi + { + public MLDSA87_RSA4096_PSS_SHA512() + { + super(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, new SHA512Digest()); + } + } + + public static final class MLDSA87_RSA4096_PSS_SHA512_PREHASH + extends SignatureSpi + { + public MLDSA87_RSA4096_PSS_SHA512_PREHASH() + { + super(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512, new SHA512Digest(), true); + } + } + + public static final class MLDSA87_ECDSA_P521_SHA512 + extends SignatureSpi + { + public MLDSA87_ECDSA_P521_SHA512() + { + super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512, new SHA512Digest()); + } + } + + public static final class MLDSA87_ECDSA_P521_SHA512_PREHASH + extends SignatureSpi + { + public MLDSA87_ECDSA_P521_SHA512_PREHASH() + { + super(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512, new SHA512Digest(), true); + } + } + + private static final class ErasableOutputStream + extends ByteArrayOutputStream + { + public ErasableOutputStream() + { + } + + public byte[] getBuf() { - super(MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512); + return buf; } } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java index f26b83bd06..b809458339 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java @@ -11,7 +11,7 @@ class DHUtil { static String privateKeyToString(String algorithm, BigInteger x, DHParameters dhParams) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); BigInteger y = dhParams.getG().modPow(x, dhParams.getP()); @@ -25,7 +25,7 @@ static String privateKeyToString(String algorithm, BigInteger x, DHParameters dh static String publicKeyToString(String algorithm, BigInteger y, DHParameters dhParams) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append(algorithm); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/IESCipher.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/IESCipher.java index 447047b1eb..de874e36cf 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/IESCipher.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dh/IESCipher.java @@ -496,7 +496,7 @@ public int engineDoFinal( * Classes that inherit from us */ - static public class IES + public static class IES extends IESCipher { public IES() @@ -507,7 +507,7 @@ public IES() } } - static public class IESwithDESedeCBC + public static class IESwithDESedeCBC extends IESCipher { public IESwithDESedeCBC() @@ -519,7 +519,7 @@ public IESwithDESedeCBC() } } - static public class IESwithAESCBC + public static class IESwithAESCBC extends IESCipher { public IESwithAESCBC() diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java index b0634bf036..e24ed64f89 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java @@ -178,7 +178,7 @@ private void writeObject( public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); BigInteger y = getParams().getG().modPow(x, getParams().getP()); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java index 0aa9691513..1c17ac875c 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java @@ -134,7 +134,7 @@ public BigInteger getY() public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append("DSA Public Key [").append(DSAUtil.generateKeyFingerprint(y, getParams())).append("]").append(nl); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java index d776a58bc6..f0e68d0796 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java @@ -117,8 +117,19 @@ else if (params instanceof ECGenParameterSpec || params instanceof ECNamedCurveG curveName = ((ECNamedCurveGenParameterSpec)params).getName(); } - //ECDomainParameters ecP = ECGOST3410NamedCurves.getByName(curveName); - ECDomainParameters ecP = DSTU4145NamedCurves.getByOID(new ASN1ObjectIdentifier(curveName)); + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.tryFromID(curveName); + + ECDomainParameters ecP; + if (oid != null) + { + ecP = DSTU4145NamedCurves.getByOID(oid); + } + else + { + // TODO Add curve names to DSTU4145NamedCurves registry and support getByName + throw new InvalidAlgorithmParameterException("non-OID curve name not supported: " + curveName); + } + if (ecP == null) { throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java index e7bc2b6eb4..3a06f28e04 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java @@ -25,6 +25,7 @@ import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECNamedDomainParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.jcajce.interfaces.BCKey; import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; @@ -37,7 +38,7 @@ import org.bouncycastle.util.Arrays; public class BCECPrivateKey - implements ECPrivateKey, org.bouncycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder + implements ECPrivateKey, org.bouncycastle.jce.interfaces.ECPrivateKey, PKCS12BagAttributeCarrier, ECPointEncoder, BCKey { static final long serialVersionUID = 994553197664784084L; diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java index bb66f7138e..3c9a2e5c53 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java @@ -21,6 +21,7 @@ import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.jcajce.interfaces.BCKey; import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; @@ -32,7 +33,7 @@ import org.bouncycastle.util.Properties; public class BCECPublicKey - implements ECPublicKey, org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder + implements ECPublicKey, org.bouncycastle.jce.interfaces.ECPublicKey, ECPointEncoder, BCKey { static final long serialVersionUID = 2422789860422731812L; diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java index ec97fe1758..45b65975b0 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java @@ -54,7 +54,7 @@ static X9ECParameters getDomainParametersFromName(String curveName, ProviderConf curveName = curveName.substring(spacePos + 1); } - ASN1ObjectIdentifier oid = getOID(curveName); + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.tryFromID(curveName); if (null == oid) { return ECUtil.getNamedCurveByName(curveName); @@ -107,20 +107,4 @@ else if (ecSpec == null) return params; } - - private static ASN1ObjectIdentifier getOID(String curveName) - { - char firstChar = curveName.charAt(0); - if (firstChar >= '0' && firstChar <= '2') - { - try - { - return new ASN1ObjectIdentifier(curveName); - } - catch (Exception e) - { - } - } - return null; - } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/GMKeyExchangeSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/GMKeyExchangeSpi.java new file mode 100644 index 0000000000..d5f308c05f --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/GMKeyExchangeSpi.java @@ -0,0 +1,110 @@ +package org.bouncycastle.jcajce.provider.asymmetric.ec; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import org.bouncycastle.crypto.agreement.SM2KeyExchange; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.params.ParametersWithID; +import org.bouncycastle.crypto.params.SM2KeyExchangePrivateParameters; +import org.bouncycastle.crypto.params.SM2KeyExchangePublicParameters; +import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi; +import org.bouncycastle.jcajce.spec.SM2KeyExchangeSpec; +import org.bouncycastle.util.Arrays; + + +public class GMKeyExchangeSpi + extends BaseAgreementSpi +{ + private final String kaAlgorithm; + private final SM2KeyExchange engine; + private SM2KeyExchangeSpec spec; + private byte[] result; + + protected GMKeyExchangeSpi(String kaAlgorithm) + { + super(kaAlgorithm, null); + + this.kaAlgorithm = kaAlgorithm; + this.engine = new SM2KeyExchange(); + } + + protected Key engineDoPhase( + Key key, + boolean lastPhase) + throws InvalidKeyException, IllegalStateException + { + if (spec == null) + { + throw new IllegalStateException(kaAlgorithm + " not initialised."); + } + + if (!lastPhase) + { + throw new IllegalStateException(kaAlgorithm + " can only be between two parties."); + } + + if (!(key instanceof BCECPublicKey)) + { + throw new InvalidKeyException(kaAlgorithm + " key agreement requires " + + getSimpleName(BCECPublicKey.class) + " for doPhase"); + } + ECPublicKeyParameters staticKey = (ECPublicKeyParameters)ECUtils.generatePublicKeyParameter((PublicKey)key); + ECPublicKeyParameters ephemeralKey = (ECPublicKeyParameters)ECUtils.generatePublicKeyParameter(spec.getOtherPartyEphemeralKey()); + + ParametersWithID parameters = new ParametersWithID(new SM2KeyExchangePublicParameters(staticKey, ephemeralKey), + spec.getOtherPartyId()); + + result = engine.calculateKey(128, parameters); + + return null; + } + + protected void doInitFromKey(Key key, AlgorithmParameterSpec parameterSpec, SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + if (parameterSpec != null && !(parameterSpec instanceof SM2KeyExchangeSpec)) + { + throw new InvalidAlgorithmParameterException("No algorithm parameters supported"); + } + + if (!(key instanceof PrivateKey)) + { + throw new InvalidKeyException(kaAlgorithm + " key agreement requires " + + getSimpleName(BCECPrivateKey.class) + " for initialisation"); + } + spec = (SM2KeyExchangeSpec)parameterSpec; + + ECPrivateKeyParameters staticKey = (ECPrivateKeyParameters)ECUtils.generatePrivateKeyParameter((PrivateKey)key); + ECPrivateKeyParameters ephemeralKey = (ECPrivateKeyParameters)ECUtils.generatePrivateKeyParameter(spec.getEphemeralPrivateKey()); + ParametersWithID parameters = new ParametersWithID(new SM2KeyExchangePrivateParameters(spec.isInitiator(), staticKey, ephemeralKey), spec.getId()); + engine.init(parameters); + } + + private static String getSimpleName(Class clazz) + { + String fullName = clazz.getName(); + + return fullName.substring(fullName.lastIndexOf('.') + 1); + } + + protected byte[] doCalcSecret() + { + return Arrays.clone(result); + } + + public static class SM2 + extends GMKeyExchangeSpi + { + public SM2() + { + super("SM2"); + } + } +} diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/GMKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/GMKeyPairGeneratorSpi.java index e1d509a186..28daab22a7 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/GMKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/GMKeyPairGeneratorSpi.java @@ -48,7 +48,7 @@ public static class BaseSM2 String algorithm; ProviderConfiguration configuration; - static private Hashtable ecParameters; + private static final Hashtable ecParameters; static { diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java index 7f729ffa74..c85218a4d9 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java @@ -48,7 +48,7 @@ public static class EC String algorithm; ProviderConfiguration configuration; - static private Hashtable ecParameters; + private static final Hashtable ecParameters; static { diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPrivateKey.java index 8444dea21c..a6f6875e48 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPrivateKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPrivateKey.java @@ -15,13 +15,14 @@ import org.bouncycastle.crypto.params.Ed448PublicKeyParameters; import org.bouncycastle.crypto.util.PrivateKeyInfoFactory; import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers; +import org.bouncycastle.jcajce.interfaces.BCKey; import org.bouncycastle.jcajce.interfaces.EdDSAPrivateKey; import org.bouncycastle.jcajce.interfaces.EdDSAPublicKey; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Properties; public class BCEdDSAPrivateKey - implements EdDSAPrivateKey + implements EdDSAPrivateKey, BCKey { static final long serialVersionUID = 1L; diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPublicKey.java index dc19a4a000..03ba020ebe 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPublicKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPublicKey.java @@ -11,12 +11,13 @@ import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; import org.bouncycastle.crypto.params.Ed448PublicKeyParameters; import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers; +import org.bouncycastle.jcajce.interfaces.BCKey; import org.bouncycastle.jcajce.interfaces.EdDSAPublicKey; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Properties; public class BCEdDSAPublicKey - implements EdDSAPublicKey + implements EdDSAPublicKey, BCKey { static final long serialVersionUID = 1L; diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/Utils.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/Utils.java index 7121b79839..ebc995b50f 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/Utils.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/Utils.java @@ -30,7 +30,7 @@ static boolean isValidPrefix(byte[] prefix, byte[] encoding) static String keyToString(String label, String algorithm, AsymmetricKeyParameter pubKey) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); byte[] keyBytes; diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/gost/GOSTUtil.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/gost/GOSTUtil.java index 772f25368e..fd0b7e753b 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/gost/GOSTUtil.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/gost/GOSTUtil.java @@ -11,7 +11,7 @@ class GOSTUtil { static String privateKeyToString(String algorithm, BigInteger x, GOST3410Parameters gostParams) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); BigInteger y = gostParams.getA().modPow(x, gostParams.getP()); @@ -25,7 +25,7 @@ static String privateKeyToString(String algorithm, BigInteger x, GOST3410Paramet static String publicKeyToString(String algorithm, BigInteger y, GOST3410Parameters gostParams) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append(algorithm); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java index ebbc2345f2..92a6864afd 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java @@ -59,13 +59,13 @@ protected byte[] engineGetEncoded() { v.add(new DERTaggedObject(false, 1, new DEROctetString(currentSpec.getEncodingV()))); } - v.add(new ASN1Integer(currentSpec.getMacKeySize())); + v.add(ASN1Integer.valueOf(currentSpec.getMacKeySize())); byte[] currentSpecNonce = currentSpec.getNonce(); if (currentSpecNonce != null) { ASN1EncodableVector cV = new ASN1EncodableVector(); - cV.add(new ASN1Integer(currentSpec.getCipherKeySize())); + cV.add(ASN1Integer.valueOf(currentSpec.getCipherKeySize())); cV.add(new DEROctetString(currentSpecNonce)); v.add(new DERSequence(cV)); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/BCMLDSAPrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/BCMLDSAPrivateKey.java index 4cc33e8b14..9f9cd2a6ca 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/BCMLDSAPrivateKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/BCMLDSAPrivateKey.java @@ -6,6 +6,7 @@ import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.jcajce.interfaces.BCKey; import org.bouncycastle.jcajce.interfaces.MLDSAPrivateKey; import org.bouncycastle.jcajce.interfaces.MLDSAPublicKey; import org.bouncycastle.jcajce.spec.MLDSAParameterSpec; @@ -19,7 +20,7 @@ import org.bouncycastle.util.encoders.Hex; public class BCMLDSAPrivateKey - implements MLDSAPrivateKey + implements MLDSAPrivateKey, BCKey { private static final long serialVersionUID = 1L; @@ -44,6 +45,7 @@ public BCMLDSAPrivateKey(PrivateKeyInfo keyInfo) private void init(PrivateKeyInfo keyInfo) throws IOException { + this.encoding = keyInfo.getEncoded(); init((MLDSAPrivateKeyParameters)PrivateKeyFactory.createKey(keyInfo), keyInfo.getAttributes()); } @@ -90,6 +92,20 @@ public final String getAlgorithm() return algorithm; } + public MLDSAPrivateKey getPrivateKey(boolean preferSeedOnly) + { + if (preferSeedOnly) + { + byte[] seed = params.getSeed(); + if (seed != null) + { + return new BCMLDSAPrivateKey(this.params.getParametersWithFormat(MLDSAPrivateKeyParameters.SEED_ONLY)); + } + } + + return new BCMLDSAPrivateKey(this.params.getParametersWithFormat(MLDSAPrivateKeyParameters.EXPANDED_KEY)); + } + public byte[] getEncoded() { if (encoding == null) diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/BCMLDSAPublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/BCMLDSAPublicKey.java index 8a88864d35..d0753cdd1d 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/BCMLDSAPublicKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/BCMLDSAPublicKey.java @@ -5,6 +5,7 @@ import java.io.ObjectOutputStream; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.jcajce.interfaces.BCKey; import org.bouncycastle.jcajce.interfaces.MLDSAPublicKey; import org.bouncycastle.jcajce.spec.MLDSAParameterSpec; import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters; @@ -16,7 +17,7 @@ import org.bouncycastle.util.encoders.Hex; public class BCMLDSAPublicKey - implements MLDSAPublicKey + implements MLDSAPublicKey, BCKey { private static final long serialVersionUID = 1L; diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/MLDSAKeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/MLDSAKeyFactorySpi.java index 3a2ba11de0..9256293d6e 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/MLDSAKeyFactorySpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/MLDSAKeyFactorySpi.java @@ -44,14 +44,22 @@ public class MLDSAKeyFactorySpi hashKeyOids.add(NISTObjectIdentifiers.id_hash_ml_dsa_87_with_sha512); } + private final boolean isHashOnly; + public MLDSAKeyFactorySpi(Set keyOids) { super(keyOids); + + this.isHashOnly = false; } public MLDSAKeyFactorySpi(ASN1ObjectIdentifier keyOid) { super(keyOid); + + this.isHashOnly = (keyOid.equals(NISTObjectIdentifiers.id_hash_ml_dsa_44_with_sha512) + || keyOid.equals(NISTObjectIdentifiers.id_hash_ml_dsa_65_with_sha512) + || keyOid.equals(NISTObjectIdentifiers.id_hash_ml_dsa_87_with_sha512)); } public final KeySpec engineGetKeySpec(Key key, Class keySpec) @@ -165,7 +173,37 @@ public PublicKey engineGeneratePublic( public PrivateKey generatePrivate(PrivateKeyInfo keyInfo) throws IOException { - return new BCMLDSAPrivateKey(keyInfo); + BCMLDSAPrivateKey key = new BCMLDSAPrivateKey(keyInfo); + + if (!isHashOnly || (key.getAlgorithm().indexOf("WITH") > 0)) + { + return key; + } + + // keyfactory for hash-only, convert key to hash-only. + MLDSAPrivateKeyParameters kParams = key.getKeyParams(); + MLDSAParameters mldsaParameters = null; + if (kParams.getParameters().equals(MLDSAParameters.ml_dsa_44)) + { + mldsaParameters = MLDSAParameters.ml_dsa_44_with_sha512; + } + else if (kParams.getParameters().equals(MLDSAParameters.ml_dsa_65)) + { + mldsaParameters = MLDSAParameters.ml_dsa_65_with_sha512; + } + else if (kParams.getParameters().equals(MLDSAParameters.ml_dsa_87)) + { + mldsaParameters = MLDSAParameters.ml_dsa_87_with_sha512; + } + else + { + throw new IllegalStateException("unknown ML-DSA parameters"); + } + + MLDSAPrivateKeyParameters hkParams = new MLDSAPrivateKeyParameters( + mldsaParameters, kParams.getRho(), kParams.getK(), kParams.getTr(), kParams.getS1(), kParams.getS2(), kParams.getT0(), kParams.getT1(), kParams.getSeed()); + + return new BCMLDSAPrivateKey(hkParams); } public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo) diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/MLDSAKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/MLDSAKeyPairGeneratorSpi.java index ce58857e60..de381cc2f3 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/MLDSAKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/MLDSAKeyPairGeneratorSpi.java @@ -10,12 +10,12 @@ import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.jcajce.spec.MLDSAParameterSpec; import org.bouncycastle.jcajce.util.BCJcaJceHelper; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.mldsa.MLDSAKeyGenerationParameters; import org.bouncycastle.pqc.crypto.mldsa.MLDSAKeyPairGenerator; import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters; import org.bouncycastle.pqc.crypto.mldsa.MLDSAPrivateKeyParameters; import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.util.Strings; public class MLDSAKeyPairGeneratorSpi diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/SignatureSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/SignatureSpi.java index 3ddc0cfdba..6aa43ce26f 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/SignatureSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mldsa/SignatureSpi.java @@ -1,5 +1,7 @@ package org.bouncycastle.jcajce.provider.asymmetric.mldsa; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; @@ -7,17 +9,23 @@ import java.security.SecureRandom; import java.security.SignatureException; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.DataLengthException; +import org.bouncycastle.jcajce.MLDSAProxyPrivateKey; +import org.bouncycastle.jcajce.interfaces.MLDSAPublicKey; import org.bouncycastle.jcajce.provider.asymmetric.util.BaseDeterministicOrRandomSignature; import org.bouncycastle.jcajce.spec.MLDSAParameterSpec; import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters; +import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters; import org.bouncycastle.pqc.crypto.mldsa.MLDSASigner; +import org.bouncycastle.pqc.crypto.util.PublicKeyFactory; public class SignatureSpi extends BaseDeterministicOrRandomSignature { - private MLDSASigner signer; - private MLDSAParameters parameters; + protected MLDSASigner signer; + protected MLDSAParameters parameters; protected SignatureSpi(MLDSASigner signer) { @@ -43,19 +51,28 @@ protected void verifyInit(PublicKey publicKey) BCMLDSAPublicKey key = (BCMLDSAPublicKey)publicKey; this.keyParams = key.getKeyParams(); - - if (parameters != null) + } + else + { + try { - String canonicalAlg = MLDSAParameterSpec.fromName(parameters.getName()).getName(); - if (!canonicalAlg.equals(key.getAlgorithm())) - { - throw new InvalidKeyException("signature configured for " + canonicalAlg); - } + SubjectPublicKeyInfo pubKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()); + this.keyParams = org.bouncycastle.pqc.crypto.util.PublicKeyFactory.createKey(pubKeyInfo); + publicKey = new BCMLDSAPublicKey((MLDSAPublicKeyParameters)this.keyParams); + } + catch (Exception e) + { + throw new InvalidKeyException("unknown public key passed to ML-DSA"); } } - else + + if (parameters != null) { - throw new InvalidKeyException("unknown public key passed to ML-DSA"); + String canonicalAlg = MLDSAParameterSpec.fromName(parameters.getName()).getName(); + if (!canonicalAlg.equals(publicKey.getAlgorithm())) + { + throw new InvalidKeyException("signature configured for " + canonicalAlg); + } } } @@ -78,6 +95,29 @@ protected void signInit(PrivateKey privateKey, SecureRandom random) } } } + else if (privateKey instanceof MLDSAProxyPrivateKey && this instanceof MLDSACalcMu) + { + MLDSAProxyPrivateKey pKey = (MLDSAProxyPrivateKey)privateKey; + MLDSAPublicKey key = pKey.getPublicKey(); + + try + { + this.keyParams = PublicKeyFactory.createKey(key.getEncoded()); + } + catch (IOException e) + { + throw new InvalidKeyException(e.getMessage()); + } + + if (parameters != null) + { + String canonicalAlg = MLDSAParameterSpec.fromName(parameters.getName()).getName(); + if (!canonicalAlg.equals(key.getAlgorithm())) + { + throw new InvalidKeyException("signature configured for " + canonicalAlg); + } + } + } else { throw new InvalidKeyException("unknown private key passed to ML-DSA"); @@ -121,7 +161,7 @@ protected void reInitialize(boolean forSigning, CipherParameters params) } public static class MLDSA - extends SignatureSpi + extends SignatureSpi { public MLDSA() { @@ -130,7 +170,7 @@ public MLDSA() } public static class MLDSA44 - extends SignatureSpi + extends SignatureSpi { public MLDSA44() { @@ -139,7 +179,7 @@ public MLDSA44() } public static class MLDSA65 - extends SignatureSpi + extends SignatureSpi { public MLDSA65() { @@ -148,12 +188,101 @@ public MLDSA65() } public static class MLDSA87 - extends SignatureSpi + extends SignatureSpi { public MLDSA87() - throws NoSuchAlgorithmException + throws NoSuchAlgorithmException { super(new MLDSASigner(), MLDSAParameters.ml_dsa_87); } } + + public static class MLDSAExtMu + extends SignatureSpi + { + private ByteArrayOutputStream bOut = new ByteArrayOutputStream(64); + + public MLDSAExtMu() + { + super(new MLDSASigner()); + } + + protected void updateEngine(byte b) + throws SignatureException + { + bOut.write(b); + } + + protected void updateEngine(byte[] b, int off, int len) + throws SignatureException + { + bOut.write(b, off, len); + } + + protected byte[] engineSign() + throws SignatureException + { + try + { + byte[] mu = bOut.toByteArray(); + + bOut.reset(); + + return signer.generateMuSignature(mu); + } + catch (DataLengthException e) + { + throw new SignatureException(e.getMessage()); + } + catch (Exception e) + { + throw new SignatureException(e.toString()); + } + } + + protected boolean engineVerify(byte[] sigBytes) + throws SignatureException + { + byte[] mu = bOut.toByteArray(); + + bOut.reset(); + + try + { + return signer.verifyMuSignature(mu, sigBytes); + } + catch (DataLengthException e) + { + throw new SignatureException(e.getMessage()); + } + } + } + + public static class MLDSACalcMu + extends SignatureSpi + { + public MLDSACalcMu() + { + super(new MLDSASigner()); + } + + protected byte[] engineSign() + throws SignatureException + { + try + { + return signer.generateMu(); + } + catch (Exception e) + { + throw new SignatureException(e.toString()); + } + } + + protected boolean engineVerify(byte[] sigBytes) + throws SignatureException + { + return signer.verifyMu(sigBytes); + } + } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/BCMLKEMPrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/BCMLKEMPrivateKey.java index 012e08b7cf..9df1acc9fd 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/BCMLKEMPrivateKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/BCMLKEMPrivateKey.java @@ -6,9 +6,11 @@ import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.jcajce.interfaces.BCKey; import org.bouncycastle.jcajce.interfaces.MLKEMPrivateKey; import org.bouncycastle.jcajce.interfaces.MLKEMPublicKey; import org.bouncycastle.jcajce.spec.MLKEMParameterSpec; +import org.bouncycastle.pqc.crypto.mldsa.MLDSAPrivateKeyParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMPrivateKeyParameters; import org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; import org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory; @@ -18,13 +20,14 @@ import org.bouncycastle.util.encoders.Hex; public class BCMLKEMPrivateKey - implements MLKEMPrivateKey + implements MLKEMPrivateKey, BCKey { private static final long serialVersionUID = 1L; private transient MLKEMPrivateKeyParameters params; private transient String algorithm; private transient ASN1Set attributes; + private transient byte[] priorEncoding; public BCMLKEMPrivateKey( MLKEMPrivateKeyParameters params) @@ -42,7 +45,8 @@ public BCMLKEMPrivateKey(PrivateKeyInfo keyInfo) private void init(PrivateKeyInfo keyInfo) throws IOException { - this.attributes = keyInfo.getAttributes();; + this.attributes = keyInfo.getAttributes(); + this.priorEncoding = keyInfo.getEncoded(); this.params = (MLKEMPrivateKeyParameters)PrivateKeyFactory.createKey(keyInfo); this.algorithm = Strings.toUpperCase(MLKEMParameterSpec.fromName(params.getParameters().getName()).getName()); } @@ -87,6 +91,10 @@ public byte[] getEncoded() { try { + if (priorEncoding != null) + { + return priorEncoding; + } PrivateKeyInfo pki = PrivateKeyInfoFactory.createPrivateKeyInfo(params, attributes); return pki.getEncoded(); @@ -114,6 +122,21 @@ public byte[] getSeed() return params.getSeed(); } + @Override + public MLKEMPrivateKey getPrivateKey(boolean preferSeedOnly) + { + if (preferSeedOnly) + { + byte[] seed = params.getSeed(); + if (seed != null) + { + return new BCMLKEMPrivateKey(this.params.withPreferredFormat(MLDSAPrivateKeyParameters.SEED_ONLY)); + } + } + + return new BCMLKEMPrivateKey(this.params.withPreferredFormat(MLDSAPrivateKeyParameters.EXPANDED_KEY)); + } + public MLKEMParameterSpec getParameterSpec() { return MLKEMParameterSpec.fromName(params.getParameters().getName()); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/BCMLKEMPublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/BCMLKEMPublicKey.java index 97f877301b..89615a5d5d 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/BCMLKEMPublicKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/BCMLKEMPublicKey.java @@ -5,6 +5,7 @@ import java.io.ObjectOutputStream; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.jcajce.interfaces.BCKey; import org.bouncycastle.jcajce.interfaces.MLKEMPublicKey; import org.bouncycastle.jcajce.spec.MLKEMParameterSpec; import org.bouncycastle.pqc.crypto.mlkem.MLKEMPublicKeyParameters; @@ -16,7 +17,7 @@ import org.bouncycastle.util.encoders.Hex; public class BCMLKEMPublicKey - implements MLKEMPublicKey + implements MLKEMPublicKey, BCKey { private static final long serialVersionUID = 1L; diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMCipherSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMCipherSpi.java index 036248b738..52c2794c70 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMCipherSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMCipherSpi.java @@ -23,7 +23,6 @@ import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.SecretWithEncapsulation; import org.bouncycastle.crypto.Wrapper; -import org.bouncycastle.jcajce.spec.KEMParameterSpec; import org.bouncycastle.jcajce.spec.KTSParameterSpec; import org.bouncycastle.jcajce.spec.MLKEMParameterSpec; import org.bouncycastle.pqc.crypto.mlkem.MLKEMExtractor; @@ -33,46 +32,46 @@ import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Exceptions; -class MLKEMCipherSpi +public class MLKEMCipherSpi extends CipherSpi { + private final MLKEMParameters mlkemParameters; private final String algorithmName; + private MLKEMGenerator kemGen; private KTSParameterSpec kemParameterSpec; private BCMLKEMPublicKey wrapKey; private BCMLKEMPrivateKey unwrapKey; private AlgorithmParameters engineParams; - private MLKEMParameters mlkemParamters; - MLKEMCipherSpi(String algorithmName) + public MLKEMCipherSpi(String algorithmName) { + this.mlkemParameters = null; this.algorithmName = algorithmName; - this.mlkemParamters = null; } - MLKEMCipherSpi(MLKEMParameters kyberParameters) + public MLKEMCipherSpi(MLKEMParameters mlkemParameters) { - this.mlkemParamters = kyberParameters; - this.algorithmName = kyberParameters.getName(); + this.mlkemParameters = mlkemParameters; + this.algorithmName = mlkemParameters.getName(); } @Override protected void engineSetMode(String mode) - throws NoSuchAlgorithmException + throws NoSuchAlgorithmException { throw new NoSuchAlgorithmException("Cannot support mode " + mode); } @Override protected void engineSetPadding(String padding) - throws NoSuchPaddingException + throws NoSuchPaddingException { throw new NoSuchPaddingException("Padding " + padding + " unknown"); } - protected int engineGetKeySize( - Key key) + protected int engineGetKeySize(Key key) { return 2048; // TODO //throw new IllegalArgumentException("not an valid key!"); @@ -137,7 +136,7 @@ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec paramSpec, if (paramSpec == null) { // TODO: default should probably use shake. - kemParameterSpec = new KEMParameterSpec("AES-KWP"); + kemParameterSpec = new KTSParameterSpec.Builder("AES-KWP", 256).build(); } else { @@ -154,7 +153,7 @@ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec paramSpec, if (key instanceof BCMLKEMPublicKey) { wrapKey = (BCMLKEMPublicKey)key; - kemGen = new MLKEMGenerator(CryptoServicesRegistrar.getSecureRandom(random)); + kemGen = new MLKEMGenerator(random); } else { @@ -177,9 +176,9 @@ else if (opmode == Cipher.UNWRAP_MODE) throw new InvalidParameterException("Cipher only valid for wrapping/unwrapping"); } - if (mlkemParamters != null) + if (mlkemParameters != null) { - String canonicalAlgName = MLKEMParameterSpec.fromName(mlkemParamters.getName()).getName(); + String canonicalAlgName = MLKEMParameterSpec.fromName(mlkemParameters.getName()).getName(); if (!canonicalAlgName.equals(key.getAlgorithm())) { throw new InvalidKeyException("cipher locked to " + canonicalAlgName); @@ -197,7 +196,7 @@ protected void engineInit(int opmode, Key key, AlgorithmParameters algorithmPara { try { - paramSpec = algorithmParameters.getParameterSpec(KEMParameterSpec.class); + paramSpec = algorithmParameters.getParameterSpec(KTSParameterSpec.class); } catch (Exception e) { @@ -235,6 +234,7 @@ protected int engineDoFinal(byte[] bytes, int i, int i1, byte[] bytes1, int i2) throw new IllegalStateException("Not supported in a wrapping mode"); } + @SuppressWarnings("Finally") protected byte[] engineWrap( Key key) throws IllegalBlockSizeException, InvalidKeyException @@ -256,11 +256,14 @@ protected byte[] engineWrap( byte[] keyToWrap = key.getEncoded(); - byte[] rv = Arrays.concatenate(encapsulation, kWrap.wrap(keyToWrap, 0, keyToWrap.length)); - - Arrays.clear(keyToWrap); - - return rv; + try + { + return Arrays.concatenate(encapsulation, kWrap.wrap(keyToWrap, 0, keyToWrap.length)); + } + finally + { + Arrays.clear(keyToWrap); + } } catch (IllegalArgumentException e) { @@ -277,7 +280,7 @@ protected byte[] engineWrap( } catch (DestroyFailedException e) { - throw new IllegalBlockSizeException("unable to destroy interim values: " + e.getMessage()); + // ignore } } } @@ -293,6 +296,7 @@ protected Key engineUnwrap( { throw new InvalidKeyException("only SECRET_KEY supported"); } + byte[] secret = null; try { @@ -318,18 +322,14 @@ protected Key engineUnwrap( } finally { - if (secret != null) - { - Arrays.clear(secret); - } + Arrays.clear(secret); } } public static class Base - extends MLKEMCipherSpi + extends MLKEMCipherSpi { public Base() - throws NoSuchAlgorithmException { super("MLKEM"); } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMKeyGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMKeyGeneratorSpi.java index eb3a50c1ca..76dc03bd5d 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMKeyGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMKeyGeneratorSpi.java @@ -21,21 +21,22 @@ import org.bouncycastle.util.Arrays; public class MLKEMKeyGeneratorSpi - extends KeyGeneratorSpi + extends KeyGeneratorSpi { + private final MLKEMParameters mlkemParameters; + private KEMGenerateSpec genSpec; private SecureRandom random; private KEMExtractSpec extSpec; - private MLKEMParameters kyberParameters; public MLKEMKeyGeneratorSpi() { this(null); } - protected MLKEMKeyGeneratorSpi(MLKEMParameters kyberParameters) + protected MLKEMKeyGeneratorSpi(MLKEMParameters mlkemParameters) { - this.kyberParameters = kyberParameters; + this.mlkemParameters = mlkemParameters; } protected void engineInit(SecureRandom secureRandom) @@ -51,9 +52,9 @@ protected void engineInit(AlgorithmParameterSpec algorithmParameterSpec, SecureR { this.genSpec = (KEMGenerateSpec)algorithmParameterSpec; this.extSpec = null; - if (kyberParameters != null) + if (mlkemParameters != null) { - String canonicalAlgName = MLKEMParameterSpec.fromName(kyberParameters.getName()).getName(); + String canonicalAlgName = MLKEMParameterSpec.fromName(mlkemParameters.getName()).getName(); if (!canonicalAlgName.equals(genSpec.getPublicKey().getAlgorithm())) { throw new InvalidAlgorithmParameterException("key generator locked to " + canonicalAlgName); @@ -64,9 +65,9 @@ else if (algorithmParameterSpec instanceof KEMExtractSpec) { this.genSpec = null; this.extSpec = (KEMExtractSpec)algorithmParameterSpec; - if (kyberParameters != null) + if (mlkemParameters != null) { - String canonicalAlgName = MLKEMParameterSpec.fromName(kyberParameters.getName()).getName(); + String canonicalAlgName = MLKEMParameterSpec.fromName(mlkemParameters.getName()).getName(); if (!canonicalAlgName.equals(extSpec.getPrivateKey().getAlgorithm())) { throw new InvalidAlgorithmParameterException("key generator locked to " + canonicalAlgName); @@ -93,24 +94,26 @@ protected SecretKey engineGenerateKey() SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(pubKey.getKeyParams()); - byte[] sharedSecret = secEnc.getSecret(); - - byte[] secret = KdfUtil.makeKeyBytes(genSpec, sharedSecret); - - Arrays.clear(sharedSecret); - - SecretKey rv = new SecretKeyWithEncapsulation(new SecretKeySpec(secret, genSpec.getKeyAlgorithmName()), secEnc.getEncapsulation()); + byte[] kemSecret = secEnc.getSecret(); + byte[] kdfSecret = KdfUtil.makeKeyBytes(genSpec, kemSecret); try { - secEnc.destroy(); + SecretKeySpec secretKey = new SecretKeySpec(kdfSecret, genSpec.getKeyAlgorithmName()); + + return new SecretKeyWithEncapsulation(secretKey, secEnc.getEncapsulation()); } - catch (DestroyFailedException e) + finally { - throw new IllegalStateException("key cleanup failed"); + try + { + secEnc.destroy(); + } + catch (DestroyFailedException e) + { + // ignore + } } - - return rv; } else { @@ -118,16 +121,21 @@ protected SecretKey engineGenerateKey() MLKEMExtractor kemExt = new MLKEMExtractor(privKey.getKeyParams()); byte[] encapsulation = extSpec.getEncapsulation(); - byte[] sharedSecret = kemExt.extractSecret(encapsulation); - byte[] secret = KdfUtil.makeKeyBytes(extSpec, sharedSecret); - - Arrays.clear(sharedSecret); - SecretKey rv = new SecretKeyWithEncapsulation(new SecretKeySpec(secret, extSpec.getKeyAlgorithmName()), encapsulation); + byte[] kemSecret = kemExt.extractSecret(encapsulation); + byte[] kdfSecret = KdfUtil.makeKeyBytes(extSpec, kemSecret); - Arrays.clear(secret); + try + { + SecretKeySpec secretKey = new SecretKeySpec(kdfSecret, extSpec.getKeyAlgorithmName()); - return rv; + // TODO Why do we return ...WithEncapsulation?? + return new SecretKeyWithEncapsulation(secretKey, encapsulation); + } + finally + { + Arrays.clear(kdfSecret); + } } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMKeyPairGeneratorSpi.java index 3393ac3489..a85f2a6ec9 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMKeyPairGeneratorSpi.java @@ -10,12 +10,12 @@ import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.jcajce.spec.MLKEMParameterSpec; import org.bouncycastle.jcajce.util.BCJcaJceHelper; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.mlkem.MLKEMKeyGenerationParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMKeyPairGenerator; import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMPrivateKeyParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMPublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.util.Strings; public class MLKEMKeyPairGeneratorSpi @@ -75,8 +75,6 @@ public void initialize( { String name = getNameFromParams(params); - MLKEMParameters kyberParams = Utils.getParameters(name); - if (name != null) { MLKEMParameters mlkemParams = Utils.getParameters(name); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java index baa4ed94be..3696fc840f 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java @@ -194,7 +194,8 @@ protected byte[] engineGetEncoded() AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier( PKCSObjectIdentifiers.id_mgf1, new AlgorithmIdentifier(DigestFactory.getOID(mgfSpec.getDigestAlgorithm()), DERNull.INSTANCE)); - RSASSAPSSparams pssP = new RSASSAPSSparams(hashAlgorithm, maskGenAlgorithm, new ASN1Integer(pssSpec.getSaltLength()), new ASN1Integer(pssSpec.getTrailerField())); + RSASSAPSSparams pssP = new RSASSAPSSparams(hashAlgorithm, maskGenAlgorithm, + ASN1Integer.valueOf(pssSpec.getSaltLength()), ASN1Integer.valueOf(pssSpec.getTrailerField())); return pssP.getEncoded("DER"); } @@ -202,7 +203,8 @@ protected byte[] engineGetEncoded() { AlgorithmIdentifier maskGenAlgorithm = new AlgorithmIdentifier( pssSpec.getMGFAlgorithm().equals("SHAKE128") ? NISTObjectIdentifiers.id_shake128 : NISTObjectIdentifiers.id_shake256); - RSASSAPSSparams pssP = new RSASSAPSSparams(hashAlgorithm, maskGenAlgorithm, new ASN1Integer(pssSpec.getSaltLength()), new ASN1Integer(pssSpec.getTrailerField())); + RSASSAPSSparams pssP = new RSASSAPSSparams(hashAlgorithm, maskGenAlgorithm, + ASN1Integer.valueOf(pssSpec.getSaltLength()), ASN1Integer.valueOf(pssSpec.getTrailerField())); return pssP.getEncoded("DER"); } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java index 477c3f35ca..748677a3b2 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java @@ -278,7 +278,7 @@ private void writeObject( public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append("RSA Private CRT Key [").append( diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java index 215945d3eb..0148644100 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java @@ -13,13 +13,14 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.jcajce.interfaces.BCKey; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; import org.bouncycastle.util.Strings; public class BCRSAPrivateKey - implements RSAPrivateKey, PKCS12BagAttributeCarrier + implements RSAPrivateKey, PKCS12BagAttributeCarrier, BCKey { static final long serialVersionUID = 5110188922551353628L; @@ -189,7 +190,7 @@ private void writeObject( public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append("RSA Private Key [").append( diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java index 2d7e11b56c..d32b9b4269 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java @@ -12,11 +12,12 @@ import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.jcajce.interfaces.BCKey; import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; import org.bouncycastle.util.Strings; public class BCRSAPublicKey - implements RSAPublicKey + implements RSAPublicKey, BCKey { static final AlgorithmIdentifier DEFAULT_ALGORITHM_IDENTIFIER = new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE); @@ -154,7 +155,7 @@ public boolean equals(Object o) public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append("RSA Public Key [").append(RSAUtil.generateKeyFingerprint(this.getModulus())).append("]") diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java index 0046767e3e..51e15d4106 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java @@ -32,6 +32,7 @@ import org.bouncycastle.crypto.engines.RSABlindedEngine; import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers; +import org.bouncycastle.jcajce.util.AnnotatedPrivateKey; import org.bouncycastle.util.Arrays; public class DigestSignatureSpi @@ -81,6 +82,11 @@ protected void engineInitSign( PrivateKey privateKey) throws InvalidKeyException { + if (privateKey instanceof AnnotatedPrivateKey) + { + privateKey = ((AnnotatedPrivateKey)privateKey).getKey(); + } + if (!(privateKey instanceof RSAPrivateKey)) { throw new InvalidKeyException("Supplied key (" + getType(privateKey) + ") is not a RSAPrivateKey instance"); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/BCSLHDSAPrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/BCSLHDSAPrivateKey.java index a0cc8ca28e..f3be261114 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/BCSLHDSAPrivateKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/BCSLHDSAPrivateKey.java @@ -6,6 +6,7 @@ import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.jcajce.interfaces.BCKey; import org.bouncycastle.jcajce.interfaces.SLHDSAPrivateKey; import org.bouncycastle.jcajce.interfaces.SLHDSAPublicKey; import org.bouncycastle.jcajce.spec.SLHDSAParameterSpec; @@ -19,7 +20,7 @@ import org.bouncycastle.util.encoders.Hex; public class BCSLHDSAPrivateKey - implements SLHDSAPrivateKey + implements SLHDSAPrivateKey, BCKey { private static final long serialVersionUID = 1L; diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/BCSLHDSAPublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/BCSLHDSAPublicKey.java index 59ee6d8b86..ab6fb7daad 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/BCSLHDSAPublicKey.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/BCSLHDSAPublicKey.java @@ -5,6 +5,7 @@ import java.io.ObjectOutputStream; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.jcajce.interfaces.BCKey; import org.bouncycastle.jcajce.interfaces.SLHDSAPublicKey; import org.bouncycastle.jcajce.spec.SLHDSAParameterSpec; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPublicKeyParameters; @@ -16,7 +17,7 @@ import org.bouncycastle.util.encoders.Hex; public class BCSLHDSAPublicKey - implements SLHDSAPublicKey + implements SLHDSAPublicKey, BCKey { private static final long serialVersionUID = 1L; diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/HashSignatureSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/HashSignatureSpi.java index 0e6b42c197..65d71a74b2 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/HashSignatureSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/HashSignatureSpi.java @@ -118,7 +118,7 @@ protected void reInitialize(boolean forSigning, CipherParameters params) signer.init(forSigning, params); } - static public class Direct + public static class Direct extends HashSignatureSpi { public Direct() diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/SLHDSAKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/SLHDSAKeyPairGeneratorSpi.java index 338de9791c..b8261ba521 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/SLHDSAKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/SLHDSAKeyPairGeneratorSpi.java @@ -11,12 +11,12 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.jcajce.spec.SLHDSAParameterSpec; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAKeyGenerationParameters; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAKeyPairGenerator; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAParameters; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPrivateKeyParameters; import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.util.Strings; public class SLHDSAKeyPairGeneratorSpi diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/SignatureSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/SignatureSpi.java index 2a8ea4a538..b0d8cb3b87 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/SignatureSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/slhdsa/SignatureSpi.java @@ -123,8 +123,8 @@ protected void reInitialize(boolean forSigning, CipherParameters params) bOut.reset(); } - - static public class Direct + + public static class Direct extends SignatureSpi { public Direct() diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java index cd9699033d..08a8df9669 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java @@ -339,12 +339,8 @@ private byte[] getSharedSecretBytes(byte[] secret, String oidAlgorithm, int keyS { throw new NoSuchAlgorithmException("algorithm OID is null"); } - ASN1ObjectIdentifier oid; - try - { - oid = new ASN1ObjectIdentifier(oidAlgorithm); - } - catch (IllegalArgumentException e) + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.tryFromID(oidAlgorithm); + if (oid == null) { throw new NoSuchAlgorithmException("no OID for algorithm: " + oidAlgorithm); } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseDeterministicOrRandomSignature.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseDeterministicOrRandomSignature.java index cc3178676b..6a4f1bde90 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseDeterministicOrRandomSignature.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseDeterministicOrRandomSignature.java @@ -7,8 +7,8 @@ import java.security.ProviderException; import java.security.PublicKey; import java.security.SecureRandom; -import java.security.Signature; import java.security.SignatureException; +import java.security.SignatureSpi; import java.security.spec.AlgorithmParameterSpec; import org.bouncycastle.crypto.CipherParameters; @@ -18,10 +18,11 @@ import org.bouncycastle.jcajce.spec.ContextParameterSpec; import org.bouncycastle.jcajce.util.BCJcaJceHelper; import org.bouncycastle.jcajce.util.JcaJceHelper; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.util.Exceptions; public abstract class BaseDeterministicOrRandomSignature - extends Signature + extends SignatureSpi { private final JcaJceHelper helper = new BCJcaJceHelper(); private final AlgorithmParameterSpec originalSpec; @@ -34,7 +35,6 @@ public abstract class BaseDeterministicOrRandomSignature protected BaseDeterministicOrRandomSignature(String name) { - super(name); this.originalSpec = ContextParameterSpec.EMPTY_CONTEXT_SPEC; } @@ -123,7 +123,16 @@ protected void engineSetParameter( } else { - throw new InvalidAlgorithmParameterException("unknown AlgorithmParameterSpec in signature"); + byte[] context = SpecUtil.getContextFrom(params); + if (context != null) + { + this.paramSpec = new ContextParameterSpec(context); + reInit(); + } + else + { + throw new InvalidAlgorithmParameterException("unknown AlgorithmParameterSpec in signature"); + } } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java index 742fa14a50..dbf983881f 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java @@ -1,11 +1,8 @@ package org.bouncycastle.jcajce.provider.asymmetric.util; -import java.lang.reflect.Method; import java.math.BigInteger; -import java.security.AccessController; import java.security.InvalidKeyException; import java.security.PrivateKey; -import java.security.PrivilegedAction; import java.security.PublicKey; import java.security.spec.AlgorithmParameterSpec; import java.util.Enumeration; @@ -24,6 +21,7 @@ import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.jcajce.provider.config.ProviderConfiguration; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.jce.interfaces.ECPrivateKey; import org.bouncycastle.jce.interfaces.ECPublicKey; import org.bouncycastle.jce.provider.BouncyCastleProvider; @@ -332,7 +330,7 @@ public static ASN1ObjectIdentifier getNamedCurveOid( curveName = curveName.substring(spacePos + 1); } - ASN1ObjectIdentifier oid = getOID(curveName); + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.tryFromID(curveName); if (null != oid) { return oid; @@ -396,7 +394,7 @@ public static String getCurveName( public static String privateKeyToString(String algorithm, BigInteger d, org.bouncycastle.jce.spec.ECParameterSpec spec) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); org.bouncycastle.math.ec.ECPoint q = new FixedPointCombMultiplier().multiply(spec.getG(), d).normalize(); @@ -411,7 +409,7 @@ public static String privateKeyToString(String algorithm, BigInteger d, org.boun public static String publicKeyToString(String algorithm, org.bouncycastle.math.ec.ECPoint q, org.bouncycastle.jce.spec.ECParameterSpec spec) { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append(algorithm); @@ -437,39 +435,6 @@ public static String generateKeyFingerprint(ECPoint publicPoint, org.bouncycastl public static String getNameFrom(final AlgorithmParameterSpec paramSpec) { - return (String)AccessController.doPrivileged(new PrivilegedAction() - { - public Object run() - { - try - { - Method m = paramSpec.getClass().getMethod("getName"); - - return m.invoke(paramSpec); - } - catch (Exception e) - { - // ignore - maybe log? - } - - return null; - } - }); - } - - private static ASN1ObjectIdentifier getOID(String curveName) - { - char firstChar = curveName.charAt(0); - if (firstChar >= '0' && firstChar <= '2') - { - try - { - return new ASN1ObjectIdentifier(curveName); - } - catch (Exception e) - { - } - } - return null; + return SpecUtil.getNameFrom(paramSpec); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java index 1664a9cf87..6a091f78cf 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/PKIXCertPath.java @@ -290,7 +290,7 @@ else if (encoding.equalsIgnoreCase("PKCS7")) } SignedData sd = new SignedData( - new ASN1Integer(1), + ASN1Integer.ONE, new DERSet(), encInfo, new DERSet(v), diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java index e7e3a76a1c..26c2637d7d 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java @@ -15,6 +15,7 @@ import org.bouncycastle.asn1.ASN1Enumerated; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.util.ASN1Dump; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.CRLReason; @@ -78,9 +79,9 @@ protected X509CRLEntryObject( */ public boolean hasUnsupportedCriticalExtension() { - Set extns = getCriticalExtensionOIDs(); + Extensions extensions = c.getExtensions(); - return extns != null && !extns.isEmpty(); + return extensions != null && extensions.hasAnyCriticalExtensions(); } private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer) @@ -90,15 +91,15 @@ private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCert return null; } - Extension ext = getExtension(Extension.certificateIssuer); - if (ext == null) + ASN1OctetString extValue = Extensions.getExtensionValue(c.getExtensions(), Extension.certificateIssuer); + if (extValue == null) { return previousCertificateIssuer; } try { - GeneralName[] names = GeneralNames.getInstance(ext.getParsedValue()).getNames(); + GeneralName[] names = GeneralNames.getInstance(extValue.getOctets()).getNames(); for (int i = 0; i < names.length; i++) { if (names[i].getTagNo() == GeneralName.directoryName) @@ -166,35 +167,9 @@ public Set getNonCriticalExtensionOIDs() return getExtensionOIDs(false); } - private Extension getExtension(ASN1ObjectIdentifier oid) - { - Extensions exts = c.getExtensions(); - - if (exts != null) - { - return exts.getExtension(oid); - } - - return null; - } - public byte[] getExtensionValue(String oid) { - Extension ext = getExtension(new ASN1ObjectIdentifier(oid)); - - if (ext != null) - { - try - { - return ext.getExtnValue().getEncoded(); - } - catch (Exception e) - { - throw new IllegalStateException("Exception encoding: " + e.toString()); - } - } - - return null; + return X509SignatureUtil.getExtensionValue(c.getExtensions(), oid); } /** @@ -267,7 +242,7 @@ public boolean hasExtensions() public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append(" userCertificate: ").append(this.getSerialNumber()).append(nl); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java index 20f6972188..b90d101c57 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java @@ -54,7 +54,6 @@ import org.bouncycastle.jcajce.util.JcaJceHelper; import org.bouncycastle.jce.X509Principal; import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Exceptions; import org.bouncycastle.util.Strings; /** @@ -84,30 +83,41 @@ abstract class X509CRLImpl this.isIndirect = isIndirect; } - /** - * Will return true if any extensions are present and marked - * as critical as we currently dont handle any extensions! - */ public boolean hasUnsupportedCriticalExtension() { - Set extns = getCriticalExtensionOIDs(); - - if (extns == null) + if (getVersion() == 2) { - return false; - } + Extensions extensions = c.getExtensions(); + if (extensions != null) + { + Enumeration e = extensions.oids(); + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - extns.remove(Extension.issuingDistributionPoint.getId()); - extns.remove(Extension.deltaCRLIndicator.getId()); + if (Extension.issuingDistributionPoint.equals(oid) || + Extension.deltaCRLIndicator.equals(oid)) + { + continue; + } + + Extension ext = extensions.getExtension(oid); + if (ext.isCritical()) + { + return true; + } + } + } + } - return !extns.isEmpty(); + return false; } private Set getExtensionOIDs(boolean critical) { if (this.getVersion() == 2) { - Extensions extensions = c.getTBSCertList().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -144,26 +154,7 @@ public Set getNonCriticalExtensionOIDs() public byte[] getExtensionValue(String oid) { - if (oid != null) - { - ASN1ObjectIdentifier asn1Oid = ASN1ObjectIdentifier.tryFromID(oid); - if (asn1Oid != null) - { - ASN1OctetString extValue = getExtensionValue(c, asn1Oid); - if (null != extValue) - { - try - { - return extValue.getEncoded(); - } - catch (Exception e) - { - throw Exceptions.illegalStateException("error parsing " + e.getMessage(), e); - } - } - } - } - return null; + return X509SignatureUtil.getExtensionValue(c.getExtensions(), oid); } public void verify(PublicKey key) @@ -532,7 +523,7 @@ public byte[] getSigAlgParams() */ public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append(" Version: ").append(this.getVersion()).append( @@ -548,7 +539,7 @@ public String toString() X509SignatureUtil.prettyPrintSignature(this.getSignature(), buf, nl); - Extensions extensions = c.getTBSCertList().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -708,25 +699,8 @@ public boolean isRevoked(Certificate cert) static byte[] getExtensionOctets(CertificateList c, ASN1ObjectIdentifier oid) { - ASN1OctetString extValue = getExtensionValue(c, oid); - if (null != extValue) - { - return extValue.getOctets(); - } - return null; - } + ASN1OctetString extValue = Extensions.getExtensionValue(c.getExtensions(), oid); - static ASN1OctetString getExtensionValue(CertificateList c, ASN1ObjectIdentifier oid) - { - Extensions exts = c.getTBSCertList().getExtensions(); - if (null != exts) - { - Extension ext = exts.getExtension(oid); - if (null != ext) - { - return ext.getExtnValue(); - } - } - return null; + return extValue == null ? null : extValue.getOctets(); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java index 2665531c27..0f58d86b96 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java @@ -271,7 +271,7 @@ public boolean[] getKeyUsage() return Arrays.clone(keyUsage); } - public List getExtendedKeyUsage() + public List getExtendedKeyUsage() throws CertificateParsingException { byte[] extOctets = getExtensionOctets(c, Extension.extendedKeyUsage); @@ -330,7 +330,7 @@ public Set getCriticalExtensionOIDs() if (this.getVersion() == 3) { Set set = new HashSet(); - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -356,26 +356,7 @@ public Set getCriticalExtensionOIDs() public byte[] getExtensionValue(String oid) { - if (oid != null) - { - ASN1ObjectIdentifier asn1Oid = ASN1ObjectIdentifier.tryFromID(oid); - if (asn1Oid != null) - { - ASN1OctetString extValue = getExtensionValue(c, asn1Oid); - if (null != extValue) - { - try - { - return extValue.getEncoded(); - } - catch (Exception e) - { - throw Exceptions.illegalStateException("error parsing " + e.getMessage(), e); - } - } - } - } - return null; + return X509SignatureUtil.getExtensionValue(c.getExtensions(), oid); } public Set getNonCriticalExtensionOIDs() @@ -383,7 +364,7 @@ public Set getNonCriticalExtensionOIDs() if (this.getVersion() == 3) { Set set = new HashSet(); - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -409,35 +390,32 @@ public Set getNonCriticalExtensionOIDs() public boolean hasUnsupportedCriticalExtension() { - if (this.getVersion() == 3) + if (getVersion() == 3) { - Extensions extensions = c.getTBSCertificate().getExtensions(); - + Extensions extensions = c.getExtensions(); if (extensions != null) { - Enumeration e = extensions.oids(); - + Enumeration e = extensions.oids(); while (e.hasMoreElements()) { ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - if (oid.equals(Extension.keyUsage) - || oid.equals(Extension.certificatePolicies) - || oid.equals(Extension.policyMappings) - || oid.equals(Extension.inhibitAnyPolicy) - || oid.equals(Extension.cRLDistributionPoints) - || oid.equals(Extension.issuingDistributionPoint) - || oid.equals(Extension.deltaCRLIndicator) - || oid.equals(Extension.policyConstraints) - || oid.equals(Extension.basicConstraints) - || oid.equals(Extension.subjectAlternativeName) - || oid.equals(Extension.nameConstraints)) + if (Extension.keyUsage.equals(oid) || + Extension.certificatePolicies.equals(oid) || + Extension.policyMappings.equals(oid) || + Extension.inhibitAnyPolicy.equals(oid) || + Extension.cRLDistributionPoints.equals(oid) || + Extension.issuingDistributionPoint.equals(oid) || + Extension.deltaCRLIndicator.equals(oid) || + Extension.policyConstraints.equals(oid) || + Extension.basicConstraints.equals(oid) || + Extension.subjectAlternativeName.equals(oid) || + Extension.nameConstraints.equals(oid)) { continue; } - Extension ext = extensions.getExtension(oid); - + Extension ext = extensions.getExtension(oid); if (ext.isCritical()) { return true; @@ -463,7 +441,7 @@ public PublicKey getPublicKey() public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append(" [0] Version: ").append(this.getVersion()).append(nl); @@ -477,7 +455,7 @@ public String toString() X509SignatureUtil.prettyPrintSignature(this.getSignature(), buf, nl); - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -724,7 +702,7 @@ else if (X509SignatureUtil.isCompositeAlgorithm(c.getSignatureAlgorithm())) //Use this only for legacy composite public keys (they have this identifier) if (key instanceof CompositePublicKey - && MiscObjectIdentifiers.id_composite_key.equals(((CompositePublicKey)key).getAlgorithmIdentifier())) + && MiscObjectIdentifiers.id_composite_key.equals(((CompositePublicKey)key).getAlgorithmIdentifier().getAlgorithm())) { List keys = ((CompositePublicKey)key).getPublicKeys(); @@ -852,25 +830,8 @@ private static Collection getAlternativeNames(org.bouncycastle.asn1.x509.Certifi static byte[] getExtensionOctets(org.bouncycastle.asn1.x509.Certificate c, ASN1ObjectIdentifier oid) { - ASN1OctetString extValue = getExtensionValue(c, oid); - if (null != extValue) - { - return extValue.getOctets(); - } - return null; - } + ASN1OctetString extValue = Extensions.getExtensionValue(c.getExtensions(), oid); - static ASN1OctetString getExtensionValue(org.bouncycastle.asn1.x509.Certificate c, ASN1ObjectIdentifier oid) - { - Extensions exts = c.getTBSCertificate().getExtensions(); - if (null != exts) - { - Extension ext = exts.getExtension(oid); - if (null != ext) - { - return ext.getExtnValue(); - } - } - return null; + return extValue == null ? null : extValue.getOctets(); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java index b2dfac7c84..e5ed6c2cac 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java @@ -15,17 +15,19 @@ import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.Extensions; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers; import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers; import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.jcajce.util.MessageDigestUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Exceptions; import org.bouncycastle.util.Objects; import org.bouncycastle.util.Properties; import org.bouncycastle.util.encoders.Hex; @@ -60,6 +62,30 @@ static boolean areEquivalentAlgorithms(AlgorithmIdentifier id1, AlgorithmIdentif return Objects.areEqual(id1.getParameters(), id2.getParameters()); } + static byte[] getExtensionValue(Extensions extensions, String oid) + { + if (oid != null) + { + ASN1ObjectIdentifier asn1Oid = ASN1ObjectIdentifier.tryFromID(oid); + if (asn1Oid != null) + { + ASN1OctetString extValue = Extensions.getExtensionValue(extensions, asn1Oid); + if (null != extValue) + { + try + { + return extValue.getEncoded(); + } + catch (Exception e) + { + throw Exceptions.illegalStateException("error parsing " + e.getMessage(), e); + } + } + } + } + return null; + } + private static boolean isAbsentOrEmptyParameters(ASN1Encodable parameters) { return parameters == null || DERNull.INSTANCE.equals(parameters); @@ -199,7 +225,7 @@ private static String lookupAlg(Provider prov, ASN1ObjectIdentifier algOid) return null; } - static void prettyPrintSignature(byte[] sig, StringBuffer buf, String nl) + static void prettyPrintSignature(byte[] sig, StringBuilder buf, String nl) { // -DM Hex.toHexString // -DM Hex.toHexString diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/drbg/DRBG.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/drbg/DRBG.java index 437de65ff3..8bb83aa619 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/drbg/DRBG.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/drbg/DRBG.java @@ -53,6 +53,14 @@ public class DRBG { private static final String PREFIX = DRBG.class.getName(); + private static int get256BitsEffectiveEntropySize() + { + // by default we assume .9 bits per real bit + int effectiveBits = Properties.asInteger("org.bouncycastle.drbg.effective_256bits_entropy", 282); + + return ((effectiveBits + 7) / 8) * 8; + } + // {"Provider class name","SecureRandomSpi class name"} private static final String[][] initialEntropySourceNames = new String[][] { @@ -463,7 +471,7 @@ private static class HybridEntropySource EntropySourceProvider entropyProvider = createCoreEntropySourceProvider(); bytesRequired = (bitsRequired + 7) / 8; // remember for the seed generator we need the correct security strength for SHA-512 - entropySource = new SignallingEntropySource(entropyDaemon, seedAvailable, entropyProvider, 256); + entropySource = new SignallingEntropySource(entropyDaemon, seedAvailable, entropyProvider, get256BitsEffectiveEntropySize()); drbg = new SP800SecureRandomBuilder(new EntropySourceProvider() { public EntropySource get(final int bitsRequired) @@ -592,7 +600,7 @@ private static class OneShotHybridEntropySource EntropySourceProvider entropyProvider = createCoreEntropySourceProvider(); bytesRequired = (bitsRequired + 7) / 8; // remember for the seed generator we need the correct security strength for SHA-512 - entropySource = new OneShotSignallingEntropySource(seedAvailable, entropyProvider, 256); + entropySource = new OneShotSignallingEntropySource(seedAvailable, entropyProvider, get256BitsEffectiveEntropySize()); drbg = new SP800SecureRandomBuilder(new EntropySourceProvider() { public EntropySource get(final int bitsRequired) diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java index 3a1a46d691..f66e47b5f1 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java @@ -77,6 +77,7 @@ import org.bouncycastle.asn1.pkcs.MacData; import org.bouncycastle.asn1.pkcs.PBES2Parameters; import org.bouncycastle.asn1.pkcs.PBKDF2Params; +import org.bouncycastle.asn1.pkcs.PBMAC1Params; import org.bouncycastle.asn1.pkcs.PKCS12PBEParams; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.Pfx; @@ -93,8 +94,14 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x509.TBSCertificate; import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.PBEParametersGenerator; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; +import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.util.DigestFactory; import org.bouncycastle.internal.asn1.cms.GCMParameters; import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers; @@ -116,6 +123,7 @@ import org.bouncycastle.jce.provider.JDKPKCS12StoreParameter; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.BigIntegers; +import org.bouncycastle.util.Exceptions; import org.bouncycastle.util.Integers; import org.bouncycastle.util.Properties; import org.bouncycastle.util.Strings; @@ -434,13 +442,13 @@ public Certificate[] engineGetCertificateChain( X509Certificate x509c = (X509Certificate)c; Certificate nextC = null; - byte[] akiBytes = x509c.getExtensionValue(Extension.authorityKeyIdentifier.getId()); - if (akiBytes != null) + byte[] akiExtValue = x509c.getExtensionValue(Extension.authorityKeyIdentifier.getId()); + if (akiExtValue != null) { - ASN1OctetString akiValue = ASN1OctetString.getInstance(akiBytes); - AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance(akiValue.getOctets()); + AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance( + ASN1OctetString.getInstance(akiExtValue).getOctets()); - byte[] keyID = aki.getKeyIdentifier(); + byte[] keyID = aki.getKeyIdentifierOctets(); if (null != keyID) { nextC = (Certificate)chainCerts.get(new CertId(keyID)); @@ -664,9 +672,13 @@ else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2)) return (PrivateKey)cipher.unwrap(data, "", Cipher.PRIVATE_KEY); } } + catch (InvalidKeyException e) + { + throw Exceptions.ioException("exception unwrapping private key:" + e.getMessage(), new UnrecoverableKeyException(e.toString())); + } catch (Exception e) { - throw new IOException("exception unwrapping private key - " + e.toString()); + throw Exceptions.ioException("exception unwrapping private key: " + e.getMessage(), e); } throw new IOException("exception unwrapping private key - cannot recognise: " + algorithm); @@ -750,12 +762,13 @@ protected byte[] cryptData( if (algorithm.on(PKCSObjectIdentifiers.pkcs_12PbeIds)) { PKCS12PBEParams pbeParams = PKCS12PBEParams.getInstance(algId.getParameters()); + PKCS12Key key = new PKCS12Key(password, wrongPKCS12Zero); + try { PBEParameterSpec defParams = new PBEParameterSpec( pbeParams.getIV(), BigIntegers.intValueExact(pbeParams.getIterations())); - PKCS12Key key = new PKCS12Key(password, wrongPKCS12Zero); Cipher cipher = helper.createCipher(algorithm.getId()); @@ -766,6 +779,10 @@ protected byte[] cryptData( { throw new IOException("exception decrypting data - " + e.toString()); } + finally + { + Arrays.clear(key.getPassword()); + } } else if (algorithm.equals(PKCSObjectIdentifiers.id_PBES2)) { @@ -933,7 +950,8 @@ public void engineLoad( { if (password.length > 0) { - throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file."); + throw Exceptions.ioException("PKCS12 key store mac invalid - wrong password or corrupted file", + new UnrecoverableKeyException("PKCS12 key store mac invalid")); } // Try with incorrect zero length password @@ -941,7 +959,7 @@ public void engineLoad( if (!Arrays.constantTimeAreEqual(res, dig)) { - throw new IOException("PKCS12 key store mac invalid - wrong password or corrupted file."); + throw Exceptions.ioException("PKCS12 key store mac invalid - wrong password or corrupted file", new UnrecoverableKeyException("PKCS12 key store mac invalid")); } wrongPKCS12Zero = true; @@ -1427,7 +1445,7 @@ private void syncFriendlyName() // TODO:delete comment // Since we cannot add any function to the KeyStore Api we will run code when saving the store // to sync the friendlyNames with Alias depending on the storeParameter - /** + /* * @Override * public void setFriendlyName(String alias, String newFriendlyName, char[] password) throws UnrecoverableKeyException, NoSuchAlgorithmException * { @@ -1984,36 +2002,21 @@ private SafeBag createSafeBag(String certId, Certificate cert, boolean overwrite if (cert instanceof X509Certificate) { TBSCertificate tbsCert = TBSCertificate.getInstance(((X509Certificate)cert).getTBSCertificate()); - Extensions exts = tbsCert.getExtensions(); - if (exts != null) - { - Extension extUsage = exts.getExtension(Extension.extendedKeyUsage); - if (extUsage != null) - { - ASN1EncodableVector fSeq = new ASN1EncodableVector(); - // oracle trusted key usage OID. - fSeq.add(MiscObjectIdentifiers.id_oracle_pkcs12_trusted_key_usage); - fSeq.add(new DERSet(ExtendedKeyUsage.getInstance(extUsage.getParsedValue()).getUsages())); - fName.add(new DERSequence(fSeq)); - } - else - { - ASN1EncodableVector fSeq = new ASN1EncodableVector(); + ASN1OctetString eku = Extensions.getExtensionValue(tbsCert.getExtensions(), + Extension.extendedKeyUsage); - fSeq.add(MiscObjectIdentifiers.id_oracle_pkcs12_trusted_key_usage); - fSeq.add(new DERSet(KeyPurposeId.anyExtendedKeyUsage)); - fName.add(new DERSequence(fSeq)); - } + DERSet attrValue; + if (eku != null) + { + attrValue = new DERSet(ExtendedKeyUsage.getInstance(eku.getOctets()).getUsages()); } else { - ASN1EncodableVector fSeq = new ASN1EncodableVector(); - - fSeq.add(MiscObjectIdentifiers.id_oracle_pkcs12_trusted_key_usage); - fSeq.add(new DERSet(KeyPurposeId.anyExtendedKeyUsage)); - fName.add(new DERSequence(fSeq)); + attrValue = new DERSet(KeyPurposeId.anyExtendedKeyUsage); } + + fName.add(new DERSequence(MiscObjectIdentifiers.id_oracle_pkcs12_trusted_key_usage, attrValue)); } return new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName)); @@ -2056,13 +2059,73 @@ private byte[] calculatePbeMac( byte[] data) throws Exception { + if (PKCSObjectIdentifiers.id_PBMAC1.equals(oid)) + { + PBMAC1Params pbmac1Params = PBMAC1Params.getInstance(macAlgorithm.getParameters()); + if (pbmac1Params == null) + { + throw new IOException("If the DigestAlgorithmIdentifier is id-PBMAC1, then the parameters field must contain valid PBMAC1-params parameters."); + } + if (PKCSObjectIdentifiers.id_PBKDF2.equals(pbmac1Params.getKeyDerivationFunc().getAlgorithm())) + { + PBKDF2Params pbkdf2Params = PBKDF2Params.getInstance(pbmac1Params.getKeyDerivationFunc().getParameters()); + if (pbkdf2Params.getKeyLength() == null) + { + throw new IOException("Key length must be present when using PBMAC1."); + } + final HMac hMac = new HMac(getPrf(pbmac1Params.getMessageAuthScheme().getAlgorithm())); + + PBEParametersGenerator generator = new PKCS5S2ParametersGenerator(getPrf(pbkdf2Params.getPrf().getAlgorithm())); + + generator.init( + Strings.toUTF8ByteArray(password), + pbkdf2Params.getSalt(), + BigIntegers.intValueExact(pbkdf2Params.getIterationCount())); + + CipherParameters key = generator.generateDerivedParameters(BigIntegers.intValueExact(pbkdf2Params.getKeyLength()) * 8); + + Arrays.clear(generator.getPassword()); + + hMac.init(key); + hMac.update(data, 0, data.length); + byte[] res = new byte[hMac.getMacSize()]; + hMac.doFinal(res, 0); + return res; + } + } + PBEParameterSpec defParams = new PBEParameterSpec(salt, itCount); + PKCS12Key key = new PKCS12Key(password, wrongPkcs12Zero); + + try + { + Mac mac = helper.createMac(oid.getId()); - Mac mac = helper.createMac(oid.getId()); - mac.init(new PKCS12Key(password, wrongPkcs12Zero), defParams); - mac.update(data); + mac.init(key, defParams); + mac.update(data); - return mac.doFinal(); + return mac.doFinal(); + } + finally + { + Arrays.clear(key.getPassword()); + } + } + + private static Digest getPrf(ASN1ObjectIdentifier prfId) + { + if (PKCSObjectIdentifiers.id_hmacWithSHA256.equals(prfId)) + { + return new SHA256Digest(); + } + else if (PKCSObjectIdentifiers.id_hmacWithSHA512.equals(prfId)) + { + return new SHA512Digest(); + } + else + { + throw new IllegalArgumentException("unknown prf id " + prfId); + } } public static class BCPKCS12KeyStore diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARIA.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARIA.java index 9f851a19ef..dc2b019dda 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARIA.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARIA.java @@ -93,7 +93,7 @@ static public class CCM { public CCM() { - super(new CCMBlockCipher(new ARIAEngine()), false, 12); + super(CCMBlockCipher.newInstance(new ARIAEngine()), false, 12); } } @@ -102,7 +102,7 @@ static public class GCM { public GCM() { - super(new GCMBlockCipher(new ARIAEngine())); + super(GCMBlockCipher.newInstance(new ARIAEngine())); } } @@ -138,7 +138,7 @@ public static class GMAC { public GMAC() { - super(new GMac(new GCMBlockCipher(new ARIAEngine()))); + super(new GMac(GCMBlockCipher.newInstance(new ARIAEngine()))); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST6.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST6.java index b9d683ea3d..6d72dd6550 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST6.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST6.java @@ -48,7 +48,7 @@ public static class GMAC { public GMAC() { - super(new GMac(new GCMBlockCipher(new CAST6Engine()))); + super(new GMac(GCMBlockCipher.newInstance(new CAST6Engine()))); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java index d4bab38db6..88e35e8da5 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java @@ -135,7 +135,7 @@ public static class GMAC { public GMAC() { - super(new GMac(new GCMBlockCipher(new CamelliaEngine()))); + super(new GMac(GCMBlockCipher.newInstance(new CamelliaEngine()))); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java index 91e95411ab..bc44af3400 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java @@ -54,7 +54,7 @@ static public class CBC { public CBC() { - super(new CBCBlockCipher(new DESedeEngine()), 64); + super(CBCBlockCipher.newInstance(new DESedeEngine()), 64); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/HKDF.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/HKDF.java new file mode 100644 index 0000000000..d8b317ba5c --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/HKDF.java @@ -0,0 +1,112 @@ +package org.bouncycastle.jcajce.provider.symmetric; + +import java.security.InvalidAlgorithmParameterException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; + +import javax.crypto.SecretKey; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA384Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.generators.HKDFBytesGenerator; +import org.bouncycastle.crypto.params.HKDFParameters; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey; +import org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory; +import org.bouncycastle.jcajce.provider.util.AlgorithmProvider; +import org.bouncycastle.jcajce.spec.HKDFParameterSpec; + +public class HKDF +{ + private HKDF() + { + + } + + public static class HKDFBase + extends BaseSecretKeyFactory + { + protected String algName; + protected HKDFBytesGenerator hkdf; + + + public HKDFBase(String algName, Digest digest, ASN1ObjectIdentifier oid) + { + super(algName, oid); + this.algName = algName; + this.hkdf = new HKDFBytesGenerator(digest); + } + + @Override + protected SecretKey engineGenerateSecret(KeySpec keySpec) + throws InvalidKeySpecException + { + if (!(keySpec instanceof HKDFParameterSpec)) + { + throw new InvalidKeySpecException("invalid KeySpec: expected HKDFParameterSpec, but got " + keySpec.getClass().getName()); + } + + HKDFParameterSpec spec = (HKDFParameterSpec) keySpec; + int derivedDataLength = spec.getOutputLength(); + hkdf.init(new HKDFParameters(spec.getIKM(), spec.getSalt(), spec.getInfo())); + + byte[] derivedData = new byte[derivedDataLength]; + hkdf.generateBytes(derivedData, 0, derivedDataLength); + + CipherParameters param = new KeyParameter(derivedData); + + return new BCPBEKey(this.algName, param); + } + } + + public static class HKDFwithSHA256 + extends HKDFBase + { + public HKDFwithSHA256() throws InvalidAlgorithmParameterException + { + super("HKDF-SHA256", new SHA256Digest(), PKCSObjectIdentifiers.id_alg_hkdf_with_sha256); + } + } + + public static class HKDFwithSHA384 + extends HKDFBase + { + public HKDFwithSHA384() throws InvalidAlgorithmParameterException + { + super("HKDF-SHA384", new SHA384Digest(), PKCSObjectIdentifiers.id_alg_hkdf_with_sha384); + } + } + + public static class HKDFwithSHA512 + extends HKDFBase + { + + public HKDFwithSHA512() throws InvalidAlgorithmParameterException + { + super("HKDF-SHA512", new SHA512Digest(), PKCSObjectIdentifiers.id_alg_hkdf_with_sha512); + } + } + + public static class Mappings + extends AlgorithmProvider + { + private static final String PREFIX = HKDF.class.getName(); + + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + provider.addAlgorithm("SecretKeyFactory.HKDF-SHA256", PREFIX + "$HKDFwithSHA256"); + provider.addAlgorithm("SecretKeyFactory.HKDF-SHA384", PREFIX + "$HKDFwithSHA384"); + provider.addAlgorithm("SecretKeyFactory.HKDF-SHA512", PREFIX + "$HKDFwithSHA512"); + } + } +} diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/IDEA.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/IDEA.java index 189bcb723c..47891fed74 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/IDEA.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/IDEA.java @@ -73,7 +73,7 @@ static public class PBEWithSHAAndIDEA { public PBEWithSHAAndIDEA() { - super(CBCBlockCipher.newInstance(new IDEAEngine())); + super(CBCBlockCipher.newInstance(new IDEAEngine()), PKCS12, SHA1, 128, 8); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Noekeon.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Noekeon.java index 1e32091ab4..6deb861060 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Noekeon.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Noekeon.java @@ -57,7 +57,7 @@ public static class GMAC { public GMAC() { - super(new GMac(new GCMBlockCipher(new NoekeonEngine()))); + super(new GMac(GCMBlockCipher.newInstance(new NoekeonEngine()))); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java index 303ff703e3..799e6b9d5b 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java @@ -22,6 +22,7 @@ import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.PasswordConverter; +import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers; import org.bouncycastle.jcajce.PBKDF2Key; import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey; @@ -44,10 +45,13 @@ public class PBEPBKDF2 prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA224, Integers.valueOf(PBE.SHA224)); prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA384, Integers.valueOf(PBE.SHA384)); prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA512, Integers.valueOf(PBE.SHA512)); + prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA512_224, Integers.valueOf(PBE.SHA512_224)); + prfCodes.put(PKCSObjectIdentifiers.id_hmacWithSHA512_256, Integers.valueOf(PBE.SHA512_256)); prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_256, Integers.valueOf(PBE.SHA3_256)); prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_224, Integers.valueOf(PBE.SHA3_224)); prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_384, Integers.valueOf(PBE.SHA3_384)); prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_512, Integers.valueOf(PBE.SHA3_512)); + prfCodes.put(IANAObjectIdentifiers.hmacRIPEMD160, Integers.valueOf(PBE.RIPEMD160)); prfCodes.put(GMObjectIdentifiers.hmac_sm3, Integers.valueOf(PBE.SM3)); } @@ -273,6 +277,24 @@ public PBKDF2withSHA512() } } + public static class PBKDF2withSHA512_224 + extends BasePBKDF2 + { + public PBKDF2withSHA512_224() + { + super("PBKDF2", PKCS5S2_UTF8, SHA512_224); + } + } + + public static class PBKDF2withSHA512_256 + extends BasePBKDF2 + { + public PBKDF2withSHA512_256() + { + super("PBKDF2", PKCS5S2_UTF8, SHA512_256); + } + } + public static class PBKDF2withGOST3411 extends BasePBKDF2 { @@ -360,6 +382,8 @@ public void configure(ConfigurableProvider provider) provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA256", PREFIX + "$PBKDF2withSHA256"); provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA384", PREFIX + "$PBKDF2withSHA384"); provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA512", PREFIX + "$PBKDF2withSHA512"); + provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA512-224", PREFIX + "$PBKDF2withSHA512_224"); + provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA512-256", PREFIX + "$PBKDF2withSHA512_256"); provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA3-224", PREFIX + "$PBKDF2withSHA3_224"); provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA3-256", PREFIX + "$PBKDF2withSHA3_256"); provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA3-384", PREFIX + "$PBKDF2withSHA3_384"); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC6.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC6.java index 81271ecd7e..2f479f5884 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC6.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/RC6.java @@ -79,7 +79,7 @@ public static class GMAC { public GMAC() { - super(new GMac(new GCMBlockCipher(new RC6Engine()))); + super(new GMac(GCMBlockCipher.newInstance(new RC6Engine()))); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java index c1b6bf9d4b..db02541e72 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java @@ -90,7 +90,7 @@ public static class GMAC { public GMAC() { - super(new GMac(new GCMBlockCipher(new SEEDEngine()))); + super(new GMac(GCMBlockCipher.newInstance(new SEEDEngine()))); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SM4.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SM4.java index 6e0202fa2f..2d790ef520 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SM4.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SM4.java @@ -5,21 +5,27 @@ import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; +import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; +import org.bouncycastle.asn1.gm.GMObjectIdentifiers; import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherKeyGenerator; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.crypto.engines.RFC3394WrapEngine; +import org.bouncycastle.crypto.engines.RFC5649WrapEngine; import org.bouncycastle.crypto.engines.SM4Engine; import org.bouncycastle.crypto.generators.Poly1305KeyGenerator; import org.bouncycastle.crypto.macs.CMac; import org.bouncycastle.crypto.macs.GMac; import org.bouncycastle.crypto.modes.GCMBlockCipher; +import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers; import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator; import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher; import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac; +import org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher; import org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider; import org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters; @@ -67,7 +73,7 @@ public static class GMAC { public GMAC() { - super(new GMac(new GCMBlockCipher(new SM4Engine()))); + super(new GMac(GCMBlockCipher.newInstance(new SM4Engine()))); } } @@ -89,6 +95,24 @@ public Poly1305KeyGen() } } + public static class Wrap + extends BaseWrapCipher + { + public Wrap() + { + super(new SM4WrapEngine()); + } + } + + public static class WrapPad + extends BaseWrapCipher + { + public WrapPad() + { + super(new SM4WrapPadEngine()); + } + } + public static class AlgParamGen extends BaseAlgorithmParameterGenerator { @@ -158,6 +182,29 @@ public void configure(ConfigurableProvider provider) addCMacAlgorithm(provider, "SM4", PREFIX + "$CMAC", PREFIX + "$KeyGen"); addGMacAlgorithm(provider, "SM4", PREFIX + "$GMAC", PREFIX + "$KeyGen"); addPoly1305Algorithm(provider, "SM4", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen"); + + provider.addAlgorithm("Cipher.SM4WRAP", PREFIX + "$Wrap"); + provider.addAlgorithm("Cipher.SM4WRAPPAD", PREFIX + "$WrapPad"); + provider.addAlgorithm("Cipher", GMObjectIdentifiers.sms4_wrap, PREFIX + "$Wrap"); + provider.addAlgorithm("Cipher", GMObjectIdentifiers.sms4_wrap_pad, PREFIX + "$WrapPad"); + } + } + + private static class SM4WrapEngine + extends RFC3394WrapEngine + { + public SM4WrapEngine() + { + super(new SM4Engine()); + } + } + + private static class SM4WrapPadEngine + extends RFC5649WrapEngine + { + public SM4WrapPadEngine() + { + super(new SM4Engine()); } } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java index a493aba7b6..25725ef2d3 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java @@ -231,7 +231,7 @@ public static class SerpentGMAC { public SerpentGMAC() { - super(new GMac(new GCMBlockCipher(new SerpentEngine()))); + super(new GMac(GCMBlockCipher.newInstance(new SerpentEngine()))); } } @@ -240,7 +240,7 @@ public static class TSerpentGMAC { public TSerpentGMAC() { - super(new GMac(new GCMBlockCipher(new TnepresEngine()))); + super(new GMac(GCMBlockCipher.newInstance(new TnepresEngine()))); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java index a759ccd20d..dfefa0c0f5 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Twofish.java @@ -50,7 +50,7 @@ public static class GMAC { public GMAC() { - super(new GMac(new GCMBlockCipher(new TwofishEngine()))); + super(new GMac(GCMBlockCipher.newInstance(new TwofishEngine()))); } } diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java index 207bd9c272..caa4bfb22b 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java @@ -331,7 +331,7 @@ protected AlgorithmParameters engineGetParameters() engineParams.init(pbeSpec); } catch (Exception e) - { + { return null; } } @@ -448,7 +448,7 @@ else if (modeName.startsWith("PGPCFB")) { throw new NoSuchAlgorithmException("no mode support for " + modeName); } - + ivLength = baseEngine.getBlockSize(); cipher = new BufferedGenericBlockCipher( new PGPCFBBlockCipher(baseEngine, inlineIV)); @@ -696,6 +696,8 @@ protected void engineInit( throw new InvalidKeyException("Algorithm requires a PBE key"); } + pbeAlgorithm = "PKCS12PBE"; + if (key instanceof BCPBEKey) { // PKCS#12 sets an IV, if we get a key that doesn't have ParametersWithIV we need to reject it. If the @@ -821,14 +823,16 @@ else if (!(key instanceof RepeatedSecretKeySpec)) param = null; } - AlgorithmParameterSpec params; + AlgorithmParameterSpec params = paramSpec; if (paramSpec instanceof PBEParameterSpec) { params = ((PBEParameterSpec)paramSpec).getParameterSpec(); - } - else - { - params = paramSpec; + // If params.getIv() returns an empty byte array, ivParam will be assigned an IV generated by PBE.Util.makePBEParameters + // according to RFC 7292. This behavior is intended for Jasypt users who choose to use NoIvGenerator. + if (params instanceof IvParameterSpec && ((IvParameterSpec)params).getIV().length == 0) + { + params = paramSpec; + } } if (params instanceof AEADParameterSpec) @@ -1324,7 +1328,7 @@ private boolean isAEADModeName( * The ciphers that inherit from us. */ - static private interface GenericBlockCipher + private static interface GenericBlockCipher { public void init(boolean forEncryption, CipherParameters params) throws IllegalArgumentException; diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java index f3f3ff3ee8..4c60a4d9d7 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java @@ -44,6 +44,8 @@ public interface PBE static final int SHA3_384 = 12; static final int SHA3_512 = 13; static final int SM3 = 14; + static final int SHA512_224 = 15; + static final int SHA512_256 = 16; static final int PKCS5S1 = 0; static final int PKCS5S2 = 1; @@ -57,9 +59,7 @@ public interface PBE */ static class Util { - static private PBEParametersGenerator makePBEGenerator( - int type, - int hash) + private static PBEParametersGenerator makePBEGenerator(int type, int hash) { PBEParametersGenerator generator; @@ -114,6 +114,12 @@ else if (type == PKCS5S2 || type == PKCS5S2_UTF8) case SHA512: generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA512PRF()); break; + case SHA512_224: + generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA512_224PRF()); + break; + case SHA512_256: + generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA512_256PRF()); + break; case SHA3_224: generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA3_224PRF()); break; diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java index 88810d9acc..adcfde06b9 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java @@ -147,6 +147,20 @@ protected void addCipherAlgorithm( } } + protected void addKEMAlgorithm( + ConfigurableProvider provider, + String algorithm, + String className, + ASN1ObjectIdentifier oid) + { + provider.addAlgorithm("KEM." + algorithm, className); + if (oid != null) + { + provider.addAlgorithm("Alg.Alias.KEM." + oid, algorithm); + provider.addAlgorithm("Alg.Alias.KEM.OID." + oid, algorithm); + } + } + protected void registerKeyFactoryOid(ConfigurableProvider provider, ASN1ObjectIdentifier oid, String name, AsymmetricKeyInfoConverter keyFactory) { provider.addAlgorithm("Alg.Alias.KeyFactory." + oid, name); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java index 686d6b8461..42c601a4bb 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java @@ -9,13 +9,16 @@ import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers; import org.bouncycastle.util.Integers; +/** + * @deprecated class appears to be no longer in use, maybe getting imported by others though. + */ public class SecretKeyUtil { - private static Map keySizes = new HashMap(); + private static Map keySizes = new HashMap(); static { - keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC.getId(), Integers.valueOf(192)); + keySizes.put(PKCSObjectIdentifiers.des_EDE3_CBC, Integers.valueOf(192)); keySizes.put(NISTObjectIdentifiers.id_aes128_CBC, Integers.valueOf(128)); keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192)); diff --git a/prov/src/main/java/org/bouncycastle/jcajce/spec/CompositeSignatureSpec.java b/prov/src/main/java/org/bouncycastle/jcajce/spec/CompositeSignatureSpec.java new file mode 100644 index 0000000000..f31dc550ba --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/jcajce/spec/CompositeSignatureSpec.java @@ -0,0 +1,45 @@ +package org.bouncycastle.jcajce.spec; + +import java.security.spec.AlgorithmParameterSpec; + +/** + * Parameters for the CompositeSignature algorithm. + */ +public class CompositeSignatureSpec + implements AlgorithmParameterSpec +{ + private final boolean isPrehashMode; + private final AlgorithmParameterSpec secondaryParameterSpec; + + /** + * Base Constructor. + * + * @param isPrehashMode if true, msg passed in will be the precalculated pre-hash. + */ + public CompositeSignatureSpec(boolean isPrehashMode) + { + this(isPrehashMode, null); + } + + /** + * Constructor which allows for another parameter spec (usually ContextParameterSpec). + * + * @param isPrehashMode if true, msg passed in will be the precalculated pre-hash. + * @param secondaryParameterSpec the other spec, in addition to pre-hash mode, which needs to be applied. + */ + public CompositeSignatureSpec(boolean isPrehashMode, AlgorithmParameterSpec secondaryParameterSpec) + { + this.isPrehashMode = isPrehashMode; + this.secondaryParameterSpec = secondaryParameterSpec; + } + + public boolean isPrehashMode() + { + return isPrehashMode; + } + + public AlgorithmParameterSpec getSecondarySpec() + { + return secondaryParameterSpec; + } +} diff --git a/prov/src/main/java/org/bouncycastle/jcajce/spec/HKDFParameterSpec.java b/prov/src/main/java/org/bouncycastle/jcajce/spec/HKDFParameterSpec.java new file mode 100644 index 0000000000..b2248100c2 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/jcajce/spec/HKDFParameterSpec.java @@ -0,0 +1,70 @@ +package org.bouncycastle.jcajce.spec; + +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.KeySpec; + +import org.bouncycastle.crypto.params.HKDFParameters; + +public class HKDFParameterSpec + implements KeySpec, AlgorithmParameterSpec +{ + private final HKDFParameters hkdfParameters; + private final int outputLength; + + public HKDFParameterSpec(byte[] ikm, byte[] salt, byte[] info, int outputLength) + { + this.hkdfParameters = new HKDFParameters(ikm, salt, info); + this.outputLength = outputLength; + } + + /** + * Returns the input keying material or seed. + * + * @return the keying material + */ + public byte[] getIKM() + { + return hkdfParameters.getIKM(); + } + + /** + * Returns if step 1: extract has to be skipped or not + * + * @return true for skipping, false for no skipping of step 1 + */ + public boolean skipExtract() + { + return hkdfParameters.skipExtract(); + } + + /** + * Returns the salt, or null if the salt should be generated as a byte array + * of HashLen zeros. + * + * @return the salt, or null + */ + public byte[] getSalt() + { + return hkdfParameters.getSalt(); + } + + /** + * Returns the info field, which may be empty (null is converted to empty). + * + * @return the info field, never null + */ + public byte[] getInfo() + { + return hkdfParameters.getInfo(); + } + + /** + * Returns the length (in bytes) of the output resulting from these parameters. + * + * @return output length, in bytes. + */ + public int getOutputLength() + { + return outputLength; + } +} diff --git a/prov/src/main/java/org/bouncycastle/jcajce/spec/SM2KeyExchangeSpec.java b/prov/src/main/java/org/bouncycastle/jcajce/spec/SM2KeyExchangeSpec.java new file mode 100644 index 0000000000..5e6e169d40 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/jcajce/spec/SM2KeyExchangeSpec.java @@ -0,0 +1,53 @@ +package org.bouncycastle.jcajce.spec; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.AlgorithmParameterSpec; + +import org.bouncycastle.util.Arrays; + +public class SM2KeyExchangeSpec + implements AlgorithmParameterSpec +{ + private final PrivateKey ephemeralPrivateKey; + private final PublicKey otherPartyEphemeralKey; + private final byte[] id; + private final byte[] otherPartyId; + private final boolean initiator; + + public SM2KeyExchangeSpec(boolean initiator, PrivateKey ephemeralPrivateKey, + PublicKey otherPartyEphemeralKey, byte[] id, byte[] otherPartyId) + { + this.initiator = initiator; + this.ephemeralPrivateKey = ephemeralPrivateKey; + this.otherPartyEphemeralKey = otherPartyEphemeralKey; + this.id = Arrays.clone(id); + this.otherPartyId = Arrays.clone(otherPartyId); + } + + public PrivateKey getEphemeralPrivateKey() + { + return ephemeralPrivateKey; + } + + public PublicKey getOtherPartyEphemeralKey() + { + return otherPartyEphemeralKey; + } + + public byte[] getId() + { + return Arrays.clone(id); + } + + public byte[] getOtherPartyId() + { + return Arrays.clone(otherPartyId); + } + + public boolean isInitiator() + { + return initiator; + } +} + diff --git a/prov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java b/prov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java index 214f86393b..1cc00c195b 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java @@ -40,6 +40,11 @@ public NamedJcaJceHelper(String providerName) this.providerName = providerName; } + public String getProviderName() + { + return providerName; + } + public Cipher createCipher( String algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException diff --git a/prov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java b/prov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java index b9a28fa5e0..fb27157be3 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java @@ -40,6 +40,11 @@ public ProviderJcaJceHelper(Provider provider) this.provider = provider; } + public Provider getProvider() + { + return provider; + } + public Cipher createCipher( String algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException diff --git a/prov/src/main/java/org/bouncycastle/jcajce/util/SpecUtil.java b/prov/src/main/java/org/bouncycastle/jcajce/util/SpecUtil.java new file mode 100644 index 0000000000..c0f1cf9d8a --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/jcajce/util/SpecUtil.java @@ -0,0 +1,56 @@ +package org.bouncycastle.jcajce.util; + +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.spec.AlgorithmParameterSpec; + +public class SpecUtil +{ + private static Class[] NO_PARAMS = new Class[0]; + private static Object[] NO_ARGS = new Object[0]; + + public static String getNameFrom(final AlgorithmParameterSpec paramSpec) + { + return (String)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + try + { + Method m = paramSpec.getClass().getMethod("getName", NO_PARAMS); + + return m.invoke(paramSpec, NO_ARGS); + } + catch (Exception e) + { + // ignore - maybe log? + } + + return null; + } + }); + } + + public static byte[] getContextFrom(final AlgorithmParameterSpec paramSpec) + { + return (byte[])AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + try + { + Method m = paramSpec.getClass().getMethod("getContext", NO_PARAMS); + + return m.invoke(paramSpec, NO_ARGS); + } + catch (Exception e) + { + // ignore - maybe log? + } + + return null; + } + }); + } +} diff --git a/prov/src/main/java/org/bouncycastle/jcajce/util/SpiUtil.java b/prov/src/main/java/org/bouncycastle/jcajce/util/SpiUtil.java new file mode 100644 index 0000000000..97af2d666c --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/jcajce/util/SpiUtil.java @@ -0,0 +1,14 @@ +package org.bouncycastle.jcajce.util; + +public abstract class SpiUtil +{ + public static boolean hasKDF() + { + return false; + } + + public static boolean hasKEM() + { + return false; + } +} diff --git a/prov/src/main/java/org/bouncycastle/jce/ECGOST3410NamedCurveTable.java b/prov/src/main/java/org/bouncycastle/jce/ECGOST3410NamedCurveTable.java index a70aa3bd7b..4a552b7137 100644 --- a/prov/src/main/java/org/bouncycastle/jce/ECGOST3410NamedCurveTable.java +++ b/prov/src/main/java/org/bouncycastle/jce/ECGOST3410NamedCurveTable.java @@ -25,13 +25,10 @@ public static ECNamedCurveParameterSpec getParameterSpec( X9ECParameters ecP = ECGOST3410NamedCurves.getByNameX9(name); if (ecP == null) { - try + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.tryFromID(name); + if (oid != null) { - ecP = ECGOST3410NamedCurves.getByOIDX9(new ASN1ObjectIdentifier(name)); - } - catch (IllegalArgumentException e) - { - return null; // not an oid. + ecP = ECGOST3410NamedCurves.getByOIDX9(oid); } } diff --git a/prov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java b/prov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java index 1165dc5db0..4e25adbc29 100644 --- a/prov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java +++ b/prov/src/main/java/org/bouncycastle/jce/ECNamedCurveTable.java @@ -21,15 +21,7 @@ public class ECNamedCurveTable public static ECNamedCurveParameterSpec getParameterSpec( String name) { - ASN1ObjectIdentifier oid; - try - { - oid = possibleOID(name) ? new ASN1ObjectIdentifier(name) : null; - } - catch (IllegalArgumentException e) - { - oid = null; - } + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.tryFromID(name); X9ECParameters ecP; if (oid != null) @@ -76,21 +68,4 @@ public static Enumeration getNames() { return org.bouncycastle.asn1.x9.ECNamedCurveTable.getNames(); } - - private static boolean possibleOID( - String identifier) - { - if (identifier.length() < 3 || identifier.charAt(1) != '.') - { - return false; - } - - char first = identifier.charAt(0); - if (first < '0' || first > '2') - { - return false; - } - - return true; - } } diff --git a/prov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java b/prov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java index cf7933d714..33a0f3e70a 100644 --- a/prov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java +++ b/prov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java @@ -199,8 +199,8 @@ private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int return new RSASSAPSSparams( hashAlgId, new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId), - new ASN1Integer(saltSize), - new ASN1Integer(1)); + ASN1Integer.valueOf(saltSize), + RSASSAPSSparams.DEFAULT_TRAILER_FIELD); } private static ASN1Sequence toDERSequence( @@ -311,11 +311,8 @@ public PKCS10CertificationRequest( if (sigOID == null) { - try - { - sigOID = new ASN1ObjectIdentifier(algorithmName); - } - catch (Exception e) + sigOID = ASN1ObjectIdentifier.tryFromID(algorithmName); + if (sigOID == null) { throw new IllegalArgumentException("Unknown signature type requested"); } diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java index c0ab81239a..1fcc023aea 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java @@ -38,9 +38,11 @@ import org.bouncycastle.pqc.jcajce.provider.hqc.HQCKeyFactorySpi; import org.bouncycastle.pqc.jcajce.provider.kyber.KyberKeyFactorySpi; import org.bouncycastle.pqc.jcajce.provider.lms.LMSKeyFactorySpi; +import org.bouncycastle.pqc.jcajce.provider.mayo.MayoKeyFactorySpi; import org.bouncycastle.pqc.jcajce.provider.newhope.NHKeyFactorySpi; import org.bouncycastle.pqc.jcajce.provider.ntru.NTRUKeyFactorySpi; import org.bouncycastle.pqc.jcajce.provider.picnic.PicnicKeyFactorySpi; +import org.bouncycastle.pqc.jcajce.provider.snova.SnovaKeyFactorySpi; import org.bouncycastle.pqc.jcajce.provider.sphincs.Sphincs256KeyFactorySpi; import org.bouncycastle.pqc.jcajce.provider.sphincsplus.SPHINCSPlusKeyFactorySpi; import org.bouncycastle.pqc.jcajce.provider.xmss.XMSSKeyFactorySpi; @@ -76,7 +78,7 @@ public final class BouncyCastleProvider extends Provider { private static final Logger LOG = Logger.getLogger(BouncyCastleProvider.class.getName()); - private static String info = "BouncyCastle Security Provider v1.80"; + private static String info = "BouncyCastle Security Provider v1.83"; public static final String PROVIDER_NAME = "BC"; @@ -92,29 +94,29 @@ public final class BouncyCastleProvider extends Provider private static final String SYMMETRIC_PACKAGE = "org.bouncycastle.jcajce.provider.symmetric."; private static final String[] SYMMETRIC_GENERIC = - { - "PBEPBKDF1", "PBEPBKDF2", "PBEPKCS12", "TLSKDF", "SCRYPT" - }; + { + "PBEPBKDF1", "PBEPBKDF2", "PBEPKCS12", "TLSKDF", "SCRYPT", "HKDF" + }; private static final String[] SYMMETRIC_MACS = - { - "SipHash", "SipHash128", "Poly1305" - }; + { + "SipHash", "SipHash128", "Poly1305" + }; private static final CryptoServiceProperties[] SYMMETRIC_CIPHERS = - { - // TODO: these numbers need a bit more work, we cap at 256 bits. - service("AES", 256), service("ARC4", 20), service("ARIA", 256), service("Blowfish", 128), service("Camellia", 256), - service("CAST5", 128), service("CAST6", 256), service("ChaCha", 128), service("DES", 56), service("DESede", 112), - service("GOST28147", 128), service("Grainv1", 128), service("Grain128", 128), service("HC128", 128), service("HC256", 256), - service("IDEA", 128), service("Noekeon", 128), service("RC2", 128), service("RC5", 128), service("RC6", 256), - service("Rijndael", 256), service("Salsa20", 128), service("SEED", 128), service("Serpent", 256), service("Shacal2", 128), - service("Skipjack", 80), service("SM4", 128), service("TEA", 128), service("Twofish", 256), service("Threefish", 128), - service("VMPC", 128), service("VMPCKSA3", 128), service("XTEA", 128), service("XSalsa20", 128), service("OpenSSLPBKDF", 128), - service("DSTU7624", 256), service("GOST3412_2015", 256), service("Zuc", 128) - }; - - /* + { + // TODO: these numbers need a bit more work, we cap at 256 bits. + service("AES", 256), service("ARC4", 20), service("ARIA", 256), service("Blowfish", 128), service("Camellia", 256), + service("CAST5", 128), service("CAST6", 256), service("ChaCha", 128), service("DES", 56), service("DESede", 112), + service("GOST28147", 128), service("Grainv1", 128), service("Grain128", 128), service("HC128", 128), service("HC256", 256), + service("IDEA", 128), service("Noekeon", 128), service("RC2", 128), service("RC5", 128), service("RC6", 256), + service("Rijndael", 256), service("Salsa20", 128), service("SEED", 128), service("Serpent", 256), service("Shacal2", 128), + service("Skipjack", 80), service("SM4", 128), service("TEA", 128), service("Twofish", 256), service("Threefish", 128), + service("VMPC", 128), service("VMPCKSA3", 128), service("XTEA", 128), service("XSalsa20", 128), service("OpenSSLPBKDF", 128), + service("DSTU7624", 256), service("GOST3412_2015", 256), service("Zuc", 128) + }; + + /* * Configurable asymmetric ciphers */ private static final String ASYMMETRIC_PACKAGE = "org.bouncycastle.jcajce.provider.asymmetric."; @@ -122,43 +124,55 @@ public final class BouncyCastleProvider extends Provider // this one is required for GNU class path - it needs to be loaded first as the // later ones configure it. private static final String[] ASYMMETRIC_GENERIC = - { - "X509", "IES", "COMPOSITE", "EXTERNAL", "CompositeSignatures" - }; + { + "X509", "IES", "COMPOSITE", "EXTERNAL", "CompositeSignatures", "NoSig" + }; private static final String[] ASYMMETRIC_CIPHERS = - { - "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal", "DSTU4145", "GM", "EdEC", "LMS", "SPHINCSPlus", "Dilithium", "Falcon", "NTRU", "CONTEXT", "SLHDSA", "MLDSA", "MLKEM" - }; + { + "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal", "DSTU4145", "GM", "EdEC", "LMS", "SPHINCSPlus", + "Dilithium", "Falcon", "NTRU", "CONTEXT", "SLHDSA", "MLDSA", "MLKEM" + }; /* * Configurable digests */ private static final String DIGEST_PACKAGE = "org.bouncycastle.jcajce.provider.digest."; private static final String[] DIGESTS = - { - "GOST3411", "Keccak", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", - "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool", "Blake2b", "Blake2s", "DSTU7564", - "Haraka", "Blake3" - }; + { + "GOST3411", "Keccak", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", + "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool", "Blake2b", "Blake2s", "DSTU7564", + "Haraka", "Blake3" + }; /* * Configurable keystores */ private static final String KEYSTORE_PACKAGE = "org.bouncycastle.jcajce.provider.keystore."; private static final String[] KEYSTORES = - { - "BC", "BCFKS", "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" - }; + { + "DRBG" + }; + + /* + * Configurable kdfs + */ + private static final String KDF_PACKAGE = "org.bouncycastle.jcajce.provider.kdf."; + private static final String[] KDFS = + { + "HKDF", "PBEPBKDF2", "SCRYPT" + }; + + private Map serviceMap = new ConcurrentHashMap(); @@ -169,7 +183,7 @@ public final class BouncyCastleProvider extends Provider */ public BouncyCastleProvider() { - super(PROVIDER_NAME, 1.80, info); + super(PROVIDER_NAME, 1.8300, info); AccessController.doPrivileged(new PrivilegedAction() { @@ -199,6 +213,8 @@ private void setup() loadAlgorithms(SECURE_RANDOM_PACKAGE, SECURE_RANDOMS); + loadAlgorithms(KDF_PACKAGE, KDFS); + loadPQCKeys(); // so we can handle certificates containing them. // @@ -404,13 +420,16 @@ private void loadPQCKeys() addKeyInfoConverter(IsaraObjectIdentifiers.id_alg_xmssmt, new XMSSMTKeyFactorySpi()); addKeyInfoConverter(PKCSObjectIdentifiers.id_alg_hss_lms_hashsig, new LMSKeyFactorySpi()); addKeyInfoConverter(BCObjectIdentifiers.picnic_key, new PicnicKeyFactorySpi()); - addKeyInfoConverter(BCObjectIdentifiers.falcon_512, new FalconKeyFactorySpi()); - addKeyInfoConverter(BCObjectIdentifiers.falcon_1024, new FalconKeyFactorySpi()); addKeyInfoConverter(NISTObjectIdentifiers.id_alg_ml_kem_512, new MLKEMKeyFactorySpi()); addKeyInfoConverter(NISTObjectIdentifiers.id_alg_ml_kem_768, new MLKEMKeyFactorySpi()); addKeyInfoConverter(NISTObjectIdentifiers.id_alg_ml_kem_1024, new MLKEMKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.old_falcon_512, new FalconKeyFactorySpi(BCObjectIdentifiers.old_falcon_512)); + addKeyInfoConverter(BCObjectIdentifiers.old_falcon_1024, new FalconKeyFactorySpi(BCObjectIdentifiers.old_falcon_1024)); + addKeyInfoConverter(BCObjectIdentifiers.falcon_512, new FalconKeyFactorySpi(BCObjectIdentifiers.falcon_512)); + addKeyInfoConverter(BCObjectIdentifiers.falcon_1024, new FalconKeyFactorySpi(BCObjectIdentifiers.falcon_1024)); + addKeyInfoConverter(BCObjectIdentifiers.dilithium2, new DilithiumKeyFactorySpi()); addKeyInfoConverter(BCObjectIdentifiers.dilithium3, new DilithiumKeyFactorySpi()); addKeyInfoConverter(BCObjectIdentifiers.dilithium5, new DilithiumKeyFactorySpi()); @@ -437,6 +456,52 @@ private void loadPQCKeys() addKeyInfoConverter(BCObjectIdentifiers.ntruhps2048677, new NTRUKeyFactorySpi()); addKeyInfoConverter(BCObjectIdentifiers.ntruhps4096821, new NTRUKeyFactorySpi()); addKeyInfoConverter(BCObjectIdentifiers.ntruhrss701, new NTRUKeyFactorySpi()); + + addKeyInfoConverter(BCObjectIdentifiers.mayo1, new MayoKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.mayo2, new MayoKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.mayo3, new MayoKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.mayo5, new MayoKeyFactorySpi()); + + addKeyInfoConverter(BCObjectIdentifiers.snova_24_5_4_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_24_5_4_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_24_5_4_shake_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_24_5_4_shake_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_24_5_5_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_24_5_5_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_24_5_5_shake_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_24_5_5_shake_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_25_8_3_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_25_8_3_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_25_8_3_shake_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_25_8_3_shake_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_37_8_4_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_37_8_4_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_37_8_4_shake_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_37_8_4_shake_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_37_17_2_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_37_17_2_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_37_17_2_shake_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_37_17_2_shake_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_49_11_3_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_49_11_3_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_49_11_3_shake_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_49_11_3_shake_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_56_25_2_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_56_25_2_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_56_25_2_shake_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_56_25_2_shake_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_60_10_4_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_60_10_4_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_60_10_4_shake_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_60_10_4_shake_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_66_15_3_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_66_15_3_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_66_15_3_shake_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_66_15_3_shake_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_75_33_2_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_75_33_2_esk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_75_33_2_shake_ssk, new SnovaKeyFactorySpi()); + addKeyInfoConverter(BCObjectIdentifiers.snova_75_33_2_shake_esk, new SnovaKeyFactorySpi()); } public void setParameter(String parameterName, Object parameter) @@ -480,7 +545,7 @@ public void addAlgorithm(String type, ASN1ObjectIdentifier oid, String className addAttributes(type + "." + oid, attributes); addAttributes(type + ".OID." + oid, attributes); } - + public void addKeyInfoConverter(ASN1ObjectIdentifier oid, AsymmetricKeyInfoConverter keyInfoConverter) { synchronized (keyInfoConverters) diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/BrokenKDF2BytesGenerator.java b/prov/src/main/java/org/bouncycastle/jce/provider/BrokenKDF2BytesGenerator.java deleted file mode 100644 index 0f328f6078..0000000000 --- a/prov/src/main/java/org/bouncycastle/jce/provider/BrokenKDF2BytesGenerator.java +++ /dev/null @@ -1,128 +0,0 @@ -package org.bouncycastle.jce.provider; - -import org.bouncycastle.crypto.DataLengthException; -import org.bouncycastle.crypto.DerivationFunction; -import org.bouncycastle.crypto.DerivationParameters; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.OutputLengthException; -import org.bouncycastle.crypto.params.KDFParameters; - -/** - * Generator for PBE derived keys and ivs as defined by IEEE P1363a - *
    - * This implementation is based on draft 9 of IEEE P1363a. Note: - * as this is still a draft the output of this generator may change, don't - * use it for anything that might be subject to long term storage. - */ -public class BrokenKDF2BytesGenerator - implements DerivationFunction -{ - private Digest digest; - private byte[] shared; - private byte[] iv; - - /** - * Construct a KDF2 Parameters generator. Generates key material - * according to IEEE P1363a - if you want orthodox results you should - * use a digest specified in the standard. - *

    - * Note: IEEE P1363a standard is still a draft standard, if the standard - * changes this function, the output of this function will change as well. - * Don't use this routine for anything subject to long term storage. - * - * @param digest the digest to be used as the source of derived keys. - */ - public BrokenKDF2BytesGenerator( - Digest digest) - { - this.digest = digest; - } - - public void init( - DerivationParameters param) - { - if (!(param instanceof KDFParameters)) - { - throw new IllegalArgumentException("KDF parameters required for generator"); - } - - KDFParameters p = (KDFParameters)param; - - shared = p.getSharedSecret(); - iv = p.getIV(); - } - - /** - * return the underlying digest. - */ - public Digest getDigest() - { - return digest; - } - - /** - * fill len bytes of the output buffer with bytes generated from - * the derivation function. - * - * @throws IllegalArgumentException if the size of the request will cause an overflow. - * @throws DataLengthException if the out buffer is too small. - */ - public int generateBytes( - byte[] out, - int outOff, - int len) - throws DataLengthException, IllegalArgumentException - { - if ((out.length - len) < outOff) - { - throw new OutputLengthException("output buffer too small"); - } - - long oBits = len * 8L; - - // - // this is at odds with the standard implementation, the - // maximum value should be hBits * (2^32 - 1) where hBits - // is the digest output size in bits. We can't have an - // array with a long index at the moment... - // - if (oBits > (digest.getDigestSize() * 8L * (1L<<32 - 1))) - { - throw new IllegalArgumentException("Output length too large"); - } - - int cThreshold = (int)(oBits / digest.getDigestSize()); - - byte[] dig = null; - - dig = new byte[digest.getDigestSize()]; - - for (int counter = 1; counter <= cThreshold; counter++) - { - digest.update(shared, 0, shared.length); - - digest.update((byte)(counter & 0xff)); - digest.update((byte)((counter >> 8) & 0xff)); - digest.update((byte)((counter >> 16) & 0xff)); - digest.update((byte)((counter >> 24) & 0xff)); - - digest.update(iv, 0, iv.length); - - digest.doFinal(dig, 0); - - if ((len - outOff) > dig.length) - { - System.arraycopy(dig, 0, out, outOff, dig.length); - outOff += dig.length; - } - else - { - System.arraycopy(dig, 0, out, outOff, len - outOff); - } - } - - digest.reset(); - - return len; - } -} diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/BrokenPBE.java b/prov/src/main/java/org/bouncycastle/jce/provider/BrokenPBE.java index 509e76fc95..5495d89202 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/BrokenPBE.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/BrokenPBE.java @@ -267,8 +267,7 @@ static class Util * * @param bytes the byte array to set the parity on. */ - static private void setOddParity( - byte[] bytes) + private static void setOddParity(byte[] bytes) { for (int i = 0; i < bytes.length; i++) { @@ -284,9 +283,7 @@ static private void setOddParity( } } - static private PBEParametersGenerator makePBEGenerator( - int type, - int hash) + private static PBEParametersGenerator makePBEGenerator(int type, int hash) { PBEParametersGenerator generator; diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java b/prov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java index efb6ff6053..f74d047890 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java @@ -51,12 +51,9 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1String; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.style.RFC4519Style; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; import org.bouncycastle.asn1.x509.CRLDistPoint; import org.bouncycastle.asn1.x509.CRLReason; import org.bouncycastle.asn1.x509.DistributionPoint; @@ -64,7 +61,6 @@ import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralNames; -import org.bouncycastle.asn1.x509.PolicyInformation; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.internal.asn1.isismtt.ISISMTTObjectIdentifiers; import org.bouncycastle.jcajce.PKIXCRLStore; @@ -413,34 +409,65 @@ protected static final Set getQualifierSet(ASN1Sequence qualifiers) return pq; } - protected static PKIXPolicyNode removePolicyNode( - PKIXPolicyNode validPolicyTree, - List[] policyNodes, - PKIXPolicyNode _node) + static PKIXPolicyNode removeChildlessPolicyNodes(PKIXPolicyNode validPolicyTree, List[] policyNodes, int depthLimit) { - PKIXPolicyNode _parent = (PKIXPolicyNode)_node.getParent(); - if (validPolicyTree == null) { return null; } - if (_parent == null) + int i = depthLimit; + while (--i >= 0) { - for (int j = 0; j < policyNodes.length; j++) + List nodes_i = policyNodes[i]; + + int j = nodes_i.size(); + while (--j >= 0) { - policyNodes[j] = new ArrayList(); + PKIXPolicyNode node_j = (PKIXPolicyNode)nodes_i.get(j); + + if (node_j.hasChildren()) + { + continue; + } + + nodes_i.remove(j); + + PKIXPolicyNode parent = (PKIXPolicyNode)node_j.getParent(); + if (parent == null) + { + return null; + } + + parent.removeChild(node_j); } + } + + return validPolicyTree; + } + static PKIXPolicyNode removePolicyNode(PKIXPolicyNode validPolicyTree, List[] policyNodes, PKIXPolicyNode node) + { + if (validPolicyTree == null) + { return null; } - else + + PKIXPolicyNode parent = (PKIXPolicyNode)node.getParent(); + if (parent == null) { - _parent.removeChild(_node); - removePolicyNodeRecurse(policyNodes, _node); + for (int j = 0; j < policyNodes.length; j++) + { + policyNodes[j].clear(); + } - return validPolicyTree; + return null; } + + parent.removeChild(node); + removePolicyNodeRecurse(policyNodes, node); + + return validPolicyTree; } private static void removePolicyNodeRecurse( @@ -496,160 +523,21 @@ protected static boolean processCertD1i( return false; } - protected static void processCertD1ii( - int index, - List[] policyNodes, - ASN1ObjectIdentifier _poid, - Set _pq) - { - List policyNodeVec = policyNodes[index - 1]; - - for (int j = 0; j < policyNodeVec.size(); j++) - { - PKIXPolicyNode _node = (PKIXPolicyNode)policyNodeVec.get(j); - - if (ANY_POLICY.equals(_node.getValidPolicy())) - { - Set _childExpectedPolicies = new HashSet(); - _childExpectedPolicies.add(_poid.getId()); - - PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(), - index, - _childExpectedPolicies, - _node, - _pq, - _poid.getId(), - false); - _node.addChild(_child); - policyNodes[index].add(_child); - return; - } - } - } - - protected static void prepareNextCertB1( - int i, - List[] policyNodes, - String id_p, - Map m_idp, - X509Certificate cert - ) - throws AnnotatedException, CertPathValidatorException + static void processCertD1ii(int index, List[] policyNodes, ASN1ObjectIdentifier _poid, Set _pq) { - boolean idp_found = false; - Iterator nodes_i = policyNodes[i].iterator(); - while (nodes_i.hasNext()) + PKIXPolicyNode anyPolicyNode = findValidPolicy(policyNodes[index - 1].iterator(), ANY_POLICY); + if (anyPolicyNode != null) { - PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next(); - if (node.getValidPolicy().equals(id_p)) - { - idp_found = true; - node.expectedPolicies = (Set)m_idp.get(id_p); - break; - } - } + String policy = _poid.getId(); - if (!idp_found) - { - nodes_i = policyNodes[i].iterator(); - while (nodes_i.hasNext()) - { - PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next(); - if (ANY_POLICY.equals(node.getValidPolicy())) - { - Set pq = null; - ASN1Sequence policies = null; - try - { - policies = DERSequence.getInstance(getExtensionValue(cert, CERTIFICATE_POLICIES)); - } - catch (Exception e) - { - throw new AnnotatedException("Certificate policies cannot be decoded.", e); - } - Enumeration e = policies.getObjects(); - while (e.hasMoreElements()) - { - PolicyInformation pinfo = null; + Set _childExpectedPolicies = new HashSet(); + _childExpectedPolicies.add(policy); - try - { - pinfo = PolicyInformation.getInstance(e.nextElement()); - } - catch (Exception ex) - { - throw new AnnotatedException("Policy information cannot be decoded.", ex); - } - if (ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId())) - { - try - { - pq = getQualifierSet(pinfo.getPolicyQualifiers()); - } - catch (CertPathValidatorException ex) - { - throw new ExtCertPathValidatorException( - "Policy qualifier info set could not be built.", ex); - } - break; - } - } - boolean ci = false; - if (cert.getCriticalExtensionOIDs() != null) - { - ci = cert.getCriticalExtensionOIDs().contains(CERTIFICATE_POLICIES); - } - - PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent(); - if (ANY_POLICY.equals(p_node.getValidPolicy())) - { - PKIXPolicyNode c_node = new PKIXPolicyNode( - new ArrayList(), i, - (Set)m_idp.get(id_p), - p_node, pq, id_p, ci); - p_node.addChild(c_node); - policyNodes[i].add(c_node); - } - break; - } - } - } - } - - protected static PKIXPolicyNode prepareNextCertB2( - int i, - List[] policyNodes, - String id_p, - PKIXPolicyNode validPolicyTree) - { - Iterator nodes_i = policyNodes[i].iterator(); - while (nodes_i.hasNext()) - { - PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next(); - if (node.getValidPolicy().equals(id_p)) - { - PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent(); - p_node.removeChild(node); - nodes_i.remove(); - for (int k = (i - 1); k >= 0; k--) - { - List nodes = policyNodes[k]; - for (int l = 0; l < nodes.size(); l++) - { - PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l); - if (!node2.hasChildren()) - { - validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node2); - if (validPolicyTree == null) - { - break; - } - } - } - } - } + PKIXPolicyNode _child = new PKIXPolicyNode(new ArrayList(), index, _childExpectedPolicies, anyPolicyNode, + _pq, policy, false); + anyPolicyNode.addChild(_child); + policyNodes[index].add(_child); } - return validPolicyTree; } protected static boolean isAnyPolicy( @@ -981,10 +869,7 @@ else if (!PrincipalUtils.getEncodedIssuerPrincipal(cert).equals(PrincipalUtils.g ASN1Enumerated reasonCode = null; if (crl_entry.hasExtensions()) { - if (crl_entry.hasUnsupportedCriticalExtension()) - { - throw new AnnotatedException("CRL entry has unsupported critical extensions."); - } + checkCRLEntryCriticalExtensions(crl_entry, "CRL entry has unsupported critical extensions."); try { @@ -1079,13 +964,16 @@ protected static Set getDeltaCRLs(Date validityDate, // 5.2.4 (c) selBuilder.setMaxBaseCRLNumber(completeCRLNumber); + // NOTE: Does not restrict to critical DCI extension, so we filter non-critical ones later + selBuilder.setDeltaCRLIndicatorEnabled(true); + PKIXCRLStoreSelector deltaSelect = selBuilder.build(); // find delta CRLs - Set temp = PKIXCRLUtil.findCRLs(deltaSelect, validityDate, certStores, pkixCrlStores); + Set deltaCRLs = getDeltaCRLs(PKIXCRLUtil.findCRLs(deltaSelect, validityDate, certStores, pkixCrlStores)); // if the named CRL store is empty, and we're told to check with CRLDP - if (temp.isEmpty() && Properties.isOverrideSet("org.bouncycastle.x509.enableCRLDP")) + if (deltaCRLs.isEmpty() && Properties.isOverrideSet("org.bouncycastle.x509.enableCRLDP")) { CertificateFactory certFact; try @@ -1109,7 +997,7 @@ protected static Set getDeltaCRLs(Date validityDate, for (int j = 0; j < genNames.length; j++) { - GeneralName name = genNames[i]; + GeneralName name = genNames[j]; if (name.getTagNo() == GeneralName.uniformResourceIdentifier) { try @@ -1118,8 +1006,9 @@ protected static Set getDeltaCRLs(Date validityDate, new URI(((ASN1String)name.getName()).getString())); if (store != null) { - temp = PKIXCRLUtil.findCRLs(deltaSelect, validityDate, Collections.EMPTY_LIST, - Collections.singletonList(store)); + deltaCRLs = getDeltaCRLs( + PKIXCRLUtil.findCRLs(deltaSelect, validityDate, Collections.EMPTY_LIST, + Collections.singletonList(store))); } break; } @@ -1132,10 +1021,15 @@ protected static Set getDeltaCRLs(Date validityDate, } } } - + + return deltaCRLs; + } + + private static Set getDeltaCRLs(Set crls) + { Set result = new HashSet(); - for (Iterator it = temp.iterator(); it.hasNext(); ) + for (Iterator it = crls.iterator(); it.hasNext(); ) { X509CRL crl = (X509CRL)it.next(); @@ -1150,14 +1044,7 @@ protected static Set getDeltaCRLs(Date validityDate, private static boolean isDeltaCRL(X509CRL crl) { - Set critical = crl.getCriticalExtensionOIDs(); - - if (critical == null) - { - return false; - } - - return critical.contains(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR); + return hasCriticalExtension(crl, Extension.deltaCRLIndicator.getId()); } /** @@ -1345,23 +1232,26 @@ static Collection findIssuerCerts( "Subject criteria for certificate selector to find issuer certificate could not be set.", e); } - try - { - byte[] akiExtensionValue = cert.getExtensionValue(AUTHORITY_KEY_IDENTIFIER); - if (akiExtensionValue != null) - { - ASN1OctetString aki = ASN1OctetString.getInstance(akiExtensionValue); - byte[] authorityKeyIdentifier = AuthorityKeyIdentifier.getInstance(aki.getOctets()).getKeyIdentifier(); - if (authorityKeyIdentifier != null) - { - selector.setSubjectKeyIdentifier(new DEROctetString(authorityKeyIdentifier).getEncoded()); - } - } - } - catch (Exception e) - { - // authority key identifier could not be retrieved from target cert, just search without it - } + // RFC 4158: 3.5.12: explicitly disallows this - subject key identifier may be calculated differently +// try +// { +// byte[] akiExtValue = cert.getExtensionValue(AUTHORITY_KEY_IDENTIFIER); +// if (akiExtValue != null) +// { +// AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance( +// ASN1OctetString.getInstance(akiExtValue).getOctets()); +// +// ASN1OctetString keyIdentifier = aki.getKeyIdentifierObject(); +// if (keyIdentifier != null) +// { +// selector.setSubjectKeyIdentifier(keyIdentifier.getEncoded(ASN1Encoding.DER)); +// } +// } +// } +// catch (Exception e) +// { +// // authority key identifier could not be retrieved from target cert, just search without it +// } PKIXCertStoreSelector certSelect = new PKIXCertStoreSelector.Builder(selector).build(); Set certs = new LinkedHashSet(); @@ -1415,4 +1305,67 @@ static void checkCRLsNotEmpty(PKIXCertRevocationCheckerParameters params, Set cr } } } + + static void checkCRLCriticalExtensions(X509CRL crl, String exceptionMessage) + throws AnnotatedException + { + Set criticalExtensions = crl.getCriticalExtensionOIDs(); + if (criticalExtensions != null) + { + int count = criticalExtensions.size(); + if (count > 0) + { + if (criticalExtensions.contains(Extension.issuingDistributionPoint.getId())) + { + --count; + } + if (criticalExtensions.contains(Extension.deltaCRLIndicator.getId())) + { + --count; + } + + if (count > 0) + { + throw new AnnotatedException(exceptionMessage); + } + } + } + } + + static void checkCRLEntryCriticalExtensions(X509CRLEntry crlEntry, String exceptionMessage) + throws AnnotatedException + { + if (crlEntry.hasUnsupportedCriticalExtension()) + { + throw new AnnotatedException(exceptionMessage); + } + } + + static PKIXPolicyNode findValidPolicy(Iterator policyNodes, String policy) + { + while (policyNodes.hasNext()) + { + PKIXPolicyNode node = (PKIXPolicyNode)policyNodes.next(); + if (policy.equals(node.getValidPolicy())) + { + return node; + } + } + return null; + } + + static boolean hasCriticalExtension(X509Certificate cert, String extensionOID) + { + return hasCriticalExtension(cert.getCriticalExtensionOIDs(), extensionOID); + } + + static boolean hasCriticalExtension(X509CRL crl, String extensionOID) + { + return hasCriticalExtension(crl.getCriticalExtensionOIDs(), extensionOID); + } + + private static boolean hasCriticalExtension(Set criticalExtensionOIDs, String extensionOID) + { + return criticalExtensionOIDs != null && criticalExtensionOIDs.contains(extensionOID); + } } diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java b/prov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java index 222d656e87..65cf34cf4c 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/JCEECPrivateKey.java @@ -416,7 +416,7 @@ public int hashCode() public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append("EC Private Key").append(nl); diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java b/prov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java index d8276b2c5d..cdf75beb09 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/JCEECPublicKey.java @@ -450,7 +450,7 @@ org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec() public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append("EC Public Key").append(nl); diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java b/prov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java index 40f007f3d7..27fc10cfa2 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey.java @@ -224,7 +224,7 @@ public boolean equals(Object o) public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append("RSA Private CRT Key").append(nl); diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java b/prov/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java index adf0e3e8e2..b4befdde75 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/JCERSAPublicKey.java @@ -118,7 +118,7 @@ public boolean equals(Object o) public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append("RSA Public Key").append(nl); diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java b/prov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java index 95a1ad7467..69489b19b9 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/JDKDSAPublicKey.java @@ -126,7 +126,7 @@ public BigInteger getY() public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append("DSA Public Key").append(nl); diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java b/prov/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java index d89e920dff..d54aa2d25b 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/PKIXPolicyNode.java @@ -53,37 +53,37 @@ public Iterator getChildren() { return children.iterator(); } - + public int getDepth() { return depth; } - + public Set getExpectedPolicies() { return expectedPolicies; } - + public PolicyNode getParent() { return parent; } - + public Set getPolicyQualifiers() { return policyQualifiers; } - + public String getValidPolicy() { return validPolicy; } - + public boolean hasChildren() { return !children.isEmpty(); } - + public boolean isCritical() { return critical; @@ -98,7 +98,12 @@ public void setCritical(boolean _critical) { critical = _critical; } - + + public void setExpectedPolicies(Set expectedPolicies) + { + this.expectedPolicies = expectedPolicies; + } + public void setParent(PKIXPolicyNode _parent) { parent = _parent; @@ -125,49 +130,39 @@ public String toString(String _indent) _buf.append("}\n"); return _buf.toString(); } - + + // TODO[api] Maybe remove this, the 'clone' loses its parent public Object clone() { return copy(); } - + public PKIXPolicyNode copy() { - Set _expectedPolicies = new HashSet(); + Set _expectedPolicies = new HashSet(); Iterator _iter = expectedPolicies.iterator(); while (_iter.hasNext()) { - _expectedPolicies.add(new String((String)_iter.next())); + _expectedPolicies.add(_iter.next()); } - - Set _policyQualifiers = new HashSet(); + + Set _policyQualifiers = new HashSet(); _iter = policyQualifiers.iterator(); while (_iter.hasNext()) { - _policyQualifiers.add(new String((String)_iter.next())); + _policyQualifiers.add(_iter.next()); } - - PKIXPolicyNode _node = new PKIXPolicyNode(new ArrayList(), - depth, - _expectedPolicies, - null, - _policyQualifiers, - new String(validPolicy), - critical); - + + PKIXPolicyNode copy = new PKIXPolicyNode(new ArrayList(), depth, _expectedPolicies, null, _policyQualifiers, + validPolicy, critical); + _iter = children.iterator(); while (_iter.hasNext()) { - PKIXPolicyNode _child = ((PKIXPolicyNode)_iter.next()).copy(); - _child.setParent(_node); - _node.addChild(_child); + PKIXPolicyNode child = (PKIXPolicyNode)_iter.next(); + copy.addChild(child.copy()); } - - return _node; - } - public void setExpectedPolicies(Set expectedPolicies) - { - this.expectedPolicies = expectedPolicies; + return copy; } } diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java b/prov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java index befb795385..09c146283c 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java @@ -808,176 +808,148 @@ protected static PKIXPolicyNode prepareCertB( int i = n - index; // (b) // - ASN1Sequence pm = null; + ASN1Sequence mappings; try { - pm = ASN1Sequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, - RFC3280CertPathUtilities.POLICY_MAPPINGS)); + mappings = ASN1Sequence.getInstance(CertPathValidatorUtilities.getExtensionValue(cert, POLICY_MAPPINGS)); } catch (AnnotatedException ex) { throw new ExtCertPathValidatorException("Policy mappings extension could not be decoded.", ex, certPath, index); } - PKIXPolicyNode _validPolicyTree = validPolicyTree; - if (pm != null) + + if (mappings != null) { - ASN1Sequence mappings = (ASN1Sequence)pm; - Map m_idp = new HashMap(); - Set s_idp = new HashSet(); + HashMap m_idp = new HashMap(); for (int j = 0; j < mappings.size(); j++) { ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j); String id_p = ((ASN1ObjectIdentifier)mapping.getObjectAt(0)).getId(); String sd_p = ((ASN1ObjectIdentifier)mapping.getObjectAt(1)).getId(); - Set tmp; - if (!m_idp.containsKey(id_p)) + HashSet tmp = (HashSet)m_idp.get(id_p); + if (tmp == null) { tmp = new HashSet(); - tmp.add(sd_p); m_idp.put(id_p, tmp); - s_idp.add(id_p); - } - else - { - tmp = (Set)m_idp.get(id_p); - tmp.add(sd_p); } + + tmp.add(sd_p); } - Iterator it_idp = s_idp.iterator(); + Iterator it_idp = m_idp.entrySet().iterator(); while (it_idp.hasNext()) { - String id_p = (String)it_idp.next(); + Map.Entry e_idp = (Map.Entry)it_idp.next(); + + String id_p = (String)e_idp.getKey(); + HashSet expectedPolicies = (HashSet)e_idp.getValue(); // - // (1) + // (2) // - if (policyMapping > 0) + if (policyMapping <= 0) { - boolean idp_found = false; - Iterator nodes_i = policyNodes[i].iterator(); - while (nodes_i.hasNext()) + List nodes_i = policyNodes[i]; + + int j = nodes_i.size(); + while (--j >= 0) { - PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next(); - if (node.getValidPolicy().equals(id_p)) + PKIXPolicyNode node_j = (PKIXPolicyNode)nodes_i.get(j); + if (node_j.getValidPolicy().equals(id_p)) { - idp_found = true; - node.expectedPolicies = (Set)m_idp.get(id_p); - break; + PKIXPolicyNode p_node = (PKIXPolicyNode)node_j.getParent(); + p_node.removeChild(node_j); + nodes_i.remove(j); } } - if (!idp_found) - { - nodes_i = policyNodes[i].iterator(); - while (nodes_i.hasNext()) - { - PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next(); - if (RFC3280CertPathUtilities.ANY_POLICY.equals(node.getValidPolicy())) - { - Set pq = null; - ASN1Sequence policies = null; - try - { - policies = (ASN1Sequence)CertPathValidatorUtilities.getExtensionValue(cert, - RFC3280CertPathUtilities.CERTIFICATE_POLICIES); - } - catch (AnnotatedException e) - { - throw new ExtCertPathValidatorException( - "Certificate policies extension could not be decoded.", e, certPath, index); - } - Enumeration e = policies.getObjects(); - while (e.hasMoreElements()) - { - PolicyInformation pinfo = null; - try - { - pinfo = PolicyInformation.getInstance(e.nextElement()); - } - catch (Exception ex) - { - throw new CertPathValidatorException( - "Policy information could not be decoded.", ex, certPath, index); - } - if (RFC3280CertPathUtilities.ANY_POLICY.equals(pinfo.getPolicyIdentifier().getId())) - { - try - { - pq = CertPathValidatorUtilities - .getQualifierSet(pinfo.getPolicyQualifiers()); - } - catch (CertPathValidatorException ex) - { - - throw new ExtCertPathValidatorException( - "Policy qualifier info set could not be decoded.", ex, certPath, - index); - } - break; - } - } - boolean ci = false; - if (cert.getCriticalExtensionOIDs() != null) - { - ci = cert.getCriticalExtensionOIDs().contains( - RFC3280CertPathUtilities.CERTIFICATE_POLICIES); - } + validPolicyTree = CertPathValidatorUtilities.removeChildlessPolicyNodes(validPolicyTree, + policyNodes, i); - PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent(); - if (RFC3280CertPathUtilities.ANY_POLICY.equals(p_node.getValidPolicy())) - { - PKIXPolicyNode c_node = new PKIXPolicyNode(new ArrayList(), i, (Set)m_idp - .get(id_p), p_node, pq, id_p, ci); - p_node.addChild(c_node); - policyNodes[i].add(c_node); - } - break; - } - } - } + continue; + } - // - // (2) - // + // + // (1) + // +// assert policyMapping > 0; + + PKIXPolicyNode validPolicyNode = CertPathValidatorUtilities.findValidPolicy( + policyNodes[i].iterator(), id_p); + + if (validPolicyNode != null) + { + validPolicyNode.setExpectedPolicies(expectedPolicies); + continue; + } + + PKIXPolicyNode anyPolicyNode = CertPathValidatorUtilities.findValidPolicy( + policyNodes[i].iterator(), ANY_POLICY); + + if (anyPolicyNode == null) + { + continue; + } + + ASN1Sequence policies; + try + { + policies = ASN1Sequence.getInstance( + CertPathValidatorUtilities.getExtensionValue(cert, CERTIFICATE_POLICIES)); + } + catch (AnnotatedException e) + { + throw new ExtCertPathValidatorException( + "Certificate policies extension could not be decoded.", e, certPath, index); } - else if (policyMapping <= 0) + + Set pq = null; + + Enumeration e = policies.getObjects(); + while (e.hasMoreElements()) { - Iterator nodes_i = policyNodes[i].iterator(); - while (nodes_i.hasNext()) + PolicyInformation policyInformation; + try + { + policyInformation = PolicyInformation.getInstance(e.nextElement()); + } + catch (Exception ex) { - PKIXPolicyNode node = (PKIXPolicyNode)nodes_i.next(); - if (node.getValidPolicy().equals(id_p)) + throw new CertPathValidatorException("Policy information could not be decoded.", ex, certPath, + index); + } + + if (ANY_POLICY.equals(policyInformation.getPolicyIdentifier().getId())) + { + try { - PKIXPolicyNode p_node = (PKIXPolicyNode)node.getParent(); - p_node.removeChild(node); - nodes_i.remove(); - for (int k = (i - 1); k >= 0; k--) - { - List nodes = policyNodes[k]; - for (int l = 0; l < nodes.size(); l++) - { - PKIXPolicyNode node2 = (PKIXPolicyNode)nodes.get(l); - if (!node2.hasChildren()) - { - _validPolicyTree = CertPathValidatorUtilities.removePolicyNode( - _validPolicyTree, policyNodes, node2); - if (_validPolicyTree == null) - { - break; - } - } - } - } + pq = CertPathValidatorUtilities.getQualifierSet(policyInformation.getPolicyQualifiers()); } + catch (CertPathValidatorException ex) + { + throw new ExtCertPathValidatorException("Policy qualifier info set could not be decoded.", + ex, certPath, index); + } + break; } } + + boolean critical = CertPathValidatorUtilities.hasCriticalExtension(cert, CERTIFICATE_POLICIES); + + PKIXPolicyNode p_node = (PKIXPolicyNode)anyPolicyNode.getParent(); + if (ANY_POLICY.equals(p_node.getValidPolicy())) + { + PKIXPolicyNode c_node = new PKIXPolicyNode(new ArrayList(), i, expectedPolicies, p_node, pq, id_p, + critical); + p_node.addChild(c_node); + policyNodes[i].add(c_node); + } } } - return _validPolicyTree; + return validPolicyTree; } protected static void prepareNextCertA( @@ -1322,20 +1294,10 @@ else if (_tmp instanceof ASN1ObjectIdentifier) continue; } - boolean _found = false; - Iterator _childrenIter = _node.getChildren(); + PKIXPolicyNode validPolicyChild = CertPathValidatorUtilities.findValidPolicy( + _node.getChildren(), _policy); - while (_childrenIter.hasNext()) - { - PKIXPolicyNode _child = (PKIXPolicyNode)_childrenIter.next(); - - if (_policy.equals(_child.getValidPolicy())) - { - _found = true; - } - } - - if (!_found) + if (validPolicyChild == null) { Set _newChildExpectedPolicies = new HashSet(); _newChildExpectedPolicies.add(_policy); @@ -1352,46 +1314,24 @@ else if (_tmp instanceof ASN1ObjectIdentifier) } } - PKIXPolicyNode _validPolicyTree = validPolicyTree; // // (d) (3) // - for (int j = (i - 1); j >= 0; j--) - { - List nodes = policyNodes[j]; - - for (int k = 0; k < nodes.size(); k++) - { - PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k); - if (!node.hasChildren()) - { - _validPolicyTree = CertPathValidatorUtilities.removePolicyNode(_validPolicyTree, policyNodes, - node); - if (_validPolicyTree == null) - { - break; - } - } - } - } + validPolicyTree = CertPathValidatorUtilities.removeChildlessPolicyNodes(validPolicyTree, policyNodes, i); // // d (4) // - Set criticalExtensionOids = cert.getCriticalExtensionOIDs(); - - if (criticalExtensionOids != null) + if (CertPathValidatorUtilities.hasCriticalExtension(cert, CERTIFICATE_POLICIES)) { - boolean critical = criticalExtensionOids.contains(RFC3280CertPathUtilities.CERTIFICATE_POLICIES); - List nodes = policyNodes[i]; for (int j = 0; j < nodes.size(); j++) { PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(j); - node.setCritical(critical); + node.setCritical(true); } } - return _validPolicyTree; + return validPolicyTree; } return null; } @@ -1800,32 +1740,13 @@ private static void checkCRL( // update reasons mask reasonMask.addReasons(interimReasonsMask); - Set criticalExtensions = crl.getCriticalExtensionOIDs(); - if (criticalExtensions != null) - { - criticalExtensions = new HashSet(criticalExtensions); - criticalExtensions.remove(Extension.issuingDistributionPoint.getId()); - criticalExtensions.remove(Extension.deltaCRLIndicator.getId()); - - if (!criticalExtensions.isEmpty()) - { - throw new AnnotatedException("CRL contains unsupported critical extensions."); - } - } + CertPathValidatorUtilities.checkCRLCriticalExtensions(crl, + "CRL contains unsupported critical extensions."); if (deltaCRL != null) { - criticalExtensions = deltaCRL.getCriticalExtensionOIDs(); - if (criticalExtensions != null) - { - criticalExtensions = new HashSet(criticalExtensions); - criticalExtensions.remove(Extension.issuingDistributionPoint.getId()); - criticalExtensions.remove(Extension.deltaCRLIndicator.getId()); - if (!criticalExtensions.isEmpty()) - { - throw new AnnotatedException("Delta CRL contains unsupported critical extension."); - } - } + CertPathValidatorUtilities.checkCRLCriticalExtensions(deltaCRL, + "Delta CRL contains unsupported critical extensions."); } validCrlFound = true; @@ -2392,8 +2313,7 @@ protected static PKIXPolicyNode wrapupCertG( } intersection = null; } - else if (CertPathValidatorUtilities.isAnyPolicy(userInitialPolicySet)) // (g) - // (ii) + else if (CertPathValidatorUtilities.isAnyPolicy(userInitialPolicySet)) // (g) (ii) { if (paramsPKIX.isExplicitPolicyRequired()) { @@ -2402,60 +2322,45 @@ else if (CertPathValidatorUtilities.isAnyPolicy(userInitialPolicySet)) // (g) throw new ExtCertPathValidatorException("Explicit policy requested but none available.", null, certPath, index); } - else + + Set _validPolicyNodeSet = new HashSet(); + + for (int j = 0; j < policyNodes.length; j++) { - Set _validPolicyNodeSet = new HashSet(); + List _nodeDepth = policyNodes[j]; - for (int j = 0; j < policyNodes.length; j++) + for (int k = 0; k < _nodeDepth.size(); k++) { - List _nodeDepth = policyNodes[j]; + PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k); - for (int k = 0; k < _nodeDepth.size(); k++) + if (ANY_POLICY.equals(_node.getValidPolicy())) { - PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k); - - if (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy())) + Iterator _iter = _node.getChildren(); + while (_iter.hasNext()) { - Iterator _iter = _node.getChildren(); - while (_iter.hasNext()) - { - _validPolicyNodeSet.add(_iter.next()); - } + _validPolicyNodeSet.add(_iter.next()); } + + // TODO[pkix] break if there can only be one ANY_POLICY node at this depth? (use findValidPolicy) } } + } - Iterator _vpnsIter = _validPolicyNodeSet.iterator(); - while (_vpnsIter.hasNext()) - { - PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next(); - String _validPolicy = _node.getValidPolicy(); + Iterator _vpnsIter = _validPolicyNodeSet.iterator(); + while (_vpnsIter.hasNext()) + { + PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next(); + String _validPolicy = _node.getValidPolicy(); - if (!acceptablePolicies.contains(_validPolicy)) - { - // validPolicyTree = - // removePolicyNode(validPolicyTree, policyNodes, - // _node); - } - } - if (validPolicyTree != null) + if (!acceptablePolicies.contains(_validPolicy)) { - for (int j = (n - 1); j >= 0; j--) - { - List nodes = policyNodes[j]; - - for (int k = 0; k < nodes.size(); k++) - { - PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k); - if (!node.hasChildren()) - { - validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, - policyNodes, node); - } - } - } + // TODO? + // validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, + // _node); } } + + validPolicyTree = CertPathValidatorUtilities.removeChildlessPolicyNodes(validPolicyTree, policyNodes, n); } intersection = validPolicyTree; @@ -2485,17 +2390,19 @@ else if (CertPathValidatorUtilities.isAnyPolicy(userInitialPolicySet)) // (g) { PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k); - if (RFC3280CertPathUtilities.ANY_POLICY.equals(_node.getValidPolicy())) + if (ANY_POLICY.equals(_node.getValidPolicy())) { Iterator _iter = _node.getChildren(); while (_iter.hasNext()) { PKIXPolicyNode _c_node = (PKIXPolicyNode)_iter.next(); - if (!RFC3280CertPathUtilities.ANY_POLICY.equals(_c_node.getValidPolicy())) + if (!ANY_POLICY.equals(_c_node.getValidPolicy())) { _validPolicyNodeSet.add(_c_node); } } + + // TODO[pkix] break if there can only be one ANY_POLICY node at this depth? (use findValidPolicy) } } } @@ -2518,27 +2425,10 @@ else if (CertPathValidatorUtilities.isAnyPolicy(userInitialPolicySet)) // (g) // // (g) (iii) 4 // - if (validPolicyTree != null) - { - for (int j = (n - 1); j >= 0; j--) - { - List nodes = policyNodes[j]; - - for (int k = 0; k < nodes.size(); k++) - { - PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k); - if (!node.hasChildren()) - { - validPolicyTree = CertPathValidatorUtilities.removePolicyNode(validPolicyTree, policyNodes, - node); - } - } - } - } + validPolicyTree = CertPathValidatorUtilities.removeChildlessPolicyNodes(validPolicyTree, policyNodes, n); intersection = validPolicyTree; } return intersection; } - } diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java b/prov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java index bbfacab4cb..e941c1e9b3 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/X509CRLEntryObject.java @@ -15,6 +15,7 @@ import org.bouncycastle.asn1.ASN1Enumerated; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.util.ASN1Dump; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.CRLReason; @@ -77,9 +78,9 @@ public X509CRLEntryObject( */ public boolean hasUnsupportedCriticalExtension() { - Set extns = getCriticalExtensionOIDs(); + Extensions extensions = c.getExtensions(); - return extns != null && !extns.isEmpty(); + return extensions != null && extensions.hasAnyCriticalExtensions(); } private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer) @@ -89,15 +90,15 @@ private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCert return null; } - Extension ext = getExtension(Extension.certificateIssuer); - if (ext == null) + ASN1OctetString extValue = Extensions.getExtensionValue(c.getExtensions(), Extension.certificateIssuer); + if (extValue == null) { return previousCertificateIssuer; } try { - GeneralName[] names = GeneralNames.getInstance(ext.getParsedValue()).getNames(); + GeneralName[] names = GeneralNames.getInstance(extValue.getOctets()).getNames(); for (int i = 0; i < names.length; i++) { if (names[i].getTagNo() == GeneralName.directoryName) @@ -165,35 +166,9 @@ public Set getNonCriticalExtensionOIDs() return getExtensionOIDs(false); } - private Extension getExtension(ASN1ObjectIdentifier oid) - { - Extensions exts = c.getExtensions(); - - if (exts != null) - { - return exts.getExtension(oid); - } - - return null; - } - public byte[] getExtensionValue(String oid) { - Extension ext = getExtension(new ASN1ObjectIdentifier(oid)); - - if (ext != null) - { - try - { - return ext.getExtnValue().getEncoded(); - } - catch (Exception e) - { - throw new RuntimeException("error encoding " + e.toString()); - } - } - - return null; + return X509SignatureUtil.getExtensionValue(c.getExtensions(), oid); } /** @@ -258,7 +233,7 @@ public boolean hasExtensions() public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append(" userCertificate: ").append(this.getSerialNumber()).append(nl); diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java b/prov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java index 5b32a13225..1b424fdf3a 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/X509CRLObject.java @@ -41,7 +41,9 @@ import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.IssuingDistributionPoint; import org.bouncycastle.asn1.x509.TBSCertList; +import org.bouncycastle.asn1.x509.Time; import org.bouncycastle.jce.X509Principal; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; @@ -108,30 +110,41 @@ public X509CRLObject( } } - /** - * Will return true if any extensions are present and marked - * as critical as we currently dont handle any extensions! - */ public boolean hasUnsupportedCriticalExtension() { - Set extns = getCriticalExtensionOIDs(); - - if (extns == null) + if (getVersion() == 2) { - return false; - } + Extensions extensions = c.getExtensions(); + if (extensions != null) + { + Enumeration e = extensions.oids(); + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT); - extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR); + if (Extension.issuingDistributionPoint.equals(oid) || + Extension.deltaCRLIndicator.equals(oid)) + { + continue; + } - return !extns.isEmpty(); + Extension ext = extensions.getExtension(oid); + if (ext.isCritical()) + { + return true; + } + } + } + } + + return false; } private Set getExtensionOIDs(boolean critical) { if (this.getVersion() == 2) { - Extensions extensions = c.getTBSCertList().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -168,26 +181,7 @@ public Set getNonCriticalExtensionOIDs() public byte[] getExtensionValue(String oid) { - Extensions exts = c.getTBSCertList().getExtensions(); - - if (exts != null) - { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - - if (ext != null) - { - try - { - return ext.getExtnValue().getEncoded(); - } - catch (Exception e) - { - throw new IllegalStateException("error parsing " + e.toString()); - } - } - } - - return null; + return X509SignatureUtil.getExtensionValue(c.getExtensions(), oid); } public byte[] getEncoded() @@ -304,14 +298,11 @@ public Date getThisUpdate() public Date getNextUpdate() { - if (c.getNextUpdate() != null) - { - return c.getNextUpdate().getDate(); - } + Time nextUpdate = c.getNextUpdate(); - return null; + return null == nextUpdate ? null : nextUpdate.getDate(); } - + private Set loadCRLEntries() { Set entrySet = new HashSet(); @@ -407,16 +398,7 @@ public String getSigAlgOID() public byte[] getSigAlgParams() { - if (sigAlgParams != null) - { - byte[] tmp = new byte[sigAlgParams.length]; - - System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length); - - return tmp; - } - - return null; + return Arrays.clone(sigAlgParams); } /** @@ -426,7 +408,7 @@ public byte[] getSigAlgParams() */ public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append(" Version: ").append(this.getVersion()).append( @@ -458,7 +440,7 @@ public String toString() } } - Extensions extensions = c.getTBSCertList().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java b/prov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java index 3954e217a6..e856a31bbd 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java @@ -38,6 +38,7 @@ import org.bouncycastle.asn1.ASN1InputStream; 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.ASN1String; @@ -87,7 +88,7 @@ public X509CertificateObject( try { - byte[] bytes = this.getExtensionBytes("2.5.29.19"); + byte[] bytes = getExtensionOctets(c, Extension.basicConstraints); if (bytes != null) { @@ -101,7 +102,7 @@ public X509CertificateObject( try { - byte[] bytes = this.getExtensionBytes("2.5.29.15"); + byte[] bytes = getExtensionOctets(c, Extension.keyUsage); if (bytes != null) { ASN1BitString bits = ASN1BitString.getInstance(ASN1Primitive.fromByteArray(bytes)); @@ -333,32 +334,29 @@ public boolean[] getKeyUsage() public List getExtendedKeyUsage() throws CertificateParsingException { - byte[] bytes = this.getExtensionBytes("2.5.29.37"); + byte[] extOctets = getExtensionOctets(c, Extension.extendedKeyUsage); + if (null == extOctets) + { + return null; + } - if (bytes != null) + try { - try - { - ASN1InputStream dIn = new ASN1InputStream(bytes); - ASN1Sequence seq = (ASN1Sequence)dIn.readObject(); - List list = new ArrayList(); + ASN1Sequence seq = ASN1Sequence.getInstance(extOctets); - for (int i = 0; i != seq.size(); i++) - { - list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId()); - } - - return Collections.unmodifiableList(list); - } - catch (Exception e) + List list = new ArrayList(); + for (int i = 0; i != seq.size(); i++) { - throw new CertificateParsingException("error processing extended key usage extension"); + list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId()); } + return Collections.unmodifiableList(list); + } + catch (Exception e) + { + throw new CertificateParsingException("error processing extended key usage extension"); } - - return null; } - + public int getBasicConstraints() { if (basicConstraints == null || !basicConstraints.isCA()) @@ -378,13 +376,13 @@ public int getBasicConstraints() public Collection getSubjectAlternativeNames() throws CertificateParsingException { - return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId())); + return getAlternativeNames(c, Extension.subjectAlternativeName); } public Collection getIssuerAlternativeNames() throws CertificateParsingException { - return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId())); + return getAlternativeNames(c, Extension.issuerAlternativeName); } public Set getCriticalExtensionOIDs() @@ -392,7 +390,7 @@ public Set getCriticalExtensionOIDs() if (this.getVersion() == 3) { Set set = new HashSet(); - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -416,44 +414,9 @@ public Set getCriticalExtensionOIDs() return null; } - private byte[] getExtensionBytes(String oid) - { - Extensions exts = c.getTBSCertificate().getExtensions(); - - if (exts != null) - { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - if (ext != null) - { - return ext.getExtnValue().getOctets(); - } - } - - return null; - } - public byte[] getExtensionValue(String oid) { - Extensions exts = c.getTBSCertificate().getExtensions(); - - if (exts != null) - { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - - if (ext != null) - { - try - { - return ext.getExtnValue().getEncoded(); - } - catch (Exception e) - { - throw new IllegalStateException("error parsing " + e.toString()); - } - } - } - - return null; + return X509SignatureUtil.getExtensionValue(c.getExtensions(), oid); } public Set getNonCriticalExtensionOIDs() @@ -461,7 +424,7 @@ public Set getNonCriticalExtensionOIDs() if (this.getVersion() == 3) { Set set = new HashSet(); - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -487,36 +450,32 @@ public Set getNonCriticalExtensionOIDs() public boolean hasUnsupportedCriticalExtension() { - if (this.getVersion() == 3) + if (getVersion() == 3) { - Extensions extensions = c.getTBSCertificate().getExtensions(); - + Extensions extensions = c.getExtensions(); if (extensions != null) { - Enumeration e = extensions.oids(); - + Enumeration e = extensions.oids(); while (e.hasMoreElements()) { ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - String oidId = oid.getId(); - - if (oidId.equals(RFC3280CertPathUtilities.KEY_USAGE) - || oidId.equals(RFC3280CertPathUtilities.CERTIFICATE_POLICIES) - || oidId.equals(RFC3280CertPathUtilities.POLICY_MAPPINGS) - || oidId.equals(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY) - || oidId.equals(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS) - || oidId.equals(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT) - || oidId.equals(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR) - || oidId.equals(RFC3280CertPathUtilities.POLICY_CONSTRAINTS) - || oidId.equals(RFC3280CertPathUtilities.BASIC_CONSTRAINTS) - || oidId.equals(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME) - || oidId.equals(RFC3280CertPathUtilities.NAME_CONSTRAINTS)) + + if (Extension.keyUsage.equals(oid) || + Extension.certificatePolicies.equals(oid) || + Extension.policyMappings.equals(oid) || + Extension.inhibitAnyPolicy.equals(oid) || + Extension.cRLDistributionPoints.equals(oid) || + Extension.issuingDistributionPoint.equals(oid) || + Extension.deltaCRLIndicator.equals(oid) || + Extension.policyConstraints.equals(oid) || + Extension.basicConstraints.equals(oid) || + Extension.subjectAlternativeName.equals(oid) || + Extension.nameConstraints.equals(oid)) { continue; } - Extension ext = extensions.getExtension(oid); - + Extension ext = extensions.getExtension(oid); if (ext.isCritical()) { return true; @@ -640,7 +599,7 @@ public void setFriendlyName(String friendlyName) public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append(" [0] Version: ").append(this.getVersion()).append(nl); @@ -667,7 +626,7 @@ public String toString() } } - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -852,17 +811,18 @@ private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2) return id1.getParameters().equals(id2.getParameters()); } - private static Collection getAlternativeNames(byte[] extVal) + private static Collection getAlternativeNames(org.bouncycastle.asn1.x509.Certificate c, ASN1ObjectIdentifier oid) throws CertificateParsingException { - if (extVal == null) + byte[] extOctets = getExtensionOctets(c, oid); + if (extOctets == null) { return null; } try { Collection temp = new ArrayList(); - Enumeration it = ASN1Sequence.getInstance(extVal).getObjects(); + Enumeration it = ASN1Sequence.getInstance(extOctets).getObjects(); while (it.hasMoreElements()) { GeneralName genName = GeneralName.getInstance(it.nextElement()); @@ -916,4 +876,11 @@ private static Collection getAlternativeNames(byte[] extVal) throw new CertificateParsingException(e.getMessage()); } } + + private static byte[] getExtensionOctets(org.bouncycastle.asn1.x509.Certificate c, ASN1ObjectIdentifier oid) + { + ASN1OctetString extValue = Extensions.getExtensionValue(c.getExtensions(), oid); + + return extValue == null ? null : extValue.getOctets(); + } } diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/X509LDAPCertStoreSpi.java b/prov/src/main/java/org/bouncycastle/jce/provider/X509LDAPCertStoreSpi.java index 5789fd1714..91e4150afc 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/X509LDAPCertStoreSpi.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/X509LDAPCertStoreSpi.java @@ -34,6 +34,7 @@ import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.x509.CertificatePair; import org.bouncycastle.jce.X509LDAPCertStoreParameters; +import org.bouncycastle.ldap.LDAPUtils; import org.bouncycastle.util.Strings; /** @@ -50,26 +51,6 @@ public class X509LDAPCertStoreSpi extends CertStoreSpi { - private static String[] FILTER_ESCAPE_TABLE = new String['\\' + 1]; - - static - { - // Filter encoding table ------------------------------------- - - // fill with char itself - for (char c = 0; c < FILTER_ESCAPE_TABLE.length; c++) - { - FILTER_ESCAPE_TABLE[c] = String.valueOf(c); - } - - // escapes (RFC2254) - FILTER_ESCAPE_TABLE['*'] = "\\2a"; - FILTER_ESCAPE_TABLE['('] = "\\28"; - FILTER_ESCAPE_TABLE[')'] = "\\29"; - FILTER_ESCAPE_TABLE['\\'] = "\\5c"; - FILTER_ESCAPE_TABLE[0] = "\\00"; - } - /** * Initial Context Factory. */ @@ -124,42 +105,6 @@ private DirContext connectLDAP() return ctx; } - private String parseDN(String subject, String subjectAttributeName) - { - String temp = subject; - int begin = Strings.toLowerCase(temp).indexOf(Strings.toLowerCase(subjectAttributeName)); - temp = temp.substring(begin + subjectAttributeName.length()); - int end = temp.indexOf(','); - if (end == -1) - { - end = temp.length(); - } - while (temp.charAt(end - 1) == '\\') - { - end = temp.indexOf(',', end + 1); - if (end == -1) - { - end = temp.length(); - } - } - temp = temp.substring(0, end); - begin = temp.indexOf('='); - temp = temp.substring(begin + 1); - if (temp.charAt(0) == ' ') - { - temp = temp.substring(1); - } - if (temp.startsWith("\"")) - { - temp = temp.substring(1); - } - if (temp.endsWith("\"")) - { - temp = temp.substring(0, temp.length() - 1); - } - return filterEncode(temp); - } - public Collection engineGetCertificates(CertSelector selector) throws CertStoreException { @@ -277,7 +222,7 @@ private Set certSubjectSerialSearch(X509CertSelector xselector, subject = xselector.getSubjectAsString(); } } - String attrValue = parseDN(subject, subjectAttributeName); + String attrValue = LDAPUtils.parseDN(subject, subjectAttributeName); set.addAll(search(attrName, "*" + attrValue + "*", attrs)); if (serial != null && params.getSearchForSerialNumberIn() != null) @@ -374,13 +319,13 @@ public Collection engineGetCRLs(CRLSelector selector) { String issuerAttributeName = params .getCertificateRevocationListIssuerAttributeName(); - attrValue = parseDN((String)o, issuerAttributeName); + attrValue = LDAPUtils.parseDN((String)o, issuerAttributeName); } else { String issuerAttributeName = params .getCertificateRevocationListIssuerAttributeName(); - attrValue = parseDN(new X500Principal((byte[])o) + attrValue = LDAPUtils.parseDN(new X500Principal((byte[])o) .getName("RFC1779"), issuerAttributeName); } set.addAll(search(attrName, "*" + attrValue + "*", attrs)); @@ -415,43 +360,7 @@ public Collection engineGetCRLs(CRLSelector selector) return crlSet; } - - /** - * Escape a value for use in a filter. - * - * @param value the value to escape. - * @return a properly escaped representation of the supplied value. - */ - private String filterEncode(String value) - { - if (value == null) - { - return null; - } - - // make buffer roomy - StringBuilder encodedValue = new StringBuilder(value.length() * 2); - - int length = value.length(); - - for (int i = 0; i < length; i++) - { - char c = value.charAt(i); - - if (c < FILTER_ESCAPE_TABLE.length) - { - encodedValue.append(FILTER_ESCAPE_TABLE[c]); - } - else - { - // default: add the char - encodedValue.append(c); - } - } - - return encodedValue.toString(); - } - + /** * Returns a Set of byte arrays with the certificate or CRL encodings. * diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java b/prov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java index 01d592682f..572eba6122 100644 --- a/prov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java +++ b/prov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java @@ -10,9 +10,8 @@ import java.security.spec.PSSParameterSpec; import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1Null; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; @@ -20,22 +19,49 @@ import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.Extensions; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers; class X509SignatureUtil { - private static final ASN1Null derNull = DERNull.INSTANCE; - - static void setSignatureParameters( - Signature signature, - ASN1Encodable params) + static byte[] getExtensionValue(Extensions extensions, String oid) + { + if (oid != null) + { + ASN1ObjectIdentifier asn1Oid = ASN1ObjectIdentifier.tryFromID(oid); + if (asn1Oid != null) + { + ASN1OctetString extValue = Extensions.getExtensionValue(extensions, asn1Oid); + if (null != extValue) + { + try + { + return extValue.getEncoded(); + } + catch (Exception e) + { + throw new IllegalStateException("error parsing " + e.toString()); + } + } + } + } + return null; + } + + private static boolean isAbsentOrEmptyParameters(ASN1Encodable parameters) + { + return parameters == null || DERNull.INSTANCE.equals(parameters); + } + + static void setSignatureParameters(Signature signature, ASN1Encodable params) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException { - if (params != null && !derNull.equals(params)) + if (!isAbsentOrEmptyParameters(params)) { - AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider()); - + String sigAlgName = signature.getAlgorithm(); + AlgorithmParameters sigParams = AlgorithmParameters.getInstance(sigAlgName, signature.getProvider()); + try { sigParams.init(params.toASN1Primitive().getEncoded()); @@ -44,8 +70,8 @@ static void setSignatureParameters( { throw new SignatureException("IOException decoding parameters: " + e.getMessage()); } - - if (signature.getAlgorithm().endsWith("MGF1")) + + if (sigAlgName.endsWith("MGF1")) { try { @@ -58,21 +84,21 @@ static void setSignatureParameters( } } } - - static String getSignatureName( - AlgorithmIdentifier sigAlgId) + + static String getSignatureName(AlgorithmIdentifier sigAlgId) { + ASN1ObjectIdentifier sigAlgOid = sigAlgId.getAlgorithm(); ASN1Encodable params = sigAlgId.getParameters(); - - if (params != null && !derNull.equals(params)) + + if (!isAbsentOrEmptyParameters(params)) { - if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) + if (PKCSObjectIdentifiers.id_RSASSA_PSS.equals(sigAlgOid)) { RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params); - + return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "withRSAandMGF1"; } - if (sigAlgId.getAlgorithm().equals(X9ObjectIdentifiers.ecdsa_with_SHA2)) + if (X9ObjectIdentifiers.ecdsa_with_SHA2.equals(sigAlgOid)) { AlgorithmIdentifier ecDsaParams = AlgorithmIdentifier.getInstance(params); @@ -80,9 +106,9 @@ static String getSignatureName( } } - return sigAlgId.getAlgorithm().getId(); + return sigAlgOid.getId(); } - + /** * Return the digest algorithm using one of the standard JCA string * representations rather the the algorithm identifier (if possible). diff --git a/prov/src/main/java/org/bouncycastle/jce/spec/GOST3410ParameterSpec.java b/prov/src/main/java/org/bouncycastle/jce/spec/GOST3410ParameterSpec.java index ba2bd01965..c5ddd2b989 100644 --- a/prov/src/main/java/org/bouncycastle/jce/spec/GOST3410ParameterSpec.java +++ b/prov/src/main/java/org/bouncycastle/jce/spec/GOST3410ParameterSpec.java @@ -25,22 +25,22 @@ public GOST3410ParameterSpec( String digestParamSetOID, String encryptionParamSetOID) { - GOST3410ParamSetParameters ecP = null; - - try - { - ecP = GOST3410NamedParameters.getByOID(new ASN1ObjectIdentifier(keyParamSetID)); - } - catch (IllegalArgumentException e) + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.tryFromID(keyParamSetID); + if (oid == null) { - ASN1ObjectIdentifier oid = GOST3410NamedParameters.getOID(keyParamSetID); + oid = GOST3410NamedParameters.getOID(keyParamSetID); if (oid != null) { keyParamSetID = oid.getId(); - ecP = GOST3410NamedParameters.getByOID(oid); } } - + + GOST3410ParamSetParameters ecP = null; + if (oid != null) + { + ecP = GOST3410NamedParameters.getByOID(oid); + } + if (ecP == null) { throw new IllegalArgumentException("no key parameter set for passed in name/OID."); diff --git a/prov/src/main/java/org/bouncycastle/ldap/LDAPUtils.java b/prov/src/main/java/org/bouncycastle/ldap/LDAPUtils.java new file mode 100644 index 0000000000..2d6bb3bc78 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/ldap/LDAPUtils.java @@ -0,0 +1,112 @@ +package org.bouncycastle.ldap; + +import org.bouncycastle.util.Strings; + +/** + * General utility methods for assisting with preparation of LDAP queries. + */ +public class LDAPUtils +{ + private static String[] FILTER_ESCAPE_TABLE = new String['\\' + 1]; + + static + { + // Filter encoding table ------------------------------------- + + // fill with char itself + for (char c = 0; c < FILTER_ESCAPE_TABLE.length; c++) + { + FILTER_ESCAPE_TABLE[c] = String.valueOf(c); + } + + // escapes (RFC2254) + FILTER_ESCAPE_TABLE['*'] = "\\2a"; + FILTER_ESCAPE_TABLE['('] = "\\28"; + FILTER_ESCAPE_TABLE[')'] = "\\29"; + FILTER_ESCAPE_TABLE['\\'] = "\\5c"; + FILTER_ESCAPE_TABLE[0] = "\\00"; + } + + /** + * Parse out the contents of a particular subject attribute name from the string form of an X.500 DN. + * + * @param subject string form of an X.500 DN. + * @param subjectAttributeName the RDN attribute name of interest. + * @return an escaped string suitable for use in an LDAP query. + */ + public static String parseDN(String subject, String subjectAttributeName) + { + String temp = subject; + int begin = Strings.toLowerCase(temp).indexOf(Strings.toLowerCase(subjectAttributeName)); + if (begin == -1) + { + return ""; + } + temp = temp.substring(begin + subjectAttributeName.length()); + int end = temp.indexOf(','); + if (end == -1) + { + end = temp.length(); + } + while (temp.charAt(end - 1) == '\\') + { + end = temp.indexOf(',', end + 1); + if (end == -1) + { + end = temp.length(); + } + } + temp = temp.substring(0, end); + begin = temp.indexOf('='); + temp = temp.substring(begin + 1); + if (temp.charAt(0) == ' ') + { + temp = temp.substring(1); + } + if (temp.startsWith("\"")) + { + temp = temp.substring(1); + } + if (temp.endsWith("\"")) + { + temp = temp.substring(0, temp.length() - 1); + } + return filterEncode(temp); + } + + /** + * Escape a value for use in a filter. + * + * @param value the value to escape. + * @return a properly escaped representation of the supplied value. + */ + private static String filterEncode(String value) + { + if (value == null) + { + return null; + } + + // make buffer roomy + StringBuilder encodedValue = new StringBuilder(value.length() * 2); + + int length = value.length(); + + for (int i = 0; i < length; i++) + { + char c = value.charAt(i); + + if (c < FILTER_ESCAPE_TABLE.length) + { + encodedValue.append(FILTER_ESCAPE_TABLE[c]); + } + else + { + // default: add the char + encodedValue.append(c); + } + } + + return encodedValue.toString(); + } +} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/MayoKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/MayoKey.java new file mode 100644 index 0000000000..efe8e2fb9d --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/MayoKey.java @@ -0,0 +1,16 @@ +package org.bouncycastle.pqc.jcajce.interfaces; + +import java.security.Key; + +import org.bouncycastle.pqc.jcajce.spec.MayoParameterSpec; + +public interface MayoKey + extends Key +{ + /** + * Return the parameters for this key. + * + * @return a MayoParameterSpec + */ + MayoParameterSpec getParameterSpec(); +} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NTRUPlusKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NTRUPlusKey.java new file mode 100644 index 0000000000..7e58ddeeab --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NTRUPlusKey.java @@ -0,0 +1,16 @@ +package org.bouncycastle.pqc.jcajce.interfaces; + +import java.security.Key; + +import org.bouncycastle.pqc.jcajce.spec.NTRUPlusParameterSpec; + +public interface NTRUPlusKey + extends Key +{ + /** + * Return the parameters for this key. + * + * @return a NTRUPlusParameterSpec + */ + NTRUPlusParameterSpec getParameterSpec(); +} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NTRUPlusPrivateKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NTRUPlusPrivateKey.java new file mode 100644 index 0000000000..8fe0afd4d8 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NTRUPlusPrivateKey.java @@ -0,0 +1,9 @@ +package org.bouncycastle.pqc.jcajce.interfaces; + +import java.security.PrivateKey; + +public interface NTRUPlusPrivateKey + extends PrivateKey, NTRUPlusKey +{ +} + diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/RainbowPublicKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NTRUPlusPublicKey.java similarity index 55% rename from prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/RainbowPublicKey.java rename to prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NTRUPlusPublicKey.java index 61dcce91a9..bb276f9d97 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/RainbowPublicKey.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/NTRUPlusPublicKey.java @@ -2,8 +2,7 @@ import java.security.PublicKey; -public interface RainbowPublicKey - extends PublicKey, RainbowKey +public interface NTRUPlusPublicKey + extends PublicKey, NTRUPlusKey { - } diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/QTESLAKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/QTESLAKey.java deleted file mode 100644 index c6fc80f917..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/QTESLAKey.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.bouncycastle.pqc.jcajce.interfaces; - -import org.bouncycastle.pqc.jcajce.spec.QTESLAParameterSpec; - -/** - * Base interface for a qTESLA key. - */ -public interface QTESLAKey -{ - /** - * Return the parameters for this key - in this case the security category. - * - * @return a QTESLAParameterSpec - */ - QTESLAParameterSpec getParams(); -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/RainbowKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/RainbowKey.java deleted file mode 100644 index 827b2f4ddd..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/RainbowKey.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.bouncycastle.pqc.jcajce.interfaces; - -import java.security.Key; - -import org.bouncycastle.pqc.jcajce.spec.RainbowParameterSpec; - -public interface RainbowKey - extends Key -{ - /** - * Return the parameters for this key. - * - * @return a RainbowParameterSpec - */ - RainbowParameterSpec getParameterSpec(); -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/RainbowPrivateKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/RainbowPrivateKey.java deleted file mode 100644 index a60f912d5d..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/RainbowPrivateKey.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.bouncycastle.pqc.jcajce.interfaces; - -import java.security.PrivateKey; - -public interface RainbowPrivateKey - extends PrivateKey, RainbowKey -{ - /** - * Return the public key corresponding to this private key. - * - * @return a Rainbow Public Key - */ - RainbowPublicKey getPublicKey(); -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/SnovaKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/SnovaKey.java new file mode 100644 index 0000000000..0615e1acc7 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/interfaces/SnovaKey.java @@ -0,0 +1,16 @@ +package org.bouncycastle.pqc.jcajce.interfaces; + +import java.security.Key; + +import org.bouncycastle.pqc.jcajce.spec.SnovaParameterSpec; + +public interface SnovaKey + extends Key +{ + /** + * Return the parameters for this key. + * + * @return a SnovaParameterSpec + */ + SnovaParameterSpec getParameterSpec(); +} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java index b1ef6ccbed..0b8662d5bb 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java @@ -22,7 +22,7 @@ public class BouncyCastlePQCProvider extends Provider implements ConfigurableProvider { - private static String info = "BouncyCastle Post-Quantum Security Provider v1.80"; + private static String info = "BouncyCastle Post-Quantum Security Provider v1.83"; public static String PROVIDER_NAME = "BCPQC"; @@ -32,15 +32,17 @@ public class BouncyCastlePQCProvider private static final Map keyInfoConverters = new HashMap(); /* - * Configurable symmetric ciphers - */ + * Configurable symmetric ciphers + */ private static final String ALGORITHM_PACKAGE = "org.bouncycastle.pqc.jcajce.provider."; private static final String[] ALGORITHMS = { //"Rainbow", "McEliece", "SPHINCS", "LMS", "NH", "XMSS", "SPHINCSPlus", "CMCE", "Frodo", "SABER", "Picnic", "NTRU", "Falcon", "Kyber", - "Dilithium", "NTRUPrime", "BIKE", "HQC", "Rainbow" + "Dilithium", "NTRUPrime", "BIKE", "HQC", "Rainbow", + "Mayo", "Snova", + "NTRUPlus" }; /** @@ -50,7 +52,7 @@ public class BouncyCastlePQCProvider */ public BouncyCastlePQCProvider() { - super(PROVIDER_NAME, 1.80, info); + super(PROVIDER_NAME, 1.83, info); AccessController.doPrivileged(new PrivilegedAction() { @@ -117,7 +119,7 @@ public void addAlgorithm(String key, String value, Map attribute addAttributes(key, attributes); } - public void addAlgorithm(String type, ASN1ObjectIdentifier oid, String className) + public void addAlgorithm(String type, ASN1ObjectIdentifier oid, String className) { if (!containsKey(type + "." + className)) { @@ -150,7 +152,7 @@ public AsymmetricKeyInfoConverter getKeyInfoConverter(ASN1ObjectIdentifier oid) public void addAttributes(String key, Map attributeMap) { - for (Iterator it = attributeMap.keySet().iterator(); it.hasNext();) + for (Iterator it = attributeMap.keySet().iterator(); it.hasNext(); ) { String attributeName = (String)it.next(); String attributeKey = key + " " + attributeName; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Falcon.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Falcon.java index 0af7244a1a..c8e56d21ee 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Falcon.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Falcon.java @@ -3,7 +3,6 @@ import org.bouncycastle.asn1.bc.BCObjectIdentifiers; 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.jcajce.provider.falcon.FalconKeyFactorySpi; public class Falcon diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/HQC.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/HQC.java index 6492ad122a..a82ef8846a 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/HQC.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/HQC.java @@ -4,6 +4,7 @@ import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; +import org.bouncycastle.jcajce.util.SpiUtil; import org.bouncycastle.pqc.jcajce.provider.hqc.HQCKeyFactorySpi; public class HQC @@ -20,20 +21,42 @@ public Mappings() public void configure(ConfigurableProvider provider) { provider.addAlgorithm("KeyFactory.HQC", PREFIX + "HQCKeyFactorySpi"); + provider.addAlgorithm("Alg.Alias.KeyFactory.HQC", "HQC"); + addKeyFactoryAlgorithm(provider, "HQC128", PREFIX + "HQCKeyFactorySpi$HQC128", BCObjectIdentifiers.hqc128, new HQCKeyFactorySpi.HQC128()); + addKeyFactoryAlgorithm(provider, "HQC192", PREFIX + "HQCKeyFactorySpi$HQC192", BCObjectIdentifiers.hqc192, new HQCKeyFactorySpi.HQC192()); + addKeyFactoryAlgorithm(provider, "HQC256", PREFIX + "HQCKeyFactorySpi$HQC256", BCObjectIdentifiers.hqc256, new HQCKeyFactorySpi.HQC256()); + provider.addAlgorithm("KeyPairGenerator.HQC", PREFIX + "HQCKeyPairGeneratorSpi"); + provider.addAlgorithm("Alg.Alias.KeyPairGenerator.HQC", "HQC"); + addKeyPairGeneratorAlgorithm(provider, "HQC128", PREFIX + "HQCKeyPairGeneratorSpi$HQC128", BCObjectIdentifiers.hqc128); + addKeyPairGeneratorAlgorithm(provider, "HQC192", PREFIX + "HQCKeyPairGeneratorSpi$HQC192", BCObjectIdentifiers.hqc192); + addKeyPairGeneratorAlgorithm(provider, "HQC256", PREFIX + "HQCKeyPairGeneratorSpi$HQC256", BCObjectIdentifiers.hqc256); provider.addAlgorithm("KeyGenerator.HQC", PREFIX + "HQCKeyGeneratorSpi"); + addKeyGeneratorAlgorithm(provider, "HQC128", PREFIX + "HQCKeyGeneratorSpi$HQC128", BCObjectIdentifiers.hqc128); + addKeyGeneratorAlgorithm(provider, "HQC192", PREFIX + "HQCKeyGeneratorSpi$HQC192", BCObjectIdentifiers.hqc192); + addKeyGeneratorAlgorithm(provider, "HQC256", PREFIX + "HQCKeyGeneratorSpi$HQC256", BCObjectIdentifiers.hqc256); AsymmetricKeyInfoConverter keyFact = new HQCKeyFactorySpi(); - provider.addAlgorithm("Cipher.HQC", PREFIX + "HQCCipherSpi$Base"); - provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.pqc_kem_hqc, "HQC"); - + addCipherAlgorithm(provider, "HQC", PREFIX + "HQCCipherSpi$Base", BCObjectIdentifiers.pqc_kem_hqc); addCipherAlgorithm(provider, "HQC128", PREFIX + "HQCCipherSpi$HQC128", BCObjectIdentifiers.hqc128); addCipherAlgorithm(provider, "HQC192", PREFIX + "HQCCipherSpi$HQC192", BCObjectIdentifiers.hqc192); addCipherAlgorithm(provider, "HQC256", PREFIX + "HQCCipherSpi$HQC256", BCObjectIdentifiers.hqc256); registerOid(provider, BCObjectIdentifiers.pqc_kem_hqc, "HQC", keyFact); + provider.addKeyInfoConverter(BCObjectIdentifiers.hqc128, keyFact); + provider.addKeyInfoConverter(BCObjectIdentifiers.hqc192, keyFact); + provider.addKeyInfoConverter(BCObjectIdentifiers.hqc256, keyFact); + + if (SpiUtil.hasKEM()) + { + provider.addAlgorithm("KEM.HQC", PREFIX + "HQCKEMSpi$HQC"); + + addKEMAlgorithm(provider, "HQC-128", PREFIX + "HQCKEMSpi$HQC128", BCObjectIdentifiers.hqc128); + addKEMAlgorithm(provider, "HQC-192", PREFIX + "HQCKEMSpi$HQC192", BCObjectIdentifiers.hqc192); + addKEMAlgorithm(provider, "HQC-256", PREFIX + "HQCKEMSpi$HQC256", BCObjectIdentifiers.hqc256); + } } } } diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Mayo.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Mayo.java new file mode 100644 index 0000000000..ae8669d748 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Mayo.java @@ -0,0 +1,44 @@ +package org.bouncycastle.pqc.jcajce.provider; + +import org.bouncycastle.asn1.bc.BCObjectIdentifiers; +import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; +import org.bouncycastle.pqc.jcajce.provider.mayo.MayoKeyFactorySpi; + +public class Mayo +{ + private static final String PREFIX = "org.bouncycastle.pqc.jcajce.provider.mayo."; + + public static class Mappings + extends AsymmetricAlgorithmProvider + { + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + provider.addAlgorithm("KeyFactory.Mayo", PREFIX + "MayoKeyFactorySpi"); + + addKeyFactoryAlgorithm(provider, "MAYO_1", PREFIX + "MayoKeyFactorySpi$Mayo1", BCObjectIdentifiers.mayo1, new MayoKeyFactorySpi.Mayo1()); + addKeyFactoryAlgorithm(provider, "MAYO_2", PREFIX + "MayoKeyFactorySpi$Mayo2", BCObjectIdentifiers.mayo2, new MayoKeyFactorySpi.Mayo2()); + addKeyFactoryAlgorithm(provider, "MAYO_3", PREFIX + "MayoKeyFactorySpi$Mayo3", BCObjectIdentifiers.mayo3, new MayoKeyFactorySpi.Mayo3()); + addKeyFactoryAlgorithm(provider, "MAYO_5", PREFIX + "MayoKeyFactorySpi$Mayo5", BCObjectIdentifiers.mayo5, new MayoKeyFactorySpi.Mayo5()); + + provider.addAlgorithm("KeyPairGenerator.Mayo", PREFIX + "MayoKeyPairGeneratorSpi"); + + addKeyPairGeneratorAlgorithm(provider, "MAYO_1", PREFIX + "MayoKeyPairGeneratorSpi$Mayo1", BCObjectIdentifiers.mayo1); + addKeyPairGeneratorAlgorithm(provider, "MAYO_2", PREFIX + "MayoKeyPairGeneratorSpi$Mayo2", BCObjectIdentifiers.mayo2); + addKeyPairGeneratorAlgorithm(provider, "MAYO_3", PREFIX + "MayoKeyPairGeneratorSpi$Mayo3", BCObjectIdentifiers.mayo3); + addKeyPairGeneratorAlgorithm(provider, "MAYO_5", PREFIX + "MayoKeyPairGeneratorSpi$Mayo5", BCObjectIdentifiers.mayo5); + + addSignatureAlgorithm(provider, "Mayo", PREFIX + "SignatureSpi$Base", BCObjectIdentifiers.mayo); + + addSignatureAlgorithm(provider, "MAYO_1", PREFIX + "SignatureSpi$Mayo1", BCObjectIdentifiers.mayo1); + addSignatureAlgorithm(provider, "MAYO_2", PREFIX + "SignatureSpi$Mayo2", BCObjectIdentifiers.mayo2); + addSignatureAlgorithm(provider, "MAYO_3", PREFIX + "SignatureSpi$Mayo3", BCObjectIdentifiers.mayo3); + addSignatureAlgorithm(provider, "MAYO_5", PREFIX + "SignatureSpi$Mayo5", BCObjectIdentifiers.mayo5); + } + } +} + diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/McEliece.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/McEliece.java deleted file mode 100644 index c3b69e5915..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/McEliece.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider; - -import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; -import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; -import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; - -public class McEliece -{ - private static final String PREFIX = "org.bouncycastle.pqc.jcajce.provider" + ".mceliece."; - - public static class Mappings - extends AsymmetricAlgorithmProvider - { - public Mappings() - { - } - - public void configure(ConfigurableProvider provider) - { - 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.McElieceKobaraImai", PREFIX + "McElieceKobaraImaiCipherSpi$McElieceKobaraImai"); - provider.addAlgorithm("Cipher.McElieceFujisaki", PREFIX + "McElieceFujisakiCipherSpi$McElieceFujisaki"); - } - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NTRU.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NTRU.java index baf13c51a3..167231d04c 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NTRU.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NTRU.java @@ -4,6 +4,7 @@ import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; +import org.bouncycastle.jcajce.util.SpiUtil; import org.bouncycastle.pqc.jcajce.provider.ntru.NTRUKeyFactorySpi; public class NTRU @@ -27,22 +28,33 @@ public void configure(ConfigurableProvider provider) provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhps2048509, "NTRU"); provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhps2048677, "NTRU"); provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhps4096821, "NTRU"); + provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhps40961229, "NTRU"); provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhrss701, "NTRU"); + provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhrss1373, "NTRU"); AsymmetricKeyInfoConverter keyFact = new NTRUKeyFactorySpi(); - provider.addAlgorithm("Cipher.NTRU", PREFIX + "NTRUCipherSpi$Base"); - provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.pqc_kem_ntru, "NTRU"); + addCipherAlgorithm(provider, "NTRU", PREFIX + "NTRUCipherSpi$Base", BCObjectIdentifiers.pqc_kem_ntru); provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhps2048509, "NTRU"); provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhps2048677, "NTRU"); provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhps4096821, "NTRU"); + provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhps40961229, "NTRU"); provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhrss701, "NTRU"); + provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhrss1373, "NTRU"); registerOid(provider, BCObjectIdentifiers.pqc_kem_ntru, "NTRU", keyFact); registerOid(provider, BCObjectIdentifiers.ntruhps2048509, "NTRU", keyFact); registerOid(provider, BCObjectIdentifiers.ntruhps2048677, "NTRU", keyFact); registerOid(provider, BCObjectIdentifiers.ntruhps4096821, "NTRU", keyFact); + registerOid(provider, BCObjectIdentifiers.ntruhps40961229, "NTRU", keyFact); registerOid(provider, BCObjectIdentifiers.ntruhrss701, "NTRU", keyFact); + registerOid(provider, BCObjectIdentifiers.ntruhrss1373, "NTRU", keyFact); + + if (SpiUtil.hasKEM()) + { + // TODO Per-parameter-set SPI classes? + addKEMAlgorithm(provider, "NTRU", PREFIX + "NTRUKEMSpi$NTRU", BCObjectIdentifiers.pqc_kem_ntru); + } } } } diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NTRUPlus.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NTRUPlus.java new file mode 100644 index 0000000000..651ac6bc8e --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NTRUPlus.java @@ -0,0 +1,55 @@ +package org.bouncycastle.pqc.jcajce.provider; + +import org.bouncycastle.asn1.bc.BCObjectIdentifiers; +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.jcajce.provider.ntruplus.NTRUPlusKeyFactorySpi; + +public class NTRUPlus +{ + private static final String PREFIX = "org.bouncycastle.pqc.jcajce.provider" + ".ntruplus."; + + public static class Mappings + extends AsymmetricAlgorithmProvider + { + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + provider.addAlgorithm("KeyFactory.NTRUPLUS", PREFIX + "NTRUPlusKeyFactorySpi"); + provider.addAlgorithm("Alg.Alias.KeyFactory.NTRUPLUS", "NTRUPLUS"); + addKeyFactoryAlgorithm(provider, "NTRU+KEM-768", PREFIX + "NTRUPlusKeyFactorySpi$NTRUPlus768", BCObjectIdentifiers.ntruPlus768, new NTRUPlusKeyFactorySpi.NTRUPlus768()); + addKeyFactoryAlgorithm(provider, "NTRU+KEM-864", PREFIX + "NTRUPlusKeyFactorySpi$NTRUPlus864", BCObjectIdentifiers.ntruPlus864, new NTRUPlusKeyFactorySpi.NTRUPlus864()); + addKeyFactoryAlgorithm(provider, "NTRU+KEM-1152", PREFIX + "NTRUPlusKeyFactorySpi$NTRUPlus1152", BCObjectIdentifiers.ntruPlus1152, new NTRUPlusKeyFactorySpi.NTRUPlus1152()); + + provider.addAlgorithm("KeyPairGenerator.NTRUPLUS", PREFIX + "NTRUPlusKeyPairGeneratorSpi"); + provider.addAlgorithm("Alg.Alias.KeyPairGenerator.NTRUPLUS", "NTRUPLUS"); + addKeyPairGeneratorAlgorithm(provider, "NTRU+KEM-768", PREFIX + "NTRUPlusKeyPairGeneratorSpi$NTRUPlus768", BCObjectIdentifiers.ntruPlus768); + addKeyPairGeneratorAlgorithm(provider, "NTRU+KEM-864", PREFIX + "NTRUPlusKeyPairGeneratorSpi$NTRUPlus864", BCObjectIdentifiers.ntruPlus864); + addKeyPairGeneratorAlgorithm(provider, "NTRU+KEM-1152", PREFIX + "NTRUPlusKeyPairGeneratorSpi$NTRUPlus1152", BCObjectIdentifiers.ntruPlus1152); + + provider.addAlgorithm("KeyGenerator.NTRUPLUS", PREFIX + "NTRUPlusKeyGeneratorSpi"); + addKeyGeneratorAlgorithm(provider, "NTRU+KEM-768", PREFIX + "NTRUPLUSKeyGeneratorSpi$NTRUPLUS768", BCObjectIdentifiers.ntruPlus768); + addKeyGeneratorAlgorithm(provider, "NTRU+KEM-864", PREFIX + "NTRUPLUSKeyGeneratorSpi$NTRUPLUS864", BCObjectIdentifiers.ntruPlus864); + addKeyGeneratorAlgorithm(provider, "NTRU+KEM-1152", PREFIX + "NTRUPLUSKeyGeneratorSpi$NTRUPLUS1152", BCObjectIdentifiers.ntruPlus1152); + + AsymmetricKeyInfoConverter keyFact = new NTRUPlusKeyFactorySpi(); + + provider.addAlgorithm("Cipher.NTRUPLUS", PREFIX + "NTRUPlusCipherSpi$Base"); + provider.addAlgorithm("Alg.Alias.Cipher.NTRUPLUS", "NTRUPLUS"); + provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruPlus, "NTRUPLUS"); + + addCipherAlgorithm(provider, "NTRU+KEM-768", PREFIX + "NTRUPLUSCipherSpi$NTRUPLUS768", BCObjectIdentifiers.ntruPlus768); + addCipherAlgorithm(provider, "NTRU+KEM-864", PREFIX + "NTRUPLUSCipherSpi$NTRUPLUS864", BCObjectIdentifiers.ntruPlus864); + addCipherAlgorithm(provider, "NTRU+KEM-1152", PREFIX + "NTRUPLUSCipherSpi$NTRUPLUS1152", BCObjectIdentifiers.ntruPlus1152); + + registerOid(provider, BCObjectIdentifiers.ntruPlus, "NTRUPLUS", keyFact); + provider.addKeyInfoConverter(BCObjectIdentifiers.ntruPlus768, keyFact); + provider.addKeyInfoConverter(BCObjectIdentifiers.ntruPlus864, keyFact); + provider.addKeyInfoConverter(BCObjectIdentifiers.ntruPlus1152, keyFact); + } + } +} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NTRUPrime.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NTRUPrime.java index f4d62eac28..630a59a678 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NTRUPrime.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/NTRUPrime.java @@ -4,6 +4,7 @@ import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; +import org.bouncycastle.jcajce.util.SpiUtil; import org.bouncycastle.pqc.jcajce.provider.ntruprime.NTRULPRimeKeyFactorySpi; import org.bouncycastle.pqc.jcajce.provider.ntruprime.SNTRUPrimeKeyFactorySpi; @@ -27,16 +28,15 @@ public void configure(ConfigurableProvider provider) AsymmetricKeyInfoConverter keyFact = new NTRULPRimeKeyFactorySpi(); - provider.addAlgorithm("Cipher.NTRULPRIME", PREFIX + "NTRULPRimeCipherSpi$Base"); - provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.pqc_kem_ntrulprime, "NTRU"); - + addCipherAlgorithm(provider, "NTRULPRIME", PREFIX + "NTRULPRimeCipherSpi$Base", BCObjectIdentifiers.pqc_kem_ntrulprime); + registerOid(provider, BCObjectIdentifiers.ntrulpr653, "NTRULPRIME", keyFact); registerOid(provider, BCObjectIdentifiers.ntrulpr761, "NTRULPRIME", keyFact); registerOid(provider, BCObjectIdentifiers.ntrulpr857, "NTRULPRIME", keyFact); registerOid(provider, BCObjectIdentifiers.ntrulpr953, "NTRULPRIME", keyFact); registerOid(provider, BCObjectIdentifiers.ntrulpr1013, "NTRULPRIME", keyFact); registerOid(provider, BCObjectIdentifiers.ntrulpr1277, "NTRULPRIME", keyFact); - + provider.addAlgorithm("KeyFactory.SNTRUPRIME", PREFIX + "SNTRUPrimeKeyFactorySpi"); provider.addAlgorithm("KeyPairGenerator.SNTRUPRIME", PREFIX + "SNTRUPrimeKeyPairGeneratorSpi"); @@ -44,8 +44,7 @@ public void configure(ConfigurableProvider provider) keyFact = new SNTRUPrimeKeyFactorySpi(); - provider.addAlgorithm("Cipher.SNTRUPRIME", PREFIX + "SNTRUPrimeCipherSpi$Base"); - provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.pqc_kem_sntruprime, "NTRU"); + addCipherAlgorithm(provider, "SNTRUPRIME", PREFIX + "SNTRUPrimeCipherSpi$Base", BCObjectIdentifiers.pqc_kem_sntruprime); registerOid(provider, BCObjectIdentifiers.sntrup653, "SNTRUPRIME", keyFact); registerOid(provider, BCObjectIdentifiers.sntrup761, "SNTRUPRIME", keyFact); @@ -53,6 +52,12 @@ public void configure(ConfigurableProvider provider) registerOid(provider, BCObjectIdentifiers.sntrup953, "SNTRUPRIME", keyFact); registerOid(provider, BCObjectIdentifiers.sntrup1013, "SNTRUPRIME", keyFact); registerOid(provider, BCObjectIdentifiers.sntrup1277, "SNTRUPRIME", keyFact); + + if (SpiUtil.hasKEM()) + { + // TODO Per-parameter-set SPI classes? + addKEMAlgorithm(provider, "SNTRUPRIME", PREFIX + "SNTRUPrimeKEMSpi$SNTRUPrime", BCObjectIdentifiers.pqc_kem_sntruprime); + } } } } diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Rainbow.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Rainbow.java deleted file mode 100644 index 7c1fcf8012..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Rainbow.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider; - -import org.bouncycastle.asn1.bc.BCObjectIdentifiers; -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.jcajce.provider.rainbow.RainbowKeyFactorySpi; - -public class Rainbow -{ - private static final String PREFIX = "org.bouncycastle.pqc.jcajce.provider" + ".rainbow."; - - public static class Mappings - extends AsymmetricAlgorithmProvider - { - public Mappings() - { - } - - public void configure(ConfigurableProvider provider) - { - provider.addAlgorithm("KeyFactory.RAINBOW", PREFIX + "RainbowKeyFactorySpi"); - provider.addAlgorithm("KeyPairGenerator.RAINBOW", PREFIX + "RainbowKeyPairGeneratorSpi"); - - addKeyPairGeneratorAlgorithm(provider, "RAINBOW-III-CLASSIC", PREFIX + "RainbowKeyPairGeneratorSpi$RainbowIIIclassic", BCObjectIdentifiers.rainbow_III_classic); - addKeyPairGeneratorAlgorithm(provider, "RAINBOW-III-CIRCUMZENITHAL", PREFIX + "RainbowKeyPairGeneratorSpi$RainbowIIIcircum", BCObjectIdentifiers.rainbow_III_circumzenithal); - addKeyPairGeneratorAlgorithm(provider, "RAINBOW-III-COMPRESSED", PREFIX + "RainbowKeyPairGeneratorSpi$RainbowIIIcomp", BCObjectIdentifiers.rainbow_III_compressed); - addKeyPairGeneratorAlgorithm(provider, "RAINBOW-V-CLASSIC", PREFIX + "RainbowKeyPairGeneratorSpi$RainbowVclassic", BCObjectIdentifiers.rainbow_V_classic); - addKeyPairGeneratorAlgorithm(provider, "RAINBOW-V-CIRCUMZENITHAL", PREFIX + "RainbowKeyPairGeneratorSpi$RainbowVcircum", BCObjectIdentifiers.rainbow_V_circumzenithal); - addKeyPairGeneratorAlgorithm(provider, "RAINBOW-V-COMPRESSED", PREFIX + "RainbowKeyPairGeneratorSpi$RainbowVcomp", BCObjectIdentifiers.rainbow_V_compressed); - - addSignatureAlgorithm(provider, "RAINBOW", PREFIX + "SignatureSpi$Base", BCObjectIdentifiers.rainbow); - - addSignatureAlgorithm(provider, "RAINBOW-III-CLASSIC", PREFIX + "SignatureSpi$RainbowIIIclassic", BCObjectIdentifiers.rainbow_III_classic); - addSignatureAlgorithm(provider, "RAINBOW-III-CIRCUMZENITHAL", PREFIX + "SignatureSpi$RainbowIIIcircum", BCObjectIdentifiers.rainbow_III_circumzenithal); - addSignatureAlgorithm(provider, "RAINBOW-III-COMPRESSED", PREFIX + "SignatureSpi$RainbowIIIcomp", BCObjectIdentifiers.rainbow_III_compressed); - addSignatureAlgorithm(provider, "RAINBOW-V-CLASSIC", PREFIX + "SignatureSpi$RainbowVclassic", BCObjectIdentifiers.rainbow_V_classic); - addSignatureAlgorithm(provider, "RAINBOW-V-CIRCUMZENITHAL", PREFIX + "SignatureSpi$RainbowVcircum", BCObjectIdentifiers.rainbow_V_circumzenithal); - addSignatureAlgorithm(provider, "RAINBOW-v-COMPRESSED", PREFIX + "SignatureSpi$RainbowVcomp", BCObjectIdentifiers.rainbow_V_compressed); - - AsymmetricKeyInfoConverter keyFact = new RainbowKeyFactorySpi(); - - registerKeyFactoryOid(provider, BCObjectIdentifiers.rainbow_III_classic, "RAINBOW", keyFact); - registerKeyFactoryOid(provider, BCObjectIdentifiers.rainbow_III_circumzenithal, "RAINBOW", keyFact); - registerKeyFactoryOid(provider, BCObjectIdentifiers.rainbow_III_compressed, "RAINBOW", keyFact); - registerKeyFactoryOid(provider, BCObjectIdentifiers.rainbow_V_classic, "RAINBOW", keyFact); - registerKeyFactoryOid(provider, BCObjectIdentifiers.rainbow_V_circumzenithal, "RAINBOW", keyFact); - registerKeyFactoryOid(provider, BCObjectIdentifiers.rainbow_V_compressed, "RAINBOW", keyFact); - } - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Snova.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Snova.java new file mode 100644 index 0000000000..4ad9ea91e8 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/Snova.java @@ -0,0 +1,164 @@ +package org.bouncycastle.pqc.jcajce.provider; + +import org.bouncycastle.asn1.bc.BCObjectIdentifiers; +import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; +import org.bouncycastle.pqc.jcajce.provider.snova.SnovaKeyFactorySpi; + +public class Snova +{ + private static final String PREFIX = "org.bouncycastle.pqc.jcajce.provider.snova."; + + public static class Mappings + extends AsymmetricAlgorithmProvider + { + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + provider.addAlgorithm("KeyFactory.Snova", PREFIX + "SnovaKeyFactorySpi"); + + addKeyFactoryAlgorithm(provider, "SNOVA_24_5_4_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_24_5_4_SSK", BCObjectIdentifiers.snova_24_5_4_ssk, new SnovaKeyFactorySpi.SNOVA_24_5_4_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_24_5_4_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_24_5_4_ESK", BCObjectIdentifiers.snova_24_5_4_esk, new SnovaKeyFactorySpi.SNOVA_24_5_4_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_24_5_4_SHAKE_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_24_5_4_SHAKE_SSK", BCObjectIdentifiers.snova_24_5_4_shake_ssk, new SnovaKeyFactorySpi.SNOVA_24_5_4_SHAKE_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_24_5_4_SHAKE_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_24_5_4_SHAKE_ESK", BCObjectIdentifiers.snova_24_5_4_shake_esk, new SnovaKeyFactorySpi.SNOVA_24_5_4_SHAKE_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_24_5_5_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_24_5_5_SSK", BCObjectIdentifiers.snova_24_5_5_ssk, new SnovaKeyFactorySpi.SNOVA_24_5_5_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_24_5_5_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_24_5_5_ESK", BCObjectIdentifiers.snova_24_5_5_esk, new SnovaKeyFactorySpi.SNOVA_24_5_5_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_24_5_5_SHAKE_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_24_5_5_SHAKE_SSK", BCObjectIdentifiers.snova_24_5_5_shake_ssk, new SnovaKeyFactorySpi.SNOVA_24_5_5_SHAKE_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_24_5_5_SHAKE_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_24_5_5_SHAKE_ESK", BCObjectIdentifiers.snova_24_5_5_shake_esk, new SnovaKeyFactorySpi.SNOVA_24_5_5_SHAKE_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_25_8_3_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_25_8_3_SSK", BCObjectIdentifiers.snova_25_8_3_ssk, new SnovaKeyFactorySpi.SNOVA_25_8_3_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_25_8_3_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_25_8_3_ESK", BCObjectIdentifiers.snova_25_8_3_esk, new SnovaKeyFactorySpi.SNOVA_25_8_3_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_25_8_3_SHAKE_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_25_8_3_SHAKE_SSK", BCObjectIdentifiers.snova_25_8_3_shake_ssk, new SnovaKeyFactorySpi.SNOVA_25_8_3_SHAKE_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_25_8_3_SHAKE_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_25_8_3_SHAKE_ESK", BCObjectIdentifiers.snova_25_8_3_shake_esk, new SnovaKeyFactorySpi.SNOVA_25_8_3_SHAKE_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_29_6_5_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_29_6_5_SSK", BCObjectIdentifiers.snova_29_6_5_ssk, new SnovaKeyFactorySpi.SNOVA_29_6_5_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_29_6_5_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_29_6_5_ESK", BCObjectIdentifiers.snova_29_6_5_esk, new SnovaKeyFactorySpi.SNOVA_29_6_5_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_29_6_5_SHAKE_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_29_6_5_SHAKE_SSK", BCObjectIdentifiers.snova_29_6_5_shake_ssk, new SnovaKeyFactorySpi.SNOVA_29_6_5_SHAKE_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_29_6_5_SHAKE_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_29_6_5_SHAKE_ESK", BCObjectIdentifiers.snova_29_6_5_shake_esk, new SnovaKeyFactorySpi.SNOVA_29_6_5_SHAKE_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_37_8_4_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_37_8_4_SSK", BCObjectIdentifiers.snova_37_8_4_ssk, new SnovaKeyFactorySpi.SNOVA_37_8_4_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_37_8_4_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_37_8_4_ESK", BCObjectIdentifiers.snova_37_8_4_esk, new SnovaKeyFactorySpi.SNOVA_37_8_4_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_37_8_4_SHAKE_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_37_8_4_SHAKE_SSK", BCObjectIdentifiers.snova_37_8_4_shake_ssk, new SnovaKeyFactorySpi.SNOVA_37_8_4_SHAKE_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_37_8_4_SHAKE_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_37_8_4_SHAKE_ESK", BCObjectIdentifiers.snova_37_8_4_shake_esk, new SnovaKeyFactorySpi.SNOVA_37_8_4_SHAKE_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_37_17_2_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_37_17_2_SSK", BCObjectIdentifiers.snova_37_17_2_ssk, new SnovaKeyFactorySpi.SNOVA_37_17_2_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_37_17_2_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_37_17_2_ESK", BCObjectIdentifiers.snova_37_17_2_esk, new SnovaKeyFactorySpi.SNOVA_37_17_2_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_37_17_2_SHAKE_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_37_17_2_SHAKE_SSK", BCObjectIdentifiers.snova_37_17_2_shake_ssk, new SnovaKeyFactorySpi.SNOVA_37_17_2_SHAKE_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_37_17_2_SHAKE_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_37_17_2_SHAKE_ESK", BCObjectIdentifiers.snova_37_17_2_shake_esk, new SnovaKeyFactorySpi.SNOVA_37_17_2_SHAKE_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_49_11_3_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_49_11_3_SSK", BCObjectIdentifiers.snova_49_11_3_ssk, new SnovaKeyFactorySpi.SNOVA_49_11_3_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_49_11_3_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_49_11_3_ESK", BCObjectIdentifiers.snova_49_11_3_esk, new SnovaKeyFactorySpi.SNOVA_49_11_3_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_49_11_3_SHAKE_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_49_11_3_SHAKE_SSK", BCObjectIdentifiers.snova_49_11_3_shake_ssk, new SnovaKeyFactorySpi.SNOVA_49_11_3_SHAKE_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_49_11_3_SHAKE_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_49_11_3_SHAKE_ESK", BCObjectIdentifiers.snova_49_11_3_shake_esk, new SnovaKeyFactorySpi.SNOVA_49_11_3_SHAKE_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_56_25_2_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_56_25_2_SSK", BCObjectIdentifiers.snova_56_25_2_ssk, new SnovaKeyFactorySpi.SNOVA_56_25_2_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_56_25_2_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_56_25_2_ESK", BCObjectIdentifiers.snova_56_25_2_esk, new SnovaKeyFactorySpi.SNOVA_56_25_2_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_56_25_2_SHAKE_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_56_25_2_SHAKE_SSK", BCObjectIdentifiers.snova_56_25_2_shake_ssk, new SnovaKeyFactorySpi.SNOVA_56_25_2_SHAKE_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_56_25_2_SHAKE_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_56_25_2_SHAKE_ESK", BCObjectIdentifiers.snova_56_25_2_shake_esk, new SnovaKeyFactorySpi.SNOVA_56_25_2_SHAKE_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_60_10_4_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_60_10_4_SSK", BCObjectIdentifiers.snova_60_10_4_ssk, new SnovaKeyFactorySpi.SNOVA_60_10_4_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_60_10_4_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_60_10_4_ESK", BCObjectIdentifiers.snova_60_10_4_esk, new SnovaKeyFactorySpi.SNOVA_60_10_4_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_60_10_4_SHAKE_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_60_10_4_SHAKE_SSK", BCObjectIdentifiers.snova_60_10_4_shake_ssk, new SnovaKeyFactorySpi.SNOVA_60_10_4_SHAKE_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_60_10_4_SHAKE_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_60_10_4_SHAKE_ESK", BCObjectIdentifiers.snova_60_10_4_shake_esk, new SnovaKeyFactorySpi.SNOVA_60_10_4_SHAKE_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_66_15_3_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_66_15_3_SSK", BCObjectIdentifiers.snova_66_15_3_ssk, new SnovaKeyFactorySpi.SNOVA_66_15_3_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_66_15_3_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_66_15_3_ESK", BCObjectIdentifiers.snova_66_15_3_esk, new SnovaKeyFactorySpi.SNOVA_66_15_3_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_66_15_3_SHAKE_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_66_15_3_SHAKE_SSK", BCObjectIdentifiers.snova_66_15_3_shake_ssk, new SnovaKeyFactorySpi.SNOVA_66_15_3_SHAKE_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_66_15_3_SHAKE_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_66_15_3_SHAKE_ESK", BCObjectIdentifiers.snova_66_15_3_shake_esk, new SnovaKeyFactorySpi.SNOVA_66_15_3_SHAKE_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_75_33_2_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_75_33_2_SSK", BCObjectIdentifiers.snova_75_33_2_ssk, new SnovaKeyFactorySpi.SNOVA_75_33_2_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_75_33_2_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_75_33_2_ESK", BCObjectIdentifiers.snova_75_33_2_esk, new SnovaKeyFactorySpi.SNOVA_75_33_2_ESK()); + addKeyFactoryAlgorithm(provider, "SNOVA_75_33_2_SHAKE_SSK", PREFIX + "SnovaKeyFactorySpi$SNOVA_75_33_2_SHAKE_SSK", BCObjectIdentifiers.snova_75_33_2_shake_ssk, new SnovaKeyFactorySpi.SNOVA_75_33_2_SHAKE_SSK()); + addKeyFactoryAlgorithm(provider, "SNOVA_75_33_2_SHAKE_ESK", PREFIX + "SnovaKeyFactorySpi$SNOVA_75_33_2_SHAKE_ESK", BCObjectIdentifiers.snova_75_33_2_shake_esk, new SnovaKeyFactorySpi.SNOVA_75_33_2_SHAKE_ESK()); + + + provider.addAlgorithm("KeyPairGenerator.Snova", PREFIX + "SnovaKeyPairGeneratorSpi"); + + addKeyPairGeneratorAlgorithm(provider, "SNOVA_24_5_4_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_24_5_4_SSK", BCObjectIdentifiers.snova_24_5_4_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_24_5_4_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_24_5_4_ESK", BCObjectIdentifiers.snova_24_5_4_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_24_5_4_SHAKE_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_24_5_4_SHAKE_SSK", BCObjectIdentifiers.snova_24_5_4_shake_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_24_5_4_SHAKE_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_24_5_4_SHAKE_ESK", BCObjectIdentifiers.snova_24_5_4_shake_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_24_5_5_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_24_5_5_SSK", BCObjectIdentifiers.snova_24_5_5_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_24_5_5_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_24_5_5_ESK", BCObjectIdentifiers.snova_24_5_5_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_24_5_5_SHAKE_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_24_5_5_SHAKE_SSK", BCObjectIdentifiers.snova_24_5_5_shake_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_24_5_5_SHAKE_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_24_5_5_SHAKE_ESK", BCObjectIdentifiers.snova_24_5_5_shake_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_25_8_3_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_25_8_3_SSK", BCObjectIdentifiers.snova_25_8_3_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_25_8_3_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_25_8_3_ESK", BCObjectIdentifiers.snova_25_8_3_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_25_8_3_SHAKE_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_25_8_3_SHAKE_SSK", BCObjectIdentifiers.snova_25_8_3_shake_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_25_8_3_SHAKE_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_25_8_3_SHAKE_ESK", BCObjectIdentifiers.snova_25_8_3_shake_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_29_6_5_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_29_6_5_SSK", BCObjectIdentifiers.snova_29_6_5_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_29_6_5_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_29_6_5_ESK", BCObjectIdentifiers.snova_29_6_5_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_29_6_5_SHAKE_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_29_6_5_SHAKE_SSK", BCObjectIdentifiers.snova_29_6_5_shake_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_29_6_5_SHAKE_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_29_6_5_SHAKE_ESK", BCObjectIdentifiers.snova_29_6_5_shake_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_37_8_4_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_37_8_4_SSK", BCObjectIdentifiers.snova_37_8_4_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_37_8_4_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_37_8_4_ESK", BCObjectIdentifiers.snova_37_8_4_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_37_8_4_SHAKE_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_37_8_4_SHAKE_SSK", BCObjectIdentifiers.snova_37_8_4_shake_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_37_8_4_SHAKE_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_37_8_4_SHAKE_ESK", BCObjectIdentifiers.snova_37_8_4_shake_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_37_17_2_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_37_17_2_SSK", BCObjectIdentifiers.snova_37_17_2_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_37_17_2_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_37_17_2_ESK", BCObjectIdentifiers.snova_37_17_2_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_37_17_2_SHAKE_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_37_17_2_SHAKE_SSK", BCObjectIdentifiers.snova_37_17_2_shake_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_37_17_2_SHAKE_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_37_17_2_SHAKE_ESK", BCObjectIdentifiers.snova_37_17_2_shake_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_49_11_3_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_49_11_3_SSK", BCObjectIdentifiers.snova_49_11_3_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_49_11_3_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_49_11_3_ESK", BCObjectIdentifiers.snova_49_11_3_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_49_11_3_SHAKE_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_49_11_3_SHAKE_SSK", BCObjectIdentifiers.snova_49_11_3_shake_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_49_11_3_SHAKE_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_49_11_3_SHAKE_ESK", BCObjectIdentifiers.snova_49_11_3_shake_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_56_25_2_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_56_25_2_SSK", BCObjectIdentifiers.snova_56_25_2_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_56_25_2_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_56_25_2_ESK", BCObjectIdentifiers.snova_56_25_2_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_56_25_2_SHAKE_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_56_25_2_SHAKE_SSK", BCObjectIdentifiers.snova_56_25_2_shake_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_56_25_2_SHAKE_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_56_25_2_SHAKE_ESK", BCObjectIdentifiers.snova_56_25_2_shake_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_60_10_4_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_60_10_4_SSK", BCObjectIdentifiers.snova_60_10_4_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_60_10_4_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_60_10_4_ESK", BCObjectIdentifiers.snova_60_10_4_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_60_10_4_SHAKE_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_60_10_4_SHAKE_SSK", BCObjectIdentifiers.snova_60_10_4_shake_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_60_10_4_SHAKE_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_60_10_4_SHAKE_ESK", BCObjectIdentifiers.snova_60_10_4_shake_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_66_15_3_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_66_15_3_SSK", BCObjectIdentifiers.snova_66_15_3_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_66_15_3_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_66_15_3_ESK", BCObjectIdentifiers.snova_66_15_3_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_66_15_3_SHAKE_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_66_15_3_SHAKE_SSK", BCObjectIdentifiers.snova_66_15_3_shake_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_66_15_3_SHAKE_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_66_15_3_SHAKE_ESK", BCObjectIdentifiers.snova_66_15_3_shake_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_75_33_2_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_75_33_2_SSK", BCObjectIdentifiers.snova_75_33_2_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_75_33_2_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_75_33_2_ESK", BCObjectIdentifiers.snova_75_33_2_esk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_75_33_2_SHAKE_SSK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_75_33_2_SHAKE_SSK", BCObjectIdentifiers.snova_75_33_2_shake_ssk); + addKeyPairGeneratorAlgorithm(provider, "SNOVA_75_33_2_SHAKE_ESK", PREFIX + "SnovaKeyPairGeneratorSpi$SNOVA_75_33_2_SHAKE_ESK", BCObjectIdentifiers.snova_75_33_2_shake_esk); + + addSignatureAlgorithm(provider, "Snova", PREFIX + "SignatureSpi$Base", BCObjectIdentifiers.snova); + + addSignatureAlgorithm(provider, "SNOVA_24_5_4_SSK", PREFIX + "SignatureSpi$SNOVA_24_5_4_SSK", BCObjectIdentifiers.snova_24_5_4_ssk); + addSignatureAlgorithm(provider, "SNOVA_24_5_4_ESK", PREFIX + "SignatureSpi$SNOVA_24_5_4_ESK", BCObjectIdentifiers.snova_24_5_4_esk); + addSignatureAlgorithm(provider, "SNOVA_24_5_4_SHAKE_SSK", PREFIX + "SignatureSpi$SNOVA_24_5_4_SHAKE_SSK", BCObjectIdentifiers.snova_24_5_4_shake_ssk); + addSignatureAlgorithm(provider, "SNOVA_24_5_4_SHAKE_ESK", PREFIX + "SignatureSpi$SNOVA_24_5_4_SHAKE_ESK", BCObjectIdentifiers.snova_24_5_4_shake_esk); + addSignatureAlgorithm(provider, "SNOVA_24_5_5_SSK", PREFIX + "SignatureSpi$SNOVA_24_5_5_SSK", BCObjectIdentifiers.snova_24_5_5_ssk); + addSignatureAlgorithm(provider, "SNOVA_24_5_5_ESK", PREFIX + "SignatureSpi$SNOVA_24_5_5_ESK", BCObjectIdentifiers.snova_24_5_5_esk); + addSignatureAlgorithm(provider, "SNOVA_24_5_5_SHAKE_SSK", PREFIX + "SignatureSpi$SNOVA_24_5_5_SHAKE_SSK", BCObjectIdentifiers.snova_24_5_5_shake_ssk); + addSignatureAlgorithm(provider, "SNOVA_24_5_5_SHAKE_ESK", PREFIX + "SignatureSpi$SNOVA_24_5_5_SHAKE_ESK", BCObjectIdentifiers.snova_24_5_5_shake_esk); + addSignatureAlgorithm(provider, "SNOVA_25_8_3_SSK", PREFIX + "SignatureSpi$SNOVA_25_8_3_SSK", BCObjectIdentifiers.snova_25_8_3_ssk); + addSignatureAlgorithm(provider, "SNOVA_25_8_3_ESK", PREFIX + "SignatureSpi$SNOVA_25_8_3_ESK", BCObjectIdentifiers.snova_25_8_3_esk); + addSignatureAlgorithm(provider, "SNOVA_25_8_3_SHAKE_SSK", PREFIX + "SignatureSpi$SNOVA_25_8_3_SHAKE_SSK", BCObjectIdentifiers.snova_25_8_3_shake_ssk); + addSignatureAlgorithm(provider, "SNOVA_25_8_3_SHAKE_ESK", PREFIX + "SignatureSpi$SNOVA_25_8_3_SHAKE_ESK", BCObjectIdentifiers.snova_25_8_3_shake_esk); + addSignatureAlgorithm(provider, "SNOVA_29_6_5_SSK", PREFIX + "SignatureSpi$SNOVA_29_6_5_SSK", BCObjectIdentifiers.snova_29_6_5_ssk); + addSignatureAlgorithm(provider, "SNOVA_29_6_5_ESK", PREFIX + "SignatureSpi$SNOVA_29_6_5_ESK", BCObjectIdentifiers.snova_29_6_5_esk); + addSignatureAlgorithm(provider, "SNOVA_29_6_5_SHAKE_SSK", PREFIX + "SignatureSpi$SNOVA_29_6_5_SHAKE_SSK", BCObjectIdentifiers.snova_29_6_5_shake_ssk); + addSignatureAlgorithm(provider, "SNOVA_29_6_5_SHAKE_ESK", PREFIX + "SignatureSpi$SNOVA_29_6_5_SHAKE_ESK", BCObjectIdentifiers.snova_29_6_5_shake_esk); + addSignatureAlgorithm(provider, "SNOVA_37_8_4_SSK", PREFIX + "SignatureSpi$SNOVA_37_8_4_SSK", BCObjectIdentifiers.snova_37_8_4_ssk); + addSignatureAlgorithm(provider, "SNOVA_37_8_4_ESK", PREFIX + "SignatureSpi$SNOVA_37_8_4_ESK", BCObjectIdentifiers.snova_37_8_4_esk); + addSignatureAlgorithm(provider, "SNOVA_37_8_4_SHAKE_SSK", PREFIX + "SignatureSpi$SNOVA_37_8_4_SHAKE_SSK", BCObjectIdentifiers.snova_37_8_4_shake_ssk); + addSignatureAlgorithm(provider, "SNOVA_37_8_4_SHAKE_ESK", PREFIX + "SignatureSpi$SNOVA_37_8_4_SHAKE_ESK", BCObjectIdentifiers.snova_37_8_4_shake_esk); + addSignatureAlgorithm(provider, "SNOVA_37_17_2_SSK", PREFIX + "SignatureSpi$SNOVA_37_17_2_SSK", BCObjectIdentifiers.snova_37_17_2_ssk); + addSignatureAlgorithm(provider, "SNOVA_37_17_2_ESK", PREFIX + "SignatureSpi$SNOVA_37_17_2_ESK", BCObjectIdentifiers.snova_37_17_2_esk); + addSignatureAlgorithm(provider, "SNOVA_37_17_2_SHAKE_SSK", PREFIX + "SignatureSpi$SNOVA_37_17_2_SHAKE_SSK", BCObjectIdentifiers.snova_37_17_2_shake_ssk); + addSignatureAlgorithm(provider, "SNOVA_37_17_2_SHAKE_ESK", PREFIX + "SignatureSpi$SNOVA_37_17_2_SHAKE_ESK", BCObjectIdentifiers.snova_37_17_2_shake_esk); + addSignatureAlgorithm(provider, "SNOVA_49_11_3_SSK", PREFIX + "SignatureSpi$SNOVA_49_11_3_SSK", BCObjectIdentifiers.snova_49_11_3_ssk); + addSignatureAlgorithm(provider, "SNOVA_49_11_3_ESK", PREFIX + "SignatureSpi$SNOVA_49_11_3_ESK", BCObjectIdentifiers.snova_49_11_3_esk); + addSignatureAlgorithm(provider, "SNOVA_49_11_3_SHAKE_SSK", PREFIX + "SignatureSpi$SNOVA_49_11_3_SHAKE_SSK", BCObjectIdentifiers.snova_49_11_3_shake_ssk); + addSignatureAlgorithm(provider, "SNOVA_49_11_3_SHAKE_ESK", PREFIX + "SignatureSpi$SNOVA_49_11_3_SHAKE_ESK", BCObjectIdentifiers.snova_49_11_3_shake_esk); + addSignatureAlgorithm(provider, "SNOVA_56_25_2_SSK", PREFIX + "SignatureSpi$SNOVA_56_25_2_SSK", BCObjectIdentifiers.snova_56_25_2_ssk); + addSignatureAlgorithm(provider, "SNOVA_56_25_2_ESK", PREFIX + "SignatureSpi$SNOVA_56_25_2_ESK", BCObjectIdentifiers.snova_56_25_2_esk); + addSignatureAlgorithm(provider, "SNOVA_56_25_2_SHAKE_SSK", PREFIX + "SignatureSpi$SNOVA_56_25_2_SHAKE_SSK", BCObjectIdentifiers.snova_56_25_2_shake_ssk); + addSignatureAlgorithm(provider, "SNOVA_56_25_2_SHAKE_ESK", PREFIX + "SignatureSpi$SNOVA_56_25_2_SHAKE_ESK", BCObjectIdentifiers.snova_56_25_2_shake_esk); + addSignatureAlgorithm(provider, "SNOVA_60_10_4_SSK", PREFIX + "SignatureSpi$SNOVA_60_10_4_SSK", BCObjectIdentifiers.snova_60_10_4_ssk); + addSignatureAlgorithm(provider, "SNOVA_60_10_4_ESK", PREFIX + "SignatureSpi$SNOVA_60_10_4_ESK", BCObjectIdentifiers.snova_60_10_4_esk); + addSignatureAlgorithm(provider, "SNOVA_60_10_4_SHAKE_SSK", PREFIX + "SignatureSpi$SNOVA_60_10_4_SHAKE_SSK", BCObjectIdentifiers.snova_60_10_4_shake_ssk); + addSignatureAlgorithm(provider, "SNOVA_60_10_4_SHAKE_ESK", PREFIX + "SignatureSpi$SNOVA_60_10_4_SHAKE_ESK", BCObjectIdentifiers.snova_60_10_4_shake_esk); + addSignatureAlgorithm(provider, "SNOVA_66_15_3_SSK", PREFIX + "SignatureSpi$SNOVA_66_15_3_SSK", BCObjectIdentifiers.snova_66_15_3_ssk); + addSignatureAlgorithm(provider, "SNOVA_66_15_3_ESK", PREFIX + "SignatureSpi$SNOVA_66_15_3_ESK", BCObjectIdentifiers.snova_66_15_3_esk); + addSignatureAlgorithm(provider, "SNOVA_66_15_3_SHAKE_SSK", PREFIX + "SignatureSpi$SNOVA_66_15_3_SHAKE_SSK", BCObjectIdentifiers.snova_66_15_3_shake_ssk); + addSignatureAlgorithm(provider, "SNOVA_66_15_3_SHAKE_ESK", PREFIX + "SignatureSpi$SNOVA_66_15_3_SHAKE_ESK", BCObjectIdentifiers.snova_66_15_3_shake_esk); + addSignatureAlgorithm(provider, "SNOVA_75_33_2_SSK", PREFIX + "SignatureSpi$SNOVA_75_33_2_SSK", BCObjectIdentifiers.snova_75_33_2_ssk); + addSignatureAlgorithm(provider, "SNOVA_75_33_2_ESK", PREFIX + "SignatureSpi$SNOVA_75_33_2_ESK", BCObjectIdentifiers.snova_75_33_2_esk); + addSignatureAlgorithm(provider, "SNOVA_75_33_2_SHAKE_SSK", PREFIX + "SignatureSpi$SNOVA_75_33_2_SHAKE_SSK", BCObjectIdentifiers.snova_75_33_2_shake_ssk); + addSignatureAlgorithm(provider, "SNOVA_75_33_2_SHAKE_ESK", PREFIX + "SignatureSpi$SNOVA_75_33_2_SHAKE_ESK", BCObjectIdentifiers.snova_75_33_2_shake_esk); + } + } +} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/bike/BIKEKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/bike/BIKEKeyPairGeneratorSpi.java index 00a9660731..bc1283a962 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/bike/BIKEKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/bike/BIKEKeyPairGeneratorSpi.java @@ -9,12 +9,12 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.bike.BIKEKeyGenerationParameters; import org.bouncycastle.pqc.crypto.bike.BIKEKeyPairGenerator; import org.bouncycastle.pqc.crypto.bike.BIKEParameters; import org.bouncycastle.pqc.crypto.bike.BIKEPrivateKeyParameters; import org.bouncycastle.pqc.crypto.bike.BIKEPublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.pqc.jcajce.spec.BIKEParameterSpec; import org.bouncycastle.util.Strings; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPrivateKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPrivateKey.java index e810a83003..a5868d94ce 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPrivateKey.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPrivateKey.java @@ -43,7 +43,7 @@ private void init(PrivateKeyInfo keyInfo) } /** - * Compare this SPHINCS-256 private key with another object. + * Compare this CMCE private key with another object. * * @param o the other object * @return the result of the comparison diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPublicKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPublicKey.java index 386b92a975..0d17b3793d 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPublicKey.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/BCCMCEPublicKey.java @@ -40,7 +40,7 @@ private void init(SubjectPublicKeyInfo keyInfo) } /** - * Compare this SPHINCS-256 public key with another object. + * Compare this CMCE public key with another object. * * @param o the other object * @return the result of the comparison diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/CMCEKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/CMCEKeyPairGeneratorSpi.java index 2ea2be425c..fdf4de84e1 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/CMCEKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/cmce/CMCEKeyPairGeneratorSpi.java @@ -9,12 +9,12 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.cmce.CMCEKeyGenerationParameters; import org.bouncycastle.pqc.crypto.cmce.CMCEKeyPairGenerator; import org.bouncycastle.pqc.crypto.cmce.CMCEParameters; import org.bouncycastle.pqc.crypto.cmce.CMCEPrivateKeyParameters; import org.bouncycastle.pqc.crypto.cmce.CMCEPublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.pqc.jcajce.spec.CMCEParameterSpec; import org.bouncycastle.util.Strings; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/dilithium/DilithiumKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/dilithium/DilithiumKeyPairGeneratorSpi.java index 5d3eb19284..ebc28a39de 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/dilithium/DilithiumKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/dilithium/DilithiumKeyPairGeneratorSpi.java @@ -10,12 +10,12 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.crystals.dilithium.DilithiumKeyGenerationParameters; import org.bouncycastle.pqc.crypto.crystals.dilithium.DilithiumKeyPairGenerator; import org.bouncycastle.pqc.crypto.crystals.dilithium.DilithiumParameters; import org.bouncycastle.pqc.crypto.crystals.dilithium.DilithiumPrivateKeyParameters; import org.bouncycastle.pqc.crypto.crystals.dilithium.DilithiumPublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.pqc.jcajce.spec.DilithiumParameterSpec; import org.bouncycastle.util.Strings; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/falcon/FalconKeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/falcon/FalconKeyFactorySpi.java index d4f36890a5..58adc178c5 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/falcon/FalconKeyFactorySpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/falcon/FalconKeyFactorySpi.java @@ -17,7 +17,6 @@ import org.bouncycastle.asn1.bc.BCObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; import org.bouncycastle.pqc.jcajce.provider.util.BaseKeyFactorySpi; public class FalconKeyFactorySpi diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/falcon/FalconKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/falcon/FalconKeyPairGeneratorSpi.java index c213ce17b1..61739f96d9 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/falcon/FalconKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/falcon/FalconKeyPairGeneratorSpi.java @@ -2,7 +2,6 @@ import java.security.InvalidAlgorithmParameterException; import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.util.HashMap; @@ -10,13 +9,12 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.falcon.FalconKeyGenerationParameters; import org.bouncycastle.pqc.crypto.falcon.FalconKeyPairGenerator; import org.bouncycastle.pqc.crypto.falcon.FalconParameters; import org.bouncycastle.pqc.crypto.falcon.FalconPrivateKeyParameters; import org.bouncycastle.pqc.crypto.falcon.FalconPublicKeyParameters; -import org.bouncycastle.pqc.crypto.falcon.FalconSigner; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.pqc.jcajce.spec.FalconParameterSpec; import org.bouncycastle.util.Strings; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/frodo/FrodoCipherSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/frodo/FrodoCipherSpi.java index f7f65a30a8..2520da5150 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/frodo/FrodoCipherSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/frodo/FrodoCipherSpi.java @@ -27,9 +27,6 @@ import org.bouncycastle.jcajce.spec.KEMParameterSpec; import org.bouncycastle.pqc.crypto.frodo.FrodoKEMExtractor; import org.bouncycastle.pqc.crypto.frodo.FrodoKEMGenerator; -import org.bouncycastle.pqc.crypto.hqc.HQCKEMGenerator; -import org.bouncycastle.pqc.jcajce.provider.hqc.BCHQCPrivateKey; -import org.bouncycastle.pqc.jcajce.provider.hqc.BCHQCPublicKey; import org.bouncycastle.pqc.jcajce.provider.util.WrapUtil; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Exceptions; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/frodo/FrodoKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/frodo/FrodoKeyPairGeneratorSpi.java index e40df6d9bf..83788367ec 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/frodo/FrodoKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/frodo/FrodoKeyPairGeneratorSpi.java @@ -9,12 +9,12 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.frodo.FrodoKeyGenerationParameters; import org.bouncycastle.pqc.crypto.frodo.FrodoKeyPairGenerator; import org.bouncycastle.pqc.crypto.frodo.FrodoParameters; import org.bouncycastle.pqc.crypto.frodo.FrodoPrivateKeyParameters; import org.bouncycastle.pqc.crypto.frodo.FrodoPublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.pqc.jcajce.spec.FrodoParameterSpec; import org.bouncycastle.util.Strings; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java deleted file mode 100644 index 53ea7c95e5..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/gmss/BCGMSSPublicKey.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.gmss; - -import java.security.PublicKey; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.CipherParameters; -import org.bouncycastle.pqc.asn1.GMSSPublicKey; -import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; -import org.bouncycastle.pqc.asn1.ParSet; -import org.bouncycastle.pqc.jcajce.provider.util.KeyUtil; -import org.bouncycastle.pqc.legacy.crypto.gmss.GMSSParameters; -import org.bouncycastle.pqc.legacy.crypto.gmss.GMSSPublicKeyParameters; -import org.bouncycastle.util.encoders.Hex; - -/** - * This class implements the GMSS public key and is usually initiated by the GMSSKeyPairGenerator. - * - * @see org.bouncycastle.pqc.legacy.crypto.gmss.GMSSKeyPairGenerator - */ -public class BCGMSSPublicKey - implements CipherParameters, PublicKey -{ - - /** - * - */ - private static final long serialVersionUID = 1L; - - /** - * The GMSS public key - */ - private byte[] publicKeyBytes; - - /** - * The GMSSParameterSet - */ - private GMSSParameters gmssParameterSet; - - - private GMSSParameters gmssParams; - - /** - * The constructor - * - * @param pub a raw GMSS public key - * @param gmssParameterSet an instance of GMSS Parameterset - * @see org.bouncycastle.pqc.legacy.crypto.gmss.GMSSKeyPairGenerator - */ - public BCGMSSPublicKey(byte[] pub, GMSSParameters gmssParameterSet) - { - this.gmssParameterSet = gmssParameterSet; - this.publicKeyBytes = pub; - } - - public BCGMSSPublicKey( - GMSSPublicKeyParameters params) - { - this(params.getPublicKey(), params.getParameters()); - } - - /** - * Returns the name of the algorithm - * - * @return "GMSS" - */ - public String getAlgorithm() - { - return "GMSS"; - } - - /** - * @return The GMSS public key byte array - */ - public byte[] getPublicKeyBytes() - { - return publicKeyBytes; - } - - /** - * @return The GMSS Parameterset - */ - public GMSSParameters getParameterSet() - { - return gmssParameterSet; - } - - /** - * Returns a human readable form of the GMSS public key - * - * @return A human readable form of the GMSS public key - */ - public String toString() - { - String out = "GMSS public key : " - + new String(Hex.encode(publicKeyBytes)) + "\n" - + "Height of Trees: \n"; - - for (int i = 0; i < gmssParameterSet.getHeightOfTrees().length; i++) - { - out = out + "Layer " + i + " : " - + gmssParameterSet.getHeightOfTrees()[i] - + " WinternitzParameter: " - + gmssParameterSet.getWinternitzParameter()[i] + " K: " - + gmssParameterSet.getK()[i] + "\n"; - } - return out; - } - - public byte[] getEncoded() - { - return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PQCObjectIdentifiers.gmss, new ParSet(gmssParameterSet.getNumOfLayers(), gmssParameterSet.getHeightOfTrees(), gmssParameterSet.getWinternitzParameter(), gmssParameterSet.getK()).toASN1Primitive()), new GMSSPublicKey(publicKeyBytes)); - } - - public String getFormat() - { - return "X.509"; - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCCipherSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCCipherSpi.java index 2281b93db1..7f6fbaf374 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCCipherSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCCipherSpi.java @@ -19,7 +19,6 @@ import javax.crypto.spec.SecretKeySpec; import javax.security.auth.DestroyFailedException; -import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.SecretWithEncapsulation; import org.bouncycastle.crypto.Wrapper; @@ -154,7 +153,7 @@ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec paramSpec, if (key instanceof BCHQCPublicKey) { wrapKey = (BCHQCPublicKey)key; - kemGen = new HQCKEMGenerator(CryptoServicesRegistrar.getSecureRandom(random)); + kemGen = new HQCKEMGenerator(random); } else { @@ -251,7 +250,7 @@ protected byte[] engineWrap( Wrapper kWrap = WrapUtil.getWrapper(kemParameterSpec.getKeyAlgorithmName()); - KeyParameter keyParameter = new KeyParameter(secEnc.getSecret()); + KeyParameter keyParameter = new KeyParameter(WrapUtil.trimSecret(kemParameterSpec.getKeyAlgorithmName(), secEnc.getSecret())); kWrap.init(true, keyParameter); @@ -296,7 +295,7 @@ protected Key engineUnwrap( Wrapper kWrap = WrapUtil.getWrapper(kemParameterSpec.getKeyAlgorithmName()); - KeyParameter keyParameter = new KeyParameter(secret); + KeyParameter keyParameter = new KeyParameter(WrapUtil.trimSecret(kemParameterSpec.getKeyAlgorithmName(), secret)); Arrays.clear(secret); diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKeyFactorySpi.java index e3b08b6ada..4a36a31c10 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKeyFactorySpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKeyFactorySpi.java @@ -3,23 +3,44 @@ 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 java.util.HashSet; +import java.util.Set; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.bc.BCObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; +import org.bouncycastle.pqc.jcajce.provider.util.BaseKeyFactorySpi; public class HQCKeyFactorySpi - extends KeyFactorySpi - implements AsymmetricKeyInfoConverter + extends BaseKeyFactorySpi { + private static final Set keyOids = new HashSet(); + + static + { + keyOids.add(BCObjectIdentifiers.hqc128); + keyOids.add(BCObjectIdentifiers.hqc192); + keyOids.add(BCObjectIdentifiers.hqc256); + } + + public HQCKeyFactorySpi() + { + super(keyOids); + } + + public HQCKeyFactorySpi(ASN1ObjectIdentifier keyOids) + { + super(keyOids); + } + public PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException { @@ -113,4 +134,31 @@ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo) { return new BCHQCPublicKey(keyInfo); } + + public static class HQC128 + extends HQCKeyFactorySpi + { + public HQC128() + { + super(BCObjectIdentifiers.hqc128); + } + } + + public static class HQC192 + extends HQCKeyFactorySpi + { + public HQC192() + { + super(BCObjectIdentifiers.hqc192); + } + } + + public static class HQC256 + extends HQCKeyFactorySpi + { + public HQC256() + { + super(BCObjectIdentifiers.hqc256); + } + } } diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKeyGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKeyGeneratorSpi.java index 87619dd57b..cd0d6e51b7 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKeyGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKeyGeneratorSpi.java @@ -15,14 +15,27 @@ import org.bouncycastle.jcajce.spec.KEMGenerateSpec; import org.bouncycastle.pqc.crypto.hqc.HQCKEMExtractor; import org.bouncycastle.pqc.crypto.hqc.HQCKEMGenerator; +import org.bouncycastle.pqc.crypto.hqc.HQCParameters; +import org.bouncycastle.pqc.jcajce.spec.HQCParameterSpec; import org.bouncycastle.util.Arrays; public class HQCKeyGeneratorSpi - extends KeyGeneratorSpi + extends KeyGeneratorSpi { private KEMGenerateSpec genSpec; private SecureRandom random; private KEMExtractSpec extSpec; + private HQCParameters hqcParameters; + + public HQCKeyGeneratorSpi() + { + this(null); + } + + public HQCKeyGeneratorSpi(HQCParameters hqcParameters) + { + this.hqcParameters = hqcParameters; + } protected void engineInit(SecureRandom secureRandom) { @@ -30,18 +43,34 @@ protected void engineInit(SecureRandom secureRandom) } protected void engineInit(AlgorithmParameterSpec algorithmParameterSpec, SecureRandom secureRandom) - throws InvalidAlgorithmParameterException + throws InvalidAlgorithmParameterException { this.random = secureRandom; if (algorithmParameterSpec instanceof KEMGenerateSpec) { this.genSpec = (KEMGenerateSpec)algorithmParameterSpec; this.extSpec = null; + if (hqcParameters != null) + { + String canonicalAlgName = HQCParameterSpec.fromName(hqcParameters.getName()).getName(); + if (!canonicalAlgName.equals(genSpec.getPublicKey().getAlgorithm())) + { + throw new InvalidAlgorithmParameterException("key generator locked to " + canonicalAlgName); + } + } } else if (algorithmParameterSpec instanceof KEMExtractSpec) { this.genSpec = null; this.extSpec = (KEMExtractSpec)algorithmParameterSpec; + if (hqcParameters != null) + { + String canonicalAlgName = HQCParameterSpec.fromName(hqcParameters.getName()).getName(); + if (!canonicalAlgName.equals(extSpec.getPrivateKey().getAlgorithm())) + { + throw new InvalidAlgorithmParameterException("key generator locked to " + canonicalAlgName); + } + } } else { @@ -91,4 +120,31 @@ protected SecretKey engineGenerateKey() return rv; } } + + public static class HQC128 + extends HQCKeyGeneratorSpi + { + public HQC128() + { + super(HQCParameters.hqc128); + } + } + + public static class HQC192 + extends HQCKeyGeneratorSpi + { + public HQC192() + { + super(HQCParameters.hqc192); + } + } + + public static class HQC256 + extends HQCKeyGeneratorSpi + { + public HQC256() + { + super(HQCParameters.hqc256); + } + } } diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKeyPairGeneratorSpi.java index 989f22714d..81046a75e5 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKeyPairGeneratorSpi.java @@ -2,6 +2,7 @@ import java.security.InvalidAlgorithmParameterException; import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.util.HashMap; @@ -9,17 +10,17 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.hqc.HQCKeyGenerationParameters; import org.bouncycastle.pqc.crypto.hqc.HQCKeyPairGenerator; import org.bouncycastle.pqc.crypto.hqc.HQCParameters; import org.bouncycastle.pqc.crypto.hqc.HQCPrivateKeyParameters; import org.bouncycastle.pqc.crypto.hqc.HQCPublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.pqc.jcajce.spec.HQCParameterSpec; import org.bouncycastle.util.Strings; public class HQCKeyPairGeneratorSpi - extends java.security.KeyPairGenerator + extends java.security.KeyPairGenerator { private static Map parameters = new HashMap(); @@ -45,17 +46,22 @@ public HQCKeyPairGeneratorSpi() super("HQC"); } + protected HQCKeyPairGeneratorSpi(HQCParameterSpec paramSpec) + { + super(Strings.toUpperCase(paramSpec.getName())); + } + public void initialize( - int strength, - SecureRandom random) + int strength, + SecureRandom random) { throw new IllegalArgumentException("use AlgorithmParameterSpec"); } public void initialize( - AlgorithmParameterSpec params, - SecureRandom random) - throws InvalidAlgorithmParameterException + AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidAlgorithmParameterException { String name = getNameFromParams(params); @@ -101,4 +107,34 @@ public KeyPair generateKeyPair() return new KeyPair(new BCHQCPublicKey(pub), new BCHQCPrivateKey(priv)); } + + public static class HQC128 + extends HQCKeyPairGeneratorSpi + { + public HQC128() + throws NoSuchAlgorithmException + { + super(HQCParameterSpec.hqc128); + } + } + + public static class HQC192 + extends HQCKeyPairGeneratorSpi + { + public HQC192() + throws NoSuchAlgorithmException + { + super(HQCParameterSpec.hqc192); + } + } + + public static class HQC256 + extends HQCKeyPairGeneratorSpi + { + public HQC256() + throws NoSuchAlgorithmException + { + super(HQCParameterSpec.hqc256); + } + } } diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/kyber/KyberCipherSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/kyber/KyberCipherSpi.java index 3712391a38..7f4d432d0e 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/kyber/KyberCipherSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/kyber/KyberCipherSpi.java @@ -154,7 +154,7 @@ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec paramSpec, if (key instanceof BCKyberPublicKey) { wrapKey = (BCKyberPublicKey)key; - kemGen = new MLKEMGenerator(CryptoServicesRegistrar.getSecureRandom(random)); + kemGen = new MLKEMGenerator(random); } else { @@ -235,6 +235,7 @@ protected int engineDoFinal(byte[] bytes, int i, int i1, byte[] bytes1, int i2) throw new IllegalStateException("Not supported in a wrapping mode"); } + @SuppressWarnings("Finally") protected byte[] engineWrap( Key key) throws IllegalBlockSizeException, InvalidKeyException diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/kyber/KyberKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/kyber/KyberKeyPairGeneratorSpi.java index 0c72535fd7..c64435471f 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/kyber/KyberKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/kyber/KyberKeyPairGeneratorSpi.java @@ -9,12 +9,12 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.mlkem.MLKEMKeyGenerationParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMKeyPairGenerator; import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMPrivateKeyParameters; import org.bouncycastle.pqc.crypto.mlkem.MLKEMPublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.pqc.jcajce.spec.KyberParameterSpec; import org.bouncycastle.util.Strings; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/BCMayoPrivateKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/BCMayoPrivateKey.java new file mode 100644 index 0000000000..043fee5635 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/BCMayoPrivateKey.java @@ -0,0 +1,131 @@ +package org.bouncycastle.pqc.jcajce.provider.mayo; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.PrivateKey; + +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.pqc.crypto.mayo.MayoPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; +import org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory; +import org.bouncycastle.pqc.jcajce.interfaces.MayoKey; +import org.bouncycastle.pqc.jcajce.spec.MayoParameterSpec; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +public class BCMayoPrivateKey + implements PrivateKey, MayoKey +{ + private static final long serialVersionUID = 1L; + + private transient MayoPrivateKeyParameters params; + private transient ASN1Set attributes; + + public BCMayoPrivateKey( + MayoPrivateKeyParameters params) + { + this.params = params; + } + + public BCMayoPrivateKey(PrivateKeyInfo keyInfo) + throws IOException + { + init(keyInfo); + } + + private void init(PrivateKeyInfo keyInfo) + throws IOException + { + this.attributes = keyInfo.getAttributes(); + this.params = (MayoPrivateKeyParameters) PrivateKeyFactory.createKey(keyInfo); + } + + /** + * Compare this private key with another object. + * + * @param o the other object + * @return the result of the comparison + */ + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (o instanceof BCMayoPrivateKey) + { + BCMayoPrivateKey otherKey = (BCMayoPrivateKey)o; + + return Arrays.areEqual(params.getEncoded(), otherKey.params.getEncoded()); + } + + return false; + } + + public int hashCode() + { + return Arrays.hashCode(params.getEncoded()); + } + + /** + * @return name of the algorithm - "Mayo[1|2|3|5]" + */ + public final String getAlgorithm() + { + return Strings.toUpperCase(params.getParameters().getName()); + } + + public byte[] getEncoded() + { + + try + { + PrivateKeyInfo pki = PrivateKeyInfoFactory.createPrivateKeyInfo(params, attributes); + + return pki.getEncoded(); + } + catch (IOException e) + { + return null; + } + } + + public MayoParameterSpec getParameterSpec() + { + return MayoParameterSpec.fromName(params.getParameters().getName()); + } + + public String getFormat() + { + return "PKCS#8"; + } + + MayoPrivateKeyParameters getKeyParams() + { + return params; + } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(PrivateKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } +} + diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/BCMayoPublicKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/BCMayoPublicKey.java new file mode 100644 index 0000000000..5d53ecc839 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/BCMayoPublicKey.java @@ -0,0 +1,127 @@ +package org.bouncycastle.pqc.jcajce.provider.mayo; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.PublicKey; + +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameters; +import org.bouncycastle.pqc.crypto.util.PublicKeyFactory; +import org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory; +import org.bouncycastle.pqc.jcajce.interfaces.MayoKey; +import org.bouncycastle.pqc.jcajce.spec.MayoParameterSpec; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +public class BCMayoPublicKey + implements PublicKey, MayoKey +{ + private static final long serialVersionUID = 1L; + + private transient MayoPublicKeyParameters params; + + public BCMayoPublicKey( + MayoPublicKeyParameters params) + { + this.params = params; + } + + public BCMayoPublicKey(SubjectPublicKeyInfo keyInfo) + throws IOException + { + init(keyInfo); + } + + private void init(SubjectPublicKeyInfo keyInfo) + throws IOException + { + this.params = (MayoPublicKeyParameters) PublicKeyFactory.createKey(keyInfo); + } + + /** + * Compare this BIKE public key with another object. + * + * @param o the other object + * @return the result of the comparison + */ + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (o instanceof BCMayoPublicKey) + { + BCMayoPublicKey otherKey = (BCMayoPublicKey)o; + + return Arrays.areEqual(params.getEncoded(), otherKey.params.getEncoded()); + } + + return false; + } + + public int hashCode() + { + return Arrays.hashCode(params.getEncoded()); + } + + /** + * @return name of the algorithm - "Mayo[1|2|3|5]" + */ + public final String getAlgorithm() + { + return Strings.toUpperCase(params.getParameters().getName()); + } + + public byte[] getEncoded() + { + try + { + SubjectPublicKeyInfo pki = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(params); + + return pki.getEncoded(); + } + catch (IOException e) + { + return null; + } + } + + public String getFormat() + { + return "X.509"; + } + + public MayoParameterSpec getParameterSpec() + { + return MayoParameterSpec.fromName(params.getParameters().getName()); + } + + MayoPublicKeyParameters getKeyParams() + { + return params; + } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(SubjectPublicKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } +} + diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/MayoKeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/MayoKeyFactorySpi.java new file mode 100644 index 0000000000..f27d25e86d --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/MayoKeyFactorySpi.java @@ -0,0 +1,130 @@ +package org.bouncycastle.pqc.jcajce.provider.mayo; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.Key; +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 java.util.HashSet; +import java.util.Set; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.bc.BCObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.pqc.jcajce.provider.util.BaseKeyFactorySpi; + +public class MayoKeyFactorySpi + extends BaseKeyFactorySpi +{ + private static final Set keyOids = new HashSet(); + + static + { + keyOids.add(BCObjectIdentifiers.mayo1); + keyOids.add(BCObjectIdentifiers.mayo2); + keyOids.add(BCObjectIdentifiers.mayo3); + keyOids.add(BCObjectIdentifiers.mayo5); + } + + public MayoKeyFactorySpi() + { + super(keyOids); + } + + public MayoKeyFactorySpi(ASN1ObjectIdentifier keyOid) + { + super(keyOid); + } + + public final KeySpec engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + if (key instanceof BCMayoPrivateKey) + { + if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) + { + return new PKCS8EncodedKeySpec(key.getEncoded()); + } + } + else if (key instanceof BCMayoPublicKey) + { + 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 BCMayoPrivateKey || key instanceof BCMayoPublicKey) + { + return key; + } + + throw new InvalidKeyException("Unsupported key type"); + } + + public PrivateKey generatePrivate(PrivateKeyInfo keyInfo) + throws IOException + { + return new BCMayoPrivateKey(keyInfo); + } + + public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo) + throws IOException + { + return new BCMayoPublicKey(keyInfo); + } + + public static class Mayo1 + extends MayoKeyFactorySpi + { + public Mayo1() + { + super(BCObjectIdentifiers.mayo1); + } + } + + public static class Mayo2 + extends MayoKeyFactorySpi + { + public Mayo2() + { + super(BCObjectIdentifiers.mayo2); + } + } + + public static class Mayo3 + extends MayoKeyFactorySpi + { + public Mayo3() + { + super(BCObjectIdentifiers.mayo3); + } + } + + public static class Mayo5 + extends MayoKeyFactorySpi + { + public Mayo5() + { + super(BCObjectIdentifiers.mayo5); + } + } +} + diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/MayoKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/MayoKeyPairGeneratorSpi.java new file mode 100644 index 0000000000..79acb2ed87 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/MayoKeyPairGeneratorSpi.java @@ -0,0 +1,148 @@ +package org.bouncycastle.pqc.jcajce.provider.mayo; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; +import org.bouncycastle.pqc.crypto.mayo.MayoKeyGenerationParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoKeyPairGenerator; +import org.bouncycastle.pqc.crypto.mayo.MayoParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoPublicKeyParameters; +import org.bouncycastle.pqc.jcajce.spec.MayoParameterSpec; +import org.bouncycastle.util.Strings; + +public class MayoKeyPairGeneratorSpi + extends java.security.KeyPairGenerator +{ + private static Map parameters = new HashMap(); + + static + { + parameters.put("MAYO_1", MayoParameters.mayo1); + parameters.put("MAYO_2", MayoParameters.mayo2); + parameters.put("MAYO_3", MayoParameters.mayo3); + parameters.put("MAYO_5", MayoParameters.mayo5); + parameters.put(MayoParameterSpec.mayo1.getName(), MayoParameters.mayo1); + parameters.put(MayoParameterSpec.mayo2.getName(), MayoParameters.mayo2); + parameters.put(MayoParameterSpec.mayo3.getName(), MayoParameters.mayo3); + parameters.put(MayoParameterSpec.mayo5.getName(), MayoParameters.mayo5); + } + + MayoKeyGenerationParameters param; + private MayoParameters mayoParameters; + MayoKeyPairGenerator engine = new MayoKeyPairGenerator(); + + SecureRandom random = CryptoServicesRegistrar.getSecureRandom(); + boolean initialised = false; + + public MayoKeyPairGeneratorSpi() + { + super("Mayo"); + } + + protected MayoKeyPairGeneratorSpi(MayoParameters mayoParameters) + { + super(mayoParameters.getName()); + this.mayoParameters = mayoParameters; + } + + public void initialize( + int strength, + SecureRandom random) + { + throw new IllegalArgumentException("use AlgorithmParameterSpec"); + } + + public void initialize( + AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidAlgorithmParameterException + { + String name = getNameFromParams(params); + + if (name != null) + { + param = new MayoKeyGenerationParameters(random, (MayoParameters)parameters.get(name)); + + engine.init(param); + initialised = true; + } + else + { + throw new InvalidAlgorithmParameterException("invalid ParameterSpec: " + params); + } + } + + private static String getNameFromParams(AlgorithmParameterSpec paramSpec) + { + if (paramSpec instanceof MayoParameterSpec) + { + MayoParameterSpec MayoParams = (MayoParameterSpec)paramSpec; + return MayoParams.getName(); + } + else + { + return Strings.toLowerCase(SpecUtil.getNameFrom(paramSpec)); + } + } + + public KeyPair generateKeyPair() + { + if (!initialised) + { + param = new MayoKeyGenerationParameters(random, MayoParameters.mayo1); + + engine.init(param); + initialised = true; + } + + AsymmetricCipherKeyPair pair = engine.generateKeyPair(); + MayoPublicKeyParameters pub = (MayoPublicKeyParameters)pair.getPublic(); + MayoPrivateKeyParameters priv = (MayoPrivateKeyParameters)pair.getPrivate(); + + return new KeyPair(new BCMayoPublicKey(pub), new BCMayoPrivateKey(priv)); + } + + public static class Mayo1 + extends MayoKeyPairGeneratorSpi + { + public Mayo1() + { + super(MayoParameters.mayo1); + } + } + + public static class Mayo2 + extends MayoKeyPairGeneratorSpi + { + public Mayo2() + { + super(MayoParameters.mayo2); + } + } + + public static class Mayo3 + extends MayoKeyPairGeneratorSpi + { + public Mayo3() + { + super(MayoParameters.mayo3); + } + } + + public static class Mayo5 + extends MayoKeyPairGeneratorSpi + { + public Mayo5() + { + super(MayoParameters.mayo5); + } + } +} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/SignatureSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/SignatureSpi.java similarity index 65% rename from prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/SignatureSpi.java rename to prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/SignatureSpi.java index 14213bb3ac..0a1075657e 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/SignatureSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mayo/SignatureSpi.java @@ -1,4 +1,4 @@ -package org.bouncycastle.pqc.jcajce.provider.rainbow; +package org.bouncycastle.pqc.jcajce.provider.mayo; import java.io.ByteArrayOutputStream; import java.security.InvalidKeyException; @@ -11,28 +11,28 @@ import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.pqc.crypto.rainbow.RainbowParameters; -import org.bouncycastle.pqc.crypto.rainbow.RainbowSigner; +import org.bouncycastle.pqc.crypto.mayo.MayoParameters; +import org.bouncycastle.pqc.crypto.mayo.MayoSigner; import org.bouncycastle.util.Strings; public class SignatureSpi extends java.security.Signature { - private ByteArrayOutputStream bOut; - private RainbowSigner signer; + private final ByteArrayOutputStream bOut; + private final MayoSigner signer; private SecureRandom random; - private RainbowParameters parameters; + private final MayoParameters parameters; - protected SignatureSpi(RainbowSigner signer) + protected SignatureSpi(MayoSigner signer) { - super("RAINBOW"); - + super("Mayo"); + this.bOut = new ByteArrayOutputStream(); this.signer = signer; this.parameters = null; } - protected SignatureSpi(RainbowSigner signer, RainbowParameters parameters) + protected SignatureSpi(MayoSigner signer, MayoParameters parameters) { super(Strings.toUpperCase(parameters.getName())); this.parameters = parameters; @@ -44,19 +44,19 @@ protected SignatureSpi(RainbowSigner signer, RainbowParameters parameters) protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { - if (!(publicKey instanceof BCRainbowPublicKey)) + if (!(publicKey instanceof BCMayoPublicKey)) { try { - publicKey = new BCRainbowPublicKey(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + publicKey = new BCMayoPublicKey(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); } catch (Exception e) { - throw new InvalidKeyException("unknown public key passed to Rainbow: " + e.getMessage(), e); + throw new InvalidKeyException("unknown public key passed to Mayo: " + e.getMessage()); } } - BCRainbowPublicKey key = (BCRainbowPublicKey)publicKey; + BCMayoPublicKey key = (BCMayoPublicKey)publicKey; if (parameters != null) { @@ -80,9 +80,9 @@ protected void engineInitSign(PrivateKey privateKey, SecureRandom random) protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { - if (privateKey instanceof BCRainbowPrivateKey) + if (privateKey instanceof BCMayoPrivateKey) { - BCRainbowPrivateKey key = (BCRainbowPrivateKey)privateKey; + BCMayoPrivateKey key = (BCMayoPrivateKey)privateKey; CipherParameters param = key.getKeyParams(); if (parameters != null) @@ -105,18 +105,18 @@ protected void engineInitSign(PrivateKey privateKey) } else { - throw new InvalidKeyException("unknown private key passed to Rainbow"); + throw new InvalidKeyException("unknown private key passed to Mayo"); } } protected void engineUpdate(byte b) - throws SignatureException + throws SignatureException { bOut.write(b); } protected void engineUpdate(byte[] b, int off, int len) - throws SignatureException + throws SignatureException { bOut.write(b, off, len); } @@ -171,65 +171,48 @@ protected Object engineGetParameter(String param) } public static class Base - extends SignatureSpi + extends org.bouncycastle.pqc.jcajce.provider.mayo.SignatureSpi { public Base() { - super(new RainbowSigner()); - } - } - - public static class RainbowIIIclassic - extends SignatureSpi - { - public RainbowIIIclassic() - { - super(new RainbowSigner(), RainbowParameters.rainbowIIIclassic); + super(new MayoSigner()); } } - public static class RainbowIIIcircum - extends SignatureSpi + public static class Mayo1 + extends org.bouncycastle.pqc.jcajce.provider.mayo.SignatureSpi { - public RainbowIIIcircum() + public Mayo1() { - super(new RainbowSigner(), RainbowParameters.rainbowIIIcircumzenithal); + super(new MayoSigner(), MayoParameters.mayo1); } } - public static class RainbowIIIcomp - extends SignatureSpi + public static class Mayo2 + extends org.bouncycastle.pqc.jcajce.provider.mayo.SignatureSpi { - public RainbowIIIcomp() + public Mayo2() { - super(new RainbowSigner(), RainbowParameters.rainbowIIIcompressed); + super(new MayoSigner(), MayoParameters.mayo2); } } - public static class RainbowVclassic - extends SignatureSpi + public static class Mayo3 + extends org.bouncycastle.pqc.jcajce.provider.mayo.SignatureSpi { - public RainbowVclassic() + public Mayo3() { - super(new RainbowSigner(), RainbowParameters.rainbowVclassic); + super(new MayoSigner(), MayoParameters.mayo3); } } - public static class RainbowVcircum - extends SignatureSpi + public static class Mayo5 + extends org.bouncycastle.pqc.jcajce.provider.mayo.SignatureSpi { - public RainbowVcircum() + public Mayo5() { - super(new RainbowSigner(), RainbowParameters.rainbowVcircumzenithal); - } - } - - public static class RainbowVcomp - extends SignatureSpi - { - public RainbowVcomp() - { - super(new RainbowSigner(), RainbowParameters.rainbowVcompressed); + super(new MayoSigner(), MayoParameters.mayo5); } } } + diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java deleted file mode 100644 index 6e163a9da8..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PrivateKey.java +++ /dev/null @@ -1,233 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.mceliece; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.security.PrivateKey; - -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.jcajce.util.MessageDigestUtils; -import org.bouncycastle.pqc.asn1.McElieceCCA2PrivateKey; -import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; -import org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2KeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PrivateKeyParameters; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.legacy.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialGF2mSmallM; - -/** - * This class implements a McEliece CCA2 private key and is usually instantiated - * by the {@link McElieceCCA2KeyPairGenerator} or {@link McElieceCCA2KeyFactorySpi}. - * - * @see McElieceCCA2KeyPairGenerator - */ -public class BCMcElieceCCA2PrivateKey - implements PrivateKey -{ - private static final long serialVersionUID = 1L; - - private transient McElieceCCA2PrivateKeyParameters params; - - public BCMcElieceCCA2PrivateKey(McElieceCCA2PrivateKeyParameters params) - { - this.params = params; - } - - private void init(PrivateKeyInfo privateKeyInfo) - throws IOException - { - this.params = (McElieceCCA2PrivateKeyParameters)PrivateKeyFactory.createKey(privateKeyInfo); - } - - /** - * Return the name of the algorithm. - * - * @return "McEliece-CCA2" - */ - public String getAlgorithm() - { - return "McEliece-CCA2"; - } - - /** - * @return the length of the code - */ - public int getN() - { - return params.getN(); - } - - /** - * @return the dimension of the code - */ - public int getK() - { - return params.getK(); - } - - /** - * @return the degree of the Goppa polynomial (error correcting capability) - */ - public int getT() - { - return params.getGoppaPoly().getDegree(); - } - - /** - * @return the finite field - */ - public GF2mField getField() - { - return params.getField(); - } - - /** - * @return the irreducible Goppa polynomial - */ - public PolynomialGF2mSmallM getGoppaPoly() - { - return params.getGoppaPoly(); - } - - /** - * @return the permutation vector - */ - public Permutation getP() - { - return params.getP(); - } - - /** - * @return the canonical check matrix - */ - public GF2Matrix getH() - { - return params.getH(); - } - - /** - * @return the matrix used to compute square roots in (GF(2^m))^t - */ - public PolynomialGF2mSmallM[] getQInv() - { - return params.getQInv(); - } - - /** - * @return a human readable form of the key - */ - // TODO: -// public String toString() -// { -// String result = ""; -// result += " extension degree of the field : " + getN() + "\n"; -// result += " dimension of the code : " + getK() + "\n"; -// result += " irreducible Goppa polynomial : " + getGoppaPoly() + "\n"; -// return result; -// } - - /** - * Compare this key with another object. - * - * @param other the other object - * @return the result of the comparison - */ - public boolean equals(Object other) - { - if (other == null || !(other instanceof BCMcElieceCCA2PrivateKey)) - { - return false; - } - - BCMcElieceCCA2PrivateKey otherKey = (BCMcElieceCCA2PrivateKey)other; - - return (getN() == otherKey.getN()) && (getK() == otherKey.getK()) - && getField().equals(otherKey.getField()) - && getGoppaPoly().equals(otherKey.getGoppaPoly()) && getP().equals(otherKey.getP()) - && getH().equals(otherKey.getH()); - } - - /** - * @return the hash code of this key - */ - public int hashCode() - { - int code = params.getK(); - - code = code * 37 + params.getN(); - code = code * 37 + params.getField().hashCode(); - code = code * 37 + params.getGoppaPoly().hashCode(); - code = code * 37 + params.getP().hashCode(); - - return code * 37 + params.getH().hashCode(); - } - - /** - * Return the keyData to encode in the SubjectPublicKeyInfo structure. - *

    - * The ASN.1 definition of the key structure is - *

    -     *   McEliecePrivateKey ::= 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
    -     *     matrixH       OCTET STRING             -- canonical check matrix
    -     *     sqRootMatrix  SEQUENCE OF OCTET STRING -- square root matrix
    -     *   }
    -     * 
    - * @return the keyData to encode in the SubjectPublicKeyInfo structure - */ - public byte[] getEncoded() - { - PrivateKeyInfo pki; - try - { - McElieceCCA2PrivateKey privateKey = new McElieceCCA2PrivateKey(getN(), getK(), getField(), getGoppaPoly(), getP(), MessageDigestUtils.getDigestAlgID(params.getDigest())); - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.mcElieceCca2); - - pki = new PrivateKeyInfo(algorithmIdentifier, privateKey); - - return pki.getEncoded(); - } - catch (IOException e) - { - return null; - } - } - - public String getFormat() - { - return "PKCS#8"; - } - - AsymmetricKeyParameter getKeyParams() - { - return params; - } - - private void readObject( - ObjectInputStream in) - throws IOException, ClassNotFoundException - { - in.defaultReadObject(); - - byte[] enc = (byte[])in.readObject(); - - init(PrivateKeyInfo.getInstance(enc)); - } - - private void writeObject( - ObjectOutputStream out) - throws IOException - { - out.defaultWriteObject(); - - out.writeObject(this.getEncoded()); - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java deleted file mode 100644 index e6416003aa..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcElieceCCA2PublicKey.java +++ /dev/null @@ -1,182 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.mceliece; - - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.security.PublicKey; - -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.jcajce.util.MessageDigestUtils; -import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey; -import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; -import org.bouncycastle.pqc.crypto.util.PublicKeyFactory; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2KeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PublicKeyParameters; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; - -/** - * This class implements a McEliece CCA2 public key and is usually instantiated - * by the {@link McElieceCCA2KeyPairGenerator} or {@link McElieceCCA2KeyFactorySpi}. - */ -public class BCMcElieceCCA2PublicKey - implements CipherParameters, PublicKey -{ - private static final long serialVersionUID = 1L; - - private transient McElieceCCA2PublicKeyParameters params; - - public BCMcElieceCCA2PublicKey(McElieceCCA2PublicKeyParameters params) - { - this.params = params; - } - - private void init(SubjectPublicKeyInfo publicKeyInfo) - throws IOException - { - this.params = (McElieceCCA2PublicKeyParameters)PublicKeyFactory.createKey(publicKeyInfo); - } - /** - * Return the name of the algorithm. - * - * @return "McEliece" - */ - public String getAlgorithm() - { - return "McEliece-CCA2"; - } - - /** - * @return the length of the code - */ - public int getN() - { - return params.getN(); - } - - /** - * @return the dimension of the code - */ - public int getK() - { - return params.getK(); - } - - /** - * @return the error correction capability of the code - */ - public int getT() - { - return params.getT(); - } - - /** - * @return the generator matrix - */ - public GF2Matrix getG() - { - return params.getG(); - } - - /** - * @return a human readable form of the key - */ - public String toString() - { - String result = "McEliecePublicKey:\n"; - result += " length of the code : " + params.getN() + "\n"; - result += " error correction capability: " + params.getT() + "\n"; - result += " generator matrix : " + params.getG().toString(); - return result; - } - - /** - * Compare this key with another object. - * - * @param other the other object - * @return the result of the comparison - */ - public boolean equals(Object other) - { - if (other == null || !(other instanceof BCMcElieceCCA2PublicKey)) - { - return false; - } - - BCMcElieceCCA2PublicKey otherKey = (BCMcElieceCCA2PublicKey)other; - - return (params.getN() == otherKey.getN()) && (params.getT() == otherKey.getT()) && (params.getG().equals(otherKey.getG())); - } - - /** - * @return the hash code of this key - */ - public int hashCode() - { - return 37 * (params.getN() + 37 * params.getT()) + params.getG().hashCode(); - } - - /** - * Return the keyData to encode in the SubjectPublicKeyInfo structure. - *

    - * The ASN.1 definition of the key structure is - *

    -     *       McEliecePublicKey ::= SEQUENCE {
    -     *         n           Integer      -- length of the code
    -     *         t           Integer      -- error correcting capability
    -     *         matrixG     OctetString  -- generator matrix as octet string
    -     *       }
    -     * 
    - * @return the keyData to encode in the SubjectPublicKeyInfo structure - */ - public byte[] getEncoded() - { - McElieceCCA2PublicKey key = new McElieceCCA2PublicKey(params.getN(), params.getT(), params.getG(), MessageDigestUtils.getDigestAlgID(params.getDigest())); - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.mcElieceCca2); - - try - { - SubjectPublicKeyInfo subjectPublicKeyInfo = new SubjectPublicKeyInfo(algorithmIdentifier, key); - - return subjectPublicKeyInfo.getEncoded(); - } - catch (IOException e) - { - return null; - } - - } - - public String getFormat() - { - return "X.509"; - } - - AsymmetricKeyParameter getKeyParams() - { - return params; - } - - private void readObject( - ObjectInputStream in) - throws IOException, ClassNotFoundException - { - in.defaultReadObject(); - - byte[] enc = (byte[])in.readObject(); - - init(SubjectPublicKeyInfo.getInstance(enc)); - } - - private void writeObject( - ObjectOutputStream out) - throws IOException - { - out.defaultWriteObject(); - - out.writeObject(this.getEncoded()); - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java deleted file mode 100644 index ac11421f0f..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePrivateKey.java +++ /dev/null @@ -1,223 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.mceliece; - -import java.io.IOException; -import java.security.PrivateKey; - -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.legacy.crypto.mceliece.McElieceKeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McEliecePrivateKeyParameters; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.legacy.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialGF2mSmallM; - -/** - * This class implements a McEliece private key and is usually instantiated by - * the {@link McElieceKeyPairGenerator} or {@link McElieceKeyFactorySpi}. - */ -public class BCMcEliecePrivateKey - implements CipherParameters, PrivateKey -{ - private static final long serialVersionUID = 1L; - - private McEliecePrivateKeyParameters params; - - public BCMcEliecePrivateKey(McEliecePrivateKeyParameters params) - { - this.params = params; - } - - /** - * Return the name of the algorithm. - * - * @return "McEliece" - */ - public String getAlgorithm() - { - return "McEliece"; - } - - /** - * @return the length of the code - */ - public int getN() - { - return params.getN(); - } - - /** - * @return the dimension of the code - */ - public int getK() - { - return params.getK(); - } - - /** - * @return the finite field - */ - public GF2mField getField() - { - return params.getField(); - } - - /** - * @return the irreducible Goppa polynomial - */ - public PolynomialGF2mSmallM getGoppaPoly() - { - return params.getGoppaPoly(); - } - - /** - * @return the k x k random binary non-singular matrix S - */ - public GF2Matrix getSInv() - { - return params.getSInv(); - } - - /** - * @return the permutation used to generate the systematic check matrix - */ - public Permutation getP1() - { - return params.getP1(); - } - - /** - * @return the permutation used to compute the public generator matrix - */ - public Permutation getP2() - { - return params.getP2(); - } - - /** - * @return the canonical check matrix - */ - public GF2Matrix getH() - { - return params.getH(); - } - - /** - * @return the matrix for computing square roots in (GF(2^m))^t - */ - public PolynomialGF2mSmallM[] getQInv() - { - return params.getQInv(); - } - - /* - * @return a human readable form of the key - */ - // TODO: -// public String toString() -// { -// 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; -// } - - /** - * Compare this key with another object. - * - * @param other the other object - * @return the result of the comparison - */ - public boolean equals(Object other) - { - if (!(other instanceof BCMcEliecePrivateKey)) - { - return false; - } - BCMcEliecePrivateKey otherKey = (BCMcEliecePrivateKey)other; - - 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()); - } - - /** - * @return the hash code of this key - */ - public int hashCode() - { - int code = params.getK(); - - 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 code * 37 + params.getSInv().hashCode(); - } - - /** - * Return the key data to encode in the SubjectPublicKeyInfo structure. - *

    - * The ASN.1 definition of the key structure is - *

    - *
    -     *   McEliecePrivateKey ::= SEQUENCE {
    -     *     n          INTEGER                   -- length of the code
    -     *     k          INTEGER                   -- dimension of the code
    -     *     fieldPoly  OCTET STRING              -- field polynomial defining GF(2ˆm)
    -     *     getGoppaPoly()  OCTET STRING              -- irreducible Goppa polynomial
    -     *     sInv       OCTET STRING              -- matrix Sˆ-1
    -     *     p1         OCTET STRING              -- permutation P1
    -     *     p2         OCTET STRING              -- permutation P2
    -     *     h          OCTET STRING              -- canonical check matrix
    -     *     qInv       SEQUENCE OF OCTET STRING  -- matrix used to compute square roots
    -     *   }
    -     * 
    - * - * @return the key data to encode in the SubjectPublicKeyInfo structure - */ - public byte[] getEncoded() - { - 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(PQCObjectIdentifiers.mcEliece); - pki = new PrivateKeyInfo(algorithmIdentifier, privateKey); - } - catch (IOException e) - { - return null; - } - try - { - byte[] encoded = pki.getEncoded(); - return encoded; - } - catch (IOException e) - { - return null; - } - } - - public String getFormat() - { - return "PKCS#8"; - } - - AsymmetricKeyParameter getKeyParams() - { - return params; - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java deleted file mode 100644 index 04acafd460..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/BCMcEliecePublicKey.java +++ /dev/null @@ -1,151 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.mceliece; - -import java.io.IOException; -import java.security.PublicKey; - -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.pqc.asn1.McEliecePublicKey; -import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceKeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McEliecePublicKeyParameters; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; - -/** - * This class implements a McEliece public key and is usually instantiated by - * the {@link McElieceKeyPairGenerator} or {@link McElieceKeyFactorySpi}. - */ -public class BCMcEliecePublicKey - implements PublicKey -{ - private static final long serialVersionUID = 1L; - - private McEliecePublicKeyParameters params; - - public BCMcEliecePublicKey(McEliecePublicKeyParameters params) - { - this.params = params; - } - - /** - * Return the name of the algorithm. - * - * @return "McEliece" - */ - public String getAlgorithm() - { - return "McEliece"; - } - - /** - * @return the length of the code - */ - public int getN() - { - return params.getN(); - } - - /** - * @return the dimension of the code - */ - public int getK() - { - return params.getK(); - } - - /** - * @return the error correction capability of the code - */ - public int getT() - { - return params.getT(); - } - - /** - * @return the generator matrix - */ - public GF2Matrix getG() - { - return params.getG(); - } - - /** - * @return a human readable form of the key - */ - public String toString() - { - String result = "McEliecePublicKey:\n"; - result += " length of the code : " + params.getN() + "\n"; - result += " error correction capability: " + params.getT() + "\n"; - result += " generator matrix : " + params.getG(); - return result; - } - - /** - * Compare this key with another object. - * - * @param other the other object - * @return the result of the comparison - */ - public boolean equals(Object other) - { - if (other instanceof BCMcEliecePublicKey) - { - BCMcEliecePublicKey otherKey = (BCMcEliecePublicKey)other; - - return (params.getN() == otherKey.getN()) && (params.getT() == otherKey.getT()) && (params.getG().equals(otherKey.getG())); - } - - return false; - } - - /** - * @return the hash code of this key - */ - public int hashCode() - { - return 37 * (params.getN() + 37 * params.getT()) + params.getG().hashCode(); - } - - /** - * Return the keyData to encode in the SubjectPublicKeyInfo structure. - *

    - * The ASN.1 definition of the key structure is - *

    - *
    -     *       McEliecePublicKey ::= SEQUENCE {
    -     *         n           Integer      -- length of the code
    -     *         t           Integer      -- error correcting capability
    -     *         matrixG     OctetString  -- generator matrix as octet string
    -     *       }
    -     * 
    - * @return the keyData to encode in the SubjectPublicKeyInfo structure - */ - public byte[] getEncoded() - { - McEliecePublicKey key = new McEliecePublicKey(params.getN(), params.getT(), params.getG()); - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.mcEliece); - - try - { - SubjectPublicKeyInfo subjectPublicKeyInfo = new SubjectPublicKeyInfo(algorithmIdentifier, key); - - return subjectPublicKeyInfo.getEncoded(); - } - catch (IOException e) - { - return null; - } - } - - public String getFormat() - { - return "X.509"; - } - - AsymmetricKeyParameter getKeyParams() - { - return params; - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java deleted file mode 100644 index 6dcddf4eb8..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyFactorySpi.java +++ /dev/null @@ -1,240 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.mceliece; - -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; -import org.bouncycastle.pqc.asn1.McElieceCCA2PrivateKey; -import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey; -import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PublicKeyParameters; - -/** - * This class is used to translate between McEliece CCA2 keys and key - * specifications. - * - * @see BCMcElieceCCA2PrivateKey - * @see BCMcElieceCCA2PublicKey - */ -public class McElieceCCA2KeyFactorySpi - extends KeyFactorySpi - implements AsymmetricKeyInfoConverter -{ - - /** - * The OID of the algorithm. - */ - public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.2"; - - /** - * Converts, if possible, a key specification into a - * {@link BCMcElieceCCA2PublicKey}. Currently, the following key - * 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. - */ - protected 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 - SubjectPublicKeyInfo pki; - try - { - pki = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)); - } - catch (IOException e) - { - throw new InvalidKeySpecException(e.toString()); - } - - - try - { - if (PQCObjectIdentifiers.mcElieceCca2.equals(pki.getAlgorithm().getAlgorithm())) - { - McElieceCCA2PublicKey key = McElieceCCA2PublicKey.getInstance(pki.parsePublicKey()); - - 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) - { - throw new InvalidKeySpecException( - "Unable to decode X509EncodedKeySpec: " - + cce.getMessage()); - } - } - - throw new InvalidKeySpecException("Unsupported key specification: " - + keySpec.getClass() + "."); - } - - /** - * Converts, if possible, a key specification into a - * {@link BCMcElieceCCA2PrivateKey}. Currently, the following key - * specifications are supported: - * {@link PKCS8EncodedKeySpec}. - * - * @param keySpec the key specification - * @return the McEliece CCA2 private key - * @throws InvalidKeySpecException if the KeySpec is not supported. - */ - protected 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(); - - // decode the PKCS#8 data structure to the pki object - PrivateKeyInfo pki; - - try - { - pki = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)); - } - catch (IOException e) - { - throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec: " + e); - } - - try - { - if (PQCObjectIdentifiers.mcElieceCca2.equals(pki.getPrivateKeyAlgorithm().getAlgorithm())) - { - McElieceCCA2PrivateKey key = McElieceCCA2PrivateKey.getInstance(pki.parsePrivateKey()); - - return new BCMcElieceCCA2PrivateKey(new McElieceCCA2PrivateKeyParameters(key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getP(), Utils.getDigest(key.getDigest()).getAlgorithmName())); - } - else - { - throw new InvalidKeySpecException("Unable to recognise OID in McEliece public key"); - } - } - catch (IOException cce) - { - throw new InvalidKeySpecException( - "Unable to decode PKCS8EncodedKeySpec."); - } - } - - 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: - * - * @param key the key - * @param keySpec the key specification - * @return the specification of the McEliece CCA2 key - * @throws InvalidKeySpecException if the key type or the key specification is not - * supported. - * @see BCMcElieceCCA2PrivateKey - * @see BCMcElieceCCA2PublicKey - */ - public KeySpec getKeySpec(Key key, Class keySpec) - throws InvalidKeySpecException - { - if (key instanceof BCMcElieceCCA2PrivateKey) - { - if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) - { - return new PKCS8EncodedKeySpec(key.getEncoded()); - } - } - else if (key instanceof BCMcElieceCCA2PublicKey) - { - 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 + "."); - } - - /** - * Translates a key into a form known by the FlexiProvider. Currently, only - * the following "source" keys are supported: {@link BCMcElieceCCA2PrivateKey}, - * {@link BCMcElieceCCA2PublicKey}. - * - * @param key the key - * @return a key of a known key type - * @throws InvalidKeyException if the key type is not supported. - */ - public Key translateKey(Key key) - throws InvalidKeyException - { - if ((key instanceof BCMcElieceCCA2PrivateKey) - || (key instanceof BCMcElieceCCA2PublicKey)) - { - return key; - } - throw new InvalidKeyException("Unsupported key type."); - - } - - public PublicKey generatePublic(SubjectPublicKeyInfo pki) - throws IOException - { - // get the inner type inside the BIT STRING - ASN1Primitive innerType = pki.parsePublicKey(); - McElieceCCA2PublicKey key = McElieceCCA2PublicKey.getInstance(innerType); - return new BCMcElieceCCA2PublicKey(new McElieceCCA2PublicKeyParameters(key.getN(), key.getT(), key.getG(), Utils.getDigest(key.getDigest()).getAlgorithmName())); - } - - public PrivateKey generatePrivate(PrivateKeyInfo pki) - throws IOException - { - // get the inner type inside the BIT STRING - ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive(); - McElieceCCA2PrivateKey key = McElieceCCA2PrivateKey.getInstance(innerType); - return new BCMcElieceCCA2PrivateKey(new McElieceCCA2PrivateKeyParameters(key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getP(), null)); - } - - protected KeySpec engineGetKeySpec(Key key, Class tClass) - throws InvalidKeySpecException - { - // TODO: - return null; //To change body of implemented methods use File | Settings | File Templates. - } - - protected Key engineTranslateKey(Key key) - throws InvalidKeyException - { - // TODO: - return null; //To change body of implemented methods use File | Settings | File Templates. - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyPairGeneratorSpi.java deleted file mode 100644 index 9e708f20f5..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyPairGeneratorSpi.java +++ /dev/null @@ -1,68 +0,0 @@ -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.crypto.CryptoServicesRegistrar; -import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2KeyGenParameterSpec; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2KeyGenerationParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2KeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2Parameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PublicKeyParameters; - -public class McElieceCCA2KeyPairGeneratorSpi - extends KeyPairGenerator -{ - private McElieceCCA2KeyPairGenerator kpg; - - public McElieceCCA2KeyPairGeneratorSpi() - { - super("McEliece-CCA2"); - } - - public void initialize(AlgorithmParameterSpec params, SecureRandom random) - throws InvalidAlgorithmParameterException - { - kpg = new McElieceCCA2KeyPairGenerator(); - - McElieceCCA2KeyGenParameterSpec ecc = (McElieceCCA2KeyGenParameterSpec)params; - - McElieceCCA2KeyGenerationParameters mccca2KGParams = new McElieceCCA2KeyGenerationParameters( - random, new McElieceCCA2Parameters(ecc.getM(), ecc.getT(), ecc.getDigest())); - kpg.init(mccca2KGParams); - } - - public void initialize(AlgorithmParameterSpec params) - throws InvalidAlgorithmParameterException - { - kpg = new McElieceCCA2KeyPairGenerator(); - - McElieceCCA2KeyGenParameterSpec ecc = (McElieceCCA2KeyGenParameterSpec)params; - - McElieceCCA2KeyGenerationParameters mccca2KGParams = new McElieceCCA2KeyGenerationParameters( - CryptoServicesRegistrar.getSecureRandom(), 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/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java deleted file mode 100644 index 397855099a..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeysToParams.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.mceliece; - -import java.security.InvalidKeyException; -import java.security.PrivateKey; -import java.security.PublicKey; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; - -/** - * utility class for converting jce/jca McElieceCCA2 objects - * objects into their org.bouncycastle.crypto counterparts. - */ -public class McElieceCCA2KeysToParams -{ - - - static public AsymmetricKeyParameter generatePublicKeyParameter( - PublicKey key) - throws InvalidKeyException - { - if (key instanceof BCMcElieceCCA2PublicKey) - { - BCMcElieceCCA2PublicKey k = (BCMcElieceCCA2PublicKey)key; - - return k.getKeyParams(); - } - - throw new InvalidKeyException("can't identify McElieceCCA2 public key: " + key.getClass().getName()); - } - - - static public AsymmetricKeyParameter generatePrivateKeyParameter( - PrivateKey key) - throws InvalidKeyException - { - if (key instanceof BCMcElieceCCA2PrivateKey) - { - BCMcElieceCCA2PrivateKey k = (BCMcElieceCCA2PrivateKey)key; - - return k.getKeyParams(); - } - - throw new InvalidKeyException("can't identify McElieceCCA2 private key."); - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java deleted file mode 100644 index c32943bfad..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.mceliece; - -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2PublicKeyParameters; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Matrix; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Vector; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2mField; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GoppaCode; -import org.bouncycastle.pqc.legacy.math.linearalgebra.Permutation; -import org.bouncycastle.pqc.legacy.math.linearalgebra.PolynomialGF2mSmallM; -import org.bouncycastle.pqc.legacy.math.linearalgebra.Vector; - -/** - * Core operations for the CCA-secure variants of McEliece. - */ -public final class McElieceCCA2Primitives -{ - - /** - * Default constructor (private). - */ - private McElieceCCA2Primitives() - { - } - - /** - * The McEliece encryption primitive. - * - * @param pubKey the public key - * @param m the message vector - * @param z the error vector - * @return m*G + z - */ - public static GF2Vector encryptionPrimitive(BCMcElieceCCA2PublicKey pubKey, - GF2Vector m, GF2Vector z) - { - - GF2Matrix matrixG = pubKey.getG(); - Vector mG = matrixG.leftMultiplyLeftCompactForm(m); - return (GF2Vector)mG.add(z); - } - - public static GF2Vector encryptionPrimitive(McElieceCCA2PublicKeyParameters pubKey, - GF2Vector m, GF2Vector z) - { - - GF2Matrix matrixG = pubKey.getG(); - Vector mG = matrixG.leftMultiplyLeftCompactForm(m); - return (GF2Vector)mG.add(z); - } - - /** - * The McEliece decryption primitive. - * - * @param privKey the private key - * @param c the ciphertext vector c = m*G + z - * @return the message vector m and the error vector z - */ - public static GF2Vector[] decryptionPrimitive( - BCMcElieceCCA2PrivateKey privKey, GF2Vector c) - { - - // obtain values from private key - int k = privKey.getK(); - Permutation p = privKey.getP(); - GF2mField field = privKey.getField(); - PolynomialGF2mSmallM gp = privKey.getGoppaPoly(); - GF2Matrix h = privKey.getH(); - PolynomialGF2mSmallM[] q = privKey.getQInv(); - - // compute inverse permutation P^-1 - Permutation pInv = p.computeInverse(); - - // multiply c with permutation P^-1 - GF2Vector cPInv = (GF2Vector)c.multiply(pInv); - - // compute syndrome of cP^-1 - GF2Vector syndVec = (GF2Vector)h.rightMultiply(cPInv); - - // decode syndrome - GF2Vector errors = GoppaCode.syndromeDecode(syndVec, field, gp, q); - GF2Vector mG = (GF2Vector)cPInv.add(errors); - - // multiply codeword and error vector with P - mG = (GF2Vector)mG.multiply(p); - errors = (GF2Vector)errors.multiply(p); - - // extract plaintext vector (last k columns of mG) - GF2Vector m = mG.extractRightVector(k); - - // return vectors - return new GF2Vector[]{m, errors}; - } - - public static GF2Vector[] decryptionPrimitive( - McElieceCCA2PrivateKeyParameters privKey, GF2Vector c) - { - - // obtain values from private key - int k = privKey.getK(); - Permutation p = privKey.getP(); - GF2mField field = privKey.getField(); - PolynomialGF2mSmallM gp = privKey.getGoppaPoly(); - GF2Matrix h = privKey.getH(); - PolynomialGF2mSmallM[] q = privKey.getQInv(); - - // compute inverse permutation P^-1 - Permutation pInv = p.computeInverse(); - - // multiply c with permutation P^-1 - GF2Vector cPInv = (GF2Vector)c.multiply(pInv); - - // compute syndrome of cP^-1 - GF2Vector syndVec = (GF2Vector)h.rightMultiply(cPInv); - - // decode syndrome - GF2Vector errors = GoppaCode.syndromeDecode(syndVec, field, gp, q); - GF2Vector mG = (GF2Vector)cPInv.add(errors); - - // multiply codeword and error vector with P - mG = (GF2Vector)mG.multiply(p); - errors = (GF2Vector)errors.multiply(p); - - // extract plaintext vector (last k columns of mG) - GF2Vector m = mG.extractRightVector(k); - - // return vectors - return new GF2Vector[]{m, errors}; - } - -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java deleted file mode 100644 index 6859ca4826..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceFujisakiCipherSpi.java +++ /dev/null @@ -1,172 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.mceliece; - -import java.io.ByteArrayOutputStream; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; - -import javax.crypto.BadPaddingException; - -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.InvalidCipherTextException; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.crypto.util.DigestFactory; -import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2KeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceFujisakiCipher; - -public class McElieceFujisakiCipherSpi - extends AsymmetricHybridCipher - implements PKCSObjectIdentifiers, X509ObjectIdentifiers -{ - // TODO digest needed? - private Digest digest; - private McElieceFujisakiCipher cipher; - - /** - * buffer to store the input data - */ - private ByteArrayOutputStream buf; - - - protected McElieceFujisakiCipherSpi(Digest digest, McElieceFujisakiCipher cipher) - { - this.digest = digest; - this.cipher = cipher; - buf = new ByteArrayOutputStream(); - - } - - /** - * Continue a multiple-part encryption or decryption operation. - * - * @param input byte array containing the next part of the input - * @param inOff index in the array where the input starts - * @param inLen length of the input - * @return the processed byte array. - */ - public byte[] update(byte[] input, int inOff, int inLen) - { - buf.write(input, inOff, inLen); - return new byte[0]; - } - - - /** - * Encrypts or decrypts data in a single-part operation, or finishes a - * multiple-part operation. The data is encrypted or decrypted, depending on - * how this cipher was initialized. - * - * @param input the input buffer - * @param inOff the offset in input where the input starts - * @param inLen the input length - * @return the new buffer with the result - * @throws BadPaddingException on deryption errors. - */ - public byte[] doFinal(byte[] input, int inOff, int inLen) - throws BadPaddingException - { - update(input, inOff, inLen); - byte[] data = buf.toByteArray(); - buf.reset(); - - if (opMode == ENCRYPT_MODE) - { - return cipher.messageEncrypt(data); - } - else if (opMode == DECRYPT_MODE) - { - try - { - return cipher.messageDecrypt(data); - } - catch (InvalidCipherTextException e) - { - throw new BadPaddingException(e.getMessage()); - } - } - else - { - throw new IllegalStateException("unknown mode in doFinal"); - } - } - - - protected int encryptOutputSize(int inLen) - { - return 0; - } - - protected int decryptOutputSize(int inLen) - { - return 0; - } - - protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params, - SecureRandom sr) - throws InvalidKeyException, - InvalidAlgorithmParameterException - { - - CipherParameters param; - param = McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key); - - param = new ParametersWithRandom(param, sr); - digest.reset(); - cipher.init(true, param); - - } - - protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params) - throws InvalidKeyException, InvalidAlgorithmParameterException - { - - CipherParameters param; - param = McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key); - - digest.reset(); - cipher.init(false, param); - } - - public String getName() - { - return "McElieceFujisakiCipher"; - } - - public int getKeySize(Key key) - throws InvalidKeyException - { - McElieceCCA2KeyParameters mcElieceCCA2KeyParameters; - if (key instanceof PublicKey) - { - mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key); - } - else - { - mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key); - - } - - - return cipher.getKeySize(mcElieceCCA2KeyParameters); - } - - - ////////////////////////////////////////////////////////////////////////////////// - - static public class McElieceFujisaki - extends McElieceFujisakiCipherSpi - { - public McElieceFujisaki() - { - super(DigestFactory.createSHA1(), new McElieceFujisakiCipher()); - } - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java deleted file mode 100644 index 422e9d7473..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyFactorySpi.java +++ /dev/null @@ -1,242 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.mceliece; - -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.AlgorithmIdentifier; -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; -import org.bouncycastle.pqc.asn1.McEliecePrivateKey; -import org.bouncycastle.pqc.asn1.McEliecePublicKey; -import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McEliecePrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McEliecePublicKeyParameters; - -/** - * This class is used to translate between McEliece keys and key specifications. - * - * @see BCMcEliecePrivateKey - * @see BCMcEliecePublicKey - */ -public class McElieceKeyFactorySpi - extends KeyFactorySpi - implements AsymmetricKeyInfoConverter -{ - /** - * The OID of the algorithm. - */ - public static final String OID = "1.3.6.1.4.1.8301.3.1.3.4.1"; - - /** - * Converts, if possible, a key specification into a - * {@link BCMcEliecePublicKey}. {@link X509EncodedKeySpec}. - * - * @param keySpec the key specification - * @return the McEliece public key - * @throws InvalidKeySpecException if the key specification is not supported. - */ - protected 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 - SubjectPublicKeyInfo pki; - try - { - pki = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)); - } - catch (IOException e) - { - throw new InvalidKeySpecException(e.toString()); - } - - try - { - if (PQCObjectIdentifiers.mcEliece.equals(pki.getAlgorithm().getAlgorithm())) - { - McEliecePublicKey key = McEliecePublicKey.getInstance(pki.parsePublicKey()); - - 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) - { - throw new InvalidKeySpecException( - "Unable to decode X509EncodedKeySpec: " - + cce.getMessage()); - } - } - - throw new InvalidKeySpecException("Unsupported key specification: " - + keySpec.getClass() + "."); - } - - /** - * Converts, if possible, a key specification into a - * {@link BCMcEliecePrivateKey}. - * - * @param keySpec the key specification - * @return the McEliece private key - * @throws InvalidKeySpecException if the KeySpec is not supported. - */ - protected 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(); - - // decode the PKCS#8 data structure to the pki object - PrivateKeyInfo pki; - - try - { - pki = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey)); - } - catch (IOException e) - { - throw new InvalidKeySpecException("Unable to decode PKCS8EncodedKeySpec: " + e); - } - - try - { - if (PQCObjectIdentifiers.mcEliece.equals(pki.getPrivateKeyAlgorithm().getAlgorithm())) - { - McEliecePrivateKey key = McEliecePrivateKey.getInstance(pki.parsePrivateKey()); - - return new BCMcEliecePrivateKey(new McEliecePrivateKeyParameters(key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getP1(), key.getP2(), key.getSInv())); - } - else - { - throw new InvalidKeySpecException("Unable to recognise OID in McEliece private key"); - } - } - catch (IOException cce) - { - throw new InvalidKeySpecException( - "Unable to decode PKCS8EncodedKeySpec."); - } - } - - 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: - * - * @param key the key - * @param keySpec the key specification - * @return the specification of the McEliece key - * @throws InvalidKeySpecException if the key type or the key specification is not - * supported. - * @see BCMcEliecePrivateKey - * @see BCMcEliecePublicKey - */ - public KeySpec getKeySpec(Key key, Class keySpec) - throws InvalidKeySpecException - { - if (key instanceof BCMcEliecePrivateKey) - { - if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) - { - return new PKCS8EncodedKeySpec(key.getEncoded()); - } - } - else if (key instanceof BCMcEliecePublicKey) - { - 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 + "."); - } - - /** - * Translates a key into a form known by the FlexiProvider. Currently, only - * the following "source" keys are supported: {@link BCMcEliecePrivateKey}, - * {@link BCMcEliecePublicKey}. - * - * @param key the key - * @return a key of a known key type - * @throws InvalidKeyException if the key type is not supported. - */ - public Key translateKey(Key key) - throws InvalidKeyException - { - if ((key instanceof BCMcEliecePrivateKey) - || (key instanceof BCMcEliecePublicKey)) - { - return key; - } - throw new InvalidKeyException("Unsupported key type."); - - } - - public PublicKey generatePublic(SubjectPublicKeyInfo pki) - throws IOException - { - // get the inner type inside the BIT STRING - ASN1Primitive innerType = pki.parsePublicKey(); - McEliecePublicKey key = McEliecePublicKey.getInstance(innerType); - return new BCMcEliecePublicKey(new McEliecePublicKeyParameters(key.getN(), key.getT(), key.getG())); - } - - public PrivateKey generatePrivate(PrivateKeyInfo pki) - throws IOException - { - // get the inner type inside the BIT STRING - ASN1Primitive innerType = pki.parsePrivateKey().toASN1Primitive(); - McEliecePrivateKey key = McEliecePrivateKey.getInstance(innerType); - return new BCMcEliecePrivateKey(new McEliecePrivateKeyParameters(key.getN(), key.getK(), key.getField(), key.getGoppaPoly(), key.getP1(), key.getP2(), key.getSInv())); - } - - protected KeySpec engineGetKeySpec(Key key, Class tClass) - throws InvalidKeySpecException - { - // TODO: - return null; //To change body of implemented methods use File | Settings | File Templates. - } - - protected Key engineTranslateKey(Key key) - throws InvalidKeyException - { - // TODO: - 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/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java deleted file mode 100644 index bdf321e9d4..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java +++ /dev/null @@ -1,61 +0,0 @@ -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.jcajce.spec.McElieceKeyGenParameterSpec; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceKeyGenerationParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceKeyPairGenerator; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McEliecePrivateKeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McEliecePublicKeyParameters; - -public class McElieceKeyPairGeneratorSpi - extends KeyPairGenerator -{ - McElieceKeyPairGenerator kpg; - - public McElieceKeyPairGeneratorSpi() - { - super("McEliece"); - } - - public void initialize(AlgorithmParameterSpec params, SecureRandom random) - throws InvalidAlgorithmParameterException - { - kpg = new McElieceKeyPairGenerator(); - McElieceKeyGenParameterSpec ecc = (McElieceKeyGenParameterSpec)params; - - McElieceKeyGenerationParameters mccKGParams = new McElieceKeyGenerationParameters( - random, new McElieceParameters(ecc.getM(), ecc.getT())); - kpg.init(mccKGParams); - } - - public void initialize(int keySize, SecureRandom random) - { - McElieceKeyGenParameterSpec paramSpec = new McElieceKeyGenParameterSpec(); - - // call the initializer with the chosen parameters - try - { - this.initialize(paramSpec, random); - } - 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)); - } - -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java deleted file mode 100644 index e1591ceb94..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeysToParams.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.mceliece; - -import java.security.InvalidKeyException; -import java.security.PrivateKey; -import java.security.PublicKey; - -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McEliecePrivateKeyParameters; - -/** - * utility class for converting jce/jca McEliece objects - * objects into their org.bouncycastle.crypto counterparts. - */ -public class McElieceKeysToParams -{ - - - static public AsymmetricKeyParameter generatePublicKeyParameter( - PublicKey key) - throws InvalidKeyException - { - if (key instanceof BCMcEliecePublicKey) - { - BCMcEliecePublicKey k = (BCMcEliecePublicKey)key; - - return k.getKeyParams(); - } - - throw new InvalidKeyException("can't identify McEliece public key: " + key.getClass().getName()); - } - - - static public AsymmetricKeyParameter generatePrivateKeyParameter( - PrivateKey key) - throws InvalidKeyException - { - if (key instanceof BCMcEliecePrivateKey) - { - BCMcEliecePrivateKey k = (BCMcEliecePrivateKey)key; - 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/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java deleted file mode 100644 index ff8546b742..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKobaraImaiCipherSpi.java +++ /dev/null @@ -1,260 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.mceliece; - -import java.io.ByteArrayOutputStream; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; - -import javax.crypto.BadPaddingException; - -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.InvalidCipherTextException; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.crypto.util.DigestFactory; -import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2KeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceKobaraImaiCipher; - -public class McElieceKobaraImaiCipherSpi - extends AsymmetricHybridCipher - implements PKCSObjectIdentifiers, X509ObjectIdentifiers -{ - - // TODO digest needed? - private Digest digest; - private McElieceKobaraImaiCipher cipher; - - /** - * buffer to store the input data - */ - private ByteArrayOutputStream buf = new ByteArrayOutputStream(); - - - public McElieceKobaraImaiCipherSpi() - { - buf = new ByteArrayOutputStream(); - } - - protected McElieceKobaraImaiCipherSpi(Digest digest, McElieceKobaraImaiCipher cipher) - { - this.digest = digest; - this.cipher = cipher; - buf = new ByteArrayOutputStream(); - } - - /** - * Continue a multiple-part encryption or decryption operation. - * - * @param input byte array containing the next part of the input - * @param inOff index in the array where the input starts - * @param inLen length of the input - * @return the processed byte array. - */ - public byte[] update(byte[] input, int inOff, int inLen) - { - buf.write(input, inOff, inLen); - return new byte[0]; - } - - - /** - * Encrypts or decrypts data in a single-part operation, or finishes a - * multiple-part operation. The data is encrypted or decrypted, depending on - * how this cipher was initialized. - * - * @param input the input buffer - * @param inOff the offset in input where the input starts - * @param inLen the input length - * @return the new buffer with the result - * @throws BadPaddingException if this cipher is in decryption mode, and (un)padding has - * been requested, but the decrypted data is not bounded by - * the appropriate padding bytes - */ - public byte[] doFinal(byte[] input, int inOff, int inLen) - throws BadPaddingException - { - update(input, inOff, inLen); - if (opMode == ENCRYPT_MODE) - { - return cipher.messageEncrypt(this.pad()); - } - else if (opMode == DECRYPT_MODE) - { - try - { - byte[] inputOfDecr = buf.toByteArray(); - buf.reset(); - - return unpad(cipher.messageDecrypt(inputOfDecr)); - } - catch (InvalidCipherTextException e) - { - throw new BadPaddingException(e.getMessage()); - } - } - else - { - throw new IllegalStateException("unknown mode in doFinal"); - } - } - - protected int encryptOutputSize(int inLen) - { - return 0; - } - - protected int decryptOutputSize(int inLen) - { - return 0; - } - - protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params, - SecureRandom sr) - throws InvalidKeyException, - InvalidAlgorithmParameterException - { - - buf.reset(); - CipherParameters param; - param = McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key); - - param = new ParametersWithRandom(param, sr); - digest.reset(); - cipher.init(true, param); - } - - protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params) - throws InvalidKeyException, InvalidAlgorithmParameterException - { - - buf.reset(); - CipherParameters param; - param = McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key); - - digest.reset(); - cipher.init(false, param); - } - - public String getName() - { - return "McElieceKobaraImaiCipher"; - } - - public int getKeySize(Key key) - throws InvalidKeyException - { - McElieceCCA2KeyParameters mcElieceCCA2KeyParameters; - if (key instanceof PublicKey) - { - mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key); - return cipher.getKeySize(mcElieceCCA2KeyParameters); - } - else if (key instanceof PrivateKey) - { - mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key); - return cipher.getKeySize(mcElieceCCA2KeyParameters); - } - else - { - throw new InvalidKeyException(); - } - - - } - - /** - * Pad and return the message stored in the message buffer. - * - * @return the padded message - */ - private byte[] pad() - { - buf.write(0x01); - byte[] result = buf.toByteArray(); - buf.reset(); - return result; - } - - /** - * Unpad a message. - * - * @param pmBytes the padded message - * @return the message - * @throws BadPaddingException if the padded message is invalid. - */ - private byte[] unpad(byte[] pmBytes) - throws BadPaddingException - { - // find first non-zero byte - int index; - for (index = pmBytes.length - 1; index >= 0 && pmBytes[index] == 0; index--) - { - ; - } - - // check if padding byte is valid - if (pmBytes[index] != 0x01) - { - throw new BadPaddingException("invalid ciphertext"); - } - - // extract and return message - byte[] mBytes = new byte[index]; - System.arraycopy(pmBytes, 0, mBytes, 0, index); - return mBytes; - } - - static public class McElieceKobaraImai - extends McElieceKobaraImaiCipherSpi - { - public McElieceKobaraImai() - { - super(DigestFactory.createSHA1(), new McElieceKobaraImaiCipher()); - } - } - - static public class McElieceKobaraImai224 - extends McElieceKobaraImaiCipherSpi - { - public McElieceKobaraImai224() - { - super(DigestFactory.createSHA224(), new McElieceKobaraImaiCipher()); - } - } - - static public class McElieceKobaraImai256 - extends McElieceKobaraImaiCipherSpi - { - public McElieceKobaraImai256() - { - super(DigestFactory.createSHA256(), new McElieceKobaraImaiCipher()); - } - } - - static public class McElieceKobaraImai384 - extends McElieceKobaraImaiCipherSpi - { - public McElieceKobaraImai384() - { - super(DigestFactory.createSHA384(), new McElieceKobaraImaiCipher()); - } - } - - static public class McElieceKobaraImai512 - extends McElieceKobaraImaiCipherSpi - { - public McElieceKobaraImai512() - { - super(DigestFactory.createSHA512(), new McElieceKobaraImaiCipher()); - } - } - - -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java deleted file mode 100644 index 24b0473654..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePKCSCipherSpi.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.mceliece; - -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; - -import javax.crypto.BadPaddingException; -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.params.ParametersWithRandom; -import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricBlockCipher; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCipher; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceKeyParameters; - -public class McEliecePKCSCipherSpi - extends AsymmetricBlockCipher - implements PKCSObjectIdentifiers, X509ObjectIdentifiers -{ - private McElieceCipher cipher; - - public McEliecePKCSCipherSpi(McElieceCipher cipher) - { - this.cipher = cipher; - } - - protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params, - SecureRandom sr) - throws InvalidKeyException, - InvalidAlgorithmParameterException - { - - CipherParameters param; - param = McElieceKeysToParams.generatePublicKeyParameter((PublicKey)key); - - param = new ParametersWithRandom(param, sr); - cipher.init(true, param); - this.maxPlainTextSize = cipher.maxPlainTextSize; - this.cipherTextSize = cipher.cipherTextSize; - } - - protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params) - throws InvalidKeyException, InvalidAlgorithmParameterException - { - CipherParameters param; - param = McElieceKeysToParams.generatePrivateKeyParameter((PrivateKey)key); - - cipher.init(false, param); - this.maxPlainTextSize = cipher.maxPlainTextSize; - this.cipherTextSize = cipher.cipherTextSize; - } - - protected byte[] messageEncrypt(byte[] input) - throws IllegalBlockSizeException, BadPaddingException - { - byte[] output = null; - try - { - output = cipher.messageEncrypt(input); - } - catch (Exception e) - { - throw new IllegalBlockSizeException(e.getMessage()); - } - return output; - } - - protected byte[] messageDecrypt(byte[] input) - throws IllegalBlockSizeException, BadPaddingException - { - byte[] output = null; - try - { - output = cipher.messageDecrypt(input); - } - catch (Exception e) - { - throw new IllegalBlockSizeException(e.getMessage()); - } - return output; - } - - public String getName() - { - return "McEliecePKCS"; - } - - public int getKeySize(Key key) - throws InvalidKeyException - { - McElieceKeyParameters mcElieceKeyParameters; - if (key instanceof PublicKey) - { - mcElieceKeyParameters = (McElieceKeyParameters)McElieceKeysToParams.generatePublicKeyParameter((PublicKey)key); - } - else - { - mcElieceKeyParameters = (McElieceKeyParameters)McElieceKeysToParams.generatePrivateKeyParameter((PrivateKey)key); - - } - - - return cipher.getKeySize(mcElieceKeyParameters); - } - - static public class McEliecePKCS - extends McEliecePKCSCipherSpi - { - public McEliecePKCS() - { - super(new McElieceCipher()); - } - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java deleted file mode 100644 index 21e37870cc..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/McEliecePointchevalCipherSpi.java +++ /dev/null @@ -1,199 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.mceliece; - -import java.io.ByteArrayOutputStream; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; - -import javax.crypto.BadPaddingException; - -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.InvalidCipherTextException; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.crypto.util.DigestFactory; -import org.bouncycastle.pqc.jcajce.provider.util.AsymmetricHybridCipher; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McElieceCCA2KeyParameters; -import org.bouncycastle.pqc.legacy.crypto.mceliece.McEliecePointchevalCipher; - -public class McEliecePointchevalCipherSpi - extends AsymmetricHybridCipher - implements PKCSObjectIdentifiers, X509ObjectIdentifiers -{ - // TODO digest needed? - private Digest digest; - private McEliecePointchevalCipher cipher; - - /** - * buffer to store the input data - */ - private ByteArrayOutputStream buf = new ByteArrayOutputStream(); - - - protected McEliecePointchevalCipherSpi(Digest digest, McEliecePointchevalCipher cipher) - { - this.digest = digest; - this.cipher = cipher; - buf = new ByteArrayOutputStream(); - } - - /** - * Continue a multiple-part encryption or decryption operation. - * - * @param input byte array containing the next part of the input - * @param inOff index in the array where the input starts - * @param inLen length of the input - * @return the processed byte array. - */ - public byte[] update(byte[] input, int inOff, int inLen) - { - buf.write(input, inOff, inLen); - return new byte[0]; - } - - - /** - * Encrypts or decrypts data in a single-part operation, or finishes a - * multiple-part operation. The data is encrypted or decrypted, depending on - * how this cipher was initialized. - * - * @param input the input buffer - * @param inOff the offset in input where the input starts - * @param inLen the input length - * @return the new buffer with the result - * @throws BadPaddingException on deryption errors. - */ - public byte[] doFinal(byte[] input, int inOff, int inLen) - throws BadPaddingException - { - update(input, inOff, inLen); - byte[] data = buf.toByteArray(); - buf.reset(); - if (opMode == ENCRYPT_MODE) - { - return cipher.messageEncrypt(data); - } - else if (opMode == DECRYPT_MODE) - { - try - { - return cipher.messageDecrypt(data); - } - catch (InvalidCipherTextException e) - { - throw new BadPaddingException(e.getMessage()); - } - } - return null; - } - - protected int encryptOutputSize(int inLen) - { - return 0; - } - - protected int decryptOutputSize(int inLen) - { - return 0; - } - - protected void initCipherEncrypt(Key key, AlgorithmParameterSpec params, - SecureRandom sr) - throws InvalidKeyException, - InvalidAlgorithmParameterException - { - CipherParameters param; - param = McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key); - - param = new ParametersWithRandom(param, sr); - digest.reset(); - cipher.init(true, param); - } - - protected void initCipherDecrypt(Key key, AlgorithmParameterSpec params) - throws InvalidKeyException, InvalidAlgorithmParameterException - { - CipherParameters param; - param = McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key); - - digest.reset(); - cipher.init(false, param); - } - - public String getName() - { - return "McEliecePointchevalCipher"; - } - - - public int getKeySize(Key key) - throws InvalidKeyException - { - McElieceCCA2KeyParameters mcElieceCCA2KeyParameters; - if (key instanceof PublicKey) - { - mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePublicKeyParameter((PublicKey)key); - } - else - { - mcElieceCCA2KeyParameters = (McElieceCCA2KeyParameters)McElieceCCA2KeysToParams.generatePrivateKeyParameter((PrivateKey)key); - } - - return cipher.getKeySize(mcElieceCCA2KeyParameters); - } - - //////////////////////////////////////////////////////////////////////////////////77 - - static public class McEliecePointcheval - extends McEliecePointchevalCipherSpi - { - public McEliecePointcheval() - { - super(DigestFactory.createSHA1(), new McEliecePointchevalCipher()); - } - } - - static public class McEliecePointcheval224 - extends McEliecePointchevalCipherSpi - { - public McEliecePointcheval224() - { - super(DigestFactory.createSHA224(), new McEliecePointchevalCipher()); - } - } - - static public class McEliecePointcheval256 - extends McEliecePointchevalCipherSpi - { - public McEliecePointcheval256() - { - super(DigestFactory.createSHA256(), new McEliecePointchevalCipher()); - } - } - - static public class McEliecePointcheval384 - extends McEliecePointchevalCipherSpi - { - public McEliecePointcheval384() - { - super(DigestFactory.createSHA384(), new McEliecePointchevalCipher()); - } - } - - static public class McEliecePointcheval512 - extends McEliecePointchevalCipherSpi - { - public McEliecePointcheval512() - { - super(DigestFactory.createSHA512(), new McEliecePointchevalCipher()); - } - } - - -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java deleted file mode 100644 index e4481abff2..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.mceliece; - -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.asn1.x509.AlgorithmIdentifier; -import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.util.DigestFactory; -import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers; - -class Utils -{ - 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/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUCipherSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUCipherSpi.java index 8eb47b868c..842f84fa89 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUCipherSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUCipherSpi.java @@ -19,14 +19,13 @@ import javax.crypto.spec.SecretKeySpec; import javax.security.auth.DestroyFailedException; -import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.SecretWithEncapsulation; import org.bouncycastle.crypto.Wrapper; import org.bouncycastle.jcajce.spec.KEMParameterSpec; import org.bouncycastle.jcajce.spec.KTSParameterSpec; -import org.bouncycastle.pqc.crypto.ntru.NTRUKEMGenerator; import org.bouncycastle.pqc.crypto.ntru.NTRUKEMExtractor; +import org.bouncycastle.pqc.crypto.ntru.NTRUKEMGenerator; import org.bouncycastle.pqc.jcajce.provider.util.WrapUtil; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Exceptions; @@ -145,7 +144,7 @@ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec paramSpec, if (key instanceof BCNTRUPublicKey) { wrapKey = (BCNTRUPublicKey)key; - kemGen = new NTRUKEMGenerator(CryptoServicesRegistrar.getSecureRandom(random)); + kemGen = new NTRUKEMGenerator(random); } else { @@ -217,6 +216,7 @@ protected int engineDoFinal(byte[] bytes, int i, int i1, byte[] bytes1, int i2) throw new IllegalStateException("Not supported in a wrapping mode"); } + @SuppressWarnings("Finally") protected byte[] engineWrap( Key key) throws IllegalBlockSizeException, InvalidKeyException diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKeyPairGeneratorSpi.java index c7ef183c18..c9d250583d 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKeyPairGeneratorSpi.java @@ -9,12 +9,12 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.ntru.NTRUKeyGenerationParameters; import org.bouncycastle.pqc.crypto.ntru.NTRUKeyPairGenerator; import org.bouncycastle.pqc.crypto.ntru.NTRUParameters; import org.bouncycastle.pqc.crypto.ntru.NTRUPrivateKeyParameters; import org.bouncycastle.pqc.crypto.ntru.NTRUPublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.pqc.jcajce.spec.NTRUParameterSpec; import org.bouncycastle.util.Strings; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/BCNTRUPlusPrivateKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/BCNTRUPlusPrivateKey.java new file mode 100644 index 0000000000..4f083325e3 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/BCNTRUPlusPrivateKey.java @@ -0,0 +1,130 @@ +package org.bouncycastle.pqc.jcajce.provider.ntruplus; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.PrivateKey; + +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; +import org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory; +import org.bouncycastle.pqc.jcajce.interfaces.NTRUPlusKey; +import org.bouncycastle.pqc.jcajce.spec.NTRUPlusParameterSpec; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +public class BCNTRUPlusPrivateKey + implements PrivateKey, NTRUPlusKey +{ + private static final long serialVersionUID = 1L; + + private transient NTRUPlusPrivateKeyParameters params; + private transient ASN1Set attributes; + + public BCNTRUPlusPrivateKey( + NTRUPlusPrivateKeyParameters params) + { + this.params = params; + } + + public BCNTRUPlusPrivateKey(PrivateKeyInfo keyInfo) + throws IOException + { + init(keyInfo); + } + + private void init(PrivateKeyInfo keyInfo) + throws IOException + { + this.attributes = keyInfo.getAttributes(); + this.params = (NTRUPlusPrivateKeyParameters) PrivateKeyFactory.createKey(keyInfo); + } + + /** + * Compare this private key with another object. + * + * @param o the other object + * @return the result of the comparison + */ + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (o instanceof BCNTRUPlusPrivateKey) + { + BCNTRUPlusPrivateKey otherKey = (BCNTRUPlusPrivateKey)o; + + return Arrays.areEqual(params.getEncoded(), otherKey.params.getEncoded()); + } + + return false; + } + + public int hashCode() + { + return Arrays.hashCode(params.getEncoded()); + } + + /** + * @return name of the algorithm - "NTRUPlus" + */ + public final String getAlgorithm() + { + return Strings.toUpperCase(params.getParameters().getName()); + } + + public byte[] getEncoded() + { + + try + { + PrivateKeyInfo pki = PrivateKeyInfoFactory.createPrivateKeyInfo(params, attributes); + + return pki.getEncoded(); + } + catch (IOException e) + { + return null; + } + } + + public NTRUPlusParameterSpec getParameterSpec() + { + return NTRUPlusParameterSpec.fromName(params.getParameters().getName()); + } + + public String getFormat() + { + return "PKCS#8"; + } + + NTRUPlusPrivateKeyParameters getKeyParams() + { + return params; + } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(PrivateKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } +} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/BCNTRUPlusPublicKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/BCNTRUPlusPublicKey.java new file mode 100644 index 0000000000..c5a5e3d295 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/BCNTRUPlusPublicKey.java @@ -0,0 +1,126 @@ +package org.bouncycastle.pqc.jcajce.provider.ntruplus; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.PublicKey; + +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusPublicKeyParameters; +import org.bouncycastle.pqc.crypto.util.PublicKeyFactory; +import org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory; +import org.bouncycastle.pqc.jcajce.interfaces.NTRUPlusKey; +import org.bouncycastle.pqc.jcajce.spec.NTRUPlusParameterSpec; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +public class BCNTRUPlusPublicKey + implements PublicKey, NTRUPlusKey +{ + private static final long serialVersionUID = 1L; + + private transient NTRUPlusPublicKeyParameters params; + + public BCNTRUPlusPublicKey( + NTRUPlusPublicKeyParameters params) + { + this.params = params; + } + + public BCNTRUPlusPublicKey(SubjectPublicKeyInfo keyInfo) + throws IOException + { + init(keyInfo); + } + + private void init(SubjectPublicKeyInfo keyInfo) + throws IOException + { + this.params = (NTRUPlusPublicKeyParameters) PublicKeyFactory.createKey(keyInfo); + } + + /** + * Compare this NTRUPlus public key with another object. + * + * @param o the other object + * @return the result of the comparison + */ + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (o instanceof BCNTRUPlusPublicKey) + { + BCNTRUPlusPublicKey otherKey = (BCNTRUPlusPublicKey)o; + + return Arrays.areEqual(params.getEncoded(), otherKey.params.getEncoded()); + } + + return false; + } + + public int hashCode() + { + return Arrays.hashCode(params.getEncoded()); + } + + /** + * @return name of the algorithm - "NTRUPlus" + */ + public final String getAlgorithm() + { + return Strings.toUpperCase(params.getParameters().getName()); + } + + public byte[] getEncoded() + { + try + { + SubjectPublicKeyInfo pki = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(params); + + return pki.getEncoded(); + } + catch (IOException e) + { + return null; + } + } + + public String getFormat() + { + return "X.509"; + } + + public NTRUPlusParameterSpec getParameterSpec() + { + return NTRUPlusParameterSpec.fromName(params.getParameters().getName()); + } + + NTRUPlusPublicKeyParameters getKeyParams() + { + return params; + } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(SubjectPublicKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } +} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/NTRUPlusCipherSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/NTRUPlusCipherSpi.java new file mode 100644 index 0000000000..7efc31e7c5 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/NTRUPlusCipherSpi.java @@ -0,0 +1,359 @@ +package org.bouncycastle.pqc.jcajce.provider.ntruplus; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.CipherSpi; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.SecretKeySpec; +import javax.security.auth.DestroyFailedException; + +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.SecretWithEncapsulation; +import org.bouncycastle.crypto.Wrapper; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.jcajce.spec.KEMParameterSpec; +import org.bouncycastle.jcajce.spec.KTSParameterSpec; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusKEMExtractor; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusKEMGenerator; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusParameters; +import org.bouncycastle.pqc.jcajce.provider.util.WrapUtil; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Exceptions; +import org.bouncycastle.util.Strings; + +class NTRUPlusCipherSpi + extends CipherSpi +{ + private final String algorithmName; + private NTRUPlusKEMGenerator kemGen; + private KTSParameterSpec kemParameterSpec; + private BCNTRUPlusPublicKey wrapKey; + private BCNTRUPlusPrivateKey unwrapKey; + private AlgorithmParameters engineParams; + private NTRUPlusParameters ntruplusParameters; + + NTRUPlusCipherSpi(String algorithmName) + throws NoSuchAlgorithmException + { + this.algorithmName = algorithmName; + } + + NTRUPlusCipherSpi(NTRUPlusParameters ntruplusParameters) + { + this.ntruplusParameters = ntruplusParameters; + this.algorithmName = Strings.toUpperCase(ntruplusParameters.getName()); + } + + @Override + protected void engineSetMode(String mode) + throws NoSuchAlgorithmException + { + throw new NoSuchAlgorithmException("Cannot support mode " + mode); + } + + @Override + protected void engineSetPadding(String padding) + throws NoSuchPaddingException + { + throw new NoSuchPaddingException("Padding " + padding + " unknown"); + } + + protected int engineGetKeySize( + Key key) + { + return 2048; // TODO + //throw new IllegalArgumentException("not an valid key!"); + } + + @Override + protected int engineGetBlockSize() + { + return 0; + } + + @Override + protected int engineGetOutputSize(int i) + { + return -1; // can't use with update/doFinal + } + + @Override + protected byte[] engineGetIV() + { + return null; + } + + @Override + protected AlgorithmParameters engineGetParameters() + { + if (engineParams == null) + { + try + { + engineParams = AlgorithmParameters.getInstance(algorithmName, "BCPQC"); + + engineParams.init(kemParameterSpec); + } + catch (Exception e) + { + throw Exceptions.illegalStateException(e.toString(), e); + } + } + + return engineParams; + } + + @Override + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + try + { + engineInit(opmode, key, (AlgorithmParameterSpec)null, random); + } + catch (InvalidAlgorithmParameterException e) + { + throw Exceptions.illegalArgumentException(e.getMessage(), e); + } + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec paramSpec, SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + if (paramSpec == null) + { + // TODO: default should probably use shake. + kemParameterSpec = new KEMParameterSpec("AES-KWP"); + } + else + { + if (!(paramSpec instanceof KTSParameterSpec)) + { + throw new InvalidAlgorithmParameterException(algorithmName + " can only accept KTSParameterSpec"); + } + + kemParameterSpec = (KTSParameterSpec)paramSpec; + } + + if (opmode == Cipher.WRAP_MODE) + { + if (key instanceof BCNTRUPlusPublicKey) + { + wrapKey = (BCNTRUPlusPublicKey)key; + kemGen = new NTRUPlusKEMGenerator(CryptoServicesRegistrar.getSecureRandom(random)); + } + else + { + throw new InvalidKeyException("Only a " + algorithmName + " public key can be used for wrapping"); + } + } + else if (opmode == Cipher.UNWRAP_MODE) + { + if (key instanceof BCNTRUPlusPrivateKey) + { + unwrapKey = (BCNTRUPlusPrivateKey)key; + } + else + { + throw new InvalidKeyException("Only a " + algorithmName + " private key can be used for unwrapping"); + } + } + else + { + throw new InvalidParameterException("Cipher only valid for wrapping/unwrapping"); + } + + if (ntruplusParameters != null) + { + String canonicalAlgName = Strings.toUpperCase(ntruplusParameters.getName()); + if (!canonicalAlgName.equals(key.getAlgorithm())) + { + throw new InvalidKeyException("cipher locked to " + canonicalAlgName); + } + } + } + + @Override + protected void engineInit(int opmode, Key key, AlgorithmParameters algorithmParameters, SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + AlgorithmParameterSpec paramSpec = null; + + if (algorithmParameters != null) + { + try + { + paramSpec = algorithmParameters.getParameterSpec(KEMParameterSpec.class); + } + catch (Exception e) + { + throw new InvalidAlgorithmParameterException("can't handle parameter " + algorithmParameters.toString()); + } + } + + engineInit(opmode, key, paramSpec, random); + } + + @Override + protected byte[] engineUpdate(byte[] bytes, int i, int i1) + { + throw new IllegalStateException("Not supported in a wrapping mode"); + } + + @Override + protected int engineUpdate(byte[] bytes, int i, int i1, byte[] bytes1, int i2) + throws ShortBufferException + { + throw new IllegalStateException("Not supported in a wrapping mode"); + } + + @Override + protected byte[] engineDoFinal(byte[] bytes, int i, int i1) + throws IllegalBlockSizeException, BadPaddingException + { + throw new IllegalStateException("Not supported in a wrapping mode"); + } + + @Override + protected int engineDoFinal(byte[] bytes, int i, int i1, byte[] bytes1, int i2) + throws ShortBufferException, IllegalBlockSizeException, BadPaddingException + { + throw new IllegalStateException("Not supported in a wrapping mode"); + } + + protected byte[] engineWrap( + Key key) + throws IllegalBlockSizeException, InvalidKeyException + { + byte[] encoded = key.getEncoded(); + if (encoded == null) + { + throw new InvalidKeyException("Cannot wrap key, null encoding."); + } + + try + { + SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(wrapKey.getKeyParams()); + + Wrapper kWrap = WrapUtil.getWrapper(kemParameterSpec.getKeyAlgorithmName()); + + KeyParameter keyParameter = new KeyParameter(WrapUtil.trimSecret(kemParameterSpec.getKeyAlgorithmName(), secEnc.getSecret())); + + kWrap.init(true, keyParameter); + + byte[] encapsulation = secEnc.getEncapsulation(); + + secEnc.destroy(); + + byte[] keyToWrap = key.getEncoded(); + + byte[] rv = Arrays.concatenate(encapsulation, kWrap.wrap(keyToWrap, 0, keyToWrap.length)); + + Arrays.clear(keyToWrap); + + return rv; + } + catch (IllegalArgumentException e) + { + throw new IllegalBlockSizeException("unable to generate KTS secret: " + e.getMessage()); + } + catch (DestroyFailedException e) + { + throw new IllegalBlockSizeException("unable to destroy interim values: " + e.getMessage()); + } + } + + protected Key engineUnwrap( + byte[] wrappedKey, + String wrappedKeyAlgorithm, + int wrappedKeyType) + throws InvalidKeyException, NoSuchAlgorithmException + { + // TODO: add support for other types. + if (wrappedKeyType != Cipher.SECRET_KEY) + { + throw new InvalidKeyException("only SECRET_KEY supported"); + } + try + { + NTRUPlusKEMExtractor kemExt = new NTRUPlusKEMExtractor(unwrapKey.getKeyParams()); + + byte[] secret = kemExt.extractSecret(Arrays.copyOfRange(wrappedKey, 0, kemExt.getEncapsulationLength())); + + Wrapper kWrap = WrapUtil.getWrapper(kemParameterSpec.getKeyAlgorithmName()); + + KeyParameter keyParameter = new KeyParameter(WrapUtil.trimSecret(kemParameterSpec.getKeyAlgorithmName(), secret)); + + Arrays.clear(secret); + + kWrap.init(false, keyParameter); + + byte[] keyEncBytes = Arrays.copyOfRange(wrappedKey, kemExt.getEncapsulationLength(), wrappedKey.length); + + SecretKey rv = new SecretKeySpec(kWrap.unwrap(keyEncBytes, 0, keyEncBytes.length), wrappedKeyAlgorithm); + + Arrays.clear(keyParameter.getKey()); + + return rv; + } + catch (IllegalArgumentException e) + { + throw new NoSuchAlgorithmException("unable to extract KTS secret: " + e.getMessage()); + } + catch (InvalidCipherTextException e) + { + throw new InvalidKeyException("unable to extract KTS secret: " + e.getMessage()); + } + } + + public static class Base + extends NTRUPlusCipherSpi + { + public Base() + throws NoSuchAlgorithmException + { + super("NTRU+"); + } + } + + public static class NTRUPlus768 + extends NTRUPlusCipherSpi + { + public NTRUPlus768() + { + super(NTRUPlusParameters.ntruplus_kem_864); + } + } + + public static class NTRUPlus864 + extends NTRUPlusCipherSpi + { + public NTRUPlus864() + { + super(NTRUPlusParameters.ntruplus_kem_864); + } + } + + public static class NTRUPlus1152 + extends NTRUPlusCipherSpi + { + public NTRUPlus1152() + { + super(NTRUPlusParameters.ntruplus_kem_1152); + } + } +} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/RainbowKeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/NTRUPlusKeyFactorySpi.java similarity index 57% rename from prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/RainbowKeyFactorySpi.java rename to prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/NTRUPlusKeyFactorySpi.java index 5c3c142a19..4532f5c9e7 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/RainbowKeyFactorySpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/NTRUPlusKeyFactorySpi.java @@ -1,27 +1,48 @@ -package org.bouncycastle.pqc.jcajce.provider.rainbow; +package org.bouncycastle.pqc.jcajce.provider.ntruplus; 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 java.util.HashSet; +import java.util.Set; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.bc.BCObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; +import org.bouncycastle.pqc.jcajce.provider.util.BaseKeyFactorySpi; -public class RainbowKeyFactorySpi - extends KeyFactorySpi - implements AsymmetricKeyInfoConverter +public class NTRUPlusKeyFactorySpi + extends BaseKeyFactorySpi { + private static final Set keyOids = new HashSet(); + + static + { + keyOids.add(BCObjectIdentifiers.ntruPlus768); + keyOids.add(BCObjectIdentifiers.ntruPlus864); + keyOids.add(BCObjectIdentifiers.ntruPlus1152); + } + + public NTRUPlusKeyFactorySpi() + { + super(keyOids); + } + + public NTRUPlusKeyFactorySpi(ASN1ObjectIdentifier keyOids) + { + super(keyOids); + } + public PrivateKey engineGeneratePrivate(KeySpec keySpec) - throws InvalidKeySpecException + throws InvalidKeySpecException { if (keySpec instanceof PKCS8EncodedKeySpec) { @@ -39,11 +60,11 @@ public PrivateKey engineGeneratePrivate(KeySpec keySpec) } throw new InvalidKeySpecException("Unsupported key specification: " - + keySpec.getClass() + "."); + + keySpec.getClass() + "."); } public PublicKey engineGeneratePublic(KeySpec keySpec) - throws InvalidKeySpecException + throws InvalidKeySpecException { if (keySpec instanceof X509EncodedKeySpec) { @@ -57,7 +78,7 @@ public PublicKey engineGeneratePublic(KeySpec keySpec) } catch (Exception e) { - throw new InvalidKeySpecException(e.toString(), e); + throw new InvalidKeySpecException(e.toString()); } } @@ -65,16 +86,16 @@ public PublicKey engineGeneratePublic(KeySpec keySpec) } public final KeySpec engineGetKeySpec(Key key, Class keySpec) - throws InvalidKeySpecException + throws InvalidKeySpecException { - if (key instanceof BCRainbowPrivateKey) + if (key instanceof BCNTRUPlusPrivateKey) { if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) { return new PKCS8EncodedKeySpec(key.getEncoded()); } } - else if (key instanceof BCRainbowPublicKey) + else if (key instanceof BCNTRUPlusPublicKey) { if (X509EncodedKeySpec.class.isAssignableFrom(keySpec)) { @@ -84,17 +105,17 @@ else if (key instanceof BCRainbowPublicKey) else { throw new InvalidKeySpecException("Unsupported key type: " - + key.getClass() + "."); + + key.getClass() + "."); } throw new InvalidKeySpecException("Unknown key specification: " - + keySpec + "."); + + keySpec + "."); } public final Key engineTranslateKey(Key key) - throws InvalidKeyException + throws InvalidKeyException { - if (key instanceof BCRainbowPrivateKey || key instanceof BCRainbowPublicKey) + if (key instanceof BCNTRUPlusPrivateKey || key instanceof BCNTRUPlusPublicKey) { return key; } @@ -103,14 +124,41 @@ public final Key engineTranslateKey(Key key) } public PrivateKey generatePrivate(PrivateKeyInfo keyInfo) - throws IOException + throws IOException { - return new BCRainbowPrivateKey(keyInfo); + return new BCNTRUPlusPrivateKey(keyInfo); } public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo) - throws IOException + throws IOException + { + return new BCNTRUPlusPublicKey(keyInfo); + } + + public static class NTRUPlus768 + extends NTRUPlusKeyFactorySpi { - return new BCRainbowPublicKey(keyInfo); + public NTRUPlus768() + { + super(BCObjectIdentifiers.ntruPlus768); + } + } + + public static class NTRUPlus864 + extends NTRUPlusKeyFactorySpi + { + public NTRUPlus864() + { + super(BCObjectIdentifiers.ntruPlus864); + } + } + + public static class NTRUPlus1152 + extends NTRUPlusKeyFactorySpi + { + public NTRUPlus1152() + { + super(BCObjectIdentifiers.ntruPlus1152); + } } } diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/NTRUPlusKeyGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/NTRUPlusKeyGeneratorSpi.java new file mode 100644 index 0000000000..6a87689f71 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/NTRUPlusKeyGeneratorSpi.java @@ -0,0 +1,150 @@ +package org.bouncycastle.pqc.jcajce.provider.ntruplus; + +import java.security.InvalidAlgorithmParameterException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.KeyGeneratorSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import javax.security.auth.DestroyFailedException; + +import org.bouncycastle.crypto.SecretWithEncapsulation; +import org.bouncycastle.jcajce.SecretKeyWithEncapsulation; +import org.bouncycastle.jcajce.spec.KEMExtractSpec; +import org.bouncycastle.jcajce.spec.KEMGenerateSpec; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusKEMExtractor; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusKEMGenerator; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusParameters; +import org.bouncycastle.pqc.jcajce.spec.NTRUPlusParameterSpec; +import org.bouncycastle.util.Arrays; + +public class NTRUPlusKeyGeneratorSpi + extends KeyGeneratorSpi +{ + private KEMGenerateSpec genSpec; + private SecureRandom random; + private KEMExtractSpec extSpec; + private NTRUPlusParameters ntruplusParameters; + + public NTRUPlusKeyGeneratorSpi() + { + this(null); + } + + public NTRUPlusKeyGeneratorSpi(NTRUPlusParameters ntruplusParameters) + { + this.ntruplusParameters = ntruplusParameters; + } + + protected void engineInit(SecureRandom secureRandom) + { + throw new UnsupportedOperationException("Operation not supported"); + } + + protected void engineInit(AlgorithmParameterSpec algorithmParameterSpec, SecureRandom secureRandom) + throws InvalidAlgorithmParameterException + { + this.random = secureRandom; + if (algorithmParameterSpec instanceof KEMGenerateSpec) + { + this.genSpec = (KEMGenerateSpec)algorithmParameterSpec; + this.extSpec = null; + if (ntruplusParameters != null) + { + String canonicalAlgName = NTRUPlusParameterSpec.fromName(ntruplusParameters.getName()).getName(); + if (!canonicalAlgName.equals(genSpec.getPublicKey().getAlgorithm())) + { + throw new InvalidAlgorithmParameterException("key generator locked to " + canonicalAlgName); + } + } + } + else if (algorithmParameterSpec instanceof KEMExtractSpec) + { + this.genSpec = null; + this.extSpec = (KEMExtractSpec)algorithmParameterSpec; + if (ntruplusParameters != null) + { + String canonicalAlgName = NTRUPlusParameterSpec.fromName(ntruplusParameters.getName()).getName(); + if (!canonicalAlgName.equals(extSpec.getPrivateKey().getAlgorithm())) + { + throw new InvalidAlgorithmParameterException("key generator locked to " + canonicalAlgName); + } + } + } + else + { + throw new InvalidAlgorithmParameterException("unknown spec"); + } + } + + protected void engineInit(int i, SecureRandom secureRandom) + { + throw new UnsupportedOperationException("Operation not supported"); + } + + protected SecretKey engineGenerateKey() + { + if (genSpec != null) + { + BCNTRUPlusPublicKey pubKey = (BCNTRUPlusPublicKey)genSpec.getPublicKey(); + NTRUPlusKEMGenerator kemGen = new NTRUPlusKEMGenerator(random); + + SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(pubKey.getKeyParams()); + + SecretKey rv = new SecretKeyWithEncapsulation(new SecretKeySpec(secEnc.getSecret(), genSpec.getKeyAlgorithmName()), secEnc.getEncapsulation()); + + try + { + secEnc.destroy(); + } + catch (DestroyFailedException e) + { + throw new IllegalStateException("key cleanup failed"); + } + + return rv; + } + else + { + BCNTRUPlusPrivateKey privKey = (BCNTRUPlusPrivateKey)extSpec.getPrivateKey(); + NTRUPlusKEMExtractor kemExt = new NTRUPlusKEMExtractor(privKey.getKeyParams()); + + byte[] encapsulation = extSpec.getEncapsulation(); + byte[] secret = kemExt.extractSecret(encapsulation); + + SecretKey rv = new SecretKeyWithEncapsulation(new SecretKeySpec(secret, extSpec.getKeyAlgorithmName()), encapsulation); + + Arrays.clear(secret); + + return rv; + } + } + + public static class NTRUPlus768 + extends NTRUPlusKeyGeneratorSpi + { + public NTRUPlus768() + { + super(NTRUPlusParameters.ntruplus_kem_768); + } + } + + public static class NTRUPlus864 + extends NTRUPlusKeyGeneratorSpi + { + public NTRUPlus864() + { + super(NTRUPlusParameters.ntruplus_kem_864); + } + } + + public static class NTRUPlus1152 + extends NTRUPlusKeyGeneratorSpi + { + public NTRUPlus1152() + { + super(NTRUPlusParameters.ntruplus_kem_1152); + } + } +} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/NTRUPlusKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/NTRUPlusKeyPairGeneratorSpi.java new file mode 100644 index 0000000000..55f5262863 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruplus/NTRUPlusKeyPairGeneratorSpi.java @@ -0,0 +1,150 @@ +package org.bouncycastle.pqc.jcajce.provider.ntruplus; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusKeyGenerationParameters; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusKeyPairGenerator; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusParameters; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusPublicKeyParameters; +import org.bouncycastle.pqc.jcajce.spec.NTRUPlusParameterSpec; +import org.bouncycastle.util.Strings; + +public class NTRUPlusKeyPairGeneratorSpi + extends java.security.KeyPairGenerator +{ + private static Map parameters = new HashMap(); + + static + { + parameters.put(NTRUPlusParameterSpec.ntruplus_768.getName(), NTRUPlusParameters.ntruplus_kem_768); + parameters.put(NTRUPlusParameterSpec.ntruplus_864.getName(), NTRUPlusParameters.ntruplus_kem_864); + parameters.put(NTRUPlusParameterSpec.ntruplus_1152.getName(), NTRUPlusParameters.ntruplus_kem_1152); + } + + private final NTRUPlusParameters ntruplusParameters; + + NTRUPlusKeyGenerationParameters param; + NTRUPlusKeyPairGenerator engine = new NTRUPlusKeyPairGenerator(); + + SecureRandom random = CryptoServicesRegistrar.getSecureRandom(); + boolean initialised = false; + + public NTRUPlusKeyPairGeneratorSpi() + { + super("NTRUPLUS"); + this.ntruplusParameters = null; + } + + protected NTRUPlusKeyPairGeneratorSpi(NTRUPlusParameters ntruplusParameters) + { + super(ntruplusParameters.getName()); + this.ntruplusParameters = ntruplusParameters; + } + + public void initialize( + int strength, + SecureRandom random) + { + throw new IllegalArgumentException("use AlgorithmParameterSpec"); + } + + public void initialize( + AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidAlgorithmParameterException + { + String name = getNameFromParams(params); + + if (name != null && parameters.containsKey(name)) + { + NTRUPlusParameters ntruplusParams = (NTRUPlusParameters)parameters.get(name); + + param = new NTRUPlusKeyGenerationParameters(random, ntruplusParams); + + if (ntruplusParameters != null && !ntruplusParams.getName().equals(ntruplusParameters.getName())) + { + throw new InvalidAlgorithmParameterException("key pair generator locked to " + Strings.toUpperCase(ntruplusParameters.getName())); + } + + engine.init(param); + initialised = true; + } + else + { + throw new InvalidAlgorithmParameterException("invalid ParameterSpec: " + params); + } + } + + private static String getNameFromParams(AlgorithmParameterSpec paramSpec) + { + if (paramSpec instanceof NTRUPlusParameterSpec) + { + NTRUPlusParameterSpec ntruplusParams = (NTRUPlusParameterSpec)paramSpec; + return ntruplusParams.getName(); + } + else + { + return Strings.toLowerCase(SpecUtil.getNameFrom(paramSpec)); + } + } + + public KeyPair generateKeyPair() + { + if (!initialised) + { + if (ntruplusParameters != null) + { + param = new NTRUPlusKeyGenerationParameters(random, ntruplusParameters); + } + else + { + param = new NTRUPlusKeyGenerationParameters(random, NTRUPlusParameters.ntruplus_kem_768); + } + + engine.init(param); + initialised = true; + } + + AsymmetricCipherKeyPair pair = engine.generateKeyPair(); + NTRUPlusPublicKeyParameters pub = (NTRUPlusPublicKeyParameters)pair.getPublic(); + NTRUPlusPrivateKeyParameters priv = (NTRUPlusPrivateKeyParameters)pair.getPrivate(); + + return new KeyPair(new BCNTRUPlusPublicKey(pub), new BCNTRUPlusPrivateKey(priv)); + } + + public static class NTRUPlus768 + extends NTRUPlusKeyPairGeneratorSpi + { + public NTRUPlus768() + { + super(NTRUPlusParameters.ntruplus_kem_768); + } + } + + public static class NTRUPlus864 + extends NTRUPlusKeyPairGeneratorSpi + { + public NTRUPlus864() + { + super(NTRUPlusParameters.ntruplus_kem_864); + } + } + + public static class NTRUPlus1152 + extends NTRUPlusKeyPairGeneratorSpi + { + public NTRUPlus1152() + { + super(NTRUPlusParameters.ntruplus_kem_864); + } + } +} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruprime/NTRULPRimeKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruprime/NTRULPRimeKeyPairGeneratorSpi.java index 9eb7186c23..851270be7c 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruprime/NTRULPRimeKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruprime/NTRULPRimeKeyPairGeneratorSpi.java @@ -9,12 +9,12 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.ntruprime.NTRULPRimeKeyGenerationParameters; import org.bouncycastle.pqc.crypto.ntruprime.NTRULPRimeKeyPairGenerator; import org.bouncycastle.pqc.crypto.ntruprime.NTRULPRimeParameters; import org.bouncycastle.pqc.crypto.ntruprime.NTRULPRimePrivateKeyParameters; import org.bouncycastle.pqc.crypto.ntruprime.NTRULPRimePublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.pqc.jcajce.spec.NTRULPRimeParameterSpec; import org.bouncycastle.util.Strings; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeCipherSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeCipherSpi.java index af92dfd3a6..9c1da960a7 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeCipherSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeCipherSpi.java @@ -19,7 +19,6 @@ import javax.crypto.spec.SecretKeySpec; import javax.security.auth.DestroyFailedException; -import org.bouncycastle.crypto.CryptoServicesRegistrar; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.SecretWithEncapsulation; import org.bouncycastle.crypto.Wrapper; @@ -144,7 +143,7 @@ protected void engineInit(int opmode, Key key, AlgorithmParameterSpec paramSpec, if (key instanceof BCSNTRUPrimePublicKey) { wrapKey = (BCSNTRUPrimePublicKey)key; - kemGen = new SNTRUPrimeKEMGenerator(CryptoServicesRegistrar.getSecureRandom(random)); + kemGen = new SNTRUPrimeKEMGenerator(random); } else { diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKeyPairGeneratorSpi.java index 0d772632f2..c43175f4bb 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKeyPairGeneratorSpi.java @@ -9,12 +9,12 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKeyGenerationParameters; import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKeyPairGenerator; import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeParameters; import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimePrivateKeyParameters; import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimePublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.pqc.jcajce.spec.SNTRUPrimeParameterSpec; import org.bouncycastle.util.Strings; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/picnic/PicnicKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/picnic/PicnicKeyPairGeneratorSpi.java index 67308e1526..79fc4436a6 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/picnic/PicnicKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/picnic/PicnicKeyPairGeneratorSpi.java @@ -9,12 +9,12 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.picnic.PicnicKeyGenerationParameters; import org.bouncycastle.pqc.crypto.picnic.PicnicKeyPairGenerator; import org.bouncycastle.pqc.crypto.picnic.PicnicParameters; import org.bouncycastle.pqc.crypto.picnic.PicnicPrivateKeyParameters; import org.bouncycastle.pqc.crypto.picnic.PicnicPublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.pqc.jcajce.spec.PicnicParameterSpec; import org.bouncycastle.util.Strings; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/BCRainbowPrivateKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/BCRainbowPrivateKey.java deleted file mode 100644 index e1e1e53f8b..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/BCRainbowPrivateKey.java +++ /dev/null @@ -1,140 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.rainbow; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.pqc.crypto.rainbow.RainbowPrivateKeyParameters; -import org.bouncycastle.pqc.crypto.rainbow.RainbowPublicKeyParameters; -import org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; -import org.bouncycastle.pqc.jcajce.interfaces.RainbowPrivateKey; -import org.bouncycastle.pqc.jcajce.interfaces.RainbowPublicKey; -import org.bouncycastle.pqc.jcajce.provider.util.KeyUtil; -import org.bouncycastle.pqc.jcajce.spec.RainbowParameterSpec; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Strings; -import org.bouncycastle.util.encoders.Hex; - -public class BCRainbowPrivateKey - implements RainbowPrivateKey -{ - private static final long serialVersionUID = 1L; - - private transient RainbowPrivateKeyParameters params; - private transient String algorithm; - private transient byte[] encoding; - private transient ASN1Set attributes; - - public BCRainbowPrivateKey( - RainbowPrivateKeyParameters params) - { - init(params, null); - } - - public BCRainbowPrivateKey(PrivateKeyInfo keyInfo) - throws IOException - { - init(keyInfo); - } - - private void init(PrivateKeyInfo keyInfo) - throws IOException - { - init((RainbowPrivateKeyParameters) PrivateKeyFactory.createKey(keyInfo), keyInfo.getAttributes()); - } - - private void init(RainbowPrivateKeyParameters params, ASN1Set attributes) - { - this.attributes = attributes; - this.params = params; - this.algorithm = Strings.toUpperCase(params.getParameters().getName()); - } - - /** - * Compare this Rainbow private key with another object. - * - * @param o the other object - * @return the result of the comparison - */ - public boolean equals(Object o) - { - if (o == this) - { - return true; - } - - if (o instanceof BCRainbowPrivateKey) - { - BCRainbowPrivateKey otherKey = (BCRainbowPrivateKey)o; - - return Arrays.areEqual(getEncoded(), otherKey.getEncoded()); - } - - return false; - } - - public int hashCode() - { - return Arrays.hashCode(getEncoded()); - } - - /** - * @return name of the algorithm - */ - public final String getAlgorithm() - { - return algorithm; - } - - public byte[] getEncoded() - { - if (encoding == null) - { - encoding = KeyUtil.getEncodedPrivateKeyInfo(params, attributes); - } - - return Arrays.clone(encoding); - } - - public RainbowParameterSpec getParameterSpec() - { - return RainbowParameterSpec.fromName(params.getParameters().getName()); - } - - public String getFormat() - { - return "PKCS#8"; - } - - public RainbowPublicKey getPublicKey() - { - return new BCRainbowPublicKey(new RainbowPublicKeyParameters(params.getParameters(), params.getPublicKey())); - } - - RainbowPrivateKeyParameters getKeyParams() - { - return params; - } - - private void readObject( - ObjectInputStream in) - throws IOException, ClassNotFoundException - { - in.defaultReadObject(); - - byte[] enc = (byte[])in.readObject(); - - init(PrivateKeyInfo.getInstance(enc)); - } - - private void writeObject( - ObjectOutputStream out) - throws IOException - { - out.defaultWriteObject(); - - out.writeObject(this.getEncoded()); - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/BCRainbowPublicKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/BCRainbowPublicKey.java deleted file mode 100644 index a8f0c63bfe..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/BCRainbowPublicKey.java +++ /dev/null @@ -1,130 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.rainbow; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.pqc.crypto.rainbow.RainbowPublicKeyParameters; -import org.bouncycastle.pqc.crypto.util.PublicKeyFactory; -import org.bouncycastle.pqc.jcajce.interfaces.RainbowPublicKey; -import org.bouncycastle.pqc.jcajce.provider.util.KeyUtil; -import org.bouncycastle.pqc.jcajce.spec.RainbowParameterSpec; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Strings; -import org.bouncycastle.util.encoders.Hex; - -public class BCRainbowPublicKey - implements RainbowPublicKey -{ - private static final long serialVersionUID = 1L; - - private transient RainbowPublicKeyParameters params; - private transient String algorithm; - private transient byte[] encoding; - - public BCRainbowPublicKey( - RainbowPublicKeyParameters params) - { - init(params); - } - - public BCRainbowPublicKey(SubjectPublicKeyInfo keyInfo) - throws IOException - { - init(keyInfo); - } - - private void init(SubjectPublicKeyInfo keyInfo) - throws IOException - { - init((RainbowPublicKeyParameters) PublicKeyFactory.createKey(keyInfo)); - } - - private void init(RainbowPublicKeyParameters params) - { - this.params = params; - this.algorithm = Strings.toUpperCase(params.getParameters().getName()); - } - - /** - * Compare this Rainbow public key with another object. - * - * @param o the other object - * @return the result of the comparison - */ - public boolean equals(Object o) - { - if (o == this) - { - return true; - } - - if (o instanceof BCRainbowPublicKey) - { - BCRainbowPublicKey otherKey = (BCRainbowPublicKey)o; - - return Arrays.areEqual(getEncoded(), otherKey.getEncoded()); - } - - return false; - } - - public int hashCode() - { - return Arrays.hashCode(getEncoded()); - } - - /** - * @return name of the algorithm - */ - public final String getAlgorithm() - { - return algorithm; - } - - public byte[] getEncoded() - { - if (encoding == null) - { - encoding = KeyUtil.getEncodedSubjectPublicKeyInfo(params); - } - - return Arrays.clone(encoding); - } - - public String getFormat() - { - return "X.509"; - } - - public RainbowParameterSpec getParameterSpec() - { - return RainbowParameterSpec.fromName(params.getParameters().getName()); - } - - RainbowPublicKeyParameters getKeyParams() - { - return params; - } - - private void readObject( - ObjectInputStream in) - throws IOException, ClassNotFoundException - { - in.defaultReadObject(); - - byte[] enc = (byte[])in.readObject(); - - init(SubjectPublicKeyInfo.getInstance(enc)); - } - - private void writeObject( - ObjectOutputStream out) - throws IOException - { - out.defaultWriteObject(); - - out.writeObject(this.getEncoded()); - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/RainbowKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/RainbowKeyPairGeneratorSpi.java deleted file mode 100644 index 0bafb9af47..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/rainbow/RainbowKeyPairGeneratorSpi.java +++ /dev/null @@ -1,180 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.rainbow; - -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyPair; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.CryptoServicesRegistrar; -import org.bouncycastle.pqc.crypto.rainbow.RainbowKeyGenerationParameters; -import org.bouncycastle.pqc.crypto.rainbow.RainbowKeyPairGenerator; -import org.bouncycastle.pqc.crypto.rainbow.RainbowParameters; -import org.bouncycastle.pqc.crypto.rainbow.RainbowPrivateKeyParameters; -import org.bouncycastle.pqc.crypto.rainbow.RainbowPublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; -import org.bouncycastle.pqc.jcajce.spec.RainbowParameterSpec; -import org.bouncycastle.util.Strings; - -public class RainbowKeyPairGeneratorSpi - extends java.security.KeyPairGenerator -{ - private static Map parameters = new HashMap(); - - static - { - parameters.put(RainbowParameterSpec.rainbowIIIclassic.getName(), RainbowParameters.rainbowIIIclassic); - parameters.put(RainbowParameterSpec.rainbowIIIcircumzenithal.getName(), RainbowParameters.rainbowIIIcircumzenithal); - parameters.put(RainbowParameterSpec.rainbowIIIcompressed.getName(), RainbowParameters.rainbowIIIcompressed); - parameters.put(RainbowParameterSpec.rainbowVclassic.getName(), RainbowParameters.rainbowVclassic); - parameters.put(RainbowParameterSpec.rainbowVcircumzenithal.getName(), RainbowParameters.rainbowVcircumzenithal); - parameters.put(RainbowParameterSpec.rainbowVcompressed.getName(), RainbowParameters.rainbowVcompressed); - } - - private final RainbowParameters rainbowParameters; - - RainbowKeyGenerationParameters param; - RainbowKeyPairGenerator engine = new RainbowKeyPairGenerator(); - - SecureRandom random = CryptoServicesRegistrar.getSecureRandom(); - boolean initialised = false; - - public RainbowKeyPairGeneratorSpi() - { - super("RAINBOW"); - this.rainbowParameters = null; - } - - protected RainbowKeyPairGeneratorSpi(RainbowParameters rainbowParameters) - { - super(rainbowParameters.getName()); - this.rainbowParameters = rainbowParameters; - } - - public void initialize( - int strength, - SecureRandom random) - { - throw new IllegalArgumentException("use AlgorithmParameterSpec"); - } - - public void initialize( - AlgorithmParameterSpec params, - SecureRandom random) - throws InvalidAlgorithmParameterException - { - String name = getNameFromParams(params); - - if (name != null && parameters.containsKey(name)) - { - RainbowParameters rainbowParams = (RainbowParameters)parameters.get(name); - - param = new RainbowKeyGenerationParameters(random, rainbowParams); - - if (rainbowParameters != null && !rainbowParams.getName().equals(rainbowParameters.getName())) - { - throw new InvalidAlgorithmParameterException("key pair generator locked to " + Strings.toUpperCase(rainbowParameters.getName())); - } - - engine.init(param); - initialised = true; - } - else - { - throw new InvalidAlgorithmParameterException("invalid ParameterSpec: " + params); - } - } - - private static String getNameFromParams(AlgorithmParameterSpec paramSpec) - { - if (paramSpec instanceof RainbowParameterSpec) - { - RainbowParameterSpec rainbowParams = (RainbowParameterSpec)paramSpec; - return rainbowParams.getName(); - } - else - { - return Strings.toLowerCase(SpecUtil.getNameFrom(paramSpec)); - } - } - - public KeyPair generateKeyPair() - { - if (!initialised) - { - if (rainbowParameters != null) - { - param = new RainbowKeyGenerationParameters(random, rainbowParameters); - } - else - { - param = new RainbowKeyGenerationParameters(random, RainbowParameters.rainbowIIIclassic); - } - - engine.init(param); - initialised = true; - } - - AsymmetricCipherKeyPair pair = engine.generateKeyPair(); - RainbowPublicKeyParameters pub = (RainbowPublicKeyParameters)pair.getPublic(); - RainbowPrivateKeyParameters priv = (RainbowPrivateKeyParameters)pair.getPrivate(); - - return new KeyPair(new BCRainbowPublicKey(pub), new BCRainbowPrivateKey(priv)); - } - - public static class RainbowIIIclassic - extends RainbowKeyPairGeneratorSpi - { - public RainbowIIIclassic() - { - super(RainbowParameters.rainbowIIIclassic); - } - } - - public static class RainbowIIIcircum - extends RainbowKeyPairGeneratorSpi - { - public RainbowIIIcircum() - { - super(RainbowParameters.rainbowIIIcircumzenithal); - } - } - - public static class RainbowIIIcomp - extends RainbowKeyPairGeneratorSpi - { - public RainbowIIIcomp() - { - super(RainbowParameters.rainbowIIIcompressed); - } - } - - public static class RainbowVclassic - extends RainbowKeyPairGeneratorSpi - { - public RainbowVclassic() - { - super(RainbowParameters.rainbowVclassic); - } - } - - public static class RainbowVcircum - extends RainbowKeyPairGeneratorSpi - { - public RainbowVcircum() - { - super(RainbowParameters.rainbowVcircumzenithal); - } - } - - public static class RainbowVcomp - extends RainbowKeyPairGeneratorSpi - { - public RainbowVcomp() - { - super(RainbowParameters.rainbowVcompressed); - } - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/saber/SABERKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/saber/SABERKeyPairGeneratorSpi.java index 436da282b1..f5573dd701 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/saber/SABERKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/saber/SABERKeyPairGeneratorSpi.java @@ -9,12 +9,12 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.saber.SABERKeyGenerationParameters; import org.bouncycastle.pqc.crypto.saber.SABERKeyPairGenerator; import org.bouncycastle.pqc.crypto.saber.SABERParameters; import org.bouncycastle.pqc.crypto.saber.SABERPrivateKeyParameters; import org.bouncycastle.pqc.crypto.saber.SABERPublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.pqc.jcajce.spec.SABERParameterSpec; import org.bouncycastle.util.Strings; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/BCSnovaPrivateKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/BCSnovaPrivateKey.java new file mode 100644 index 0000000000..34f47b2df0 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/BCSnovaPrivateKey.java @@ -0,0 +1,132 @@ +package org.bouncycastle.pqc.jcajce.provider.snova; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.PrivateKey; + +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.pqc.crypto.snova.SnovaPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; +import org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory; +import org.bouncycastle.pqc.jcajce.interfaces.SnovaKey; +import org.bouncycastle.pqc.jcajce.spec.SnovaParameterSpec; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +public class BCSnovaPrivateKey + implements PrivateKey, SnovaKey +{ + private static final long serialVersionUID = 1L; + + private transient SnovaPrivateKeyParameters params; + private transient ASN1Set attributes; + + public BCSnovaPrivateKey( + SnovaPrivateKeyParameters params) + { + this.params = params; + } + + public BCSnovaPrivateKey(PrivateKeyInfo keyInfo) + throws IOException + { + init(keyInfo); + } + + private void init(PrivateKeyInfo keyInfo) + throws IOException + { + this.attributes = keyInfo.getAttributes(); + this.params = (SnovaPrivateKeyParameters) PrivateKeyFactory.createKey(keyInfo); + } + + /** + * Compare this private key with another object. + * + * @param o the other object + * @return the result of the comparison + */ + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (o instanceof BCSnovaPrivateKey) + { + BCSnovaPrivateKey otherKey = (BCSnovaPrivateKey)o; + + return Arrays.areEqual(params.getEncoded(), otherKey.params.getEncoded()); + } + + return false; + } + + public int hashCode() + { + return Arrays.hashCode(params.getEncoded()); + } + + /** + * @return name of the algorithm - "Snova_[v]_[o]_[l]" + */ + public final String getAlgorithm() + { + return Strings.toUpperCase(params.getParameters().getName()); + } + + public byte[] getEncoded() + { + + try + { + PrivateKeyInfo pki = PrivateKeyInfoFactory.createPrivateKeyInfo(params, attributes); + + return pki.getEncoded(); + } + catch (IOException e) + { + return null; + } + } + + public SnovaParameterSpec getParameterSpec() + { + return SnovaParameterSpec.fromName(params.getParameters().getName()); + } + + public String getFormat() + { + return "PKCS#8"; + } + + SnovaPrivateKeyParameters getKeyParams() + { + return params; + } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(PrivateKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } +} + + diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/BCSnovaPublicKey.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/BCSnovaPublicKey.java new file mode 100644 index 0000000000..3c6ec6b946 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/BCSnovaPublicKey.java @@ -0,0 +1,128 @@ +package org.bouncycastle.pqc.jcajce.provider.snova; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.PublicKey; + +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.pqc.crypto.snova.SnovaPublicKeyParameters; +import org.bouncycastle.pqc.crypto.util.PublicKeyFactory; +import org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory; +import org.bouncycastle.pqc.jcajce.interfaces.SnovaKey; +import org.bouncycastle.pqc.jcajce.spec.SnovaParameterSpec; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; + +public class BCSnovaPublicKey + implements PublicKey, SnovaKey +{ + private static final long serialVersionUID = 1L; + + private transient SnovaPublicKeyParameters params; + + public BCSnovaPublicKey( + SnovaPublicKeyParameters params) + { + this.params = params; + } + + public BCSnovaPublicKey(SubjectPublicKeyInfo keyInfo) + throws IOException + { + init(keyInfo); + } + + private void init(SubjectPublicKeyInfo keyInfo) + throws IOException + { + this.params = (SnovaPublicKeyParameters) PublicKeyFactory.createKey(keyInfo); + } + + /** + * Compare this BIKE public key with another object. + * + * @param o the other object + * @return the result of the comparison + */ + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (o instanceof BCSnovaPublicKey) + { + BCSnovaPublicKey otherKey = (BCSnovaPublicKey)o; + + return Arrays.areEqual(params.getEncoded(), otherKey.params.getEncoded()); + } + + return false; + } + + public int hashCode() + { + return Arrays.hashCode(params.getEncoded()); + } + + /** + * @return name of the algorithm - "Snova_[v]_[o]_[l]" + */ + public final String getAlgorithm() + { + return Strings.toUpperCase(params.getParameters().getName()); + } + + public byte[] getEncoded() + { + try + { + SubjectPublicKeyInfo pki = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(params); + + return pki.getEncoded(); + } + catch (IOException e) + { + return null; + } + } + + public String getFormat() + { + return "X.509"; + } + + public SnovaParameterSpec getParameterSpec() + { + return SnovaParameterSpec.fromName(params.getParameters().getName()); + } + + SnovaPublicKeyParameters getKeyParams() + { + return params; + } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(SubjectPublicKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } +} + + diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/SignatureSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/SignatureSpi.java new file mode 100644 index 0000000000..e544734348 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/SignatureSpi.java @@ -0,0 +1,578 @@ +package org.bouncycastle.pqc.jcajce.provider.snova; + +import java.io.ByteArrayOutputStream; +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.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.pqc.crypto.snova.SnovaParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaSigner; +import org.bouncycastle.util.Strings; + +public class SignatureSpi + extends java.security.Signature +{ + private final ByteArrayOutputStream bOut; + private final SnovaSigner signer; + private SecureRandom random; + private final SnovaParameters parameters; + + protected SignatureSpi(SnovaSigner signer) + { + super("Snova"); + + this.bOut = new ByteArrayOutputStream(); + this.signer = signer; + this.parameters = null; + } + + protected SignatureSpi(SnovaSigner signer, SnovaParameters parameters) + { + super(Strings.toUpperCase(parameters.getName())); + this.parameters = parameters; + + this.bOut = new ByteArrayOutputStream(); + this.signer = signer; + } + + protected void engineInitVerify(PublicKey publicKey) + throws InvalidKeyException + { + if (!(publicKey instanceof BCSnovaPublicKey)) + { + try + { + publicKey = new BCSnovaPublicKey(SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); + } + catch (Exception e) + { + throw new InvalidKeyException("unknown public key passed to Snova: " + e.getMessage()); + } + } + + BCSnovaPublicKey key = (BCSnovaPublicKey)publicKey; + + if (parameters != null) + { + String canonicalAlg = Strings.toUpperCase(parameters.getName()); + if (!canonicalAlg.equals(key.getAlgorithm())) + { + throw new InvalidKeyException("signature configured for " + canonicalAlg); + } + } + + signer.init(false, key.getKeyParams()); + } + + protected void engineInitSign(PrivateKey privateKey, SecureRandom random) + throws InvalidKeyException + { + this.random = random; + engineInitSign(privateKey); + } + + protected void engineInitSign(PrivateKey privateKey) + throws InvalidKeyException + { + if (privateKey instanceof BCSnovaPrivateKey) + { + BCSnovaPrivateKey key = (BCSnovaPrivateKey)privateKey; + CipherParameters param = key.getKeyParams(); + + if (parameters != null) + { + String canonicalAlg = Strings.toUpperCase(parameters.getName()); + if (!canonicalAlg.equals(key.getAlgorithm())) + { + throw new InvalidKeyException("signature configured for " + canonicalAlg); + } + } + + if (random != null) + { + signer.init(true, new ParametersWithRandom(param, random)); + } + else + { + signer.init(true, param); + } + } + else + { + throw new InvalidKeyException("unknown private key passed to Snova"); + } + } + + protected void engineUpdate(byte b) + throws SignatureException + { + bOut.write(b); + } + + protected void engineUpdate(byte[] b, int off, int len) + throws SignatureException + { + bOut.write(b, off, len); + } + + protected byte[] engineSign() + throws SignatureException + { + try + { + byte[] message = bOut.toByteArray(); + + bOut.reset(); + + return signer.generateSignature(message); + } + catch (Exception e) + { + throw new SignatureException(e.toString()); + } + } + + protected boolean engineVerify(byte[] sigBytes) + throws SignatureException + { + byte[] message = bOut.toByteArray(); + + bOut.reset(); + + return signer.verifySignature(message, sigBytes); + } + + protected void engineSetParameter(AlgorithmParameterSpec params) + { + // TODO + throw new UnsupportedOperationException("engineSetParameter unsupported"); + } + + /** + * @deprecated replaced with #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"); + } + + public static class Base + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public Base() + { + super(new SnovaSigner()); + } + } + + public static class SNOVA_24_5_4_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_24_5_4_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_24_5_4_SSK); + } + } + + public static class SNOVA_24_5_4_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_24_5_4_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_24_5_4_ESK); + } + } + + public static class SNOVA_24_5_4_SHAKE_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_24_5_4_SHAKE_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_24_5_4_SHAKE_ESK); + } + } + + public static class SNOVA_24_5_4_SHAKE_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_24_5_4_SHAKE_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_24_5_4_SHAKE_SSK); + } + } + + public static class SNOVA_24_5_5_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_24_5_5_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_24_5_5_SSK); + } + } + + public static class SNOVA_24_5_5_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_24_5_5_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_24_5_5_ESK); + } + } + + public static class SNOVA_24_5_5_SHAKE_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_24_5_5_SHAKE_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_24_5_5_SHAKE_ESK); + } + } + + public static class SNOVA_24_5_5_SHAKE_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_24_5_5_SHAKE_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_24_5_5_SHAKE_SSK); + } + } + + public static class SNOVA_25_8_3_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_25_8_3_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_25_8_3_SSK); + } + } + + public static class SNOVA_25_8_3_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_25_8_3_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_25_8_3_ESK); + } + } + + public static class SNOVA_25_8_3_SHAKE_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_25_8_3_SHAKE_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_25_8_3_SHAKE_ESK); + } + } + + public static class SNOVA_25_8_3_SHAKE_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_25_8_3_SHAKE_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_25_8_3_SHAKE_SSK); + } + } + + public static class SNOVA_29_6_5_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_29_6_5_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_29_6_5_SSK); + } + } + + public static class SNOVA_29_6_5_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_29_6_5_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_29_6_5_ESK); + } + } + + public static class SNOVA_29_6_5_SHAKE_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_29_6_5_SHAKE_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_29_6_5_SHAKE_ESK); + } + } + + public static class SNOVA_29_6_5_SHAKE_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_29_6_5_SHAKE_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_29_6_5_SHAKE_SSK); + } + } + + public static class SNOVA_37_8_4_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_37_8_4_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_37_8_4_SSK); + } + } + + public static class SNOVA_37_8_4_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_37_8_4_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_37_8_4_ESK); + } + } + + public static class SNOVA_37_8_4_SHAKE_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_37_8_4_SHAKE_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_37_8_4_SHAKE_ESK); + } + } + + public static class SNOVA_37_8_4_SHAKE_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_37_8_4_SHAKE_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_37_8_4_SHAKE_SSK); + } + } + + public static class SNOVA_37_17_2_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_37_17_2_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_37_17_2_SSK); + } + } + + public static class SNOVA_37_17_2_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_37_17_2_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_37_17_2_ESK); + } + } + + public static class SNOVA_37_17_2_SHAKE_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_37_17_2_SHAKE_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_37_17_2_SHAKE_ESK); + } + } + + public static class SNOVA_37_17_2_SHAKE_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_37_17_2_SHAKE_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_37_17_2_SHAKE_SSK); + } + } + + public static class SNOVA_49_11_3_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_49_11_3_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_49_11_3_SSK); + } + } + + public static class SNOVA_49_11_3_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_49_11_3_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_49_11_3_ESK); + } + } + + public static class SNOVA_49_11_3_SHAKE_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_49_11_3_SHAKE_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_49_11_3_SHAKE_ESK); + } + } + + public static class SNOVA_49_11_3_SHAKE_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_49_11_3_SHAKE_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_49_11_3_SHAKE_SSK); + } + } + + public static class SNOVA_56_25_2_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_56_25_2_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_56_25_2_SSK); + } + } + + public static class SNOVA_56_25_2_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_56_25_2_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_56_25_2_ESK); + } + } + + public static class SNOVA_56_25_2_SHAKE_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_56_25_2_SHAKE_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_56_25_2_SHAKE_ESK); + } + } + + public static class SNOVA_56_25_2_SHAKE_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_56_25_2_SHAKE_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_56_25_2_SHAKE_SSK); + } + } + + public static class SNOVA_60_10_4_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_60_10_4_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_60_10_4_SSK); + } + } + + public static class SNOVA_60_10_4_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_60_10_4_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_60_10_4_ESK); + } + } + + public static class SNOVA_60_10_4_SHAKE_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_60_10_4_SHAKE_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_60_10_4_SHAKE_ESK); + } + } + + public static class SNOVA_60_10_4_SHAKE_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_60_10_4_SHAKE_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_60_10_4_SHAKE_SSK); + } + } + + public static class SNOVA_66_15_3_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_66_15_3_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_66_15_3_SSK); + } + } + + public static class SNOVA_66_15_3_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_66_15_3_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_66_15_3_ESK); + } + } + + public static class SNOVA_66_15_3_SHAKE_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_66_15_3_SHAKE_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_66_15_3_SHAKE_ESK); + } + } + + public static class SNOVA_66_15_3_SHAKE_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_66_15_3_SHAKE_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_66_15_3_SHAKE_SSK); + } + } + + public static class SNOVA_75_33_2_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_75_33_2_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_75_33_2_SSK); + } + } + + public static class SNOVA_75_33_2_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_75_33_2_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_75_33_2_ESK); + } + } + + public static class SNOVA_75_33_2_SHAKE_ESK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_75_33_2_SHAKE_ESK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_75_33_2_SHAKE_ESK); + } + } + + public static class SNOVA_75_33_2_SHAKE_SSK + extends org.bouncycastle.pqc.jcajce.provider.snova.SignatureSpi + { + public SNOVA_75_33_2_SHAKE_SSK() + { + super(new SnovaSigner(), SnovaParameters.SNOVA_75_33_2_SHAKE_SSK); + } + } +} + diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/SnovaKeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/SnovaKeyFactorySpi.java new file mode 100644 index 0000000000..060696c0f5 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/SnovaKeyFactorySpi.java @@ -0,0 +1,531 @@ +package org.bouncycastle.pqc.jcajce.provider.snova; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.Key; +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 java.util.HashSet; +import java.util.Set; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.bc.BCObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.pqc.jcajce.provider.util.BaseKeyFactorySpi; + +public class SnovaKeyFactorySpi + extends BaseKeyFactorySpi +{ + private static final Set keyOids = new HashSet(); + + static + { + keyOids.add(BCObjectIdentifiers.snova_24_5_4_ssk); + keyOids.add(BCObjectIdentifiers.snova_24_5_4_esk); + keyOids.add(BCObjectIdentifiers.snova_24_5_4_shake_ssk); + keyOids.add(BCObjectIdentifiers.snova_24_5_4_shake_esk); + keyOids.add(BCObjectIdentifiers.snova_24_5_5_ssk); + keyOids.add(BCObjectIdentifiers.snova_24_5_5_esk); + keyOids.add(BCObjectIdentifiers.snova_24_5_5_shake_ssk); + keyOids.add(BCObjectIdentifiers.snova_24_5_5_shake_esk); + keyOids.add(BCObjectIdentifiers.snova_25_8_3_ssk); + keyOids.add(BCObjectIdentifiers.snova_25_8_3_esk); + keyOids.add(BCObjectIdentifiers.snova_25_8_3_shake_ssk); + keyOids.add(BCObjectIdentifiers.snova_25_8_3_shake_esk); + keyOids.add(BCObjectIdentifiers.snova_29_6_5_ssk); + keyOids.add(BCObjectIdentifiers.snova_29_6_5_esk); + keyOids.add(BCObjectIdentifiers.snova_29_6_5_shake_ssk); + keyOids.add(BCObjectIdentifiers.snova_29_6_5_shake_esk); + keyOids.add(BCObjectIdentifiers.snova_37_8_4_ssk); + keyOids.add(BCObjectIdentifiers.snova_37_8_4_esk); + keyOids.add(BCObjectIdentifiers.snova_37_8_4_shake_ssk); + keyOids.add(BCObjectIdentifiers.snova_37_8_4_shake_esk); + keyOids.add(BCObjectIdentifiers.snova_37_17_2_ssk); + keyOids.add(BCObjectIdentifiers.snova_37_17_2_esk); + keyOids.add(BCObjectIdentifiers.snova_37_17_2_shake_ssk); + keyOids.add(BCObjectIdentifiers.snova_37_17_2_shake_esk); + keyOids.add(BCObjectIdentifiers.snova_49_11_3_ssk); + keyOids.add(BCObjectIdentifiers.snova_49_11_3_esk); + keyOids.add(BCObjectIdentifiers.snova_49_11_3_shake_ssk); + keyOids.add(BCObjectIdentifiers.snova_49_11_3_shake_esk); + keyOids.add(BCObjectIdentifiers.snova_56_25_2_ssk); + keyOids.add(BCObjectIdentifiers.snova_56_25_2_esk); + keyOids.add(BCObjectIdentifiers.snova_56_25_2_shake_ssk); + keyOids.add(BCObjectIdentifiers.snova_56_25_2_shake_esk); + keyOids.add(BCObjectIdentifiers.snova_60_10_4_ssk); + keyOids.add(BCObjectIdentifiers.snova_60_10_4_esk); + keyOids.add(BCObjectIdentifiers.snova_60_10_4_shake_ssk); + keyOids.add(BCObjectIdentifiers.snova_60_10_4_shake_esk); + keyOids.add(BCObjectIdentifiers.snova_66_15_3_ssk); + keyOids.add(BCObjectIdentifiers.snova_66_15_3_esk); + keyOids.add(BCObjectIdentifiers.snova_66_15_3_shake_ssk); + keyOids.add(BCObjectIdentifiers.snova_66_15_3_shake_esk); + keyOids.add(BCObjectIdentifiers.snova_75_33_2_ssk); + keyOids.add(BCObjectIdentifiers.snova_75_33_2_esk); + keyOids.add(BCObjectIdentifiers.snova_75_33_2_shake_ssk); + keyOids.add(BCObjectIdentifiers.snova_75_33_2_shake_esk); + } + + public SnovaKeyFactorySpi() + { + super(keyOids); + } + + public SnovaKeyFactorySpi(ASN1ObjectIdentifier keyOid) + { + super(keyOid); + } + + public final KeySpec engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + if (key instanceof BCSnovaPrivateKey) + { + if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) + { + return new PKCS8EncodedKeySpec(key.getEncoded()); + } + } + else if (key instanceof BCSnovaPublicKey) + { + 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 BCSnovaPrivateKey || key instanceof BCSnovaPublicKey) + { + return key; + } + + throw new InvalidKeyException("Unsupported key type"); + } + + public PrivateKey generatePrivate(PrivateKeyInfo keyInfo) + throws IOException + { + return new BCSnovaPrivateKey(keyInfo); + } + + public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo) + throws IOException + { + return new BCSnovaPublicKey(keyInfo); + } + + public static class SNOVA_24_5_4_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_24_5_4_SSK() + { + super(BCObjectIdentifiers.snova_24_5_4_ssk); + } + } + + public static class SNOVA_24_5_4_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_24_5_4_ESK() + { + super(BCObjectIdentifiers.snova_24_5_4_esk); + } + } + + public static class SNOVA_24_5_4_SHAKE_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_24_5_4_SHAKE_SSK() + { + super(BCObjectIdentifiers.snova_24_5_4_shake_ssk); + } + } + + public static class SNOVA_24_5_4_SHAKE_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_24_5_4_SHAKE_ESK() + { + super(BCObjectIdentifiers.snova_24_5_4_shake_esk); + } + } + + public static class SNOVA_24_5_5_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_24_5_5_SSK() + { + super(BCObjectIdentifiers.snova_24_5_5_ssk); + } + } + + public static class SNOVA_24_5_5_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_24_5_5_ESK() + { + super(BCObjectIdentifiers.snova_24_5_5_esk); + } + } + + public static class SNOVA_24_5_5_SHAKE_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_24_5_5_SHAKE_SSK() + { + super(BCObjectIdentifiers.snova_24_5_5_shake_ssk); + } + } + + public static class SNOVA_24_5_5_SHAKE_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_24_5_5_SHAKE_ESK() + { + super(BCObjectIdentifiers.snova_24_5_5_shake_esk); + } + } + + public static class SNOVA_25_8_3_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_25_8_3_SSK() + { + super(BCObjectIdentifiers.snova_25_8_3_ssk); + } + } + + public static class SNOVA_25_8_3_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_25_8_3_ESK() + { + super(BCObjectIdentifiers.snova_25_8_3_esk); + } + } + + public static class SNOVA_25_8_3_SHAKE_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_25_8_3_SHAKE_SSK() + { + super(BCObjectIdentifiers.snova_25_8_3_shake_ssk); + } + } + + public static class SNOVA_25_8_3_SHAKE_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_25_8_3_SHAKE_ESK() + { + super(BCObjectIdentifiers.snova_25_8_3_shake_esk); + } + } + + public static class SNOVA_29_6_5_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_29_6_5_SSK() + { + super(BCObjectIdentifiers.snova_29_6_5_ssk); + } + } + + public static class SNOVA_29_6_5_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_29_6_5_ESK() + { + super(BCObjectIdentifiers.snova_29_6_5_esk); + } + } + + public static class SNOVA_29_6_5_SHAKE_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_29_6_5_SHAKE_SSK() + { + super(BCObjectIdentifiers.snova_29_6_5_shake_ssk); + } + } + + public static class SNOVA_29_6_5_SHAKE_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_29_6_5_SHAKE_ESK() + { + super(BCObjectIdentifiers.snova_29_6_5_shake_esk); + } + } + + public static class SNOVA_37_8_4_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_37_8_4_SSK() + { + super(BCObjectIdentifiers.snova_37_8_4_ssk); + } + } + + public static class SNOVA_37_8_4_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_37_8_4_ESK() + { + super(BCObjectIdentifiers.snova_37_8_4_esk); + } + } + + public static class SNOVA_37_8_4_SHAKE_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_37_8_4_SHAKE_SSK() + { + super(BCObjectIdentifiers.snova_37_8_4_shake_ssk); + } + } + + public static class SNOVA_37_8_4_SHAKE_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_37_8_4_SHAKE_ESK() + { + super(BCObjectIdentifiers.snova_37_8_4_shake_esk); + } + } + + public static class SNOVA_37_17_2_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_37_17_2_SSK() + { + super(BCObjectIdentifiers.snova_37_17_2_ssk); + } + } + + public static class SNOVA_37_17_2_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_37_17_2_ESK() + { + super(BCObjectIdentifiers.snova_37_17_2_esk); + } + } + + public static class SNOVA_37_17_2_SHAKE_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_37_17_2_SHAKE_SSK() + { + super(BCObjectIdentifiers.snova_37_17_2_shake_ssk); + } + } + + public static class SNOVA_37_17_2_SHAKE_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_37_17_2_SHAKE_ESK() + { + super(BCObjectIdentifiers.snova_37_17_2_shake_esk); + } + } + + public static class SNOVA_49_11_3_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_49_11_3_SSK() + { + super(BCObjectIdentifiers.snova_49_11_3_ssk); + } + } + + public static class SNOVA_49_11_3_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_49_11_3_ESK() + { + super(BCObjectIdentifiers.snova_49_11_3_esk); + } + } + + public static class SNOVA_49_11_3_SHAKE_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_49_11_3_SHAKE_SSK() + { + super(BCObjectIdentifiers.snova_49_11_3_shake_ssk); + } + } + + public static class SNOVA_49_11_3_SHAKE_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_49_11_3_SHAKE_ESK() + { + super(BCObjectIdentifiers.snova_49_11_3_shake_esk); + } + } + + public static class SNOVA_56_25_2_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_56_25_2_SSK() + { + super(BCObjectIdentifiers.snova_56_25_2_ssk); + } + } + + public static class SNOVA_56_25_2_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_56_25_2_ESK() + { + super(BCObjectIdentifiers.snova_56_25_2_esk); + } + } + + public static class SNOVA_56_25_2_SHAKE_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_56_25_2_SHAKE_SSK() + { + super(BCObjectIdentifiers.snova_56_25_2_shake_ssk); + } + } + + public static class SNOVA_56_25_2_SHAKE_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_56_25_2_SHAKE_ESK() + { + super(BCObjectIdentifiers.snova_56_25_2_shake_esk); + } + } + + public static class SNOVA_60_10_4_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_60_10_4_SSK() + { + super(BCObjectIdentifiers.snova_60_10_4_ssk); + } + } + + public static class SNOVA_60_10_4_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_60_10_4_ESK() + { + super(BCObjectIdentifiers.snova_60_10_4_esk); + } + } + + public static class SNOVA_60_10_4_SHAKE_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_60_10_4_SHAKE_SSK() + { + super(BCObjectIdentifiers.snova_60_10_4_shake_ssk); + } + } + + public static class SNOVA_60_10_4_SHAKE_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_60_10_4_SHAKE_ESK() + { + super(BCObjectIdentifiers.snova_60_10_4_shake_esk); + } + } + + public static class SNOVA_66_15_3_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_66_15_3_SSK() + { + super(BCObjectIdentifiers.snova_66_15_3_ssk); + } + } + + public static class SNOVA_66_15_3_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_66_15_3_ESK() + { + super(BCObjectIdentifiers.snova_66_15_3_esk); + } + } + + public static class SNOVA_66_15_3_SHAKE_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_66_15_3_SHAKE_SSK() + { + super(BCObjectIdentifiers.snova_66_15_3_shake_ssk); + } + } + + public static class SNOVA_66_15_3_SHAKE_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_66_15_3_SHAKE_ESK() + { + super(BCObjectIdentifiers.snova_66_15_3_shake_esk); + } + } + + public static class SNOVA_75_33_2_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_75_33_2_SSK() + { + super(BCObjectIdentifiers.snova_75_33_2_ssk); + } + } + + public static class SNOVA_75_33_2_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_75_33_2_ESK() + { + super(BCObjectIdentifiers.snova_75_33_2_esk); + } + } + + public static class SNOVA_75_33_2_SHAKE_SSK + extends SnovaKeyFactorySpi + { + public SNOVA_75_33_2_SHAKE_SSK() + { + super(BCObjectIdentifiers.snova_75_33_2_shake_ssk); + } + } + + public static class SNOVA_75_33_2_SHAKE_ESK + extends SnovaKeyFactorySpi + { + public SNOVA_75_33_2_SHAKE_ESK() + { + super(BCObjectIdentifiers.snova_75_33_2_shake_esk); + } + } +} + + diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/SnovaKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/SnovaKeyPairGeneratorSpi.java new file mode 100644 index 0000000000..fa21b3ce7a --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/snova/SnovaKeyPairGeneratorSpi.java @@ -0,0 +1,590 @@ +package org.bouncycastle.pqc.jcajce.provider.snova; + + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; +import org.bouncycastle.pqc.crypto.snova.SnovaKeyGenerationParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaKeyPairGenerator; +import org.bouncycastle.pqc.crypto.snova.SnovaParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.snova.SnovaPublicKeyParameters; +import org.bouncycastle.pqc.jcajce.spec.SnovaParameterSpec; +import org.bouncycastle.util.Strings; + +public class SnovaKeyPairGeneratorSpi + extends java.security.KeyPairGenerator +{ + private static Map parameters = new HashMap(); + + static + { + parameters.put("SNOVA_24_5_4_SSK", SnovaParameters.SNOVA_24_5_4_SSK); + parameters.put("SNOVA_24_5_4_ESK", SnovaParameters.SNOVA_24_5_4_ESK); + parameters.put("SNOVA_24_5_4_SHAKE_SSK", SnovaParameters.SNOVA_24_5_4_SHAKE_SSK); + parameters.put("SNOVA_24_5_4_SHAKE_ESK", SnovaParameters.SNOVA_24_5_4_SHAKE_ESK); + parameters.put("SNOVA_24_5_5_SSK", SnovaParameters.SNOVA_24_5_5_SSK); + parameters.put("SNOVA_24_5_5_ESK", SnovaParameters.SNOVA_24_5_5_ESK); + parameters.put("SNOVA_24_5_5_SHAKE_SSK", SnovaParameters.SNOVA_24_5_5_SHAKE_SSK); + parameters.put("SNOVA_24_5_5_SHAKE_ESK", SnovaParameters.SNOVA_24_5_5_SHAKE_ESK); + parameters.put("SNOVA_25_8_3_SSK", SnovaParameters.SNOVA_25_8_3_SSK); + parameters.put("SNOVA_25_8_3_ESK", SnovaParameters.SNOVA_25_8_3_ESK); + parameters.put("SNOVA_25_8_3_SHAKE_SSK", SnovaParameters.SNOVA_25_8_3_SHAKE_SSK); + parameters.put("SNOVA_25_8_3_SHAKE_ESK", SnovaParameters.SNOVA_25_8_3_SHAKE_ESK); + parameters.put("SNOVA_29_6_5_SSK", SnovaParameters.SNOVA_29_6_5_SSK); + parameters.put("SNOVA_29_6_5_ESK", SnovaParameters.SNOVA_29_6_5_ESK); + parameters.put("SNOVA_29_6_5_SHAKE_SSK", SnovaParameters.SNOVA_29_6_5_SHAKE_SSK); + parameters.put("SNOVA_29_6_5_SHAKE_ESK", SnovaParameters.SNOVA_29_6_5_SHAKE_ESK); + parameters.put("SNOVA_37_8_4_SSK", SnovaParameters.SNOVA_37_8_4_SSK); + parameters.put("SNOVA_37_8_4_ESK", SnovaParameters.SNOVA_37_8_4_ESK); + parameters.put("SNOVA_37_8_4_SHAKE_SSK", SnovaParameters.SNOVA_37_8_4_SHAKE_SSK); + parameters.put("SNOVA_37_8_4_SHAKE_ESK", SnovaParameters.SNOVA_37_8_4_SHAKE_ESK); + parameters.put("SNOVA_37_17_2_SSK", SnovaParameters.SNOVA_37_17_2_SSK); + parameters.put("SNOVA_37_17_2_ESK", SnovaParameters.SNOVA_37_17_2_ESK); + parameters.put("SNOVA_37_17_2_SHAKE_SSK", SnovaParameters.SNOVA_37_17_2_SHAKE_SSK); + parameters.put("SNOVA_37_17_2_SHAKE_ESK", SnovaParameters.SNOVA_37_17_2_SHAKE_ESK); + parameters.put("SNOVA_49_11_3_SSK", SnovaParameters.SNOVA_49_11_3_SSK); + parameters.put("SNOVA_49_11_3_ESK", SnovaParameters.SNOVA_49_11_3_ESK); + parameters.put("SNOVA_49_11_3_SHAKE_SSK", SnovaParameters.SNOVA_49_11_3_SHAKE_SSK); + parameters.put("SNOVA_49_11_3_SHAKE_ESK", SnovaParameters.SNOVA_49_11_3_SHAKE_ESK); + parameters.put("SNOVA_56_25_2_SSK", SnovaParameters.SNOVA_56_25_2_SSK); + parameters.put("SNOVA_56_25_2_ESK", SnovaParameters.SNOVA_56_25_2_ESK); + parameters.put("SNOVA_56_25_2_SHAKE_SSK", SnovaParameters.SNOVA_56_25_2_SHAKE_SSK); + parameters.put("SNOVA_56_25_2_SHAKE_ESK", SnovaParameters.SNOVA_56_25_2_SHAKE_ESK); + parameters.put("SNOVA_60_10_4_SSK", SnovaParameters.SNOVA_60_10_4_SSK); + parameters.put("SNOVA_60_10_4_ESK", SnovaParameters.SNOVA_60_10_4_ESK); + parameters.put("SNOVA_60_10_4_SHAKE_SSK", SnovaParameters.SNOVA_60_10_4_SHAKE_SSK); + parameters.put("SNOVA_60_10_4_SHAKE_ESK", SnovaParameters.SNOVA_60_10_4_SHAKE_ESK); + parameters.put("SNOVA_66_15_3_SSK", SnovaParameters.SNOVA_66_15_3_SSK); + parameters.put("SNOVA_66_15_3_ESK", SnovaParameters.SNOVA_66_15_3_ESK); + parameters.put("SNOVA_66_15_3_SHAKE_SSK", SnovaParameters.SNOVA_66_15_3_SHAKE_SSK); + parameters.put("SNOVA_66_15_3_SHAKE_ESK", SnovaParameters.SNOVA_66_15_3_SHAKE_ESK); + parameters.put("SNOVA_75_33_2_SSK", SnovaParameters.SNOVA_75_33_2_SSK); + parameters.put("SNOVA_75_33_2_ESK", SnovaParameters.SNOVA_75_33_2_ESK); + parameters.put("SNOVA_75_33_2_SHAKE_SSK", SnovaParameters.SNOVA_75_33_2_SHAKE_SSK); + parameters.put("SNOVA_75_33_2_SHAKE_ESK", SnovaParameters.SNOVA_75_33_2_SHAKE_ESK); + parameters.put(SnovaParameterSpec.SNOVA_24_5_4_SSK.getName(), SnovaParameters.SNOVA_24_5_4_SSK); + parameters.put(SnovaParameterSpec.SNOVA_24_5_4_ESK.getName(), SnovaParameters.SNOVA_24_5_4_ESK); + parameters.put(SnovaParameterSpec.SNOVA_24_5_4_SHAKE_SSK.getName(), SnovaParameters.SNOVA_24_5_4_SHAKE_SSK); + parameters.put(SnovaParameterSpec.SNOVA_24_5_4_SHAKE_ESK.getName(), SnovaParameters.SNOVA_24_5_4_SHAKE_ESK); + parameters.put(SnovaParameterSpec.SNOVA_24_5_5_SSK.getName(), SnovaParameters.SNOVA_24_5_5_SSK); + parameters.put(SnovaParameterSpec.SNOVA_24_5_5_ESK.getName(), SnovaParameters.SNOVA_24_5_5_ESK); + parameters.put(SnovaParameterSpec.SNOVA_24_5_5_SHAKE_SSK.getName(), SnovaParameters.SNOVA_24_5_5_SHAKE_SSK); + parameters.put(SnovaParameterSpec.SNOVA_24_5_5_SHAKE_ESK.getName(), SnovaParameters.SNOVA_24_5_5_SHAKE_ESK); + parameters.put(SnovaParameterSpec.SNOVA_25_8_3_SSK.getName(), SnovaParameters.SNOVA_25_8_3_SSK); + parameters.put(SnovaParameterSpec.SNOVA_25_8_3_ESK.getName(), SnovaParameters.SNOVA_25_8_3_ESK); + parameters.put(SnovaParameterSpec.SNOVA_25_8_3_SHAKE_SSK.getName(), SnovaParameters.SNOVA_25_8_3_SHAKE_SSK); + parameters.put(SnovaParameterSpec.SNOVA_25_8_3_SHAKE_ESK.getName(), SnovaParameters.SNOVA_25_8_3_SHAKE_ESK); + parameters.put(SnovaParameterSpec.SNOVA_29_6_5_SSK.getName(), SnovaParameters.SNOVA_29_6_5_SSK); + parameters.put(SnovaParameterSpec.SNOVA_29_6_5_ESK.getName(), SnovaParameters.SNOVA_29_6_5_ESK); + parameters.put(SnovaParameterSpec.SNOVA_29_6_5_SHAKE_SSK.getName(), SnovaParameters.SNOVA_29_6_5_SHAKE_SSK); + parameters.put(SnovaParameterSpec.SNOVA_29_6_5_SHAKE_ESK.getName(), SnovaParameters.SNOVA_29_6_5_SHAKE_ESK); + parameters.put(SnovaParameterSpec.SNOVA_37_8_4_SSK.getName(), SnovaParameters.SNOVA_37_8_4_SSK); + parameters.put(SnovaParameterSpec.SNOVA_37_8_4_ESK.getName(), SnovaParameters.SNOVA_37_8_4_ESK); + parameters.put(SnovaParameterSpec.SNOVA_37_8_4_SHAKE_SSK.getName(), SnovaParameters.SNOVA_37_8_4_SHAKE_SSK); + parameters.put(SnovaParameterSpec.SNOVA_37_8_4_SHAKE_ESK.getName(), SnovaParameters.SNOVA_37_8_4_SHAKE_ESK); + parameters.put(SnovaParameterSpec.SNOVA_37_17_2_SSK.getName(), SnovaParameters.SNOVA_37_17_2_SSK); + parameters.put(SnovaParameterSpec.SNOVA_37_17_2_ESK.getName(), SnovaParameters.SNOVA_37_17_2_ESK); + parameters.put(SnovaParameterSpec.SNOVA_37_17_2_SHAKE_SSK.getName(), SnovaParameters.SNOVA_37_17_2_SHAKE_SSK); + parameters.put(SnovaParameterSpec.SNOVA_37_17_2_SHAKE_ESK.getName(), SnovaParameters.SNOVA_37_17_2_SHAKE_ESK); + parameters.put(SnovaParameterSpec.SNOVA_49_11_3_SSK.getName(), SnovaParameters.SNOVA_49_11_3_SSK); + parameters.put(SnovaParameterSpec.SNOVA_49_11_3_ESK.getName(), SnovaParameters.SNOVA_49_11_3_ESK); + parameters.put(SnovaParameterSpec.SNOVA_49_11_3_SHAKE_SSK.getName(), SnovaParameters.SNOVA_49_11_3_SHAKE_SSK); + parameters.put(SnovaParameterSpec.SNOVA_49_11_3_SHAKE_ESK.getName(), SnovaParameters.SNOVA_49_11_3_SHAKE_ESK); + parameters.put(SnovaParameterSpec.SNOVA_56_25_2_SSK.getName(), SnovaParameters.SNOVA_56_25_2_SSK); + parameters.put(SnovaParameterSpec.SNOVA_56_25_2_ESK.getName(), SnovaParameters.SNOVA_56_25_2_ESK); + parameters.put(SnovaParameterSpec.SNOVA_56_25_2_SHAKE_SSK.getName(), SnovaParameters.SNOVA_56_25_2_SHAKE_SSK); + parameters.put(SnovaParameterSpec.SNOVA_56_25_2_SHAKE_ESK.getName(), SnovaParameters.SNOVA_56_25_2_SHAKE_ESK); + parameters.put(SnovaParameterSpec.SNOVA_60_10_4_SSK.getName(), SnovaParameters.SNOVA_60_10_4_SSK); + parameters.put(SnovaParameterSpec.SNOVA_60_10_4_ESK.getName(), SnovaParameters.SNOVA_60_10_4_ESK); + parameters.put(SnovaParameterSpec.SNOVA_60_10_4_SHAKE_SSK.getName(), SnovaParameters.SNOVA_60_10_4_SHAKE_SSK); + parameters.put(SnovaParameterSpec.SNOVA_60_10_4_SHAKE_ESK.getName(), SnovaParameters.SNOVA_60_10_4_SHAKE_ESK); + parameters.put(SnovaParameterSpec.SNOVA_66_15_3_SSK.getName(), SnovaParameters.SNOVA_66_15_3_SSK); + parameters.put(SnovaParameterSpec.SNOVA_66_15_3_ESK.getName(), SnovaParameters.SNOVA_66_15_3_ESK); + parameters.put(SnovaParameterSpec.SNOVA_66_15_3_SHAKE_SSK.getName(), SnovaParameters.SNOVA_66_15_3_SHAKE_SSK); + parameters.put(SnovaParameterSpec.SNOVA_66_15_3_SHAKE_ESK.getName(), SnovaParameters.SNOVA_66_15_3_SHAKE_ESK); + parameters.put(SnovaParameterSpec.SNOVA_75_33_2_SSK.getName(), SnovaParameters.SNOVA_75_33_2_SSK); + parameters.put(SnovaParameterSpec.SNOVA_75_33_2_ESK.getName(), SnovaParameters.SNOVA_75_33_2_ESK); + parameters.put(SnovaParameterSpec.SNOVA_75_33_2_SHAKE_SSK.getName(), SnovaParameters.SNOVA_75_33_2_SHAKE_SSK); + parameters.put(SnovaParameterSpec.SNOVA_75_33_2_SHAKE_ESK.getName(), SnovaParameters.SNOVA_75_33_2_SHAKE_ESK); + } + + SnovaKeyGenerationParameters param; + private SnovaParameters snovaParameters; + SnovaKeyPairGenerator engine = new SnovaKeyPairGenerator(); + + SecureRandom random = CryptoServicesRegistrar.getSecureRandom(); + boolean initialised = false; + + public SnovaKeyPairGeneratorSpi() + { + super("Snova"); + } + + protected SnovaKeyPairGeneratorSpi(SnovaParameters SnovaParameters) + { + super(SnovaParameters.getName()); + this.snovaParameters = SnovaParameters; + } + + public void initialize( + int strength, + SecureRandom random) + { + throw new IllegalArgumentException("use AlgorithmParameterSpec"); + } + + public void initialize( + AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidAlgorithmParameterException + { + String name = getNameFromParams(params); + + if (name != null) + { + param = new SnovaKeyGenerationParameters(random, (SnovaParameters)parameters.get(name)); + + engine.init(param); + initialised = true; + } + else + { + throw new InvalidAlgorithmParameterException("invalid ParameterSpec: " + params); + } + } + + private static String getNameFromParams(AlgorithmParameterSpec paramSpec) + { + if (paramSpec instanceof SnovaParameterSpec) + { + SnovaParameterSpec SnovaParams = (SnovaParameterSpec)paramSpec; + return SnovaParams.getName(); + } + else + { + return Strings.toLowerCase(SpecUtil.getNameFrom(paramSpec)); + } + } + + public KeyPair generateKeyPair() + { + if (!initialised) + { + param = new SnovaKeyGenerationParameters(random, SnovaParameters.SNOVA_24_5_4_SSK); + + engine.init(param); + initialised = true; + } + + AsymmetricCipherKeyPair pair = engine.generateKeyPair(); + SnovaPublicKeyParameters pub = (SnovaPublicKeyParameters)pair.getPublic(); + SnovaPrivateKeyParameters priv = (SnovaPrivateKeyParameters)pair.getPrivate(); + + return new KeyPair(new BCSnovaPublicKey(pub), new BCSnovaPrivateKey(priv)); + } + + public static class SNOVA_24_5_4_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_24_5_4_SSK() + { + super(SnovaParameters.SNOVA_24_5_4_SSK); + } + } + + public static class SNOVA_24_5_4_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_24_5_4_ESK() + { + super(SnovaParameters.SNOVA_24_5_4_ESK); + } + } + + public static class SNOVA_24_5_4_SHAKE_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_24_5_4_SHAKE_SSK() + { + super(SnovaParameters.SNOVA_24_5_4_SHAKE_SSK); + } + } + + public static class SNOVA_24_5_4_SHAKE_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_24_5_4_SHAKE_ESK() + { + super(SnovaParameters.SNOVA_24_5_4_SHAKE_ESK); + } + } + + public static class SNOVA_24_5_5_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_24_5_5_SSK() + { + super(SnovaParameters.SNOVA_24_5_5_SSK); + } + } + + public static class SNOVA_24_5_5_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_24_5_5_ESK() + { + super(SnovaParameters.SNOVA_24_5_5_ESK); + } + } + + public static class SNOVA_24_5_5_SHAKE_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_24_5_5_SHAKE_SSK() + { + super(SnovaParameters.SNOVA_24_5_5_SHAKE_SSK); + } + } + + public static class SNOVA_24_5_5_SHAKE_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_24_5_5_SHAKE_ESK() + { + super(SnovaParameters.SNOVA_24_5_5_SHAKE_ESK); + } + } + + public static class SNOVA_25_8_3_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_25_8_3_SSK() + { + super(SnovaParameters.SNOVA_25_8_3_SSK); + } + } + + public static class SNOVA_25_8_3_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_25_8_3_ESK() + { + super(SnovaParameters.SNOVA_25_8_3_ESK); + } + } + + public static class SNOVA_25_8_3_SHAKE_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_25_8_3_SHAKE_SSK() + { + super(SnovaParameters.SNOVA_25_8_3_SHAKE_SSK); + } + } + + public static class SNOVA_25_8_3_SHAKE_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_25_8_3_SHAKE_ESK() + { + super(SnovaParameters.SNOVA_25_8_3_SHAKE_ESK); + } + } + + public static class SNOVA_29_6_5_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_29_6_5_SSK() + { + super(SnovaParameters.SNOVA_29_6_5_SSK); + } + } + + public static class SNOVA_29_6_5_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_29_6_5_ESK() + { + super(SnovaParameters.SNOVA_29_6_5_ESK); + } + } + + public static class SNOVA_29_6_5_SHAKE_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_29_6_5_SHAKE_SSK() + { + super(SnovaParameters.SNOVA_29_6_5_SHAKE_SSK); + } + } + + public static class SNOVA_29_6_5_SHAKE_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_29_6_5_SHAKE_ESK() + { + super(SnovaParameters.SNOVA_29_6_5_SHAKE_ESK); + } + } + + public static class SNOVA_37_8_4_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_37_8_4_SSK() + { + super(SnovaParameters.SNOVA_37_8_4_SSK); + } + } + + public static class SNOVA_37_8_4_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_37_8_4_ESK() + { + super(SnovaParameters.SNOVA_37_8_4_ESK); + } + } + + public static class SNOVA_37_8_4_SHAKE_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_37_8_4_SHAKE_SSK() + { + super(SnovaParameters.SNOVA_37_8_4_SHAKE_SSK); + } + } + + public static class SNOVA_37_8_4_SHAKE_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_37_8_4_SHAKE_ESK() + { + super(SnovaParameters.SNOVA_37_8_4_SHAKE_ESK); + } + } + + public static class SNOVA_37_17_2_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_37_17_2_SSK() + { + super(SnovaParameters.SNOVA_37_17_2_SSK); + } + } + + public static class SNOVA_37_17_2_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_37_17_2_ESK() + { + super(SnovaParameters.SNOVA_37_17_2_ESK); + } + } + + public static class SNOVA_37_17_2_SHAKE_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_37_17_2_SHAKE_SSK() + { + super(SnovaParameters.SNOVA_37_17_2_SHAKE_SSK); + } + } + + public static class SNOVA_37_17_2_SHAKE_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_37_17_2_SHAKE_ESK() + { + super(SnovaParameters.SNOVA_37_17_2_SHAKE_ESK); + } + } + + public static class SNOVA_49_11_3_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_49_11_3_SSK() + { + super(SnovaParameters.SNOVA_49_11_3_SSK); + } + } + + public static class SNOVA_49_11_3_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_49_11_3_ESK() + { + super(SnovaParameters.SNOVA_49_11_3_ESK); + } + } + + public static class SNOVA_49_11_3_SHAKE_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_49_11_3_SHAKE_SSK() + { + super(SnovaParameters.SNOVA_49_11_3_SHAKE_SSK); + } + } + + public static class SNOVA_49_11_3_SHAKE_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_49_11_3_SHAKE_ESK() + { + super(SnovaParameters.SNOVA_49_11_3_SHAKE_ESK); + } + } + + public static class SNOVA_56_25_2_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_56_25_2_SSK() + { + super(SnovaParameters.SNOVA_56_25_2_SSK); + } + } + + public static class SNOVA_56_25_2_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_56_25_2_ESK() + { + super(SnovaParameters.SNOVA_56_25_2_ESK); + } + } + + public static class SNOVA_56_25_2_SHAKE_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_56_25_2_SHAKE_SSK() + { + super(SnovaParameters.SNOVA_56_25_2_SHAKE_SSK); + } + } + + public static class SNOVA_56_25_2_SHAKE_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_56_25_2_SHAKE_ESK() + { + super(SnovaParameters.SNOVA_56_25_2_SHAKE_ESK); + } + } + + public static class SNOVA_60_10_4_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_60_10_4_SSK() + { + super(SnovaParameters.SNOVA_60_10_4_SSK); + } + } + + public static class SNOVA_60_10_4_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_60_10_4_ESK() + { + super(SnovaParameters.SNOVA_60_10_4_ESK); + } + } + + public static class SNOVA_60_10_4_SHAKE_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_60_10_4_SHAKE_SSK() + { + super(SnovaParameters.SNOVA_60_10_4_SHAKE_SSK); + } + } + + public static class SNOVA_60_10_4_SHAKE_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_60_10_4_SHAKE_ESK() + { + super(SnovaParameters.SNOVA_60_10_4_SHAKE_ESK); + } + } + + public static class SNOVA_66_15_3_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_66_15_3_SSK() + { + super(SnovaParameters.SNOVA_66_15_3_SSK); + } + } + + public static class SNOVA_66_15_3_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_66_15_3_ESK() + { + super(SnovaParameters.SNOVA_66_15_3_ESK); + } + } + + public static class SNOVA_66_15_3_SHAKE_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_66_15_3_SHAKE_SSK() + { + super(SnovaParameters.SNOVA_66_15_3_SHAKE_SSK); + } + } + + public static class SNOVA_66_15_3_SHAKE_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_66_15_3_SHAKE_ESK() + { + super(SnovaParameters.SNOVA_66_15_3_SHAKE_ESK); + } + } + + public static class SNOVA_75_33_2_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_75_33_2_SSK() + { + super(SnovaParameters.SNOVA_75_33_2_SSK); + } + } + + public static class SNOVA_75_33_2_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_75_33_2_ESK() + { + super(SnovaParameters.SNOVA_75_33_2_ESK); + } + } + + public static class SNOVA_75_33_2_SHAKE_SSK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_75_33_2_SHAKE_SSK() + { + super(SnovaParameters.SNOVA_75_33_2_SHAKE_SSK); + } + } + + public static class SNOVA_75_33_2_SHAKE_ESK + extends SnovaKeyPairGeneratorSpi + { + public SNOVA_75_33_2_SHAKE_ESK() + { + super(SnovaParameters.SNOVA_75_33_2_SHAKE_ESK); + } + } +} + diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincsplus/SPHINCSPlusKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincsplus/SPHINCSPlusKeyPairGeneratorSpi.java index 286e6b45cd..d26ce391f8 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincsplus/SPHINCSPlusKeyPairGeneratorSpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/sphincsplus/SPHINCSPlusKeyPairGeneratorSpi.java @@ -9,12 +9,12 @@ import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.CryptoServicesRegistrar; +import org.bouncycastle.jcajce.util.SpecUtil; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusKeyGenerationParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusKeyPairGenerator; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusPrivateKeyParameters; import org.bouncycastle.pqc.crypto.sphincsplus.SPHINCSPlusPublicKeyParameters; -import org.bouncycastle.pqc.jcajce.provider.util.SpecUtil; import org.bouncycastle.pqc.jcajce.spec.SPHINCSPlusParameterSpec; import org.bouncycastle.util.Strings; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/BaseKeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/BaseKeyFactorySpi.java index 52433bc59b..2a64e117e3 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/BaseKeyFactorySpi.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/BaseKeyFactorySpi.java @@ -53,6 +53,10 @@ public PrivateKey engineGeneratePrivate(KeySpec keySpec) { throw e; } + catch (IllegalStateException e) + { + throw new InvalidKeySpecException(e.getMessage()); + } catch (Exception e) { throw new InvalidKeySpecException(e.toString()); diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/KdfUtil.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/KdfUtil.java index f3c30e7163..56ec3ba431 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/KdfUtil.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/KdfUtil.java @@ -34,7 +34,7 @@ public class KdfUtil */ public static byte[] makeKeyBytes(KEMKDFSpec kdfSpec, byte[] secret) { - byte[] keyBytes = null; + byte[] keyBytes; try { if (kdfSpec == null) @@ -42,8 +42,11 @@ public static byte[] makeKeyBytes(KEMKDFSpec kdfSpec, byte[] secret) keyBytes = new byte[secret.length]; System.arraycopy(secret, 0, keyBytes, 0, keyBytes.length); } - - keyBytes = makeKeyBytes(kdfSpec.getKdfAlgorithm(), secret, kdfSpec.getOtherInfo(), kdfSpec.getKeySize()); + else + { + keyBytes = makeKeyBytes(kdfSpec.getKdfAlgorithm(), secret, kdfSpec.getOtherInfo(), + kdfSpec.getKeySize()); + } } finally { diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/SpecUtil.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/SpecUtil.java index d313cf96b1..841e83bdea 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/SpecUtil.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/SpecUtil.java @@ -5,6 +5,10 @@ import java.security.PrivilegedAction; import java.security.spec.AlgorithmParameterSpec; +/** + * @deprecated use org.bouncycastle.jcajce.util.SpecUtil + */ +@Deprecated public class SpecUtil { private static Class[] NO_PARAMS = new Class[0]; diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/WrapUtil.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/WrapUtil.java index 7d1f11900b..5a99f1cd7d 100644 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/WrapUtil.java +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/util/WrapUtil.java @@ -55,10 +55,10 @@ public static Wrapper getKeyUnwrapper(KTSParameterSpec ktsParameterSpec, byte[] public static Wrapper getWrapper(String keyAlgorithmName) { Wrapper kWrap; - + if (keyAlgorithmName.equalsIgnoreCase("AESWRAP") || keyAlgorithmName.equalsIgnoreCase("AES")) { - kWrap = new RFC3394WrapEngine(new AESEngine()); + kWrap = new RFC3394WrapEngine(AESEngine.newInstance()); } else if (keyAlgorithmName.equalsIgnoreCase("ARIA")) { @@ -91,6 +91,16 @@ else if (keyAlgorithmName.equalsIgnoreCase("ARIA-KWP")) return kWrap; } + public static byte[] trimSecret(String algName, byte[] secret) + { + if (algName.equals("SEED")) + { + return Arrays.copyOfRange(secret, 0, 16); + } + + return secret; + } + private static byte[] makeKeyBytes(KTSParameterSpec ktsSpec, byte[] secret) throws InvalidKeyException { diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/MayoParameterSpec.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/MayoParameterSpec.java new file mode 100644 index 0000000000..9f3ee3e061 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/MayoParameterSpec.java @@ -0,0 +1,48 @@ +package org.bouncycastle.pqc.jcajce.spec; + +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.pqc.crypto.mayo.MayoParameters; +import org.bouncycastle.util.Strings; + +public class MayoParameterSpec + implements AlgorithmParameterSpec +{ + public static final MayoParameterSpec mayo1 = new MayoParameterSpec(MayoParameters.mayo1); + public static final MayoParameterSpec mayo2 = new MayoParameterSpec(MayoParameters.mayo2); + public static final MayoParameterSpec mayo3 = new MayoParameterSpec(MayoParameters.mayo3); + public static final MayoParameterSpec mayo5 = new MayoParameterSpec(MayoParameters.mayo5); + + private static Map parameters = new HashMap(); + + static + { +// parameters.put("mayo1", mayo1); +// parameters.put("mayo2", mayo2); +// parameters.put("mayo3", mayo3); +// parameters.put("mayo5", mayo5); + parameters.put("MAYO_1", mayo1); + parameters.put("MAYO_2", mayo2); + parameters.put("MAYO_3", mayo3); + parameters.put("MAYO_5", mayo5); + } + + private final String name; + + private MayoParameterSpec(MayoParameters parameters) + { + this.name = parameters.getName(); + } + + public String getName() + { + return name; + } + + public static MayoParameterSpec fromName(String name) + { + return (MayoParameterSpec)parameters.get(Strings.toLowerCase(name)); + } +} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2KeyGenParameterSpec.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2KeyGenParameterSpec.java deleted file mode 100644 index a2b801fcb7..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceCCA2KeyGenParameterSpec.java +++ /dev/null @@ -1,219 +0,0 @@ -package org.bouncycastle.pqc.jcajce.spec; - -import java.security.InvalidParameterException; -import java.security.spec.AlgorithmParameterSpec; - -import org.bouncycastle.pqc.legacy.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 keysize < 1. - */ - 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 m < 1 or m > 32 or - * t < 0 or t > n. - */ - 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 m < 1 or m > 32 or - * t < 0 or t > n or - * poly 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/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceKeyGenParameterSpec.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceKeyGenParameterSpec.java deleted file mode 100644 index 4baa518349..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/McElieceKeyGenParameterSpec.java +++ /dev/null @@ -1,186 +0,0 @@ -package org.bouncycastle.pqc.jcajce.spec; - -import java.security.InvalidParameterException; -import java.security.spec.AlgorithmParameterSpec; - -import org.bouncycastle.pqc.legacy.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 McElieceKeyGenParameterSpec - implements AlgorithmParameterSpec -{ - - /** - * 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 int m; - - /** - * error correction capability of the code - */ - private int t; - - /** - * length of the code - */ - private int n; - - /** - * the field polynomial - */ - private int fieldPoly; - - /** - * Constructor. Set the default parameters: extension degree. - */ - public McElieceKeyGenParameterSpec() - { - this(DEFAULT_M, DEFAULT_T); - } - - /** - * Constructor. - * - * @param keysize the length of a Goppa code - * @throws IllegalArgumentException if keysize < 1. - */ - public McElieceKeyGenParameterSpec(int keysize) - { - if (keysize < 1) - { - throw new IllegalArgumentException("key size must be positive"); - } - m = 0; - n = 1; - while (n < keysize) - { - n <<= 1; - m++; - } - t = n >>> 1; - t /= m; - fieldPoly = PolynomialRingGF2.getIrreduciblePolynomial(m); - } - - /** - * Constructor. - * - * @param m degree of the finite field GF(2^m) - * @param t error correction capability of the code - * @throws InvalidParameterException if m < 1 or m > 32 or - * t < 0 or t > n. - */ - public McElieceKeyGenParameterSpec(int m, int t) - throws InvalidParameterException - { - 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); - } - - /** - * 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 m < 1 or m > 32 or - * t < 0 or t > n or - * poly is not an irreducible field polynomial. - */ - public McElieceKeyGenParameterSpec(int m, int t, int poly) - { - 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)"); - } - } - - /** - * @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; - } - -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/NTRUPlusParameterSpec.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/NTRUPlusParameterSpec.java new file mode 100644 index 0000000000..cb8c8e23ad --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/NTRUPlusParameterSpec.java @@ -0,0 +1,42 @@ +package org.bouncycastle.pqc.jcajce.spec; + +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.pqc.crypto.ntruplus.NTRUPlusParameters; +import org.bouncycastle.util.Strings; + +public class NTRUPlusParameterSpec + implements AlgorithmParameterSpec +{ + public static final NTRUPlusParameterSpec ntruplus_768 = new NTRUPlusParameterSpec(NTRUPlusParameters.ntruplus_kem_768); + public static final NTRUPlusParameterSpec ntruplus_864 = new NTRUPlusParameterSpec(NTRUPlusParameters.ntruplus_kem_864); + public static final NTRUPlusParameterSpec ntruplus_1152 = new NTRUPlusParameterSpec(NTRUPlusParameters.ntruplus_kem_1152); + + private static Map parameters = new HashMap(); + + static + { + parameters.put("ntruplus-768", ntruplus_768); + parameters.put("ntruplus-864", ntruplus_864); + parameters.put("ntruplus-864", ntruplus_864); + } + + private final String name; + + private NTRUPlusParameterSpec(NTRUPlusParameters parameters) + { + this.name = Strings.toUpperCase(parameters.getName()); + } + + public String getName() + { + return name; + } + + public static NTRUPlusParameterSpec fromName(String name) + { + return (NTRUPlusParameterSpec)parameters.get(Strings.toLowerCase(name)); + } +} \ No newline at end of file diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/QTESLAParameterSpec.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/QTESLAParameterSpec.java deleted file mode 100644 index 0f1d24895e..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/QTESLAParameterSpec.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.bouncycastle.pqc.jcajce.spec; - -import java.security.spec.AlgorithmParameterSpec; - -import org.bouncycastle.pqc.legacy.crypto.qtesla.QTESLASecurityCategory; - -/** - * qTESLA parameter details. These are divided up on the basis of the security categories for each - * individual parameter set. - */ -public class QTESLAParameterSpec - implements AlgorithmParameterSpec -{ - /** - * Available security categories. - */ - public static final String PROVABLY_SECURE_I = QTESLASecurityCategory.getName(QTESLASecurityCategory.PROVABLY_SECURE_I); - public static final String PROVABLY_SECURE_III = QTESLASecurityCategory.getName(QTESLASecurityCategory.PROVABLY_SECURE_III); - - private String securityCategory; - - /** - * Base constructor. - * - * @param securityCategory the security category we want this parameterSpec to match. - */ - public QTESLAParameterSpec(String securityCategory) - { - this.securityCategory = securityCategory; - } - - /** - * Return the security category. - * - * @return the security category. - */ - public String getSecurityCategory() - { - return securityCategory; - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/RainbowParameterSpec.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/RainbowParameterSpec.java deleted file mode 100644 index b1efc87996..0000000000 --- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/RainbowParameterSpec.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.bouncycastle.pqc.jcajce.spec; - -import java.security.spec.AlgorithmParameterSpec; -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.pqc.crypto.crystals.dilithium.DilithiumParameters; -import org.bouncycastle.pqc.crypto.rainbow.RainbowParameters; -import org.bouncycastle.util.Strings; - -public class RainbowParameterSpec - implements AlgorithmParameterSpec -{ - public static final RainbowParameterSpec rainbowIIIclassic = new RainbowParameterSpec(RainbowParameters.rainbowIIIclassic); - public static final RainbowParameterSpec rainbowIIIcircumzenithal = new RainbowParameterSpec(RainbowParameters.rainbowIIIcircumzenithal); - public static final RainbowParameterSpec rainbowIIIcompressed = new RainbowParameterSpec(RainbowParameters.rainbowIIIcompressed); - - public static final RainbowParameterSpec rainbowVclassic = new RainbowParameterSpec(RainbowParameters.rainbowVclassic); - public static final RainbowParameterSpec rainbowVcircumzenithal = new RainbowParameterSpec(RainbowParameters.rainbowVcircumzenithal); - public static final RainbowParameterSpec rainbowVcompressed = new RainbowParameterSpec(RainbowParameters.rainbowVcompressed); - - private static Map parameters = new HashMap(); - - static - { - parameters.put("rainbow-iii-classic", rainbowIIIclassic); - parameters.put("rainbow-iii-circumzenithal", rainbowIIIcircumzenithal); - parameters.put("rainbow-iii-compressed", rainbowIIIcompressed); - parameters.put("rainbow-v-classic", rainbowVclassic); - parameters.put("rainbow-v-circumzenithal", rainbowVcircumzenithal); - parameters.put("rainbow-v-compressed", rainbowVcompressed); - } - - private final String name; - - private RainbowParameterSpec(RainbowParameters parameters) - { - this.name = Strings.toUpperCase(parameters.getName()); - } - - public String getName() - { - return name; - } - - public static RainbowParameterSpec fromName(String name) - { - return (RainbowParameterSpec)parameters.get(Strings.toLowerCase(name)); - } -} diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/SnovaParameterSpec.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/SnovaParameterSpec.java new file mode 100644 index 0000000000..2e72629f24 --- /dev/null +++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/SnovaParameterSpec.java @@ -0,0 +1,145 @@ +package org.bouncycastle.pqc.jcajce.spec; + +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; +import java.util.Map; + +import org.bouncycastle.pqc.crypto.snova.SnovaParameters; +import org.bouncycastle.util.Strings; + +public class SnovaParameterSpec + implements AlgorithmParameterSpec +{ + public static final SnovaParameterSpec SNOVA_24_5_4_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_24_5_4_SSK); + public static final SnovaParameterSpec SNOVA_24_5_4_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_24_5_4_ESK); + public static final SnovaParameterSpec SNOVA_24_5_4_SHAKE_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_24_5_4_SHAKE_SSK); + public static final SnovaParameterSpec SNOVA_24_5_4_SHAKE_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_24_5_4_SHAKE_ESK); + + public static final SnovaParameterSpec SNOVA_24_5_5_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_24_5_5_SSK); + public static final SnovaParameterSpec SNOVA_24_5_5_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_24_5_5_ESK); + public static final SnovaParameterSpec SNOVA_24_5_5_SHAKE_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_24_5_5_SHAKE_SSK); + public static final SnovaParameterSpec SNOVA_24_5_5_SHAKE_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_24_5_5_SHAKE_ESK); + + public static final SnovaParameterSpec SNOVA_25_8_3_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_25_8_3_SSK); + public static final SnovaParameterSpec SNOVA_25_8_3_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_25_8_3_ESK); + public static final SnovaParameterSpec SNOVA_25_8_3_SHAKE_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_25_8_3_SHAKE_SSK); + public static final SnovaParameterSpec SNOVA_25_8_3_SHAKE_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_25_8_3_SHAKE_ESK); + + public static final SnovaParameterSpec SNOVA_29_6_5_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_29_6_5_SSK); + public static final SnovaParameterSpec SNOVA_29_6_5_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_29_6_5_ESK); + public static final SnovaParameterSpec SNOVA_29_6_5_SHAKE_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_29_6_5_SHAKE_SSK); + public static final SnovaParameterSpec SNOVA_29_6_5_SHAKE_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_29_6_5_SHAKE_ESK); + + public static final SnovaParameterSpec SNOVA_37_8_4_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_37_8_4_SSK); + public static final SnovaParameterSpec SNOVA_37_8_4_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_37_8_4_ESK); + public static final SnovaParameterSpec SNOVA_37_8_4_SHAKE_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_37_8_4_SHAKE_SSK); + public static final SnovaParameterSpec SNOVA_37_8_4_SHAKE_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_37_8_4_SHAKE_ESK); + + public static final SnovaParameterSpec SNOVA_37_17_2_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_37_17_2_SSK); + public static final SnovaParameterSpec SNOVA_37_17_2_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_37_17_2_ESK); + public static final SnovaParameterSpec SNOVA_37_17_2_SHAKE_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_37_17_2_SHAKE_SSK); + public static final SnovaParameterSpec SNOVA_37_17_2_SHAKE_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_37_17_2_SHAKE_ESK); + + public static final SnovaParameterSpec SNOVA_49_11_3_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_49_11_3_SSK); + public static final SnovaParameterSpec SNOVA_49_11_3_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_49_11_3_ESK); + public static final SnovaParameterSpec SNOVA_49_11_3_SHAKE_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_49_11_3_SHAKE_SSK); + public static final SnovaParameterSpec SNOVA_49_11_3_SHAKE_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_49_11_3_SHAKE_ESK); + + public static final SnovaParameterSpec SNOVA_56_25_2_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_56_25_2_SSK); + public static final SnovaParameterSpec SNOVA_56_25_2_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_56_25_2_ESK); + public static final SnovaParameterSpec SNOVA_56_25_2_SHAKE_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_56_25_2_SHAKE_SSK); + public static final SnovaParameterSpec SNOVA_56_25_2_SHAKE_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_56_25_2_SHAKE_ESK); + + public static final SnovaParameterSpec SNOVA_60_10_4_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_60_10_4_SSK); + public static final SnovaParameterSpec SNOVA_60_10_4_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_60_10_4_ESK); + public static final SnovaParameterSpec SNOVA_60_10_4_SHAKE_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_60_10_4_SHAKE_SSK); + public static final SnovaParameterSpec SNOVA_60_10_4_SHAKE_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_60_10_4_SHAKE_ESK); + + public static final SnovaParameterSpec SNOVA_66_15_3_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_66_15_3_SSK); + public static final SnovaParameterSpec SNOVA_66_15_3_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_66_15_3_ESK); + public static final SnovaParameterSpec SNOVA_66_15_3_SHAKE_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_66_15_3_SHAKE_SSK); + public static final SnovaParameterSpec SNOVA_66_15_3_SHAKE_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_66_15_3_SHAKE_ESK); + + public static final SnovaParameterSpec SNOVA_75_33_2_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_75_33_2_SSK); + public static final SnovaParameterSpec SNOVA_75_33_2_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_75_33_2_ESK); + public static final SnovaParameterSpec SNOVA_75_33_2_SHAKE_SSK = new SnovaParameterSpec(SnovaParameters.SNOVA_75_33_2_SHAKE_SSK); + public static final SnovaParameterSpec SNOVA_75_33_2_SHAKE_ESK = new SnovaParameterSpec(SnovaParameters.SNOVA_75_33_2_SHAKE_ESK); + + + private static Map parameters = new HashMap(); + + static + { + parameters.put("SNOVA_24_5_4_SSK", SNOVA_24_5_4_SSK); + parameters.put("SNOVA_24_5_4_ESK", SNOVA_24_5_4_ESK); + parameters.put("SNOVA_24_5_4_SHAKE_SSK", SNOVA_24_5_4_SHAKE_SSK); + parameters.put("SNOVA_24_5_4_SHAKE_ESK", SNOVA_24_5_4_SHAKE_ESK); + + parameters.put("SNOVA_24_5_5_SSK", SNOVA_24_5_5_SSK); + parameters.put("SNOVA_24_5_5_ESK", SNOVA_24_5_5_ESK); + parameters.put("SNOVA_24_5_5_SHAKE_SSK", SNOVA_24_5_5_SHAKE_SSK); + parameters.put("SNOVA_24_5_5_SHAKE_ESK", SNOVA_24_5_5_SHAKE_ESK); + + parameters.put("SNOVA_25_8_3_SSK", SNOVA_25_8_3_SSK); + parameters.put("SNOVA_25_8_3_ESK", SNOVA_25_8_3_ESK); + parameters.put("SNOVA_25_8_3_SHAKE_SSK", SNOVA_25_8_3_SHAKE_SSK); + parameters.put("SNOVA_25_8_3_SHAKE_ESK", SNOVA_25_8_3_SHAKE_ESK); + + parameters.put("SNOVA_29_6_5_SSK", SNOVA_29_6_5_SSK); + parameters.put("SNOVA_29_6_5_ESK", SNOVA_29_6_5_ESK); + parameters.put("SNOVA_29_6_5_SHAKE_SSK", SNOVA_29_6_5_SHAKE_SSK); + parameters.put("SNOVA_29_6_5_SHAKE_ESK", SNOVA_29_6_5_SHAKE_ESK); + + parameters.put("SNOVA_37_8_4_SSK", SNOVA_37_8_4_SSK); + parameters.put("SNOVA_37_8_4_ESK", SNOVA_37_8_4_ESK); + parameters.put("SNOVA_37_8_4_SHAKE_SSK", SNOVA_37_8_4_SHAKE_SSK); + parameters.put("SNOVA_37_8_4_SHAKE_ESK", SNOVA_37_8_4_SHAKE_ESK); + + parameters.put("SNOVA_37_17_2_SSK", SNOVA_37_17_2_SSK); + parameters.put("SNOVA_37_17_2_ESK", SNOVA_37_17_2_ESK); + parameters.put("SNOVA_37_17_2_SHAKE_SSK", SNOVA_37_17_2_SHAKE_SSK); + parameters.put("SNOVA_37_17_2_SHAKE_ESK", SNOVA_37_17_2_SHAKE_ESK); + + parameters.put("SNOVA_49_11_3_SSK", SNOVA_49_11_3_SSK); + parameters.put("SNOVA_49_11_3_ESK", SNOVA_49_11_3_ESK); + parameters.put("SNOVA_49_11_3_SHAKE_SSK", SNOVA_49_11_3_SHAKE_SSK); + parameters.put("SNOVA_49_11_3_SHAKE_ESK", SNOVA_49_11_3_SHAKE_ESK); + + parameters.put("SNOVA_56_25_2_SSK", SNOVA_56_25_2_SSK); + parameters.put("SNOVA_56_25_2_ESK", SNOVA_56_25_2_ESK); + parameters.put("SNOVA_56_25_2_SHAKE_SSK", SNOVA_56_25_2_SHAKE_SSK); + parameters.put("SNOVA_56_25_2_SHAKE_ESK", SNOVA_56_25_2_SHAKE_ESK); + + parameters.put("SNOVA_60_10_4_SSK", SNOVA_60_10_4_SSK); + parameters.put("SNOVA_60_10_4_ESK", SNOVA_60_10_4_ESK); + parameters.put("SNOVA_60_10_4_SHAKE_SSK", SNOVA_60_10_4_SHAKE_SSK); + parameters.put("SNOVA_60_10_4_SHAKE_ESK", SNOVA_60_10_4_SHAKE_ESK); + + parameters.put("SNOVA_66_15_3_SSK", SNOVA_66_15_3_SSK); + parameters.put("SNOVA_66_15_3_ESK", SNOVA_66_15_3_ESK); + parameters.put("SNOVA_66_15_3_SHAKE_SSK", SNOVA_66_15_3_SHAKE_SSK); + parameters.put("SNOVA_66_15_3_SHAKE_ESK", SNOVA_66_15_3_SHAKE_ESK); + + parameters.put("SNOVA_75_33_2_SSK", SNOVA_75_33_2_SSK); + parameters.put("SNOVA_75_33_2_ESK", SNOVA_75_33_2_ESK); + parameters.put("SNOVA_75_33_2_SHAKE_SSK", SNOVA_75_33_2_SHAKE_SSK); + parameters.put("SNOVA_75_33_2_SHAKE_ESK", SNOVA_75_33_2_SHAKE_ESK); + } + + private final String name; + + private SnovaParameterSpec(SnovaParameters parameters) + { + this.name = parameters.getName(); + } + + public String getName() + { + return name; + } + + public static SnovaParameterSpec fromName(String name) + { + return (SnovaParameterSpec)parameters.get(Strings.toLowerCase(name)); + } +} diff --git a/prov/src/main/java/org/bouncycastle/x509/PKIXCRLUtil.java b/prov/src/main/java/org/bouncycastle/x509/PKIXCRLUtil.java index ebabf5693d..baec352c2b 100644 --- a/prov/src/main/java/org/bouncycastle/x509/PKIXCRLUtil.java +++ b/prov/src/main/java/org/bouncycastle/x509/PKIXCRLUtil.java @@ -43,7 +43,7 @@ static Set findCRLs(X509CRLStoreSelector crlselect, PKIXParameters paramsPKIX) * a List containing only {@link org.bouncycastle.x509.X509Store X509Store} objects. * These are used to search for CRLs */ - private static void findCRLs(HashSet crls, X509CRLStoreSelector crlSelect, List crlStores) throws AnnotatedException + private static void findCRLs(Set crls, X509CRLStoreSelector crlSelect, List crlStores) throws AnnotatedException { AnnotatedException lastException = null; boolean foundValidStore = false; diff --git a/prov/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java b/prov/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java index d8d090f066..7efa89f1f7 100644 --- a/prov/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java +++ b/prov/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java @@ -38,6 +38,7 @@ import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1Enumerated; import org.bouncycastle.asn1.ASN1IA5String; import org.bouncycastle.asn1.ASN1InputStream; @@ -47,7 +48,6 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.x509.AccessDescription; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.AuthorityInformationAccess; @@ -852,11 +852,11 @@ else if (isSelfIssued(cert)) { ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.NoIssuerPublicKey"); // if there is an authority key extension add the serial and issuer of the missing certificate - byte[] akiBytes = cert.getExtensionValue(Extension.authorityKeyIdentifier.getId()); - if (akiBytes != null) + byte[] akiExtValue = cert.getExtensionValue(Extension.authorityKeyIdentifier.getId()); + if (akiExtValue != null) { AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance( - DEROctetString.getInstance(akiBytes).getOctets()); + ASN1OctetString.getInstance(akiExtValue).getOctets()); GeneralNames issuerNames = aki.getAuthorityCertIssuer(); if (issuerNames != null) { @@ -1952,7 +1952,7 @@ private String IPtoString(byte[] ip) } catch (Exception e) { - StringBuffer b = new StringBuffer(); + StringBuilder b = new StringBuilder(); for (int i = 0; i != ip.length; i++) { @@ -2435,25 +2435,25 @@ protected Collection getTrustAnchors(X509Certificate cert, Set trustanchors) thr try { certSelectX509.setSubject(getEncodedIssuerPrincipal(cert).getEncoded()); - byte[] ext = cert.getExtensionValue(Extension.authorityKeyIdentifier.getId()); - if (ext != null) + byte[] akiExtValue = cert.getExtensionValue(Extension.authorityKeyIdentifier.getId()); + if (akiExtValue != null) { - ASN1OctetString oct = (ASN1OctetString)ASN1Primitive.fromByteArray(ext); - AuthorityKeyIdentifier authID = AuthorityKeyIdentifier.getInstance(ASN1Primitive.fromByteArray(oct.getOctets())); + AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance( + ASN1OctetString.getInstance(akiExtValue).getOctets()); // we ignore key identifier as if set, selector expects parent to have subjectKeyID - BigInteger serial = authID.getAuthorityCertSerialNumber(); + BigInteger serial = aki.getAuthorityCertSerialNumber(); if (serial != null) { - certSelectX509.setSerialNumber(authID.getAuthorityCertSerialNumber()); + certSelectX509.setSerialNumber(aki.getAuthorityCertSerialNumber()); } else { - byte[] keyID = authID.getKeyIdentifier(); - if (keyID != null) + ASN1OctetString keyIdentifier = aki.getKeyIdentifierObject(); + if (keyIdentifier != null) { - certSelectX509.setSubjectKeyIdentifier(new DEROctetString(keyID).getEncoded()); + certSelectX509.setSubjectKeyIdentifier(keyIdentifier.getEncoded(ASN1Encoding.DER)); } } } diff --git a/prov/src/main/java/org/bouncycastle/x509/X509CollectionStoreParameters.java b/prov/src/main/java/org/bouncycastle/x509/X509CollectionStoreParameters.java index 16420fed09..92b546ec1a 100644 --- a/prov/src/main/java/org/bouncycastle/x509/X509CollectionStoreParameters.java +++ b/prov/src/main/java/org/bouncycastle/x509/X509CollectionStoreParameters.java @@ -61,7 +61,7 @@ public Collection getCollection() */ public String toString() { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append("X509CollectionStoreParameters: [\n"); sb.append(" collection: " + collection + "\n"); sb.append("]"); diff --git a/prov/src/main/java/org/bouncycastle/x509/X509Util.java b/prov/src/main/java/org/bouncycastle/x509/X509Util.java index 2be58a87f6..dc8d44303a 100644 --- a/prov/src/main/java/org/bouncycastle/x509/X509Util.java +++ b/prov/src/main/java/org/bouncycastle/x509/X509Util.java @@ -133,8 +133,8 @@ private static RSASSAPSSparams creatPSSParams(AlgorithmIdentifier hashAlgId, int return new RSASSAPSSparams( hashAlgId, new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, hashAlgId), - new ASN1Integer(saltSize), - new ASN1Integer(1)); + ASN1Integer.valueOf(saltSize), + RSASSAPSSparams.DEFAULT_TRAILER_FIELD); } static ASN1ObjectIdentifier getAlgorithmOID( diff --git a/prov/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java b/prov/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java index 8eb5e983af..9ef019376b 100644 --- a/prov/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java +++ b/prov/src/main/java/org/bouncycastle/x509/X509V2AttributeCertificate.java @@ -265,12 +265,12 @@ public Set getCriticalExtensionOIDs() { return getExtensionOIDs(true); } - + public boolean hasUnsupportedCriticalExtension() { - Set extensions = getCriticalExtensionOIDs(); + Extensions extensions = cert.getAcinfo().getExtensions(); - return extensions != null && !extensions.isEmpty(); + return extensions != null && extensions.hasAnyCriticalExtensions(); } public X509Attribute[] getAttributes() diff --git a/prov/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java b/prov/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java index bcd5993264..b629286e46 100644 --- a/prov/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java +++ b/prov/src/main/java/org/bouncycastle/x509/extension/AuthorityKeyIdentifierStructure.java @@ -1,6 +1,7 @@ package org.bouncycastle.x509.extension; import java.io.IOException; +import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.PublicKey; import java.security.cert.CertificateParsingException; @@ -59,48 +60,36 @@ public AuthorityKeyIdentifierStructure( super((ASN1Sequence)extension.getParsedValue()); } - private static ASN1Sequence fromCertificate( - X509Certificate certificate) + private static ASN1Sequence fromCertificate(X509Certificate certificate) throws CertificateParsingException { try { - if (certificate.getVersion() != 3) - { - GeneralName genName = new GeneralName(PrincipalUtil.getIssuerX509Principal(certificate)); - SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(certificate.getPublicKey().getEncoded()); - - return (ASN1Sequence)new AuthorityKeyIdentifier( - info, new GeneralNames(genName), certificate.getSerialNumber()).toASN1Primitive(); - } - else + GeneralName genName = new GeneralName(PrincipalUtil.getIssuerX509Principal(certificate)); + GeneralNames genNames = new GeneralNames(genName); + BigInteger serialNumber = certificate.getSerialNumber(); + + if (certificate.getVersion() == 3) { - GeneralName genName = new GeneralName(PrincipalUtil.getIssuerX509Principal(certificate)); - - byte[] ext = certificate.getExtensionValue(Extension.subjectKeyIdentifier.getId()); - + byte[] ext = certificate.getExtensionValue(Extension.subjectKeyIdentifier.getId()); if (ext != null) { - ASN1OctetString str = (ASN1OctetString)X509ExtensionUtil.fromExtensionValue(ext); - - return (ASN1Sequence)new AuthorityKeyIdentifier( - str.getOctets(), new GeneralNames(genName), certificate.getSerialNumber()).toASN1Primitive(); - } - else - { - SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(certificate.getPublicKey().getEncoded()); - - return (ASN1Sequence)new AuthorityKeyIdentifier( - info, new GeneralNames(genName), certificate.getSerialNumber()).toASN1Primitive(); + ASN1OctetString str = (ASN1OctetString)X509ExtensionUtil.fromExtensionValue(ext); + return (ASN1Sequence)new AuthorityKeyIdentifier(str.getOctets(), genNames, serialNumber) + .toASN1Primitive(); } } + + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(certificate.getPublicKey().getEncoded()); + + return (ASN1Sequence)new AuthorityKeyIdentifier(info, genNames, serialNumber).toASN1Primitive(); } catch (Exception e) { throw new CertificateParsingException("Exception extracting certificate details: " + e.toString()); } } - + private static ASN1Sequence fromKey( PublicKey pubKey) throws InvalidKeyException diff --git a/prov/src/main/java/org/bouncycastle/x509/util/LDAPStoreHelper.java b/prov/src/main/java/org/bouncycastle/x509/util/LDAPStoreHelper.java index 8121a498ed..e1af28594a 100644 --- a/prov/src/main/java/org/bouncycastle/x509/util/LDAPStoreHelper.java +++ b/prov/src/main/java/org/bouncycastle/x509/util/LDAPStoreHelper.java @@ -35,6 +35,7 @@ import org.bouncycastle.jce.provider.X509CRLParser; import org.bouncycastle.jce.provider.X509CertPairParser; import org.bouncycastle.jce.provider.X509CertParser; +import org.bouncycastle.ldap.LDAPUtils; import org.bouncycastle.util.StoreException; import org.bouncycastle.util.Strings; import org.bouncycastle.x509.X509AttributeCertStoreSelector; @@ -65,7 +66,6 @@ */ public class LDAPStoreHelper { - // TODO: cache results private X509LDAPCertStoreParameters params; @@ -95,7 +95,8 @@ public LDAPStoreHelper(X509LDAPCertStoreParameters params) */ private static final String URL_CONTEXT_PREFIX = "com.sun.jndi.url"; - private DirContext connectLDAP() throws NamingException + private DirContext connectLDAP() + throws NamingException { Properties props = new Properties(); props.setProperty(Context.INITIAL_CONTEXT_FACTORY, LDAP_PROVIDER); @@ -111,47 +112,6 @@ private DirContext connectLDAP() throws NamingException return ctx; } - private String parseDN(String subject, String dNAttributeName) - { - String temp = subject; - int begin = Strings.toLowerCase(temp).indexOf( - Strings.toLowerCase(dNAttributeName) + "="); - if (begin == -1) - { - return ""; - } - temp = temp.substring(begin + dNAttributeName.length()); - int end = temp.indexOf(','); - if (end == -1) - { - end = temp.length(); - } - while (temp.charAt(end - 1) == '\\') - { - end = temp.indexOf(',', end + 1); - if (end == -1) - { - end = temp.length(); - } - } - temp = temp.substring(0, end); - begin = temp.indexOf('='); - temp = temp.substring(begin + 1); - if (temp.charAt(0) == ' ') - { - temp = temp.substring(1); - } - if (temp.startsWith("\"")) - { - temp = temp.substring(1); - } - if (temp.endsWith("\"")) - { - temp = temp.substring(0, temp.length() - 1); - } - return temp; - } - private Set createCerts(List list, X509CertStoreSelector xselector) throws StoreException { @@ -224,7 +184,7 @@ private List certSubjectSerialSearch(X509CertStoreSelector xselector, { for (int i = 0; i < subjectAttributeNames.length; i++) { - attrValue = parseDN(subject, subjectAttributeNames[i]); + attrValue = LDAPUtils.parseDN(subject, subjectAttributeNames[i]); list .addAll(search(attrNames, "*" + attrValue + "*", attrs)); @@ -235,7 +195,7 @@ private List certSubjectSerialSearch(X509CertStoreSelector xselector, attrValue = serial; list.addAll(search( splitString(params.getSearchForSerialNumberIn()), - attrValue, attrs)); + attrValue, attrs)); } if (serial == null && subject == null) { @@ -246,7 +206,6 @@ private List certSubjectSerialSearch(X509CertStoreSelector xselector, } - /** * Can use the subject of the forward certificate of the set certificate * pair or the subject of the forward @@ -290,7 +249,7 @@ private List crossCertificatePairSubjectSearch( { for (int i = 0; i < subjectAttributeNames.length; i++) { - attrValue = parseDN(subject, subjectAttributeNames[i]); + attrValue = LDAPUtils.parseDN(subject, subjectAttributeNames[i]); list .addAll(search(attrNames, "*" + attrValue + "*", attrs)); @@ -385,7 +344,7 @@ private List attrCertSubjectSerialSearch( { for (int i = 0; i < subjectAttributeNames.length; i++) { - attrValue = parseDN(subject, subjectAttributeNames[i]); + attrValue = LDAPUtils.parseDN(subject, subjectAttributeNames[i]); list .addAll(search(attrNames, "*" + attrValue + "*", attrs)); @@ -441,11 +400,11 @@ private List cRLIssuerSearch(X509CRLStoreSelector xselector, if (xselector.getAttrCertificateChecking() != null) { Principal principals[] = xselector.getAttrCertificateChecking().getIssuer().getPrincipals(); - for (int i=0; i + * * @param selector The CRL selector to use to find the CRLs. * @return A possible empty collection with CRLs. * @throws StoreException */ public Collection getAttributeCertificateRevocationLists( - X509CRLStoreSelector selector) throws StoreException + X509CRLStoreSelector selector) + throws StoreException { String[] attrs = splitString(params .getAttributeCertificateRevocationListAttribute()); @@ -754,12 +718,14 @@ public Collection getAttributeCertificateRevocationLists( * The attributeAuthorityList holds a list of AA certificates that have been * revoked. *

    + * * @param selector The CRL selector to use to find the CRLs. * @return A possible empty collection with CRLs * @throws StoreException */ public Collection getAttributeAuthorityRevocationLists( - X509CRLStoreSelector selector) throws StoreException + X509CRLStoreSelector selector) + throws StoreException { String[] attrs = splitString(params.getAttributeAuthorityRevocationListAttribute()); String attrNames[] = splitString(params @@ -789,7 +755,8 @@ public Collection getAttributeAuthorityRevocationLists( * @throws StoreException */ public Collection getCrossCertificatePairs( - X509CertPairStoreSelector selector) throws StoreException + X509CertPairStoreSelector selector) + throws StoreException { String[] attrs = splitString(params.getCrossCertificateAttribute()); String attrNames[] = splitString(params.getLdapCrossCertificateAttributeName()); @@ -850,6 +817,7 @@ public Collection getUserCertificates(X509CertStoreSelector selector) *

    * The aAcertificate holds the privileges of an attribute authority. *

    + * * @param selector The selector to find the attribute certificates. * @return A possible empty collection with attribute certificates. * @throws StoreException @@ -882,12 +850,14 @@ public Collection getAACertificates(X509AttributeCertStoreSelector selector) * authority and holds a description of the privilege and its delegation * rules. *

    + * * @param selector The selector to find the attribute certificates. * @return A possible empty collection with attribute certificates. * @throws StoreException */ public Collection getAttributeDescriptorCertificates( - X509AttributeCertStoreSelector selector) throws StoreException + X509AttributeCertStoreSelector selector) + throws StoreException { String[] attrs = splitString(params.getAttributeDescriptorCertificateAttribute()); String attrNames[] = splitString(params @@ -916,6 +886,7 @@ public Collection getAttributeDescriptorCertificates( * store self-issued certificates (if any) and certificates issued to this * CA by CAs in the same realm as this CA. *

    + * * @param selector The selector to find the certificates. * @return A possible empty collection with certificates. * @throws StoreException @@ -948,7 +919,8 @@ public Collection getCACertificates(X509CertStoreSelector selector) * @throws StoreException */ public Collection getDeltaCertificateRevocationLists( - X509CRLStoreSelector selector) throws StoreException + X509CRLStoreSelector selector) + throws StoreException { String[] attrs = splitString(params.getDeltaRevocationListAttribute()); String attrNames[] = splitString(params.getLdapDeltaRevocationListAttributeName()); @@ -973,12 +945,14 @@ public Collection getDeltaCertificateRevocationLists( *

    * The attributeCertificateAttribute holds the privileges of a user *

    + * * @param selector The selector to find the attribute certificates. * @return A possible empty collection with attribute certificates. * @throws StoreException */ public Collection getAttributeCertificateAttributes( - X509AttributeCertStoreSelector selector) throws StoreException + X509AttributeCertStoreSelector selector) + throws StoreException { String[] attrs = splitString(params.getAttributeCertificateAttributeAttribute()); String attrNames[] = splitString(params @@ -1007,7 +981,8 @@ public Collection getAttributeCertificateAttributes( * @throws StoreException */ public Collection getCertificateRevocationLists( - X509CRLStoreSelector selector) throws StoreException + X509CRLStoreSelector selector) + throws StoreException { String[] attrs = splitString(params.getCertificateRevocationListAttribute()); String attrNames[] = splitString(params diff --git a/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java index 21391a5323..a54d4aa287 100644 --- a/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java +++ b/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java @@ -17,19 +17,20 @@ import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Null; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers; import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.Extensions; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.jcajce.util.MessageDigestUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Exceptions; import org.bouncycastle.util.Strings; - class X509SignatureUtil { private static final Map algNames = new HashMap(); @@ -42,29 +43,56 @@ class X509SignatureUtil algNames.put(X9ObjectIdentifiers.id_dsa_with_sha1, "SHA1withDSA"); } - private static final ASN1Null derNull = DERNull.INSTANCE; + static byte[] getExtensionValue(Extensions extensions, String oid) + { + if (oid != null) + { + ASN1ObjectIdentifier asn1Oid = ASN1ObjectIdentifier.tryFromID(oid); + if (asn1Oid != null) + { + ASN1OctetString extValue = Extensions.getExtensionValue(extensions, asn1Oid); + if (null != extValue) + { + try + { + return extValue.getEncoded(); + } + catch (Exception e) + { + throw Exceptions.illegalStateException("error parsing " + e.getMessage(), e); + } + } + } + } + return null; + } + + private static boolean isAbsentOrEmptyParameters(ASN1Encodable parameters) + { + return parameters == null || DERNull.INSTANCE.equals(parameters); + } - static void setSignatureParameters( - Signature signature, - ASN1Encodable params) + static void setSignatureParameters(Signature signature, ASN1Encodable params) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException { - if (params != null && !derNull.equals(params)) + if (!isAbsentOrEmptyParameters(params)) { + String sigAlgName = signature.getAlgorithm(); - AlgorithmParameters sigParams; + String sigParamsAlg; + if (sigAlgName.indexOf("MGF1") > 0) + { + sigParamsAlg = "PSS"; + } + else + { + sigParamsAlg = Strings.toUpperCase(sigAlgName); + } try { - if (signature.getAlgorithm().indexOf("MGF1") > 0) - { - sigParams = AlgorithmParameters.getInstance("PSS"); - } - else - { - sigParams = AlgorithmParameters.getInstance(Strings.toUpperCase(signature.getAlgorithm())); - } - + AlgorithmParameters sigParams = AlgorithmParameters.getInstance(sigParamsAlg); + sigParams.init(params.toASN1Primitive().getEncoded()); } catch (IOException e) @@ -73,38 +101,38 @@ static void setSignatureParameters( } } } - - static String getSignatureName( - AlgorithmIdentifier sigAlgId) + + static String getSignatureName(AlgorithmIdentifier sigAlgId) { + ASN1ObjectIdentifier sigAlgOid = sigAlgId.getAlgorithm(); ASN1Encodable params = sigAlgId.getParameters(); - - if (params != null && !derNull.equals(params)) + + if (!isAbsentOrEmptyParameters(params)) { - if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) + if (PKCSObjectIdentifiers.id_RSASSA_PSS.equals(sigAlgOid)) { RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params); - + return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "WITHRSAANDMGF1"; } - if (sigAlgId.getAlgorithm().equals(X9ObjectIdentifiers.ecdsa_with_SHA2)) + if (X9ObjectIdentifiers.ecdsa_with_SHA2.equals(sigAlgOid)) { - ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params); - - return getDigestAlgName((ASN1ObjectIdentifier)ecDsaParams.getObjectAt(0)) + "WITHECDSA"; + AlgorithmIdentifier ecDsaParams = AlgorithmIdentifier.getInstance(params); + + return getDigestAlgName(ecDsaParams.getAlgorithm()) + "WITHECDSA"; } } // deal with the "weird" ones. - String algName = (String)algNames.get(sigAlgId.getAlgorithm()); + String algName = (String)algNames.get(sigAlgOid); if (algName != null) { return algName; } - return findAlgName(sigAlgId.getAlgorithm()); + return findAlgName(sigAlgOid); } - + /** * Return the digest algorithm using one of the standard JCA string * representations rather the the algorithm identifier (if possible). @@ -155,7 +183,7 @@ private static String findAlgName(ASN1ObjectIdentifier algOid) private static String lookupAlg(Provider prov, ASN1ObjectIdentifier algOid) { - String algName = prov.getProperty("Alg.Alias.Signature." + algOid); + String algName = prov.getProperty("Alg.Alias.Signature." + algOid); if (algName != null) { diff --git a/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/BouncyCastleProvider.java index 2e22ef7c08..2df257de72 100644 --- a/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/BouncyCastleProvider.java +++ b/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/BouncyCastleProvider.java @@ -43,7 +43,7 @@ public final class BouncyCastleProvider extends Provider implements ConfigurableProvider { - private static String info = "BouncyCastle Security Provider v1.80"; + private static String info = "BouncyCastle Security Provider v1.82"; public static final String PROVIDER_NAME = "BC"; @@ -118,7 +118,7 @@ public final class BouncyCastleProvider extends Provider */ public BouncyCastleProvider() { - super(PROVIDER_NAME, 1.8000, info); + super(PROVIDER_NAME, 1.8200, info); setup(); } diff --git a/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/X509CRLObject.java b/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/X509CRLObject.java index d256e7d1a0..9e5e6a9872 100644 --- a/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/X509CRLObject.java +++ b/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/X509CRLObject.java @@ -37,7 +37,9 @@ import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.IssuingDistributionPoint; import org.bouncycastle.asn1.x509.TBSCertList; +import org.bouncycastle.asn1.x509.Time; import org.bouncycastle.jce.X509Principal; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.x509.extension.X509ExtensionUtil; @@ -102,30 +104,41 @@ public X509CRLObject( } } - /** - * Will return true if any extensions are present and marked - * as critical as we currently dont handle any extensions! - */ public boolean hasUnsupportedCriticalExtension() { - Set extns = getCriticalExtensionOIDs(); - - if (extns == null) + if (getVersion() == 2) { - return false; - } + Extensions extensions = c.getExtensions(); + if (extensions != null) + { + Enumeration e = extensions.oids(); + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT); - extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR); + if (Extension.issuingDistributionPoint.equals(oid) || + Extension.deltaCRLIndicator.equals(oid)) + { + continue; + } + + Extension ext = extensions.getExtension(oid); + if (ext.isCritical()) + { + return true; + } + } + } + } - return !extns.isEmpty(); + return false; } private Set getExtensionOIDs(boolean critical) { if (this.getVersion() == 2) { - Extensions extensions = c.getTBSCertList().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -162,26 +175,7 @@ public Set getNonCriticalExtensionOIDs() public byte[] getExtensionValue(String oid) { - Extensions exts = c.getTBSCertList().getExtensions(); - - if (exts != null) - { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - - if (ext != null) - { - try - { - return ext.getExtnValue().getEncoded(); - } - catch (Exception e) - { - throw new IllegalStateException("error parsing " + e.toString()); - } - } - } - - return null; + return X509SignatureUtil.getExtensionValue(c.getExtensions(), oid); } public byte[] getEncoded() @@ -250,12 +244,9 @@ public Date getThisUpdate() public Date getNextUpdate() { - if (c.getNextUpdate() != null) - { - return c.getNextUpdate().getDate(); - } + Time nextUpdate = c.getNextUpdate(); - return null; + return null == nextUpdate ? null : nextUpdate.getDate(); } private Set loadCRLEntries() @@ -353,16 +344,7 @@ public String getSigAlgOID() public byte[] getSigAlgParams() { - if (sigAlgParams != null) - { - byte[] tmp = new byte[sigAlgParams.length]; - - System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length); - - return tmp; - } - - return null; + return Arrays.clone(sigAlgParams); } /** @@ -404,7 +386,7 @@ public String toString() } } - Extensions extensions = c.getTBSCertList().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { diff --git a/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/X509CertificateObject.java b/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/X509CertificateObject.java index 1e4c262dd3..0ff3c41c21 100644 --- a/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/X509CertificateObject.java +++ b/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/X509CertificateObject.java @@ -34,6 +34,7 @@ import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1OutputStream; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; @@ -83,7 +84,7 @@ public X509CertificateObject( try { - byte[] bytes = this.getExtensionBytes("2.5.29.19"); + byte[] bytes = getExtensionOctets(c, Extension.basicConstraints); if (bytes != null) { @@ -97,10 +98,10 @@ public X509CertificateObject( try { - byte[] bytes = this.getExtensionBytes("2.5.29.15"); + byte[] bytes = getExtensionOctets(c, Extension.keyUsage); if (bytes != null) { - ASN1BitString bits = ASN1BitString.getInstance(ASN1Primitive.fromByteArray(bytes)); + ASN1BitString bits = ASN1BitString.getInstance(ASN1Primitive.fromByteArray(bytes)); bytes = bits.getBytes(); int length = (bytes.length * 8) - bits.getPadBits(); @@ -312,32 +313,29 @@ public boolean[] getKeyUsage() public List getExtendedKeyUsage() throws CertificateParsingException { - byte[] bytes = this.getExtensionBytes("2.5.29.37"); + byte[] extOctets = getExtensionOctets(c, Extension.extendedKeyUsage); + if (null == extOctets) + { + return null; + } - if (bytes != null) + try { - try - { - ASN1InputStream dIn = new ASN1InputStream(bytes); - ASN1Sequence seq = (ASN1Sequence)dIn.readObject(); - List list = new ArrayList(); + ASN1Sequence seq = ASN1Sequence.getInstance(extOctets); - for (int i = 0; i != seq.size(); i++) - { - list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId()); - } - - return Collections.unmodifiableList(list); - } - catch (Exception e) + List list = new ArrayList(); + for (int i = 0; i != seq.size(); i++) { - throw new CertificateParsingException("error processing extended key usage extension"); + list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId()); } + return Collections.unmodifiableList(list); + } + catch (Exception e) + { + throw new CertificateParsingException("error processing extended key usage extension"); } - - return null; } - + public int getBasicConstraints() { if (basicConstraints != null) @@ -365,13 +363,13 @@ public int getBasicConstraints() public Collection getSubjectAlternativeNames() throws CertificateParsingException { - return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId())); + return getAlternativeNames(c, Extension.subjectAlternativeName); } public Collection getIssuerAlternativeNames() throws CertificateParsingException { - return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId())); + return getAlternativeNames(c, Extension.issuerAlternativeName); } public Set getCriticalExtensionOIDs() @@ -379,7 +377,7 @@ public Set getCriticalExtensionOIDs() if (this.getVersion() == 3) { Set set = new HashSet(); - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -403,44 +401,9 @@ public Set getCriticalExtensionOIDs() return null; } - private byte[] getExtensionBytes(String oid) - { - Extensions exts = c.getTBSCertificate().getExtensions(); - - if (exts != null) - { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - if (ext != null) - { - return ext.getExtnValue().getOctets(); - } - } - - return null; - } - public byte[] getExtensionValue(String oid) { - Extensions exts = c.getTBSCertificate().getExtensions(); - - if (exts != null) - { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - - if (ext != null) - { - try - { - return ext.getExtnValue().getEncoded(); - } - catch (Exception e) - { - throw new IllegalStateException("error parsing " + e.toString()); - } - } - } - - return null; + return X509SignatureUtil.getExtensionValue(c.getExtensions(), oid); } public Set getNonCriticalExtensionOIDs() @@ -448,7 +411,7 @@ public Set getNonCriticalExtensionOIDs() if (this.getVersion() == 3) { Set set = new HashSet(); - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -474,36 +437,32 @@ public Set getNonCriticalExtensionOIDs() public boolean hasUnsupportedCriticalExtension() { - if (this.getVersion() == 3) + if (getVersion() == 3) { - Extensions extensions = c.getTBSCertificate().getExtensions(); - + Extensions extensions = c.getExtensions(); if (extensions != null) { - Enumeration e = extensions.oids(); - + Enumeration e = extensions.oids(); while (e.hasMoreElements()) { ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - String oidId = oid.getId(); - - if (oidId.equals(RFC3280CertPathUtilities.KEY_USAGE) - || oidId.equals(RFC3280CertPathUtilities.CERTIFICATE_POLICIES) - || oidId.equals(RFC3280CertPathUtilities.POLICY_MAPPINGS) - || oidId.equals(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY) - || oidId.equals(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS) - || oidId.equals(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT) - || oidId.equals(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR) - || oidId.equals(RFC3280CertPathUtilities.POLICY_CONSTRAINTS) - || oidId.equals(RFC3280CertPathUtilities.BASIC_CONSTRAINTS) - || oidId.equals(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME) - || oidId.equals(RFC3280CertPathUtilities.NAME_CONSTRAINTS)) + + if (Extension.keyUsage.equals(oid) || + Extension.certificatePolicies.equals(oid) || + Extension.policyMappings.equals(oid) || + Extension.inhibitAnyPolicy.equals(oid) || + Extension.cRLDistributionPoints.equals(oid) || + Extension.issuingDistributionPoint.equals(oid) || + Extension.deltaCRLIndicator.equals(oid) || + Extension.policyConstraints.equals(oid) || + Extension.basicConstraints.equals(oid) || + Extension.subjectAlternativeName.equals(oid) || + Extension.nameConstraints.equals(oid)) { continue; } - Extension ext = extensions.getExtension(oid); - + Extension ext = extensions.getExtension(oid); if (ext.isCritical()) { return true; @@ -644,7 +603,7 @@ public String toString() } } - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -799,17 +758,18 @@ private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2) return id1.getParameters().equals(id2.getParameters()); } - private static Collection getAlternativeNames(byte[] extVal) + private static Collection getAlternativeNames(org.bouncycastle.asn1.x509.Certificate c, ASN1ObjectIdentifier oid) throws CertificateParsingException { - if (extVal == null) + byte[] extOctets = getExtensionOctets(c, oid); + if (extOctets == null) { return null; } try { Collection temp = new ArrayList(); - Enumeration it = ASN1Sequence.getInstance(extVal).getObjects(); + Enumeration it = ASN1Sequence.getInstance(extOctets).getObjects(); while (it.hasMoreElements()) { GeneralName genName = GeneralName.getInstance(it.nextElement()); @@ -854,4 +814,11 @@ private static Collection getAlternativeNames(byte[] extVal) throw new CertificateParsingException(e.getMessage()); } } + + private static byte[] getExtensionOctets(org.bouncycastle.asn1.x509.Certificate c, ASN1ObjectIdentifier oid) + { + ASN1OctetString extValue = Extensions.getExtensionValue(c.getExtensions(), oid); + + return extValue == null ? null : extValue.getOctets(); + } } diff --git a/prov/src/main/jdk1.11/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java b/prov/src/main/jdk1.11/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java index 58a475e28c..cd3720ce1a 100644 --- a/prov/src/main/jdk1.11/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java +++ b/prov/src/main/jdk1.11/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java @@ -18,6 +18,7 @@ import org.bouncycastle.crypto.agreement.XDHUnifiedAgreement; import org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator; import org.bouncycastle.crypto.generators.KDF2BytesGenerator; +import org.bouncycastle.crypto.generators.HKDFBytesGenerator; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.X25519PrivateKeyParameters; import org.bouncycastle.crypto.params.X25519PublicKeyParameters; @@ -476,4 +477,23 @@ public X448UwithSHA512KDF() super("X448UwithSHA512KDF", new KDF2BytesGenerator(DigestFactory.createSHA512())); } } + + + public final static class X448withSHA512HKDF + extends KeyAgreementSpi + { + public X448withSHA512HKDF() + { + super("X448withSHA512HKDF", new HKDFBytesGenerator(DigestFactory.createSHA512())); + } + } + + public final static class X25519withSHA256HKDF + extends KeyAgreementSpi + { + public X25519withSHA256HKDF() + { + super("X25519withSHA256HKDF", new HKDFBytesGenerator(DigestFactory.createSHA256())); + } + } } diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMCipherSpi.java b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMCipherSpi.java index 8731c92a51..882e77b45d 100644 --- a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMCipherSpi.java +++ b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMCipherSpi.java @@ -32,46 +32,46 @@ import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Exceptions; -class MLKEMCipherSpi +public class MLKEMCipherSpi extends CipherSpi { + private final MLKEMParameters mlkemParameters; private final String algorithmName; + private MLKEMGenerator kemGen; private KTSParameterSpec kemParameterSpec; private BCMLKEMPublicKey wrapKey; private BCMLKEMPrivateKey unwrapKey; private AlgorithmParameters engineParams; - private MLKEMParameters mlkemParamters; - MLKEMCipherSpi(String algorithmName) + public MLKEMCipherSpi(String algorithmName) { + this.mlkemParameters = null; this.algorithmName = algorithmName; - this.mlkemParamters = null; } - MLKEMCipherSpi(MLKEMParameters kyberParameters) + public MLKEMCipherSpi(MLKEMParameters mlkemParameters) { - this.mlkemParamters = kyberParameters; - this.algorithmName = kyberParameters.getName(); + this.mlkemParameters = mlkemParameters; + this.algorithmName = mlkemParameters.getName(); } @Override protected void engineSetMode(String mode) - throws NoSuchAlgorithmException + throws NoSuchAlgorithmException { throw new NoSuchAlgorithmException("Cannot support mode " + mode); } @Override protected void engineSetPadding(String padding) - throws NoSuchPaddingException + throws NoSuchPaddingException { throw new NoSuchPaddingException("Padding " + padding + " unknown"); } - protected int engineGetKeySize( - Key key) + protected int engineGetKeySize(Key key) { return 2048; // TODO //throw new IllegalArgumentException("not an valid key!"); @@ -176,9 +176,9 @@ else if (opmode == Cipher.UNWRAP_MODE) throw new InvalidParameterException("Cipher only valid for wrapping/unwrapping"); } - if (mlkemParamters != null) + if (mlkemParameters != null) { - String canonicalAlgName = MLKEMParameterSpec.fromName(mlkemParamters.getName()).getName(); + String canonicalAlgName = MLKEMParameterSpec.fromName(mlkemParameters.getName()).getName(); if (!canonicalAlgName.equals(key.getAlgorithm())) { throw new InvalidKeyException("cipher locked to " + canonicalAlgName); @@ -255,11 +255,14 @@ protected byte[] engineWrap( byte[] keyToWrap = key.getEncoded(); - byte[] rv = Arrays.concatenate(encapsulation, kWrap.wrap(keyToWrap, 0, keyToWrap.length)); - - Arrays.clear(keyToWrap); - - return rv; + try + { + return Arrays.concatenate(encapsulation, kWrap.wrap(keyToWrap, 0, keyToWrap.length)); + } + finally + { + Arrays.clear(keyToWrap); + } } catch (IllegalArgumentException e) { @@ -276,7 +279,7 @@ protected byte[] engineWrap( } catch (Exception e) { - throw new IllegalBlockSizeException("unable to destroy interim values: " + e.getMessage()); + // ignore } } } @@ -292,6 +295,7 @@ protected Key engineUnwrap( { throw new InvalidKeyException("only SECRET_KEY supported"); } + byte[] secret = null; try { @@ -317,18 +321,14 @@ protected Key engineUnwrap( } finally { - if (secret != null) - { - Arrays.clear(secret); - } + Arrays.clear(secret); } } public static class Base - extends MLKEMCipherSpi + extends MLKEMCipherSpi { public Base() - throws NoSuchAlgorithmException { super("MLKEM"); } diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMKeyGeneratorSpi.java b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMKeyGeneratorSpi.java index 6b09d0f4f0..c7da53cf6c 100644 --- a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMKeyGeneratorSpi.java +++ b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMKeyGeneratorSpi.java @@ -7,6 +7,7 @@ import javax.crypto.KeyGeneratorSpi; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; +import javax.security.auth.DestroyFailedException; import org.bouncycastle.crypto.SecretWithEncapsulation; import org.bouncycastle.jcajce.SecretKeyWithEncapsulation; @@ -20,21 +21,22 @@ import org.bouncycastle.util.Arrays; public class MLKEMKeyGeneratorSpi - extends KeyGeneratorSpi + extends KeyGeneratorSpi { + private final MLKEMParameters mlkemParameters; + private KEMGenerateSpec genSpec; private SecureRandom random; private KEMExtractSpec extSpec; - private MLKEMParameters kyberParameters; public MLKEMKeyGeneratorSpi() { this(null); } - protected MLKEMKeyGeneratorSpi(MLKEMParameters kyberParameters) + protected MLKEMKeyGeneratorSpi(MLKEMParameters mlkemParameters) { - this.kyberParameters = kyberParameters; + this.mlkemParameters = mlkemParameters; } protected void engineInit(SecureRandom secureRandom) @@ -50,9 +52,9 @@ protected void engineInit(AlgorithmParameterSpec algorithmParameterSpec, SecureR { this.genSpec = (KEMGenerateSpec)algorithmParameterSpec; this.extSpec = null; - if (kyberParameters != null) + if (mlkemParameters != null) { - String canonicalAlgName = MLKEMParameterSpec.fromName(kyberParameters.getName()).getName(); + String canonicalAlgName = MLKEMParameterSpec.fromName(mlkemParameters.getName()).getName(); if (!canonicalAlgName.equals(genSpec.getPublicKey().getAlgorithm())) { throw new InvalidAlgorithmParameterException("key generator locked to " + canonicalAlgName); @@ -63,9 +65,9 @@ else if (algorithmParameterSpec instanceof KEMExtractSpec) { this.genSpec = null; this.extSpec = (KEMExtractSpec)algorithmParameterSpec; - if (kyberParameters != null) + if (mlkemParameters != null) { - String canonicalAlgName = MLKEMParameterSpec.fromName(kyberParameters.getName()).getName(); + String canonicalAlgName = MLKEMParameterSpec.fromName(mlkemParameters.getName()).getName(); if (!canonicalAlgName.equals(extSpec.getPrivateKey().getAlgorithm())) { throw new InvalidAlgorithmParameterException("key generator locked to " + canonicalAlgName); @@ -92,24 +94,26 @@ protected SecretKey engineGenerateKey() SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(pubKey.getKeyParams()); - byte[] sharedSecret = secEnc.getSecret(); - - byte[] secret = KdfUtil.makeKeyBytes(genSpec, sharedSecret); - - Arrays.clear(sharedSecret); - - SecretKey rv = new SecretKeyWithEncapsulation(new SecretKeySpec(secret, genSpec.getKeyAlgorithmName()), secEnc.getEncapsulation()); + byte[] kemSecret = secEnc.getSecret(); + byte[] kdfSecret = KdfUtil.makeKeyBytes(genSpec, kemSecret); try { - secEnc.destroy(); + SecretKeySpec secretKey = new SecretKeySpec(kdfSecret, genSpec.getKeyAlgorithmName()); + + return new SecretKeyWithEncapsulation(secretKey, secEnc.getEncapsulation()); } - catch (Exception e) + finally { - throw new IllegalStateException("key cleanup failed"); + try + { + secEnc.destroy(); + } + catch (DestroyFailedException e) + { + // ignore + } } - - return rv; } else { @@ -117,16 +121,21 @@ protected SecretKey engineGenerateKey() MLKEMExtractor kemExt = new MLKEMExtractor(privKey.getKeyParams()); byte[] encapsulation = extSpec.getEncapsulation(); - byte[] sharedSecret = kemExt.extractSecret(encapsulation); - byte[] secret = KdfUtil.makeKeyBytes(extSpec, sharedSecret); - Arrays.clear(sharedSecret); + byte[] kemSecret = kemExt.extractSecret(encapsulation); + byte[] kdfSecret = KdfUtil.makeKeyBytes(extSpec, kemSecret); - SecretKey rv = new SecretKeyWithEncapsulation(new SecretKeySpec(secret, extSpec.getKeyAlgorithmName()), encapsulation); - - Arrays.clear(secret); + try + { + SecretKeySpec secretKey = new SecretKeySpec(kdfSecret, extSpec.getKeyAlgorithmName()); - return rv; + // TODO Why do we return ...WithEncapsulation?? + return new SecretKeyWithEncapsulation(secretKey, encapsulation); + } + finally + { + Arrays.clear(kdfSecret); + } } } diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java index 14d816c8da..e12e92d440 100644 --- a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java +++ b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java @@ -10,9 +10,10 @@ import java.util.Set; import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Enumerated; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Enumerated; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.util.ASN1Dump; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.CRLReason; @@ -78,9 +79,9 @@ public X509CRLEntryObject( */ public boolean hasUnsupportedCriticalExtension() { - Set extns = getCriticalExtensionOIDs(); + Extensions extensions = c.getExtensions(); - return extns != null && !extns.isEmpty(); + return extensions != null && extensions.hasAnyCriticalExtensions(); } private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer) @@ -90,16 +91,15 @@ private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCert return null; } - byte[] ext = getExtensionValue(X509Extension.certificateIssuer.getId()); - if (ext == null) + ASN1OctetString extValue = Extensions.getExtensionValue(c.getExtensions(), Extension.certificateIssuer); + if (extValue == null) { return previousCertificateIssuer; } try { - GeneralName[] names = GeneralNames.getInstance( - X509ExtensionUtil.fromExtensionValue(ext)).getNames(); + GeneralName[] names = GeneralNames.getInstance(extValue.getOctets()).getNames(); for (int i = 0; i < names.length; i++) { if (names[i].getTagNo() == GeneralName.directoryName) @@ -168,26 +168,7 @@ public Set getNonCriticalExtensionOIDs() public byte[] getExtensionValue(String oid) { - Extensions exts = c.getExtensions(); - - if (exts != null) - { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - - if (ext != null) - { - try - { - return ext.getExtnValue().getEncoded(); - } - catch (Exception e) - { - throw new RuntimeException("error encoding " + e.toString()); - } - } - } - - return null; + return X509SignatureUtil.getExtensionValue(c.getExtensions(), oid); } /** diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java index a0055b04c8..e11c0e9949 100644 --- a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java +++ b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java @@ -41,6 +41,7 @@ import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.IssuingDistributionPoint; import org.bouncycastle.asn1.x509.TBSCertList; +import org.bouncycastle.asn1.x509.Time; import org.bouncycastle.jcajce.interfaces.BCX509Certificate; import org.bouncycastle.jcajce.io.OutputStreamFactory; import org.bouncycastle.jcajce.util.JcaJceHelper; @@ -76,30 +77,41 @@ abstract class X509CRLImpl this.isIndirect = isIndirect; } - /** - * Will return true if any extensions are present and marked - * as critical as we currently dont handle any extensions! - */ public boolean hasUnsupportedCriticalExtension() { - Set extns = getCriticalExtensionOIDs(); - - if (extns == null) + if (getVersion() == 2) { - return false; - } + Extensions extensions = c.getExtensions(); + if (extensions != null) + { + Enumeration e = extensions.oids(); + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + + if (Extension.issuingDistributionPoint.equals(oid) || + Extension.deltaCRLIndicator.equals(oid)) + { + continue; + } - extns.remove(Extension.issuingDistributionPoint.getId()); - extns.remove(Extension.deltaCRLIndicator.getId()); + Extension ext = extensions.getExtension(oid); + if (ext.isCritical()) + { + return true; + } + } + } + } - return !extns.isEmpty(); + return false; } private Set getExtensionOIDs(boolean critical) { if (this.getVersion() == 2) { - Extensions extensions = c.getTBSCertList().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -136,19 +148,7 @@ public Set getNonCriticalExtensionOIDs() public byte[] getExtensionValue(String oid) { - ASN1OctetString extValue = getExtensionValue(c, oid); - if (null != extValue) - { - try - { - return extValue.getEncoded(); - } - catch (Exception e) - { - throw new IllegalStateException("error parsing " + e.toString()); - } - } - return null; + return X509SignatureUtil.getExtensionValue(c.getExtensions(), oid); } public byte[] getEncoded() @@ -285,14 +285,11 @@ public Date getThisUpdate() public Date getNextUpdate() { - if (c.getNextUpdate() != null) - { - return c.getNextUpdate().getDate(); - } + Time nextUpdate = c.getNextUpdate(); - return null; + return null == nextUpdate ? null : nextUpdate.getDate(); } - + private Set loadCRLEntries() { Set entrySet = new HashSet(); @@ -430,7 +427,7 @@ public String toString() } } - Extensions extensions = c.getTBSCertList().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -595,28 +592,10 @@ public boolean isRevoked(Certificate cert) return false; } - protected static byte[] getExtensionOctets(CertificateList c, String oid) + static byte[] getExtensionOctets(CertificateList c, ASN1ObjectIdentifier oid) { - ASN1OctetString extValue = getExtensionValue(c, oid); - if (null != extValue) - { - return extValue.getOctets(); - } - return null; - } + ASN1OctetString extValue = Extensions.getExtensionValue(c.getExtensions(), oid); - protected static ASN1OctetString getExtensionValue(CertificateList c, String oid) - { - Extensions exts = c.getTBSCertList().getExtensions(); - if (null != exts) - { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - if (null != ext) - { - return ext.getExtnValue(); - } - } - return null; + return extValue == null ? null : extValue.getOctets(); } } - diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java index dfb0b0dc8d..964a705db4 100644 --- a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java +++ b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java @@ -135,7 +135,7 @@ private static boolean isIndirectCRL(CertificateList c) throws CRLException { try { - byte[] extOctets = getExtensionOctets(c, Extension.issuingDistributionPoint.getId()); + byte[] extOctets = getExtensionOctets(c, Extension.issuingDistributionPoint); if (null == extOctets) { return false; diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java index 527be010bf..f9ed96804b 100644 --- a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java +++ b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java @@ -244,7 +244,7 @@ public boolean[] getKeyUsage() public List getExtendedKeyUsage() throws CertificateParsingException { - byte[] extOctets = getExtensionOctets(c, "2.5.29.37"); + byte[] extOctets = getExtensionOctets(c, Extension.extendedKeyUsage); if (null == extOctets) { return null; @@ -294,13 +294,13 @@ public int getBasicConstraints() public Collection getSubjectAlternativeNames() throws CertificateParsingException { - return getAlternativeNames(c, Extension.subjectAlternativeName.getId()); + return getAlternativeNames(c, Extension.subjectAlternativeName); } public Collection getIssuerAlternativeNames() throws CertificateParsingException { - return getAlternativeNames(c, Extension.issuerAlternativeName.getId()); + return getAlternativeNames(c, Extension.issuerAlternativeName); } public Set getCriticalExtensionOIDs() @@ -308,7 +308,7 @@ public Set getCriticalExtensionOIDs() if (this.getVersion() == 3) { Set set = new HashSet(); - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -332,22 +332,9 @@ public Set getCriticalExtensionOIDs() return null; } - public byte[] getExtensionValue(String oid) + public byte[] getExtensionValue(String oid) { - ASN1OctetString extValue = getExtensionValue(c, oid); - if (null != extValue) - { - try - { - return extValue.getEncoded(); - } - catch (Exception e) - { - throw new IllegalStateException("error parsing " + e.toString()); - } - } - - return null; + return X509SignatureUtil.getExtensionValue(c.getExtensions(), oid); } public Set getNonCriticalExtensionOIDs() @@ -355,7 +342,7 @@ public Set getNonCriticalExtensionOIDs() if (this.getVersion() == 3) { Set set = new HashSet(); - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -381,35 +368,32 @@ public Set getNonCriticalExtensionOIDs() public boolean hasUnsupportedCriticalExtension() { - if (this.getVersion() == 3) + if (getVersion() == 3) { - Extensions extensions = c.getTBSCertificate().getExtensions(); - + Extensions extensions = c.getExtensions(); if (extensions != null) { - Enumeration e = extensions.oids(); - + Enumeration e = extensions.oids(); while (e.hasMoreElements()) { ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - if (oid.equals(Extension.keyUsage) - || oid.equals(Extension.certificatePolicies) - || oid.equals(Extension.policyMappings) - || oid.equals(Extension.inhibitAnyPolicy) - || oid.equals(Extension.cRLDistributionPoints) - || oid.equals(Extension.issuingDistributionPoint) - || oid.equals(Extension.deltaCRLIndicator) - || oid.equals(Extension.policyConstraints) - || oid.equals(Extension.basicConstraints) - || oid.equals(Extension.subjectAlternativeName) - || oid.equals(Extension.nameConstraints)) + if (Extension.keyUsage.equals(oid) || + Extension.certificatePolicies.equals(oid) || + Extension.policyMappings.equals(oid) || + Extension.inhibitAnyPolicy.equals(oid) || + Extension.cRLDistributionPoints.equals(oid) || + Extension.issuingDistributionPoint.equals(oid) || + Extension.deltaCRLIndicator.equals(oid) || + Extension.policyConstraints.equals(oid) || + Extension.basicConstraints.equals(oid) || + Extension.subjectAlternativeName.equals(oid) || + Extension.nameConstraints.equals(oid)) { continue; } - Extension ext = extensions.getExtension(oid); - + Extension ext = extensions.getExtension(oid); if (ext.isCritical()) { return true; @@ -475,7 +459,7 @@ public String toString() } } - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -678,7 +662,7 @@ private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2) return id1.getParameters().equals(id2.getParameters()); } - private static Collection getAlternativeNames(org.bouncycastle.asn1.x509.Certificate c, String oid) + private static Collection getAlternativeNames(org.bouncycastle.asn1.x509.Certificate c, ASN1ObjectIdentifier oid) throws CertificateParsingException { byte[] extOctets = getExtensionOctets(c, oid); @@ -737,27 +721,10 @@ private static Collection getAlternativeNames(org.bouncycastle.asn1.x509.Certifi } } - protected static byte[] getExtensionOctets(org.bouncycastle.asn1.x509.Certificate c, String oid) + static byte[] getExtensionOctets(org.bouncycastle.asn1.x509.Certificate c, ASN1ObjectIdentifier oid) { - ASN1OctetString extValue = getExtensionValue(c, oid); - if (null != extValue) - { - return extValue.getOctets(); - } - return null; - } + ASN1OctetString extValue = Extensions.getExtensionValue(c.getExtensions(), oid); - protected static ASN1OctetString getExtensionValue(org.bouncycastle.asn1.x509.Certificate c, String oid) - { - Extensions exts = c.getTBSCertificate().getExtensions(); - if (null != exts) - { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - if (null != ext) - { - return ext.getExtnValue(); - } - } - return null; + return extValue == null ? null : extValue.getOctets(); } } diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java index a08a326deb..613fa78553 100644 --- a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java +++ b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java @@ -14,6 +14,7 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; import org.bouncycastle.jcajce.util.JcaJceHelper; import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; @@ -232,7 +233,7 @@ private static BasicConstraints createBasicConstraints(org.bouncycastle.asn1.x50 { try { - byte[] extOctets = getExtensionOctets(c, "2.5.29.19"); + byte[] extOctets = getExtensionOctets(c, Extension.basicConstraints); if (null == extOctets) { return null; @@ -250,7 +251,7 @@ private static boolean[] createKeyUsage(org.bouncycastle.asn1.x509.Certificate c { try { - byte[] extOctets = getExtensionOctets(c, "2.5.29.15"); + byte[] extOctets = getExtensionOctets(c, Extension.keyUsage); if (null == extOctets) { return null; diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java index 925ccc3206..1d594b178c 100644 --- a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java +++ b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java @@ -17,13 +17,14 @@ import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Null; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers; import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.pkcs.RSASSAPSSparams; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.Extensions; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.jcajce.util.MessageDigestUtils; import org.bouncycastle.jce.provider.BouncyCastleProvider; @@ -40,22 +41,47 @@ class X509SignatureUtil algNames.put(X9ObjectIdentifiers.id_dsa_with_sha1, "SHA1withDSA"); } - private static final ASN1Null derNull = DERNull.INSTANCE; + static byte[] getExtensionValue(Extensions extensions, String oid) + { + if (oid != null) + { + ASN1ObjectIdentifier asn1Oid = ASN1ObjectIdentifier.tryFromID(oid); + if (asn1Oid != null) + { + ASN1OctetString extValue = Extensions.getExtensionValue(extensions, asn1Oid); + if (null != extValue) + { + try + { + return extValue.getEncoded(); + } + catch (Exception e) + { + throw new IllegalStateException("error parsing " + e.toString()); + } + } + } + } + return null; + } + + private static boolean isAbsentOrEmptyParameters(ASN1Encodable parameters) + { + return parameters == null || DERNull.INSTANCE.equals(parameters); + } - static void setSignatureParameters( - Signature signature, - ASN1Encodable params) + static void setSignatureParameters(Signature signature, ASN1Encodable params) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException { - if (params != null && !derNull.equals(params)) + if (!isAbsentOrEmptyParameters(params)) { - - AlgorithmParameters sigParams; + String sigAlgName = signature.getAlgorithm(); try { - sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider().getName()); - + AlgorithmParameters sigParams = AlgorithmParameters.getInstance(sigAlgName, + signature.getProvider().getName()); + sigParams.init(params.toASN1Primitive().getEncoded()); } catch (NoSuchProviderException e) @@ -66,8 +92,8 @@ static void setSignatureParameters( { throw new SignatureException("IOException decoding parameters: " + e.getMessage()); } - - if (signature.getAlgorithm().endsWith("MGF1")) + + if (sigAlgName.endsWith("MGF1")) { try { @@ -80,38 +106,38 @@ static void setSignatureParameters( } } } - - static String getSignatureName( - AlgorithmIdentifier sigAlgId) + + static String getSignatureName(AlgorithmIdentifier sigAlgId) { + ASN1ObjectIdentifier sigAlgOid = sigAlgId.getAlgorithm(); ASN1Encodable params = sigAlgId.getParameters(); - - if (params != null && !derNull.equals(params)) + + if (!isAbsentOrEmptyParameters(params)) { - if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) + if (PKCSObjectIdentifiers.id_RSASSA_PSS.equals(sigAlgOid)) { RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params); - + return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "withRSAandMGF1"; } - if (sigAlgId.getAlgorithm().equals(X9ObjectIdentifiers.ecdsa_with_SHA2)) + if (X9ObjectIdentifiers.ecdsa_with_SHA2.equals(sigAlgOid)) { - ASN1Sequence ecDsaParams = ASN1Sequence.getInstance(params); - - return getDigestAlgName((ASN1ObjectIdentifier)ecDsaParams.getObjectAt(0)) + "withECDSA"; + AlgorithmIdentifier ecDsaParams = AlgorithmIdentifier.getInstance(params); + + return getDigestAlgName(ecDsaParams.getAlgorithm()) + "withECDSA"; } } // deal with the "weird" ones. - String algName = (String)algNames.get(sigAlgId.getAlgorithm()); + String algName = (String)algNames.get(sigAlgOid); if (algName != null) { return algName; } - return findAlgName(sigAlgId.getAlgorithm()); + return findAlgName(sigAlgOid); } - + /** * Return the digest algorithm using one of the standard JCA string * representations rather the the algorithm identifier (if possible). @@ -162,7 +188,7 @@ private static String findAlgName(ASN1ObjectIdentifier algOid) private static String lookupAlg(Provider prov, ASN1ObjectIdentifier algOid) { - String algName = prov.getProperty("Alg.Alias.Signature." + algOid); + String algName = prov.getProperty("Alg.Alias.Signature." + algOid); if (algName != null) { diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java index 25c201ed61..bbdc1b21d8 100644 --- a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java +++ b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java @@ -505,7 +505,7 @@ else if (modeName.equals("GCM")) else { ivLength = 12; - cipher = new AEADGenericBlockCipher(new GCMBlockCipher(baseEngine)); + cipher = new AEADGenericBlockCipher(GCMBlockCipher.newInstance(baseEngine)); } } else @@ -1214,7 +1214,7 @@ private boolean isAEADModeName( * The ciphers that inherit from us. */ - static private interface GenericBlockCipher + private static interface GenericBlockCipher { public void init(boolean forEncryption, CipherParameters params) throws IllegalArgumentException; diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CRLEntryObject.java b/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CRLEntryObject.java index af7be81ce9..9b0a50b568 100644 --- a/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CRLEntryObject.java +++ b/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CRLEntryObject.java @@ -12,6 +12,7 @@ import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Enumerated; import org.bouncycastle.asn1.util.ASN1Dump; import org.bouncycastle.asn1.x500.X500Name; @@ -78,9 +79,9 @@ public X509CRLEntryObject( */ public boolean hasUnsupportedCriticalExtension() { - Set extns = getCriticalExtensionOIDs(); + Extensions extensions = c.getExtensions(); - return extns != null && !extns.isEmpty(); + return extensions != null && extensions.hasAnyCriticalExtensions(); } private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCertificateIssuer) @@ -90,16 +91,15 @@ private X500Name loadCertificateIssuer(boolean isIndirect, X500Name previousCert return null; } - byte[] ext = getExtensionValue(X509Extension.certificateIssuer.getId()); - if (ext == null) + ASN1OctetString extValue = Extensions.getExtensionValue(c.getExtensions(), Extension.certificateIssuer); + if (extValue == null) { return previousCertificateIssuer; } try { - GeneralName[] names = GeneralNames.getInstance( - X509ExtensionUtil.fromExtensionValue(ext)).getNames(); + GeneralName[] names = GeneralNames.getInstance(extValue.getOctets()).getNames(); for (int i = 0; i < names.length; i++) { if (names[i].getTagNo() == GeneralName.directoryName) @@ -121,8 +121,8 @@ public X509Principal getCertificateIssuer() { return null; } - try - { + try + { return new X509Principal(certificateIssuer.getEncoded()); } catch (Exception e) @@ -130,6 +130,7 @@ public X509Principal getCertificateIssuer() throw new IllegalStateException(e.toString()); } } + private Set getExtensionOIDs(boolean critical) { Extensions extensions = c.getExtensions(); @@ -168,26 +169,7 @@ public Set getNonCriticalExtensionOIDs() public byte[] getExtensionValue(String oid) { - Extensions exts = c.getExtensions(); - - if (exts != null) - { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - - if (ext != null) - { - try - { - return ext.getExtnValue().getEncoded(); - } - catch (Exception e) - { - throw new RuntimeException("error encoding " + e.toString()); - } - } - } - - return null; + return X509SignatureUtil.getExtensionValue(c.getExtensions(), oid); } /** diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CRLObject.java b/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CRLObject.java index 43fcadc46c..3020ee486b 100644 --- a/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CRLObject.java +++ b/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CRLObject.java @@ -37,9 +37,10 @@ import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.asn1.x509.IssuingDistributionPoint; import org.bouncycastle.asn1.x509.TBSCertList; +import org.bouncycastle.asn1.x509.Time; import org.bouncycastle.jce.X509Principal; -import org.bouncycastle.jce.provider.RFC3280CertPathUtilities; 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.x509.extension.X509ExtensionUtil; @@ -104,30 +105,41 @@ public X509CRLObject( } } - /** - * Will return true if any extensions are present and marked - * as critical as we currently dont handle any extensions! - */ public boolean hasUnsupportedCriticalExtension() { - Set extns = getCriticalExtensionOIDs(); - - if (extns == null) + if (getVersion() == 2) { - return false; - } + Extensions extensions = c.getExtensions(); + if (extensions != null) + { + Enumeration e = extensions.oids(); + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT); - extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR); + if (Extension.issuingDistributionPoint.equals(oid) || + Extension.deltaCRLIndicator.equals(oid)) + { + continue; + } + + Extension ext = extensions.getExtension(oid); + if (ext.isCritical()) + { + return true; + } + } + } + } - return !extns.isEmpty(); + return false; } private Set getExtensionOIDs(boolean critical) { if (this.getVersion() == 2) { - Extensions extensions = c.getTBSCertList().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -164,26 +176,7 @@ public Set getNonCriticalExtensionOIDs() public byte[] getExtensionValue(String oid) { - Extensions exts = c.getTBSCertList().getExtensions(); - - if (exts != null) - { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - - if (ext != null) - { - try - { - return ext.getExtnValue().getEncoded(); - } - catch (Exception e) - { - throw new IllegalStateException("error parsing " + e.toString()); - } - } - } - - return null; + return X509SignatureUtil.getExtensionValue(c.getExtensions(), oid); } public byte[] getEncoded() @@ -252,14 +245,11 @@ public Date getThisUpdate() public Date getNextUpdate() { - if (c.getNextUpdate() != null) - { - return c.getNextUpdate().getDate(); - } + Time nextUpdate = c.getNextUpdate(); - return null; + return null == nextUpdate ? null : nextUpdate.getDate(); } - + private Set loadCRLEntries() { Set entrySet = new HashSet(); @@ -355,16 +345,7 @@ public String getSigAlgOID() public byte[] getSigAlgParams() { - if (sigAlgParams != null) - { - byte[] tmp = new byte[sigAlgParams.length]; - - System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length); - - return tmp; - } - - return null; + return Arrays.clone(sigAlgParams); } /** @@ -406,7 +387,7 @@ public String toString() } } - Extensions extensions = c.getTBSCertList().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CertificateObject.java b/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CertificateObject.java index 21bae59d99..ee198b6196 100644 --- a/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CertificateObject.java +++ b/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CertificateObject.java @@ -34,6 +34,7 @@ import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1OutputStream; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; @@ -57,7 +58,6 @@ import org.bouncycastle.asn1.x509.KeyUsage; import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; import org.bouncycastle.jce.X509Principal; -import org.bouncycastle.jce.provider.RFC3280CertPathUtilities; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; import org.bouncycastle.util.Arrays; @@ -85,7 +85,7 @@ public X509CertificateObject( try { - byte[] bytes = this.getExtensionBytes("2.5.29.19"); + byte[] bytes = getExtensionOctets(c, Extension.basicConstraints); if (bytes != null) { @@ -99,10 +99,10 @@ public X509CertificateObject( try { - byte[] bytes = this.getExtensionBytes("2.5.29.15"); + byte[] bytes = getExtensionOctets(c, Extension.keyUsage); if (bytes != null) { - ASN1BitString bits = ASN1BitString.getInstance(ASN1Primitive.fromByteArray(bytes)); + ASN1BitString bits = ASN1BitString.getInstance(ASN1Primitive.fromByteArray(bytes)); bytes = bits.getBytes(); int length = (bytes.length * 8) - bits.getPadBits(); @@ -314,32 +314,29 @@ public boolean[] getKeyUsage() public List getExtendedKeyUsage() throws CertificateParsingException { - byte[] bytes = this.getExtensionBytes("2.5.29.37"); + byte[] extOctets = getExtensionOctets(c, Extension.extendedKeyUsage); + if (null == extOctets) + { + return null; + } - if (bytes != null) + try { - try - { - ASN1InputStream dIn = new ASN1InputStream(bytes); - ASN1Sequence seq = (ASN1Sequence)dIn.readObject(); - List list = new ArrayList(); + ASN1Sequence seq = ASN1Sequence.getInstance(extOctets); - for (int i = 0; i != seq.size(); i++) - { - list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId()); - } - - return Collections.unmodifiableList(list); - } - catch (Exception e) + List list = new ArrayList(); + for (int i = 0; i != seq.size(); i++) { - throw new CertificateParsingException("error processing extended key usage extension"); + list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId()); } + return Collections.unmodifiableList(list); + } + catch (Exception e) + { + throw new CertificateParsingException("error processing extended key usage extension"); } - - return null; } - + public int getBasicConstraints() { if (basicConstraints != null) @@ -367,13 +364,13 @@ public int getBasicConstraints() public Collection getSubjectAlternativeNames() throws CertificateParsingException { - return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId())); + return getAlternativeNames(c, Extension.subjectAlternativeName); } public Collection getIssuerAlternativeNames() throws CertificateParsingException { - return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId())); + return getAlternativeNames(c, Extension.issuerAlternativeName); } public Set getCriticalExtensionOIDs() @@ -381,7 +378,7 @@ public Set getCriticalExtensionOIDs() if (this.getVersion() == 3) { Set set = new HashSet(); - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -405,44 +402,9 @@ public Set getCriticalExtensionOIDs() return null; } - private byte[] getExtensionBytes(String oid) - { - Extensions exts = c.getTBSCertificate().getExtensions(); - - if (exts != null) - { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - if (ext != null) - { - return ext.getExtnValue().getOctets(); - } - } - - return null; - } - public byte[] getExtensionValue(String oid) { - Extensions exts = c.getTBSCertificate().getExtensions(); - - if (exts != null) - { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - - if (ext != null) - { - try - { - return ext.getExtnValue().getEncoded(); - } - catch (Exception e) - { - throw new IllegalStateException("error parsing " + e.toString()); - } - } - } - - return null; + return X509SignatureUtil.getExtensionValue(c.getExtensions(), oid); } public Set getNonCriticalExtensionOIDs() @@ -450,7 +412,7 @@ public Set getNonCriticalExtensionOIDs() if (this.getVersion() == 3) { Set set = new HashSet(); - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -476,36 +438,32 @@ public Set getNonCriticalExtensionOIDs() public boolean hasUnsupportedCriticalExtension() { - if (this.getVersion() == 3) + if (getVersion() == 3) { - Extensions extensions = c.getTBSCertificate().getExtensions(); - + Extensions extensions = c.getExtensions(); if (extensions != null) { - Enumeration e = extensions.oids(); - + Enumeration e = extensions.oids(); while (e.hasMoreElements()) { ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - String oidId = oid.getId(); - - if (oidId.equals(RFC3280CertPathUtilities.KEY_USAGE) - || oidId.equals(RFC3280CertPathUtilities.CERTIFICATE_POLICIES) - || oidId.equals(RFC3280CertPathUtilities.POLICY_MAPPINGS) - || oidId.equals(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY) - || oidId.equals(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS) - || oidId.equals(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT) - || oidId.equals(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR) - || oidId.equals(RFC3280CertPathUtilities.POLICY_CONSTRAINTS) - || oidId.equals(RFC3280CertPathUtilities.BASIC_CONSTRAINTS) - || oidId.equals(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME) - || oidId.equals(RFC3280CertPathUtilities.NAME_CONSTRAINTS)) + + if (Extension.keyUsage.equals(oid) || + Extension.certificatePolicies.equals(oid) || + Extension.policyMappings.equals(oid) || + Extension.inhibitAnyPolicy.equals(oid) || + Extension.cRLDistributionPoints.equals(oid) || + Extension.issuingDistributionPoint.equals(oid) || + Extension.deltaCRLIndicator.equals(oid) || + Extension.policyConstraints.equals(oid) || + Extension.basicConstraints.equals(oid) || + Extension.subjectAlternativeName.equals(oid) || + Extension.nameConstraints.equals(oid)) { continue; } - Extension ext = extensions.getExtension(oid); - + Extension ext = extensions.getExtension(oid); if (ext.isCritical()) { return true; @@ -646,7 +604,7 @@ public String toString() } } - Extensions extensions = c.getTBSCertificate().getExtensions(); + Extensions extensions = c.getExtensions(); if (extensions != null) { @@ -801,17 +759,18 @@ private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2) return id1.getParameters().equals(id2.getParameters()); } - private static Collection getAlternativeNames(byte[] extVal) + private static Collection getAlternativeNames(org.bouncycastle.asn1.x509.Certificate c, ASN1ObjectIdentifier oid) throws CertificateParsingException { - if (extVal == null) + byte[] extOctets = getExtensionOctets(c, oid); + if (extOctets == null) { return null; } try { Collection temp = new ArrayList(); - Enumeration it = ASN1Sequence.getInstance(extVal).getObjects(); + Enumeration it = ASN1Sequence.getInstance(extOctets).getObjects(); while (it.hasMoreElements()) { GeneralName genName = GeneralName.getInstance(it.nextElement()); @@ -856,4 +815,11 @@ private static Collection getAlternativeNames(byte[] extVal) throw new CertificateParsingException(e.getMessage()); } } + + private static byte[] getExtensionOctets(org.bouncycastle.asn1.x509.Certificate c, ASN1ObjectIdentifier oid) + { + ASN1OctetString extValue = Extensions.getExtensionValue(c.getExtensions(), oid); + + return extValue == null ? null : extValue.getOctets(); + } } diff --git a/prov/src/main/jdk1.3/org/bouncycastle/x509/ExtendedPKIXParameters.java b/prov/src/main/jdk1.3/org/bouncycastle/x509/ExtendedPKIXParameters.java index a79ccdf3ca..2b3e6376e3 100644 --- a/prov/src/main/jdk1.3/org/bouncycastle/x509/ExtendedPKIXParameters.java +++ b/prov/src/main/jdk1.3/org/bouncycastle/x509/ExtendedPKIXParameters.java @@ -499,7 +499,7 @@ public void setTrustedACIssuers(Set trustedACIssuers) { if (trustedACIssuers == null) { - trustedACIssuers.clear(); + this.trustedACIssuers.clear(); return; } for (Iterator it = trustedACIssuers.iterator(); it.hasNext();) diff --git a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/GMKeyPairGeneratorSpi.java b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/GMKeyPairGeneratorSpi.java index e5f472ead6..d69b4188de 100644 --- a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/GMKeyPairGeneratorSpi.java +++ b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/GMKeyPairGeneratorSpi.java @@ -46,7 +46,7 @@ public static class BaseSM2 String algorithm; ProviderConfiguration configuration; - static private Hashtable ecParameters; + private static final Hashtable ecParameters; static { diff --git a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java index 2ca2c524c8..5c7f9e6c59 100644 --- a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java +++ b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java @@ -50,7 +50,7 @@ public static class EC String algorithm; ProviderConfiguration configuration; - static private Hashtable ecParameters; + private static final Hashtable ecParameters; static { ecParameters = new Hashtable(); diff --git a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java index d461361cd9..9b17d648e6 100644 --- a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java +++ b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java @@ -1294,7 +1294,7 @@ private boolean isAEADModeName( * The ciphers that inherit from us. */ - static private interface GenericBlockCipher + private static interface GenericBlockCipher { public void init(boolean forEncryption, CipherParameters params) throws IllegalArgumentException; diff --git a/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/BouncyCastleProvider.java index 7cfaade391..204395efe0 100644 --- a/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/BouncyCastleProvider.java +++ b/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/BouncyCastleProvider.java @@ -51,7 +51,7 @@ public final class BouncyCastleProvider extends Provider implements ConfigurableProvider { - private static String info = "BouncyCastle Security Provider v1.80"; + private static String info = "BouncyCastle Security Provider v1.83"; public static final String PROVIDER_NAME = "BC"; @@ -135,7 +135,7 @@ public final class BouncyCastleProvider extends Provider */ public BouncyCastleProvider() { - super(PROVIDER_NAME, 1.8000, info); + super(PROVIDER_NAME, 1.8300, info); AccessController.doPrivileged(new PrivilegedAction() { diff --git a/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/X509SignatureUtil.java b/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/X509SignatureUtil.java index 3338e07046..8e5c90a3b3 100644 --- a/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/X509SignatureUtil.java +++ b/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/X509SignatureUtil.java @@ -6,27 +6,54 @@ import java.security.SignatureException; import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1Null; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.internal.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.x509.Extensions; +import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers; class X509SignatureUtil { - private static final ASN1Null derNull = DERNull.INSTANCE; - - static void setSignatureParameters( - Signature signature, - ASN1Encodable params) + static byte[] getExtensionValue(Extensions extensions, String oid) + { + if (oid != null) + { + ASN1ObjectIdentifier asn1Oid = ASN1ObjectIdentifier.tryFromID(oid); + if (asn1Oid != null) + { + ASN1OctetString extValue = Extensions.getExtensionValue(extensions, asn1Oid); + if (null != extValue) + { + try + { + return extValue.getEncoded(); + } + catch (Exception e) + { + throw new IllegalStateException("error parsing " + e.toString()); + } + } + } + } + return null; + } + + private static boolean isAbsentOrEmptyParameters(ASN1Encodable parameters) + { + return parameters == null || DERNull.INSTANCE.equals(parameters); + } + + static void setSignatureParameters(Signature signature, ASN1Encodable params) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException { - if (params != null && !derNull.equals(params)) + if (!isAbsentOrEmptyParameters(params)) { /* AlgorithmParameters sigParams = AlgorithmParameters.getInstance(signature.getAlgorithm(), signature.getProvider()); @@ -51,25 +78,31 @@ static void setSignatureParameters( */ } } - - static String getSignatureName( - AlgorithmIdentifier sigAlgId) + + static String getSignatureName(AlgorithmIdentifier sigAlgId) { + ASN1ObjectIdentifier sigAlgOid = sigAlgId.getAlgorithm(); ASN1Encodable params = sigAlgId.getParameters(); - - if (params != null && !derNull.equals(params)) + + if (!isAbsentOrEmptyParameters(params)) { - if (sigAlgId.getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) - { + if (PKCSObjectIdentifiers.id_RSASSA_PSS.equals(sigAlgOid)) + { RSASSAPSSparams rsaParams = RSASSAPSSparams.getInstance(params); - + return getDigestAlgName(rsaParams.getHashAlgorithm().getAlgorithm()) + "withRSAandMGF1"; } + if (X9ObjectIdentifiers.ecdsa_with_SHA2.equals(sigAlgOid)) + { + AlgorithmIdentifier ecDsaParams = AlgorithmIdentifier.getInstance(params); + + return getDigestAlgName(ecDsaParams.getAlgorithm()) + "withECDSA"; + } } - return sigAlgId.getAlgorithm().getId(); + return sigAlgOid.getId(); } - + /** * Return the digest algorithm using one of the standard JCA string * representations rather the the algorithm identifier (if possible). diff --git a/prov/src/main/jdk1.5/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/prov/src/main/jdk1.5/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java index 5ccc3eb33a..8487dd341f 100644 --- a/prov/src/main/jdk1.5/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java +++ b/prov/src/main/jdk1.5/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java @@ -1317,7 +1317,7 @@ private boolean isAEADModeName( * The ciphers that inherit from us. */ - static private interface GenericBlockCipher + private static interface GenericBlockCipher { public void init(boolean forEncryption, CipherParameters params) throws IllegalArgumentException; diff --git a/prov/src/main/jdk1.9/module-info.java b/prov/src/main/jdk1.9/module-info.java index 237e3c8fa2..3e000a9c79 100644 --- a/prov/src/main/jdk1.9/module-info.java +++ b/prov/src/main/jdk1.9/module-info.java @@ -13,6 +13,9 @@ opens org.bouncycastle.pqc.jcajce.provider.lms to java.base; opens org.bouncycastle.pqc.jcajce.provider.falcon to java.base; opens org.bouncycastle.pqc.jcajce.provider.dilithium to java.base; + opens org.bouncycastle.pqc.jcajce.provider.mayo to java.base; + opens org.bouncycastle.pqc.jcajce.provider.snova to java.base; + opens org.bouncycastle.pqc.jcajce.provider.ntruplus to java.base; exports org.bouncycastle; exports org.bouncycastle.asn1; @@ -125,11 +128,12 @@ exports org.bouncycastle.pqc.crypto.mlkem; exports org.bouncycastle.pqc.crypto.falcon; exports org.bouncycastle.pqc.crypto.frodo; - exports org.bouncycastle.pqc.crypto.gemss; exports org.bouncycastle.pqc.crypto.hqc; exports org.bouncycastle.pqc.crypto.lms; + exports org.bouncycastle.pqc.crypto.mayo; exports org.bouncycastle.pqc.crypto.newhope; exports org.bouncycastle.pqc.crypto.ntru; + exports org.bouncycastle.pqc.crypto.ntruplus; exports org.bouncycastle.pqc.crypto.ntruprime; exports org.bouncycastle.pqc.crypto.picnic; exports org.bouncycastle.pqc.crypto.rainbow; @@ -137,6 +141,7 @@ exports org.bouncycastle.pqc.crypto.sphincs; exports org.bouncycastle.pqc.crypto.sphincsplus; exports org.bouncycastle.pqc.crypto.slhdsa; + exports org.bouncycastle.pqc.crypto.snova; exports org.bouncycastle.pqc.crypto.util; exports org.bouncycastle.pqc.crypto.xmss; exports org.bouncycastle.pqc.math.ntru; @@ -148,29 +153,22 @@ exports org.bouncycastle.pqc.jcajce.provider.dilithium; exports org.bouncycastle.pqc.jcajce.provider.falcon; exports org.bouncycastle.pqc.jcajce.provider.frodo; - exports org.bouncycastle.pqc.jcajce.provider.gmss; exports org.bouncycastle.pqc.jcajce.provider.hqc; exports org.bouncycastle.pqc.jcajce.provider.kyber; exports org.bouncycastle.pqc.jcajce.provider.lms; - exports org.bouncycastle.pqc.jcajce.provider.mceliece; + exports org.bouncycastle.pqc.jcajce.provider.mayo; exports org.bouncycastle.pqc.jcajce.provider.ntru; + exports org.bouncycastle.pqc.jcajce.provider.ntruplus; exports org.bouncycastle.pqc.jcajce.provider.ntruprime; exports org.bouncycastle.pqc.jcajce.provider.newhope; exports org.bouncycastle.pqc.jcajce.provider.picnic; - exports org.bouncycastle.pqc.jcajce.provider.rainbow; exports org.bouncycastle.pqc.jcajce.provider.saber; + exports org.bouncycastle.pqc.jcajce.provider.snova; exports org.bouncycastle.pqc.jcajce.provider.sphincs; exports org.bouncycastle.pqc.jcajce.provider.sphincsplus; exports org.bouncycastle.pqc.jcajce.provider.util; exports org.bouncycastle.pqc.jcajce.provider.xmss; exports org.bouncycastle.pqc.jcajce.spec; - exports org.bouncycastle.pqc.legacy.crypto.gmss; - exports org.bouncycastle.pqc.legacy.crypto.gmss.util; - exports org.bouncycastle.pqc.legacy.crypto.qtesla; - exports org.bouncycastle.pqc.legacy.crypto.mceliece; - exports org.bouncycastle.pqc.legacy.crypto.rainbow; - exports org.bouncycastle.pqc.legacy.crypto.rainbow.util; - exports org.bouncycastle.pqc.legacy.math.linearalgebra; exports org.bouncycastle.util; exports org.bouncycastle.util.encoders; exports org.bouncycastle.util.io; diff --git a/prov/src/main/jdk17/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMDecapsulatorSpi.java b/prov/src/main/jdk17/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMDecapsulatorSpi.java new file mode 100644 index 0000000000..619e8965e2 --- /dev/null +++ b/prov/src/main/jdk17/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMDecapsulatorSpi.java @@ -0,0 +1,86 @@ +package org.bouncycastle.jcajce.provider.asymmetric.mlkem; + +import java.util.Objects; + +import javax.crypto.DecapsulateException; +import javax.crypto.KEMSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.jcajce.spec.KTSParameterSpec; +import org.bouncycastle.pqc.crypto.mlkem.MLKEMExtractor; +import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil; +import org.bouncycastle.util.Arrays; + +/* + * NOTE: Per javadoc for javax.crypto.KEM, "Encapsulator and Decapsulator objects are also immutable. It is safe to + * invoke multiple encapsulate and decapsulate methods on the same Encapsulator or Decapsulator object at the same + * time. Each invocation of encapsulate will generate a new shared secret and key encapsulation message." + */ +class MLKEMDecapsulatorSpi + implements KEMSpi.DecapsulatorSpi +{ +// private final BCMLKEMPrivateKey privateKey; + private final KTSParameterSpec parameterSpec; + private final MLKEMExtractor kemExt; + + MLKEMDecapsulatorSpi(BCMLKEMPrivateKey privateKey, KTSParameterSpec parameterSpec) + { +// this.privateKey = privateKey; + this.parameterSpec = parameterSpec; + this.kemExt = new MLKEMExtractor(privateKey.getKeyParams()); + } + + @Override + public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, String algorithm) + throws DecapsulateException + { + Objects.checkFromToIndex(from, to, engineSecretSize()); + Objects.requireNonNull(algorithm, "null algorithm"); + Objects.requireNonNull(encapsulation, "null encapsulation"); + + if (encapsulation.length != engineEncapsulationSize()) + { + throw new DecapsulateException("incorrect encapsulation size"); + } + + String keyAlgName = parameterSpec.getKeyAlgorithmName(); + if (!"Generic".equals(keyAlgName)) + { + // if algorithm is Generic then use parameterSpec to wrap key + if ("Generic".equals(algorithm)) + { + algorithm = keyAlgName; + } + // check spec algorithm mismatch provided algorithm + else if (!algorithm.equals(keyAlgName)) + { + throw new UnsupportedOperationException(keyAlgName + " does not match " + algorithm); + } + } + + byte[] kemSecret = kemExt.extractSecret(encapsulation); + byte[] kdfSecret = KdfUtil.makeKeyBytes(parameterSpec, kemSecret); + + try + { + return new SecretKeySpec(kdfSecret, from, to - from, algorithm); + } + finally + { + Arrays.clear(kdfSecret); + } + } + + @Override + public int engineSecretSize() + { + return parameterSpec.getKeySize() / 8; + } + + @Override + public int engineEncapsulationSize() + { + return kemExt.getEncapsulationLength(); + } +} diff --git a/prov/src/main/jdk17/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMEncapsulatorSpi.java b/prov/src/main/jdk17/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMEncapsulatorSpi.java new file mode 100644 index 0000000000..b7a4265a73 --- /dev/null +++ b/prov/src/main/jdk17/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMEncapsulatorSpi.java @@ -0,0 +1,86 @@ +package org.bouncycastle.jcajce.provider.asymmetric.mlkem; + +import java.security.SecureRandom; +import java.util.Objects; + +import javax.crypto.KEM; +import javax.crypto.KEMSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.crypto.SecretWithEncapsulation; +import org.bouncycastle.jcajce.spec.KTSParameterSpec; +import org.bouncycastle.pqc.crypto.mlkem.MLKEMGenerator; +import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil; +import org.bouncycastle.util.Arrays; + +/* + * NOTE: Per javadoc for javax.crypto.KEM, "Encapsulator and Decapsulator objects are also immutable. It is safe to + * invoke multiple encapsulate and decapsulate methods on the same Encapsulator or Decapsulator object at the same + * time. Each invocation of encapsulate will generate a new shared secret and key encapsulation message." + */ +class MLKEMEncapsulatorSpi + implements KEMSpi.EncapsulatorSpi +{ + private final BCMLKEMPublicKey publicKey; + private final KTSParameterSpec parameterSpec; + private final MLKEMGenerator kemGen; + + MLKEMEncapsulatorSpi(BCMLKEMPublicKey publicKey, KTSParameterSpec parameterSpec, SecureRandom random) + { + this.publicKey = publicKey; + this.parameterSpec = parameterSpec; + this.kemGen = new MLKEMGenerator(random); + } + + @Override + public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm) + { + Objects.checkFromToIndex(from, to, engineSecretSize()); + Objects.requireNonNull(algorithm, "null algorithm"); + + String keyAlgName = parameterSpec.getKeyAlgorithmName(); + if (!"Generic".equals(keyAlgName)) + { + // if algorithm is Generic then use parameterSpec to wrap key + if ("Generic".equals(algorithm)) + { + algorithm = keyAlgName; + } + // check spec algorithm mismatch provided algorithm + else if (!algorithm.equals(keyAlgName)) + { + throw new UnsupportedOperationException(keyAlgName + " does not match " + algorithm); + } + } + + SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(publicKey.getKeyParams()); + + byte[] encapsulation = secEnc.getEncapsulation(); + + byte[] kemSecret = secEnc.getSecret(); + byte[] kdfSecret = KdfUtil.makeKeyBytes(parameterSpec, kemSecret); + + try + { + SecretKey secretKey = new SecretKeySpec(kdfSecret, from, to - from, algorithm); + return new KEM.Encapsulated(secretKey, encapsulation, null); + } + finally + { + Arrays.clear(kdfSecret); + } + } + + @Override + public int engineSecretSize() + { + return parameterSpec.getKeySize() / 8; + } + + @Override + public int engineEncapsulationSize() + { + return publicKey.getKeyParams().getParameters().getEncapsulationLength(); + } +} diff --git a/prov/src/main/jdk17/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMSpi.java b/prov/src/main/jdk17/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMSpi.java new file mode 100644 index 0000000000..a8b89c048e --- /dev/null +++ b/prov/src/main/jdk17/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMSpi.java @@ -0,0 +1,114 @@ +package org.bouncycastle.jcajce.provider.asymmetric.mlkem; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.KEMSpi; + +import org.bouncycastle.jcajce.spec.KTSParameterSpec; +import org.bouncycastle.pqc.crypto.mlkem.MLKEMKeyParameters; +import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters; + +public abstract class MLKEMSpi + implements KEMSpi +{ + private final MLKEMParameters mlkemParameters; + + MLKEMSpi(MLKEMParameters mlkemParameters) + { + this.mlkemParameters = mlkemParameters; + } + + @Override + public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, AlgorithmParameterSpec spec, + SecureRandom secureRandom) throws InvalidAlgorithmParameterException, InvalidKeyException + { + if (!(publicKey instanceof BCMLKEMPublicKey bcPublicKey)) + { + throw new InvalidKeyException("unsupported key type"); + } + + checkKeyParameters(bcPublicKey.getKeyParams()); + + if (spec == null) + { + // Do not wrap key, no KDF + spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build(); + } + else if (!(spec instanceof KTSParameterSpec)) + { + throw new InvalidAlgorithmParameterException("ML-KEM can only accept KTSParameterSpec"); + } + + return new MLKEMEncapsulatorSpi(bcPublicKey, (KTSParameterSpec)spec, secureRandom); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, AlgorithmParameterSpec spec) + throws InvalidAlgorithmParameterException, InvalidKeyException + { + if (!(privateKey instanceof BCMLKEMPrivateKey bcPrivateKey)) + { + throw new InvalidKeyException("unsupported key type"); + } + + checkKeyParameters(bcPrivateKey.getKeyParams()); + + if (spec == null) + { + // Do not unwrap key, no KDF + spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build(); + } + else if (!(spec instanceof KTSParameterSpec)) + { + throw new InvalidAlgorithmParameterException("ML-KEM can only accept KTSParameterSpec"); + } + + return new MLKEMDecapsulatorSpi(bcPrivateKey, (KTSParameterSpec)spec); + } + + private void checkKeyParameters(MLKEMKeyParameters key) throws InvalidKeyException + { + if (mlkemParameters != null && mlkemParameters != key.getParameters()) + { + throw new InvalidKeyException("ML-KEM key mismatch"); + } + } + + public static class MLKEM extends MLKEMSpi + { + public MLKEM() + { + // NOTE: Unrestricted parameters/keys + super(null); + } + } + + public static class MLKEM512 extends MLKEMSpi + { + public MLKEM512() + { + super(MLKEMParameters.ml_kem_512); + } + } + + public static class MLKEM768 extends MLKEMSpi + { + public MLKEM768() + { + super(MLKEMParameters.ml_kem_768); + } + } + + public static class MLKEM1024 extends MLKEMSpi + { + public MLKEM1024() + { + super(MLKEMParameters.ml_kem_1024); + } + } +} diff --git a/prov/src/main/jdk17/org/bouncycastle/jcajce/util/SpiUtil.java b/prov/src/main/jdk17/org/bouncycastle/jcajce/util/SpiUtil.java new file mode 100644 index 0000000000..dacd6a5d22 --- /dev/null +++ b/prov/src/main/jdk17/org/bouncycastle/jcajce/util/SpiUtil.java @@ -0,0 +1,15 @@ +package org.bouncycastle.jcajce.util; + +public abstract class SpiUtil +{ + public static boolean hasKDF() + { + return false; + } + + public static boolean hasKEM() + { + // TODO Dynamic check for javax.crypto.KEMSpi (added in 21 and backported to 17 MR 1) + return true; + } +} diff --git a/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/hqc/HQCDecapsulatorSpi.java b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/hqc/HQCDecapsulatorSpi.java new file mode 100644 index 0000000000..b0861b5351 --- /dev/null +++ b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/hqc/HQCDecapsulatorSpi.java @@ -0,0 +1,86 @@ +package org.bouncycastle.pqc.jcajce.provider.hqc; + +import java.util.Objects; + +import javax.crypto.DecapsulateException; +import javax.crypto.KEMSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.jcajce.spec.KTSParameterSpec; +import org.bouncycastle.pqc.crypto.hqc.HQCKEMExtractor; +import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil; +import org.bouncycastle.util.Arrays; + +/* + * NOTE: Per javadoc for javax.crypto.KEM, "Encapsulator and Decapsulator objects are also immutable. It is safe to + * invoke multiple encapsulate and decapsulate methods on the same Encapsulator or Decapsulator object at the same + * time. Each invocation of encapsulate will generate a new shared secret and key encapsulation message." + */ +class HQCDecapsulatorSpi + implements KEMSpi.DecapsulatorSpi +{ +// private final BCHQCPrivateKey privateKey; + private final KTSParameterSpec parameterSpec; + private final HQCKEMExtractor kemExt; + + HQCDecapsulatorSpi(BCHQCPrivateKey privateKey, KTSParameterSpec parameterSpec) + { +// this.privateKey = privateKey; + this.parameterSpec = parameterSpec; + this.kemExt = new HQCKEMExtractor(privateKey.getKeyParams()); + } + + @Override + public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, String algorithm) + throws DecapsulateException + { + Objects.checkFromToIndex(from, to, engineSecretSize()); + Objects.requireNonNull(algorithm, "null algorithm"); + Objects.requireNonNull(encapsulation, "null encapsulation"); + + if (encapsulation.length != engineEncapsulationSize()) + { + throw new DecapsulateException("incorrect encapsulation size"); + } + + String keyAlgName = parameterSpec.getKeyAlgorithmName(); + if (!"Generic".equals(keyAlgName)) + { + // if algorithm is Generic then use parameterSpec to wrap key + if ("Generic".equals(algorithm)) + { + algorithm = keyAlgName; + } + // check spec algorithm mismatch provided algorithm + else if (!algorithm.equals(keyAlgName)) + { + throw new UnsupportedOperationException(keyAlgName + " does not match " + algorithm); + } + } + + byte[] kemSecret = kemExt.extractSecret(encapsulation); + byte[] kdfSecret = KdfUtil.makeKeyBytes(parameterSpec, kemSecret); + + try + { + return new SecretKeySpec(kdfSecret, from, to - from, algorithm); + } + finally + { + Arrays.clear(kdfSecret); + } + } + + @Override + public int engineSecretSize() + { + return parameterSpec.getKeySize() / 8; + } + + @Override + public int engineEncapsulationSize() + { + return kemExt.getEncapsulationLength(); + } +} diff --git a/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/hqc/HQCEncapsulatorSpi.java b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/hqc/HQCEncapsulatorSpi.java new file mode 100644 index 0000000000..9fd498df34 --- /dev/null +++ b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/hqc/HQCEncapsulatorSpi.java @@ -0,0 +1,86 @@ +package org.bouncycastle.pqc.jcajce.provider.hqc; + +import java.security.SecureRandom; +import java.util.Objects; + +import javax.crypto.KEM; +import javax.crypto.KEMSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.crypto.SecretWithEncapsulation; +import org.bouncycastle.jcajce.spec.KTSParameterSpec; +import org.bouncycastle.pqc.crypto.hqc.HQCKEMGenerator; +import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil; +import org.bouncycastle.util.Arrays; + +/* + * NOTE: Per javadoc for javax.crypto.KEM, "Encapsulator and Decapsulator objects are also immutable. It is safe to + * invoke multiple encapsulate and decapsulate methods on the same Encapsulator or Decapsulator object at the same + * time. Each invocation of encapsulate will generate a new shared secret and key encapsulation message." + */ +class HQCEncapsulatorSpi + implements KEMSpi.EncapsulatorSpi +{ + private final BCHQCPublicKey publicKey; + private final KTSParameterSpec parameterSpec; + private final HQCKEMGenerator kemGen; + + HQCEncapsulatorSpi(BCHQCPublicKey publicKey, KTSParameterSpec parameterSpec, SecureRandom random) + { + this.publicKey = publicKey; + this.parameterSpec = parameterSpec; + this.kemGen = new HQCKEMGenerator(random); + } + + @Override + public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm) + { + Objects.checkFromToIndex(from, to, engineSecretSize()); + Objects.requireNonNull(algorithm, "null algorithm"); + + String keyAlgName = parameterSpec.getKeyAlgorithmName(); + if (!"Generic".equals(keyAlgName)) + { + // if algorithm is Generic then use parameterSpec to wrap key + if ("Generic".equals(algorithm)) + { + algorithm = keyAlgName; + } + // check spec algorithm mismatch provided algorithm + else if (!algorithm.equals(keyAlgName)) + { + throw new UnsupportedOperationException(keyAlgName + " does not match " + algorithm); + } + } + + SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(publicKey.getKeyParams()); + + byte[] encapsulation = secEnc.getEncapsulation(); + + byte[] kemSecret = secEnc.getSecret(); + byte[] kdfSecret = KdfUtil.makeKeyBytes(parameterSpec, kemSecret); + + try + { + SecretKey secretKey = new SecretKeySpec(kdfSecret, from, to - from, algorithm); + return new KEM.Encapsulated(secretKey, encapsulation, null); + } + finally + { + Arrays.clear(kdfSecret); + } + } + + @Override + public int engineSecretSize() + { + return parameterSpec.getKeySize() / 8; + } + + @Override + public int engineEncapsulationSize() + { + return publicKey.getKeyParams().getParameters().getEncapsulationLength(); + } +} diff --git a/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKEMSpi.java b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKEMSpi.java new file mode 100644 index 0000000000..6057bd9c43 --- /dev/null +++ b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/hqc/HQCKEMSpi.java @@ -0,0 +1,114 @@ +package org.bouncycastle.pqc.jcajce.provider.hqc; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.KEMSpi; + +import org.bouncycastle.jcajce.spec.KTSParameterSpec; +import org.bouncycastle.pqc.crypto.hqc.HQCKeyParameters; +import org.bouncycastle.pqc.crypto.hqc.HQCParameters; + +public abstract class HQCKEMSpi + implements KEMSpi +{ + private final HQCParameters hqcParameters; + + HQCKEMSpi(HQCParameters hqcParameters) + { + this.hqcParameters = hqcParameters; + } + + @Override + public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, AlgorithmParameterSpec spec, + SecureRandom secureRandom) throws InvalidAlgorithmParameterException, InvalidKeyException + { + if (!(publicKey instanceof BCHQCPublicKey bcPublicKey)) + { + throw new InvalidKeyException("unsupported key type"); + } + + checkKeyParameters(bcPublicKey.getKeyParams()); + + if (spec == null) + { + // Do not wrap key, no KDF + spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build(); + } + else if (!(spec instanceof KTSParameterSpec)) + { + throw new InvalidAlgorithmParameterException("HQC can only accept KTSParameterSpec"); + } + + return new HQCEncapsulatorSpi(bcPublicKey, (KTSParameterSpec)spec, secureRandom); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, AlgorithmParameterSpec spec) + throws InvalidAlgorithmParameterException, InvalidKeyException + { + if (!(privateKey instanceof BCHQCPrivateKey bcPrivateKey)) + { + throw new InvalidKeyException("unsupported key type"); + } + + checkKeyParameters(bcPrivateKey.getKeyParams()); + + if (spec == null) + { + // Do not unwrap key, no KDF + spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build(); + } + else if (!(spec instanceof KTSParameterSpec)) + { + throw new InvalidAlgorithmParameterException("HQC can only accept KTSParameterSpec"); + } + + return new HQCDecapsulatorSpi(bcPrivateKey, (KTSParameterSpec)spec); + } + + private void checkKeyParameters(HQCKeyParameters key) throws InvalidKeyException + { + if (hqcParameters != null && hqcParameters != key.getParameters()) + { + throw new InvalidKeyException("HQC key mismatch"); + } + } + + public static class HQC extends HQCKEMSpi + { + public HQC() + { + // NOTE: Unrestricted parameters/keys + super(null); + } + } + + public static class HQC128 extends HQCKEMSpi + { + public HQC128() + { + super(HQCParameters.hqc128); + } + } + + public static class HQC192 extends HQCKEMSpi + { + public HQC192() + { + super(HQCParameters.hqc192); + } + } + + public static class HQC256 extends HQCKEMSpi + { + public HQC256() + { + super(HQCParameters.hqc256); + } + } +} diff --git a/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUDecapsulatorSpi.java b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUDecapsulatorSpi.java new file mode 100644 index 0000000000..823e2dffc2 --- /dev/null +++ b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUDecapsulatorSpi.java @@ -0,0 +1,86 @@ +package org.bouncycastle.pqc.jcajce.provider.ntru; + +import java.util.Objects; + +import javax.crypto.DecapsulateException; +import javax.crypto.KEMSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.jcajce.spec.KTSParameterSpec; +import org.bouncycastle.pqc.crypto.ntru.NTRUKEMExtractor; +import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil; +import org.bouncycastle.util.Arrays; + +/* + * NOTE: Per javadoc for javax.crypto.KEM, "Encapsulator and Decapsulator objects are also immutable. It is safe to + * invoke multiple encapsulate and decapsulate methods on the same Encapsulator or Decapsulator object at the same + * time. Each invocation of encapsulate will generate a new shared secret and key encapsulation message." + */ +class NTRUDecapsulatorSpi + implements KEMSpi.DecapsulatorSpi +{ +// private final BCNTRUPrivateKey privateKey; + private final KTSParameterSpec parameterSpec; + private final NTRUKEMExtractor kemExt; + + NTRUDecapsulatorSpi(BCNTRUPrivateKey privateKey, KTSParameterSpec parameterSpec) + { +// this.privateKey = privateKey; + this.parameterSpec = parameterSpec; + this.kemExt = new NTRUKEMExtractor(privateKey.getKeyParams()); + } + + @Override + public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, String algorithm) + throws DecapsulateException + { + Objects.checkFromToIndex(from, to, engineSecretSize()); + Objects.requireNonNull(algorithm, "null algorithm"); + Objects.requireNonNull(encapsulation, "null encapsulation"); + + if (encapsulation.length != engineEncapsulationSize()) + { + throw new DecapsulateException("incorrect encapsulation size"); + } + + String keyAlgName = parameterSpec.getKeyAlgorithmName(); + if (!"Generic".equals(keyAlgName)) + { + // if algorithm is Generic then use parameterSpec to wrap key + if ("Generic".equals(algorithm)) + { + algorithm = keyAlgName; + } + // check spec algorithm mismatch provided algorithm + else if (!algorithm.equals(keyAlgName)) + { + throw new UnsupportedOperationException(keyAlgName + " does not match " + algorithm); + } + } + + byte[] kemSecret = kemExt.extractSecret(encapsulation); + byte[] kdfSecret = KdfUtil.makeKeyBytes(parameterSpec, kemSecret); + + try + { + return new SecretKeySpec(kdfSecret, from, to - from, algorithm); + } + finally + { + Arrays.clear(kdfSecret); + } + } + + @Override + public int engineSecretSize() + { + return parameterSpec.getKeySize() / 8; + } + + @Override + public int engineEncapsulationSize() + { + return kemExt.getEncapsulationLength(); + } +} diff --git a/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUEncapsulatorSpi.java b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUEncapsulatorSpi.java new file mode 100644 index 0000000000..99fa652516 --- /dev/null +++ b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUEncapsulatorSpi.java @@ -0,0 +1,86 @@ +package org.bouncycastle.pqc.jcajce.provider.ntru; + +import java.security.SecureRandom; +import java.util.Objects; + +import javax.crypto.KEM; +import javax.crypto.KEMSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.crypto.SecretWithEncapsulation; +import org.bouncycastle.jcajce.spec.KTSParameterSpec; +import org.bouncycastle.pqc.crypto.ntru.NTRUKEMGenerator; +import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil; +import org.bouncycastle.util.Arrays; + +/* + * NOTE: Per javadoc for javax.crypto.KEM, "Encapsulator and Decapsulator objects are also immutable. It is safe to + * invoke multiple encapsulate and decapsulate methods on the same Encapsulator or Decapsulator object at the same + * time. Each invocation of encapsulate will generate a new shared secret and key encapsulation message." + */ +class NTRUEncapsulatorSpi + implements KEMSpi.EncapsulatorSpi +{ + private final BCNTRUPublicKey publicKey; + private final KTSParameterSpec parameterSpec; + private final NTRUKEMGenerator kemGen; + + NTRUEncapsulatorSpi(BCNTRUPublicKey publicKey, KTSParameterSpec parameterSpec, SecureRandom random) + { + this.publicKey = publicKey; + this.parameterSpec = parameterSpec; + this.kemGen = new NTRUKEMGenerator(random); + } + + @Override + public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm) + { + Objects.checkFromToIndex(from, to, engineSecretSize()); + Objects.requireNonNull(algorithm, "null algorithm"); + + String keyAlgName = parameterSpec.getKeyAlgorithmName(); + if (!"Generic".equals(keyAlgName)) + { + // if algorithm is Generic then use parameterSpec to wrap key + if ("Generic".equals(algorithm)) + { + algorithm = keyAlgName; + } + // check spec algorithm mismatch provided algorithm + else if (!algorithm.equals(keyAlgName)) + { + throw new UnsupportedOperationException(keyAlgName + " does not match " + algorithm); + } + } + + SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(publicKey.getKeyParams()); + + byte[] encapsulation = secEnc.getEncapsulation(); + + byte[] kemSecret = secEnc.getSecret(); + byte[] kdfSecret = KdfUtil.makeKeyBytes(parameterSpec, kemSecret); + + try + { + SecretKey secretKey = new SecretKeySpec(kdfSecret, from, to - from, algorithm); + return new KEM.Encapsulated(secretKey, encapsulation, null); + } + finally + { + Arrays.clear(kdfSecret); + } + } + + @Override + public int engineSecretSize() + { + return parameterSpec.getKeySize() / 8; + } + + @Override + public int engineEncapsulationSize() + { + return publicKey.getKeyParams().getParameters().getEncapsulationLength(); + } +} diff --git a/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKEMSpi.java b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKEMSpi.java new file mode 100644 index 0000000000..0584f2eac5 --- /dev/null +++ b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKEMSpi.java @@ -0,0 +1,90 @@ +package org.bouncycastle.pqc.jcajce.provider.ntru; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.KEMSpi; + +import org.bouncycastle.jcajce.spec.KTSParameterSpec; +import org.bouncycastle.pqc.crypto.ntru.NTRUKeyParameters; +import org.bouncycastle.pqc.crypto.ntru.NTRUParameters; + +public abstract class NTRUKEMSpi + implements KEMSpi +{ + private final NTRUParameters ntruParameters; + + NTRUKEMSpi(NTRUParameters ntruParameters) + { + this.ntruParameters = ntruParameters; + } + + @Override + public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, AlgorithmParameterSpec spec, + SecureRandom secureRandom) throws InvalidAlgorithmParameterException, InvalidKeyException + { + if (!(publicKey instanceof BCNTRUPublicKey bcPublicKey)) + { + throw new InvalidKeyException("unsupported key type"); + } + + checkKeyParameters(bcPublicKey.getKeyParams()); + + if (spec == null) + { + // Do not wrap key, no KDF + spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build(); + } + else if (!(spec instanceof KTSParameterSpec)) + { + throw new InvalidAlgorithmParameterException("NTRU can only accept KTSParameterSpec"); + } + + return new NTRUEncapsulatorSpi(bcPublicKey, (KTSParameterSpec)spec, secureRandom); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, AlgorithmParameterSpec spec) + throws InvalidAlgorithmParameterException, InvalidKeyException + { + if (!(privateKey instanceof BCNTRUPrivateKey bcPrivateKey)) + { + throw new InvalidKeyException("unsupported key type"); + } + + checkKeyParameters(bcPrivateKey.getKeyParams()); + + if (spec == null) + { + // Do not unwrap key, no KDF + spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build(); + } + else if (!(spec instanceof KTSParameterSpec)) + { + throw new InvalidAlgorithmParameterException("NTRU can only accept KTSParameterSpec"); + } + + return new NTRUDecapsulatorSpi(bcPrivateKey, (KTSParameterSpec)spec); + } + + private void checkKeyParameters(NTRUKeyParameters key) throws InvalidKeyException + { + if (ntruParameters != null && ntruParameters != key.getParameters()) + { + throw new InvalidKeyException("NTRU key mismatch"); + } + } + + public static class NTRU extends NTRUKEMSpi + { + public NTRU() + { + // NOTE: Unrestricted parameters/keys + super(null); + } + } +} diff --git a/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java new file mode 100644 index 0000000000..45cb048ff9 --- /dev/null +++ b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java @@ -0,0 +1,86 @@ +package org.bouncycastle.pqc.jcajce.provider.ntruprime; + +import java.util.Objects; + +import javax.crypto.DecapsulateException; +import javax.crypto.KEMSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.jcajce.spec.KTSParameterSpec; +import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMExtractor; +import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil; +import org.bouncycastle.util.Arrays; + +/* + * NOTE: Per javadoc for javax.crypto.KEM, "Encapsulator and Decapsulator objects are also immutable. It is safe to + * invoke multiple encapsulate and decapsulate methods on the same Encapsulator or Decapsulator object at the same + * time. Each invocation of encapsulate will generate a new shared secret and key encapsulation message." + */ +class SNTRUPrimeDecapsulatorSpi + implements KEMSpi.DecapsulatorSpi +{ +// private final BCSNTRUPrimePrivateKey privateKey; + private final KTSParameterSpec parameterSpec; + private final SNTRUPrimeKEMExtractor kemExt; + + SNTRUPrimeDecapsulatorSpi(BCSNTRUPrimePrivateKey privateKey, KTSParameterSpec parameterSpec) + { +// this.privateKey = privateKey; + this.parameterSpec = parameterSpec; + this.kemExt = new SNTRUPrimeKEMExtractor(privateKey.getKeyParams()); + } + + @Override + public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, String algorithm) + throws DecapsulateException + { + Objects.checkFromToIndex(from, to, engineSecretSize()); + Objects.requireNonNull(algorithm, "null algorithm"); + Objects.requireNonNull(encapsulation, "null encapsulation"); + + if (encapsulation.length != engineEncapsulationSize()) + { + throw new DecapsulateException("incorrect encapsulation size"); + } + + String keyAlgName = parameterSpec.getKeyAlgorithmName(); + if (!"Generic".equals(keyAlgName)) + { + // if algorithm is Generic then use parameterSpec to wrap key + if ("Generic".equals(algorithm)) + { + algorithm = keyAlgName; + } + // check spec algorithm mismatch provided algorithm + else if (!algorithm.equals(keyAlgName)) + { + throw new UnsupportedOperationException(keyAlgName + " does not match " + algorithm); + } + } + + byte[] kemSecret = kemExt.extractSecret(encapsulation); + byte[] kdfSecret = KdfUtil.makeKeyBytes(parameterSpec, kemSecret); + + try + { + return new SecretKeySpec(kdfSecret, from, to - from, algorithm); + } + finally + { + Arrays.clear(kdfSecret); + } + } + + @Override + public int engineSecretSize() + { + return parameterSpec.getKeySize() / 8; + } + + @Override + public int engineEncapsulationSize() + { + return kemExt.getEncapsulationLength(); + } +} diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java similarity index 50% rename from prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java rename to prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java index 13698138a7..f4e60a4cb5 100644 --- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java +++ b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java @@ -1,18 +1,24 @@ package org.bouncycastle.pqc.jcajce.provider.ntruprime; +import java.security.SecureRandom; +import java.util.Objects; + +import javax.crypto.KEM; +import javax.crypto.KEMSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + import org.bouncycastle.crypto.SecretWithEncapsulation; import org.bouncycastle.jcajce.spec.KTSParameterSpec; import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMGenerator; import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil; import org.bouncycastle.util.Arrays; -import javax.crypto.KEM; -import javax.crypto.KEMSpi; -import javax.crypto.spec.SecretKeySpec; -import java.security.InvalidKeyException; -import java.security.SecureRandom; -import java.util.Objects; - +/* + * NOTE: Per javadoc for javax.crypto.KEM, "Encapsulator and Decapsulator objects are also immutable. It is safe to + * invoke multiple encapsulate and decapsulate methods on the same Encapsulator or Decapsulator object at the same + * time. Each invocation of encapsulate will generate a new shared secret and key encapsulation message." + */ class SNTRUPrimeEncapsulatorSpi implements KEMSpi.EncapsulatorSpi { @@ -20,13 +26,11 @@ class SNTRUPrimeEncapsulatorSpi private final KTSParameterSpec parameterSpec; private final SNTRUPrimeKEMGenerator kemGen; - - public SNTRUPrimeEncapsulatorSpi(BCSNTRUPrimePublicKey publicKey, KTSParameterSpec parameterSpec, SecureRandom random) + SNTRUPrimeEncapsulatorSpi(BCSNTRUPrimePublicKey publicKey, KTSParameterSpec parameterSpec, SecureRandom random) { this.publicKey = publicKey; this.parameterSpec = parameterSpec; - - kemGen = new SNTRUPrimeKEMGenerator(random); + this.kemGen = new SNTRUPrimeKEMGenerator(random); } @Override @@ -35,31 +39,37 @@ public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm) Objects.checkFromToIndex(from, to, engineSecretSize()); Objects.requireNonNull(algorithm, "null algorithm"); - // if algorithm is Generic then use parameterSpec to wrap key - if (!parameterSpec.getKeyAlgorithmName().equals("Generic") && - algorithm.equals("Generic")) - { - algorithm = parameterSpec.getKeyAlgorithmName(); - } - - // check spec algorithm mismatch provided algorithm - if (!parameterSpec.getKeyAlgorithmName().equals("Generic") && - !parameterSpec.getKeyAlgorithmName().equals(algorithm)) + String keyAlgName = parameterSpec.getKeyAlgorithmName(); + if (!"Generic".equals(keyAlgName)) { - throw new UnsupportedOperationException(parameterSpec.getKeyAlgorithmName() + " does not match " + algorithm); + // if algorithm is Generic then use parameterSpec to wrap key + if ("Generic".equals(algorithm)) + { + algorithm = keyAlgName; + } + // check spec algorithm mismatch provided algorithm + else if (!algorithm.equals(keyAlgName)) + { + throw new UnsupportedOperationException(keyAlgName + " does not match " + algorithm); + } } - // Only use KDF when ktsParameterSpec is provided - // Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(publicKey.getKeyParams()); byte[] encapsulation = secEnc.getEncapsulation(); - byte[] secret = secEnc.getSecret(); - byte[] secretKey = Arrays.copyOfRange(KdfUtil.makeKeyBytes(parameterSpec, secret), from, to); - - return new KEM.Encapsulated(new SecretKeySpec(secretKey, algorithm), encapsulation, null); //TODO: DER encoding for params + byte[] kemSecret = secEnc.getSecret(); + byte[] kdfSecret = KdfUtil.makeKeyBytes(parameterSpec, kemSecret); + try + { + SecretKey secretKey = new SecretKeySpec(kdfSecret, from, to - from, algorithm); + return new KEM.Encapsulated(secretKey, encapsulation, null); + } + finally + { + Arrays.clear(kdfSecret); + } } @Override diff --git a/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKEMSpi.java b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKEMSpi.java new file mode 100644 index 0000000000..4a321664fa --- /dev/null +++ b/prov/src/main/jdk17/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKEMSpi.java @@ -0,0 +1,90 @@ +package org.bouncycastle.pqc.jcajce.provider.ntruprime; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.KEMSpi; + +import org.bouncycastle.jcajce.spec.KTSParameterSpec; +import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKeyParameters; +import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeParameters; + +public abstract class SNTRUPrimeKEMSpi + implements KEMSpi +{ + private final SNTRUPrimeParameters sntruPrimeParameters; + + SNTRUPrimeKEMSpi(SNTRUPrimeParameters sntruPrimeParameters) + { + this.sntruPrimeParameters = sntruPrimeParameters; + } + + @Override + public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, AlgorithmParameterSpec spec, + SecureRandom secureRandom) throws InvalidAlgorithmParameterException, InvalidKeyException + { + if (!(publicKey instanceof BCSNTRUPrimePublicKey bcPublicKey)) + { + throw new InvalidKeyException("unsupported key type"); + } + + checkKeyParameters(bcPublicKey.getKeyParams()); + + if (spec == null) + { + // Do not wrap key, no KDF + spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build(); + } + else if (!(spec instanceof KTSParameterSpec)) + { + throw new InvalidAlgorithmParameterException("SNTRUPrime can only accept KTSParameterSpec"); + } + + return new SNTRUPrimeEncapsulatorSpi(bcPublicKey, (KTSParameterSpec)spec, secureRandom); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, AlgorithmParameterSpec spec) + throws InvalidAlgorithmParameterException, InvalidKeyException + { + if (!(privateKey instanceof BCSNTRUPrimePrivateKey bcPrivateKey)) + { + throw new InvalidKeyException("unsupported key type"); + } + + checkKeyParameters(bcPrivateKey.getKeyParams()); + + if (spec == null) + { + // Do not unwrap key, no KDF + spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build(); + } + else if (!(spec instanceof KTSParameterSpec)) + { + throw new InvalidAlgorithmParameterException("SNTRUPrime can only accept KTSParameterSpec"); + } + + return new SNTRUPrimeDecapsulatorSpi(bcPrivateKey, (KTSParameterSpec)spec); + } + + private void checkKeyParameters(SNTRUPrimeKeyParameters key) throws InvalidKeyException + { + if (sntruPrimeParameters != null && sntruPrimeParameters != key.getParameters()) + { + throw new InvalidKeyException("SNTRUPrime key mismatch"); + } + } + + public static class SNTRUPrime extends SNTRUPrimeKEMSpi + { + public SNTRUPrime() + { + // NOTE: Unrestricted parameters/keys + super(null); + } + } +} diff --git a/prov/src/main/jdk21/org/bouncycastle/jcajce/provider/asymmetric/MLKEM.java b/prov/src/main/jdk21/org/bouncycastle/jcajce/provider/asymmetric/MLKEM.java deleted file mode 100644 index b9013ee4b6..0000000000 --- a/prov/src/main/jdk21/org/bouncycastle/jcajce/provider/asymmetric/MLKEM.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.bouncycastle.jcajce.provider.asymmetric; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; -import org.bouncycastle.jcajce.provider.asymmetric.mlkem.MLKEMKeyFactorySpi; -import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; -import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; -import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; - -public class MLKEM -{ - private static final String PREFIX = "org.bouncycastle.jcajce.provider.asymmetric" + ".mlkem."; - - public static class Mappings - extends AsymmetricAlgorithmProvider - { - public Mappings() - { - } - - public void configure(ConfigurableProvider provider) - { - provider.addAlgorithm("KeyFactory.ML-KEM", PREFIX + "MLKEMKeyFactorySpi"); - provider.addAlgorithm("Alg.Alias.KeyFactory.MLKEM", "ML-KEM"); - - addKeyFactoryAlgorithm(provider, "ML-KEM-512", PREFIX + "MLKEMKeyFactorySpi$MLKEM512", NISTObjectIdentifiers.id_alg_ml_kem_512, new MLKEMKeyFactorySpi.MLKEM512()); - addKeyFactoryAlgorithm(provider, "ML-KEM-768", PREFIX + "MLKEMKeyFactorySpi$MLKEM768", NISTObjectIdentifiers.id_alg_ml_kem_768, new MLKEMKeyFactorySpi.MLKEM768()); - addKeyFactoryAlgorithm(provider, "ML-KEM-1024", PREFIX + "MLKEMKeyFactorySpi$MLKEM1024", NISTObjectIdentifiers.id_alg_ml_kem_1024, new MLKEMKeyFactorySpi.MLKEM1024()); - - provider.addAlgorithm("KeyPairGenerator.ML-KEM", PREFIX + "MLKEMKeyPairGeneratorSpi"); - provider.addAlgorithm("Alg.Alias.KeyPairGenerator.MLKEM", "ML-KEM"); - - addKeyPairGeneratorAlgorithm(provider, "ML-KEM-512", PREFIX + "MLKEMKeyPairGeneratorSpi$MLKEM512", NISTObjectIdentifiers.id_alg_ml_kem_512); - addKeyPairGeneratorAlgorithm(provider, "ML-KEM-768", PREFIX + "MLKEMKeyPairGeneratorSpi$MLKEM768", NISTObjectIdentifiers.id_alg_ml_kem_768); - addKeyPairGeneratorAlgorithm(provider, "ML-KEM-1024", PREFIX + "MLKEMKeyPairGeneratorSpi$MLKEM1024", NISTObjectIdentifiers.id_alg_ml_kem_1024); - - provider.addAlgorithm("KeyGenerator.ML-KEM", PREFIX + "MLKEMKeyGeneratorSpi"); - - addKeyGeneratorAlgorithm(provider, "ML-KEM-512", PREFIX + "MLKEMKeyGeneratorSpi$MLKEM512", NISTObjectIdentifiers.id_alg_ml_kem_512); - addKeyGeneratorAlgorithm(provider, "ML-KEM-768", PREFIX + "MLKEMKeyGeneratorSpi$MLKEM768", NISTObjectIdentifiers.id_alg_ml_kem_768); - addKeyGeneratorAlgorithm(provider, "ML-KEM-1024", PREFIX + "MLKEMKeyGeneratorSpi$MLKEM1024", NISTObjectIdentifiers.id_alg_ml_kem_1024); - - AsymmetricKeyInfoConverter keyFact = new MLKEMKeyFactorySpi(); - - provider.addAlgorithm("Cipher.ML-KEM", PREFIX + "MLKEMCipherSpi$Base"); - provider.addAlgorithm("Alg.Alias.Cipher.MLKEM", "ML-KEM"); - - addCipherAlgorithm(provider, "ML-KEM-512", PREFIX + "MLKEMCipherSpi$MLKEM512", NISTObjectIdentifiers.id_alg_ml_kem_512); - addCipherAlgorithm(provider, "ML-KEM-768", PREFIX + "MLKEMCipherSpi$MLKEM768", NISTObjectIdentifiers.id_alg_ml_kem_768); - addCipherAlgorithm(provider, "ML-KEM-1024", PREFIX + "MLKEMCipherSpi$MLKEM1024", NISTObjectIdentifiers.id_alg_ml_kem_1024); - - provider.addKeyInfoConverter(NISTObjectIdentifiers.id_alg_ml_kem_512, keyFact); - provider.addKeyInfoConverter(NISTObjectIdentifiers.id_alg_ml_kem_768, keyFact); - provider.addKeyInfoConverter(NISTObjectIdentifiers.id_alg_ml_kem_1024, keyFact); - - provider.addAlgorithm("KEM.ML-KEM", PREFIX + "MLKEMSpi"); - provider.addAlgorithm("Alg.Alias.KEM." + NISTObjectIdentifiers.id_alg_ml_kem_512, "ML-KEM"); - provider.addAlgorithm("Alg.Alias.KEM." + NISTObjectIdentifiers.id_alg_ml_kem_768, "ML-KEM"); - provider.addAlgorithm("Alg.Alias.KEM." + NISTObjectIdentifiers.id_alg_ml_kem_1024, "ML-KEM"); - } - } -} diff --git a/prov/src/main/jdk21/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMDecapsulatorSpi.java b/prov/src/main/jdk21/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMDecapsulatorSpi.java deleted file mode 100644 index 30f3e94f99..0000000000 --- a/prov/src/main/jdk21/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMDecapsulatorSpi.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.bouncycastle.jcajce.provider.asymmetric.mlkem; - -import org.bouncycastle.jcajce.provider.asymmetric.mlkem.BCMLKEMPrivateKey; -import org.bouncycastle.jcajce.spec.KTSParameterSpec; -import org.bouncycastle.pqc.crypto.mlkem.MLKEMExtractor; -import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil; - -import javax.crypto.DecapsulateException; -import javax.crypto.KEMSpi; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; -import java.security.InvalidKeyException; -import java.util.Arrays; -import java.util.Objects; - -public class MLKEMDecapsulatorSpi - implements KEMSpi.DecapsulatorSpi -{ - BCMLKEMPrivateKey privateKey; - KTSParameterSpec parameterSpec; - MLKEMExtractor kemExt; - - public MLKEMDecapsulatorSpi(BCMLKEMPrivateKey privateKey, KTSParameterSpec parameterSpec) - { - this.privateKey = privateKey; - this.parameterSpec = parameterSpec; - - this.kemExt = new MLKEMExtractor(privateKey.getKeyParams()); - } - - @Override - public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, String algorithm) throws DecapsulateException - { - Objects.checkFromToIndex(from, to, engineSecretSize()); - Objects.requireNonNull(algorithm, "null algorithm"); - Objects.requireNonNull(encapsulation, "null encapsulation"); - - if (encapsulation.length != engineEncapsulationSize()) - { - throw new DecapsulateException("incorrect encapsulation size"); - } - - // if algorithm is Generic then use parameterSpec to wrap key - if (!parameterSpec.getKeyAlgorithmName().equals("Generic") && - algorithm.equals("Generic")) - { - algorithm = parameterSpec.getKeyAlgorithmName(); - } - - // check spec algorithm mismatch provided algorithm - if (!parameterSpec.getKeyAlgorithmName().equals("Generic") && - !parameterSpec.getKeyAlgorithmName().equals(algorithm)) - { - throw new UnsupportedOperationException(parameterSpec.getKeyAlgorithmName() + " does not match " + algorithm); - } - - // Only use KDF when ktsParameterSpec is provided - // Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided - boolean useKDF = parameterSpec.getKdfAlgorithm() != null; - - byte[] secret = kemExt.extractSecret(encapsulation); - byte[] secretKey = Arrays.copyOfRange(KdfUtil.makeKeyBytes(parameterSpec, secret), from, to); - - return new SecretKeySpec(secretKey, algorithm); - } - - @Override - public int engineSecretSize() - { - return parameterSpec.getKeySize() / 8; - } - - @Override - public int engineEncapsulationSize() - { - return kemExt.getEncapsulationLength(); - } -} diff --git a/prov/src/main/jdk21/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMEncapsulatorSpi.java b/prov/src/main/jdk21/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMEncapsulatorSpi.java deleted file mode 100644 index 4f453da7ae..0000000000 --- a/prov/src/main/jdk21/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMEncapsulatorSpi.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.bouncycastle.jcajce.provider.asymmetric.mlkem; - -import org.bouncycastle.crypto.SecretWithEncapsulation; -import org.bouncycastle.jcajce.provider.asymmetric.mlkem.BCMLKEMPublicKey; -import org.bouncycastle.jcajce.spec.KTSParameterSpec; -import org.bouncycastle.pqc.crypto.mlkem.MLKEMGenerator; -import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil; - -import javax.crypto.KEM; -import javax.crypto.KEMSpi; -import javax.crypto.spec.SecretKeySpec; -import java.security.InvalidKeyException; -import java.security.SecureRandom; -import java.util.Arrays; -import java.util.Objects; - -public class MLKEMEncapsulatorSpi - implements KEMSpi.EncapsulatorSpi -{ - private final BCMLKEMPublicKey publicKey; - private final KTSParameterSpec parameterSpec; - private final MLKEMGenerator kemGen; - - public MLKEMEncapsulatorSpi(BCMLKEMPublicKey publicKey, KTSParameterSpec parameterSpec, SecureRandom random) - { - this.publicKey = publicKey; - this.parameterSpec = parameterSpec; - - this.kemGen = new MLKEMGenerator(random); - } - - - @Override - public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm) - { - Objects.checkFromToIndex(from, to, engineSecretSize()); - Objects.requireNonNull(algorithm, "null algorithm"); - - // if algorithm is Generic then use parameterSpec to wrap key - if (!parameterSpec.getKeyAlgorithmName().equals("Generic") && - algorithm.equals("Generic")) - { - algorithm = parameterSpec.getKeyAlgorithmName(); - } - - // check spec algorithm mismatch provided algorithm - if (!parameterSpec.getKeyAlgorithmName().equals("Generic") && - !parameterSpec.getKeyAlgorithmName().equals(algorithm)) - { - throw new UnsupportedOperationException(parameterSpec.getKeyAlgorithmName() + " does not match " + algorithm); - } - - // Only use KDF when ktsParameterSpec is provided - // Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided - boolean useKDF = parameterSpec.getKdfAlgorithm() != null; - - SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(publicKey.getKeyParams()); - - byte[] encapsulation = secEnc.getEncapsulation(); - byte[] secret = secEnc.getSecret(); - byte[] secretKey = Arrays.copyOfRange(KdfUtil.makeKeyBytes(parameterSpec, secret), from, to); - - return new KEM.Encapsulated(new SecretKeySpec(secretKey, algorithm), encapsulation, null); //TODO: DER encoding for params } - } - - @Override - public int engineSecretSize() - { - return parameterSpec.getKeySize() / 8; - } - - - @Override - public int engineEncapsulationSize() - { - //TODO: Maybe make parameterSet public or add getEncapsulationSize() in KEMGenerator.java - switch (publicKey.getKeyParams().getParameters().getName()) - { - case "ML-KEM-512": - return 768; - case "ML-KEM-768": - return 1088; - case "ML-KEM-1024": - return 1568; - default: - return -1; - } - } -} diff --git a/prov/src/main/jdk21/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMSpi.java b/prov/src/main/jdk21/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMSpi.java deleted file mode 100644 index db4fed4ff4..0000000000 --- a/prov/src/main/jdk21/org/bouncycastle/jcajce/provider/asymmetric/mlkem/MLKEMSpi.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.bouncycastle.jcajce.provider.asymmetric.mlkem; - -import org.bouncycastle.jcajce.provider.asymmetric.mlkem.BCMLKEMPrivateKey; -import org.bouncycastle.jcajce.provider.asymmetric.mlkem.BCMLKEMPublicKey; -import org.bouncycastle.jcajce.spec.KTSParameterSpec; - -import javax.crypto.KEMSpi; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; - -public class MLKEMSpi - implements KEMSpi -{ - @Override - public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, AlgorithmParameterSpec spec, SecureRandom secureRandom) - throws InvalidAlgorithmParameterException, InvalidKeyException - { - if (!(publicKey instanceof BCMLKEMPublicKey)) - { - throw new InvalidKeyException("unsupported key"); - } - if (spec == null) - { - // Do not wrap key, no KDF - spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build(); - } - if (!(spec instanceof KTSParameterSpec)) - { - throw new InvalidAlgorithmParameterException("MLKEM can only accept KTSParameterSpec"); - } - if (secureRandom == null) - { - secureRandom = new SecureRandom(); - } - return new MLKEMEncapsulatorSpi((BCMLKEMPublicKey) publicKey, (KTSParameterSpec) spec, secureRandom); - } - - @Override - public DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, AlgorithmParameterSpec spec) - throws InvalidAlgorithmParameterException, InvalidKeyException - { - if (!(privateKey instanceof BCMLKEMPrivateKey)) - { - throw new InvalidKeyException("unsupported key"); - } - if (spec == null) - { - // Do not unwrap key, no KDF - spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build(); - } - if (!(spec instanceof KTSParameterSpec)) - { - throw new InvalidAlgorithmParameterException("MLKEM can only accept KTSParameterSpec"); - } - return new MLKEMDecapsulatorSpi((BCMLKEMPrivateKey) privateKey, (KTSParameterSpec) spec); - } -} diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/NTRU.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/NTRU.java deleted file mode 100644 index aa4377f28f..0000000000 --- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/NTRU.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider; - -import org.bouncycastle.asn1.bc.BCObjectIdentifiers; -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.jcajce.provider.ntru.NTRUKeyFactorySpi; - -public class NTRU -{ - private static final String PREFIX = "org.bouncycastle.pqc.jcajce.provider" + ".ntru."; - - public static class Mappings - extends AsymmetricAlgorithmProvider - { - public Mappings() - { - } - - public void configure(ConfigurableProvider provider) - { - provider.addAlgorithm("KeyFactory.NTRU", PREFIX + "NTRUKeyFactorySpi"); - provider.addAlgorithm("KeyPairGenerator.NTRU", PREFIX + "NTRUKeyPairGeneratorSpi"); - - provider.addAlgorithm("KeyGenerator.NTRU", PREFIX + "NTRUKeyGeneratorSpi"); - - AsymmetricKeyInfoConverter keyFact = new NTRUKeyFactorySpi(); - - provider.addAlgorithm("Cipher.NTRU", PREFIX + "NTRUCipherSpi$Base"); - provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.pqc_kem_ntru, "NTRU"); - - registerOid(provider, BCObjectIdentifiers.ntruhps2048509, "NTRU", keyFact); - registerOid(provider, BCObjectIdentifiers.ntruhps2048677, "NTRU", keyFact); - registerOid(provider, BCObjectIdentifiers.ntruhps4096821, "NTRU", keyFact); - registerOid(provider, BCObjectIdentifiers.ntruhps40961229, "NTRU", keyFact); - registerOid(provider, BCObjectIdentifiers.ntruhrss701, "NTRU", keyFact); - registerOid(provider, BCObjectIdentifiers.ntruhrss1373, "NTRU", keyFact); - - provider.addAlgorithm("Kem.NTRU", PREFIX + "NTRUKEMSpi"); - provider.addAlgorithm("Alg.Alias.Kem." + BCObjectIdentifiers.pqc_kem_ntru, "NTRU"); - } - } -} \ No newline at end of file diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/NTRUPrime.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/NTRUPrime.java deleted file mode 100644 index 3501d6e969..0000000000 --- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/NTRUPrime.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider; - -import org.bouncycastle.asn1.bc.BCObjectIdentifiers; -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.jcajce.provider.ntruprime.NTRULPRimeKeyFactorySpi; -import org.bouncycastle.pqc.jcajce.provider.ntruprime.SNTRUPrimeKeyFactorySpi; - -public class NTRUPrime -{ - private static final String PREFIX = "org.bouncycastle.pqc.jcajce.provider" + ".ntruprime."; - - public static class Mappings - extends AsymmetricAlgorithmProvider - { - public Mappings() - { - } - - public void configure(ConfigurableProvider provider) - { - provider.addAlgorithm("KeyFactory.NTRULPRIME", PREFIX + "NTRULPRimeKeyFactorySpi"); - provider.addAlgorithm("KeyPairGenerator.NTRULPRIME", PREFIX + "NTRULPRimeKeyPairGeneratorSpi"); - - provider.addAlgorithm("KeyGenerator.NTRULPRIME", PREFIX + "NTRULPRimeKeyGeneratorSpi"); - - AsymmetricKeyInfoConverter keyFact = new NTRULPRimeKeyFactorySpi(); - - provider.addAlgorithm("Cipher.NTRULPRIME", PREFIX + "NTRULPRimeCipherSpi$Base"); - provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.pqc_kem_ntrulprime, "NTRU"); - - registerOid(provider, BCObjectIdentifiers.ntrulpr653, "NTRULPRIME", keyFact); - registerOid(provider, BCObjectIdentifiers.ntrulpr761, "NTRULPRIME", keyFact); - registerOid(provider, BCObjectIdentifiers.ntrulpr857, "NTRULPRIME", keyFact); - registerOid(provider, BCObjectIdentifiers.ntrulpr953, "NTRULPRIME", keyFact); - registerOid(provider, BCObjectIdentifiers.ntrulpr1013, "NTRULPRIME", keyFact); - registerOid(provider, BCObjectIdentifiers.ntrulpr1277, "NTRULPRIME", keyFact); - - provider.addAlgorithm("KeyFactory.SNTRUPRIME", PREFIX + "SNTRUPrimeKeyFactorySpi"); - provider.addAlgorithm("KeyPairGenerator.SNTRUPRIME", PREFIX + "SNTRUPrimeKeyPairGeneratorSpi"); - - provider.addAlgorithm("KeyGenerator.SNTRUPRIME", PREFIX + "SNTRUPrimeKeyGeneratorSpi"); - - keyFact = new SNTRUPrimeKeyFactorySpi(); - - provider.addAlgorithm("Cipher.SNTRUPRIME", PREFIX + "SNTRUPrimeCipherSpi$Base"); - provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.pqc_kem_sntruprime, "NTRU"); - - registerOid(provider, BCObjectIdentifiers.sntrup653, "SNTRUPRIME", keyFact); - registerOid(provider, BCObjectIdentifiers.sntrup761, "SNTRUPRIME", keyFact); - registerOid(provider, BCObjectIdentifiers.sntrup857, "SNTRUPRIME", keyFact); - registerOid(provider, BCObjectIdentifiers.sntrup953, "SNTRUPRIME", keyFact); - registerOid(provider, BCObjectIdentifiers.sntrup1013, "SNTRUPRIME", keyFact); - registerOid(provider, BCObjectIdentifiers.sntrup1277, "SNTRUPRIME", keyFact); - - provider.addAlgorithm("Kem.SNTRUPRIME", PREFIX + "SNTRUPrimeKEMSpi"); - provider.addAlgorithm("Alg.Alias.Kem." + BCObjectIdentifiers.pqc_kem_sntruprime, "SNTRUPRIME"); - } - } -} \ No newline at end of file diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUDecapsulatorSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUDecapsulatorSpi.java deleted file mode 100644 index 71c174efa9..0000000000 --- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUDecapsulatorSpi.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.ntru; - -import org.bouncycastle.jcajce.spec.KTSParameterSpec; - -import org.bouncycastle.jcajce.spec.KTSParameterSpec; -import org.bouncycastle.pqc.crypto.ntru.NTRUKEMExtractor; -import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil; - -import javax.crypto.DecapsulateException; -import javax.crypto.KEMSpi; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; -import java.security.InvalidKeyException; -import java.util.Arrays; -import java.util.Objects; - -public class NTRUDecapsulatorSpi - implements KEMSpi.DecapsulatorSpi -{ - BCNTRUPrivateKey privateKey; - KTSParameterSpec parameterSpec; - NTRUKEMExtractor kemExt; - - public NTRUDecapsulatorSpi(BCNTRUPrivateKey privateKey, KTSParameterSpec parameterSpec) - { - this.privateKey = privateKey; - this.parameterSpec = parameterSpec; - - this.kemExt = new NTRUKEMExtractor(privateKey.getKeyParams()); - } - - @Override - public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, String algorithm) throws DecapsulateException - { - Objects.checkFromToIndex(from, to, engineSecretSize()); - Objects.requireNonNull(algorithm, "null algorithm"); - Objects.requireNonNull(encapsulation, "null encapsulation"); - - if (encapsulation.length != engineEncapsulationSize()) - { - throw new DecapsulateException("incorrect encapsulation size"); - } - - // if algorithm is Generic then use parameterSpec to wrap key - if (!parameterSpec.getKeyAlgorithmName().equals("Generic") && - algorithm.equals("Generic")) - { - algorithm = parameterSpec.getKeyAlgorithmName(); - } - - // check spec algorithm mismatch provided algorithm - if (!parameterSpec.getKeyAlgorithmName().equals("Generic") && - !parameterSpec.getKeyAlgorithmName().equals(algorithm)) - { - throw new UnsupportedOperationException(parameterSpec.getKeyAlgorithmName() + " does not match " + algorithm); - } - - // Only use KDF when ktsParameterSpec is provided - // Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided - boolean useKDF = parameterSpec.getKdfAlgorithm() != null; - - byte[] secret = kemExt.extractSecret(encapsulation); - byte[] secretKey = Arrays.copyOfRange(KdfUtil.makeKeyBytes(parameterSpec, secret), from, to); - - return new SecretKeySpec(secretKey, algorithm); - } - - @Override - public int engineSecretSize() - { - return parameterSpec.getKeySize() / 8; - } - - @Override - public int engineEncapsulationSize() - { - return kemExt.getEncapsulationLength(); - } -} diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUEncapsulatorSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUEncapsulatorSpi.java deleted file mode 100644 index fea938b4ee..0000000000 --- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUEncapsulatorSpi.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.ntru; - -import org.bouncycastle.crypto.SecretWithEncapsulation; -import org.bouncycastle.jcajce.spec.KTSParameterSpec; -import org.bouncycastle.pqc.crypto.ntru.NTRUKEMGenerator; -import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil; - -import javax.crypto.KEM; -import javax.crypto.KEMSpi; -import javax.crypto.spec.SecretKeySpec; -import java.security.InvalidKeyException; -import java.security.SecureRandom; -import java.util.Arrays; -import java.util.Objects; - -public class NTRUEncapsulatorSpi - implements KEMSpi.EncapsulatorSpi -{ - private final BCNTRUPublicKey publicKey; - private final KTSParameterSpec parameterSpec; - private final NTRUKEMGenerator kemGen; - - public NTRUEncapsulatorSpi(BCNTRUPublicKey publicKey, KTSParameterSpec parameterSpec, SecureRandom random) - { - this.publicKey = publicKey; - this.parameterSpec = parameterSpec; - - this.kemGen = new NTRUKEMGenerator(random); - } - - @Override - public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm) - { - Objects.checkFromToIndex(from, to, engineSecretSize()); - Objects.requireNonNull(algorithm, "null algorithm"); - - // if algorithm is Generic then use parameterSpec to wrap key - if (!parameterSpec.getKeyAlgorithmName().equals("Generic") && - algorithm.equals("Generic")) - { - algorithm = parameterSpec.getKeyAlgorithmName(); - } - - // check spec algorithm mismatch provided algorithm - if (!parameterSpec.getKeyAlgorithmName().equals("Generic") && - !parameterSpec.getKeyAlgorithmName().equals(algorithm)) - { - throw new UnsupportedOperationException(parameterSpec.getKeyAlgorithmName() + " does not match " + algorithm); - } - - // Only use KDF when ktsParameterSpec is provided - // Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided - boolean useKDF = parameterSpec.getKdfAlgorithm() != null; - - SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(publicKey.getKeyParams()); - - byte[] encapsulation = secEnc.getEncapsulation(); - byte[] secret = secEnc.getSecret(); - byte[] secretKey = Arrays.copyOfRange(KdfUtil.makeKeyBytes(parameterSpec, secret), from, to); - - return new KEM.Encapsulated(new SecretKeySpec(secretKey, algorithm), encapsulation, null); //TODO: DER encoding for params - } - - @Override - public int engineSecretSize() - { - return parameterSpec.getKeySize() / 8; - } - - @Override - public int engineEncapsulationSize() - { - //TODO: Maybe make parameterSet public or add getEncapsulationSize() in NTRUKEMGenerator.java - switch (publicKey.getKeyParams().getParameters().getName()) - { - case "ntruhps2048509": - return 699; - case "ntruhps2048677": - return 930; - case "ntruhps4096821": - return 1230; - case "ntruhps40961229": - return 1843; - case "ntruhrss701": - return 1138; - case "ntruhrss1373": - return 2401; - default: - return -1; - } - } -} diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKEMSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKEMSpi.java deleted file mode 100644 index 77b7a2bf54..0000000000 --- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKEMSpi.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.ntru; - -import org.bouncycastle.jcajce.spec.KTSParameterSpec; -import org.bouncycastle.pqc.jcajce.provider.ntru.BCNTRUPrivateKey; -import org.bouncycastle.pqc.jcajce.provider.ntru.NTRUDecapsulatorSpi; - -import javax.crypto.KEMSpi; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; - -public class NTRUKEMSpi - implements KEMSpi -{ - - @Override - public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, AlgorithmParameterSpec spec, SecureRandom secureRandom) - throws InvalidAlgorithmParameterException, InvalidKeyException - { - if (!(publicKey instanceof BCNTRUPublicKey)) - { - throw new InvalidKeyException("unsupported key"); - } - if (spec == null) - { - // Do not wrap key, no KDF - spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build(); - } - if (!(spec instanceof KTSParameterSpec)) - { - throw new InvalidAlgorithmParameterException("NTRU can only accept KTSParameterSpec"); - } - if (secureRandom == null) - { - secureRandom = new SecureRandom(); - } - return new NTRUEncapsulatorSpi((BCNTRUPublicKey) publicKey, (KTSParameterSpec) spec, secureRandom); - } - - @Override - public DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, AlgorithmParameterSpec spec) - throws InvalidAlgorithmParameterException, InvalidKeyException - { - if (!(privateKey instanceof BCNTRUPrivateKey)) - { - throw new InvalidKeyException("unsupported key"); - } - if (spec == null) - { - // Do not unwrap key, no KDF - spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build(); - } - if (!(spec instanceof KTSParameterSpec)) - { - throw new InvalidAlgorithmParameterException("NTRU can only accept KTSParameterSpec"); - } - return new NTRUDecapsulatorSpi((BCNTRUPrivateKey) privateKey, (KTSParameterSpec) spec); - } -} diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java deleted file mode 100644 index 945237dca6..0000000000 --- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.ntruprime; - -import org.bouncycastle.jcajce.spec.KTSParameterSpec; -import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMExtractor; -import org.bouncycastle.pqc.jcajce.provider.util.KdfUtil; -import org.bouncycastle.util.Arrays; - -import javax.crypto.DecapsulateException; -import javax.crypto.KEMSpi; -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; -import java.security.InvalidKeyException; -import java.util.Objects; - -class SNTRUPrimeDecapsulatorSpi - implements KEMSpi.DecapsulatorSpi -{ - BCSNTRUPrimePrivateKey privateKey; - KTSParameterSpec parameterSpec; - - SNTRUPrimeKEMExtractor kemExt; - - public SNTRUPrimeDecapsulatorSpi(BCSNTRUPrimePrivateKey privateKey, KTSParameterSpec parameterSpec) - { - this.privateKey = privateKey; - this.parameterSpec = parameterSpec; - - kemExt = new SNTRUPrimeKEMExtractor(privateKey.getKeyParams()); - } - - @Override - public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, String algorithm) throws DecapsulateException - { - Objects.checkFromToIndex(from, to, engineSecretSize()); - Objects.requireNonNull(algorithm, "null algorithm"); - Objects.requireNonNull(encapsulation, "null encapsulation"); - - if (encapsulation.length != engineEncapsulationSize()) - { - throw new DecapsulateException("incorrect encapsulation size"); - } - - // if algorithm is Generic then use parameterSpec to wrap key - if (!parameterSpec.getKeyAlgorithmName().equals("Generic") && - algorithm.equals("Generic")) - { - algorithm = parameterSpec.getKeyAlgorithmName(); - } - - // check spec algorithm mismatch provided algorithm - if (!parameterSpec.getKeyAlgorithmName().equals("Generic") && - !parameterSpec.getKeyAlgorithmName().equals(algorithm)) - { - throw new UnsupportedOperationException(parameterSpec.getKeyAlgorithmName() + " does not match " + algorithm); - } - - // Only use KDF when ktsParameterSpec is provided - // Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided - byte[] secret = kemExt.extractSecret(encapsulation); - - byte[] secretKey = Arrays.copyOfRange(KdfUtil.makeKeyBytes(parameterSpec, secret), from, to); - - return new SecretKeySpec(secretKey, algorithm); - } - - @Override - public int engineSecretSize() - { - return parameterSpec.getKeySize() / 8; - } - - @Override - public int engineEncapsulationSize() - { - return kemExt.getEncapsulationLength(); - } -} diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKEMSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKEMSpi.java deleted file mode 100644 index 64be2c116e..0000000000 --- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKEMSpi.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.ntruprime; - -import org.bouncycastle.jcajce.spec.KTSParameterSpec; - -import javax.crypto.KEMSpi; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; - -public class SNTRUPrimeKEMSpi - implements KEMSpi -{ - - @Override - public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, AlgorithmParameterSpec spec, SecureRandom secureRandom) throws InvalidAlgorithmParameterException, InvalidKeyException - { - if (!(publicKey instanceof BCSNTRUPrimePublicKey)) - { - throw new InvalidKeyException("unsupported key"); - } - if (spec == null) - { - // Do not wrap key, no KDF - spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build(); - } - if (!(spec instanceof KTSParameterSpec)) - { - throw new InvalidAlgorithmParameterException("SNTRUPrime can only accept KTSParameterSpec"); - } - if (secureRandom == null) - { - secureRandom = new SecureRandom(); - } - return new SNTRUPrimeEncapsulatorSpi((BCSNTRUPrimePublicKey) publicKey,(KTSParameterSpec) spec, secureRandom); - } - - @Override - public DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, AlgorithmParameterSpec spec) throws InvalidAlgorithmParameterException, InvalidKeyException - { - if (!(privateKey instanceof BCSNTRUPrimePrivateKey)) - { - throw new InvalidKeyException("unsupported key"); - } - if (spec == null) - { - // Do not unwrap key, no KDF - spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build(); - } - if (!(spec instanceof KTSParameterSpec)) - { - throw new InvalidAlgorithmParameterException("SNTRUPrime can only accept KTSParameterSpec"); - } - return new SNTRUPrimeDecapsulatorSpi((BCSNTRUPrimePrivateKey) privateKey, (KTSParameterSpec) spec); - } -} diff --git a/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/HKDF.java b/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/HKDF.java new file mode 100644 index 0000000000..bcfc2c2a0f --- /dev/null +++ b/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/HKDF.java @@ -0,0 +1,35 @@ +package org.bouncycastle.jcajce.provider.kdf; + +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import org.bouncycastle.jcajce.provider.util.AlgorithmProvider; + +public class HKDF +{ + private static final String PREFIX = "org.bouncycastle.jcajce.provider.kdf" + ".hkdf."; + + public static class Mappings + extends AlgorithmProvider + { + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + /* + * TODO Would need HKDFSpi to be public, have a constructor from KDFParameters, and have some way to + * decide which digest to use. + */ +// provider.addAlgorithm("KDF.HKDF", PREFIX + "HKDFSpi"); + + provider.addAlgorithm("KDF.HKDF-SHA256", PREFIX + "HKDFSpi$HKDFwithSHA256"); + provider.addAlgorithm("KDF.HKDF-SHA384", PREFIX + "HKDFSpi$HKDFwithSHA384"); + provider.addAlgorithm("KDF.HKDF-SHA512", PREFIX + "HKDFSpi$HKDFwithSHA512"); + + provider.addAlgorithm("Alg.Alias.KDF." + PKCSObjectIdentifiers.id_alg_hkdf_with_sha256, "HKDF-SHA256"); + provider.addAlgorithm("Alg.Alias.KDF." + PKCSObjectIdentifiers.id_alg_hkdf_with_sha384, "HKDF-SHA384"); + provider.addAlgorithm("Alg.Alias.KDF." + PKCSObjectIdentifiers.id_alg_hkdf_with_sha512, "HKDF-SHA512"); + } + } +} diff --git a/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/PBEPBKDF2.java b/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/PBEPBKDF2.java new file mode 100644 index 0000000000..2aabe7c618 --- /dev/null +++ b/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/PBEPBKDF2.java @@ -0,0 +1,45 @@ +package org.bouncycastle.jcajce.provider.kdf; + +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import org.bouncycastle.jcajce.provider.util.AlgorithmProvider; + +class PBEPBKDF2 +{ + private static final String PREFIX = "org.bouncycastle.jcajce.provider.kdf" + ".pbepbkdf2."; + + public static class Mappings + extends AlgorithmProvider + { + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { +// provider.addAlgorithm("AlgorithmParameters.PBKDF2", PREFIX + "PBEPBKDF2Spi$AlgParams"); +// provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_PBKDF2, "PBKDF2"); + provider.addAlgorithm("KDF.PBKDF2", PREFIX + "PBEPBKDF2Spi$PBKDF2withUTF8"); + provider.addAlgorithm("Alg.Alias.KDF.PBKDF2WITHHMACSHA1", "PBKDF2"); + provider.addAlgorithm("Alg.Alias.KDF.PBKDF2WITHHMACSHA1ANDUTF8", "PBKDF2"); + provider.addAlgorithm("Alg.Alias.KDF." + PKCSObjectIdentifiers.id_PBKDF2, "PBKDF2"); + provider.addAlgorithm("KDF.PBKDF2WITHASCII", PREFIX + "PBEPBKDF2Spi$PBKDF2with8BIT"); + provider.addAlgorithm("Alg.Alias.KDF.PBKDF2WITH8BIT", "PBKDF2WITHASCII"); + provider.addAlgorithm("Alg.Alias.KDF.PBKDF2WITHHMACSHA1AND8BIT", "PBKDF2WITHASCII"); + provider.addAlgorithm("KDF.PBKDF2WITHHMACSHA224", PREFIX + "PBEPBKDF2Spi$PBKDF2withSHA224"); + provider.addAlgorithm("KDF.PBKDF2WITHHMACSHA256", PREFIX + "PBEPBKDF2Spi$PBKDF2withSHA256"); + provider.addAlgorithm("KDF.PBKDF2WITHHMACSHA384", PREFIX + "PBEPBKDF2Spi$PBKDF2withSHA384"); + provider.addAlgorithm("KDF.PBKDF2WITHHMACSHA512", PREFIX + "PBEPBKDF2Spi$PBKDF2withSHA512"); + provider.addAlgorithm("KDF.PBKDF2WITHHMACSHA512-224", PREFIX + "PBEPBKDF2Spi$PBKDF2withSHA512_224"); + provider.addAlgorithm("KDF.PBKDF2WITHHMACSHA512-256", PREFIX + "PBEPBKDF2Spi$PBKDF2withSHA512_256"); + provider.addAlgorithm("KDF.PBKDF2WITHHMACSHA3-224", PREFIX + "PBEPBKDF2Spi$PBKDF2withSHA3_224"); + provider.addAlgorithm("KDF.PBKDF2WITHHMACSHA3-256", PREFIX + "PBEPBKDF2Spi$PBKDF2withSHA3_256"); + provider.addAlgorithm("KDF.PBKDF2WITHHMACSHA3-384", PREFIX + "PBEPBKDF2Spi$PBKDF2withSHA3_384"); + provider.addAlgorithm("KDF.PBKDF2WITHHMACSHA3-512", PREFIX + "PBEPBKDF2Spi$PBKDF2withSHA3_512"); + provider.addAlgorithm("KDF.PBKDF2WITHHMACGOST3411", PREFIX + "PBEPBKDF2Spi$PBKDF2withGOST3411"); + provider.addAlgorithm("KDF.PBKDF2WITHHMACSM3", PREFIX + "PBEPBKDF2Spi$PBKDF2withSM3"); + + + } + } +} diff --git a/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/SCRYPT.java b/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/SCRYPT.java new file mode 100644 index 0000000000..62d27a8c54 --- /dev/null +++ b/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/SCRYPT.java @@ -0,0 +1,22 @@ +package org.bouncycastle.jcajce.provider.kdf; + +import org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import org.bouncycastle.jcajce.provider.util.AlgorithmProvider; + +class SCRYPT +{ + private static final String PREFIX = "org.bouncycastle.jcajce.provider.kdf" + ".scrypt."; + + public static class Mappings + extends AlgorithmProvider + { + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + provider.addAlgorithm("KDF.SCRYPT", PREFIX + "ScryptSpi$ScryptWithUTF8"); + } + } +} diff --git a/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/hkdf/HKDFSpi.java b/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/hkdf/HKDFSpi.java new file mode 100644 index 0000000000..bc84721c44 --- /dev/null +++ b/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/hkdf/HKDFSpi.java @@ -0,0 +1,215 @@ +package org.bouncycastle.jcajce.provider.kdf.hkdf; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.AlgorithmParameterSpec; +import java.util.ArrayList; +import java.util.List; + +import javax.crypto.KDFParameters; +import javax.crypto.KDFSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.HKDFParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.digests.SHA384Digest; +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.generators.HKDFBytesGenerator; +import org.bouncycastle.crypto.params.HKDFParameters; +import org.bouncycastle.util.Arrays; + +public class HKDFSpi extends KDFSpi +{ + private final HKDFBytesGenerator hkdf; + + HKDFSpi(KDFParameters kdfParameters, Digest digest) + throws InvalidAlgorithmParameterException + { + super(requireNull(kdfParameters, "HKDF" + " does not support parameters")); + this.hkdf = new HKDFBytesGenerator(digest); + } + + /** + * Returns the {@code KDFParameters} used with this {@code KDF} object. + *

    + * The returned parameters may be the same that were used to initialize + * this {@code KDF} object, or may contain additional default or + * random parameter values used by the underlying KDF algorithm. + * If the required parameters were not supplied and can be generated by + * the {@code KDF} object, the generated parameters are returned; + * otherwise {@code null} is returned. + * + * @return the parameters used with this {@code KDF} object, or + * {@code null} + */ + @Override + protected KDFParameters engineGetParameters() + { + return null; + } + + @Override + protected SecretKey engineDeriveKey(String alg, AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException, NoSuchAlgorithmException + { + byte[] derivedKey = engineDeriveData(derivationSpec); + + try + { + return new SecretKeySpec(derivedKey, alg); + } + finally + { + Arrays.clear(derivedKey); + } + } + + @Override + protected byte[] engineDeriveData(AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException + { + if (derivationSpec instanceof org.bouncycastle.jcajce.spec.HKDFParameterSpec) + { + org.bouncycastle.jcajce.spec.HKDFParameterSpec spec = (org.bouncycastle.jcajce.spec.HKDFParameterSpec)derivationSpec; + + byte[] ikm = spec.getIKM(); + byte[] salt = spec.getSalt(); + byte[] info = spec.getInfo(); + + return expand(spec.getOutputLength(), new HKDFParameters(ikm, salt, info)); + } + + if (!(derivationSpec instanceof HKDFParameterSpec)) + { + throw new InvalidAlgorithmParameterException("Invalid AlgorithmParameterSpec provided"); + } + + if (derivationSpec instanceof HKDFParameterSpec.Expand) + { + HKDFParameterSpec.Expand spec = (HKDFParameterSpec.Expand)derivationSpec; + + byte[] ikm = spec.prk().getEncoded(); + byte[] info = spec.info(); + + return expand(spec.length(), HKDFParameters.skipExtractParameters(ikm, info)); + } + else if (derivationSpec instanceof HKDFParameterSpec.Extract) + { + HKDFParameterSpec.Extract spec = (HKDFParameterSpec.Extract)derivationSpec; + + byte[] ikm = flattenSecretKeys(spec.ikms()); + byte[] salt = flattenSecretKeys(spec.salts()); + + return hkdf.extractPRK(salt, ikm); + } + else if (derivationSpec instanceof HKDFParameterSpec.ExtractThenExpand) + { + HKDFParameterSpec.ExtractThenExpand spec = (HKDFParameterSpec.ExtractThenExpand)derivationSpec; + + byte[] ikm = flattenSecretKeys(spec.ikms()); + byte[] salt = flattenSecretKeys(spec.salts()); + byte[] info = spec.info(); + + return expand(spec.length(), new HKDFParameters(ikm, salt, info)); + } + else if (derivationSpec instanceof org.bouncycastle.jcajce.spec.HKDFParameterSpec) + { + org.bouncycastle.jcajce.spec.HKDFParameterSpec spec = (org.bouncycastle.jcajce.spec.HKDFParameterSpec)derivationSpec; + + byte[] ikm = spec.getIKM(); + byte[] salt = spec.getSalt(); + byte[] info = spec.getInfo(); + + return expand(spec.getOutputLength(), new HKDFParameters(ikm, salt, info)); + } + else + { + throw new InvalidAlgorithmParameterException("invalid HKDFParameterSpec provided"); + } + } + + private byte[] expand(int length, HKDFParameters hkdfParameters) + { + hkdf.init(hkdfParameters); + + byte[] result = new byte[length]; + hkdf.generateBytes(result, 0, length); + return result; + } + + private static byte[] flattenSecretKeys(List keys) + { + if (keys.size() == 1) + { + return keys.get(0).getEncoded(); + } + + int len = 0; + int off = 0; + + ArrayList encodings = new ArrayList(keys.size()); + for (SecretKey key : keys) + { + byte[] encoding = key.getEncoded(); + encodings.add(encoding); + len += encoding.length; + } + + byte[] res = new byte[len]; + for (byte[] encoding : encodings) + { + System.arraycopy(encoding, 0, res, off, encoding.length); + off += encoding.length; + Arrays.clear(encoding); + } + return res; + } + + private static KDFParameters requireNull(KDFParameters kdfParameters, String message) + throws InvalidAlgorithmParameterException + { + if (kdfParameters != null) + { + throw new InvalidAlgorithmParameterException(message); + } + return null; + } + + public static class HKDFwithSHA256 extends HKDFSpi + { + public HKDFwithSHA256(KDFParameters kdfParameters) throws InvalidAlgorithmParameterException + { + super(kdfParameters, new SHA256Digest()); + } + public HKDFwithSHA256() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class HKDFwithSHA384 extends HKDFSpi + { + public HKDFwithSHA384(KDFParameters kdfParameters) throws InvalidAlgorithmParameterException + { + super(kdfParameters, new SHA384Digest()); + } + public HKDFwithSHA384() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class HKDFwithSHA512 extends HKDFSpi + { + public HKDFwithSHA512(KDFParameters kdfParameters) throws InvalidAlgorithmParameterException + { + super(kdfParameters, new SHA512Digest()); + } + public HKDFwithSHA512() throws InvalidAlgorithmParameterException + { + this(null); + } + } +} diff --git a/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/pbepbkdf2/PBEPBKDF2Spi.java b/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/pbepbkdf2/PBEPBKDF2Spi.java new file mode 100644 index 0000000000..de34e43b34 --- /dev/null +++ b/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/pbepbkdf2/PBEPBKDF2Spi.java @@ -0,0 +1,289 @@ +package org.bouncycastle.jcajce.provider.kdf.pbepbkdf2; + +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.PasswordConverter; +import org.bouncycastle.crypto.digests.GOST3411Digest; +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.digests.SM3Digest; +import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.jcajce.spec.PBKDF2ParameterSpec; +import org.bouncycastle.util.Arrays; + +import javax.crypto.KDFParameters; +import javax.crypto.KDFSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.AlgorithmParameterSpec; + +class PBEPBKDF2Spi + extends KDFSpi +{ + final PasswordConverter pwdConverter; + final PKCS5S2ParametersGenerator generator; + + protected PBEPBKDF2Spi(KDFParameters kdfParameters) + throws InvalidAlgorithmParameterException + { + this(kdfParameters, new SHA1Digest(), PasswordConverter.UTF8); + } + + protected PBEPBKDF2Spi(KDFParameters kdfParameters, Digest digest) + throws InvalidAlgorithmParameterException + { + this(kdfParameters, digest, PasswordConverter.UTF8); + } + + protected PBEPBKDF2Spi(KDFParameters kdfParameters, Digest digest, PasswordConverter pwdConverter) + throws InvalidAlgorithmParameterException + { + super(requireNull(kdfParameters, "PBEPBKDF2" + " does not support parameters")); + this.pwdConverter = pwdConverter; + this.generator = new PKCS5S2ParametersGenerator(digest); + } + + @Override + protected KDFParameters engineGetParameters() + { + return null; + } + + @Override + protected SecretKey engineDeriveKey(String alg, AlgorithmParameterSpec derivationSpec) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException + { + byte[] derivedKey = engineDeriveData(derivationSpec); + + return new SecretKeySpec(derivedKey, alg); + } + + @Override + protected byte[] engineDeriveData(AlgorithmParameterSpec derivationSpec) throws InvalidAlgorithmParameterException + { + if (!(derivationSpec instanceof PBEKeySpec)) + { + throw new InvalidAlgorithmParameterException("Invalid AlgorithmParameterSpec provided"); + } + + PBEKeySpec spec = (PBEKeySpec) derivationSpec; + + char[] password = spec.getPassword(); + byte[] salt = spec.getSalt(); + int iterCount = spec.getIterationCount(); + int keyLen = spec.getKeyLength(); + + if (password == null || salt == null) + { + throw new InvalidAlgorithmParameterException("Password and salt cannot be null"); + } + + generator.init(pwdConverter.convert(password), salt, iterCount); + + KeyParameter params = (KeyParameter) generator.generateDerivedParameters(keyLen); + byte[] derivedData = params.getKey(); + + Arrays.fill(password, (char) 0); + + return derivedData; + } + + private static KDFParameters requireNull(KDFParameters kdfParameters, + String message) throws InvalidAlgorithmParameterException + { + if (kdfParameters != null) + { + throw new InvalidAlgorithmParameterException(message); + } + return null; + } + + public static class PBKDF2withUTF8 + extends PBEPBKDF2Spi + { + public PBKDF2withUTF8(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters, new SHA1Digest()); + } + public PBKDF2withUTF8() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class PBKDF2withSHA224 + extends PBEPBKDF2Spi + { + public PBKDF2withSHA224(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters, new SHA224Digest()); + } + public PBKDF2withSHA224() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class PBKDF2withSHA256 + extends PBEPBKDF2Spi + { + public PBKDF2withSHA256(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters, new SHA256Digest()); + } + public PBKDF2withSHA256() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class PBKDF2withSHA384 + extends PBEPBKDF2Spi + { + public PBKDF2withSHA384(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters, new SHA384Digest()); + } + public PBKDF2withSHA384() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class PBKDF2withSHA512 + extends PBEPBKDF2Spi + { + public PBKDF2withSHA512(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters, new SHA512Digest()); + } + public PBKDF2withSHA512() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class PBKDF2withSHA512_224 + extends PBEPBKDF2Spi + { + public PBKDF2withSHA512_224(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters, new SHA512tDigest(224)); + } + public PBKDF2withSHA512_224() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class PBKDF2withSHA512_256 + extends PBEPBKDF2Spi + { + public PBKDF2withSHA512_256(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters, new SHA512tDigest(256)); + } + public PBKDF2withSHA512_256() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class PBKDF2withGOST3411 + extends PBEPBKDF2Spi + { + public PBKDF2withGOST3411(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters, new GOST3411Digest()); + } + public PBKDF2withGOST3411() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class PBKDF2withSHA3_224 + extends PBEPBKDF2Spi + { + public PBKDF2withSHA3_224(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters, new SHA3Digest(224)); + } + public PBKDF2withSHA3_224() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class PBKDF2withSHA3_256 + extends PBEPBKDF2Spi + { + public PBKDF2withSHA3_256(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters, new SHA3Digest(256)); + } + public PBKDF2withSHA3_256() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class PBKDF2withSHA3_384 + extends PBEPBKDF2Spi + { + public PBKDF2withSHA3_384(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters, new SHA3Digest(384)); + } + public PBKDF2withSHA3_384() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class PBKDF2withSHA3_512 + extends PBEPBKDF2Spi + { + public PBKDF2withSHA3_512(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters, new SHA3Digest(512)); + } + public PBKDF2withSHA3_512() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class PBKDF2with8BIT + extends PBEPBKDF2Spi + { + public PBKDF2with8BIT(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters, new SHA1Digest(), PasswordConverter.ASCII); + } + public PBKDF2with8BIT() throws InvalidAlgorithmParameterException + { + this(null); + } + } + + public static class PBKDF2withSM3 + extends PBEPBKDF2Spi + { + public PBKDF2withSM3(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters, new SM3Digest()); + } + public PBKDF2withSM3() throws InvalidAlgorithmParameterException + { + this(null); + } + } +} diff --git a/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/scrypt/ScryptSpi.java b/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/scrypt/ScryptSpi.java new file mode 100644 index 0000000000..f8ec262db2 --- /dev/null +++ b/prov/src/main/jdk25/org/bouncycastle/jcajce/provider/kdf/scrypt/ScryptSpi.java @@ -0,0 +1,105 @@ +package org.bouncycastle.jcajce.provider.kdf.scrypt; + +import org.bouncycastle.crypto.PasswordConverter; +import org.bouncycastle.crypto.generators.SCrypt; +import org.bouncycastle.jcajce.spec.ScryptKeySpec; +import org.bouncycastle.jcajce.spec.ScryptParameterSpec; +import org.bouncycastle.util.Arrays; + +import javax.crypto.KDFParameters; +import javax.crypto.KDFSpi; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.spec.AlgorithmParameterSpec; + +/** + * Example KDFSpi that delegates to Bouncy Castle’s SCrypt implementation. + */ +class ScryptSpi + extends KDFSpi +{ + protected ScryptSpi(KDFParameters kdfParameters) + throws InvalidAlgorithmParameterException + { + super(requireNull(kdfParameters, "Scrypt" + " does not support parameters")); + } + + @Override + protected KDFParameters engineGetParameters() + { + return null; + } + + @Override + protected SecretKey engineDeriveKey(String alg, AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException, NoSuchAlgorithmException + { + byte[] derived = engineDeriveData(derivationSpec); + + return new SecretKeySpec(derived, alg); + } + + @Override + protected byte[] engineDeriveData(AlgorithmParameterSpec derivationSpec) + throws InvalidAlgorithmParameterException + { + if (!(derivationSpec instanceof ScryptParameterSpec)) + { + throw new InvalidAlgorithmParameterException( + "SCrypt requires an SCryptParameterSpec as derivation parameters"); + } + + ScryptKeySpec spec = (ScryptKeySpec) derivationSpec; + + char[] password = spec.getPassword(); + byte[] salt = spec.getSalt(); + int cost = spec.getCostParameter(); + int blockSize = spec.getBlockSize(); + int p = spec.getParallelizationParameter(); + int keyLen = spec.getKeyLength(); + + if (salt == null) + { + throw new InvalidAlgorithmParameterException("Salt S must be provided."); + } + if (cost <= 1) + { + throw new InvalidAlgorithmParameterException("Cost parameter N must be > 1."); + } + + if (keyLen <= 0) + { + throw new InvalidAlgorithmParameterException("positive key length required: " + + keyLen); + } + + byte[] derived = SCrypt.generate( + PasswordConverter.UTF8.convert(password), + salt, cost, blockSize, p, keyLen / 8); + + Arrays.clear(password); + + return derived; + } + + private static KDFParameters requireNull(KDFParameters kdfParameters, + String message) throws InvalidAlgorithmParameterException + { + if (kdfParameters != null) + { + throw new InvalidAlgorithmParameterException(message); + } + return null; + } + + public static class ScryptWithUTF8 + extends ScryptSpi + { + public ScryptWithUTF8(KDFParameters parameters) throws InvalidAlgorithmParameterException + { + super(parameters); + } + } +} diff --git a/prov/src/main/jdk25/org/bouncycastle/jcajce/spec/PBKDF2ParameterSpec.java b/prov/src/main/jdk25/org/bouncycastle/jcajce/spec/PBKDF2ParameterSpec.java new file mode 100644 index 0000000000..e47d49e975 --- /dev/null +++ b/prov/src/main/jdk25/org/bouncycastle/jcajce/spec/PBKDF2ParameterSpec.java @@ -0,0 +1,24 @@ +package org.bouncycastle.jcajce.spec; + +import javax.crypto.spec.PBEKeySpec; +import java.security.spec.AlgorithmParameterSpec; + +public class PBKDF2ParameterSpec + extends PBEKeySpec + implements AlgorithmParameterSpec +{ + public PBKDF2ParameterSpec(char[] password) + { + super(password); + } + + public PBKDF2ParameterSpec(char[] password, byte[] salt, int iterationCount, int keyLength) + { + super(password, salt, iterationCount, keyLength); + } + + public PBKDF2ParameterSpec(char[] password, byte[] salt, int iterationCount) + { + super(password, salt, iterationCount); + } +} diff --git a/prov/src/main/jdk25/org/bouncycastle/jcajce/spec/ScryptParameterSpec.java b/prov/src/main/jdk25/org/bouncycastle/jcajce/spec/ScryptParameterSpec.java new file mode 100644 index 0000000000..ff8e374b5b --- /dev/null +++ b/prov/src/main/jdk25/org/bouncycastle/jcajce/spec/ScryptParameterSpec.java @@ -0,0 +1,15 @@ +package org.bouncycastle.jcajce.spec; + +import org.bouncycastle.jcajce.spec.ScryptKeySpec; + +import java.security.spec.AlgorithmParameterSpec; + +public class ScryptParameterSpec + extends ScryptKeySpec + implements AlgorithmParameterSpec +{ + public ScryptParameterSpec(char[] password, byte[] salt, int costParameter, int blockSize, int parallelizationParameter, int keySize) + { + super(password, salt, costParameter, blockSize, parallelizationParameter, keySize); + } +} diff --git a/prov/src/main/jdk25/org/bouncycastle/jcajce/util/SpiUtil.java b/prov/src/main/jdk25/org/bouncycastle/jcajce/util/SpiUtil.java new file mode 100644 index 0000000000..443908ddf9 --- /dev/null +++ b/prov/src/main/jdk25/org/bouncycastle/jcajce/util/SpiUtil.java @@ -0,0 +1,14 @@ +package org.bouncycastle.jcajce.util; + +public abstract class SpiUtil +{ + public static boolean hasKDF() + { + return true; + } + + public static boolean hasKEM() + { + return true; + } +} diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java index 295182830e..b14545d2f2 100644 --- a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java +++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java @@ -33,6 +33,7 @@ public static Test suite() suite.addTestSuite(CompositeSignaturesTest.class); suite.addTestSuite(BouncyCastleProviderTest.class); suite.addTestSuite(PQCSignatureTest.class); + suite.addTestSuite(SecretKeyUtilTest.class); return new BCTestSetup(suite); } diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeMLDSAECDSASignature.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeMLDSAECDSASignature.java new file mode 100644 index 0000000000..49123ee88f --- /dev/null +++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeMLDSAECDSASignature.java @@ -0,0 +1,276 @@ +package org.bouncycastle.jcajce.provider.test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.SecureRandom; +import java.security.Security; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; + +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.asn1.bc.BCObjectIdentifiers; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.signers.ECDSASigner; +import org.bouncycastle.crypto.signers.HMacDSAKCalculator; +import org.bouncycastle.jcajce.CompositePrivateKey; +import org.bouncycastle.jcajce.CompositePublicKey; +import org.bouncycastle.jcajce.interfaces.MLDSAPrivateKey; +import org.bouncycastle.jcajce.interfaces.MLDSAPublicKey; +import org.bouncycastle.jcajce.spec.MLDSAParameterSpec; +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters; +import org.bouncycastle.pqc.crypto.mldsa.MLDSAPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters; +import org.bouncycastle.pqc.crypto.mldsa.MLDSASigner; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; + +public class CompositeMLDSAECDSASignature +{ + + // Constants + private static final String PREFIX_STRING = "CompositeAlgorithmSignatures2025"; + private static final byte[] PREFIX = PREFIX_STRING.getBytes(java.nio.charset.StandardCharsets.US_ASCII); + private static final byte[] DOMAIN_SEPARATOR = Hex.decode("060B6086480186FA6B50080167");//060B6086480186FA6B50080153 + private static final byte[] HASH_OID_SHA256 = Hex.decode("0609608648016503040201"); + private static final int ML_DSA_SIG_SIZE = 2420; // For ML-DSA-44 + private static final int RANDOMIZER_SIZE = 32; + + static + { + Security.addProvider(new BouncyCastleProvider()); + } + + public static class CompositeKeyPair + { + private final CompositePublicKey publicKey; + private final CompositePrivateKey privateKey; + + public CompositeKeyPair(CompositePublicKey publicKey, CompositePrivateKey privateKey) + { + this.publicKey = publicKey; + this.privateKey = privateKey; + } + + public CompositePublicKey getPublicKey() + { + return publicKey; + } + + public CompositePrivateKey getPrivateKey() + { + return privateKey; + } + } + + public static CompositeKeyPair generateKeyPair() + throws Exception + { + SecureRandom random = new SecureRandom(); + + // Generate ML-DSA key pair + KeyPairGenerator mlDsaKpg = KeyPairGenerator.getInstance("ML-DSA", "BC"); + mlDsaKpg.initialize(MLDSAParameterSpec.ml_dsa_65); + + KeyPair mlDsaKeyPair = mlDsaKpg.generateKeyPair(); + MLDSAPublicKey mlDsaPub = (MLDSAPublicKey)mlDsaKeyPair.getPublic(); + MLDSAPrivateKey mlDsaPriv = (MLDSAPrivateKey)mlDsaKeyPair.getPrivate(); + + // Generate ECDSA key pair + KeyPairGenerator ecKpg = KeyPairGenerator.getInstance("EC", "BC"); + ecKpg.initialize(new ECGenParameterSpec("secp256r1"), random); + KeyPair ecKeyPair = ecKpg.generateKeyPair(); + ECPublicKey ecPub = (ECPublicKey)ecKeyPair.getPublic(); + ECPrivateKey ecPriv = (ECPrivateKey)ecKeyPair.getPrivate(); + + // Create composite keys + CompositePublicKey pubKey = new CompositePublicKey( + BCObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, + mlDsaPub, + ecPub); + + CompositePrivateKey privKey = new CompositePrivateKey( + BCObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, + mlDsaPriv, + ecPriv + ); + + return new CompositeKeyPair(pubKey, privKey); + } + + public static byte[] sign(CompositePrivateKey privateKey, byte[] message, byte[] ctx) + throws Exception + { + if (ctx.length > 255) + { + throw new IllegalArgumentException("Context too long"); + } + + SecureRandom random = new SecureRandom(); + + // Step 1: Generate randomizer r (32 bytes) + byte[] r = new byte[RANDOMIZER_SIZE]; + random.nextBytes(r); + + // Step 2: Compute PH = SHA256(r || M) + MessageDigest digest = MessageDigest.getInstance("SHA256"); + digest.update(r); + digest.update(message); + byte[] ph = digest.digest(); + + // Step 3: Build M' + ByteArrayOutputStream mPrimeStream = new ByteArrayOutputStream(); + mPrimeStream.write(PREFIX); + mPrimeStream.write(DOMAIN_SEPARATOR); + mPrimeStream.write(ctx.length); + mPrimeStream.write(ctx); + mPrimeStream.write(r); + mPrimeStream.write(HASH_OID_SHA256); + mPrimeStream.write(ph); + byte[] mPrime = mPrimeStream.toByteArray(); + + // Step 4: Sign M' with ML-DSA + MLDSASigner mlDsaSigner = new MLDSASigner(); +// mlDsaSigner.init(true, recreateMlDsaPrivateKey(privateKey.getMlDsaSeed())); + mlDsaSigner.update(mPrime, 0, mPrime.length); + byte[] mlDsaSig = mlDsaSigner.generateSignature(); + + // Step 5: Sign M' with ECDSA + ECDSASigner ecdsaSigner = new ECDSASigner(new HMacDSAKCalculator(new SHA256Digest())); +// ecdsaSigner.init(true, new ECPrivateKeyParameters( +// new BigInteger(1, privateKey.getEcPrivKey()), +// new ECNamedDomainParameters(ECNamedCurveTable.getParameterSpec("secp256r1")) +// )); + BigInteger[] ecSig = ecdsaSigner.generateSignature(mPrime); + byte[] ecDerSig = derEncodeECSignature(ecSig[0], ecSig[1]); + + // Step 6: Serialize composite signature + ByteArrayOutputStream sigStream = new ByteArrayOutputStream(); + sigStream.write(r); + sigStream.write(mlDsaSig); + sigStream.write(ecDerSig); + + return sigStream.toByteArray(); + } + + public static boolean verify(CompositePublicKey publicKey, byte[] message, byte[] ctx, byte[] signature) + throws Exception + { + if (ctx != null && ctx.length > 255) + { + throw new IllegalArgumentException("Context too long"); + } + + // Split signature + if (signature.length < RANDOMIZER_SIZE + ML_DSA_SIG_SIZE) + { + return false; + } + byte[] r = Arrays.copyOfRange(signature, 0, RANDOMIZER_SIZE); + byte[] mlDsaSig = Arrays.copyOfRange(signature, RANDOMIZER_SIZE, RANDOMIZER_SIZE + ML_DSA_SIG_SIZE); + byte[] ecDerSig = Arrays.copyOfRange(signature, RANDOMIZER_SIZE + ML_DSA_SIG_SIZE, signature.length); + + // Step 1: Compute PH = SHA256(r || M) + MessageDigest digest = MessageDigest.getInstance("SHA256"); + digest.update(r); + digest.update(message); + byte[] ph = digest.digest(); + + // Step 2: Build M' + ByteArrayOutputStream mPrimeStream = new ByteArrayOutputStream(); + mPrimeStream.write(PREFIX); + mPrimeStream.write(DOMAIN_SEPARATOR); + if (ctx != null) + { + mPrimeStream.write(ctx.length); + mPrimeStream.write(ctx); + } + else + { + mPrimeStream.write(0); + } + mPrimeStream.write(r); + mPrimeStream.write(HASH_OID_SHA256); + mPrimeStream.write(ph); + byte[] mPrime = mPrimeStream.toByteArray(); + + // Step 3: Verify ML-DSA signature + MLDSASigner mlDsaVerifier = new MLDSASigner(); +// mlDsaVerifier.init(false, recreateMlDsaPublicKey(publicKey.getMlDsaPubKey())); + mlDsaVerifier.update(mPrime, 0, mPrime.length); + boolean mlDsaValid = mlDsaVerifier.verifySignature(mlDsaSig); + + // Step 4: Verify ECDSA signature + BigInteger[] ecSig = derDecodeECSignature(ecDerSig); + ECDSASigner ecdsaVerifier = new ECDSASigner(); +// ecdsaVerifier.init(false, recreateEcPublicKey(publicKey.getEcPubKey())); + boolean ecValid = ecdsaVerifier.verifySignature(mPrime, ecSig[0], ecSig[1]); + + return mlDsaValid && ecValid; + } + + // Helper methods + private static MLDSAPrivateKeyParameters recreateMlDsaPrivateKey(byte[] encoded) + { + return new MLDSAPrivateKeyParameters(MLDSAParameters.ml_dsa_44, encoded); + } + + private static MLDSAPublicKeyParameters recreateMlDsaPublicKey(byte[] encoded) + { + return new MLDSAPublicKeyParameters(MLDSAParameters.ml_dsa_44, encoded); + } + + private static ECPublicKeyParameters recreateEcPublicKey(byte[] encoded) + { + ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("secp256r1"); + return new ECPublicKeyParameters( + spec.getCurve().decodePoint(encoded), + new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(), spec.getH()) + ); + } + + private static byte[] derEncodeECSignature(BigInteger r, BigInteger s) + throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(new ASN1Integer(r)); + v.add(new ASN1Integer(s)); + return new DERSequence(v).getEncoded(); + } + + private static BigInteger[] derDecodeECSignature(byte[] der) + throws IOException + { + ASN1Sequence seq = ASN1Sequence.getInstance(der); + return new BigInteger[]{ + ASN1Integer.getInstance(seq.getObjectAt(0)).getValue(), + ASN1Integer.getInstance(seq.getObjectAt(1)).getValue() + }; + } + + public static void main(String[] args) + throws Exception + { + // Example usage + CompositeKeyPair keyPair = generateKeyPair(); + byte[] message = "Hello, Composite Signatures!".getBytes(); + byte[] ctx = "example-context".getBytes(); + + byte[] signature = sign(keyPair.getPrivateKey(), message, ctx); + boolean isValid = verify(keyPair.getPublicKey(), message, ctx, signature); + + System.out.println("Signature valid: " + isValid); + } +} \ No newline at end of file diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java index 0621709a51..43245272fe 100644 --- a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java +++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java @@ -1,39 +1,109 @@ package org.bouncycastle.jcajce.provider.test; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.security.InvalidKeyException; +import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.PublicKey; import java.security.Security; import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; import junit.framework.TestCase; import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers; import org.bouncycastle.jcajce.CompositePrivateKey; import org.bouncycastle.jcajce.CompositePublicKey; +import org.bouncycastle.jcajce.interfaces.MLDSAPrivateKey; +import org.bouncycastle.jcajce.interfaces.MLDSAPublicKey; import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeIndex; -import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey; +import org.bouncycastle.jcajce.spec.CompositeSignatureSpec; import org.bouncycastle.jcajce.spec.ContextParameterSpec; +import org.bouncycastle.jcajce.spec.MLDSAParameterSpec; +import org.bouncycastle.jcajce.spec.MLDSAPrivateKeySpec; +import org.bouncycastle.jcajce.spec.MLDSAPublicKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.test.TestResourceFinder; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Base64; +import org.bouncycastle.util.encoders.Hex; public class CompositeSignaturesTest extends TestCase { - private static String[] compositeSignaturesOIDs = { - "2.16.840.1.114027.80.8.1.21", //id-MLDSA44-RSA2048-PSS-SHA256 - "2.16.840.1.114027.80.8.1.22", //id-MLDSA44-RSA2048-PKCS15-SHA256 - "2.16.840.1.114027.80.8.1.23", //id-MLDSA44-Ed25519-SHA512 - "2.16.840.1.114027.80.8.1.24", //id-MLDSA44-ECDSA-P256-SHA256 - "2.16.840.1.114027.80.8.1.26", //id-MLDSA65-RSA3072-PSS-SHA512 - "2.16.840.1.114027.80.8.1.27", //id-MLDSA65-RSA3072-PKCS15-SHA512 - "2.16.840.1.114027.80.8.1.28", //id-MLDSA65-ECDSA-P256-SHA512 - "2.16.840.1.114027.80.8.1.29", //id-MLDSA65-ECDSA-brainpoolP256r1-SHA512 - "2.16.840.1.114027.80.8.1.30", //id-MLDSA65-Ed25519-SHA512 - "2.16.840.1.114027.80.8.1.31", //id-MLDSA87-ECDSA-P384-SHA512 - "2.16.840.1.114027.80.8.1.32", //id-MLDSA87-ECDSA-brainpoolP384r1-SHA512 - "2.16.840.1.114027.80.8.1.33", //id-MLDSA87-Ed448-SHA512 + "1.3.6.1.5.5.7.6.37", // id_MLDSA44_RSA2048_PSS_SHA256 + "1.3.6.1.5.5.7.6.38", // id_MLDSA44_RSA2048_PKCS15_SHA256 + "1.3.6.1.5.5.7.6.39", // id_MLDSA44_Ed25519_SHA512 + "1.3.6.1.5.5.7.6.40", // id_MLDSA44_ECDSA_P256_SHA256 + "1.3.6.1.5.5.7.6.41", // id_MLDSA65_RSA3072_PSS_SHA512 + "1.3.6.1.5.5.7.6.42", // id_MLDSA65_RSA3072_PKCS15_SHA512 + "1.3.6.1.5.5.7.6.43", // id_MLDSA65_RSA4096_PSS_SHA512 + "1.3.6.1.5.5.7.6.44", // id_MLDSA65_RSA4096_PKCS15_SHA512 + "1.3.6.1.5.5.7.6.45", // id_MLDSA65_ECDSA_P256_SHA512 + "1.3.6.1.5.5.7.6.46", // id_MLDSA65_ECDSA_P384_SHA512 + "1.3.6.1.5.5.7.6.47", // id_MLDSA65_ECDSA_brainpoolP256r1_SHA512 + "1.3.6.1.5.5.7.6.48", // id_MLDSA65_Ed25519_SHA512 + "1.3.6.1.5.5.7.6.49", // id_MLDSA87_ECDSA_P384_SHA512 + "1.3.6.1.5.5.7.6.50", // id_MLDSA87_ECDSA_brainpoolP384r1_SHA512 + "1.3.6.1.5.5.7.6.51", // id_MLDSA87_Ed448_SHAKE256 + "1.3.6.1.5.5.7.6.52", // id_MLDSA87_RSA3072_PSS_SHA512 + "1.3.6.1.5.5.7.6.53", // id_MLDSA87_RSA4096_PSS_SHA512 + "1.3.6.1.5.5.7.6.54" // id_MLDSA87_ECDSA_P521_SHA512 }; + static final Map oidMap = new HashMap(); + + static + { + oidMap.put("id-ML-DSA-44", "2.16.840.1.101.3.4.3.17"); + oidMap.put("id-ML-DSA-65", "2.16.840.1.101.3.4.3.18"); + oidMap.put("id-ML-DSA-87", "2.16.840.1.101.3.4.3.19"); + oidMap.put("id-MLDSA44-RSA2048-PSS-SHA256", IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256.getId()); + oidMap.put("id-MLDSA44-RSA2048-PKCS15-SHA256", IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256.getId()); + oidMap.put("id-MLDSA44-Ed25519-SHA512", IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512.getId()); + oidMap.put("id-MLDSA44-ECDSA-P256-SHA256", IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.getId()); + oidMap.put("id-MLDSA65-RSA3072-PSS-SHA512", IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512.getId()); + oidMap.put("id-MLDSA65-RSA3072-PKCS15-SHA512", IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512.getId()); + oidMap.put("id-MLDSA65-RSA4096-PSS-SHA512", IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512.getId()); + oidMap.put("id-MLDSA65-RSA4096-PKCS15-SHA512", IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512.getId()); + oidMap.put("id-MLDSA65-ECDSA-P256-SHA512", IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512.getId()); + oidMap.put("id-MLDSA65-ECDSA-P384-SHA512", IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512.getId()); + oidMap.put("id-MLDSA65-ECDSA-brainpoolP256r1-SHA512", IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512.getId()); + oidMap.put("id-MLDSA65-Ed25519-SHA512", IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512.getId()); + oidMap.put("id-MLDSA87-ECDSA-P384-SHA512", IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512.getId()); + oidMap.put("id-MLDSA87-ECDSA-brainpoolP384r1-SHA512", IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512.getId()); + oidMap.put("id-MLDSA87-Ed448-SHAKE256", IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256.getId()); + oidMap.put("id-MLDSA87-RSA3072-PSS-SHA512", IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512.getId()); + oidMap.put("id-MLDSA87-RSA4096-PSS-SHA512", IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512.getId()); + oidMap.put("id-MLDSA87-ECDSA-P521-SHA512", IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512.getId()); + } + + public static final String messageToBeSigned = "Hello, how was your day?"; public void setUp() @@ -41,6 +111,13 @@ public void setUp() Security.addProvider(new BouncyCastleProvider()); } + public void testTestVectors() + throws Exception + { + List> testVectors = readTestVectorsFromJson("pqc/crypto/composite", "testvectors.json"); + compositeSignaturesTest(testVectors); + } + public void testKeyPairGeneration() throws Exception { @@ -52,98 +129,583 @@ public void testKeyPairGeneration() CompositePublicKey compositePublicKey = (CompositePublicKey)keyPair.getPublic(); CompositePrivateKey compositePrivateKey = (CompositePrivateKey)keyPair.getPrivate(); - String firstPublicKeyAlgorithm = Strings.toUpperCase(compositePublicKey.getPublicKeys().get(0).getAlgorithm()); - String secondPublicKeyAlgorithm = Strings.toUpperCase(compositePublicKey.getPublicKeys().get(1).getAlgorithm()); - String firstPrivateKeyAlgorithm = Strings.toUpperCase(compositePrivateKey.getPrivateKeys().get(0).getAlgorithm()); - String secondPrivateKeyAlgorithm = Strings.toUpperCase(compositePrivateKey.getPrivateKeys().get(1).getAlgorithm()); - - BCRSAPublicKey rsaPublicKey = null; - BCRSAPublicKey rsaPrivateKey = null; - -// switch (CompositeSignaturesConstants.ASN1IdentifierCompositeNameMap.get(new ASN1ObjectIdentifier(oid))) -// { -// case MLDSA44_RSA2048_PSS_SHA256: -// case MLDSA44_RSA2048_PKCS15_SHA256: -// TestCase.assertEquals("ML-DSA-44", firstPublicKeyAlgorithm); -// TestCase.assertEquals("ML-DSA-44", firstPrivateKeyAlgorithm); -// TestCase.assertEquals("RSA", secondPublicKeyAlgorithm); -// TestCase.assertEquals("RSA", secondPrivateKeyAlgorithm); -// rsaPublicKey = (BCRSAPublicKey)compositePublicKey.getPublicKeys().get(1); -// rsaPrivateKey = (BCRSAPublicKey)compositePublicKey.getPublicKeys().get(1); -// TestCase.assertEquals(2048, rsaPublicKey.getModulus().bitLength()); -// TestCase.assertEquals(2048, rsaPrivateKey.getModulus().bitLength()); -// break; -// case MLDSA44_Ed25519_SHA512: -// TestCase.assertEquals("ML-DSA-44", firstPublicKeyAlgorithm); -// TestCase.assertEquals("ML-DSA-44", firstPrivateKeyAlgorithm); -// TestCase.assertEquals("ED25519", secondPublicKeyAlgorithm); -// TestCase.assertEquals("ED25519", secondPrivateKeyAlgorithm); -// break; -// case MLDSA44_ECDSA_P256_SHA256: -// case MLDSA44_ECDSA_brainpoolP256r1_SHA256: -// TestCase.assertEquals("ML-DSA-44", firstPublicKeyAlgorithm); -// TestCase.assertEquals("ML-DSA-44", firstPrivateKeyAlgorithm); -// TestCase.assertEquals("ECDSA", secondPublicKeyAlgorithm); -// TestCase.assertEquals("ECDSA", secondPrivateKeyAlgorithm); -// break; -// case MLDSA65_RSA3072_PSS_SHA512: -// case MLDSA65_RSA3072_PKCS15_SHA512: -// TestCase.assertEquals("ML-DSA-65", firstPublicKeyAlgorithm); -// TestCase.assertEquals("ML-DSA-65", firstPrivateKeyAlgorithm); -// TestCase.assertEquals("RSA", secondPublicKeyAlgorithm); -// TestCase.assertEquals("RSA", secondPrivateKeyAlgorithm); -// rsaPublicKey = (BCRSAPublicKey)compositePublicKey.getPublicKeys().get(1); -// rsaPrivateKey = (BCRSAPublicKey)compositePublicKey.getPublicKeys().get(1); -// TestCase.assertEquals(3072, rsaPublicKey.getModulus().bitLength()); -// TestCase.assertEquals(3072, rsaPrivateKey.getModulus().bitLength()); -// break; -// case MLDSA65_Ed25519_SHA512: -// TestCase.assertEquals("ML-DSA-65", firstPublicKeyAlgorithm); -// TestCase.assertEquals("ML-DSA-65", firstPrivateKeyAlgorithm); -// TestCase.assertEquals("ED25519", secondPublicKeyAlgorithm); -// TestCase.assertEquals("ED25519", secondPrivateKeyAlgorithm); -// break; -// case MLDSA65_ECDSA_P256_SHA512: -// case MLDSA65_ECDSA_brainpoolP256r1_SHA512: ompositeK -// TestCase.assertEquals("ML-DSA-65", firstPublicKeyAlgorithm); -// TestCase.assertEquals("ML-DSA-65", firstPrivateKeyAlgorithm); -// TestCase.assertEquals("ECDSA", secondPublicKeyAlgorithm); -// TestCase.assertEquals("ECDSA", secondPrivateKeyAlgorithm); -// break; -// case MLDSA87_Ed448_SHA512: -// TestCase.assertEquals("ML-DSA-87", firstPublicKeyAlgorithm); -// TestCase.assertEquals("ML-DSA-87", firstPrivateKeyAlgorithm); -// TestCase.assertEquals("ED448", secondPublicKeyAlgorithm); -// TestCase.assertEquals("ED448", secondPrivateKeyAlgorithm); -// break; -// case MLDSA87_ECDSA_P384_SHA512: -// case MLDSA87_ECDSA_brainpoolP384r1_SHA512: -// TestCase.assertEquals("ML-DSA-87", firstPublicKeyAlgorithm); -// TestCase.assertEquals("ML-DSA-87", firstPrivateKeyAlgorithm); -// TestCase.assertEquals("ECDSA", secondPublicKeyAlgorithm); -// TestCase.assertEquals("ECDSA", secondPrivateKeyAlgorithm); -// break; -// default: -// throw new IllegalStateException( -// "Unexpected key algorithm." + CompositeSignaturesConstants.ASN1IdentifierCompositeNameMap.get(new ASN1ObjectIdentifier(oid))); -// } + ASN1ObjectIdentifier compAlg = compositePrivateKey.getAlgorithmIdentifier().getAlgorithm(); + if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256)) + { + check_RSA_Composite("ML-DSA-44", 2048, compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512)) + { + check_RSA_Composite("ML-DSA-65", 3072, compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA87_RSA3072_PSS_SHA512)) + { + check_RSA_Composite("ML-DSA-87", 3072, compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA87_RSA4096_PSS_SHA512)) + { + check_RSA_Composite("ML-DSA-87", 4096, compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA44_Ed25519_SHA512)) + { + check_EdDSA_Composite("ML-DSA-44", "Ed25519", compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA65_Ed25519_SHA512)) + { + check_EdDSA_Composite("ML-DSA-65", "Ed25519", compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA87_Ed448_SHAKE256)) + { + check_EdDSA_Composite("ML-DSA-87", "Ed448", compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256)) + { + check_ECDSA_Composite("ML-DSA-44", compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512)) + { + check_ECDSA_Composite("ML-DSA-65", compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA65_ECDSA_P384_SHA512)) + { + check_ECDSA_Composite("ML-DSA-65", compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512)) + { + check_ECDSA_Composite("ML-DSA-87", compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512)) + { + check_ECDSA_Composite("ML-DSA-87", compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA87_ECDSA_P521_SHA512)) + { + check_ECDSA_Composite("ML-DSA-87", compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512)) + { + check_ECDSA_Composite("ML-DSA-65", compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256)) + { + check_RSA_Composite("ML-DSA-44", 2048, compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512)) + { + check_RSA_Composite("ML-DSA-65", 3072, compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PSS_SHA512)) + { + check_RSA_Composite("ML-DSA-65", 4096, compositePublicKey, compositePrivateKey); + } + else if (compAlg.equals(IANAObjectIdentifiers.id_MLDSA65_RSA4096_PKCS15_SHA512)) + { + check_RSA_Composite("ML-DSA-65", 4096, compositePublicKey, compositePrivateKey); + } + else + { + throw new IllegalStateException("untested: " + CompositeIndex.getAlgorithmName(compAlg)); + } + } + } + + private void check_RSA_Composite(String firstAlg, int rsaKeySize, CompositePublicKey compPub, CompositePrivateKey compPriv) + { + TestCase.assertEquals(firstAlg, compPub.getPublicKeys().get(0).getAlgorithm()); + TestCase.assertEquals("RSA", compPub.getPublicKeys().get(1).getAlgorithm()); + RSAPublicKey rsaPublicKey = (RSAPublicKey)compPub.getPublicKeys().get(1); + RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)compPriv.getPrivateKeys().get(1); + TestCase.assertEquals(rsaKeySize, rsaPublicKey.getModulus().bitLength()); + TestCase.assertEquals(rsaKeySize, rsaPrivateKey.getModulus().bitLength()); + } + + private void check_EdDSA_Composite(String firstAlg, String edDSAAlg, CompositePublicKey compPub, CompositePrivateKey compPriv) + { + TestCase.assertEquals(firstAlg, compPub.getPublicKeys().get(0).getAlgorithm()); + TestCase.assertEquals(edDSAAlg, compPub.getPublicKeys().get(1).getAlgorithm()); + TestCase.assertEquals(firstAlg, compPriv.getPrivateKeys().get(0).getAlgorithm()); + TestCase.assertEquals(edDSAAlg, compPriv.getPrivateKeys().get(1).getAlgorithm()); + } + + private void check_ECDSA_Composite(String firstAlg, CompositePublicKey compPub, CompositePrivateKey compPriv) + { + TestCase.assertEquals(firstAlg, compPub.getPublicKeys().get(0).getAlgorithm()); + TestCase.assertEquals("EC", compPub.getPublicKeys().get(1).getAlgorithm()); + TestCase.assertEquals(firstAlg, compPriv.getPrivateKeys().get(0).getAlgorithm()); + TestCase.assertEquals("EC", compPriv.getPrivateKeys().get(1).getAlgorithm()); + } + + public void testKeyBuilders() + throws Exception + { + String[] algorithms = new String[]{ + "MLDSA44-RSA2048-PSS-SHA256", + "MLDSA44-RSA2048-PKCS15-SHA256", + "MLDSA44-Ed25519-SHA512", + "MLDSA44-ECDSA-P256-SHA256", + "MLDSA65-RSA3072-PSS-SHA512", + "MLDSA65-RSA3072-PKCS15-SHA512", + "MLDSA65-RSA4096-PSS-SHA512", + "MLDSA65-RSA4096-PKCS15-SHA512", + "MLDSA65-ECDSA-P256-SHA512", + "MLDSA65-ECDSA-P384-SHA512", + "MLDSA65-ECDSA-brainpoolP256r1-SHA512", + "MLDSA65-Ed25519-SHA512", + "MLDSA87-ECDSA-P384-SHA512", + "MLDSA87-ECDSA-brainpoolP384R1-SHA512", + "MLDSA87-Ed448-SHAKE256", + "MLDSA87-RSA4096-PSS-SHA512", + "MLDSA87-ECDSA-P521-SHA512", + "MLDSA87-RSA3072-PSS-SHA512" + }; + + CompositePublicKey.Builder pubBuilder = null; + CompositePrivateKey.Builder privBuilder = null; + + for (int i = 0; i != algorithms.length; i++) + { + pubBuilder = CompositePublicKey.builder(algorithms[i]); + privBuilder = CompositePrivateKey.builder(algorithms[i]); } + + assertNotNull(pubBuilder); + assertNotNull(privBuilder); + } + + public void testSelfComposition() + throws Exception + { + KeyPairGenerator mldsaKpGen = KeyPairGenerator.getInstance("ML-DSA", "BC"); + + mldsaKpGen.initialize(MLDSAParameterSpec.ml_dsa_44); + + KeyPair mldsaKp = mldsaKpGen.generateKeyPair(); + + KeyPairGenerator ecKpGen = KeyPairGenerator.getInstance("EC", "BC"); + + ecKpGen.initialize(new ECGenParameterSpec("P-256")); + + KeyPair ecKp = ecKpGen.generateKeyPair(); + + CompositePublicKey compPublicKey = new CompositePublicKey(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, mldsaKp.getPublic(), ecKp.getPublic()); + CompositePrivateKey compPrivateKey = new CompositePrivateKey(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256, mldsaKp.getPrivate(), ecKp.getPrivate()); + + Signature signature = Signature.getInstance(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.getId(), "BC"); + signature.initSign(compPrivateKey); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + byte[] signatureValue = signature.sign(); + + signature.initVerify(compPublicKey); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + TestCase.assertTrue(signature.verify(signatureValue)); + + KeyFactory compFact = KeyFactory.getInstance(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.getId(), "BC"); + PrivateKey compPriv = compFact.generatePrivate(new PKCS8EncodedKeySpec(compPrivateKey.getEncoded())); + PublicKey compPub = compFact.generatePublic(new X509EncodedKeySpec(compPublicKey.getEncoded())); + + signature.initSign(compPriv); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + signatureValue = signature.sign(); + + signature.initVerify(compPub); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + TestCase.assertTrue(signature.verify(signatureValue)); + + } + + public void testMixedComposition() + throws Exception + { + if (Security.getProvider("SunEC") == null) + { + return; + } + KeyPairGenerator mldsaKpGen = KeyPairGenerator.getInstance("ML-DSA", "BC"); + + mldsaKpGen.initialize(MLDSAParameterSpec.ml_dsa_44); + + KeyPair mldsaKp = mldsaKpGen.generateKeyPair(); + + KeyPairGenerator ecKpGen = KeyPairGenerator.getInstance("EC", "SunEC"); + + ecKpGen.initialize(new ECGenParameterSpec("secp256r1")); + + KeyPair ecKp = ecKpGen.generateKeyPair(); + + CompositePublicKey compPublicKey = CompositePublicKey.builder(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256) + .addPublicKey(mldsaKp.getPublic(), "BC") + .addPublicKey(ecKp.getPublic(), "SunEC") + .build(); + CompositePrivateKey compPrivateKey = CompositePrivateKey.builder(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256) + .addPrivateKey(mldsaKp.getPrivate(), "BC") + .addPrivateKey(ecKp.getPrivate(), "SunEC") + .build(); + + Signature signature = Signature.getInstance(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.getId(), "BC"); + signature.initSign(compPrivateKey); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + byte[] signatureValue = signature.sign(); + + signature.initVerify(compPublicKey); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + TestCase.assertTrue(signature.verify(signatureValue)); + + signature = Signature.getInstance("COMPOSITE", "BC"); + + signature.initVerify(compPublicKey); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + TestCase.assertTrue(signature.verify(signatureValue)); + + KeyFactory compFact = KeyFactory.getInstance(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.getId(), "BC"); + PrivateKey compPriv = compFact.generatePrivate(new PKCS8EncodedKeySpec(compPrivateKey.getEncoded())); + PublicKey compPub = compFact.generatePublic(new X509EncodedKeySpec(compPublicKey.getEncoded())); + signature = Signature.getInstance(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.getId(), "BC"); + + signature.initSign(compPriv); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + signatureValue = signature.sign(); + + signature.initVerify(compPub); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + TestCase.assertTrue(signature.verify(signatureValue)); + + // + // as COMPOSITE on sig creation + // + compPublicKey = CompositePublicKey.builder(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256) + .addPublicKey(mldsaKp.getPublic(), "BC") + .addPublicKey(ecKp.getPublic(), "SunEC") + .build(); + compPrivateKey = CompositePrivateKey.builder(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256) + .addPrivateKey(mldsaKp.getPrivate(), "BC") + .addPrivateKey(ecKp.getPrivate(), "SunEC") + .build(); + + signature = Signature.getInstance("COMPOSITE", "BC"); + + signature.initSign(compPriv); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + signatureValue = signature.sign(); + + signature = Signature.getInstance(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.getId(), "BC"); + signature.initVerify(compPub); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + TestCase.assertTrue(signature.verify(signatureValue)); + } + + public void testMixedCompositionHSMStyle() + throws Exception + { + if (Security.getProvider("SunEC") == null) + { + return; + } + KeyPairGenerator mldsaKpGen = KeyPairGenerator.getInstance("ML-DSA", "BC"); + + mldsaKpGen.initialize(MLDSAParameterSpec.ml_dsa_44); + + KeyPair mldsaKp = mldsaKpGen.generateKeyPair(); + + KeyPairGenerator ecKpGen = KeyPairGenerator.getInstance("EC", "SunEC"); + + ecKpGen.initialize(new ECGenParameterSpec("secp256r1")); + + KeyPair ecKp = ecKpGen.generateKeyPair(); + + CompositePublicKey compPublicKey = CompositePublicKey.builder(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256) + .addPublicKey(mldsaKp.getPublic(), "BC") + .addPublicKey(ecKp.getPublic(), "SunEC") + .build(); + CompositePrivateKey compPrivateKey = CompositePrivateKey.builder(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256) + .addPrivateKey(new ProxyHSMPrivateKey((MLDSAPrivateKey)mldsaKp.getPrivate()), "BC") + .addPrivateKey(ecKp.getPrivate(), "SunEC") + .build(); + + Signature signature = Signature.getInstance("COMPOSITE", "BC"); + + try + { + signature.initSign(compPrivateKey); + fail("proxy HSM key did not fail with BC"); + } + catch (InvalidKeyException e) + { + // we want to make sure it got at least as far as passing key to ML-DSA implementation + assertEquals("unknown private key passed to ML-DSA", e.getMessage()); + } + } + + public void testMixedCompositionWithNull() + throws Exception + { + if (Security.getProvider("SunEC") == null) + { + return; + } + KeyPairGenerator mldsaKpGen = KeyPairGenerator.getInstance("ML-DSA", "BC"); + + mldsaKpGen.initialize(MLDSAParameterSpec.ml_dsa_44); + + KeyPair mldsaKp = mldsaKpGen.generateKeyPair(); + + KeyPairGenerator ecKpGen = KeyPairGenerator.getInstance("EC", "SunEC"); + + ecKpGen.initialize(new ECGenParameterSpec("secp256r1")); + + KeyPair ecKp = ecKpGen.generateKeyPair(); + + CompositePublicKey compPublicKey = CompositePublicKey.builder(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256) + .addPublicKey(mldsaKp.getPublic()) + .addPublicKey(ecKp.getPublic()).build(); + CompositePrivateKey compPrivateKey = CompositePrivateKey.builder(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256) + .addPrivateKey(mldsaKp.getPrivate()) + .addPrivateKey(ecKp.getPrivate(), "SunEC") + .build(); + + Signature signature = Signature.getInstance(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.getId(), "BC"); + signature.initSign(compPrivateKey); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + byte[] signatureValue = signature.sign(); + + signature.initVerify(compPublicKey); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + TestCase.assertTrue(signature.verify(signatureValue)); + + KeyFactory compFact = KeyFactory.getInstance(IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.getId(), "BC"); + PrivateKey compPriv = compFact.generatePrivate(new PKCS8EncodedKeySpec(compPrivateKey.getEncoded())); + PublicKey compPub = compFact.generatePublic(new X509EncodedKeySpec(compPublicKey.getEncoded())); + + signature.initSign(compPriv); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + signatureValue = signature.sign(); + + signature.initVerify(compPub); + signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + TestCase.assertTrue(signature.verify(signatureValue)); + + } + + public void testPrehash() + throws Exception + { + doTestPrehash("MLDSA44-ECDSA-P256-SHA256", "SHA256"); + doTestPrehash("MLDSA65-ECDSA-P256-SHA512", "SHA512"); + } + + public void testNamedPrehash() + throws Exception + { + for (Iterator it = CompositeIndex.getSupportedIdentifiers().iterator(); it.hasNext(); ) + { + String name = CompositeIndex.getAlgorithmName((ASN1ObjectIdentifier)it.next()); + doTestNamedPrehash(name, name.substring(name.lastIndexOf("-") + 1)); + } + } + + public void testPrehashWithContext() + throws Exception + { + doTestPrehash("MLDSA44-ECDSA-P256-SHA256", "SHA256", new ContextParameterSpec(Hex.decode("deadbeef"))); + doTestPrehash("MLDSA65-ECDSA-P256-SHA512", "SHA512", new ContextParameterSpec(Hex.decode("deadbeef"))); + } + + private void doTestPrehash(String sigName, String digestName) + throws Exception + { + byte[] msg = Strings.toUTF8ByteArray(messageToBeSigned); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(sigName, "BC"); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + // full msg sign, verify hash + Signature signature = Signature.getInstance(sigName, "BC"); + signature.initSign(keyPair.getPrivate()); + signature.update(msg); + + byte[] signatureValue = signature.sign(); + + signature.initVerify(keyPair.getPublic()); + signature.setParameter(new CompositeSignatureSpec(true)); + signature.update(MessageDigest.getInstance(digestName, "BC").digest(msg)); + assertTrue(signature.verify(signatureValue)); + + // full msg sign, verify hash + signature = Signature.getInstance(sigName, "BC"); + signature.initSign(keyPair.getPrivate()); + signature.setParameter(new CompositeSignatureSpec(true)); + signature.update(MessageDigest.getInstance(digestName, "BC").digest(msg)); + + signatureValue = signature.sign(); + + signature.initVerify(keyPair.getPublic()); + signature.setParameter(new CompositeSignatureSpec(false)); + signature.update(msg); + assertTrue(signature.verify(signatureValue)); + + // exceptions + signature.initSign(keyPair.getPrivate()); + try + { + signature.setParameter(new CompositeSignatureSpec(true)); + signature.update(Hex.decode("beef")); + signature.sign(); + fail("sign"); + } + catch (SignatureException e) + { + assertEquals("provided pre-hash digest is the wrong length", e.getMessage()); + } + + // exceptions + signature.initVerify(keyPair.getPublic()); + try + { + signature.setParameter(new CompositeSignatureSpec(true)); + signature.update(Hex.decode("beef")); + signature.verify(signatureValue); + fail("verify"); + } + catch (SignatureException e) + { + assertEquals("provided pre-hash digest is the wrong length", e.getMessage()); + } + } + + private void doTestNamedPrehash(String sigName, String digestName) + throws Exception + { + byte[] msg = Strings.toUTF8ByteArray(messageToBeSigned); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(sigName, "BC"); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + // full msg sign, verify hash + Signature signature = Signature.getInstance(sigName, "BC"); + signature.initSign(keyPair.getPrivate()); + signature.update(msg); + + byte[] signatureValue = signature.sign(); + + signature = Signature.getInstance(sigName + "-PREHASH", "BC"); + signature.initVerify(keyPair.getPublic()); + signature.update(MessageDigest.getInstance(digestName, "BC").digest(msg)); + assertTrue(signature.verify(signatureValue)); + + // full msg sign, verify hash + signature = Signature.getInstance(sigName + "-PREHASH", "BC"); + signature.initSign(keyPair.getPrivate()); + signature.update(MessageDigest.getInstance(digestName, "BC").digest(msg)); + + signatureValue = signature.sign(); + + signature = Signature.getInstance(sigName, "BC"); + signature.initVerify(keyPair.getPublic()); + signature.update(msg); + assertTrue(signature.verify(signatureValue)); + + // exceptions + signature = Signature.getInstance(sigName + "-PREHASH", "BC"); + signature.initSign(keyPair.getPrivate()); + try + { + signature.update(Hex.decode("beef")); + signature.sign(); + fail("sign"); + } + catch (SignatureException e) + { + assertEquals("provided pre-hash digest is the wrong length", e.getMessage()); + } + + // exceptions + signature.initVerify(keyPair.getPublic()); + try + { + signature.setParameter(new CompositeSignatureSpec(true)); + signature.update(Hex.decode("beef")); + signature.verify(signatureValue); + fail("verify"); + } + catch (SignatureException e) + { + assertEquals("provided pre-hash digest is the wrong length", e.getMessage()); + } + } + + private void doTestPrehash(String sigName, String digestName, ContextParameterSpec contextSpec) + throws Exception + { + byte[] msg = Strings.toUTF8ByteArray(messageToBeSigned); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(sigName, "BC"); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + // full msg sign, verify hash + Signature signature = Signature.getInstance(sigName, "BC"); + signature.initSign(keyPair.getPrivate()); + signature.setParameter(contextSpec); + signature.update(msg); + + byte[] signatureValue = signature.sign(); + + signature.initVerify(keyPair.getPublic()); + signature.setParameter(new CompositeSignatureSpec(true, contextSpec)); + signature.update(MessageDigest.getInstance(digestName, "BC").digest(msg)); + assertTrue(signature.verify(signatureValue)); + + // check reflection case + signature.initVerify(keyPair.getPublic()); + signature.setParameter(new CompositeSignatureSpec(true, new MyContextSpec(contextSpec.getContext()))); + signature.update(MessageDigest.getInstance(digestName, "BC").digest(msg)); + assertTrue(signature.verify(signatureValue)); + + // full msg sign, verify hash + signature = Signature.getInstance(sigName, "BC"); + signature.initSign(keyPair.getPrivate()); + signature.setParameter(new CompositeSignatureSpec(true, contextSpec)); + signature.update(MessageDigest.getInstance(digestName, "BC").digest(msg)); + + signatureValue = signature.sign(); + + signature.initVerify(keyPair.getPublic()); + signature.setParameter(new CompositeSignatureSpec(false, contextSpec)); + signature.update(msg); + assertTrue(signature.verify(signatureValue)); + + signature.initVerify(keyPair.getPublic()); + signature.setParameter(new CompositeSignatureSpec(false)); + signature.update(msg); + assertFalse(signature.verify(signatureValue)); } public void testSigningAndVerificationInternal() throws Exception { + byte[] msg = Strings.toUTF8ByteArray(messageToBeSigned); + for (String oid : compositeSignaturesOIDs) { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(oid, "BC"); KeyPair keyPair = keyPairGenerator.generateKeyPair(); Signature signature = Signature.getInstance(oid, "BC"); signature.initSign(keyPair.getPrivate()); - signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + signature.update(msg); byte[] signatureValue = signature.sign(); signature.initVerify(keyPair.getPublic()); - signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); + signature.update(msg); + TestCase.assertTrue(signature.verify(signatureValue)); + + Signature compSig = Signature.getInstance("COMPOSITE", "BC"); + + compSig.initVerify(keyPair.getPublic()); + compSig.update(msg); + + TestCase.assertTrue(compSig.verify(signatureValue)); + + compSig.initSign(keyPair.getPrivate()); + compSig.update(msg); + signatureValue = compSig.sign(); + + signature.initVerify(keyPair.getPublic()); + signature.update(msg); TestCase.assertTrue(signature.verify(signatureValue)); } } @@ -151,7 +713,7 @@ public void testSigningAndVerificationInternal() public void testContextParameterSpec() throws Exception { - String oid = "2.16.840.1.114027.80.8.1.24"; // MLDSA44withECDSA_P256_SHA256 + String oid = IANAObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.getId(); // MLDSA44withECDSA_P256_SHA256 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(oid, "BC"); KeyPair keyPair = keyPairGenerator.generateKeyPair(); @@ -166,52 +728,259 @@ public void testContextParameterSpec() signature = Signature.getInstance(oid, "BC"); signature.initVerify(keyPair.getPublic()); - + signature.setParameter(new ContextParameterSpec(Strings.toByteArray("Hello, world!"))); signature.update(Strings.toUTF8ByteArray(messageToBeSigned)); TestCase.assertTrue(signature.verify(signatureValue)); } - - /* - //TODO: samples now out of date - public void testDecodingAndVerificationExternal() + + public void compositeSignaturesTest(List> testVectors) + throws Exception + { + for (int i = 0; i < testVectors.size(); i++) + { + + Map map = testVectors.get(i); + String tcId = (String)map.get("tcId"); + byte[] pk = (byte[])map.get("pk"); + byte[] x5c = (byte[])map.get("x5c"); + byte[] sk = (byte[])map.get("sk"); + byte[] sk_pkcs8 = (byte[])map.get("sk_pkcs8"); + byte[] s = (byte[])map.get("s"); + byte[] m = (byte[])map.get("m"); + byte[] x5cpk = null; + PublicKey pubKey = null, certPubKey = null; + PrivateKey privKey = null; + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + X509Certificate cert = null; + try + { + cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(x5c)); + } + catch (Exception e) + { + //Ignore IOException + } + + if (tcId.contains("id-ML-DSA")) + { + KeyFactory kFact = KeyFactory.getInstance("ML-DSA", "BC"); + MLDSAParameterSpec parameterSpec = null; + if (tcId.contains("44")) + { + parameterSpec = MLDSAParameterSpec.ml_dsa_44; + } + else if (tcId.contains("65")) + { + parameterSpec = MLDSAParameterSpec.ml_dsa_65; + } + else if (tcId.contains("87")) + { + parameterSpec = MLDSAParameterSpec.ml_dsa_87; + } + MLDSAPrivateKeySpec privSpec = new MLDSAPrivateKeySpec(parameterSpec, sk); + assertTrue(privSpec.isSeed()); + privKey = kFact.generatePrivate(privSpec); + MLDSAPublicKeySpec pubSpec = new MLDSAPublicKeySpec(((MLDSAPrivateKey)privKey).getParameterSpec(), + ((MLDSAPrivateKey)privKey).getPublicKey().getPublicData()); + pubKey = kFact.generatePublic(pubSpec); + x5cpk = ((MLDSAPublicKey)cert.getPublicKey()).getPublicData(); + certPubKey = kFact.generatePublic(new MLDSAPublicKeySpec(((MLDSAPrivateKey)privKey).getParameterSpec(), + x5cpk)); + } + else + { + KeyFactory keyFactory = KeyFactory.getInstance(oidMap.get(tcId), "BC"); + pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(new SubjectPublicKeyInfo( + new AlgorithmIdentifier(new ASN1ObjectIdentifier(oidMap.get(tcId))), pk).getEncoded())); + privKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(new PrivateKeyInfo( + new AlgorithmIdentifier(new ASN1ObjectIdentifier(oidMap.get(tcId))), new DEROctetString(sk)).getEncoded())); + certPubKey = cert.getPublicKey(); + x5cpk = certPubKey.getEncoded(); + byte[] pkEncoded = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()).getPublicKeyData().getBytes(); + TestCase.assertTrue(Arrays.areEqual(pkEncoded, pk)); + byte[] skEncoded = PrivateKeyInfo.getInstance(privKey.getEncoded()).getPrivateKey().getOctets(); + privKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(sk_pkcs8)); + TestCase.assertTrue(Arrays.areEqual(skEncoded, sk)); + } + Signature signature = Signature.getInstance(oidMap.get(tcId), "BC"); + //1. Load the public key pk or certificate x5c and use it to verify the signature s over the message m. + signature.initVerify(pubKey); + signature.update(m); + + TestCase.assertTrue(signature.verify(s)); + // 2. Validate the self-signed certificate x5c. + cert.verify(cert.getPublicKey(), "BC"); + signature.initVerify(certPubKey); + signature.update(m); + TestCase.assertTrue(signature.verify(s)); + // Compare public keys + //TestCase.assertTrue(Arrays.areEqual(pk, x5cpk)); + + // 3. Load the signing private key sk and use it to produce a new signature which can be verified using the provided pk or x5c. + signature.initSign(privKey); + signature.update(m); + byte[] signatureValue = signature.sign(); + signature.initVerify(pubKey); + signature.update(m); + TestCase.assertTrue(signature.verify(signatureValue)); + } + } + + + public List> readTestVectorsFromJson(String homeDire, String fileName) throws Exception { - InputStream is = TestResourceFinder.findTestResource("pqc/composite", "compositeSignatures.sample"); - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - String line = null; - int count = 0; - while ((line = reader.readLine()) != null) + InputStream src = TestResourceFinder.findTestResource(homeDire, fileName); + BufferedReader bin = new BufferedReader(new InputStreamReader(src)); + String line; + List> testCases = new ArrayList>(); + HashMap map = new HashMap(); + StringBuilder currentObject = null; + byte[] m = null; + while ((line = bin.readLine()) != null) { - if (line.length() == 0) + line = line.trim(); + + if (line.startsWith("{")) { - continue; + currentObject = new StringBuilder(); } - String[] lineParts = line.split(";"); + if (currentObject != null) + { + currentObject.append(line); + } - if (lineParts.length != 4) + if ((line.endsWith("},") || line.endsWith("}")) && currentObject != null) { - throw new IllegalStateException("Input file has unexpected format."); + String jsonObj = currentObject.toString(); + Map testCase = parseJsonObject(jsonObj); + testCase.put("m", m); + testCases.add(testCase); + currentObject = null; } - String oid = lineParts[0]; - String signatureValueBase64 = lineParts[1]; - String publicKeyBase64 = lineParts[2]; - String messageBase64 = lineParts[3]; - X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(Base64.decode(publicKeyBase64)); - KeyFactory keyFactory = KeyFactory.getInstance(oid, "BC"); - CompositePublicKey compositePublicKey = (CompositePublicKey)keyFactory.generatePublic(pubKeySpec); - - Signature signature = Signature.getInstance(oid, "BC"); - signature.initVerify(compositePublicKey); - signature.update(Base64.decode(messageBase64)); - assertTrue(oid.toString(), signature.verify(Base64.decode(signatureValueBase64))); - count++; + if (currentObject != null && currentObject.toString().contains("\"m\":")) + { + m = Base64.decode(extractString(currentObject.toString(), "m")); + currentObject = new StringBuilder(); + } } - assertEquals(compositeSignaturesOIDs.length, count); + return testCases; + } + + private static Map parseJsonObject(String json) + { + HashMap testCase = new HashMap(); + testCase.put("tcId", extractString(json, "tcId")); + testCase.put("pk", Base64.decode(extractString(json, "pk"))); + testCase.put("x5c", Base64.decode(extractString(json, "x5c"))); + testCase.put("sk", Base64.decode(extractString(json, "sk"))); + testCase.put("sk_pkcs8", Base64.decode(extractString(json, "sk_pkcs8"))); + testCase.put("s", Base64.decode(extractString(json, "s"))); + return testCase; + } + + private static String extractString(String json, String key) + { + String pattern = "\"" + key + "\""; + int start = json.indexOf(pattern); + if (start < 0) + { + return ""; + } + + start = json.indexOf(":", start) + 1; + while (json.charAt(start) != '"') + { + start++; + } + start++; + + int end = start; + while (json.charAt(end) != '"') + { + end++; + } + + return json.substring(start, end).replace("\\\"", "\""); + } + + public static class MyContextSpec + implements AlgorithmParameterSpec + { + private final byte[] context; + + MyContextSpec(byte[] context) + { + this.context = context; + } + + public byte[] getContext() + { + return context; + } + } + + private static class ProxyHSMPrivateKey + implements MLDSAPrivateKey + { + private final MLDSAPrivateKey privateKey; + + ProxyHSMPrivateKey(MLDSAPrivateKey privateKey) + { + this.privateKey = privateKey; + } + + @Override + public String getAlgorithm() + { + return privateKey.getAlgorithm(); + } + + @Override + public String getFormat() + { + throw new IllegalStateException("getFormat() called"); + } + + @Override + public byte[] getEncoded() + { + throw new IllegalStateException("getEncoded() called"); + } + + @Override + public MLDSAParameterSpec getParameterSpec() + { + return privateKey.getParameterSpec(); + } + + @Override + public MLDSAPublicKey getPublicKey() + { + return privateKey.getPublicKey(); + } + + @Override + public byte[] getPrivateData() + { + throw new IllegalStateException("getPrivateData() called"); + } + + @Override + public byte[] getSeed() + { + throw new IllegalStateException("getSeed() called"); + } + + @Override + public MLDSAPrivateKey getPrivateKey(boolean preferSeedOnly) + { + throw new IllegalStateException("getPrivateKey() called"); + } } - */ } diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECAlgorithmParametersTest.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECAlgorithmParametersTest.java index d863d6a6dc..b2d485371a 100644 --- a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECAlgorithmParametersTest.java +++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECAlgorithmParametersTest.java @@ -1,6 +1,7 @@ package org.bouncycastle.jcajce.provider.test; import java.security.AlgorithmParameters; +import java.security.Provider; import java.security.Security; import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; @@ -138,6 +139,22 @@ public class ECAlgorithmParametersTest "X9.62 c2pnb368w1", "1.2.840.10045.3.0.19"}; + public static void main(String[] args) + { + ECAlgorithmParametersTest test = new ECAlgorithmParametersTest(); + test.testSupportAttributes(); + } + + public void testSupportAttributes() + { + Provider prov = new BouncyCastleProvider(); + String target = prov.getService("AlgorithmParameters", "EC").getAttribute("SupportedCurves"); + for (int i = 0; i != entries.length; i++) + { + TestCase.assertTrue(entries[i] + " should be in the list", target.contains(entries[i])); + } + } + public void testRecogniseStandardCurveNames() throws Exception { diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/RandomTest.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/RandomTest.java index 5804c43f6d..0b4f11fec4 100644 --- a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/RandomTest.java +++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/RandomTest.java @@ -2,7 +2,6 @@ import java.security.SecureRandom; -import junit.framework.Assert; import junit.framework.TestCase; import org.bouncycastle.jce.provider.BouncyCastleProvider; @@ -18,7 +17,7 @@ public void testCheckRandom() random.nextBytes(rng); - Assert.assertTrue(checkNonConstant(rng)); + assertTrue(checkNonConstant(rng)); } public void testCheckNonceIVRandom() @@ -30,7 +29,7 @@ public void testCheckNonceIVRandom() random.nextBytes(rng); - Assert.assertTrue(checkNonConstant(rng)); + assertTrue(checkNonConstant(rng)); } private boolean checkNonConstant(byte[] data) diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/SecretKeyUtilTest.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/SecretKeyUtilTest.java new file mode 100644 index 0000000000..a545cdea09 --- /dev/null +++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/SecretKeyUtilTest.java @@ -0,0 +1,24 @@ +package org.bouncycastle.jcajce.provider.test; + +import junit.framework.TestCase; +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers; +import org.bouncycastle.jcajce.provider.util.SecretKeyUtil; + +public class SecretKeyUtilTest + extends TestCase +{ + public void testgetKeySize() + { + assertEquals(192, SecretKeyUtil.getKeySize(PKCSObjectIdentifiers.des_EDE3_CBC)); + + assertEquals(128, SecretKeyUtil.getKeySize(NISTObjectIdentifiers.id_aes128_CBC)); + assertEquals(192, SecretKeyUtil.getKeySize(NISTObjectIdentifiers.id_aes192_CBC)); + assertEquals(256, SecretKeyUtil.getKeySize(NISTObjectIdentifiers.id_aes256_CBC)); + + assertEquals(128, SecretKeyUtil.getKeySize(NTTObjectIdentifiers.id_camellia128_cbc)); + assertEquals(192, SecretKeyUtil.getKeySize(NTTObjectIdentifiers.id_camellia192_cbc)); + assertEquals(256, SecretKeyUtil.getKeySize(NTTObjectIdentifiers.id_camellia256_cbc)); + } +} diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/BlockCipherTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/BlockCipherTest.java index 2209f35b66..df47466717 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/BlockCipherTest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/BlockCipherTest.java @@ -7,6 +7,7 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.InvalidParameterException; @@ -37,12 +38,17 @@ import javax.crypto.spec.RC5ParameterSpec; import javax.crypto.spec.SecretKeySpec; +import org.bouncycastle.crypto.BufferedBlockCipher; +import org.bouncycastle.crypto.DefaultMultiBlockCipher; +import org.bouncycastle.crypto.engines.AESEngine; +import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; import org.bouncycastle.util.test.TestFailedException; + /** * basic test class for a block cipher, basically this just exercises the provider, and makes sure we * are behaving sensibly, correctness of the implementation is shown in the lightweight test classes. @@ -842,6 +848,61 @@ else if (algorithm.startsWith("RC5")) fail("" + algorithm + " failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); } + // + // Try the doFinal - same input/output same index, index + // + byte[] data = Arrays.concatenate(input, new byte[2 * in.getBlockSize()]); + int len = 0; + try + { + if (algorithm.indexOf("GCM") > 0) + { + out = Cipher.getInstance(algorithm, "BC"); + out.init(Cipher.ENCRYPT_MODE, key, rand); + } + + len = out.doFinal(data, 0, input.length, data, 0); + } + catch (Exception e) + { + fail(e.toString()); + } + + if (!Arrays.areEqual(data, 0, len, output, 0, output.length)) + { + fail("" + algorithm + " failed doFinal - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(data))); + } + + // + // Try the doFinal - same input/output shifted offset + // + data = Arrays.concatenate(input, new byte[2 * in.getBlockSize()]); + len = 0; + try + { + + if (algorithm.indexOf("GCM") > 0) + { + out = Cipher.getInstance(algorithm, "BC"); + out.init(Cipher.ENCRYPT_MODE, key, rand); + } + + len = out.doFinal(data, 0, input.length, data, 1); + +// System.out.println(Hex.toHexString(output)); +// System.out.println(Hex.toHexString(Arrays.copyOfRange(data, 1, 1 + len))); +// System.out.println(len + " " + output.length); + } + catch (Exception e) + { + fail(e.toString()); + } + + if (!Arrays.areEqual(data, 1, 1 + len, output, 0, output.length)) + { + fail("" + algorithm + " failed doFinal - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(data))); + } + // // decryption pass // @@ -1699,6 +1760,7 @@ private void testIncorrectCipherModes() } public void performTest() + throws Exception { for (int i = 0; i != cipherTests1.length; i += 2) { @@ -1738,6 +1800,163 @@ public void performTest() testExceptions(); testIncorrectCipherModes(); + doFinalTest(); + testOverlapping(); + testOverlapping2(); + testOverlap(); + } + + private void doFinalTest() + { + try + { + int INPUT_LENGTH = 32; + int offset = 1; + byte[] PT = new byte[INPUT_LENGTH + offset]; + SecretKey KEY = new SecretKeySpec(new byte[16], "AES"); + Cipher c = Cipher.getInstance("AES/ECB/NoPadding", "BC"); + c.init(Cipher.ENCRYPT_MODE, KEY); + int len = c.doFinal(PT, 0, INPUT_LENGTH, PT, offset); + + byte[] expected = Hex.decode("0066e94bd4ef8a2c3b884cfa59ca342b2e66e94bd4ef8a2c3b884cfa59ca342b2e"); + + isTrue("expected not match PT", areEqual(expected, PT)); + } + catch (GeneralSecurityException e) + { + fail(e.toString()); + } + } + + private void testOverlapping() + throws Exception + { + //Skip the dofinal of the test + BufferedBlockCipher bc = new BufferedBlockCipher(AESEngine.newInstance()); + SecureRandom random = new SecureRandom(); + byte[] keyBytes = new byte[16]; + random.nextBytes(keyBytes); + KeyParameter key = new KeyParameter(keyBytes); + + int offset = 2 + random.nextInt(bc.getBlockSize() - 1); + byte[] data = new byte[bc.getBlockSize() * 2 + offset]; + byte[] expected = new byte[bc.getOutputSize(bc.getBlockSize() * 2)]; + random.nextBytes(data); + + bc.init(true, key); + int r = bc.processBytes(data, 0, bc.getBlockSize() * 2, expected, 0); + r += bc.doFinal(expected, r); + + bc.init(true, key); + r = bc.processBytes(data, 0, bc.getBlockSize() * 2, data, offset); + r += bc.doFinal(data, r + offset); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + bc.getBlockSize() * 2))) + { + fail("failed for overlapping encryption"); + } + + bc.init(false, key); + bc.processBytes(data, 0, bc.getBlockSize() * 2 + 1, expected, 0); + bc.init(false, key); + bc.processBytes(data, 0, bc.getBlockSize() * 2 + 1, data, offset); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + bc.getBlockSize() * 2))) + { + fail("failed for overlapping decryption"); + } + } + + private void testOverlapping2() + { + //Skip the dofinal of the test + DefaultMultiBlockCipher bc = new AESEngine(); + SecureRandom random = new SecureRandom(); + byte[] keyBytes = new byte[16]; + random.nextBytes(keyBytes); + KeyParameter key = new KeyParameter(keyBytes); + + int offset = 2 + random.nextInt(bc.getBlockSize() - 1); + byte[] data = new byte[bc.getBlockSize() * 2 + offset]; + byte[] expected = new byte[bc.getBlockSize() * 2]; + random.nextBytes(data); + + bc.init(true, key); + bc.processBlocks(data, 0, 2, expected, 0); + bc.init(true, key); + bc.processBlocks(data, 0, 2, data, offset); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + bc.getBlockSize() * 2))) + { + fail("failed to overlapping of encryption"); + } + + bc.init(false, key); + bc.processBlocks(data, 0, 2, expected, 0); + bc.init(false, key); + bc.processBlocks(data, 0, 2, data, offset); + + if (!areEqual(expected, Arrays.copyOfRange(data, offset, offset + bc.getBlockSize() * 2))) + { + fail("failed to overlapping of encryption"); + } + } + + public void testOverlap() + { + try + { + int l = 32; + byte[] msg = new byte[l]; + Arrays.fill(msg, (byte)1); + + byte[] workingArray = new byte[l * 2]; + Arrays.fill(workingArray, (byte)1); + System.arraycopy(msg, 0, workingArray, 0, msg.length); + + byte[] originalWorkingArray = new byte[workingArray.length]; + System.arraycopy(workingArray, 0, originalWorkingArray, 0, workingArray.length); + + Cipher javaEncrypt = Cipher.getInstance("AES/ECB/NoPadding", BouncyCastleProvider.PROVIDER_NAME); + javaEncrypt.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[16], "AES")); + + // + // Expected encryption + // + byte[] expectedOutput = new byte[msg.length]; + javaEncrypt.doFinal(msg, 0, msg.length, expectedOutput, 0); + + + // + // We expect to see the "expectedOutput" being written at each offset. + // + for (int outputOffset = 0; outputOffset < msg.length; outputOffset++) + { + javaEncrypt.doFinal(workingArray, 0, msg.length, workingArray, outputOffset); + + // Grab a copy of the produced cipher text + byte[] ct = Arrays.copyOfRange(workingArray, outputOffset, outputOffset + msg.length); +// System.out.println("\nOutput Offset: " + outputOffset); +// System.out.println("Expected: " + pad(outputOffset * 2) + Hex.toHexString(expectedOutput)); +// System.out.println("Actual : " + Hex.toHexString(workingArray)); + + isTrue(Arrays.areEqual(ct, expectedOutput)); + + System.arraycopy(originalWorkingArray, 0, workingArray, 0, originalWorkingArray.length); + } + } + catch (Exception e) + { + fail(e.getMessage(), e); + } + + } + + public String pad(int len) + { + char[] buf = new char[len]; + Arrays.fill(buf, ' '); + return new String(buf); } public static void main( diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/CertPathBuilderTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/CertPathBuilderTest.java index 07a1e6b992..8b133f984c 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/CertPathBuilderTest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/CertPathBuilderTest.java @@ -117,6 +117,54 @@ private void v0Test() } } + private void noSigV0Test() + throws Exception + { + // create certificates and CRLs + KeyPair rootPair = TestUtils.generateRSAKeyPair(); + KeyPair interPair = TestUtils.generateRSAKeyPair(); + KeyPair endPair = TestUtils.generateRSAKeyPair(); + + X509Certificate rootCert = TestUtils.generateNoSigRootCert(rootPair); + X509Certificate interCert = TestUtils.generateIntermediateCert(interPair.getPublic(), rootPair.getPrivate(), rootCert); + X509Certificate endCert = TestUtils.generateEndEntityCert(endPair.getPublic(), interPair.getPrivate(), interCert); + + BigInteger revokedSerialNumber = BigInteger.valueOf(2); + X509CRL rootCRL = TestCertificateGen.createCRL(rootCert, rootPair.getPrivate(), revokedSerialNumber); + X509CRL interCRL = TestCertificateGen.createCRL(interCert, interPair.getPrivate(), revokedSerialNumber); + + // create CertStore to support path building + List list = new ArrayList(); + + list.add(rootCert); + list.add(interCert); + list.add(endCert); + list.add(rootCRL); + list.add(interCRL); + + CollectionCertStoreParameters params = new CollectionCertStoreParameters(list); + CertStore store = CertStore.getInstance("Collection", params); + + // build the path + CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", "BC"); + X509CertSelector pathConstraints = new X509CertSelector(); + + pathConstraints.setSubject(endCert.getSubjectX500Principal().getEncoded()); + + PKIXBuilderParameters buildParams = new PKIXBuilderParameters(Collections.singleton(new TrustAnchor(rootCert, null)), pathConstraints); + + buildParams.addCertStore(store); + buildParams.setDate(new Date()); + + PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult)builder.build(buildParams); + CertPath path = result.getCertPath(); + + if (path.getCertificates().size() != 2) + { + fail("wrong number of certs in v0Test path"); + } + } + private void eeInSelectorTest() throws Exception { @@ -206,10 +254,11 @@ private void eeOnlyInSelectorTest() public void performTest() throws Exception { - baseTest(); - v0Test(); - eeInSelectorTest(); - eeOnlyInSelectorTest(); +// baseTest(); +// v0Test(); + noSigV0Test(); +// eeInSelectorTest(); +// eeOnlyInSelectorTest(); } public String getName() diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java index dbcedc5f2a..30ef07cee0 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java @@ -1393,7 +1393,7 @@ private int calculateHashCode() public String toString() { - StringBuffer buf = new StringBuffer(); + StringBuilder buf = new StringBuilder(); String nl = Strings.lineSeparator(); buf.append(" [0] Version: ").append(this.getVersion()).append(nl); @@ -1668,7 +1668,7 @@ private static Collection getAlternativeNames(byte[] extVal) } } - private class DodgyCertificate + private static class DodgyCertificate extends ASN1Object { ASN1Sequence seq; @@ -1758,7 +1758,7 @@ public ASN1Primitive toASN1Primitive() } } - private class DodgyTBSCertificate + private static class DodgyTBSCertificate extends ASN1Object { ASN1Sequence seq; @@ -1791,7 +1791,7 @@ private DodgyTBSCertificate( else { seqStart = -1; // field 0 is missing! - version = new ASN1Integer(0); + version = ASN1Integer.ZERO; } boolean isV1 = false; diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/CertUniqueIDTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/CertUniqueIDTest.java index b61018bc98..a1dc5a5f79 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/CertUniqueIDTest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/CertUniqueIDTest.java @@ -129,7 +129,7 @@ public void checkCreation1() private String arrayToString(boolean[] array) { - StringBuffer b = new StringBuffer(); + StringBuilder b = new StringBuilder(); for (int i = 0; i != array.length; i++) { diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/CipherStreamTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/CipherStreamTest.java index 55181ad62a..4220bedf2d 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/CipherStreamTest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/CipherStreamTest.java @@ -100,7 +100,7 @@ public class CipherStreamTest private static final byte[] GRAIN_128 = Hex.decode("0123456789abcdef123456789abcdef0"); private static final byte[] GRAIN_128_IV = Hex.decode("0123456789abcdef12345678"); private static final byte[] GRAIN_128_IN = new byte[16]; - private static final byte[] GRAIN_128_OUT = Hex.decode("afb5babfa8de896b4b9c6acaf7c4fbfd"); + private static final byte[] GRAIN_128_OUT = Hex.decode("ba399daf90df8eba103d9ea83c805904"); public CipherStreamTest() { diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/DESedeTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/DESedeTest.java index 684fb17335..416e0cb55b 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/DESedeTest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/DESedeTest.java @@ -19,6 +19,7 @@ import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTest; @@ -79,50 +80,11 @@ public String getName() return "DESEDE"; } - private boolean equalArray( - byte[] a, - byte[] b) + private static boolean equalPrefix(byte[] a, byte[] b, int length) { - if (a.length != b.length) - { - return false; - } - - for (int i = 0; i != a.length; i++) - { - if (a[i] != b[i]) - { - return false; - } - } - - return true; - } - - private boolean equalArray( - byte[] a, - byte[] b, - int length) - { - if (a.length < length) - { - return false; - } - - if (b.length < length) - { - return false; - } - - for (int i = 0; i != length; i++) - { - if (a[i] != b[i]) - { - return false; - } - } - - return true; + return a.length >= length + && b.length >= length + && Arrays.areEqual(a, 0, length, b, 0, length); } private void wrapTest( @@ -142,7 +104,7 @@ private void wrapTest( try { byte[] cText = wrapper.wrap(new SecretKeySpec(in, alg)); - if (!equalArray(cText, out)) + if (!Arrays.areEqual(cText, out)) { fail("failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); } @@ -157,7 +119,7 @@ private void wrapTest( try { Key pText = wrapper.unwrap(out, alg, Cipher.SECRET_KEY); - if (!equalArray(pText.getEncoded(), in)) + if (!Arrays.areEqual(pText.getEncoded(), in)) { fail("failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText.getEncoded()))); } @@ -242,7 +204,7 @@ public void test( bytes = bOut.toByteArray(); - if (!equalArray(bytes, output)) + if (!Arrays.areEqual(bytes, output)) { fail(alg + " failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); } @@ -265,13 +227,14 @@ public void test( bytes[i] = (byte)dIn.read(); } dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + dIn.close(); } catch (Exception e) { fail(alg + " failed encryption - " + e.toString()); } - if (!equalArray(bytes, input)) + if (!Arrays.areEqual(bytes, input)) { fail(alg + " failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); } @@ -284,7 +247,7 @@ public void test( SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(alg, "BC"); DESedeKeySpec keySpec = (DESedeKeySpec)keyFactory.getKeySpec((SecretKey)key, DESedeKeySpec.class); - if (!equalArray(key.getEncoded(), keySpec.getKey(), 16)) + if (!equalPrefix(key.getEncoded(), keySpec.getKey(), 16)) { fail(alg + " KeySpec does not match key."); } diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/DSATest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/DSATest.java index 4701e449d1..89b3ee3ace 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/DSATest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/DSATest.java @@ -274,7 +274,7 @@ 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()); + X509EncodedKeySpec x509s = new X509EncodedKeySpec(new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), ASN1Integer.valueOf(10001)).getEncoded()); DSAPublicKey key1 = (DSAPublicKey)f.generatePublic(x509s); DSAPublicKey key2 = (DSAPublicKey)f.generatePublic(x509s); diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/DSTU4145Test.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/DSTU4145Test.java index 44e89c2755..abc8598603 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/DSTU4145Test.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/DSTU4145Test.java @@ -36,8 +36,7 @@ public String getName() public void performTest() throws Exception { - - DSTU4145Test(); + implDSTU4145Test(); generationTest(); //parametersTest(); generateFromCurveTest(); @@ -127,7 +126,7 @@ private void generateFromCurveTest() } } - private void DSTU4145Test() + private void implDSTU4145Test() throws Exception { diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/DetDSATest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/DetDSATest.java index 8e75b474c5..1c4a7cef9b 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/DetDSATest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/DetDSATest.java @@ -14,8 +14,8 @@ import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.nist.NISTNamedCurves; import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.ec.CustomNamedCurves; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.util.encoders.Hex; @@ -78,13 +78,16 @@ private void doTestHMACDetDSATest(String algName, PrivateKey privKey, BigInteger private void testECHMacDeterministic() throws Exception { - X9ECParameters x9ECParameters = NISTNamedCurves.getByName("P-192"); - ECCurve curve = x9ECParameters.getCurve(); + X9ECParameters x9ECParameters = CustomNamedCurves.getByName("P-192"); + ECCurve.AbstractFp curve = (ECCurve.AbstractFp)x9ECParameters.getCurve(); + BigInteger q = curve.getQ(); + + org.bouncycastle.math.ec.ECPoint g = x9ECParameters.getG().normalize(); ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(new BigInteger("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), new ECParameterSpec( - new EllipticCurve(new ECFieldFp(((ECCurve.Fp)curve).getQ()), curve.getA().toBigInteger(), curve.getB().toBigInteger(), null), - new ECPoint(x9ECParameters.getG().getXCoord().toBigInteger(), x9ECParameters.getG().getYCoord().toBigInteger()), + new EllipticCurve(new ECFieldFp(q), curve.getA().toBigInteger(), curve.getB().toBigInteger(), null), + new ECPoint(g.getAffineXCoord().toBigInteger(), g.getAffineYCoord().toBigInteger()), x9ECParameters.getN(), x9ECParameters.getH().intValue()) ); diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/EdECTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/EdECTest.java index 6069675087..45ddcd75a0 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/EdECTest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/EdECTest.java @@ -751,7 +751,7 @@ private void testPKCS8Override() PrivateKeyInfo info = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded()); isTrue(info.getPublicKeyData() == null); - isTrue(info.getVersion().equals(new ASN1Integer(0))); + isTrue(info.getVersion().equals(ASN1Integer.ZERO)); kpGen = KeyPairGenerator.getInstance("XDH", "BC"); @@ -762,7 +762,7 @@ private void testPKCS8Override() info = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded()); isTrue(info.getPublicKeyData() == null); - isTrue(info.getVersion().equals(new ASN1Integer(0))); + isTrue(info.getVersion().equals(ASN1Integer.ZERO)); System.setProperty("org.bouncycastle.pkcs8.v1_info_only", "false"); @@ -775,7 +775,7 @@ private void testPKCS8Override() info = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded()); isTrue(info.getPublicKeyData() != null); - isTrue(info.getVersion().equals(new ASN1Integer(1))); + isTrue(info.getVersion().equals(ASN1Integer.ONE)); kpGen = KeyPairGenerator.getInstance("XDH", "BC"); @@ -786,7 +786,7 @@ private void testPKCS8Override() info = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded()); isTrue(info.getPublicKeyData() != null); - isTrue(info.getVersion().equals(new ASN1Integer(1))); + isTrue(info.getVersion().equals(ASN1Integer.ONE)); } public static void main( diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/FIPSDESTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/FIPSDESTest.java index 80024d458a..f9af706d6c 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/FIPSDESTest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/FIPSDESTest.java @@ -16,6 +16,7 @@ import javax.crypto.spec.SecretKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTestResult; import org.bouncycastle.util.test.Test; @@ -54,26 +55,6 @@ public String getName() return "FIPSDESTest"; } - private boolean equalArray( - byte[] a, - byte[] b) - { - if (a.length != b.length) - { - return false; - } - - for (int i = 0; i != a.length; i++) - { - if (a[i] != b[i]) - { - return false; - } - } - - return true; - } - public TestResult test( String algorithm, byte[] input, @@ -89,8 +70,6 @@ public TestResult test( try { - String baseAlgorithm; - key = new SecretKeySpec(Hex.decode("0123456789abcdef"), "DES"); in = Cipher.getInstance(algorithm, "BC"); @@ -151,7 +130,7 @@ public TestResult test( bytes = bOut.toByteArray(); - if (!equalArray(bytes, output)) + if (!Arrays.areEqual(bytes, output)) { return new SimpleTestResult(false, getName() + ": " + algorithm + " failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); } @@ -174,13 +153,14 @@ public TestResult test( bytes[i] = (byte)dIn.read(); } dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + dIn.close(); } catch (Exception e) { return new SimpleTestResult(false, getName() + ": " + algorithm + " failed encryption - " + e.toString()); } - if (!equalArray(bytes, input)) + if (!Arrays.areEqual(bytes, input)) { return new SimpleTestResult(false, getName() + ": " + algorithm + " failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); } diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/PBETest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/PBETest.java index a566bb64fc..4a96f95702 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/PBETest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/PBETest.java @@ -23,10 +23,18 @@ import org.bouncycastle.asn1.bc.BCObjectIdentifiers; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.PBEParametersGenerator; +import org.bouncycastle.crypto.digests.GOST3411Digest; 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.digests.SM3Digest; import org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator; import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; +import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.jcajce.PKCS12Key; @@ -49,17 +57,17 @@ public class PBETest private static class OpenSSLTest extends SimpleTest { - char[] password; - String baseAlgorithm; - String algorithm; - int keySize; - int ivSize; - + char[] password; + String baseAlgorithm; + String algorithm; + int keySize; + int ivSize; + OpenSSLTest( - String baseAlgorithm, - String algorithm, - int keySize, - int ivSize) + String baseAlgorithm, + String algorithm, + int keySize, + int ivSize) { this.password = algorithm.toCharArray(); this.baseAlgorithm = baseAlgorithm; @@ -67,35 +75,35 @@ private static class OpenSSLTest this.keySize = keySize; this.ivSize = ivSize; } - + public String getName() { return "OpenSSLPBE"; } - + public void performTest() throws Exception { byte[] salt = new byte[16]; - int iCount = 100; - + int iCount = 100; + for (int i = 0; i != salt.length; i++) { salt[i] = (byte)i; } - OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); + OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); pGen.init( - PBEParametersGenerator.PKCS5PasswordToBytes(password), - salt, - iCount); + PBEParametersGenerator.PKCS5PasswordToBytes(password), + salt, + iCount); ParametersWithIV params = (ParametersWithIV)pGen.generateDerivedParameters(keySize, ivSize); - SecretKeySpec encKey = new SecretKeySpec(((KeyParameter)params.getParameters()).getKey(), baseAlgorithm); + SecretKeySpec encKey = new SecretKeySpec(((KeyParameter)params.getParameters()).getKey(), baseAlgorithm); - Cipher c; + Cipher c; if (baseAlgorithm.equals("RC4")) { @@ -110,16 +118,16 @@ public void performTest() c.init(Cipher.ENCRYPT_MODE, encKey, new IvParameterSpec(params.getIV())); } - byte[] enc = c.doFinal(salt); + byte[] enc = c.doFinal(salt); c = Cipher.getInstance(algorithm, "BC"); - PBEKeySpec keySpec = new PBEKeySpec(password, salt, iCount); - SecretKeyFactory fact = SecretKeyFactory.getInstance(algorithm, "BC"); + PBEKeySpec keySpec = new PBEKeySpec(password, salt, iCount); + SecretKeyFactory fact = SecretKeyFactory.getInstance(algorithm, "BC"); c.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec)); - byte[] dec = c.doFinal(enc); + byte[] dec = c.doFinal(enc); if (!Arrays.areEqual(salt, dec)) { @@ -127,23 +135,23 @@ public void performTest() } } } - + private static class PKCS12Test extends SimpleTest { - char[] password; - String baseAlgorithm; - String algorithm; - Digest digest; - int keySize; - int ivSize; - + char[] password; + String baseAlgorithm; + String algorithm; + Digest digest; + int keySize; + int ivSize; + PKCS12Test( - String baseAlgorithm, - String algorithm, - Digest digest, - int keySize, - int ivSize) + String baseAlgorithm, + String algorithm, + Digest digest, + int keySize, + int ivSize) { this.password = algorithm.toCharArray(); this.baseAlgorithm = baseAlgorithm; @@ -152,32 +160,32 @@ private static class PKCS12Test this.keySize = keySize; this.ivSize = ivSize; } - + public String getName() { return "PKCS12PBE"; } - + public void performTest() throws Exception { byte[] salt = new byte[digest.getDigestSize()]; - int iCount = 100; - + int iCount = 100; + digest.doFinal(salt, 0); - PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(digest); + PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(digest); pGen.init( - PBEParametersGenerator.PKCS12PasswordToBytes(password), - salt, - iCount); + PBEParametersGenerator.PKCS12PasswordToBytes(password), + salt, + iCount); ParametersWithIV params = (ParametersWithIV)pGen.generateDerivedParameters(keySize, ivSize); - SecretKeySpec encKey = new SecretKeySpec(((KeyParameter)params.getParameters()).getKey(), baseAlgorithm); + SecretKeySpec encKey = new SecretKeySpec(((KeyParameter)params.getParameters()).getKey(), baseAlgorithm); - Cipher c; + Cipher c; if (baseAlgorithm.equals("RC4")) { @@ -192,26 +200,26 @@ public void performTest() c.init(Cipher.ENCRYPT_MODE, encKey, new IvParameterSpec(params.getIV())); } - byte[] enc = c.doFinal(salt); + byte[] enc = c.doFinal(salt); c = Cipher.getInstance(algorithm, "BC"); - PBEKeySpec keySpec = new PBEKeySpec(password, salt, iCount); - SecretKeyFactory fact = SecretKeyFactory.getInstance(algorithm, "BC"); + PBEKeySpec keySpec = new PBEKeySpec(password, salt, iCount); + SecretKeyFactory fact = SecretKeyFactory.getInstance(algorithm, "BC"); c.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec)); - byte[] dec = c.doFinal(enc); + byte[] dec = c.doFinal(enc); if (!Arrays.areEqual(salt, dec)) { fail("" + algorithm + "failed encryption/decryption test"); } - + // // get the parameters // - AlgorithmParameters param = checkParameters(c, salt, iCount); + AlgorithmParameters param = checkParameters(c, algorithm, salt, iCount); // // try using parameters @@ -222,7 +230,7 @@ public void performTest() c.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec), param); - checkParameters(c, salt, iCount); + checkParameters(c, algorithm, salt, iCount); dec = c.doFinal(enc); @@ -240,7 +248,7 @@ public void performTest() c.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec), param.getParameterSpec(PBEParameterSpec.class)); - checkParameters(c, salt, iCount); + checkParameters(c, algorithm, salt, iCount); dec = c.doFinal(enc); @@ -250,7 +258,7 @@ public void performTest() } } - private AlgorithmParameters checkParameters(Cipher c, byte[] salt, int iCount) + private AlgorithmParameters checkParameters(Cipher c, String algorithm, byte[] salt, int iCount) throws InvalidParameterSpecException { AlgorithmParameters param = c.getParameters(); @@ -268,54 +276,175 @@ private AlgorithmParameters checkParameters(Cipher c, byte[] salt, int iCount) return param; } } + + private static class PBKDF2Test + extends SimpleTest + { + char[] password; + String baseAlgorithm; + String algorithm; + Digest digest; + int keySize; + + PBKDF2Test( + String baseAlgorithm, + String algorithm, + Digest digest, + int keySize) + { + this.password = algorithm.toCharArray(); + this.baseAlgorithm = baseAlgorithm; + this.algorithm = algorithm; + this.digest = digest; + this.keySize = keySize; + } + + public String getName() + { + return "PBKDF2PBE"; + } + + public void performTest() + throws Exception + { + byte[] salt = new byte[digest.getDigestSize()]; + int iCount = 100; + + digest.doFinal(salt, 0); + + PKCS5S2ParametersGenerator pGen = new PKCS5S2ParametersGenerator(digest); + + pGen.init( + PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password), + salt, + iCount); + + ParametersWithIV params = (ParametersWithIV)pGen.generateDerivedParameters(keySize, 128); + + SecretKeySpec encKey = new SecretKeySpec(((KeyParameter)params.getParameters()).getKey(), baseAlgorithm); + + String cipherAlgorithm = baseAlgorithm + "/CBC/PKCS7Padding"; + Cipher c = Cipher.getInstance(cipherAlgorithm, "BC"); + + c.init(Cipher.ENCRYPT_MODE, encKey, new IvParameterSpec(params.getIV())); + + byte[] enc = c.doFinal(salt); + + c = Cipher.getInstance(cipherAlgorithm, "BC"); + + PBEKeySpec keySpec = new PBEKeySpec(password, salt, iCount, keySize); + SecretKeyFactory fact = SecretKeyFactory.getInstance(algorithm, "BC"); + + c.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec), new IvParameterSpec(params.getIV())); + + byte[] dec = c.doFinal(enc); + + if (!Arrays.areEqual(salt, dec)) + { + fail("" + algorithm + "failed encryption/decryption test"); + } + // + // get the parameters + // + AlgorithmParameters param = c.getParameters(); + + // + // try using parameters + // + c = Cipher.getInstance(cipherAlgorithm, "BC"); + + c.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec), param); + + dec = c.doFinal(enc); + + if (!Arrays.areEqual(salt, dec)) + { + fail("" + algorithm + "failed encryption/decryption test"); + } + } + + private AlgorithmParameters checkParameters(Cipher c, String algorithm, byte[] salt, int iCount) + throws InvalidParameterSpecException + { + AlgorithmParameters param = c.getParameters(); + PBEParameterSpec spec = (PBEParameterSpec)param.getParameterSpec(PBEParameterSpec.class); + + if (!Arrays.areEqual(salt, spec.getSalt())) + { + fail("" + algorithm + "failed salt test"); + } + + if (iCount != spec.getIterationCount()) + { + fail("" + algorithm + "failed count test"); + } + return param; + } + } + private PKCS12Test[] pkcs12Tests = { - new PKCS12Test("DESede", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC", new SHA1Digest(), 192, 64), - new PKCS12Test("DESede", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC", new SHA1Digest(), 128, 64), - new PKCS12Test("RC4", "PBEWITHSHAAND128BITRC4", new SHA1Digest(), 128, 0), - new PKCS12Test("RC4", "PBEWITHSHAAND40BITRC4", new SHA1Digest(), 40, 0), - new PKCS12Test("RC2", "PBEWITHSHAAND128BITRC2-CBC", new SHA1Digest(), 128, 64), - new PKCS12Test("RC2", "PBEWITHSHAAND40BITRC2-CBC", new SHA1Digest(), 40, 64), - new PKCS12Test("AES", "PBEWithSHA1And128BitAES-CBC-BC", new SHA1Digest(), 128, 128), - new PKCS12Test("AES", "PBEWithSHA1And192BitAES-CBC-BC", new SHA1Digest(), 192, 128), - new PKCS12Test("AES", "PBEWithSHA1And256BitAES-CBC-BC", new SHA1Digest(), 256, 128), - new PKCS12Test("AES", "PBEWithSHA256And128BitAES-CBC-BC", new SHA256Digest(), 128, 128), - new PKCS12Test("AES", "PBEWithSHA256And192BitAES-CBC-BC", new SHA256Digest(), 192, 128), - new PKCS12Test("AES", "PBEWithSHA256And256BitAES-CBC-BC", new SHA256Digest(), 256, 128), - new PKCS12Test("Twofish","PBEWithSHAAndTwofish-CBC", new SHA1Digest(), 256, 128), - new PKCS12Test("IDEA", "PBEWithSHAAndIDEA-CBC", new SHA1Digest(), 128, 64), - new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), new SHA1Digest(), 128, 128), - new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), new SHA1Digest(), 192, 128), - new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), new SHA1Digest(), 256, 128), - new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), new SHA256Digest(), 128, 128), - new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), new SHA256Digest(), 192, 128), - new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), new SHA256Digest(), 256, 128), + new PKCS12Test("DESede", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC", new SHA1Digest(), 192, 64), + new PKCS12Test("DESede", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC", new SHA1Digest(), 128, 64), + new PKCS12Test("RC4", "PBEWITHSHAAND128BITRC4", new SHA1Digest(), 128, 0), + new PKCS12Test("RC4", "PBEWITHSHAAND40BITRC4", new SHA1Digest(), 40, 0), + new PKCS12Test("RC2", "PBEWITHSHAAND128BITRC2-CBC", new SHA1Digest(), 128, 64), + new PKCS12Test("RC2", "PBEWITHSHAAND40BITRC2-CBC", new SHA1Digest(), 40, 64), + new PKCS12Test("AES", "PBEWithSHA1And128BitAES-CBC-BC", new SHA1Digest(), 128, 128), + new PKCS12Test("AES", "PBEWithSHA1And192BitAES-CBC-BC", new SHA1Digest(), 192, 128), + new PKCS12Test("AES", "PBEWithSHA1And256BitAES-CBC-BC", new SHA1Digest(), 256, 128), + new PKCS12Test("AES", "PBEWithSHA256And128BitAES-CBC-BC", new SHA256Digest(), 128, 128), + new PKCS12Test("AES", "PBEWithSHA256And192BitAES-CBC-BC", new SHA256Digest(), 192, 128), + new PKCS12Test("AES", "PBEWithSHA256And256BitAES-CBC-BC", new SHA256Digest(), 256, 128), + new PKCS12Test("Twofish", "PBEWithSHAAndTwofish-CBC", new SHA1Digest(), 256, 128), + new PKCS12Test("IDEA", "PBEWithSHAAndIDEA-CBC", new SHA1Digest(), 128, 64), + new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), new SHA1Digest(), 128, 128), + new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), new SHA1Digest(), 192, 128), + new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), new SHA1Digest(), 256, 128), + new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), new SHA256Digest(), 128, 128), + new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), new SHA256Digest(), 192, 128), + new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), new SHA256Digest(), 256, 128), }; - + + private PBKDF2Test[] pbkdf2Tests = { + new PBKDF2Test("AES", "PBKDF2WITHHMACSHA224", new SHA224Digest(), 256), + new PBKDF2Test("AES", "PBKDF2WITHHMACSHA256", new SHA256Digest(), 256), + new PBKDF2Test("AES", "PBKDF2WITHHMACSHA384", new SHA384Digest(), 256), + new PBKDF2Test("AES", "PBKDF2WITHHMACSHA512", new SHA512Digest(), 256), + new PBKDF2Test("AES", "PBKDF2WITHHMACSHA512-224", new SHA512tDigest(224), 256), + new PBKDF2Test("AES", "PBKDF2WITHHMACSHA512-256", new SHA512tDigest(256), 256), + new PBKDF2Test("AES", "PBKDF2WITHHMACSHA3-224", new SHA3Digest(224), 256), + new PBKDF2Test("AES", "PBKDF2WITHHMACSHA3-256", new SHA3Digest(256), 256), + new PBKDF2Test("AES", "PBKDF2WITHHMACSHA3-384", new SHA3Digest(384), 256), + new PBKDF2Test("AES", "PBKDF2WITHHMACSHA3-512", new SHA3Digest(512), 256), + new PBKDF2Test("AES", "PBKDF2WITHHMACGOST3411", new GOST3411Digest(), 256), + new PBKDF2Test("AES", "PBKDF2WITHHMACSM3", new SM3Digest(), 256) + }; + private OpenSSLTest openSSLTests[] = { new OpenSSLTest("AES", "PBEWITHMD5AND128BITAES-CBC-OPENSSL", 128, 128), new OpenSSLTest("AES", "PBEWITHMD5AND192BITAES-CBC-OPENSSL", 192, 128), new OpenSSLTest("AES", "PBEWITHMD5AND256BITAES-CBC-OPENSSL", 256, 128) }; - - static byte[] message = Hex.decode("4869205468657265"); - + + static byte[] message = Hex.decode("4869205468657265"); + private byte[] hMac1 = Hex.decode("bcc42174ccb04f425d9a5c8c4a95d6fd7c372911"); private byte[] hMac2 = Hex.decode("cb1d8bdb6aca9e3fa8980d6eb41ab28a7eb2cfd6"); private byte[] hMac3 = Hex.decode("514aa173a302c770689269aac08eb8698e5879ac"); private byte[] hMac4 = Hex.decode("d24b4eb0e5bd611d4ca88bd6428d14ee2e004c7e"); private Cipher makePBECipherUsingParam( - String algorithm, - int mode, - char[] password, - byte[] salt, - int iterationCount) + String algorithm, + int mode, + char[] password, + byte[] salt, + int iterationCount) throws Exception { - PBEKeySpec pbeSpec = new PBEKeySpec(password); - SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, "BC"); - PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount); + PBEKeySpec pbeSpec = new PBEKeySpec(password); + SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, "BC"); + PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount); Cipher cipher = Cipher.getInstance(algorithm, "BC"); @@ -325,15 +454,15 @@ private Cipher makePBECipherUsingParam( } private Cipher makePBECipherWithoutParam( - String algorithm, - int mode, - char[] password, - byte[] salt, - int iterationCount) + String algorithm, + int mode, + char[] password, + byte[] salt, + int iterationCount) throws Exception { - PBEKeySpec pbeSpec = new PBEKeySpec(password, salt, iterationCount); - SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, "BC"); + PBEKeySpec pbeSpec = new PBEKeySpec(password, salt, iterationCount); + SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, "BC"); Cipher cipher = Cipher.getInstance(algorithm, "BC"); @@ -343,19 +472,19 @@ private Cipher makePBECipherWithoutParam( } public void testPBEHMac( - String hmacName, - byte[] output) + String hmacName, + byte[] output) { - SecretKey key; - byte[] out; - Mac mac; + SecretKey key; + byte[] out; + Mac mac; try { - SecretKeyFactory fact = SecretKeyFactory.getInstance(hmacName, "BC"); + SecretKeyFactory fact = SecretKeyFactory.getInstance(hmacName, "BC"); key = fact.generateSecret(new PBEKeySpec("hello".toCharArray())); - + mac = Mac.getInstance(hmacName, "BC"); } catch (Exception e) @@ -375,7 +504,7 @@ public void testPBEHMac( } mac.reset(); - + mac.update(message, 0, message.length); out = mac.doFinal(); @@ -387,12 +516,12 @@ public void testPBEHMac( } public void testPKCS12HMac( - String hmacName, - byte[] output) + String hmacName, + byte[] output) { - SecretKey key; - byte[] out; - Mac mac; + SecretKey key; + byte[] out; + Mac mac; try { @@ -427,16 +556,16 @@ public void testPKCS12HMac( } public void testPBEonSecretKeyHmac( - String hmacName, - byte[] output) + String hmacName, + byte[] output) { - SecretKey key; - byte[] out; - Mac mac; + SecretKey key; + byte[] out; + Mac mac; try { - SecretKeyFactory fact = SecretKeyFactory.getInstance(hmacName, "BC"); + SecretKeyFactory fact = SecretKeyFactory.getInstance(hmacName, "BC"); key = fact.generateSecret(new PBEKeySpec("hello".toCharArray(), new byte[20], 100, 160)); } @@ -478,15 +607,15 @@ private void testCipherNameWithWrap(String name, String simpleName) SecretKey key = kg.generateKey(); byte[] salt = { - (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c, - (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99 - }; - char[] password = { 'p','a','s','s','w','o','r','d' }; + (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c, + (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99 + }; + char[] password = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}; PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 20); PBEKeySpec pbeKeySpec = new PBEKeySpec(password); SecretKeyFactory keyFac = - SecretKeyFactory.getInstance(name); + SecretKeyFactory.getInstance(name); SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec); Cipher pbeEncryptCipher = Cipher.getInstance(name, "BC"); @@ -533,7 +662,7 @@ private void testExtendedPBEParameterSpec() SecureRandom random = new FixedSecureRandom(Hex.decode( "000102030405060708090a0b0c0d0e0f" - + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf")); + + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf")); char[] password = "abcdefghijklmnop".toCharArray(); PBEKeySpec pbeKeySpec = new PBEKeySpec(password); @@ -564,7 +693,44 @@ private void testExtendedPBEParameterSpec() isTrue(Arrays.areEqual(input, decryptedBytes)); } - + + private void testNoIvPBEParameterSpec() + throws Exception + { + String cipherAlgo = "PBEWITHSHA256AND256BITAES-CBC-BC"; + + SecureRandom random = new FixedSecureRandom(Hex.decode( + "000102030405060708090a0b0c0d0e0f" + + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf")); + + char[] password = "abcdefghijklmnop".toCharArray(); + PBEKeySpec pbeKeySpec = new PBEKeySpec(password); + + SecretKeyFactory factory = SecretKeyFactory.getInstance( + "PBEWITHSHA256AND256BITAES-CBC-BC", + "BC"); + SecretKey key = factory.generateSecret(pbeKeySpec); + + byte[] salt = new byte[16]; + random.nextBytes(salt); + // simulate the situation for issue #1985 + byte[] iv = new byte[0]; + + PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 1000, new IvParameterSpec(iv)); + + Cipher encryptCipher = Cipher.getInstance(cipherAlgo, "BC"); + Cipher decryptCipher = Cipher.getInstance(cipherAlgo, "BC"); + + encryptCipher.init(Cipher.ENCRYPT_MODE, key, pbeParamSpec); + decryptCipher.init(Cipher.DECRYPT_MODE, key, pbeParamSpec); + + byte[] input = Strings.toByteArray("testing"); + byte[] encryptedBytes = encryptCipher.doFinal(input); + byte[] decryptedBytes = decryptCipher.doFinal(encryptedBytes); + + isTrue(Arrays.areEqual(input, decryptedBytes)); + } + public void performTest() throws Exception { @@ -573,24 +739,24 @@ public void performTest() // // DES // - Cipher cEnc = Cipher.getInstance("DES/CBC/PKCS7Padding", "BC"); + Cipher cEnc = Cipher.getInstance("DES/CBC/PKCS7Padding", "BC"); cEnc.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Hex.decode("30e69252758e5346"), "DES"), new IvParameterSpec(Hex.decode("7c1c1ab9c454a688"))); - byte[] out = cEnc.doFinal(input); + byte[] out = cEnc.doFinal(input); - char[] password = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd' }; + char[] password = {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}; - Cipher cDec = makePBECipherUsingParam( - "PBEWithSHA1AndDES", - Cipher.DECRYPT_MODE, - password, - Hex.decode("7d60435f02e9e0ae"), - 2048); + Cipher cDec = makePBECipherUsingParam( + "PBEWithSHA1AndDES", + Cipher.DECRYPT_MODE, + password, + Hex.decode("7d60435f02e9e0ae"), + 2048); - byte[] in = cDec.doFinal(out); + byte[] in = cDec.doFinal(out); if (!Arrays.areEqual(input, in)) { @@ -598,19 +764,19 @@ public void performTest() } cDec = makePBECipherWithoutParam( - "PBEWithSHA1AndDES", - Cipher.DECRYPT_MODE, - password, - Hex.decode("7d60435f02e9e0ae"), - 2048); + "PBEWithSHA1AndDES", + Cipher.DECRYPT_MODE, + password, + Hex.decode("7d60435f02e9e0ae"), + 2048); in = cDec.doFinal(out); - + if (!Arrays.areEqual(input, in)) { fail("DES failed without param"); } - + // // DESede // @@ -623,11 +789,11 @@ public void performTest() out = cEnc.doFinal(input); cDec = makePBECipherUsingParam( - "PBEWithSHAAnd3-KeyTripleDES-CBC", - Cipher.DECRYPT_MODE, - password, - Hex.decode("7d60435f02e9e0ae"), - 2048); + "PBEWithSHAAnd3-KeyTripleDES-CBC", + Cipher.DECRYPT_MODE, + password, + Hex.decode("7d60435f02e9e0ae"), + 2048); in = cDec.doFinal(out); @@ -648,11 +814,11 @@ public void performTest() out = cEnc.doFinal(input); cDec = makePBECipherUsingParam( - "PBEWithSHAAnd40BitRC2-CBC", - Cipher.DECRYPT_MODE, - password, - Hex.decode("7d60435f02e9e0ae"), - 2048); + "PBEWithSHAAnd40BitRC2-CBC", + Cipher.DECRYPT_MODE, + password, + Hex.decode("7d60435f02e9e0ae"), + 2048); in = cDec.doFinal(out); @@ -672,11 +838,11 @@ public void performTest() out = cEnc.doFinal(input); cDec = makePBECipherUsingParam( - "PBEWithSHAAnd128BitRC4", - Cipher.DECRYPT_MODE, - password, - Hex.decode("7d60435f02e9e0ae"), - 2048); + "PBEWithSHAAnd128BitRC4", + Cipher.DECRYPT_MODE, + password, + Hex.decode("7d60435f02e9e0ae"), + 2048); in = cDec.doFinal(out); @@ -686,14 +852,14 @@ public void performTest() } cDec = makePBECipherWithoutParam( - "PBEWithSHAAnd128BitRC4", - Cipher.DECRYPT_MODE, - password, - Hex.decode("7d60435f02e9e0ae"), - 2048); + "PBEWithSHAAnd128BitRC4", + Cipher.DECRYPT_MODE, + password, + Hex.decode("7d60435f02e9e0ae"), + 2048); in = cDec.doFinal(out); - + if (!Arrays.areEqual(input, in)) { fail("RC4 failed without param"); @@ -701,16 +867,21 @@ public void performTest() for (int i = 0; i != pkcs12Tests.length; i++) { - pkcs12Tests[i].perform(); + pkcs12Tests[i].performTest(); + } + + for (int i = 0; i != pbkdf2Tests.length; i++) + { + pbkdf2Tests[i].performTest(); } - + for (int i = 0; i != openSSLTests.length; i++) { - openSSLTests[i].perform(); + openSSLTests[i].performTest(); } testExtendedPBEParameterSpec(); - + testNoIvPBEParameterSpec(); testPKCS12Interop(); testPBEHMac("PBEWithHMacSHA1", hMac1); @@ -856,7 +1027,7 @@ public String getName() public static void main( - String[] args) + String[] args) { Security.addProvider(new BouncyCastleProvider()); diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java index 0ebbcdb104..20264c18b7 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java @@ -13,6 +13,7 @@ import java.security.PublicKey; import java.security.Security; import java.security.Signature; +import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; @@ -943,6 +944,361 @@ public class PKCS12StoreTest private static byte[] rawKeyBagStore = Base64.decode("MIIFlgIBAzCCBY8GCSqGSIb3DQEHAaCCBYAEggV8MIIFeDCCAv4GCSqGSIb3DQEHAaCCAu8EggLrMIIC5zCCAuMGCyqGSIb3DQEMCgEBoIICejCCAnYCAQAwDQYJKoZIhvcNAQEBBQAEggJgMIICXAIBAAKBgQCF4Tw78b8eDuwY+FomQazkPFuAxDbWTs//AozC4MvzBatdJeDu+s9WyK3PdU+gI7wFish0r2FP8M5dj/rA0ieCJ9UDTGWVKm06DB0y7zmAO3SS/3TXGQRekMmOXBtVlZa4AYVy8Tr+Ls69gfo3sgqJU8uH0ebWuoQTKJz/mpst0wIDAQABAoGBAIJbpu/jWylkdEV4BSd9CWCO2LYP2CliQirXC8JxaoTuf0ZKrLNlqd+htYPsgSS3xstKsBbV8hYJrpbxq8J2npok973j0bm9sW9RL8XmAYJbaat27IzQQkGj2j4CNWPJzQC3NsDWQJPMJMFHvT1ZIj5ASwvOHwKpM6haLPxX24o5AkEA/zBVPpO6Ic9Yfd8Fk+BN/DykpPbLMUNZFl/I2MavoXTh5Ng7J4/S5ABxkvvQdqKf1Nhal5CznakU4BjFUGr+dwJBAIZOLwlfToFgekV4SmcPnq4aNGdetDfEettRGJLrKf+qrZrTzW3Rj6N2cjxKHsE5/xOpyjOtgVv3cTQm0x//VoUCQAdQBUFTzmOlo22H9Ir2RIXT3wvzHoN84JKpkAHWP7YquUZrg9ZwYqSx9o81tBWSN25L/NyXAu6jp7t8OjtBtaUCQCILB1k0001wCw4444MkLnCrK8VX+A56uzmEYNo8ybSIquCn91Zy3BnvGB24G/uWm9V8IEjhHf0Vx5gUj0d5DZECQGRs4BMYE+y2Tpn7/zbjhZh/iAdttDq5/b2BBMbSiosSKRIGkOyHTu0SJKoxoDnHA5ryLK8NoSwoGjID5qESjA8xVjAjBgkqhkiG9w0BCRUxFgQU3U3Taaj7rCAV2GyyVEnAUZvc4JkwLwYJKoZIhvcNAQkUMSIeIABPAE4AVgBJAEYAXwBUAGUAcwB0AF8AQQBsAGkAYQBzMIICcgYJKoZIhvcNAQcBoIICYwSCAl8wggJbMIICVwYLKoZIhvcNAQwKAQOgggHuMIIB6gYKKoZIhvcNAQkWAaCCAdoEggHWMIIB0jCCATugAwIBAgIICNurBKCCK6gwDQYJKoZIhvcNAQEFBQAwIDERMA8GA1UEAwwIT05WSUYgVFQxCzAJBgNVBAYTAlVTMCAXDTcwMDEwMTAwMDAwMFoYDzk5OTkxMjMxMjM1OTU5WjAgMREwDwYDVQQDDAhPTlZJRiBUVDELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIXhPDvxvx4O7Bj4WiZBrOQ8W4DENtZOz/8CjMLgy/MFq10l4O76z1bIrc91T6AjvAWKyHSvYU/wzl2P+sDSJ4In1QNMZZUqbToMHTLvOYA7dJL/dNcZBF6QyY5cG1WVlrgBhXLxOv4uzr2B+jeyColTy4fR5ta6hBMonP+amy3TAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEARmnQ9q/lUycK5P4shGFlwK0Uy3dHZs4VxOBSinejSTTy1FL4+SRzwA+YDMmfRrI0WHY/upUCYyugDj5kDg5K6/mSiIWGr0PDjl+8qw352fpUQgY4vnpGBaJoLQf/KRFilVhZJz0QDq5iHo16UkibDDHYQqdt6la5SHKx4U6AJwYxVjAjBgkqhkiG9w0BCRUxFgQU3U3Taaj7rCAV2GyyVEnAUZvc4JkwLwYJKoZIhvcNAQkUMSIeIABPAE4AVgBJAEYAXwBUAGUAcwB0AF8AQQBsAGkAYQBz"); + // Valid PKCS #12 File with SHA-256 HMAC and PRF + private static final byte[] pkcs12WithPBMac1PBKdf2_a1 = Base64.decode( + "MIIKigIBAzCCCgUGCSqGSIb3DQEHAaCCCfYEggnyMIIJ7jCCBGIGCSqGSIb3DQEH\n" + + "BqCCBFMwggRPAgEAMIIESAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG\n" + + "SIb3DQEFDDAcBAg9pxXxY2yscwICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQME\n" + + "ASoEEK7yYaFQDi1pYwWzm9F/fs+AggPgFIT2XapyaFgDppdvLkdvaF3HXw+zjzKb\n" + + "7xFC76DtVPhVTWVHD+kIss+jsj+XyvMwY0aCuAhAG/Dig+vzWomnsqB5ssw5/kTb\n" + + "+TMQ5PXLkNeoBmB6ArKeGc/QmCBQvQG/a6b+nXSWmxNpP+71772dmWmB8gcSJ0kF\n" + + "Fj75NrIbmNiDMCb71Q8gOzBMFf6BpXf/3xWAJtxyic+tSNETfOJa8zTZb0+lV0w9\n" + + "5eUmDrPUpuxEVbb0KJtIc63gRkcfrPtDd6Ii4Zzbzj2Evr4/S4hnrQBsiryVzJWy\n" + + "IEjaD0y6+DmG0JwMgRuGi1wBoGowi37GMrDCOyOZWC4n5wHLtYyhR6JaElxbrhxP\n" + + "H46z2USLKmZoF+YgEQgYcSBXMgP0t36+XQocFWYi2N5niy02TnctwF430FYsQlhJ\n" + + "Suma4I33E808dJuMv8T/soF66HsD4Zj46hOf4nWmas7IaoSAbGKXgIa7KhGRJvij\n" + + "xM3WOX0aqNi/8bhnxSA7fCmIy/7opyx5UYJFWGBSmHP1pBHBVmx7Ad8SAsB9MSsh\n" + + "nbGjGiUk4h0QcOi29/M9WwFlo4urePyI8PK2qtVAmpD3rTLlsmgzguZ69L0Q/CFU\n" + + "fbtqsMF0bgEuh8cfivd1DYFABEt1gypuwCUtCqQ7AXK2nQqOjsQCxVz9i9K8NDeD\n" + + "aau98VAl0To2sk3/VR/QUq0PRwU1jPN5BzUevhE7SOy/ImuJKwpGqqFljYdrQmj5\n" + + "jDe+LmYH9QGVRlfN8zuU+48FY8CAoeBeHn5AAPml0PYPVUnt3/jQN1+v+CahNVI+\n" + + "La8q1Nen+j1R44aa2I3y/pUgtzXRwK+tPrxTQbG030EU51LYJn8amPWmn3w75ZIA\n" + + "MJrXWeKj44de7u4zdUsEBVC2uM44rIHM8MFjyYAwYsey0rcp0emsaxzar+7ZA67r\n" + + "lDoXvvS3NqsnTXHcn3T9tkPRoee6L7Dh3x4Od96lcRwgdYT5BwyH7e34ld4VTUmJ\n" + + "bDEq7Ijvn4JKrwQJh1RCC+Z/ObfkC42xAm7G010u3g08xB0Qujpdg4a7VcuWrywF\n" + + "c7hLNquuaF4qoDaVwYXHH3iuX6YlJ/3siTKbYCVXPEZOAMBP9lF/OU76UMJBQNfU\n" + + "0xjDx+3AhUVgnGuCsmYlK6ETDp8qOZKGyV0KrNSGtqLx3uMhd7PETeW+ML3tDQ/0\n" + + "X9fMkcZHi4C2fXnoHV/qa2dGhBj4jjQ0Xh1poU6mxGn2Mebe2hDsBZkkBpnn7pK4\n" + + "wP/VqXdQTwqEuvzGHLVFsCuADe40ZFBmtBrf70wG7ZkO8SUZ8Zz1IX3+S024g7yj\n" + + "QRev/6x6TtkwggWEBgkqhkiG9w0BBwGgggV1BIIFcTCCBW0wggVpBgsqhkiG9w0B\n" + + "DAoBAqCCBTEwggUtMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhTxzw+\n" + + "VptrYAICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEK9nSqc1I2t4tMVG\n" + + "bWHpdtQEggTQzCwI7j34gCTvfj6nuOSndAjShGv7mN2j7WMV0pslTpq2b9Bn3vn1\n" + + "Y0JMvL4E7sLrUzNU02pdOcfCnEpMFccNv2sQrLp1mOCKxu8OjSqHZLoKVL0ROVsZ\n" + + "8dMECLLigDlPKRiSyLErl14tErX4/zbkUaWMROO28kFbTbubQ8YoHlRUwsKW1xLg\n" + + "vfi0gRkG/zHXRfQHjX/8NStv7hXlehn7/Gy2EKPsRFhadm/iUHAfmCMkMgHTU248\n" + + "JER9+nsXltd59H+IeDpj/kbxZ+YvHow9XUZKu828d3MQnUpLZ1BfJGhMBPVwbVUD\n" + + "A40CiQBVdCoGtPJyalL28xoS3H0ILFCnwQOr6u0HwleNJPGHq78HUyH6Hwxnh0b0\n" + + "5o163r6wTFZn5cMOxpbs/Ttd+3TrxmrYpd2XnuRme3cnaYJ0ILvpc/8eLLR7SKjD\n" + + "T4JhZ0h/CfcV2WWvhpQugkY0pWrZ+EIMneB1dZB96mJVLxOi148OeSgi0PsxZMNi\n" + + "YM33rTpwQT5WqOsEyDwUQpne5b8Kkt/s7EN0LJNnPyJJRL1LcqOdr6j+6YqRtPa7\n" + + "a9oWJqMcuTP+bqzGRJh+3HDlFBw2Yzp9iadv4KmB2MzhStLUoi2MSjvnnkkd5Led\n" + + "sshAd6WbKfF7kLAHQHT4Ai6dMEO4EKkEVF9JBtxCR4JEn6C98Lpg+Lk+rfY7gHOf\n" + + "ZxtgGURwgXRY3aLUrdT55ZKgk3ExVKPzi5EhdpAau7JKhpOwyKozAp/OKWMNrz6h\n" + + "obu2Mbn1B+IA60psYHHxynBgsJHv7WQmbYh8HyGfHgVvaA8pZCYqxxjpLjSJrR8B\n" + + "Bu9H9xkTh7KlhxgreXYv19uAYbUd95kcox9izad6VPnovgFSb+Omdy6PJACPj6hF\n" + + "W6PJbucP0YPpO0VtWtQdZZ3df1P0hZ7qvKwOPFA+gKZSckgqASfygiP9V3Zc8jIi\n" + + "wjNzoDM2QT+UUJKiiGYXJUEOO9hxzFHlGj759DcNRhpgl5AgR57ofISD9yBuCAJY\n" + + "PQ/aZHPFuRTrcVG3RaIbCAS73nEznKyFaLOXfzyfyaSmyhsH253tnyL1MejC+2bR\n" + + "Eko/yldgFUxvU5JI+Q3KJ6Awj+PnduHXx71E4UwSuu2xXYMpxnQwI6rroQpZBX82\n" + + "HhqgcLV83P8lpzQwPdHjH5zkoxmWdC0+jU/tcQfNXYpJdyoaX7tDmVclLhwl9ps/\n" + + "O841pIsNLJWXwvxG6B+3LN/kw4QjwN194PopiOD7+oDm5mhttO78CrBrRxHMD/0Q\n" + + "qniZjKzSZepxlZq+J792u8vtMnuzzChxu0Bf3PhIXcJNcVhwUtr0yKe/N+NvC0tm\n" + + "p8wyik/BlndxN9eKbdTOi2wIi64h2QG8nOk66wQ/PSIJYwZl6eDNEQSzH/1mGCfU\n" + + "QnUT17UC/p+Qgenf6Auap2GWlvsJrB7u/pytz65rtjt/ouo6Ih6EwWqwVVpGXZD0\n" + + "7gVWH0Ke/Vr6aPGNvkLcmftPuDZsn9jiig3guhdeyRVf10Ox369kKWcG75q77hxE\n" + + "IzSzDyUlBNbnom9SIjut3r+qVYmWONatC6q/4D0I42Lnjd3dEyZx7jmH3g/S2ASM\n" + + "FzWr9pvXc61dsYOkdZ4PYa9XPUZxXFagZsoS3F1sU799+IJVU0tC0MExJTAjBgkq\n" + + "hkiG9w0BCRUxFgQUwWO5DorvVWYF3BWUmAw0rUEajScwfDBtMEkGCSqGSIb3DQEF\n" + + "DjA8MCwGCSqGSIb3DQEFDDAfBAhvRzw4sC4xcwICCAACASAwDAYIKoZIhvcNAgkF\n" + + "ADAMBggqhkiG9w0CCQUABCB6pW2FOdcCNj87zS64NUXG36K5aXDnFHctIk5Bf4kG\n" + + "3QQITk9UIFVTRUQCAQE=\n"); + + // Valid PKCS #12 File with SHA-256 HMAC and SHA-512 PRF + private static final byte[] pkcs12WithPBMac1PBKdf2_a2 = Base64.decode("MIIKigIBAzCCCgUGCSqGSIb3DQEHAaCCCfYEggnyMIIJ7jCCBGIGCSqGSIb3DQEH\n" + + "BqCCBFMwggRPAgEAMIIESAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG\n" + + "SIb3DQEFDDAcBAi4j6UBBY2iOgICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQME\n" + + "ASoEEFpHSS5zrk/9pkDo1JRbtE6AggPgtbMLGoFd5KLpVXMdcxLrT129L7/vCr0B\n" + + "0I2tnhPPA7aFtRjjuGbwooCMQwxw9qzuCX1eH4xK2LUw6Gbd2H47WimSOWJMaiUb\n" + + "wy4alIWELYufe74kXPmKPCyH92lN1hqu8s0EGhIl7nBhWbFzow1+qpIc9/lpujJo\n" + + "wodSY+pNBD8oBeoU1m6DgOjgc62apL7m0nwavDUqEt7HAqtTBxKxu/3lpb1q8nbl\n" + + "XLTqROax5feXErf+GQAqs24hUJIPg3O1eCMDVzH0h5pgZyRN9ZSIP0HC1i+d1lnb\n" + + "JwHyrAhZv8GMdAVKaXHETbq8zTpxT3UE/LmH1gyZGOG2B21D2dvNDKa712sHOS/t\n" + + "3XkFngHDLx+a9pVftt6p7Nh6jqI581tb7fyc7HBV9VUc/+xGgPgHZouaZw+I3PUz\n" + + "fjHboyLQer22ndBz+l1/S2GhhZ4xLXg4l0ozkgn7DX92S/UlbmcZam1apjGwkGY/\n" + + "7ktA8BarNW211mJF+Z+hci+BeDiM7eyEguLCYRdH+/UBiUuYjG1hi5Ki3+42pRZD\n" + + "FZkTHGOrcG6qE2KJDsENj+RkGiylG98v7flm4iWFVAB78AlAogT38Bod40evR7Ok\n" + + "c48sOIW05eCH/GLSO0MHKcttYUQNMqIDiG1TLzP1czFghhG97AxiTzYkKLx2cYfs\n" + + "pgg5PE9drq1fNzBZMUmC2bSwRhGRb5PDu6meD8uqvjxoIIZQAEV53xmD63umlUH1\n" + + "jhVXfcWSmhU/+vV/IWStZgQbwhF7DmH2q6S8itCkz7J7Byp5xcDiUOZ5Gpf9RJnk\n" + + "DTZoOYM5iA8kte6KCwA+jnmCgstI5EbRbnsNcjNvAT3q/X776VdmnehW0VeL+6k4\n" + + "z+GvQkr+D2sxPpldIb5hrb+1rcp9nOQgtpBnbXaT16Lc1HdTNe5kx4ScujXOWwfd\n" + + "Iy6bR6H0QFq2SLKAAC0qw4E8h1j3WPxll9e0FXNtoRKdsRuX3jzyqDBrQ6oGskkL\n" + + "wnyMtVjSX+3c9xbFc4vyJPFMPwb3Ng3syjUDrOpU5RxaMEAWt4josadWKEeyIC2F\n" + + "wrS1dzFn/5wv1g7E7xWq+nLq4zdppsyYOljzNUbhOEtJ2lhme3NJ45fxnxXmrPku\n" + + "gBda1lLf29inVuzuTjwtLjQwGk+usHJm9R/K0hTaSNRgepXnjY0cIgS+0gEY1/BW\n" + + "k3+Y4GE2JXds2cQToe5rCSYH3QG0QTyUAGvwX6hAlhrRRgUG3vxtYSixQ3UUuwzs\n" + + "eQW2SUFLl1611lJ7cQwFSPyr0sL0p81vdxWiigwjkfPtgljZ2QpmzR5rX2xiqItH\n" + + "Dy4E+iVigIYwggWEBgkqhkiG9w0BBwGgggV1BIIFcTCCBW0wggVpBgsqhkiG9w0B\n" + + "DAoBAqCCBTEwggUtMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhDiwsh\n" + + "4wt3aAICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEELNFnEpJT65wsXwd\n" + + "fZ1g56cEggTQRo04bP/fWfPPZrTEczq1qO1HHV86j76Sgxau2WQ9OQAG998HFtNq\n" + + "NxO8R66en6QFhqpWCI73tSJD+oA29qOsT+Xt2bR2z5+K7D4QoiXuLa3gXv62VkjB\n" + + "0DLCHAS7Mu+hkp5OKCpXCS7fo0OnAiQjM4EluAsiwwLrHu7z1E16UwpmlgKQnaC1\n" + + "S44fV9znS9TxofRTnuCq1lupdn2qQjSydOU6inQeKLBflKRiLrJHOobaFmjWwp1U\n" + + "OQAMuZrALhHyIbOFXMPYk3mmU/1UPuRGcbcV5v2Ut2UME+WYExXSCOYR3/R4UfVk\n" + + "IfEzeRPFs2slJMIDS2fmMyFkEEElBckhKO9IzhQV3koeKUBdM066ufyax/uIyXPm\n" + + "MiB9fAqbQQ4jkQTT80bKkBAP1Bvyg2L8BssstR5iCoZgWnfA9Uz4RI5GbRqbCz7H\n" + + "iSkuOIowEqOox3IWbXty5VdWBXNjZBHpbE0CyMLSH/4QdGVw8R0DiCAC0mmaMaZq\n" + + "32yrBR32E472N+2KaicvX31MwB/LkZN46c34TGanL5LJZx0DR6ITjdNgP8TlSSrp\n" + + "7y2mqi7VbKp/C/28Cj5r+m++Gk6EOUpLHsZ2d2hthrr7xqoPzUAEkkyYWedHJaoQ\n" + + "TkoIisZb0MGlXb9thjQ8Ee429ekfjv7CQfSDS6KTE/+mhuJ33mPz1ZcIacHjdHhE\n" + + "6rbrKhjSrLbgmrGa8i7ezd89T4EONu0wkG9KW0wM2cn5Gb12PF6rxjTfzypG7a50\n" + + "yc1IJ2Wrm0B7gGuYpVoCeIohr7IlxPYdeQGRO/SlzTd0xYaJVm9FzJaMNK0ZqnZo\n" + + "QMEPaeq8PC3kMjpa8eAiHXk9K3DWdOWYviGVCPVYIZK6Cpwe+EwfXs+2hZgZlYzc\n" + + "vpUWg60md1PD4UsyLQagaj37ubR6K4C4mzlhFx5NovV/C/KD+LgekMbjCtwEQeWy\n" + + "agev2l9KUEz73/BT4TgQFM5K2qZpVamwmsOmldPpekGPiUCu5YxYg/y4jUKvAqj1\n" + + "S9t4wUAScCJx8OvXUfgpmS2+mhFPBiFps0M4O3nWG91Q6mKMqbNHPUcFDn9P7cUh\n" + + "s1xu3NRLyJ+QIfVfba3YBTV8A6WBYEmL9lxf1uL1WS2Bx6+Crh0keyNUPo9cRjpx\n" + + "1oj/xkInoc2HQODEkvuK9DD7VrLr7sDhfmJvr1mUfJMQ5/THk7Z+E+NAuMdMtkM2\n" + + "yKXxghZAbBrQkU3mIW150i7PsjlUw0o0/LJvQwJIsh6yeJDHY8mby9mIdeP3LQAF\n" + + "clYKzNwmgwbdtmVAXmQxLuhmEpXfstIzkBrNJzChzb2onNSfa+r5L6XEHNHl7wCw\n" + + "TuuV/JWldNuYXLfVfuv3msfSjSWkv6aRtRWIvmOv0Qba2o05LlwFMd1PzKM5uN4D\n" + + "DYtsS9A6yQOXEsvUkWcLOJnCs8SkJRdXhJTxdmzeBqM1JttKwLbgGMbpjbxlg3ns\n" + + "N+Z+sEFox+2ZWOglgnBHj0mCZOiAC8wqUu+sxsLT4WndaPWKVqoRQChvDaZaNOaN\n" + + "qHciF9HPUcfZow+fH8TnSHneiQcDe6XcMhSaQ2MtpY8/jrgNKguZt22yH9gw/VpT\n" + + "3/QOB7FBgKFIEbvUaf3nVjFIlryIheg+LeiBd2isoMNNXaBwcg2YXukxJTAjBgkq\n" + + "hkiG9w0BCRUxFgQUwWO5DorvVWYF3BWUmAw0rUEajScwfDBtMEkGCSqGSIb3DQEF\n" + + "DjA8MCwGCSqGSIb3DQEFDDAfBAgUr2yP+/DBrgICCAACASAwDAYIKoZIhvcNAgsF\n" + + "ADAMBggqhkiG9w0CCQUABCA5zFL93jw8ItGlcbHKhqkNwbgpp6layuOuxSju4/Vd\n" + + "6QQITk9UIFVTRUQCAQE="); + + // Valid PKCS #12 File with SHA-512 HMAC and PRF + private static final byte[] pkcs12WithPBMac1PBKdf2_a3 = Base64.decode("MIIKrAIBAzCCCgUGCSqGSIb3DQEHAaCCCfYEggnyMIIJ7jCCBGIGCSqGSIb3DQEH\n" + + "BqCCBFMwggRPAgEAMIIESAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG\n" + + "SIb3DQEFDDAcBAisrqL8obSBaQICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQME\n" + + "ASoEECjXYYca0pwsgn1Imb9WqFGAggPgT7RcF5YzEJANZU9G3tSdpCHnyWatTlhm\n" + + "iCEcBGgwI5gz0+GoX+JCojgYY4g+KxeqznyCu+6GeD00T4Em7SWme9nzAfBFzng0\n" + + "3lYCSnahSEKfgHerbzAtq9kgXkclPVk0Liy92/buf0Mqotjjs/5o78AqP86Pwbj8\n" + + "xYNuXOU1ivO0JiW2c2HefKYvUvMYlOh99LCoZPLHPkaaZ4scAwDjFeTICU8oowVk\n" + + "LKvslrg1pHbfmXHMFJ4yqub37hRtj2CoJNy4+UA2hBYlBi9WnuAJIsjv0qS3kpLe\n" + + "4+J2DGe31GNG8pD01XD0l69OlailK1ykh4ap2u0KeD2z357+trCFbpWMMXQcSUCO\n" + + "OcVjxYqgv/l1++9huOHoPSt224x4wZfJ7cO2zbAAx/K2CPhdvi4CBaDHADsRq/c8\n" + + "SAi+LX5SCocGT51zL5KQD6pnr2ExaVum+U8a3nMPPMv9R2MfFUksYNGgFvS+lcZf\n" + + "R3qk/G9iXtSgray0mwRA8pWzoXl43vc9HJuuCU+ryOc/h36NChhQ9ltivUNaiUc2\n" + + "b9AAQSrZD8Z7KtxjbH3noS+gjDtimDB0Uh199zaCwQ95y463zdYsNCESm1OT979o\n" + + "Y+81BWFMFM/Hog5s7Ynhoi2E9+ZlyLK2UeKwvWjGzvcdPvxHR+5l/h6PyWROlpaZ\n" + + "zmzZBm+NKmbXtMD2AEa5+Q32ZqJQhijXZyIji3NS65y81j/a1ZrvU0lOVKA+MSPN\n" + + "KU27/eKZuF1LEL6qaazTUmpznLLdaVQy5aZ1qz5dyCziKcuHIclhh+RCblHU6XdE\n" + + "6pUTZSRQQiGUIkPUTnU9SFlZc7VwvxgeynLyXPCSzOKNWYGajy1LxDvv28uhMgNd\n" + + "WF51bNkl1QYl0fNunGO7YFt4wk+g7CQ/Yu2w4P7S3ZLMw0g4eYclcvyIMt4vxXfp\n" + + "VTKIPyzMqLr+0dp1eCPm8fIdaBZUhMUC/OVqLwgnPNY9cXCrn2R1cGKo5LtvtjbH\n" + + "2skz/D5DIOErfZSBJ8LE3De4j8MAjOeC8ia8LaM4PNfW/noQP1LBsZtTDTqEy01N\n" + + "Z5uliIocyQzlyWChErJv/Wxh+zBpbk1iXc2Owmh2GKjx0VSe7XbiqdoKkONUNUIE\n" + + "siseASiU/oXdJYUnBYVEUDJ1HPz7qnKiFhSgxNJZnoPfzbbx1hEzV+wxQqNnWIqQ\n" + + "U0s7Jt22wDBzPBHGao2tnGRLuBZWVePJGbsxThGKwrf3vYsNJTxme5KJiaxcPMwE\n" + + "r+ln2AqVOzzXHXgIxv/dvK0Qa7pH3AvGzcFjQChTRipgqiRrLor0//8580h+Ly2l\n" + + "IFo7bCuztmcwggWEBgkqhkiG9w0BBwGgggV1BIIFcTCCBW0wggVpBgsqhkiG9w0B\n" + + "DAoBAqCCBTEwggUtMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAi1c7S5\n" + + "IEG77wICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEN6rzRtIdYxqOnY+\n" + + "aDS3AFYEggTQNdwUoZDXCryOFBUI/z71vfoyAxlnwJLRHNXQUlI7w0KkH22aNnSm\n" + + "xiaXHoCP1HgcmsYORS7p/ITi/9atCHqnGR4zHmePNhoMpNHFehdjlUUWgt004vUJ\n" + + "5ZwTdXweM+K4We6CfWA/tyvsyGNAsuunel+8243Zsv0mGLKpjA+ZyALt51s0knmX\n" + + "OD2DW49FckImUVnNC5LmvEIAmVC/ZNycryZQI+2EBkJKe+BC3834GexJnSwtUBg3\n" + + "Xg33ZV7X66kw8tK1Ws5zND5GQAJyIu47mnjZkIWQBY+XbWowrBZ8uXIQuxMZC0p8\n" + + "u62oIAtZaVQoVTR1LyR/7PISFW6ApwtbTn6uQxsb16qF8lEM0S1+x0AfJY6Zm11t\n" + + "yCqbb2tYZF+X34MoUkR/IYC/KCq/KJdpnd8Yqgfrwjg8dR2WGIxbp2GBHq6BK/DI\n" + + "ehOLMcLcsOuP0DEXppfcelMOGNIs+4h4KsjWiHVDMPsqLdozBdm6FLGcno3lY5FO\n" + + "+avVrlElAOB+9evgaBbD2lSrEMoOjAoD090tgXXwYBEnWnIpdk+56cf5IpshrLBA\n" + + "/+H13LBLes+X1o5dd0Mu+3abp5RtAv7zLPRRtXkDYJPzgNcTvJ2Wxw2C+zrAclzZ\n" + + "7IRdcLESUa4CsN01aEvQgOtkCNVjSCtkJGP0FstsWM4hP7lfSB7P2tDL+ugy6GvB\n" + + "X1sz9fMC7QMAFL98nDm/yqcnejG1BcQXZho8n0svSfbcVByGlPZGMuI9t25+0B2M\n" + + "TAx0f6zoD8+fFmhcVgS6MQPybGKFawckYl0zulsePqs+G4voIW17owGKsRiv06Jm\n" + + "ZSwd3KoGmjM49ADzuG9yrQ5PSa0nhVk1tybNape4HNYHrAmmN0ILlN+E0Bs/Edz4\n" + + "ntYZuoc/Z35tCgm79dV4/Vl6HUZ1JrLsLrEWCByVytwVFyf3/MwTWdf+Ac+XzBuC\n" + + "yEMqPlvnPWswdnaid35pxios79fPl1Hr0/Q6+DoA5GyYq8SFdP7EYLrGMGa5GJ+x\n" + + "5nS7z6U4UmZ2sXuKYHnuhB0zi6Y04a+fhT71x02eTeC7aPlEB319UqysujJVJnso\n" + + "bkcwOu/Jj0Is9YeFd693dB44xeZuYyvlwoD19lqcim0TSa2Tw7D1W/yu47dKrVP2\n" + + "VKxRqomuAQOpoZiuSfq1/7ysrV8U4hIlIU2vnrSVJ8EtPQKsoBW5l70dQGwXyxBk\n" + + "BUTHqfJ4LG/kPGRMOtUzgqFw2DjJtbym1q1MZgp2ycMon4vp7DeQLGs2XfEANB+Y\n" + + "nRwtjpevqAnIuK6K3Y02LY4FXTNQpC37Xb04bmdIQAcE0MaoP4/hY87aS82PQ68g\n" + + "3bI79uKo4we2g+WaEJlEzQ7147ZzV2wbDq89W69x1MWTfaDwlEtd4UaacYchAv7B\n" + + "TVaaVFiRAUywWaHGePpZG2WV1feH/zd+temxWR9qMFgBZySg1jipBPVciwl0LqlW\n" + + "s/raIBYmLmAaMMgM3759UkNVznDoFHrY4z2EADXp0RHHVzJS1x+yYvp/9I+AcW55\n" + + "oN0UP/3uQ6eyz/ix22sovQwhMJ8rmgR6CfyRPKmXu1RPK3puNv7mbFTfTXpYN2vX\n" + + "vhEZReXY8hJF/9o4G3UrJ1F0MgUHMCG86cw1z0bhPSaXVoufOnx/fRoxJTAjBgkq\n" + + "hkiG9w0BCRUxFgQUwWO5DorvVWYF3BWUmAw0rUEajScwgZ0wgY0wSQYJKoZIhvcN\n" + + "AQUOMDwwLAYJKoZIhvcNAQUMMB8ECFDaXOUaOcUPAgIIAAIBQDAMBggqhkiG9w0C\n" + + "CwUAMAwGCCqGSIb3DQILBQAEQHIAM8C9OAsHUCj9CmOJioqf7YwD4O/b3UiZ3Wqo\n" + + "F6OmQIRDc68SdkZJ6024l4nWlnhTE7a4lb2Tru4k3NOTa1oECE5PVCBVU0VEAgEB"); + + // Invalid PKCS #12 File with Incorrect Iteration Count + private static final byte[] pkcs12WithPBMac1PBKdf2_a4 = Base64.decode("MIIKiwIBAzCCCgUGCSqGSIb3DQEHAaCCCfYEggnyMIIJ7jCCBGIGCSqGSIb3DQEH\n" + + "BqCCBFMwggRPAgEAMIIESAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG\n" + + "SIb3DQEFDDAcBAg9pxXxY2yscwICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQME\n" + + "ASoEEK7yYaFQDi1pYwWzm9F/fs+AggPgFIT2XapyaFgDppdvLkdvaF3HXw+zjzKb\n" + + "7xFC76DtVPhVTWVHD+kIss+jsj+XyvMwY0aCuAhAG/Dig+vzWomnsqB5ssw5/kTb\n" + + "+TMQ5PXLkNeoBmB6ArKeGc/QmCBQvQG/a6b+nXSWmxNpP+71772dmWmB8gcSJ0kF\n" + + "Fj75NrIbmNiDMCb71Q8gOzBMFf6BpXf/3xWAJtxyic+tSNETfOJa8zTZb0+lV0w9\n" + + "5eUmDrPUpuxEVbb0KJtIc63gRkcfrPtDd6Ii4Zzbzj2Evr4/S4hnrQBsiryVzJWy\n" + + "IEjaD0y6+DmG0JwMgRuGi1wBoGowi37GMrDCOyOZWC4n5wHLtYyhR6JaElxbrhxP\n" + + "H46z2USLKmZoF+YgEQgYcSBXMgP0t36+XQocFWYi2N5niy02TnctwF430FYsQlhJ\n" + + "Suma4I33E808dJuMv8T/soF66HsD4Zj46hOf4nWmas7IaoSAbGKXgIa7KhGRJvij\n" + + "xM3WOX0aqNi/8bhnxSA7fCmIy/7opyx5UYJFWGBSmHP1pBHBVmx7Ad8SAsB9MSsh\n" + + "nbGjGiUk4h0QcOi29/M9WwFlo4urePyI8PK2qtVAmpD3rTLlsmgzguZ69L0Q/CFU\n" + + "fbtqsMF0bgEuh8cfivd1DYFABEt1gypuwCUtCqQ7AXK2nQqOjsQCxVz9i9K8NDeD\n" + + "aau98VAl0To2sk3/VR/QUq0PRwU1jPN5BzUevhE7SOy/ImuJKwpGqqFljYdrQmj5\n" + + "jDe+LmYH9QGVRlfN8zuU+48FY8CAoeBeHn5AAPml0PYPVUnt3/jQN1+v+CahNVI+\n" + + "La8q1Nen+j1R44aa2I3y/pUgtzXRwK+tPrxTQbG030EU51LYJn8amPWmn3w75ZIA\n" + + "MJrXWeKj44de7u4zdUsEBVC2uM44rIHM8MFjyYAwYsey0rcp0emsaxzar+7ZA67r\n" + + "lDoXvvS3NqsnTXHcn3T9tkPRoee6L7Dh3x4Od96lcRwgdYT5BwyH7e34ld4VTUmJ\n" + + "bDEq7Ijvn4JKrwQJh1RCC+Z/ObfkC42xAm7G010u3g08xB0Qujpdg4a7VcuWrywF\n" + + "c7hLNquuaF4qoDaVwYXHH3iuX6YlJ/3siTKbYCVXPEZOAMBP9lF/OU76UMJBQNfU\n" + + "0xjDx+3AhUVgnGuCsmYlK6ETDp8qOZKGyV0KrNSGtqLx3uMhd7PETeW+ML3tDQ/0\n" + + "X9fMkcZHi4C2fXnoHV/qa2dGhBj4jjQ0Xh1poU6mxGn2Mebe2hDsBZkkBpnn7pK4\n" + + "wP/VqXdQTwqEuvzGHLVFsCuADe40ZFBmtBrf70wG7ZkO8SUZ8Zz1IX3+S024g7yj\n" + + "QRev/6x6TtkwggWEBgkqhkiG9w0BBwGgggV1BIIFcTCCBW0wggVpBgsqhkiG9w0B\n" + + "DAoBAqCCBTEwggUtMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhTxzw+\n" + + "VptrYAICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEK9nSqc1I2t4tMVG\n" + + "bWHpdtQEggTQzCwI7j34gCTvfj6nuOSndAjShGv7mN2j7WMV0pslTpq2b9Bn3vn1\n" + + "Y0JMvL4E7sLrUzNU02pdOcfCnEpMFccNv2sQrLp1mOCKxu8OjSqHZLoKVL0ROVsZ\n" + + "8dMECLLigDlPKRiSyLErl14tErX4/zbkUaWMROO28kFbTbubQ8YoHlRUwsKW1xLg\n" + + "vfi0gRkG/zHXRfQHjX/8NStv7hXlehn7/Gy2EKPsRFhadm/iUHAfmCMkMgHTU248\n" + + "JER9+nsXltd59H+IeDpj/kbxZ+YvHow9XUZKu828d3MQnUpLZ1BfJGhMBPVwbVUD\n" + + "A40CiQBVdCoGtPJyalL28xoS3H0ILFCnwQOr6u0HwleNJPGHq78HUyH6Hwxnh0b0\n" + + "5o163r6wTFZn5cMOxpbs/Ttd+3TrxmrYpd2XnuRme3cnaYJ0ILvpc/8eLLR7SKjD\n" + + "T4JhZ0h/CfcV2WWvhpQugkY0pWrZ+EIMneB1dZB96mJVLxOi148OeSgi0PsxZMNi\n" + + "YM33rTpwQT5WqOsEyDwUQpne5b8Kkt/s7EN0LJNnPyJJRL1LcqOdr6j+6YqRtPa7\n" + + "a9oWJqMcuTP+bqzGRJh+3HDlFBw2Yzp9iadv4KmB2MzhStLUoi2MSjvnnkkd5Led\n" + + "sshAd6WbKfF7kLAHQHT4Ai6dMEO4EKkEVF9JBtxCR4JEn6C98Lpg+Lk+rfY7gHOf\n" + + "ZxtgGURwgXRY3aLUrdT55ZKgk3ExVKPzi5EhdpAau7JKhpOwyKozAp/OKWMNrz6h\n" + + "obu2Mbn1B+IA60psYHHxynBgsJHv7WQmbYh8HyGfHgVvaA8pZCYqxxjpLjSJrR8B\n" + + "Bu9H9xkTh7KlhxgreXYv19uAYbUd95kcox9izad6VPnovgFSb+Omdy6PJACPj6hF\n" + + "W6PJbucP0YPpO0VtWtQdZZ3df1P0hZ7qvKwOPFA+gKZSckgqASfygiP9V3Zc8jIi\n" + + "wjNzoDM2QT+UUJKiiGYXJUEOO9hxzFHlGj759DcNRhpgl5AgR57ofISD9yBuCAJY\n" + + "PQ/aZHPFuRTrcVG3RaIbCAS73nEznKyFaLOXfzyfyaSmyhsH253tnyL1MejC+2bR\n" + + "Eko/yldgFUxvU5JI+Q3KJ6Awj+PnduHXx71E4UwSuu2xXYMpxnQwI6rroQpZBX82\n" + + "HhqgcLV83P8lpzQwPdHjH5zkoxmWdC0+jU/tcQfNXYpJdyoaX7tDmVclLhwl9ps/\n" + + "O841pIsNLJWXwvxG6B+3LN/kw4QjwN194PopiOD7+oDm5mhttO78CrBrRxHMD/0Q\n" + + "qniZjKzSZepxlZq+J792u8vtMnuzzChxu0Bf3PhIXcJNcVhwUtr0yKe/N+NvC0tm\n" + + "p8wyik/BlndxN9eKbdTOi2wIi64h2QG8nOk66wQ/PSIJYwZl6eDNEQSzH/1mGCfU\n" + + "QnUT17UC/p+Qgenf6Auap2GWlvsJrB7u/pytz65rtjt/ouo6Ih6EwWqwVVpGXZD0\n" + + "7gVWH0Ke/Vr6aPGNvkLcmftPuDZsn9jiig3guhdeyRVf10Ox369kKWcG75q77hxE\n" + + "IzSzDyUlBNbnom9SIjut3r+qVYmWONatC6q/4D0I42Lnjd3dEyZx7jmH3g/S2ASM\n" + + "FzWr9pvXc61dsYOkdZ4PYa9XPUZxXFagZsoS3F1sU799+IJVU0tC0MExJTAjBgkq\n" + + "hkiG9w0BCRUxFgQUwWO5DorvVWYF3BWUmAw0rUEajScwfTBtMEkGCSqGSIb3DQEF\n" + + "DjA8MCwGCSqGSIb3DQEFDDAfBAhvRzw4sC4xcwICCAECASAwDAYIKoZIhvcNAgkF\n" + + "ADAMBggqhkiG9w0CCQUABCB6pW2FOdcCNj87zS64NUXG36K5aXDnFHctIk5Bf4kG\n" + + "3QQITk9UIFVTRUQCAggA"); + + // Invalid PKCS #12 File with Incorrect Salt + private static final byte[] pkcs12WithPBMac1PBKdf2_a5 = Base64.decode("MIIKigIBAzCCCgUGCSqGSIb3DQEHAaCCCfYEggnyMIIJ7jCCBGIGCSqGSIb3DQEH\n" + + "BqCCBFMwggRPAgEAMIIESAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG\n" + + "SIb3DQEFDDAcBAg9pxXxY2yscwICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQME\n" + + "ASoEEK7yYaFQDi1pYwWzm9F/fs+AggPgFIT2XapyaFgDppdvLkdvaF3HXw+zjzKb\n" + + "7xFC76DtVPhVTWVHD+kIss+jsj+XyvMwY0aCuAhAG/Dig+vzWomnsqB5ssw5/kTb\n" + + "+TMQ5PXLkNeoBmB6ArKeGc/QmCBQvQG/a6b+nXSWmxNpP+71772dmWmB8gcSJ0kF\n" + + "Fj75NrIbmNiDMCb71Q8gOzBMFf6BpXf/3xWAJtxyic+tSNETfOJa8zTZb0+lV0w9\n" + + "5eUmDrPUpuxEVbb0KJtIc63gRkcfrPtDd6Ii4Zzbzj2Evr4/S4hnrQBsiryVzJWy\n" + + "IEjaD0y6+DmG0JwMgRuGi1wBoGowi37GMrDCOyOZWC4n5wHLtYyhR6JaElxbrhxP\n" + + "H46z2USLKmZoF+YgEQgYcSBXMgP0t36+XQocFWYi2N5niy02TnctwF430FYsQlhJ\n" + + "Suma4I33E808dJuMv8T/soF66HsD4Zj46hOf4nWmas7IaoSAbGKXgIa7KhGRJvij\n" + + "xM3WOX0aqNi/8bhnxSA7fCmIy/7opyx5UYJFWGBSmHP1pBHBVmx7Ad8SAsB9MSsh\n" + + "nbGjGiUk4h0QcOi29/M9WwFlo4urePyI8PK2qtVAmpD3rTLlsmgzguZ69L0Q/CFU\n" + + "fbtqsMF0bgEuh8cfivd1DYFABEt1gypuwCUtCqQ7AXK2nQqOjsQCxVz9i9K8NDeD\n" + + "aau98VAl0To2sk3/VR/QUq0PRwU1jPN5BzUevhE7SOy/ImuJKwpGqqFljYdrQmj5\n" + + "jDe+LmYH9QGVRlfN8zuU+48FY8CAoeBeHn5AAPml0PYPVUnt3/jQN1+v+CahNVI+\n" + + "La8q1Nen+j1R44aa2I3y/pUgtzXRwK+tPrxTQbG030EU51LYJn8amPWmn3w75ZIA\n" + + "MJrXWeKj44de7u4zdUsEBVC2uM44rIHM8MFjyYAwYsey0rcp0emsaxzar+7ZA67r\n" + + "lDoXvvS3NqsnTXHcn3T9tkPRoee6L7Dh3x4Od96lcRwgdYT5BwyH7e34ld4VTUmJ\n" + + "bDEq7Ijvn4JKrwQJh1RCC+Z/ObfkC42xAm7G010u3g08xB0Qujpdg4a7VcuWrywF\n" + + "c7hLNquuaF4qoDaVwYXHH3iuX6YlJ/3siTKbYCVXPEZOAMBP9lF/OU76UMJBQNfU\n" + + "0xjDx+3AhUVgnGuCsmYlK6ETDp8qOZKGyV0KrNSGtqLx3uMhd7PETeW+ML3tDQ/0\n" + + "X9fMkcZHi4C2fXnoHV/qa2dGhBj4jjQ0Xh1poU6mxGn2Mebe2hDsBZkkBpnn7pK4\n" + + "wP/VqXdQTwqEuvzGHLVFsCuADe40ZFBmtBrf70wG7ZkO8SUZ8Zz1IX3+S024g7yj\n" + + "QRev/6x6TtkwggWEBgkqhkiG9w0BBwGgggV1BIIFcTCCBW0wggVpBgsqhkiG9w0B\n" + + "DAoBAqCCBTEwggUtMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhTxzw+\n" + + "VptrYAICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEK9nSqc1I2t4tMVG\n" + + "bWHpdtQEggTQzCwI7j34gCTvfj6nuOSndAjShGv7mN2j7WMV0pslTpq2b9Bn3vn1\n" + + "Y0JMvL4E7sLrUzNU02pdOcfCnEpMFccNv2sQrLp1mOCKxu8OjSqHZLoKVL0ROVsZ\n" + + "8dMECLLigDlPKRiSyLErl14tErX4/zbkUaWMROO28kFbTbubQ8YoHlRUwsKW1xLg\n" + + "vfi0gRkG/zHXRfQHjX/8NStv7hXlehn7/Gy2EKPsRFhadm/iUHAfmCMkMgHTU248\n" + + "JER9+nsXltd59H+IeDpj/kbxZ+YvHow9XUZKu828d3MQnUpLZ1BfJGhMBPVwbVUD\n" + + "A40CiQBVdCoGtPJyalL28xoS3H0ILFCnwQOr6u0HwleNJPGHq78HUyH6Hwxnh0b0\n" + + "5o163r6wTFZn5cMOxpbs/Ttd+3TrxmrYpd2XnuRme3cnaYJ0ILvpc/8eLLR7SKjD\n" + + "T4JhZ0h/CfcV2WWvhpQugkY0pWrZ+EIMneB1dZB96mJVLxOi148OeSgi0PsxZMNi\n" + + "YM33rTpwQT5WqOsEyDwUQpne5b8Kkt/s7EN0LJNnPyJJRL1LcqOdr6j+6YqRtPa7\n" + + "a9oWJqMcuTP+bqzGRJh+3HDlFBw2Yzp9iadv4KmB2MzhStLUoi2MSjvnnkkd5Led\n" + + "sshAd6WbKfF7kLAHQHT4Ai6dMEO4EKkEVF9JBtxCR4JEn6C98Lpg+Lk+rfY7gHOf\n" + + "ZxtgGURwgXRY3aLUrdT55ZKgk3ExVKPzi5EhdpAau7JKhpOwyKozAp/OKWMNrz6h\n" + + "obu2Mbn1B+IA60psYHHxynBgsJHv7WQmbYh8HyGfHgVvaA8pZCYqxxjpLjSJrR8B\n" + + "Bu9H9xkTh7KlhxgreXYv19uAYbUd95kcox9izad6VPnovgFSb+Omdy6PJACPj6hF\n" + + "W6PJbucP0YPpO0VtWtQdZZ3df1P0hZ7qvKwOPFA+gKZSckgqASfygiP9V3Zc8jIi\n" + + "wjNzoDM2QT+UUJKiiGYXJUEOO9hxzFHlGj759DcNRhpgl5AgR57ofISD9yBuCAJY\n" + + "PQ/aZHPFuRTrcVG3RaIbCAS73nEznKyFaLOXfzyfyaSmyhsH253tnyL1MejC+2bR\n" + + "Eko/yldgFUxvU5JI+Q3KJ6Awj+PnduHXx71E4UwSuu2xXYMpxnQwI6rroQpZBX82\n" + + "HhqgcLV83P8lpzQwPdHjH5zkoxmWdC0+jU/tcQfNXYpJdyoaX7tDmVclLhwl9ps/\n" + + "O841pIsNLJWXwvxG6B+3LN/kw4QjwN194PopiOD7+oDm5mhttO78CrBrRxHMD/0Q\n" + + "qniZjKzSZepxlZq+J792u8vtMnuzzChxu0Bf3PhIXcJNcVhwUtr0yKe/N+NvC0tm\n" + + "p8wyik/BlndxN9eKbdTOi2wIi64h2QG8nOk66wQ/PSIJYwZl6eDNEQSzH/1mGCfU\n" + + "QnUT17UC/p+Qgenf6Auap2GWlvsJrB7u/pytz65rtjt/ouo6Ih6EwWqwVVpGXZD0\n" + + "7gVWH0Ke/Vr6aPGNvkLcmftPuDZsn9jiig3guhdeyRVf10Ox369kKWcG75q77hxE\n" + + "IzSzDyUlBNbnom9SIjut3r+qVYmWONatC6q/4D0I42Lnjd3dEyZx7jmH3g/S2ASM\n" + + "FzWr9pvXc61dsYOkdZ4PYa9XPUZxXFagZsoS3F1sU799+IJVU0tC0MExJTAjBgkq\n" + + "hkiG9w0BCRUxFgQUwWO5DorvVWYF3BWUmAw0rUEajScwfDBtMEkGCSqGSIb3DQEF\n" + + "DjA8MCwGCSqGSIb3DQEFDDAfBAhOT1QgVVNFRAICCAACASAwDAYIKoZIhvcNAgkF\n" + + "ADAMBggqhkiG9w0CCQUABCB6pW2FOdcCNj87zS64NUXG36K5aXDnFHctIk5Bf4kG\n" + + "3QQIb0c8OLAuMXMCAQE="); + + // Invalid PKCS #12 File with Missing Key Length + private static final byte[] pkcs12WithPBMac1PBKdf2_a6 = Base64.decode("MIIKiAIBAzCCCgUGCSqGSIb3DQEHAaCCCfYEggnyMIIJ7jCCBGIGCSqGSIb3DQEH\n" + + "BqCCBFMwggRPAgEAMIIESAYJKoZIhvcNAQcBMFcGCSqGSIb3DQEFDTBKMCkGCSqG\n" + + "SIb3DQEFDDAcBAg9pxXxY2yscwICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQME\n" + + "ASoEEK7yYaFQDi1pYwWzm9F/fs+AggPgFIT2XapyaFgDppdvLkdvaF3HXw+zjzKb\n" + + "7xFC76DtVPhVTWVHD+kIss+jsj+XyvMwY0aCuAhAG/Dig+vzWomnsqB5ssw5/kTb\n" + + "+TMQ5PXLkNeoBmB6ArKeGc/QmCBQvQG/a6b+nXSWmxNpP+71772dmWmB8gcSJ0kF\n" + + "Fj75NrIbmNiDMCb71Q8gOzBMFf6BpXf/3xWAJtxyic+tSNETfOJa8zTZb0+lV0w9\n" + + "5eUmDrPUpuxEVbb0KJtIc63gRkcfrPtDd6Ii4Zzbzj2Evr4/S4hnrQBsiryVzJWy\n" + + "IEjaD0y6+DmG0JwMgRuGi1wBoGowi37GMrDCOyOZWC4n5wHLtYyhR6JaElxbrhxP\n" + + "H46z2USLKmZoF+YgEQgYcSBXMgP0t36+XQocFWYi2N5niy02TnctwF430FYsQlhJ\n" + + "Suma4I33E808dJuMv8T/soF66HsD4Zj46hOf4nWmas7IaoSAbGKXgIa7KhGRJvij\n" + + "xM3WOX0aqNi/8bhnxSA7fCmIy/7opyx5UYJFWGBSmHP1pBHBVmx7Ad8SAsB9MSsh\n" + + "nbGjGiUk4h0QcOi29/M9WwFlo4urePyI8PK2qtVAmpD3rTLlsmgzguZ69L0Q/CFU\n" + + "fbtqsMF0bgEuh8cfivd1DYFABEt1gypuwCUtCqQ7AXK2nQqOjsQCxVz9i9K8NDeD\n" + + "aau98VAl0To2sk3/VR/QUq0PRwU1jPN5BzUevhE7SOy/ImuJKwpGqqFljYdrQmj5\n" + + "jDe+LmYH9QGVRlfN8zuU+48FY8CAoeBeHn5AAPml0PYPVUnt3/jQN1+v+CahNVI+\n" + + "La8q1Nen+j1R44aa2I3y/pUgtzXRwK+tPrxTQbG030EU51LYJn8amPWmn3w75ZIA\n" + + "MJrXWeKj44de7u4zdUsEBVC2uM44rIHM8MFjyYAwYsey0rcp0emsaxzar+7ZA67r\n" + + "lDoXvvS3NqsnTXHcn3T9tkPRoee6L7Dh3x4Od96lcRwgdYT5BwyH7e34ld4VTUmJ\n" + + "bDEq7Ijvn4JKrwQJh1RCC+Z/ObfkC42xAm7G010u3g08xB0Qujpdg4a7VcuWrywF\n" + + "c7hLNquuaF4qoDaVwYXHH3iuX6YlJ/3siTKbYCVXPEZOAMBP9lF/OU76UMJBQNfU\n" + + "0xjDx+3AhUVgnGuCsmYlK6ETDp8qOZKGyV0KrNSGtqLx3uMhd7PETeW+ML3tDQ/0\n" + + "X9fMkcZHi4C2fXnoHV/qa2dGhBj4jjQ0Xh1poU6mxGn2Mebe2hDsBZkkBpnn7pK4\n" + + "wP/VqXdQTwqEuvzGHLVFsCuADe40ZFBmtBrf70wG7ZkO8SUZ8Zz1IX3+S024g7yj\n" + + "QRev/6x6TtkwggWEBgkqhkiG9w0BBwGgggV1BIIFcTCCBW0wggVpBgsqhkiG9w0B\n" + + "DAoBAqCCBTEwggUtMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAhTxzw+\n" + + "VptrYAICCAAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEK9nSqc1I2t4tMVG\n" + + "bWHpdtQEggTQzCwI7j34gCTvfj6nuOSndAjShGv7mN2j7WMV0pslTpq2b9Bn3vn1\n" + + "Y0JMvL4E7sLrUzNU02pdOcfCnEpMFccNv2sQrLp1mOCKxu8OjSqHZLoKVL0ROVsZ\n" + + "8dMECLLigDlPKRiSyLErl14tErX4/zbkUaWMROO28kFbTbubQ8YoHlRUwsKW1xLg\n" + + "vfi0gRkG/zHXRfQHjX/8NStv7hXlehn7/Gy2EKPsRFhadm/iUHAfmCMkMgHTU248\n" + + "JER9+nsXltd59H+IeDpj/kbxZ+YvHow9XUZKu828d3MQnUpLZ1BfJGhMBPVwbVUD\n" + + "A40CiQBVdCoGtPJyalL28xoS3H0ILFCnwQOr6u0HwleNJPGHq78HUyH6Hwxnh0b0\n" + + "5o163r6wTFZn5cMOxpbs/Ttd+3TrxmrYpd2XnuRme3cnaYJ0ILvpc/8eLLR7SKjD\n" + + "T4JhZ0h/CfcV2WWvhpQugkY0pWrZ+EIMneB1dZB96mJVLxOi148OeSgi0PsxZMNi\n" + + "YM33rTpwQT5WqOsEyDwUQpne5b8Kkt/s7EN0LJNnPyJJRL1LcqOdr6j+6YqRtPa7\n" + + "a9oWJqMcuTP+bqzGRJh+3HDlFBw2Yzp9iadv4KmB2MzhStLUoi2MSjvnnkkd5Led\n" + + "sshAd6WbKfF7kLAHQHT4Ai6dMEO4EKkEVF9JBtxCR4JEn6C98Lpg+Lk+rfY7gHOf\n" + + "ZxtgGURwgXRY3aLUrdT55ZKgk3ExVKPzi5EhdpAau7JKhpOwyKozAp/OKWMNrz6h\n" + + "obu2Mbn1B+IA60psYHHxynBgsJHv7WQmbYh8HyGfHgVvaA8pZCYqxxjpLjSJrR8B\n" + + "Bu9H9xkTh7KlhxgreXYv19uAYbUd95kcox9izad6VPnovgFSb+Omdy6PJACPj6hF\n" + + "W6PJbucP0YPpO0VtWtQdZZ3df1P0hZ7qvKwOPFA+gKZSckgqASfygiP9V3Zc8jIi\n" + + "wjNzoDM2QT+UUJKiiGYXJUEOO9hxzFHlGj759DcNRhpgl5AgR57ofISD9yBuCAJY\n" + + "PQ/aZHPFuRTrcVG3RaIbCAS73nEznKyFaLOXfzyfyaSmyhsH253tnyL1MejC+2bR\n" + + "Eko/yldgFUxvU5JI+Q3KJ6Awj+PnduHXx71E4UwSuu2xXYMpxnQwI6rroQpZBX82\n" + + "HhqgcLV83P8lpzQwPdHjH5zkoxmWdC0+jU/tcQfNXYpJdyoaX7tDmVclLhwl9ps/\n" + + "O841pIsNLJWXwvxG6B+3LN/kw4QjwN194PopiOD7+oDm5mhttO78CrBrRxHMD/0Q\n" + + "qniZjKzSZepxlZq+J792u8vtMnuzzChxu0Bf3PhIXcJNcVhwUtr0yKe/N+NvC0tm\n" + + "p8wyik/BlndxN9eKbdTOi2wIi64h2QG8nOk66wQ/PSIJYwZl6eDNEQSzH/1mGCfU\n" + + "QnUT17UC/p+Qgenf6Auap2GWlvsJrB7u/pytz65rtjt/ouo6Ih6EwWqwVVpGXZD0\n" + + "7gVWH0Ke/Vr6aPGNvkLcmftPuDZsn9jiig3guhdeyRVf10Ox369kKWcG75q77hxE\n" + + "IzSzDyUlBNbnom9SIjut3r+qVYmWONatC6q/4D0I42Lnjd3dEyZx7jmH3g/S2ASM\n" + + "FzWr9pvXc61dsYOkdZ4PYa9XPUZxXFagZsoS3F1sU799+IJVU0tC0MExJTAjBgkq\n" + + "hkiG9w0BCRUxFgQUwWO5DorvVWYF3BWUmAw0rUEajScwejBqMEYGCSqGSIb3DQEF\n" + + "DjA5MCkGCSqGSIb3DQEFDDAcBAhvRzw4sC4xcwICCAAwDAYIKoZIhvcNAgkFADAM\n" + + "BggqhkiG9w0CCQUABCB6pW2FOdcCNj87zS64NUXG36K5aXDnFHctIk5Bf4kG3QQI\n" + + "b0c8OLAuMXMCAggA"); + /** * we generate a self signed certificate for the sake of testing - RSA */ @@ -2006,6 +2362,26 @@ private void testNoExtraLocalKeyID(byte[] store1data) } } + public void testPKCS12StoreWrongPassword() + throws Exception + { + KeyStore store = KeyStore.getInstance("PKCS12", BC); + ByteArrayInputStream stream = new ByteArrayInputStream(pkcs12); + + try + { + store.load(stream, "Goodbye World!".toCharArray()); + fail("no exception"); + } + catch (IOException e) + { + if (!(e.getCause() instanceof UnrecoverableKeyException)) + { + fail("no exception cause found for wrong password"); + } + } + } + private void testChainCycle() throws Exception { @@ -2145,6 +2521,73 @@ private void testIterationCount() System.clearProperty("org.bouncycastle.pkcs12.max_it_count"); } + private void testPBMac1PBKdf2() + throws Exception + { + KeyStore store = KeyStore.getInstance("PKCS12", BC); + final char[] password = "1234".toCharArray(); + ByteArrayInputStream stream; + // valid test vectors + for (byte[] test_vector : new byte[][]{pkcs12WithPBMac1PBKdf2_a1, pkcs12WithPBMac1PBKdf2_a2, pkcs12WithPBMac1PBKdf2_a3}) + { + // + // load test + // + stream = new ByteArrayInputStream(test_vector); + store.load(stream, password); + + try + { + store.load(stream, "not right".toCharArray()); + fail("no exception"); + } + catch (IOException ignored) {} + + // + // save test + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + store.store(bOut, passwd); + stream = new ByteArrayInputStream(bOut.toByteArray()); + store.load(stream, passwd); + + // + // save test using LoadStoreParameter + // + bOut = new ByteArrayOutputStream(); + PKCS12StoreParameter storeParam = new PKCS12StoreParameter(bOut, passwd, true); + store.store(storeParam); + byte[] data = bOut.toByteArray(); + stream = new ByteArrayInputStream(data); + store.load(stream, passwd); + } + // invalid test vectors + for (byte[] test_vector : new byte[][]{pkcs12WithPBMac1PBKdf2_a4, pkcs12WithPBMac1PBKdf2_a5}) + { + stream = new ByteArrayInputStream(test_vector); + try + { + store.load(stream, password); + fail("no exception"); + } + catch (IOException e) + { + isTrue(e.getMessage().contains("PKCS12 key store mac invalid - wrong password or corrupted file")); + } + } + // invalid test vector that throws exception + stream = new ByteArrayInputStream(pkcs12WithPBMac1PBKdf2_a6); + try + { + store.load(stream, password); + fail("no exception"); + } + catch (IOException e) + { + isTrue(e.getMessage().contains("Key length must be present when using PBMAC1.")); + } + } + private void testBCFKSLoad() throws Exception { @@ -2327,6 +2770,7 @@ public void performTest() { testPKCS12StoreFriendlyName(); testIterationCount(); + testPBMac1PBKdf2(); testPKCS12Store(); testGOSTStore(); testChainCycle(); @@ -2341,6 +2785,7 @@ public void performTest() testRawKeyBagStore(); testAES256_AES128(); testAES256GCM_AES128_GCM(); + testPKCS12StoreWrongPassword(); // converter tests diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/PQCDHTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/PQCDHTest.java new file mode 100644 index 0000000000..7c9f299cad --- /dev/null +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/PQCDHTest.java @@ -0,0 +1,89 @@ +package org.bouncycastle.jce.provider.test; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Security; +import java.security.spec.ECGenParameterSpec; + +import javax.crypto.KeyAgreement; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; + +import org.bouncycastle.jcajce.SecretKeyWithEncapsulation; +import org.bouncycastle.jcajce.spec.HybridValueParameterSpec; +import org.bouncycastle.jcajce.spec.KEMExtractSpec; +import org.bouncycastle.jcajce.spec.KEMGenerateSpec; +import org.bouncycastle.jcajce.spec.MLKEMParameterSpec; +import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec; +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 PQCDHTest + extends SimpleTest +{ + public String getName() + { + return "PQCDHTest"; + } + + private void testMLKemECDH() + throws Exception + { + + KeyPairGenerator kemKeyGen = KeyPairGenerator.getInstance("ML-KEM", "BC"); + + kemKeyGen.initialize(MLKEMParameterSpec.ml_kem_768); + + KeyPair kemKp = kemKeyGen.generateKeyPair(); + + KeyPairGenerator ecKeyGen = KeyPairGenerator.getInstance("EC", "BC"); + + ecKeyGen.initialize(new ECGenParameterSpec("P-256")); + + KeyPair ecKp = ecKeyGen.generateKeyPair(); + + byte[] ukm = Hex.decode("030f136fa7fef90d185655ed1c6d46bacdb820"); + + KeyGenerator keyGen = KeyGenerator.getInstance("ML-KEM", "BC"); + + keyGen.init(new KEMGenerateSpec.Builder(kemKp.getPublic(), "DEF", 256).withNoKdf().build()); + + SecretKeyWithEncapsulation secEnc1 = (SecretKeyWithEncapsulation)keyGen.generateKey(); + + KeyAgreement agreement = KeyAgreement.getInstance("ECCDHwithSHA256CKDF", "BC"); + + agreement.init(ecKp.getPrivate(), new HybridValueParameterSpec(secEnc1.getEncoded(), new UserKeyingMaterialSpec(ukm))); + + agreement.doPhase(ecKp.getPublic(), true); + + SecretKey k1 = agreement.generateSecret("AES[256]"); + + keyGen.init(new KEMExtractSpec.Builder(kemKp.getPrivate(), secEnc1.getEncapsulation(), "DEF", 256).withNoKdf().build()); + + SecretKeyWithEncapsulation secEnc2 = (SecretKeyWithEncapsulation)keyGen.generateKey(); + + agreement.init(ecKp.getPrivate(), new HybridValueParameterSpec(secEnc2.getEncoded(), new UserKeyingMaterialSpec(ukm))); + + agreement.doPhase(ecKp.getPublic(), true); + + SecretKey k2 = agreement.generateSecret("AES[256]"); + + isTrue(Arrays.areEqual(k1.getEncoded(), k2.getEncoded())); + } + + @Override + public void performTest() + throws Exception + { + testMLKemECDH(); + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PQCDHTest()); + } +} diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/PSSTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/PSSTest.java index 75931bf195..462c06d5d7 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/PSSTest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/PSSTest.java @@ -47,27 +47,6 @@ public void nextBytes( } } - private boolean arrayEquals( - byte[] a, - byte[] b) - { - if (a.length != b.length) - { - return false; - } - - for (int i = 0; i != a.length; i++) - { - if (a[i] != b[i]) - { - return false; - } - } - - return true; - } - - private RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec( new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), new BigInteger("010001",16)); @@ -109,7 +88,7 @@ public void performTest() throws Exception s.update(msg1a); byte[] sig = s.sign(); - if (!arrayEquals(sig1a, sig)) + if (!Arrays.areEqual(sig1a, sig)) { fail("PSS Sign test expected " + new String(Hex.encode(sig1a)) + " got " + new String(Hex.encode(sig))); } @@ -135,7 +114,7 @@ public void performTest() throws Exception } AlgorithmParameters pss = s.getParameters(); - if (!arrayEquals(pss.getEncoded(), new byte[] { 0x30, 0x00 })) + if (!Arrays.areEqual(pss.getEncoded(), new byte[]{ 0x30, 0x00 })) { fail("failed default encoding test."); } @@ -148,7 +127,7 @@ public void performTest() throws Exception pss = s.getParameters(); - if (!arrayEquals(sig1b, sig)) + if (!Arrays.areEqual(sig1b, sig)) { fail("PSS Sign test expected " + new String(Hex.encode(sig1b)) + " got " + new String(Hex.encode(sig))); } @@ -251,7 +230,7 @@ public void performTest() throws Exception pss = s.getParameters(); - if (!arrayEquals(sig1c, sig)) + if (!Arrays.areEqual(sig1c, sig)) { fail("PSS Sign test expected " + new String(Hex.encode(sig1c)) + " got " + new String(Hex.encode(sig))); } diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/RSATest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/RSATest.java index 81a406175a..cd755dd835 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/RSATest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/RSATest.java @@ -967,24 +967,42 @@ private void rawModeTest(String sigName, ASN1ObjectIdentifier digestOID, MessageDigest digest = MessageDigest.getInstance(digestOID.getId(), "BC"); byte[] hash = digest.digest(sampleMessage); - byte[] digInfo = derEncode(digestOID, hash); - Signature rawSig = Signature.getInstance("RSA", "BC"); - rawSig.initSign(privKey); - rawSig.update(digInfo); - byte[] rawResult = rawSig.sign(); - - if (!Arrays.areEqual(normalResult, rawResult)) { - fail("raw mode signature differs from normal one"); - } + Signature rawSig = Signature.getInstance("RSA", "BC"); + rawSig.initSign(privKey); + rawSig.update(hash); + byte[] rawResult = rawSig.sign(); - rawSig.initVerify(pubKey); - rawSig.update(digInfo); + rawSig.initVerify(pubKey); + rawSig.update(hash); + + if (!rawSig.verify(rawResult)) + { + fail("raw mode (no DigestInfo) signature verification failed"); + } + } - if (!rawSig.verify(rawResult)) { - fail("raw mode signature verification failed"); + byte[] digInfo = derEncode(digestOID, hash); + + Signature rawSig = Signature.getInstance("RSA", "BC"); + rawSig.initSign(privKey); + rawSig.update(digInfo); + byte[] rawResult = rawSig.sign(); + + if (!Arrays.areEqual(normalResult, rawResult)) + { + fail("raw mode signature differs from normal one"); + } + + rawSig.initVerify(pubKey); + rawSig.update(digInfo); + + if (!rawSig.verify(rawResult)) + { + fail("raw mode signature verification failed"); + } } } diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java index 226b948364..9d1038b76b 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/RegressionTest.java @@ -8,92 +8,100 @@ public class RegressionTest { - public static Test[] tests = { - new FIPSDESTest(), - new DESedeTest(), - new AESTest(), + public static Test[] tests = { new AEADTest(), - new CamelliaTest(), - new SEEDTest(), new AESSICTest(), - new GOST28147Test(), - new PBETest(), + new AESTest(), + new AlgorithmParametersTest(), + new ARIATest(), + new BCFKSStoreTest(), new BlockCipherTest(), - new MacTest(), - new HMacTest(), - new SealedTest(), - new RSATest(), - new DHTest(), + new CamelliaTest(), + new CertLocaleTest(), + new CertPathBuilderTest(), + new CertPathTest(), + new CertPathValidatorTest(), + new CertStoreTest(), + new CertTest(), + new CertUniqueIDTest(), + new ChaCha20Poly1305Test(), + new CipherStreamTest(), + new CipherStreamTest2(), + new CMacTest(), + new CRL5Test(), + new DESedeTest(), + new DetDSATest(), new DHIESTest(), + new DHTest(), + new DigestTest(), + new DoFinalTest(), + new DRBGTest(), new DSATest(), - new ImplicitlyCaTest(), - new ECNRTest(), + new DSTU4145Test(), + new DSTU7624Test(), + new ECDSA5Test(), + new ECEncodingTest(), new ECIESTest(), new ECIESVectorTest(), - new ECDSA5Test(), - new GOST3410Test(), + new ECNRTest(), + new EdECTest(), new ElGamalTest(), - new IESTest(), - new SigTest(), - new CertTest(), - new PKCS10CertRequestTest(), new EncryptedPrivateKeyInfoTest(), + new FIPSDESTest(), + new GMacTest(), + new GOST28147Test(), + new GOST3410KeyPairTest(), + new GOST3410Test(), + new GOST3412Test(), + new HMacTest(), + new IESTest(), + new ImplicitlyCaTest(), + new KeccakTest(), new KeyStoreTest(), - new PKCS12StoreTest(), - new DigestTest(), - new PSSTest(), - new WrapTest(), - new DoFinalTest(), - new CipherStreamTest(), - new CipherStreamTest2(), + new MacTest(), + new MQVTest(), + new MultiCertStoreTest(), new NamedCurveTest(), - new PKIXTest(), new NetscapeCertRequestTest(), - new X509StreamParserTest(), - new X509CertificatePairTest(), - new CertPathTest(), - new CertStoreTest(), - new CertPathValidatorTest(), - new CertPathBuilderTest(), - new ECEncodingTest(), - new AlgorithmParametersTest(), new NISTCertPathTest(), - new PKIXPolicyMappingTest(), - new SlotTwoTest(), - new PKIXNameConstraintsTest(), - new MultiCertStoreTest(), new NoekeonTest(), - new SerialisationTest(), - new SigNameTest(), - new MQVTest(), - new CMacTest(), - new GMacTest(), new OCBTest(), - new DSTU4145Test(), - new CRL5Test(), + new OpenSSHSpecTests(), + new PBETest(), + new PKCS10CertRequestTest(), + new PKCS12StorePBETest(), + new PKCS12StoreTest(), + new PKIXNameConstraintsTest(), + new PKIXPolicyMappingTest(), + new PKIXTest(), new Poly1305Test(), + new PQCDHTest(), + new PSSTest(), + new RSATest(), + new SealedTest(), + new SEEDTest(), + new SerialisationTest(), + new Shacal2Test(), + new SigNameTest(), + new SignatureTest(), + new SigTest(), + new SipHash128Test(), new SipHashTest(), - new KeccakTest(), new SkeinTest(), - new Shacal2Test(), - new DetDSATest(), - new ThreefishTest(), + new SlotTwoTest(), + new SM2CipherTest(), + new SM2KeyExchangeTest(), new SM2SignatureTest(), new SM4Test(), + new ThreefishTest(), new TLSKDFTest(), - new BCFKSStoreTest(), - new DSTU7624Test(), - new GOST3412Test(), - new GOST3410KeyPairTest(), - new EdECTest(), - new OpenSSHSpecTests(), - new SM2CipherTest(), - new ZucTest(), - new ChaCha20Poly1305Test(), - new SipHash128Test(), - new XOFTest(), + new WrapTest(), + new X509CertificatePairTest(), + new X509LDAPCertStoreTest(), + new X509StreamParserTest(), new XIESTest(), - new CertLocaleTest() + new XOFTest(), + new ZucTest(), }; public static void main(String[] args) diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/SM2KeyExchangeTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/SM2KeyExchangeTest.java new file mode 100644 index 0000000000..80ae3599e2 --- /dev/null +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/SM2KeyExchangeTest.java @@ -0,0 +1,66 @@ +package org.bouncycastle.jce.provider.test; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; + +import javax.crypto.KeyAgreement; + +import org.bouncycastle.jcajce.spec.SM2KeyExchangeSpec; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.test.SimpleTest; + +public class SM2KeyExchangeTest + extends SimpleTest +{ + @Override + public String getName() + { + return "SM2KeyExchange"; + } + + @Override + public void performTest() + throws Exception + { + KeyAgreement keyAgreement = KeyAgreement.getInstance("SM2", "BC"); + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("SM2", "BC"); + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + KeyPair kp3 = kpGen.generateKeyPair(); + KeyPair kp4 = kpGen.generateKeyPair(); + + keyAgreement.init(kp1.getPrivate(), new SM2KeyExchangeSpec(true, kp2.getPrivate(), kp4.getPublic(), Strings.toByteArray("ALICE123@YAHOO.COM"), Strings.toByteArray("BILL456@YAHOO.COM"))); + keyAgreement.doPhase(kp3.getPublic(), true); + + byte[] sec1 = keyAgreement.generateSecret(); + + keyAgreement.init(kp3.getPrivate(), new SM2KeyExchangeSpec(false, kp4.getPrivate(), kp2.getPublic(), Strings.toByteArray("BILL456@YAHOO.COM"), Strings.toByteArray("ALICE123@YAHOO.COM"))); + + keyAgreement.doPhase(kp1.getPublic(), true); + + byte[] sec2 = keyAgreement.generateSecret(); + + isTrue(areEqual(sec1, sec2)); + byte[] id1 = new byte[16]; + byte[] id2 = new byte[16]; + SecureRandom random = new SecureRandom(); + random.nextBytes(id1); + random.nextBytes(id2); + + keyAgreement.init(kp1.getPrivate(), new SM2KeyExchangeSpec(true, kp2.getPrivate(), kp4.getPublic(), id1, id2)); + keyAgreement.doPhase(kp3.getPublic(), true); + + byte[] sec3 = keyAgreement.generateSecret(); + + keyAgreement.init(kp3.getPrivate(), new SM2KeyExchangeSpec(false, kp4.getPrivate(), kp2.getPublic(), id2, id1)); + + keyAgreement.doPhase(kp1.getPublic(), true); + + byte[] sec4 = keyAgreement.generateSecret(); + + isTrue(areEqual(sec3, sec4)); + isTrue(!areEqual(sec1, sec4)); + + } +} diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/SM4Test.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/SM4Test.java index 428a9cfe32..b0fe05a489 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/SM4Test.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/SM4Test.java @@ -134,6 +134,10 @@ public void test( public void performTest() throws Exception { + wrapTest(1, "SM4WRAP", Hex.decode("0123456789abcdeffedcba9876543210"), null, + null, Hex.decode("0123456789abcdeffedcba9876543210"), Hex.decode("5d9c31d2f37a186c13943c7e650fbcf895a91f670b7b92bd")); + wrapTest(2, "SM4WRAPPAD", Hex.decode("0123456789abcdeffedcba9876543210"), null, + null, Hex.decode("0123456789abcdeffedcba9876543210"), Hex.decode("7d7110bfbdad2f7b453499338fd40f27014be97c0c69867a")); for (int i = 0; i != cipherTests.length; i += 4) { test(Integer.parseInt(cipherTests[i]), diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/SignedData.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/SignedData.java index ccb897ee69..3fc68af98b 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/SignedData.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/SignedData.java @@ -60,11 +60,6 @@ class SignedData extends ASN1Object { - private static final ASN1Integer VERSION_1 = new ASN1Integer(1); - private static final ASN1Integer VERSION_3 = new ASN1Integer(3); - private static final ASN1Integer VERSION_4 = new ASN1Integer(4); - private static final ASN1Integer VERSION_5 = new ASN1Integer(5); - private ASN1Integer version; private ASN1Set digestAlgorithms; private ContentInfo contentInfo; @@ -159,7 +154,7 @@ else if (tagged.getTagNo() == 3) if (otherCert) { - return new ASN1Integer(5); + return ASN1Integer.FIVE; } if (crls != null) // no need to check if otherCert is true @@ -176,30 +171,30 @@ else if (tagged.getTagNo() == 3) if (otherCrl) { - return VERSION_5; + return ASN1Integer.FIVE; } if (attrCertV2Found) { - return VERSION_4; + return ASN1Integer.FOUR; } if (attrCertV1Found) { - return VERSION_3; + return ASN1Integer.THREE; } if (checkForVersion3(signerInfs)) { - return VERSION_3; + return ASN1Integer.THREE; } if (!CMSObjectIdentifiers.data.equals(contentOid)) { - return VERSION_3; + return ASN1Integer.THREE; } - return VERSION_1; + return ASN1Integer.ONE; } private boolean checkForVersion3(ASN1Set signerInfs) diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/TestCertificateGen.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/TestCertificateGen.java index 1758e27387..ba2f0408a8 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/TestCertificateGen.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/TestCertificateGen.java @@ -1,15 +1,10 @@ package org.bouncycastle.jce.provider.test; import java.io.ByteArrayInputStream; -import java.io.IOException; import java.math.BigInteger; import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; -import java.security.SecureRandom; import java.security.Signature; import java.security.cert.CertificateFactory; import java.security.cert.X509CRL; @@ -29,17 +24,13 @@ import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; -import org.bouncycastle.asn1.x509.BasicConstraints; import org.bouncycastle.asn1.x509.CRLNumber; import org.bouncycastle.asn1.x509.CRLReason; -import org.bouncycastle.asn1.x509.Certificate; 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.KeyUsage; -import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x509.TBSCertList; import org.bouncycastle.asn1.x509.TBSCertificate; @@ -66,7 +57,7 @@ public class TestCertificateGen algIds.put("Ed448", new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448)); } - private synchronized static long getSerialNumber() + private static synchronized long getSerialNumber() { return serialNumber++; } @@ -84,7 +75,7 @@ public static X509Certificate createSelfSignedCert(X500Name dn, String sigName, long time = System.currentTimeMillis(); - certGen.setSerialNumber(new ASN1Integer(getSerialNumber())); + certGen.setSerialNumber(ASN1Integer.valueOf(getSerialNumber())); certGen.setIssuer(dn); certGen.setSubject(dn); certGen.setStartDate(new Time(new Date(time - 5000))); @@ -122,7 +113,7 @@ public static X509Certificate createCert(X500Name signerName, PrivateKey signerK long time = System.currentTimeMillis(); - certGen.setSerialNumber(new ASN1Integer(getSerialNumber())); + certGen.setSerialNumber(ASN1Integer.valueOf(getSerialNumber())); certGen.setIssuer(signerName); certGen.setSubject(dn); certGen.setStartDate(new Time(new Date(time - 5000))); @@ -155,7 +146,7 @@ public static X509Certificate createCertWithIDs(X500Name signerName, String sigN long time = System.currentTimeMillis(); - certGen.setSerialNumber(new ASN1Integer(getSerialNumber())); + certGen.setSerialNumber(ASN1Integer.valueOf(getSerialNumber())); certGen.setIssuer(signerName); certGen.setSubject(signerName); certGen.setStartDate(new Time(new Date(time - 5000))); @@ -190,83 +181,6 @@ public static X509Certificate createCertWithIDs(X500Name signerName, String sigN return (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER))); } - /** - * Create a random 1024 bit RSA key pair - */ - public static KeyPair generateRSAKeyPair() - throws Exception - { - KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); - - kpGen.initialize(1024, new SecureRandom()); - - return kpGen.generateKeyPair(); - } - - public static X509Certificate generateRootCert(KeyPair pair) - throws Exception - { - return createSelfSignedCert("CN=Test CA Certificate", "SHA256withRSA", pair); - } - - public static X509Certificate generateRootCert(KeyPair pair, X500Name dn) - throws Exception - { - return createSelfSignedCert(dn, "SHA256withRSA", pair); - } - - public static X509Certificate generateIntermediateCert(PublicKey intKey, PrivateKey caKey, X509Certificate caCert) - throws Exception - { - return generateIntermediateCert( - intKey, new X500Name("CN=Test Intermediate Certificate"), caKey, caCert); - } - - public static X509Certificate generateIntermediateCert(PublicKey intKey, X500Name subject, PrivateKey caKey, X509Certificate caCert) - throws Exception - { - Certificate caCertLw = Certificate.getInstance(caCert.getEncoded()); - - ExtensionsGenerator extGen = new ExtensionsGenerator(); - - extGen.addExtension(Extension.authorityKeyIdentifier, false, new AuthorityKeyIdentifier(getDigest(caCertLw.getSubjectPublicKeyInfo()), - new GeneralNames(new GeneralName(caCertLw.getIssuer())), - caCertLw.getSerialNumber().getValue())); - extGen.addExtension(Extension.subjectKeyIdentifier, false, new SubjectKeyIdentifier(getDigest(SubjectPublicKeyInfo.getInstance(intKey.getEncoded())))); - extGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0)); - extGen.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign)); - - return createCert( - caCertLw.getSubject(), - caKey, subject, "SHA256withRSA", extGen.generate(), intKey); - } - - public static X509Certificate generateEndEntityCert(PublicKey intKey, PrivateKey caKey, X509Certificate caCert) - throws Exception - { - return generateEndEntityCert( - intKey, new X500Name("CN=Test End Certificate"), caKey, caCert); - } - - public static X509Certificate generateEndEntityCert(PublicKey entityKey, X500Name subject, PrivateKey caKey, X509Certificate caCert) - throws Exception - { - Certificate caCertLw = Certificate.getInstance(caCert.getEncoded()); - - ExtensionsGenerator extGen = new ExtensionsGenerator(); - - extGen.addExtension(Extension.authorityKeyIdentifier, false, new AuthorityKeyIdentifier(getDigest(caCertLw.getSubjectPublicKeyInfo()), - new GeneralNames(new GeneralName(caCertLw.getIssuer())), - caCertLw.getSerialNumber().getValue())); - extGen.addExtension(Extension.subjectKeyIdentifier, false, new SubjectKeyIdentifier(getDigest(entityKey.getEncoded()))); - extGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0)); - extGen.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign)); - - return createCert( - caCertLw.getSubject(), - caKey, subject, "SHA256withRSA", extGen.generate(), entityKey); - } - public static X509CRL createCRL( X509Certificate caCert, PrivateKey caKey, @@ -309,23 +223,23 @@ public static X509CRL createCRL( return (X509CRL)CertificateFactory.getInstance("X.509", "BC").generateCRL(new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER))); } - private static byte[] getDigest(SubjectPublicKeyInfo spki) - throws IOException - { - return getDigest(spki.getPublicKeyData().getBytes()); - } - - private static byte[] getDigest(byte[] bytes) - { - try - { - return MessageDigest.getInstance("SHA1").digest(bytes); - } - catch (NoSuchAlgorithmException e) - { - return null; - } - } +// private static byte[] getDigest(SubjectPublicKeyInfo spki) +// throws IOException +// { +// return getDigest(spki.getPublicKeyData().getBytes()); +// } + +// private static byte[] getDigest(byte[] bytes) +// { +// try +// { +// return MessageDigest.getInstance("SHA1").digest(bytes); +// } +// catch (NoSuchAlgorithmException e) +// { +// return null; +// } +// } private static DERBitString booleanToBitString(boolean[] id) { diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/TestUtils.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/TestUtils.java index 12415dcb2e..1c99d038ad 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/TestUtils.java +++ b/prov/src/test/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.X509ObjectIdentifiers; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.digests.SHA1Digest; @@ -92,7 +93,7 @@ public static X509Certificate createSelfSignedCert(X500Name dn, String sigName, long time = System.currentTimeMillis(); - certGen.setSerialNumber(new ASN1Integer(serialNumber.getAndIncrement())); + certGen.setSerialNumber(ASN1Integer.valueOf(serialNumber.getAndIncrement())); certGen.setIssuer(dn); certGen.setSubject(dn); certGen.setStartDate(new Time(new Date(time - 5000))); @@ -117,6 +118,32 @@ public static X509Certificate createSelfSignedCert(X500Name dn, String sigName, return (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER))); } + public static X509Certificate createNoSigCert(X500Name dn, KeyPair keyPair) + throws Exception + { + V1TBSCertificateGenerator certGen = new V1TBSCertificateGenerator(); + + long time = System.currentTimeMillis(); + + certGen.setSerialNumber(ASN1Integer.valueOf(serialNumber.getAndIncrement())); + certGen.setIssuer(dn); + certGen.setSubject(dn); + certGen.setStartDate(new Time(new Date(time - 5000))); + certGen.setEndDate(new Time(new Date(time + 30 * 60 * 1000))); + certGen.setSignature(new AlgorithmIdentifier(X509ObjectIdentifiers.id_alg_unsigned)); + certGen.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded())); + + TBSCertificate tbsCert = certGen.generateTBSCertificate(); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsCert); + v.add(new AlgorithmIdentifier(X509ObjectIdentifiers.id_alg_unsigned)); + v.add(new DERBitString(new byte[0])); + + return (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER))); + } + public static X509Certificate createCert(X500Name signerName, PrivateKey signerKey, String dn, String sigName, Extensions extensions, PublicKey pubKey) throws Exception { @@ -130,7 +157,7 @@ public static X509Certificate createCert(X500Name signerName, PrivateKey signerK long time = System.currentTimeMillis(); - certGen.setSerialNumber(new ASN1Integer(serialNumber.getAndIncrement())); + certGen.setSerialNumber(ASN1Integer.valueOf(serialNumber.getAndIncrement())); certGen.setIssuer(signerName); certGen.setSubject(dn); certGen.setStartDate(new Time(new Date(time - 5000))); @@ -167,6 +194,12 @@ public static KeyPair generateRSAKeyPair() return kpGen.generateKeyPair(); } + public static X509Certificate generateNoSigRootCert(KeyPair pair) + throws Exception + { + return createNoSigCert(new X500Name("CN=Test CA Certificate"), pair); + } + public static X509Certificate generateRootCert(KeyPair pair) throws Exception { @@ -222,8 +255,8 @@ public static X509Certificate generateEndEntityCert(PublicKey entityKey, X500Nam new GeneralNames(new GeneralName(caCertLw.getIssuer())), caCertLw.getSerialNumber().getValue())); extGen.addExtension(Extension.subjectKeyIdentifier, false, new SubjectKeyIdentifier(getDigest(entityKey.getEncoded()))); - extGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0)); - extGen.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign)); + extGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(false)); + extGen.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature)); return createCert( caCertLw.getSubject(), @@ -247,8 +280,8 @@ public static X509Certificate generateEndEntityCert(PublicKey entityKey, X500Nam new GeneralNames(new GeneralName(caCertLw.getIssuer())), caCertLw.getSerialNumber().getValue())); extGen.addExtension(Extension.subjectKeyIdentifier, false, new SubjectKeyIdentifier(getDigest(entityKey.getEncoded()))); - extGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0)); - extGen.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign)); + extGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(false)); + extGen.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature)); if (keyPurpose2 == null) { extGen.addExtension(Extension.extendedKeyUsage, true, new ExtendedKeyUsage(keyPurpose1)); diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/X509LDAPCertStoreTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/X509LDAPCertStoreTest.java index 98419dab77..03c31c2ed2 100644 --- a/prov/src/test/java/org/bouncycastle/jce/provider/test/X509LDAPCertStoreTest.java +++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/X509LDAPCertStoreTest.java @@ -9,12 +9,12 @@ import com.unboundid.ldap.sdk.LDAPResult; import com.unboundid.ldap.sdk.ResultCode; import com.unboundid.ldif.LDIFException; -import junit.framework.TestCase; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.jce.X509LDAPCertStoreParameters; import org.bouncycastle.jce.exception.ExtCertPathBuilderException; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.test.TestResourceFinder; +import org.bouncycastle.util.test.SimpleTest; import javax.net.ServerSocketFactory; import javax.net.SocketFactory; @@ -39,18 +39,10 @@ import java.util.List; public class X509LDAPCertStoreTest - extends TestCase + extends SimpleTest { - public void setUp() - { - if (Security.getProvider("BC") == null) - { - Security.addProvider(new BouncyCastleProvider()); - } - } - - public void testLdapFilter() - throws Exception + public void performTest() + throws Exception { BcFilterCheck filterCheck = new BcFilterCheck(); @@ -96,7 +88,7 @@ public void testLdapFilter() //shut down ldap server ds.shutDown(true); - assertTrue(filterCheck.isUsed()); + isTrue(filterCheck.isUsed()); } private static InMemoryDirectoryServer mockLdapServer(BcFilterCheck filterCheck) @@ -116,7 +108,7 @@ private static InMemoryDirectoryServer mockLdapServer(BcFilterCheck filterCheck) return new InMemoryDirectoryServer(serverConfig); } - public static void readEntriesFromFile(InMemoryDirectoryServer ds) throws IOException, LDAPException, LDIFException + private void readEntriesFromFile(InMemoryDirectoryServer ds) throws IOException, LDAPException, LDIFException { InputStream src = TestResourceFinder.findTestResource("ldap/", "X509LDAPCertTest.ldif"); BufferedReader bin = new BufferedReader(new InputStreamReader(src)); @@ -168,11 +160,12 @@ public static void readEntriesFromFile(InMemoryDirectoryServer ds) throws IOExce // addEntry(ds, "dn: cn=chars[*()\\\0],dc=people,dc=test", "objectClass: Person", "objectClass: organizationalPerson", "sn: chars", "cn: chars[*()\\\0]"); // } - public static void addEntry(InMemoryDirectoryServer ds, String... args) + private void addEntry(InMemoryDirectoryServer ds, String... args) throws LDIFException, LDAPException { LDAPResult result = ds.add(args); - assertEquals(0, result.getResultCode().intValue()); + + isEquals(0, result.getResultCode().intValue()); } static void verifyCert(X509Certificate cert) @@ -199,7 +192,6 @@ static void verifyCert(X509Certificate cert) { CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", "BC"); PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult)builder.build(pkixParams); - } catch (ExtCertPathBuilderException exception) { @@ -210,7 +202,7 @@ static void verifyCert(X509Certificate cert) /* check we get a suitably escaped subject. */ - static class BcFilterCheck + class BcFilterCheck extends InMemoryOperationInterceptor { private volatile boolean used = false; @@ -219,7 +211,7 @@ public void processSearchResult(InMemoryInterceptedSearchResult result) { String filter = result.getRequest().getFilter().toString(); - assertEquals("(&(cn=*chars[\\2a\\28\\29\\00]*)(userCertificate=*))", filter); + isEquals("(&(cn=*chars[\\2a\\28\\29\\00]*)(userCertificate=*))", filter); used = true; @@ -231,4 +223,16 @@ boolean isUsed() return used; } } + + public String getName() + { + return "X509LDAPCertStore"; + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new X509LDAPCertStoreTest()); + } } diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java index 693dae7730..51e9d6ece8 100644 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java +++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/AllTests.java @@ -75,8 +75,9 @@ public static Test suite() suite.addTestSuite(BIKETest.class); suite.addTestSuite(HQCKeyPairGeneratorTest.class); suite.addTestSuite(HQCTest.class); - suite.addTestSuite(RainbowKeyPairGeneratorTest.class); - suite.addTestSuite(RainbowTest.class); + suite.addTestSuite(MayoKeyPairGeneratorTest.class); + suite.addTestSuite(MayoTest.class); + suite.addTestSuite(SnovaTest.class); return new BCTestSetup(suite); } diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/FalconTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/FalconTest.java index 5908b82825..df2c864705 100644 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/FalconTest.java +++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/FalconTest.java @@ -2,6 +2,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.security.InvalidAlgorithmParameterException; @@ -9,6 +10,8 @@ import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.Provider; +import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; import java.security.Signature; @@ -23,10 +26,14 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.pqc.jcajce.interfaces.FalconKey; import org.bouncycastle.pqc.jcajce.interfaces.FalconPrivateKey; +import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; import org.bouncycastle.pqc.jcajce.spec.FalconParameterSpec; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.io.pem.PemObject; +import org.bouncycastle.util.io.pem.PemReader; public class FalconTest extends TestCase @@ -41,8 +48,72 @@ public void setUp() } } + public void testOQSPublicKeyExample() + throws Exception + { + try + { + // Register BouncyCastle PQC provider + Security.addProvider(new BouncyCastlePQCProvider()); + + for (Provider provider : Security.getProviders()) + { + if ("BCPQC".equals(provider.getName())) + { + System.out.println("Provider: " + provider.getName() + " " + provider.getVersion()); + } + } + + // Read public key + byte[] data = ("-----BEGIN PUBLIC KEY-----\n" + + "MIIDjzAHBgUrzg8DCwOCA4IACQTGjlTc0dE3Gt3rHNvjaQ1VdPgRBbdS3LK+50W7\n" + + "FEESAMeCdwFMSFiBhjlVDvCHnodDXnzLRacPjekdlvWew6pAYSITnjmk6hXQQCOJ\n" + + "NSnppbCbCC+R1XEjBrCPvFnTNm5maSjzUoMT75iZ9sNu0SALQeFGa0w9vvaK4g7S\n" + + "UiU02OYjZdUdTVG7DCK8RxaGRVCmCH5G60YmJNuYcExZtV01L6jYuDprjjd05aoT\n" + + "2Kp0pjp1Ms2gj6AsubmcG7c0MFEN07pCvEyROYWqMgST6FseW6l5y1XVHrA8tsDH\n" + + "ga0xum3zcRaNIEXhXgKaXeEusTQRAxqVvfI5dghVaiRp1eIWgTgRwaya7IuGkFXK\n" + + "CXWDPy9myAGUn5pEvL2WM5uZtrJC5daKQreojXT96rmg+MoKlhnkaYbOcgWBGVAJ\n" + + "+akOqdwBoK6UU58cpVR+yGnrqE6cAwZdgthQyAWYBaxSI86ydoIia0tacomTrLw7\n" + + "ujD1CC2YuzJjRQOpjyPd+7SCpSEzacao4CNvso3H5+jkJIW15hjbn1sVupYyk+cJ\n" + + "bnk91o5NuqbYTQbKnohShayHfZh6NiJAmm0QB2WSGgQVq5J1BKjGHcSOp9hOSMLM\n" + + "TGr6PvIlQRVy8XQjA1Tdj7CFt9iNX5eYSSlWIgVuIkLrKClvMBmnS+zErVnR/OBO\n" + + "xokvoKFWHKqpTn5NCw1bxIBO5XTZ4UWplh37h29WYgKwt6QljS6+6xCXTL2m1tZh\n" + + "q8grMflqsctTmlQl14TWVqllkAATrUQned44pmahupl1TETfHVp9cMbCfBYHWbTe\n" + + "IRVkpYbgCCjMJKSDjocEqONhQkktxC0lxlQIVKlWTJ83tFMHW9Z7tdlJyHefF6dh\n" + + "R4Ozi6eEyGE49ZkAC3JmR2EKDXUYUFNfIoKX5LIBwBLCN/B6pKMSpBENe0jhbtlL\n" + + "XSHIpy0yl8rKsudMFjxJapSzyxs4rbFTe0SFMDjgwz9MJHROcpgHLEmOGBlFr8bP\n" + + "uJm+A/yWn3sh+vS1A+NsBH4R8gedRK7YSdoJBnUkp/LUyPJK+oGAwoJZXwiFyQxN\n" + + "r0R8x8Iqy3Y4oXWGLcYnQUEpAPjFQbCEONrlpUanxPSoQ9sMLKinxemTWD35rsXN\n" + + "iW09ZO6hYaiVggY8ETeZHXnN8eCcG7s88GejwisLGVY1I4cdkHLuNxmEn9yr4adL\n" + + "Huc6\n" + + "-----END PUBLIC KEY-----").getBytes(); + + PemReader reader = new PemReader(new InputStreamReader(new ByteArrayInputStream(data))); + PemObject pemObject = reader.readPemObject(); + reader.close(); + + byte[] keyBytes = pemObject.getContent(); + + // Load the public key + KeyFactory keyFactory = KeyFactory.getInstance("Falcon", "BCPQC"); + PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(keyBytes)); + + // Print information + System.out.println("Public Key Algorithm : " + publicKey.getAlgorithm()); + System.out.println("Public Key Format : " + publicKey.getFormat()); + System.out.println("Encoded Key Length : " + publicKey.getEncoded().length + " bytes"); + System.out.println("Encoded Key (Base64) : " + Base64.toBase64String(publicKey.getEncoded())); + + } + catch (Exception e) + { + System.err.println("Failed to read Falcon-512 public key."); + e.printStackTrace(); + } + } + public void testPrivateKeyRecovery() - throws Exception + throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("Falcon", "BC"); @@ -80,7 +151,7 @@ public void testPrivateKeyRecovery() } public void testPublicKeyRecovery() - throws Exception + throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("Falcon", "BC"); @@ -233,7 +304,7 @@ private void doTestRestrictedKeyPairGen(FalconParameterSpec spec, FalconParamete } public void testFalconRandomSig() - throws Exception + throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("Falcon", "BC"); @@ -266,10 +337,11 @@ public void testFalconRandomSig() * pk = 096BA86CB658A8F445C9A5E4C28374BEC879C8655F68526923240918074D0147C03162E4A49200648C652803C6FD7509AE9AA799D6310D0BD42724E0635920186207000767CA5A8546B1755308C304B84FC93B069E265985B398D6B834698287FF829AA820F17A7F4226AB21F601EBD7175226BAB256D8888F009032566D6383D68457EA155A94301870D589C678ED304259E9D37B193BC2A7CCBCBEC51D69158C44073AEC9792630253318BC954DBF50D15028290DC2D309C7B7B02A6823744D463DA17749595CB77E6D16D20D1B4C3AAD89D320EBE5A672BB96D6CD5C1EFEC8B811200CBB062E473352540EDDEF8AF9499F8CDD1DC7C6873F0C7A6BCB7097560271F946849B7F373640BB69CA9B518AA380A6EB0A7275EE84E9C221AED88F5BFBAF43A3EDE8E6AA42558104FAF800E018441930376C6F6E751569971F47ADBCA5CA00C801988F317A18722A29298925EA154DBC9024E120524A2D41DC0F18FD8D909F6C50977404E201767078BA9A1F9E40A8B2BA9C01B7DA3A0B73A4C2A6B4F518BBEE3455D0AF2204DDC031C805C72CCB647940B1E6794D859AAEBCEA0DEB581D61B9248BD9697B5CB974A8176E8F910469CAE0AB4ED92D2AEE9F7EB50296DAF8057476305C1189D1D9840A0944F0447FB81E511420E67891B98FA6C257034D5A063437D379177CE8D3FA6EAF12E2DBB7EB8E498481612B1929617DA5FB45E4CDF893927D8BA842AA861D9C50471C6D0C6DF7E2BB26465A0EB6A3A709DE792AAFAAF922AA95DD5920B72B4B8856C6E632860B10F5CC08450003671AF388961872B466400ADB815BA81EA794945D19A100622A6CA0D41C4EA620C21DC125119E372418F04402D9FA7180F7BC89AFA54F8082244A42F46E5B5ABCE87B50A7D6FEBE8D7BBBAC92657CBDA1DB7C25572A4C1D0BAEA30447A865A2B1036B880037E2F4D26D453E9E913259779E9169B28A62EB809A5C744E04E260E1F2BBDA874F1AC674839DDB47B3148C5946DE0180148B7973D63C58193B17CD05D16E80CD7928C2A338363A23A81C0608C87505589B9DA1C617E7B70786B6754FBB30A5816810B9E126CFCC5AA49326E9D842973874B6359B5DB75610BA68A98C7B5E83F125A82522E13B83FB8F864E2A97B73B5D544A7415B6504A13939EAB1595D64FAF41FAB25A864A574DE524405E878339877886D2FC07FA0311508252413EDFA1158466667AFF78386DAF7CB4C9B850992F96E20525330599AB601D454688E294C8C3E * sk = 59044102F3CFBE1BE03C144102F7EF75FBEF83043F7CFC20C20BEEC007DE3F041FBF0BFF401041030C40040FAE7E103F7E100085FC013D1410C80C2F000810461C2F480BEE8017D17F07F1411BA24013C1BDF83DC407D17E07C13917F0F9044045FC40BD0FF07D07EF0003DFC1F3CFFD1FC03FEFC0B8FC6E7B0BBDBD0FE0BE17D14307EFFE0FBFC6F81FBFF43EC1F87041D42083EC3DC2F4407BF84EC4140FC403F037F3FEC013E0FEE02180082F83FBE07BFFE043F40EC6FFB1BF200007FFBFFA0FFF6FFBCE83EBFEBEFC0FFDF3F103FC6F3FF0500A18718308007D03F200E4213BF04FFD17D000F0017A17F180E04FFF07DEC2244048148E8704503EE06F86080243F81FFF03BF4003F07EF3DE02FBFFC00420C1F40FBDF0707E043FF5FFD0000430400C4F49F4207C142F80EC3E010BFF7C13F07FF85F7F17E07C17FF33FC4EC303FFBCFFEEC41830FF0831BDF45F05F06FC503B0C0F84E4013E100E7E1441450C2FBEEBC0C0FBEFC60BCFFEF3CFBDF4303EF800BF2BE0BF001F01F43F41FFE08517B001141E00144F7EF8007CEBDFFFF4213A0B9F8A0FE04103C17E0820BB1C30C30C00FFFFC00007D18017CFF90C3101E7E103040FC4FBE04213E07AF80FFEFC80FBFBD0810BCFB8FBC087FB8FFF1010C2E81002F3EF3BF01F07E41FBC07F2C0FB8F43F401C5D81FFCEBE07C07E0BF17EEBEE830C514003FF7EF3E08403D1FFFFE105F840C20BDF0607FFFEF46E7EFFF08000400DE830000F3F82EF9D82E84EFFF3CEC4E81E01002103102EFC080F3B0801041BAE42F7F040F83EC31010031BC0410FAFF9F0004010133A089FFEF7BE8317A0020FEF010052BA04107E100F821C2F41F44F4EF7B000F02E41F82F380830FE08A1F707FF82EC7F42E81004041103E8307B13D0FDFF8F830F9FC5FFCD7E040F410FFFB9F423750860C11C5FFA144EC0080F02DC0F420820450790020BCF80EFFFBCEC4FBFF4200AFC00C02060C004303EF81FFA104107E4117AF01F81202FC1E44143FFE206EB3E881BB13F13920403FF7A000144102E7FFC2143E7FF4AF3F13F07E181DC317E240F4500303F2DDDCF1E1513E3EF15E8DC1309E50AEE03EFDC17081706FD03E6ECE4F30EBD1909051906E90CE806EB0B19E719EFFBF10D0DF1DC0CF6F1F4F8FEFBE9F9550E2107FCDCCBDFE9F4F7EE1AF8142115F910002AF2F5FF141ADA220AECFE040CEF0B29EB201930F2D3E401E5DEEFF4DDEA17F1FE141217F81C36050109F8F61F02DD19F90310C7F40208E9052C3942F8FFF2CCF9FDF83CFA12DC091C0D02F00411F5281E40D7F92DBA11D73D04C10BFD13E617110AF3ED05F6CFE705E0F70E1FF80533FC120C002CE81FF52638190FE3FED6F0FBBB23E6F408EF32220B13DD27F007E5FA00D72614F0E302210707EC111E070E2A032DF91DE3FCE800F1F9F2F7FE170101180412CBD1E90019F2011522DAEAED13F8E5F425DCEF24E01CE614E7DCEC01F2F4F914F4010107ED26E2E9DF0BF5F007EA07FAFBC6D7E607FAFCFD270DFD0D17FC4EF0EE00071AECDE09F8F215E113F80209CCF308D7E6251ECE0EDFED0CC9F4050B2714F61BF703F0EBF104010DEBFBF21AFC1BF01823FEDEFAF7F807E3F3020AEB01FE19EEE8E90D00E5FAED1EFDF628E5F0E6F0FC13F4FB05FB0B09EA0A0E08EE13293212E90CE4FEF223F4FF030BEBED1B402ED2F6171102BC0CF9E9F335ED0C01FAF0FEFAE41DF0050A162C11171CD90BEE211218EDFAFA0F03F4171412F319D60B01FAEE1F2823F0D6EF12D6DFEAFBFC170DECDA06E7CED500031E * sm = 026833B3C07507E4201748494D832B6EE2A6C93BFF9B0EE343B550D1F85A3D0DE0D704C6D17842951309D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8290765843D1E460D17A527D2BCA405BD55BBC7DA09A8C620BE0AF4A767D9DB96B80F55E466676751EAABA7B93B86D71132DAA0EB376782B9EEE37519CE10FDD33FE9F29312C31D8736206D165CF4C528AA3DDC017845E1F0DD5B0A44FF961C42D874A95533E5B438982F524CA954D87533BFBE42C63FF2ABC77A34C79DB55A99171BBCB72C842A6530AF2F753F0C34AC632F9F1E7949F0BF6C67665B27722A8857D626B6FF1A136D923A39F4069B7477FF946E5247A6627791D49B59EDC9E2525A860E6E9828D18F64A9F17222E8166A02453859BBDA0B8186D8C9928BB571E4146401D7430E225904673AD21CCAC54C146C248A1DD69AB6491E901D6D71B152155BE97DE057F3916A3F1B4273308C29B2F4D9697167B90681B1583ED930A71E990467DEA368134BECEEBD597F9BEC922E816F1B0570D728F4AE0464C1F797657F87A4E52DCDCAEB9272662EA66D7C6CD8781B31AF555AD93F5F65E75816CB8DC306BB67E592B5261BACA7C509629EA2AF8ABB80CBA89EE535B76DFD9CCBBE3BF48F2BC8AA34B26E1103291053F5CB8DE3A45AFA5A76DF8B2122ED2C82FBCF2259290D41A14F86B12F35F5D49762B34CFF13EE7E42EDEC70201D7F37C33316288FA3078E36E58108865C3CFE263D563692043DECC62F3426F86061285B7B1B336F56FF41BB65E9CD6D9B92FD90F864AA1C923CB8C755F5CDE1770D862595427149D7721AAAB5D194AEA9ACDECA15BE43CBA6A62B5A33909E9FC4DA1C5814FBD7CD6A2FA572E318B42C6C319140B86E66392580A11A2B431F44C1F9270E4F7B2490F3B325A9977A71A575915636635B9969DBD6D220B24C3D99CEBBBD834B88222BD08C3ABE124E80 + * * @throws Exception */ public void testFalconKATSig() - throws Exception + throws Exception { byte[] pubK = Hex.decode("096BA86CB658A8F445C9A5E4C28374BEC879C8655F68526923240918074D0147C03162E4A49200648C652803C6FD7509AE9AA799D6310D0BD42724E0635920186207000767CA5A8546B1755308C304B84FC93B069E265985B398D6B834698287FF829AA820F17A7F4226AB21F601EBD7175226BAB256D8888F009032566D6383D68457EA155A94301870D589C678ED304259E9D37B193BC2A7CCBCBEC51D69158C44073AEC9792630253318BC954DBF50D15028290DC2D309C7B7B02A6823744D463DA17749595CB77E6D16D20D1B4C3AAD89D320EBE5A672BB96D6CD5C1EFEC8B811200CBB062E473352540EDDEF8AF9499F8CDD1DC7C6873F0C7A6BCB7097560271F946849B7F373640BB69CA9B518AA380A6EB0A7275EE84E9C221AED88F5BFBAF43A3EDE8E6AA42558104FAF800E018441930376C6F6E751569971F47ADBCA5CA00C801988F317A18722A29298925EA154DBC9024E120524A2D41DC0F18FD8D909F6C50977404E201767078BA9A1F9E40A8B2BA9C01B7DA3A0B73A4C2A6B4F518BBEE3455D0AF2204DDC031C805C72CCB647940B1E6794D859AAEBCEA0DEB581D61B9248BD9697B5CB974A8176E8F910469CAE0AB4ED92D2AEE9F7EB50296DAF8057476305C1189D1D9840A0944F0447FB81E511420E67891B98FA6C257034D5A063437D379177CE8D3FA6EAF12E2DBB7EB8E498481612B1929617DA5FB45E4CDF893927D8BA842AA861D9C50471C6D0C6DF7E2BB26465A0EB6A3A709DE792AAFAAF922AA95DD5920B72B4B8856C6E632860B10F5CC08450003671AF388961872B466400ADB815BA81EA794945D19A100622A6CA0D41C4EA620C21DC125119E372418F04402D9FA7180F7BC89AFA54F8082244A42F46E5B5ABCE87B50A7D6FEBE8D7BBBAC92657CBDA1DB7C25572A4C1D0BAEA30447A865A2B1036B880037E2F4D26D453E9E913259779E9169B28A62EB809A5C744E04E260E1F2BBDA874F1AC674839DDB47B3148C5946DE0180148B7973D63C58193B17CD05D16E80CD7928C2A338363A23A81C0608C87505589B9DA1C617E7B70786B6754FBB30A5816810B9E126CFCC5AA49326E9D842973874B6359B5DB75610BA68A98C7B5E83F125A82522E13B83FB8F864E2A97B73B5D544A7415B6504A13939EAB1595D64FAF41FAB25A864A574DE524405E878339877886D2FC07FA0311508252413EDFA1158466667AFF78386DAF7CB4C9B850992F96E20525330599AB601D454688E294C8C3E"); byte[] privK = Hex.decode("59044102F3CFBE1BE03C144102F7EF75FBEF83043F7CFC20C20BEEC007DE3F041FBF0BFF401041030C40040FAE7E103F7E100085FC013D1410C80C2F000810461C2F480BEE8017D17F07F1411BA24013C1BDF83DC407D17E07C13917F0F9044045FC40BD0FF07D07EF0003DFC1F3CFFD1FC03FEFC0B8FC6E7B0BBDBD0FE0BE17D14307EFFE0FBFC6F81FBFF43EC1F87041D42083EC3DC2F4407BF84EC4140FC403F037F3FEC013E0FEE02180082F83FBE07BFFE043F40EC6FFB1BF200007FFBFFA0FFF6FFBCE83EBFEBEFC0FFDF3F103FC6F3FF0500A18718308007D03F200E4213BF04FFD17D000F0017A17F180E04FFF07DEC2244048148E8704503EE06F86080243F81FFF03BF4003F07EF3DE02FBFFC00420C1F40FBDF0707E043FF5FFD0000430400C4F49F4207C142F80EC3E010BFF7C13F07FF85F7F17E07C17FF33FC4EC303FFBCFFEEC41830FF0831BDF45F05F06FC503B0C0F84E4013E100E7E1441450C2FBEEBC0C0FBEFC60BCFFEF3CFBDF4303EF800BF2BE0BF001F01F43F41FFE08517B001141E00144F7EF8007CEBDFFFF4213A0B9F8A0FE04103C17E0820BB1C30C30C00FFFFC00007D18017CFF90C3101E7E103040FC4FBE04213E07AF80FFEFC80FBFBD0810BCFB8FBC087FB8FFF1010C2E81002F3EF3BF01F07E41FBC07F2C0FB8F43F401C5D81FFCEBE07C07E0BF17EEBEE830C514003FF7EF3E08403D1FFFFE105F840C20BDF0607FFFEF46E7EFFF08000400DE830000F3F82EF9D82E84EFFF3CEC4E81E01002103102EFC080F3B0801041BAE42F7F040F83EC31010031BC0410FAFF9F0004010133A089FFEF7BE8317A0020FEF010052BA04107E100F821C2F41F44F4EF7B000F02E41F82F380830FE08A1F707FF82EC7F42E81004041103E8307B13D0FDFF8F830F9FC5FFCD7E040F410FFFB9F423750860C11C5FFA144EC0080F02DC0F420820450790020BCF80EFFFBCEC4FBFF4200AFC00C02060C004303EF81FFA104107E4117AF01F81202FC1E44143FFE206EB3E881BB13F13920403FF7A000144102E7FFC2143E7FF4AF3F13F07E181DC317E240F4500303F2DDDCF1E1513E3EF15E8DC1309E50AEE03EFDC17081706FD03E6ECE4F30EBD1909051906E90CE806EB0B19E719EFFBF10D0DF1DC0CF6F1F4F8FEFBE9F9550E2107FCDCCBDFE9F4F7EE1AF8142115F910002AF2F5FF141ADA220AECFE040CEF0B29EB201930F2D3E401E5DEEFF4DDEA17F1FE141217F81C36050109F8F61F02DD19F90310C7F40208E9052C3942F8FFF2CCF9FDF83CFA12DC091C0D02F00411F5281E40D7F92DBA11D73D04C10BFD13E617110AF3ED05F6CFE705E0F70E1FF80533FC120C002CE81FF52638190FE3FED6F0FBBB23E6F408EF32220B13DD27F007E5FA00D72614F0E302210707EC111E070E2A032DF91DE3FCE800F1F9F2F7FE170101180412CBD1E90019F2011522DAEAED13F8E5F425DCEF24E01CE614E7DCEC01F2F4F914F4010107ED26E2E9DF0BF5F007EA07FAFBC6D7E607FAFCFD270DFD0D17FC4EF0EE00071AECDE09F8F215E113F80209CCF308D7E6251ECE0EDFED0CC9F4050B2714F61BF703F0EBF104010DEBFBF21AFC1BF01823FEDEFAF7F807E3F3020AEB01FE19EEE8E90D00E5FAED1EFDF628E5F0E6F0FC13F4FB05FB0B09EA0A0E08EE13293212E90CE4FEF223F4FF030BEBED1B402ED2F6171102BC0CF9E9F335ED0C01FAF0FEFAE41DF0050A162C11171CD90BEE211218EDFAFA0F03F4171412F319D60B01FAEE1F2823F0D6EF12D6DFEAFBFC170DECDA06E7CED500031E"); @@ -292,9 +364,9 @@ public void testFalconKATSig() PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded()); ASN1Sequence privSeq = ASN1Sequence.getInstance(privInfo.parsePrivateKey()); - + byte[] privCat = Arrays.concatenate( - new byte[] { 0x59 }, + new byte[]{0x59}, ASN1OctetString.getInstance(privSeq.getObjectAt(1)).getOctets(), ASN1OctetString.getInstance(privSeq.getObjectAt(2)).getOctets(), ASN1OctetString.getInstance(privSeq.getObjectAt(3)).getOctets()); @@ -321,7 +393,7 @@ public void testFalconKATSig() } private static class RiggedRandom - extends SecureRandom + extends SecureRandom { public void nextBytes(byte[] bytes) { diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/HQCKeyPairGeneratorTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/HQCKeyPairGeneratorTest.java index f5e08f860a..f866b4fbd5 100644 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/HQCKeyPairGeneratorTest.java +++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/HQCKeyPairGeneratorTest.java @@ -31,9 +31,9 @@ public void testKeyPairEncoding() HQCParameterSpec[] specs = new HQCParameterSpec[] { - HQCParameterSpec.hqc128, - HQCParameterSpec.hqc192, - HQCParameterSpec.hqc256 + HQCParameterSpec.hqc128, + HQCParameterSpec.hqc192, + HQCParameterSpec.hqc256 }; kf = KeyFactory.getInstance("HQC", "BCPQC"); diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/HQCTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/HQCTest.java index 107512a2be..e7caacb8c4 100644 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/HQCTest.java +++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/HQCTest.java @@ -11,7 +11,6 @@ import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; -import junit.framework.TestCase; import org.bouncycastle.jcajce.SecretKeyWithEncapsulation; import org.bouncycastle.jcajce.spec.KEMExtractSpec; import org.bouncycastle.jcajce.spec.KEMGenerateSpec; @@ -20,6 +19,9 @@ import org.bouncycastle.pqc.jcajce.spec.HQCParameterSpec; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.test.FixedSecureRandom; + +import junit.framework.TestCase; /** * KEM tests for HQC with the BCPQC provider. @@ -27,16 +29,28 @@ public class HQCTest extends TestCase { + public static void main(String[] args) + throws Exception + { + HQCTest test = new HQCTest(); + test.setUp(); + test.testGenerateAES(); + } + public void setUp() { if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) { Security.addProvider(new BouncyCastlePQCProvider()); } +// if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) +// { +// Security.addProvider(new BouncyCastleProvider()); +// } } public void testBasicKEMAES() - throws Exception + throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("HQC", "BCPQC"); kpg.initialize(HQCParameterSpec.hqc128, new SecureRandom()); @@ -51,7 +65,7 @@ public void testBasicKEMAES() } public void testBasicKEMCamellia() - throws Exception + throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("HQC", "BCPQC"); kpg.initialize(HQCParameterSpec.hqc128, new SecureRandom()); @@ -61,7 +75,7 @@ public void testBasicKEMCamellia() } public void testBasicKEMSEED() - throws Exception + throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("HQC", "BCPQC"); kpg.initialize(HQCParameterSpec.hqc128, new SecureRandom()); @@ -70,7 +84,7 @@ public void testBasicKEMSEED() } public void testBasicKEMARIA() - throws Exception + throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("HQC", "BCPQC"); kpg.initialize(HQCParameterSpec.hqc128, new SecureRandom()); @@ -80,7 +94,7 @@ public void testBasicKEMARIA() } private void performKEMScipher(KeyPair kp, String algorithm, KEMParameterSpec ktsParameterSpec) - throws Exception + throws Exception { Cipher w1 = Cipher.getInstance(algorithm, "BCPQC"); @@ -109,7 +123,7 @@ private void performKEMScipher(KeyPair kp, String algorithm, KEMParameterSpec kt } public void testGenerateAES() - throws Exception + throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("HQC", "BCPQC"); kpg.initialize(HQCParameterSpec.hqc128, new SecureRandom()); @@ -123,7 +137,7 @@ public void testGenerateAES() SecretKeyWithEncapsulation secEnc1 = (SecretKeyWithEncapsulation)keyGen.generateKey(); assertEquals("AES", secEnc1.getAlgorithm()); - assertEquals(16, secEnc1.getEncoded().length); + assertEquals(32, secEnc1.getEncoded().length); keyGen.init(new KEMExtractSpec(kp.getPrivate(), secEnc1.getEncapsulation(), "AES")); @@ -135,7 +149,7 @@ public void testGenerateAES() } public void testGenerateAES256() - throws Exception + throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("HQC", "BCPQC"); kpg.initialize(HQCParameterSpec.hqc256, new SecureRandom()); @@ -159,4 +173,45 @@ public void testGenerateAES256() assertTrue(Arrays.areEqual(secEnc1.getEncoded(), secEnc2.getEncoded())); } + + public void testReedSolomon() + throws Exception + { + byte[] seed = Hex.decode("416a32ada1c7a569c34d5334273a781c340aac25eb7614271aa6930d0358fb30fd87e111336a29e165dc60d9643a3e9b");//b + byte[] kemSeed = Hex.decode("13f36c0636ff93af6d702f7774097c185bf67cddc9b09f9b584d736c4faf40e073b0499efa0c926e9a44fec1e45ee4cf"); + //HQCKeyPairGenerator kpg = new HQCKeyPairGenerator(); + //kpg.init(new HQCKeyGenerationParameters(); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("HQC", "BCPQC"); + SecureRandom random = new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(seed)}); + SecureRandom kemRandom = new FixedSecureRandom(new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(kemSeed)}); + kpg.initialize(HQCParameterSpec.hqc128, random); + KeyPair kp = kpg.generateKeyPair(); + String algorithm = "HQC"; + KEMParameterSpec ktsParameterSpec = new KEMParameterSpec("ARIA-KWP"); + Cipher w1 = Cipher.getInstance(algorithm, "BCPQC"); + + byte[] keyBytes; + if (algorithm.endsWith("KWP")) + { + keyBytes = Hex.decode("000102030405060708090a0b0c0d0e0faa"); + } + else + { + keyBytes = Hex.decode("000102030405060708090a0b0c0d0e0f"); + } + SecretKey key = new SecretKeySpec(keyBytes, "AES"); + + w1.init(Cipher.WRAP_MODE, kp.getPublic(), ktsParameterSpec, kemRandom); + + byte[] data = w1.wrap(key); + + Cipher w2 = Cipher.getInstance(algorithm, "BCPQC"); + + w2.init(Cipher.UNWRAP_MODE, kp.getPrivate(), ktsParameterSpec); + + Key k = w2.unwrap(data, "AES", Cipher.SECRET_KEY); + + assertTrue(Arrays.areEqual(keyBytes, k.getEncoded())); + } + } diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/KeyStoreTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/KeyStoreTest.java index 8aeaa7c993..0e8d20327f 100644 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/KeyStoreTest.java +++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/KeyStoreTest.java @@ -40,7 +40,7 @@ import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; -import org.bouncycastle.pqc.jcajce.spec.McElieceKeyGenParameterSpec; +import org.bouncycastle.pqc.jcajce.spec.CMCEParameterSpec; import org.bouncycastle.pqc.jcajce.spec.SPHINCS256KeyGenParameterSpec; import org.bouncycastle.pqc.jcajce.spec.XMSSMTParameterSpec; @@ -116,10 +116,9 @@ private void tryKeyStore(String format) store.setCertificateEntry("root ca", rootCA); // McEliece - kpg = KeyPairGenerator.getInstance("McEliece", "BCPQC"); - - McElieceKeyGenParameterSpec params = new McElieceKeyGenParameterSpec(9, 33); - kpg.initialize(params); + kpg = KeyPairGenerator.getInstance("CMCE", "BCPQC"); + + kpg.initialize(CMCEParameterSpec.mceliece348864); KeyPair mcelieceKp = kpg.generateKeyPair(); @@ -202,7 +201,7 @@ private static X509Certificate createPQSelfSignedCert(X500Name dn, String sigNam { V3TBSCertificateGenerator certGen = new V3TBSCertificateGenerator(); long time = System.currentTimeMillis(); - certGen.setSerialNumber(new ASN1Integer(serialNumber.getAndIncrement())); + certGen.setSerialNumber(ASN1Integer.valueOf(serialNumber.getAndIncrement())); certGen.setIssuer(dn); certGen.setSubject(dn); certGen.setStartDate(new Time(new Date(time - 5000))); @@ -239,7 +238,7 @@ private static X509Certificate createCert(X500Name signerName, PrivateKey signer long time = System.currentTimeMillis(); - certGen.setSerialNumber(new ASN1Integer(serialNumber.getAndIncrement())); + certGen.setSerialNumber(ASN1Integer.valueOf(serialNumber.getAndIncrement())); certGen.setIssuer(signerName); certGen.setSubject(dn); certGen.setStartDate(new Time(new Date(time - 5000))); diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MLDSATest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MLDSATest.java index 44939fadd2..d1d1a551cb 100644 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MLDSATest.java +++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MLDSATest.java @@ -10,9 +10,12 @@ import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.PrivateKey; import java.security.SecureRandom; import java.security.Security; import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; @@ -20,9 +23,13 @@ import junit.framework.TestCase; import org.bouncycastle.asn1.ASN1BitString; import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.jcajce.MLDSAProxyPrivateKey; import org.bouncycastle.jcajce.interfaces.MLDSAKey; import org.bouncycastle.jcajce.interfaces.MLDSAPrivateKey; import org.bouncycastle.jcajce.spec.ContextParameterSpec; @@ -32,7 +39,9 @@ import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.test.FixedSecureRandom; /** * MLDSA now in BC provider @@ -88,17 +97,17 @@ public void testKeyFactory() throws Exception { KeyFactory kFact = KeyFactory.getInstance("ML-DSA", "BC"); - KeyPairGenerator kpGen44 = KeyPairGenerator.getInstance("ML-DSA-44"); + KeyPairGenerator kpGen44 = KeyPairGenerator.getInstance("ML-DSA-44", "BC"); KeyPair kp44 = kpGen44.generateKeyPair(); - KeyPairGenerator kpGen65 = KeyPairGenerator.getInstance("ML-DSA-65"); + KeyPairGenerator kpGen65 = KeyPairGenerator.getInstance("ML-DSA-65", "BC"); KeyPair kp65 = kpGen65.generateKeyPair(); - KeyPairGenerator kpGen87 = KeyPairGenerator.getInstance("ML-DSA-87"); + KeyPairGenerator kpGen87 = KeyPairGenerator.getInstance("ML-DSA-87", "BC"); KeyPair kp87 = kpGen87.generateKeyPair(); - KeyPairGenerator kpGen44withSha512 = KeyPairGenerator.getInstance("ML-DSA-44-WITH-SHA512"); + KeyPairGenerator kpGen44withSha512 = KeyPairGenerator.getInstance("ML-DSA-44-WITH-SHA512", "BC"); KeyPair kp44withSha512 = kpGen44withSha512.generateKeyPair(); - KeyPairGenerator kpGen65withSha512 = KeyPairGenerator.getInstance("ML-DSA-65-WITH-SHA512"); + KeyPairGenerator kpGen65withSha512 = KeyPairGenerator.getInstance("ML-DSA-65-WITH-SHA512", "BC"); KeyPair kp65withSha512 = kpGen65withSha512.generateKeyPair(); - KeyPairGenerator kpGen87withSha512 = KeyPairGenerator.getInstance("ML-DSA-87-WITH-SHA512"); + KeyPairGenerator kpGen87withSha512 = KeyPairGenerator.getInstance("ML-DSA-87-WITH-SHA512", "BC"); KeyPair kp87withSha512 = kpGen87withSha512.generateKeyPair(); tryKeyFact(KeyFactory.getInstance("ML-DSA-44", "BC"), kp44, kp65, "2.16.840.1.101.3.4.3.18"); @@ -119,6 +128,8 @@ private void tryKeyFact(KeyFactory kFact, KeyPair kpValid, KeyPair kpInvalid, St throws Exception { kFact.generatePrivate(new PKCS8EncodedKeySpec(kpValid.getPrivate().getEncoded())); + kFact.generatePrivate(new PKCS8EncodedKeySpec(((MLDSAPrivateKey)kpValid.getPrivate()).getPrivateKey(true).getEncoded())); + kFact.generatePrivate(new PKCS8EncodedKeySpec(((MLDSAPrivateKey)kpValid.getPrivate()).getPrivateKey(false).getEncoded())); kFact.generatePublic(new X509EncodedKeySpec(kpValid.getPublic().getEncoded())); try @@ -171,6 +182,89 @@ public void testPrivateKeyRecovery() assertEquals(((MLDSAPrivateKey)privKey).getPublicKey(), ((MLDSAPrivateKey)privKey2).getPublicKey()); } + public void testDefaultPrivateKeyEncoding() + throws Exception + { + KeyPairGenerator kpGen44 = KeyPairGenerator.getInstance("ML-DSA-44", "BC"); + + byte[] seed = Hex.decode("000102030405060708090a0b0c0d0e0f" + "100102030405060708090a0b0c0d0e0f"); + + kpGen44.initialize(MLDSAParameterSpec.ml_dsa_44, new FixedSecureRandom(seed)); + KeyPair kp44 = kpGen44.generateKeyPair(); + + PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp44.getPrivate().getEncoded()); + ASN1OctetString seq = ASN1OctetString.getInstance(ASN1Sequence.getInstance(privInfo.getPrivateKey().getOctets()).getObjectAt(0)); + + assertTrue(Arrays.areEqual(seq.getOctets(), seed)); + + ASN1OctetString privData = ASN1OctetString.getInstance(ASN1Sequence.getInstance(privInfo.getPrivateKey().getOctets()).getObjectAt(1)); + + assertTrue(Arrays.areEqual(privData.getOctets(), ((MLDSAPrivateKey)kp44.getPrivate()).getPrivateData())); + } + + public void testSeedPrivateKeyEncoding() + throws Exception + { + KeyPairGenerator kpGen44 = KeyPairGenerator.getInstance("ML-DSA-44", "BC"); + + byte[] seed = Hex.decode("000102030405060708090a0b0c0d0e0f" + "100102030405060708090a0b0c0d0e0f"); + + kpGen44.initialize(MLDSAParameterSpec.ml_dsa_44, new FixedSecureRandom(seed)); + KeyPair kp44 = kpGen44.generateKeyPair(); + + PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(((MLDSAPrivateKey)kp44.getPrivate()).getPrivateKey(true).getEncoded()); + + ASN1OctetString k = privInfo.getPrivateKey(); + + assertTrue(Arrays.areEqual(ASN1OctetString.getInstance((ASN1TaggedObject)privInfo.parsePrivateKey(), false).getOctets(), seed)); + } + + public void testExpandedKeyPrivateKeyEncoding() + throws Exception + { + KeyPairGenerator kpGen44 = KeyPairGenerator.getInstance("ML-DSA-44", "BC"); + + byte[] seed = Hex.decode("000102030405060708090a0b0c0d0e0f" + "100102030405060708090a0b0c0d0e0f"); + byte[] expandedKey = Base64.decode("w/FofbPea45APAHeQqNeZL4KcvMHr8V/inNsUbmYlE0vTZbckQVhHq8sQi2F3yC7B1/aLXIta1rImyPmzsYITzPH4Iz+3/ysH0n3TDx9HFKMp5WwuOX7ZRnNqS/RaiaYltSR0LBwyi5uPgGqw1Cb/mAsJkoJuGx31QGfc1KTMSQYAjEiqU0QJjHAlAyBtiRSxkGZIFFYGAYIIEXSSC4YE2rAooADOQoIQmwbKARSQiWBRExbOIkEQEVJIEQcEUCTxhEjQCahpJFLwDEIhIFamETJqDEbEWrKyCwBKWnCQECcNgYDtAQMMWwMQTFjwCiisEUTQEGiFAoRQibaQmmaokgjFUYJREmMBHAClSABlyRQFAlQECCgRiSCJIEQEwoACSRElg0QEjBSFAgIOQLIuDCiRHHcFoIZp0zkCDCbBIkbFYnYFAQMQ1ELGSCYICDSBGhhBmAcoS0JQ0HBEGGUiIlTIkYaGGpJMJHLtCDAEDKBpgXUAgoSxQAjQm0EuUQjCBDcIkbKwkUUom0clomLKHETNpBioEBTpEDLEkocIzJiQI0JBAIaMQHaRCQbkW0KSHHgBGADoi0AFHHYFA3hgg0ayU1iloyIAEmQBJLLKC4JgQADhiGbmIiUggBcwCWDIiwByWCSEExaRC0ZkgALM0kTlZCJAnHUNEaYlJEEMU6JtAUAo0gRJ23kokkSxoREsjCSomBUyCFEAEpUJmkDkWVLloSSQkpjkm0AEQqZxFEIE4gjGCGTpkEhsEAUEyIZqEAjJg1BRlHBmCEJg4AZSGobNE5gMIWRRmTMtGBcgCVhpo2bwCDjFFLbAkJksHCZRAEKMVBjQi1jhkQQpg3EgmybBjDDqC3hRIBMoGHUpiHIMilQEgpQMA7QEClMBolUNihTAmDQAICTEm6IqEATCCEMOCoEEYwKN4maRDAjkSEJRmnIohALgAADBCoBhjFgJiIYkWmTQiHkKA4cImYLk3CSBIKUEA4gE2ibMkRjkkUKACyMRkYRoWQUl0wbmW2QBkkJR4AgR2iCJAYUMgpLKGwgKVHiBE4iBRALNYwbFwwUAGpQwAwDQSwSwQAQAi7REgrSIAlbkHEJyZAASWDMMm4YlSHiwFFIFkrbFI6IJJERJUhLlkXRyCAAk5GDoC2JyJGYQgkRRGkTJE2jRCzUGFEiF1DAghECNIJIgHAgQWlvzZh7vICP92WCMX3B8zbvb7tgGJ1FERU17RMAxgnav4gEW/oe9DFzrwvEKF4Ku25tc0FQgdmnvLQFYwpTQuDjTxsug4GZViD6JP0GvZpbvfRhSWIjeFVdQcspJ26wR3IaM4M8yRhim1xEfUf7HcopRHQ6bzJ0B7rhE60A1mouwYG8ekzSxQ4WPtqecHdT57vYaEjOqjM0g3vUKa8ybDzUUVJDXx/6pcww596LIBNHygVaBGdRyAhNYxzSg0Z9BuxN295I3WJLU13+yYsdgvMq/qoj0LVZPevCjMBLnGnBAGsXxpYmTZbiyE6v5vQO3xWB6So6vX+G82gl0T33gZEw0B0stRf76XAcHHNkQl5nz1ZdkCS2QGh8Or4nmnuatXYkfXSP8YWDFz7bgtISNta6w7iiluZOySkDb8unuWXa2lUiSbHOJJ1vJ3kxa/jOpQvKULjQ49VFJQpH+vVVZKRtXkvpkFnOmISVSx0rfus9NJCPpQm8S7DJH6pRA1ZgKYsLochGcs0pjWJGAZtUC9V0Bz7gz5XEWJzouDZZe7DfOagc/Ts7irQmpLMFuBeno9kzplKmYSDW1N88uO9CsCP4JOY/EKusbqzRu/032a0I9kozn8gyw3aAU6MArCVbfmr4/L+LV+MhLlnxe2RHy9iLw0SmVI2nJDNoLWichbLKJ7euagFMjqyw45WTmIYXKvX8rsl9TATOwcvL+0okzt8GuDyDmWej1UoGPPC74eyRfVVifPCPfb0M/o+QVwsNMggT11piJcEYmPS3hJWlTJ6t3WDIqwpvh9Bh2OBmNyJ0xMC3Zw3rNWVCLalzxf3RdOhINiSS91DtDP5FDqnZ8Br0HK5GCN00NPfWNt0FjNAWYuRoIBPqx471i+91mQAM7cRwP8izxj7D+wcGQMyQs/FA3ALXU62532rTt/eG90vPtTtj6Jvxcqx+l5oclJIZ/6qQjaqpzP6DIhlPa0e6FBiwRefdazXu2C5gPKtyY9YukXWftFnu3xDqRvxcYd/LBeK0utJYtERs4U2naS0W/8DMRrTTtiME4QZf8QSHnQoEjOS+ZNxb1yUUdmH0FKqeLgPNfXfVmD1B6ZTp/B02o3uRd7y9k4f5IKIPQedW4gdUIfycBP20lYmV5U1xcYVG6r/r1L1kfeCwlEsJ/3NsapVQx2JVuJ+EKBdqsx3zUHHSLnk3kRoZ4q0E5KRPccxgEGCpb2rK4W+hwvskcqfhKZQhYij4B10yzeno8FNIxT2vvXyALAxg2t4nSCVX7Wc1jv9ufEV3z1d5xzo5IDRHVkM1qT+V6zx+mkwXXksaVLiMNkeoy3/FF7uJxNcLajSwUwxht5LAzALa3LqlMyleIvK2fGWiqLaDkp1aYwvzc4i66sm42x2LHE6XwVVR/RnHj/1cg9rbcdVr1huGWA+TmLc0u01EYZrZnc0fGi9BnlYvm3JcEaNJ3f09cB/iN7pgMD/j8kzhykd0RsJgS5sU1ggAFkK4E9kt3WPrNqyIP1jdUZ30+Qnj6KL/bcTcvaxbC6Y1E0sIQgTSaQC9n3yhKawohtEjRDGnbqqltCw9qw6MRjTXWEPeju5YwRpN0DeVNB+3B8/sLeR7aR2tvbk7tyHvB9pW6WSInfmsGnTPqVChU7F0m/qYeP6PwjGK8TY69Pr0ziBh0JOLKYRVG2RwQnZGsGoLoXSHxZCV90Q5mIRagpGDBslvJTcxWtnUWT/ktFYkiFXHvW09hD/jqjzBRXSKOzfZnr5Xery2BIcmslYrSYbb38dY/3TmFL2k56R7nXS2uQEzhFJhT1OjOoOZ6hy6fGlNHhTXhiK0ZmF6AGb/Nw1nS0zW3HEa0wTJ5gnFUQrgkgon3NBtah5+dBsxNGn02O24vF4Lg8Va1Zj04igpuE/CctbUlJ5YKqqAj2SwL5hpBtNk8eV0srIFaFImaMcgzTJXt4tz5gOI3Ds3fkLjt3NBdLwMjw9VegdKHboCCYhVPzFY2lG++5LqJud37flp7Ikni17qpdUYO7khvsMLeUru6ouFqdV6fVdVywn2bW22Xs0DNNIfXGjnfhwhZ4AEvOqyFXmYHYqRYWOtBIxWu0aUtvtjcIi8gkDNsi0kY2Iuf6UFqwN7zqvuGYwsuC+n0UODwdi/48k1FWz/pOzqeaxo9O6AccKNEdDaXT4kwuJZsuvuKo0zv9IxDkVYoRB5Jx+vt58MtKGSxSpylWpJfw=="); + + kpGen44.initialize(MLDSAParameterSpec.ml_dsa_44, new FixedSecureRandom(seed)); + KeyPair kp44 = kpGen44.generateKeyPair(); + + PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(((MLDSAPrivateKey)kp44.getPrivate()).getPrivateKey(false).getEncoded()); + + assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(privInfo.parsePrivateKey()).getOctets(), expandedKey)); + } + + public void testPrivateKeyRecoding() + throws Exception + { + // TODO: rebuild with newer encodings. +// byte[] mldsa44_sequence = Base64.decode("MIIKPgIBADALBglghkgBZQMEAxEEggoqMIIKJgQgAAECAwQFBgcICQoLDA0ODxABAgMEBQYHCAkKCwwNDg+BggoAw/FofbPea45APAHeQqNeZL4KcvMHr8V/inNsUbmYlE0vTZbckQVhHq8sQi2F3yC7B1/aLXIta1rImyPmzsYITzPH4Iz+3/ysH0n3TDx9HFKMp5WwuOX7ZRnNqS/RaiaYltSR0LBwyi5uPgGqw1Cb/mAsJkoJuGx31QGfc1KTMSQYAjEiqU0QJjHAlAyBtiRSxkGZIFFYGAYIIEXSSC4YE2rAooADOQoIQmwbKARSQiWBRExbOIkEQEVJIEQcEUCTxhEjQCahpJFLwDEIhIFamETJqDEbEWrKyCwBKWnCQECcNgYDtAQMMWwMQTFjwCiisEUTQEGiFAoRQibaQmmaokgjFUYJREmMBHAClSABlyRQFAlQECCgRiSCJIEQEwoACSRElg0QEjBSFAgIOQLIuDCiRHHcFoIZp0zkCDCbBIkbFYnYFAQMQ1ELGSCYICDSBGhhBmAcoS0JQ0HBEGGUiIlTIkYaGGpJMJHLtCDAEDKBpgXUAgoSxQAjQm0EuUQjCBDcIkbKwkUUom0clomLKHETNpBioEBTpEDLEkocIzJiQI0JBAIaMQHaRCQbkW0KSHHgBGADoi0AFHHYFA3hgg0ayU1iloyIAEmQBJLLKC4JgQADhiGbmIiUggBcwCWDIiwByWCSEExaRC0ZkgALM0kTlZCJAnHUNEaYlJEEMU6JtAUAo0gRJ23kokkSxoREsjCSomBUyCFEAEpUJmkDkWVLloSSQkpjkm0AEQqZxFEIE4gjGCGTpkEhsEAUEyIZqEAjJg1BRlHBmCEJg4AZSGobNE5gMIWRRmTMtGBcgCVhpo2bwCDjFFLbAkJksHCZRAEKMVBjQi1jhkQQpg3EgmybBjDDqC3hRIBMoGHUpiHIMilQEgpQMA7QEClMBolUNihTAmDQAICTEm6IqEATCCEMOCoEEYwKN4maRDAjkSEJRmnIohALgAADBCoBhjFgJiIYkWmTQiHkKA4cImYLk3CSBIKUEA4gE2ibMkRjkkUKACyMRkYRoWQUl0wbmW2QBkkJR4AgR2iCJAYUMgpLKGwgKVHiBE4iBRALNYwbFwwUAGpQwAwDQSwSwQAQAi7REgrSIAlbkHEJyZAASWDMMm4YlSHiwFFIFkrbFI6IJJERJUhLlkXRyCAAk5GDoC2JyJGYQgkRRGkTJE2jRCzUGFEiF1DAghECNIJIgHAgQWlvzZh7vICP92WCMX3B8zbvb7tgGJ1FERU17RMAxgnav4gEW/oe9DFzrwvEKF4Ku25tc0FQgdmnvLQFYwpTQuDjTxsug4GZViD6JP0GvZpbvfRhSWIjeFVdQcspJ26wR3IaM4M8yRhim1xEfUf7HcopRHQ6bzJ0B7rhE60A1mouwYG8ekzSxQ4WPtqecHdT57vYaEjOqjM0g3vUKa8ybDzUUVJDXx/6pcww596LIBNHygVaBGdRyAhNYxzSg0Z9BuxN295I3WJLU13+yYsdgvMq/qoj0LVZPevCjMBLnGnBAGsXxpYmTZbiyE6v5vQO3xWB6So6vX+G82gl0T33gZEw0B0stRf76XAcHHNkQl5nz1ZdkCS2QGh8Or4nmnuatXYkfXSP8YWDFz7bgtISNta6w7iiluZOySkDb8unuWXa2lUiSbHOJJ1vJ3kxa/jOpQvKULjQ49VFJQpH+vVVZKRtXkvpkFnOmISVSx0rfus9NJCPpQm8S7DJH6pRA1ZgKYsLochGcs0pjWJGAZtUC9V0Bz7gz5XEWJzouDZZe7DfOagc/Ts7irQmpLMFuBeno9kzplKmYSDW1N88uO9CsCP4JOY/EKusbqzRu/032a0I9kozn8gyw3aAU6MArCVbfmr4/L+LV+MhLlnxe2RHy9iLw0SmVI2nJDNoLWichbLKJ7euagFMjqyw45WTmIYXKvX8rsl9TATOwcvL+0okzt8GuDyDmWej1UoGPPC74eyRfVVifPCPfb0M/o+QVwsNMggT11piJcEYmPS3hJWlTJ6t3WDIqwpvh9Bh2OBmNyJ0xMC3Zw3rNWVCLalzxf3RdOhINiSS91DtDP5FDqnZ8Br0HK5GCN00NPfWNt0FjNAWYuRoIBPqx471i+91mQAM7cRwP8izxj7D+wcGQMyQs/FA3ALXU62532rTt/eG90vPtTtj6Jvxcqx+l5oclJIZ/6qQjaqpzP6DIhlPa0e6FBiwRefdazXu2C5gPKtyY9YukXWftFnu3xDqRvxcYd/LBeK0utJYtERs4U2naS0W/8DMRrTTtiME4QZf8QSHnQoEjOS+ZNxb1yUUdmH0FKqeLgPNfXfVmD1B6ZTp/B02o3uRd7y9k4f5IKIPQedW4gdUIfycBP20lYmV5U1xcYVG6r/r1L1kfeCwlEsJ/3NsapVQx2JVuJ+EKBdqsx3zUHHSLnk3kRoZ4q0E5KRPccxgEGCpb2rK4W+hwvskcqfhKZQhYij4B10yzeno8FNIxT2vvXyALAxg2t4nSCVX7Wc1jv9ufEV3z1d5xzo5IDRHVkM1qT+V6zx+mkwXXksaVLiMNkeoy3/FF7uJxNcLajSwUwxht5LAzALa3LqlMyleIvK2fGWiqLaDkp1aYwvzc4i66sm42x2LHE6XwVVR/RnHj/1cg9rbcdVr1huGWA+TmLc0u01EYZrZnc0fGi9BnlYvm3JcEaNJ3f09cB/iN7pgMD/j8kzhykd0RsJgS5sU1ggAFkK4E9kt3WPrNqyIP1jdUZ30+Qnj6KL/bcTcvaxbC6Y1E0sIQgTSaQC9n3yhKawohtEjRDGnbqqltCw9qw6MRjTXWEPeju5YwRpN0DeVNB+3B8/sLeR7aR2tvbk7tyHvB9pW6WSInfmsGnTPqVChU7F0m/qYeP6PwjGK8TY69Pr0ziBh0JOLKYRVG2RwQnZGsGoLoXSHxZCV90Q5mIRagpGDBslvJTcxWtnUWT/ktFYkiFXHvW09hD/jqjzBRXSKOzfZnr5Xery2BIcmslYrSYbb38dY/3TmFL2k56R7nXS2uQEzhFJhT1OjOoOZ6hy6fGlNHhTXhiK0ZmF6AGb/Nw1nS0zW3HEa0wTJ5gnFUQrgkgon3NBtah5+dBsxNGn02O24vF4Lg8Va1Zj04igpuE/CctbUlJ5YKqqAj2SwL5hpBtNk8eV0srIFaFImaMcgzTJXt4tz5gOI3Ds3fkLjt3NBdLwMjw9VegdKHboCCYhVPzFY2lG++5LqJud37flp7Ikni17qpdUYO7khvsMLeUru6ouFqdV6fVdVywn2bW22Xs0DNNIfXGjnfhwhZ4AEvOqyFXmYHYqRYWOtBIxWu0aUtvtjcIi8gkDNsi0kY2Iuf6UFqwN7zqvuGYwsuC+n0UODwdi/48k1FWz/pOzqeaxo9O6AccKNEdDaXT4kwuJZsuvuKo0zv9IxDkVYoRB5Jx+vt58MtKGSxSpylWpJfw=="); + byte[] mldsa44_seed_only = Base64.decode("MDICAQAwCwYJYIZIAWUDBAMRBCAAAQIDBAUGBwgJCgsMDQ4PEAECAwQFBgcICQoLDA0ODw=="); + byte[] mldsa44_wrap_seed_only = Base64.decode("MDQCAQAwCwYJYIZIAWUDBAMRBCIEIAABAgMEBQYHCAkKCwwNDg8QAQIDBAUGBwgJCgsMDQ4P"); + byte[] mldsa44_expanded_only = Base64.decode("MIIKFAIBADALBglghkgBZQMEAxEEggoAw/FofbPea45APAHeQqNeZL4KcvMHr8V/inNsUbmYlE0vTZbckQVhHq8sQi2F3yC7B1/aLXIta1rImyPmzsYITzPH4Iz+3/ysH0n3TDx9HFKMp5WwuOX7ZRnNqS/RaiaYltSR0LBwyi5uPgGqw1Cb/mAsJkoJuGx31QGfc1KTMSQYAjEiqU0QJjHAlAyBtiRSxkGZIFFYGAYIIEXSSC4YE2rAooADOQoIQmwbKARSQiWBRExbOIkEQEVJIEQcEUCTxhEjQCahpJFLwDEIhIFamETJqDEbEWrKyCwBKWnCQECcNgYDtAQMMWwMQTFjwCiisEUTQEGiFAoRQibaQmmaokgjFUYJREmMBHAClSABlyRQFAlQECCgRiSCJIEQEwoACSRElg0QEjBSFAgIOQLIuDCiRHHcFoIZp0zkCDCbBIkbFYnYFAQMQ1ELGSCYICDSBGhhBmAcoS0JQ0HBEGGUiIlTIkYaGGpJMJHLtCDAEDKBpgXUAgoSxQAjQm0EuUQjCBDcIkbKwkUUom0clomLKHETNpBioEBTpEDLEkocIzJiQI0JBAIaMQHaRCQbkW0KSHHgBGADoi0AFHHYFA3hgg0ayU1iloyIAEmQBJLLKC4JgQADhiGbmIiUggBcwCWDIiwByWCSEExaRC0ZkgALM0kTlZCJAnHUNEaYlJEEMU6JtAUAo0gRJ23kokkSxoREsjCSomBUyCFEAEpUJmkDkWVLloSSQkpjkm0AEQqZxFEIE4gjGCGTpkEhsEAUEyIZqEAjJg1BRlHBmCEJg4AZSGobNE5gMIWRRmTMtGBcgCVhpo2bwCDjFFLbAkJksHCZRAEKMVBjQi1jhkQQpg3EgmybBjDDqC3hRIBMoGHUpiHIMilQEgpQMA7QEClMBolUNihTAmDQAICTEm6IqEATCCEMOCoEEYwKN4maRDAjkSEJRmnIohALgAADBCoBhjFgJiIYkWmTQiHkKA4cImYLk3CSBIKUEA4gE2ibMkRjkkUKACyMRkYRoWQUl0wbmW2QBkkJR4AgR2iCJAYUMgpLKGwgKVHiBE4iBRALNYwbFwwUAGpQwAwDQSwSwQAQAi7REgrSIAlbkHEJyZAASWDMMm4YlSHiwFFIFkrbFI6IJJERJUhLlkXRyCAAk5GDoC2JyJGYQgkRRGkTJE2jRCzUGFEiF1DAghECNIJIgHAgQWlvzZh7vICP92WCMX3B8zbvb7tgGJ1FERU17RMAxgnav4gEW/oe9DFzrwvEKF4Ku25tc0FQgdmnvLQFYwpTQuDjTxsug4GZViD6JP0GvZpbvfRhSWIjeFVdQcspJ26wR3IaM4M8yRhim1xEfUf7HcopRHQ6bzJ0B7rhE60A1mouwYG8ekzSxQ4WPtqecHdT57vYaEjOqjM0g3vUKa8ybDzUUVJDXx/6pcww596LIBNHygVaBGdRyAhNYxzSg0Z9BuxN295I3WJLU13+yYsdgvMq/qoj0LVZPevCjMBLnGnBAGsXxpYmTZbiyE6v5vQO3xWB6So6vX+G82gl0T33gZEw0B0stRf76XAcHHNkQl5nz1ZdkCS2QGh8Or4nmnuatXYkfXSP8YWDFz7bgtISNta6w7iiluZOySkDb8unuWXa2lUiSbHOJJ1vJ3kxa/jOpQvKULjQ49VFJQpH+vVVZKRtXkvpkFnOmISVSx0rfus9NJCPpQm8S7DJH6pRA1ZgKYsLochGcs0pjWJGAZtUC9V0Bz7gz5XEWJzouDZZe7DfOagc/Ts7irQmpLMFuBeno9kzplKmYSDW1N88uO9CsCP4JOY/EKusbqzRu/032a0I9kozn8gyw3aAU6MArCVbfmr4/L+LV+MhLlnxe2RHy9iLw0SmVI2nJDNoLWichbLKJ7euagFMjqyw45WTmIYXKvX8rsl9TATOwcvL+0okzt8GuDyDmWej1UoGPPC74eyRfVVifPCPfb0M/o+QVwsNMggT11piJcEYmPS3hJWlTJ6t3WDIqwpvh9Bh2OBmNyJ0xMC3Zw3rNWVCLalzxf3RdOhINiSS91DtDP5FDqnZ8Br0HK5GCN00NPfWNt0FjNAWYuRoIBPqx471i+91mQAM7cRwP8izxj7D+wcGQMyQs/FA3ALXU62532rTt/eG90vPtTtj6Jvxcqx+l5oclJIZ/6qQjaqpzP6DIhlPa0e6FBiwRefdazXu2C5gPKtyY9YukXWftFnu3xDqRvxcYd/LBeK0utJYtERs4U2naS0W/8DMRrTTtiME4QZf8QSHnQoEjOS+ZNxb1yUUdmH0FKqeLgPNfXfVmD1B6ZTp/B02o3uRd7y9k4f5IKIPQedW4gdUIfycBP20lYmV5U1xcYVG6r/r1L1kfeCwlEsJ/3NsapVQx2JVuJ+EKBdqsx3zUHHSLnk3kRoZ4q0E5KRPccxgEGCpb2rK4W+hwvskcqfhKZQhYij4B10yzeno8FNIxT2vvXyALAxg2t4nSCVX7Wc1jv9ufEV3z1d5xzo5IDRHVkM1qT+V6zx+mkwXXksaVLiMNkeoy3/FF7uJxNcLajSwUwxht5LAzALa3LqlMyleIvK2fGWiqLaDkp1aYwvzc4i66sm42x2LHE6XwVVR/RnHj/1cg9rbcdVr1huGWA+TmLc0u01EYZrZnc0fGi9BnlYvm3JcEaNJ3f09cB/iN7pgMD/j8kzhykd0RsJgS5sU1ggAFkK4E9kt3WPrNqyIP1jdUZ30+Qnj6KL/bcTcvaxbC6Y1E0sIQgTSaQC9n3yhKawohtEjRDGnbqqltCw9qw6MRjTXWEPeju5YwRpN0DeVNB+3B8/sLeR7aR2tvbk7tyHvB9pW6WSInfmsGnTPqVChU7F0m/qYeP6PwjGK8TY69Pr0ziBh0JOLKYRVG2RwQnZGsGoLoXSHxZCV90Q5mIRagpGDBslvJTcxWtnUWT/ktFYkiFXHvW09hD/jqjzBRXSKOzfZnr5Xery2BIcmslYrSYbb38dY/3TmFL2k56R7nXS2uQEzhFJhT1OjOoOZ6hy6fGlNHhTXhiK0ZmF6AGb/Nw1nS0zW3HEa0wTJ5gnFUQrgkgon3NBtah5+dBsxNGn02O24vF4Lg8Va1Zj04igpuE/CctbUlJ5YKqqAj2SwL5hpBtNk8eV0srIFaFImaMcgzTJXt4tz5gOI3Ds3fkLjt3NBdLwMjw9VegdKHboCCYhVPzFY2lG++5LqJud37flp7Ikni17qpdUYO7khvsMLeUru6ouFqdV6fVdVywn2bW22Xs0DNNIfXGjnfhwhZ4AEvOqyFXmYHYqRYWOtBIxWu0aUtvtjcIi8gkDNsi0kY2Iuf6UFqwN7zqvuGYwsuC+n0UODwdi/48k1FWz/pOzqeaxo9O6AccKNEdDaXT4kwuJZsuvuKo0zv9IxDkVYoRB5Jx+vt58MtKGSxSpylWpJfw=="); +// byte[] mldsa44_wrap_expanded_only = Base64.decode("MIIKGAIBADALBglghkgBZQMEAxEEggoEBIIKAMPxaH2z3muOQDwB3kKjXmS+CnLzB6/Ff4pzbFG5mJRNL02W3JEFYR6vLEIthd8guwdf2i1yLWtayJsj5s7GCE8zx+CM/t/8rB9J90w8fRxSjKeVsLjl+2UZzakv0WommJbUkdCwcMoubj4BqsNQm/5gLCZKCbhsd9UBn3NSkzEkGAIxIqlNECYxwJQMgbYkUsZBmSBRWBgGCCBF0kguGBNqwKKAAzkKCEJsGygEUkIlgURMWziJBEBFSSBEHBFAk8YRI0AmoaSRS8AxCISBWphEyagxGxFqysgsASlpwkBAnDYGA7QEDDFsDEExY8AoorBFE0BBohQKEUIm2kJpmqJIIxVGCURJjARwApUgAZckUBQJUBAgoEYkgiSBEBMKAAkkRJYNEBIwUhQICDkCyLgwokRx3BaCGadM5AgwmwSJGxWJ2BQEDENRCxkgmCAg0gRoYQZgHKEtCUNBwRBhlIiJUyJGGhhqSTCRy7QgwBAygaYF1AIKEsUAI0JtBLlEIwgQ3CJGysJFFKJtHJaJiyhxEzaQYqBAU6RAyxJKHCMyYkCNCQQCGjEB2kQkG5FtCkhx4ARgA6ItABRx2BQN4YINGslNYpaMiABJkASSyyguCYEAA4Yhm5iIlIIAXMAlgyIsAclgkhBMWkQtGZIACzNJE5WQiQJx1DRGmJSRBDFOibQFAKNIESdt5KJJEsaERLIwkqJgVMghRABKVCZpA5FlS5aEkkJKY5JtABEKmcRRCBOIIxghk6ZBIbBAFBMiGahAIyYNQUZRwZghCYOAGUhqGzROYDCFkUZkzLRgXIAlYaaNm8Ag4xRS2wJCZLBwmUQBCjFQY0ItY4ZEEKYNxIJsmwYww6gt4USATKBh1KYhyDIpUBIKUDAO0BApTAaJVDYoUwJg0ACAkxJuiKhAEwghDDgqBBGMCjeJmkQwI5EhCUZpyKIQC4AAAwQqAYYxYCYiGJFpk0Ih5CgOHCJmC5NwkgSClBAOIBNomzJEY5JFCgAsjEZGEaFkFJdMG5ltkAZJCUeAIEdogiQGFDIKSyhsIClR4gROIgUQCzWMGxcMFABqUMAMA0EsEsEAEAIu0RIK0iAJW5BxCcmQAElgzDJuGJUh4sBRSBZK2xSOiCSRESVIS5ZF0cggAJORg6AticiRmEIJEURpEyRNo0Qs1BhRIhdQwIIRAjSCSIBwIEFpb82Ye7yAj/dlgjF9wfM272+7YBidRREVNe0TAMYJ2r+IBFv6HvQxc68LxCheCrtubXNBUIHZp7y0BWMKU0Lg408bLoOBmVYg+iT9Br2aW730YUliI3hVXUHLKSdusEdyGjODPMkYYptcRH1H+x3KKUR0Om8ydAe64ROtANZqLsGBvHpM0sUOFj7annB3U+e72GhIzqozNIN71CmvMmw81FFSQ18f+qXMMOfeiyATR8oFWgRnUcgITWMc0oNGfQbsTdveSN1iS1Nd/smLHYLzKv6qI9C1WT3rwozAS5xpwQBrF8aWJk2W4shOr+b0Dt8VgekqOr1/hvNoJdE994GRMNAdLLUX++lwHBxzZEJeZ89WXZAktkBofDq+J5p7mrV2JH10j/GFgxc+24LSEjbWusO4opbmTskpA2/Lp7ll2tpVIkmxziSdbyd5MWv4zqULylC40OPVRSUKR/r1VWSkbV5L6ZBZzpiElUsdK37rPTSQj6UJvEuwyR+qUQNWYCmLC6HIRnLNKY1iRgGbVAvVdAc+4M+VxFic6Lg2WXuw3zmoHP07O4q0JqSzBbgXp6PZM6ZSpmEg1tTfPLjvQrAj+CTmPxCrrG6s0bv9N9mtCPZKM5/IMsN2gFOjAKwlW35q+Py/i1fjIS5Z8XtkR8vYi8NEplSNpyQzaC1onIWyyie3rmoBTI6ssOOVk5iGFyr1/K7JfUwEzsHLy/tKJM7fBrg8g5lno9VKBjzwu+HskX1VYnzwj329DP6PkFcLDTIIE9daYiXBGJj0t4SVpUyerd1gyKsKb4fQYdjgZjcidMTAt2cN6zVlQi2pc8X90XToSDYkkvdQ7Qz+RQ6p2fAa9ByuRgjdNDT31jbdBYzQFmLkaCAT6seO9YvvdZkADO3EcD/Is8Y+w/sHBkDMkLPxQNwC11Otud9q07f3hvdLz7U7Y+ib8XKsfpeaHJSSGf+qkI2qqcz+gyIZT2tHuhQYsEXn3Ws17tguYDyrcmPWLpF1n7RZ7t8Q6kb8XGHfywXitLrSWLREbOFNp2ktFv/AzEa007YjBOEGX/EEh50KBIzkvmTcW9clFHZh9BSqni4DzX131Zg9QemU6fwdNqN7kXe8vZOH+SCiD0HnVuIHVCH8nAT9tJWJleVNcXGFRuq/69S9ZH3gsJRLCf9zbGqVUMdiVbifhCgXarMd81Bx0i55N5EaGeKtBOSkT3HMYBBgqW9qyuFvocL7JHKn4SmUIWIo+AddMs3p6PBTSMU9r718gCwMYNreJ0glV+1nNY7/bnxFd89Xecc6OSA0R1ZDNak/les8fppMF15LGlS4jDZHqMt/xRe7icTXC2o0sFMMYbeSwMwC2ty6pTMpXiLytnxloqi2g5KdWmML83OIuurJuNsdixxOl8FVUf0Zx4/9XIPa23HVa9YbhlgPk5i3NLtNRGGa2Z3NHxovQZ5WL5tyXBGjSd39PXAf4je6YDA/4/JM4cpHdEbCYEubFNYIABZCuBPZLd1j6zasiD9Y3VGd9PkJ4+ii/23E3L2sWwumNRNLCEIE0mkAvZ98oSmsKIbRI0Qxp26qpbQsPasOjEY011hD3o7uWMEaTdA3lTQftwfP7C3ke2kdrb25O7ch7wfaVulkiJ35rBp0z6lQoVOxdJv6mHj+j8IxivE2OvT69M4gYdCTiymEVRtkcEJ2RrBqC6F0h8WQlfdEOZiEWoKRgwbJbyU3MVrZ1Fk/5LRWJIhVx71tPYQ/46o8wUV0ijs32Z6+V3q8tgSHJrJWK0mG29/HWP905hS9pOeke510trkBM4RSYU9TozqDmeocunxpTR4U14YitGZhegBm/zcNZ0tM1txxGtMEyeYJxVEK4JIKJ9zQbWoefnQbMTRp9NjtuLxeC4PFWtWY9OIoKbhPwnLW1JSeWCqqgI9ksC+YaQbTZPHldLKyBWhSJmjHIM0yV7eLc+YDiNw7N35C47dzQXS8DI8PVXoHSh26AgmIVT8xWNpRvvuS6ibnd+35aeyJJ4te6qXVGDu5Ib7DC3lK7uqLhanVen1XVcsJ9m1ttl7NAzTSH1xo534cIWeABLzqshV5mB2KkWFjrQSMVrtGlLb7Y3CIvIJAzbItJGNiLn+lBasDe86r7hmMLLgvp9FDg8HYv+PJNRVs/6Ts6nmsaPTugHHCjRHQ2l0+JMLiWbLr7iqNM7/SMQ5FWKEQeScfr7efDLShksUqcpVqSX8="); +// byte[] mldsa44_seed_with_pub_key = Base64.decode("MIIFVwIBATALBglghkgBZQMEAxEEIAABAgMEBQYHCAkKCwwNDg8QAQIDBAUGBwgJCgsMDQ4PgYIFIQDD8Wh9s95rjkA8Ad5Co15kvgpy8wevxX+Kc2xRuZiUTcEHWDP0MI8enUbboCTOE020U+28L6HkQZZ4JzkhORY54IkHcSKSRcKkiNkLdbm9jWKOEiQAWKuYJyQ3dcbNWa4ogK+E4LsT2jHguWA/rmSJ42Azys2/d+kIMTmmKt3Y2PyiWU5zzj/2TNOQUHaHuJhAmXAT7iCrcEz+6vCsH/dKQrcVjMjIfbibRyRMLZIrLhqXqV4vboYE/yu9jzNRUGQH5rmenF+wDtnvu7YNO/2hWYRZJKrbTgy+nuBEBAkCKorHWVaGJvmXcEPSodB+5cRIQ5+uCCswH1lJT00+SzKsCacs68iBFcte5TkAOwTzq7slL1lAptILPkzwAhNhqKGCVz4B+qRiB6CK8917el2ioTKPxyHBtgHTKPIEoIdRAgi0+uaVBPAQ21VUlYDcILBd0mAH/7rxXsIdfq5PmklvIVD0VNxeDmwIbQH0J/LNr9kKCfmHSAXgZ3Vh/DQa2eVukKv7PZiBGSCyBHukEFK+791XNCydlSNsJkvz+xvp5cEkAseNxGJoUigCW4a5r2FV37JD9FQE6PDeCrKSL428p8vMl4Vpp6I+G90JuVv7+c0ShDh9n/PdnF/hC3v9uHso/COKsYvaKN4CIo9pwiyrm44XLuDSoX+F8DcmmaLYcEqW+o06/mVz5+dTSSrWZgiXqkIkPFI44AgwC/21SI9piGtdXouzcjxmIrgg1n1utPGESQXE2xxd3AkYJtVnPpdvMoEv/MSN2OMl5LGeO0DhPD4rdRYkT1HnT1/dbb5QoKpWHBiUgxTb2xJGzljMMaFooPi9mQiUas1fSjGk/7gNKgfi88nR8HiAPm5me3NGfxcS3plrI1UewwB9ubOOBfAQiRYQI2w5ax12ygyiPSS8ekYLv1HD2TfpfdVzwIQhWYnYWDls6WhW+sJ15Al5QJ3kGe2fIQflEH6196P5Xo/4Kmv1A02jzeN3KSPb/KutI8HM4TXWAgsQX+7XmH+zzS3lXqdjRhhQ0RQ9HK4HFZ2OFw9/2KhsbR0vMIcsc0VB0zsx096ZIgMynAbyQ5rI3mFeKM7n+CD4m5KXMYSupfesNv9e8Of/FROnwR9It9N2BzQVcLWwiMuwYiqgchfUfmZFWcD2if5e23xuSt/t8hYReU/I2SydkhzTUNfwbELIkjcsxwWVkpYFIf7rT2i5Atkl6auBag5Eg/fjEuiR7RsFS1C/AcHx5lxqqbckZ/eXinG7kPDw9ZSpjHki4/PeKTeviCs4aOGtLC9kexDAU++k2cFQe7fqbUHST+eENU2m9HQ1/WfUt1426wDUdYZTqInnvk/PjUbkvE0RNbFzS+0w9Qsnh28YfLXRt/j+IcZhG4buivL2G0N/UqHtwWpyh3Wigic5tqpMaTZ54RN1/jJWmsQS3rvd8rHaZPk2CbH0Iss1PrcROzksogqZBQn4Y1zwDsF6yqdscqaMJXmH5+7REdQACUTCzU2Qj4x59doVByXnKY+Of8fAB1XTjurYgq8DrbKnzfUThC3zEodT/HTcLdP7gEIhPizDQYxNA6LlGUxGzpy7+iMs3j38WiSbToASbB1dCsFtR7Jp0P8qc9LJmX36CW87JON1pEVaTCth/HQS8AXUsGU7HSorD/CkCwehxKlABcRbpPTIZC/dtR9LkrkI5T9AyTWMDS2pPzICo+PUhOOkU3pSKS6o20VnvZtj2uU8M31K6I16H5KbqXMr"); + + KeyFactory kFact = KeyFactory.getInstance("ML-DSA", "BC"); + +// checkEncodeRecode(kFact, mldsa44_sequence); + checkEncodeRecode(kFact, mldsa44_seed_only); + checkEncodeRecode(kFact, mldsa44_wrap_seed_only); + checkEncodeRecode(kFact, mldsa44_expanded_only); +// checkEncodeRecode(kFact, mldsa44_wrap_expanded_only); +// checkEncodeRecode(kFact, mldsa44_seed_with_pub_key); + } + + private void checkEncodeRecode(KeyFactory kFact, byte[] encoding) + throws Exception + { + PrivateKey key = kFact.generatePrivate(new PKCS8EncodedKeySpec(encoding)); + + assertTrue(Arrays.areEqual(encoding, key.getEncoded())); + } + + public void testPublicKeyRecovery() throws Exception { @@ -256,6 +350,72 @@ private void doTestRestrictedSignature(String sigName, MLDSAParameterSpec spec, } } + /* + public void testMLDSA() + throws Exception + { + + KeyPairGenerator kpGen44 = KeyPairGenerator.getInstance("ML-DSA-44"); + KeyPair kp44 = kpGen44.generateKeyPair(); + KeyPairGenerator kpGen65 = KeyPairGenerator.getInstance("ML-DSA-65"); + KeyPair kp65 = kpGen65.generateKeyPair(); + KeyPairGenerator kpGen87 = KeyPairGenerator.getInstance("ML-DSA-87"); + KeyPair kp87 = kpGen87.generateKeyPair(); + + outputKeyPair("ml-dsa-44", kp44); + outputKeyPair("ml-dsa-65", kp65); + outputKeyPair("ml-dsa-87", kp87); + } + + private void outputKeyPair(String algorithm, KeyPair kp) + throws Exception + { + KeyFactory kFact = KeyFactory.getInstance("ML-DSA", "BC"); + + System.setProperty("seed", "true"); + System.setProperty("expanded", "true"); + FileWriter fWrt = new FileWriter("/tmp/ml-dsa-pems/" + algorithm + "-priv.pem"); + + PemWriter pWrt = new PemWriter(fWrt); + + pWrt.writeObject(new PemObject("PRIVATE KEY", kp.getPrivate().getEncoded())); + + pWrt.close(); + + PrivateKey priv = kFact.generatePrivate(new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded())); + + System.setProperty("seed", "true"); + System.setProperty("expanded", "false"); + fWrt = new FileWriter("/tmp/ml-dsa-pems/" + algorithm + "-seed-only-priv.pem"); + + pWrt = new PemWriter(fWrt); + + pWrt.writeObject(new PemObject("PRIVATE KEY", priv.getEncoded())); + + pWrt.close(); + + priv = kFact.generatePrivate(new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded())); + + System.setProperty("seed", "false"); + System.setProperty("expanded", "true"); + fWrt = new FileWriter("/tmp/ml-dsa-pems/" + algorithm + "-expanded-only-priv.pem"); + + pWrt = new PemWriter(fWrt); + + pWrt.writeObject(new PemObject("PRIVATE KEY", priv.getEncoded())); + + pWrt.close(); + + fWrt = new FileWriter("/tmp/ml-dsa-pems/" + algorithm + "-pub.pem"); + + pWrt = new PemWriter(fWrt); + + pWrt.writeObject(new PemObject("PUBLIC KEY", kp.getPublic().getEncoded())); + + pWrt.close(); + } + */ + public void testRestrictedKeyPairGen() throws Exception { @@ -319,60 +479,30 @@ public void testMLDSARandomSig() assertTrue(sig.verify(s)); } - public void testMLDSAKATSig() + public void testMLDSARandomMsgAndMuSig() throws Exception { - byte[] pubK = Hex.decode("dc7bc9a2e0b6dc66823ae4fbde971c0cfc46f9d96bbfbeebb3470ae0a5a0139fdd6a6ce5bc76e94faa9e9250abd4cee02cf1ee46a8e99ce12d7395781fa7519021273da3365519724efbe279add6c35f92c9d42b032832f1bf29ebbecd3ec87a3af3da33c611f7f35fa35acab174024f118979e23bf2fe069269a2ec45fbc1b9c1fb0e1f05486a6a833eb48adc2960641d9af6eb8b7381b1ec55d889f26b084ddfa1c9ed9b962d342694cede83825309d9db6bd6ba7582132534861e44a04388a694242411761d34e7c085d282b723c65948a2ac764d9702bd8ed7fe9931d7d8704a39e6508844f3f84843c305594fe6e5404e08f18ed039ac6563cbaa34b0ca38320299d6256ec0f78d421f088159d49dc439cbc539a55884a3eb4efc9cf190b42f713441cb97004245d41437a39b7b77fc602fbbfd619a42363714b265173cae68fd8a1b3ca2bd30ae60c53e5604577a4a3b1f1506e697c37432dbd883553aac8d382a3d250cf5b29e4d1be2cbcd531ff0e07e89c1f7dbc8d4529aeebe55b5ce4d0214bfdec69e080bd3ef36cca6a54933f1ef2f37867c0d38fd5865b87929115808c7e2595458e993bacc6c5a3b9f5025001e9b41447708bfbaa0462efa63876c42f769908b432f5485508a393224960551d77eadfaf4411cbc49fdff46f2f155ddd6ec30867905b709888ca0f30f935fb8d7f4803cfc7a5f7790ca181d99ca21f2621d69a5c6d49c76b4969da62740a378470332b30947ab31ccdb9ba0c7b625879eec4bd81f0200ba23504a7dc3b118bc2ab1145df13af3c8cc39f577873b84911b3d85fbbf4cb19e4d36b10a938eeb78b599dc86615fd6cec6eb7b8f7afa5f6d6be19ea81630d36ccfb2f487de50d0cf46da8d3fe3512812043c0e3ef2d7231fb0b0a35a0fb283be30a1247780f30ae0294e8b6f5897383edb895595f577524df54593cdf927b4967616ee3913e4d6b29b0dbd7c33a2a45e4ef1b1954ea5d91ce37efc1302e7ce02a97395565da2a5c5d3fdb0d87684e9b1c0ad07ec33df2dfad528e2ea0966d2a47dd5ee88e77d653c0d004fab0165f0757c4da40af327e7192536c79947a80a827aa2107dacfae3debfc8fad3d6e08076d938c510a276bdf6721a1f087cb169515028ad5ce27a1047abd92809934ca63b893f71f9a34a99c0fd30310c47e9aa37394d0ab73b254d3ca69d9c5549c9479aae24264ac5ea64d3fd821c3962ec77e709f9d30bc7b65a52e48c16e80603558caca1811411c3155d1f949fc9cf9aa9385a7199e99be77a66fad7eed91258de55b2c4c83f9a050adebea5f09758f40dac4a1c394ee8d687879150d26426895ab1938e14ae11b376254c91fc6130436996f8ed43bd27be20ec9067111c116ec94cc2b06cc91a13c5d10bbd7eecea4792f17b2b77631ef145e9fb41a83eaa11c2b72a48fb90fdbd88644c4edf8ab20dce3118364b276ac1237b36c8926e346aab5a111aa0bf341c518b7bff9e9dbb8bcb4728601b3760663e67650331e6fb54ac82fc414cb8ddfc160a25311ec5272de46217fef8b992ff89754fbee351f21bb90b6c97078b510c983350681266c8fed1f0583c5151e7b8fe3b7292319699687cc6b641fdbd689428543bc0fa1facc109de65b62784c2d985ab15d77d3af12af6d03e8d1859a553688584d75ef673a1de74093ee108c761fff32c217c231b0e2953daf521429264c0963bc8a5cdeddc617a7285b934ea51ddb5cdab23bcede86be36e001bc65c65e9a1c94baff4fab8eb5f8ed42ec377423633fe00049142467c47c5d58a7202c8e9104841c1f7f380145a6a0a828c570235e507ae5868a6062f722bb98ff6be"); - byte[] privK = Hex.decode("dc7bc9a2e0b6dc66823ae4fbde971c0cfc46f9d96bbfbeebb3470ae0a5a0139ff037b84e75537e0a1cf02a517acfe323ffffe11df72e4f38430e0e66a2654b2f2ef757da47649d9f63fa03f1bf6fe6bc7c62971a98a2bd9d36eb0ec43ad4e9d940df3bb5874f5c92192aa31e0535d3cf70950bba858d11a688eaf854f63ecfc520c50d624891434265d8b0680c03061040299a104082c0910c8508d1100d44a6509408292211125b90508a2688e1302dc4021280028ac302611820851237808a000ae2040421b4910bb80550a08051b2511c28428a3672a494504910201bb45161424424a75001328181942d62a850023449ca94200b296213156408924c48122100b605030208e0060200a311e1802021116483a62898029291480801083041066613200e5b360951400c53000aa08851944842e316704ab2089b92440025121b0309418209c2a0800b290a819851c4340da4424500a0105b048e603400138928a4422648002c90202d194068e2146d19278a083746e4146914006422c660d3a03013242844965014166da0284dcc462e94367100232e1c114909a2040131060a2172c2142ada000c5a260d13228a62c444e3142d013445980224d33841c0308121a621e348720b1984d2c89108b8690887714a2884d496451a9301ca2285da30859ac851dcc00820106060465262302aa224251044640b2842988011540692144251d236719bb4900b082890188e41c469e1a469032160e01409d3020c20c88c1cb23164086218476920228ccb8470089528029550533270013405888424541041d202881aa84ccac88181008d0392899ab809d9900c9a1290614065c9322d89860c123521cc4266c8360010062411028ea3b44d44023043a0285a002ed1980c4882658922441c010212907084226e12134d011902519064113364c91806c2c04589262908b63024308cda022e0c27250b367058162c5116420b4946c1208841246c99466a04434e18a86c821661922028639409c30211029520211782d43868003460c84688e0160000a32dc0a82824b640831464c81022a2086503234ac8122ea098418c2072cc308a62c665093408412682da429089328514967081226001176d5948428ab88d592051d80892e2c0889044700ac0245a020904218a59c45094441094140820460209270c441020dcc8209212015038250c456e4a1666223770dc808ca426412222441ba3618a343099844099c42952046d88146ccb242a7cd129a8d333115c62d033b6a8357cf7cd10268ab12f16fceb7975d0a28a6c4822213c9a772df084ad91a669e2040550fc5e8d0aeb10fab2375fc9625ef9cd48c19631997a1cb6455d2c6286c569c9637add0317ce990996b28e51c3f3f717fb5907bbdd53961ad3497f2c3c473cce170906ac4c624a89aa8fbe624d99385e9c9548bf05e8cafd47d2476e41b73001f813726499e88b2b3b6f596ca311657850346598994c40e34747161e4e76264deef2a3019389d1594c942301af47b7544c23ecda2df2dece81e487d8f3f58ea89cd811d7275807ff1b0369ba86470088c174a3099fdafbe5fbb4d158801053b2b435d54059e26dee76d10a7a372f06b0b88b985b32f52052387438be8dc8bc6ae7369e2da9aa5e2585f8de403d091ccb7f790d54ddb34c608b0876f2825e9113be20a2b85867a01bda53287ac780bcd8b606d2e6d7712c56ce0142d22fe6b786de544963e134fecedfafb83d763061d799096a59e30d4472e440ae1faaabdf42640ce69740ceb9cae1a9612c21931b74af3f780236123321b205b6efd6cbb134f4c73d63c0c13e660b59d5920bc33197c355853d8d1cddc7959f7bc500ac81d985016f5b89a0eec79b0d9364ead8e38577c2a6549f2d067cb09438fdb21220aec80f6e22a476f332a2a4a0b7acbeb9e078d2b5a92ae84c924f7cb19fc7df377beb6546af97aa985c747cd111a127a674b4c26d89c14485b82e3a498a12d05406febd6c4d4b8bc051ab2cb91224b078538374b794b7dd9ddf3ac2b4a671fb7b9cf5acb78622ae2709eb2db16943aa24a9c97a81077bc784d25c0ea5991d2de883798a1f0e78f3361ed6a10dded81b1d683658331534fd7c01bc0eb00dfc4c3c84f0693046ff806bb200dd7bd4c0e6abca3f2934b4814fc0e1f8be615a2dda7c8a8d06cf9ce8566b40f4a6543b25bacddc926863fc0fa2007d6d7bf6d18dc98df696bd0865bf0be4c492b8043a32def8e3595ba7da345252f38f95be10fd7fb899b498fa01b09de5d5608eabc44a721aa04c4ef1dcb86102ac5f5f79c9708dcf5c5e896edd8c2c7bde3fa83e6ffce22d66174e31657a0b6361585e669d3031952f08631ae1f16ff90b90d0aad3c6d7e1dd0a9c41ab00a6e1c4f96af9ac5b79fcf821ffc016cb059245fb78dbe6c633d965aaab5333be07195c4b74b18e4600ce783c0a914ef4281016e80a7c9aa92d0fd789879c5e6751125ecb154432311e41cebd4fab3a31e4d2ce22d0f8c67737bf8a0dd85fe1349d5079a4d5feb3fee9378ca47ae46cc58a3f02038cfd53c4cee9cc4270cebc3d115a39c831e8ed41c4dbe4051b51d7872ba0c2bb163e0085201188eaa624a6bea9400a3a1fcc355a57f15704e61fda55a5dbaea8448fa5cb2d377a07f58305ad107e844ab4806e5bf99c1f513ee1d0a2acc04549f0801742169a77971d0adbfbfe0dd2ee5d16bc461e35748d1f3f6f4598321e8c49e79e740f990359858d2729dde007fcb26fdda9aa6e2ec4bd736f2836e7e4c83440191c849f6a53c72a4f8f830d001ea3b18f3cb4a5bd3cf066032b4932cfd2e62a9b55723fa61c688c935518af6860cd649bfbf1bf5fdc1f36dcaefaa157438d1cc8d56a150161511df82631f5e88e773e4ce263f276b7b3678d4c6fc75311d411c0d01bfdb595bb70552838e1b86517c837d909e772b428599e1fe569f77ce61531fde6fd31cdce1bdee4ba467fcbfbb9feeaad99fef67d4906e036c73662ddce158d4e5d4635e5d366f79f31a19d1b3dc4a591b0df194bb06c18147f41d88d1a409becdfb67eb063d16312266fd51b521ba9115e2e5e2aeae6ec511cede13ed4132ffbe0273f6c7039b3874f058804a54809af60557a21d9b4b831d04156a7c22dcbcdfe14f62437f449cb5ef12bf4251d485496cd835c0c2bc58bd845963dfa76ecd68519c4bdaf110be7ab052876dc3407591568c956ea3bf107c90fd5853a292f59a8d4b58b5d3fddf29bdbeac36852e3c69766fe460176a801831292b8e88a74a01ecbbe09a7b4d74cfd7fd628841944d9d556dbd60c76f96f07dc53443805ee9aa09365de4fb8179252c6b099b5dd351fdefc23dbd8090596c5d208ffd2c5661d8e5612dd574fc69045c769a969e600d77cfe192f1d3ae911289355c585811491b0ccd73692ab158824ab9edf8ac8193f0b33e6138b72c6dcd5d344f807b3da92425037de5ea4eead1c795effaa145e2ecdd327606eb2609929b9474b2bb04653602555c068385e92f06f29ca613ce5b4404f01ab1805db0acaa890330d291f40692df382509302b6dc8668f2c8f2d3a44fd58dca26e9802794f73d25b3149e6d576441"); - byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - byte[] s = Hex.decode("237c7b8820733d2cf35345f8a851996061675570ce42923ee2cd437e41b4a9b391481f71ece9e0b64c584a73710d8d688a930ac0bf02abf57c6e4709e724a9e4178c629018bc0b73b37a087dd3e7ea8da65b1145bcfeed1a7c1223607eaf0aef04ab2b60d47460945c621a4f9356130bcb5e94f00c710d1cfe99c05ea0cf9e0779577f3671560316bf24ec9cf2572b13e9a50d5fbcca4ddce481f740db1d7e200268459629d66eb5a0b5603ad6468a4a04498d84df62ee394d6fc5a3a7b1ef9de0cebe88168e5d6f771efc1ea315e78b83cb2c0ef88f167ee170dffddb9acaa5df380af1f80353746b6a5530c9fde8458eec99b478dcc6673236b277c41cde9eba586b9808146ccfae6fd8bea1d0654f65cac7583ab7050711b1a322d8da6c6aad16608a9053a655580d66016fc9cefaa17fe0fed5080dbd4daa9692f96794243a2813677ad542e1e164efa9341bd0fdba956a1b4b594f1a70fb3c14aed1217b861dcb749a56b281205d7df5d472a08fb376955524dda1017bcc8be85768191d0e18570fa8f263bd592a8d5358cf7f6ac28e0c664776acf51b689cf2e96603cb7de14978cc56f00819a217b5ae5e3c083c487f5a23c07939737c9ed6b2a51e04f39ddc69da569b88054fc64769098056d83539759d0cc487a711125bf73de1f6671695f5633645534e6cb2d374645c3c9fd39c5347c4b82fb1a452fbb6137f3c470eb1fc7240a5c2a281a1dd45670807552bcc0d160a6775b6dfebbc68500eb76e1e96db1ca0f31413c96f87354ab7071c7786c9e67d0d6476282bd676af23feeb7127b7864daca72f994a85bd10f1f66ea1240882f9b62895f19c0aaad1cf35cda81b311993194d977337d9a10728a7f3d82c8d7fe35cd7047d233c8efe1d9b66b2828c9b582dc2e4605683ace6be76ba351b6d7a1db23a81854d17e9601e7dc69beaae6426ef307300508d204b433026e0534dd0f0123b06252524769f2f86771c8cf5ee82f0b3b3010828a300578871af9b6031f34342cb2d5ea4093c50b621b10248d0a32c1cd5684ca50b5f9886e2df6deca3213bd5cd79d63b5dc8266beb4d80beeed82c9ee801ed35c6a9f69947e806e791173b5b883e20192573e85e7003f99c5ab417e72f03563eb93b163f4c2300675e8c1ab9f80cf62c88b1876fd0bd4258e0e083da712e341fbbceef37d59e090f6eca0cb3e8e6b7fe1c7f35c3a9db958cd273fcc581b285e30e3c35714f01d2eda306a6e66d9609d4ae88248bf76a991acb8b833255aaafcb27498d009eff0aa5264e1874b17eb646dfce4707e8bfb946babfa4f7affe388c0656b9dc4a8bbc670e64d42676db5b3cd017ce6d52e2547d43745e66ed9b1ca2228594546b4c2c636f524edec65d9ade60a9fd3b2586af169ada64574d85594cbaac5f3827d3c4317e51722c497f09dcaa4b7c4f03bd4fef3ba847d38d252fccecd7e207830fe4d60733b49527b5d29e71d2b736a97d9d34475fb081d0bc8810507f672ae03232bc32a33c711a3f12826fe1801f40962061e3d3fdeb3368e91eab892cdac18f0e06a4312e67f445578dbeaf54f5c3cbdbae0ab2dd84525a32253b3720d83c9b3e50ecf0554c89d15bd352b0636b40b79d38fc5cca5e696c1ff0cd2f0934fb3eaadccc1b6d5fac5544b6fe5c6e0a317c4fcfff2b1f70718b7e4e7cf3db3bf1c002031ef50c049bdffc3b78358e0be20eb57ed41bae04cdd09091afefa457a8aebb3376370ee04a7f48d444b7f1170edab68e0b970e8fc2850976536ce3bb14586af06baeac171278a5e949e00af7cdb0d4b841244ccccc797ff3fd4187077d4c9d33873cab0bf6e690591b9021f80c52d47494051ac1ff75554b6b1907903dc530ec6b42d025f723d7d4e539222e683e47532541f25f14b0c007b093b7ccbfc0172e78e543517f632149d842821a2b414d0db9aac1398b5e99c269ef4e303e1373f9bcdf8211b55c65ec19f93a0422a7148cabd4c311f11a49efc757534d00cae3c84cb849e975193145538917f81225cc96457bc1a2ab8fa72afa8563dc314766ffd19a10db92dabf9a0656066728d384f598229fa94e906b8a3222b0dfe164afd9c116f31c315ee53ffb0b0d582ee0abfad259f1b4095c00a347673fd4e17ea7d8f974dbf2ed90311cb167d61aebea7b0b17a34f5b721fecafcfbc3feac7091b81851f8a5b051add8e724a503386a53b70d106d86a99813d579ef75a065cf70cc1ab9d80c39a01d3c5946049efed8d4e383b5ca65827a9cee08cba792a903347f7547a64745f8e17d71a0d40d71d15484b9a6814c86230aa05539e907cddda5efb3162c356f35829bc32a28bc80ec9454e5bfec24a6dd74675e3b913647f3d176a6773c1a0e40edd17ecd13aee3493710b1154f855f2591e62cc7073c608bbaa77104e8d4993b67cf81f65af89c8c91d695f7560daa68ad14160cb7df4e7a61b1860255320dbb813676df1285c015aec994d7bc0ce29751416b31ed15b69172968ddaa515692b8febccb4e3298e8bf169c20b965903b80f26f20a6a3bd5facd1bc38c6c817e23bf35187ff75f982ae9ed65a43f6199b61ae84683e1befcf9c0178b8ea2890f96a6e08d33d44c3ce50d9ccbd1cdf96df6b2f5e8f1c6cb04300f7f6d483108390aea8ed31b07b32c87c542ab475946d525e24c16b2d0afb86687e47cce7abb5b7fc41d6a9953a59a8b221d057b793845cfab414726b3753d87c020253fb93722263ceee93a66acf163c86eb7bd62136f70ec414b5562862f1202deeb9feaf7981416be2a09c0e7c1f18ee95314b54d0497bac2986d90e9ed3990220e96ae1622e11f2ee91c1b16128e7384a87fabc6731c7b0b00bb707fd1abe0392c95e4c435460b47d2199829b076b4ef6b11ad32825cad85794a674eefdd6173dca39dcbf397c1b9531380a72d142b7d4005d884fcbd59211827820fc5b2bc605e5c717c31e124cd1f57180d4ba598833f097056f809b71214fbee25f7fe7f14e3df8cb6bbf6c3f3de82885f71bfd874e6b7ad11db7210fd73c0ccbaa60f008a86a59a9860c0c851672da17b077d35977c52cf35bf06d450f3ec061977f627324c55aada361c6abb3de77e828a63aef6dc37cdf0caf3b98c3a409e3cdbdd2edd0dc4feb1a6ede8df7252cb658413f22728142304d7d02b06e438b10814f7731a489e79b6b8a6b0fca6b63fe9a61ff2994704bdff918e1ae6a99df07d3e18a216890465397b6eda5f47ad2f216817544b8840c6af1704d9a71a02c73b6a29fb6fb17787d97a8984790a34736050607093d3f557d9ba5afb8ced3d4dee1e8eef1f8fc0117474f558c96b2b4c2d6d9f8439198aac0cad2d3eaed0d1a243d44456486cfdce4e6f1000000000000000000000000000000000000000000000015222c39"); - byte[] seed = Hex.decode("7c9935a0b07694aa0c6d10e4db6b1add2fd81a25ccb148032dcd739936737f2d"); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-DSA", "BC"); - SecureRandom katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null); - - kpg.initialize(MLDSAParameterSpec.ml_dsa_44, katRandom); - - KeyPair kp = kpg.generateKeyPair(); - - SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded()); - - ASN1BitString pubSeq = pubInfo.getPublicKeyData(); - - assertTrue(Arrays.areEqual(pubSeq.getOctets(), pubK)); - - PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded()); - ASN1OctetString seq = privInfo.getPrivateKey(); - assertTrue(Arrays.areEqual(seq.getOctets(), seed)); - - Signature sig = Signature.getInstance("ML-DSA", "BC"); - - sig.initSign(kp.getPrivate()); - - sig.update(msg, 0, msg.length); - - byte[] genS = sig.sign(); + kpg.initialize(MLDSAParameterSpec.ml_dsa_44, new SecureRandom()); - assertTrue(Arrays.areEqual(s, genS)); + final KeyPair kp = kpg.generateKeyPair(); - sig = Signature.getInstance("ML-DSA", "BC"); + Signature sig = Signature.getInstance("ML-DSA-CALCULATE-MU", "BC"); - sig.initVerify(kp.getPublic()); + sig.initSign(kp.getPrivate(), new SecureRandom()); sig.update(msg, 0, msg.length); - assertTrue(sig.verify(s)); + byte[] mu = sig.sign(); - // check randomisation + sig = Signature.getInstance("ML-DSA-EXTERNAL-MU", "BC"); sig.initSign(kp.getPrivate(), new SecureRandom()); - sig.update(msg, 0, msg.length); - - genS = sig.sign(); + sig.update(mu, 0, mu.length); - assertFalse(Arrays.areEqual(s, genS)); + byte[] s = sig.sign(); sig = Signature.getInstance("ML-DSA", "BC"); @@ -381,102 +511,100 @@ public void testMLDSAKATSig() sig.update(msg, 0, msg.length); assertTrue(sig.verify(s)); - } - public void testMLDSAKATSigWithContext() - throws Exception - { - byte[] pubK = Hex.decode("dc7bc9a2e0b6dc66823ae4fbde971c0cfc46f9d96bbfbeebb3470ae0a5a0139fdd6a6ce5bc76e94faa9e9250abd4cee02cf1ee46a8e99ce12d7395781fa7519021273da3365519724efbe279add6c35f92c9d42b032832f1bf29ebbecd3ec87a3af3da33c611f7f35fa35acab174024f118979e23bf2fe069269a2ec45fbc1b9c1fb0e1f05486a6a833eb48adc2960641d9af6eb8b7381b1ec55d889f26b084ddfa1c9ed9b962d342694cede83825309d9db6bd6ba7582132534861e44a04388a694242411761d34e7c085d282b723c65948a2ac764d9702bd8ed7fe9931d7d8704a39e6508844f3f84843c305594fe6e5404e08f18ed039ac6563cbaa34b0ca38320299d6256ec0f78d421f088159d49dc439cbc539a55884a3eb4efc9cf190b42f713441cb97004245d41437a39b7b77fc602fbbfd619a42363714b265173cae68fd8a1b3ca2bd30ae60c53e5604577a4a3b1f1506e697c37432dbd883553aac8d382a3d250cf5b29e4d1be2cbcd531ff0e07e89c1f7dbc8d4529aeebe55b5ce4d0214bfdec69e080bd3ef36cca6a54933f1ef2f37867c0d38fd5865b87929115808c7e2595458e993bacc6c5a3b9f5025001e9b41447708bfbaa0462efa63876c42f769908b432f5485508a393224960551d77eadfaf4411cbc49fdff46f2f155ddd6ec30867905b709888ca0f30f935fb8d7f4803cfc7a5f7790ca181d99ca21f2621d69a5c6d49c76b4969da62740a378470332b30947ab31ccdb9ba0c7b625879eec4bd81f0200ba23504a7dc3b118bc2ab1145df13af3c8cc39f577873b84911b3d85fbbf4cb19e4d36b10a938eeb78b599dc86615fd6cec6eb7b8f7afa5f6d6be19ea81630d36ccfb2f487de50d0cf46da8d3fe3512812043c0e3ef2d7231fb0b0a35a0fb283be30a1247780f30ae0294e8b6f5897383edb895595f577524df54593cdf927b4967616ee3913e4d6b29b0dbd7c33a2a45e4ef1b1954ea5d91ce37efc1302e7ce02a97395565da2a5c5d3fdb0d87684e9b1c0ad07ec33df2dfad528e2ea0966d2a47dd5ee88e77d653c0d004fab0165f0757c4da40af327e7192536c79947a80a827aa2107dacfae3debfc8fad3d6e08076d938c510a276bdf6721a1f087cb169515028ad5ce27a1047abd92809934ca63b893f71f9a34a99c0fd30310c47e9aa37394d0ab73b254d3ca69d9c5549c9479aae24264ac5ea64d3fd821c3962ec77e709f9d30bc7b65a52e48c16e80603558caca1811411c3155d1f949fc9cf9aa9385a7199e99be77a66fad7eed91258de55b2c4c83f9a050adebea5f09758f40dac4a1c394ee8d687879150d26426895ab1938e14ae11b376254c91fc6130436996f8ed43bd27be20ec9067111c116ec94cc2b06cc91a13c5d10bbd7eecea4792f17b2b77631ef145e9fb41a83eaa11c2b72a48fb90fdbd88644c4edf8ab20dce3118364b276ac1237b36c8926e346aab5a111aa0bf341c518b7bff9e9dbb8bcb4728601b3760663e67650331e6fb54ac82fc414cb8ddfc160a25311ec5272de46217fef8b992ff89754fbee351f21bb90b6c97078b510c983350681266c8fed1f0583c5151e7b8fe3b7292319699687cc6b641fdbd689428543bc0fa1facc109de65b62784c2d985ab15d77d3af12af6d03e8d1859a553688584d75ef673a1de74093ee108c761fff32c217c231b0e2953daf521429264c0963bc8a5cdeddc617a7285b934ea51ddb5cdab23bcede86be36e001bc65c65e9a1c94baff4fab8eb5f8ed42ec377423633fe00049142467c47c5d58a7202c8e9104841c1f7f380145a6a0a828c570235e507ae5868a6062f722bb98ff6be"); - byte[] privK = Hex.decode("dc7bc9a2e0b6dc66823ae4fbde971c0cfc46f9d96bbfbeebb3470ae0a5a0139ff037b84e75537e0a1cf02a517acfe323ffffe11df72e4f38430e0e66a2654b2f2ef757da47649d9f63fa03f1bf6fe6bc7c62971a98a2bd9d36eb0ec43ad4e9d940df3bb5874f5c92192aa31e0535d3cf70950bba858d11a688eaf854f63ecfc520c50d624891434265d8b0680c03061040299a104082c0910c8508d1100d44a6509408292211125b90508a2688e1302dc4021280028ac302611820851237808a000ae2040421b4910bb80550a08051b2511c28428a3672a494504910201bb45161424424a75001328181942d62a850023449ca94200b296213156408924c48122100b605030208e0060200a311e1802021116483a62898029291480801083041066613200e5b360951400c53000aa08851944842e316704ab2089b92440025121b0309418209c2a0800b290a819851c4340da4424500a0105b048e603400138928a4422648002c90202d194068e2146d19278a083746e4146914006422c660d3a03013242844965014166da0284dcc462e94367100232e1c114909a2040131060a2172c2142ada000c5a260d13228a62c444e3142d013445980224d33841c0308121a621e348720b1984d2c89108b8690887714a2884d496451a9301ca2285da30859ac851dcc00820106060465262302aa224251044640b2842988011540692144251d236719bb4900b082890188e41c469e1a469032160e01409d3020c20c88c1cb23164086218476920228ccb8470089528029550533270013405888424541041d202881aa84ccac88181008d0392899ab809d9900c9a1290614065c9322d89860c123521cc4266c8360010062411028ea3b44d44023043a0285a002ed1980c4882658922441c010212907084226e12134d011902519064113364c91806c2c04589262908b63024308cda022e0c27250b367058162c5116420b4946c1208841246c99466a04434e18a86c821661922028639409c30211029520211782d43868003460c84688e0160000a32dc0a82824b640831464c81022a2086503234ac8122ea098418c2072cc308a62c665093408412682da429089328514967081226001176d5948428ab88d592051d80892e2c0889044700ac0245a020904218a59c45094441094140820460209270c441020dcc8209212015038250c456e4a1666223770dc808ca426412222441ba3618a343099844099c42952046d88146ccb242a7cd129a8d333115c62d033b6a8357cf7cd10268ab12f16fceb7975d0a28a6c4822213c9a772df084ad91a669e2040550fc5e8d0aeb10fab2375fc9625ef9cd48c19631997a1cb6455d2c6286c569c9637add0317ce990996b28e51c3f3f717fb5907bbdd53961ad3497f2c3c473cce170906ac4c624a89aa8fbe624d99385e9c9548bf05e8cafd47d2476e41b73001f813726499e88b2b3b6f596ca311657850346598994c40e34747161e4e76264deef2a3019389d1594c942301af47b7544c23ecda2df2dece81e487d8f3f58ea89cd811d7275807ff1b0369ba86470088c174a3099fdafbe5fbb4d158801053b2b435d54059e26dee76d10a7a372f06b0b88b985b32f52052387438be8dc8bc6ae7369e2da9aa5e2585f8de403d091ccb7f790d54ddb34c608b0876f2825e9113be20a2b85867a01bda53287ac780bcd8b606d2e6d7712c56ce0142d22fe6b786de544963e134fecedfafb83d763061d799096a59e30d4472e440ae1faaabdf42640ce69740ceb9cae1a9612c21931b74af3f780236123321b205b6efd6cbb134f4c73d63c0c13e660b59d5920bc33197c355853d8d1cddc7959f7bc500ac81d985016f5b89a0eec79b0d9364ead8e38577c2a6549f2d067cb09438fdb21220aec80f6e22a476f332a2a4a0b7acbeb9e078d2b5a92ae84c924f7cb19fc7df377beb6546af97aa985c747cd111a127a674b4c26d89c14485b82e3a498a12d05406febd6c4d4b8bc051ab2cb91224b078538374b794b7dd9ddf3ac2b4a671fb7b9cf5acb78622ae2709eb2db16943aa24a9c97a81077bc784d25c0ea5991d2de883798a1f0e78f3361ed6a10dded81b1d683658331534fd7c01bc0eb00dfc4c3c84f0693046ff806bb200dd7bd4c0e6abca3f2934b4814fc0e1f8be615a2dda7c8a8d06cf9ce8566b40f4a6543b25bacddc926863fc0fa2007d6d7bf6d18dc98df696bd0865bf0be4c492b8043a32def8e3595ba7da345252f38f95be10fd7fb899b498fa01b09de5d5608eabc44a721aa04c4ef1dcb86102ac5f5f79c9708dcf5c5e896edd8c2c7bde3fa83e6ffce22d66174e31657a0b6361585e669d3031952f08631ae1f16ff90b90d0aad3c6d7e1dd0a9c41ab00a6e1c4f96af9ac5b79fcf821ffc016cb059245fb78dbe6c633d965aaab5333be07195c4b74b18e4600ce783c0a914ef4281016e80a7c9aa92d0fd789879c5e6751125ecb154432311e41cebd4fab3a31e4d2ce22d0f8c67737bf8a0dd85fe1349d5079a4d5feb3fee9378ca47ae46cc58a3f02038cfd53c4cee9cc4270cebc3d115a39c831e8ed41c4dbe4051b51d7872ba0c2bb163e0085201188eaa624a6bea9400a3a1fcc355a57f15704e61fda55a5dbaea8448fa5cb2d377a07f58305ad107e844ab4806e5bf99c1f513ee1d0a2acc04549f0801742169a77971d0adbfbfe0dd2ee5d16bc461e35748d1f3f6f4598321e8c49e79e740f990359858d2729dde007fcb26fdda9aa6e2ec4bd736f2836e7e4c83440191c849f6a53c72a4f8f830d001ea3b18f3cb4a5bd3cf066032b4932cfd2e62a9b55723fa61c688c935518af6860cd649bfbf1bf5fdc1f36dcaefaa157438d1cc8d56a150161511df82631f5e88e773e4ce263f276b7b3678d4c6fc75311d411c0d01bfdb595bb70552838e1b86517c837d909e772b428599e1fe569f77ce61531fde6fd31cdce1bdee4ba467fcbfbb9feeaad99fef67d4906e036c73662ddce158d4e5d4635e5d366f79f31a19d1b3dc4a591b0df194bb06c18147f41d88d1a409becdfb67eb063d16312266fd51b521ba9115e2e5e2aeae6ec511cede13ed4132ffbe0273f6c7039b3874f058804a54809af60557a21d9b4b831d04156a7c22dcbcdfe14f62437f449cb5ef12bf4251d485496cd835c0c2bc58bd845963dfa76ecd68519c4bdaf110be7ab052876dc3407591568c956ea3bf107c90fd5853a292f59a8d4b58b5d3fddf29bdbeac36852e3c69766fe460176a801831292b8e88a74a01ecbbe09a7b4d74cfd7fd628841944d9d556dbd60c76f96f07dc53443805ee9aa09365de4fb8179252c6b099b5dd351fdefc23dbd8090596c5d208ffd2c5661d8e5612dd574fc69045c769a969e600d77cfe192f1d3ae911289355c585811491b0ccd73692ab158824ab9edf8ac8193f0b33e6138b72c6dcd5d344f807b3da92425037de5ea4eead1c795effaa145e2ecdd327606eb2609929b9474b2bb04653602555c068385e92f06f29ca613ce5b4404f01ab1805db0acaa890330d291f40692df382509302b6dc8668f2c8f2d3a44fd58dca26e9802794f73d25b3149e6d576441"); - byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - byte[] s = Hex.decode("098d5709482f9975b8c5c2e04f2dd8b54b4cf14fab51794948e88ab469656e1989a76c1a67bb93f8e8ae33f691773da3a86876c850e77ae2a4f58189f0f98d4fd5c748c9f760cd75f7c1912ad06df232c6ac38d49ceb8f648bfdd5998797812d8d2326cf5a07292a9c0d8fb87ae33cf85723c2e6383f1072d0c2b96aa4f00c981fb2e0c619344fa5ebb9761b8d2f2011639724b6a66cf502a9795da237776bc5da3a0ce35da57a2f36edf365d138c013582a21c8e4e26a43b259240c2af48504fa298ca816bfe1620dedfa72ea338da2a81e03b207bda413d2bbe38f9a4939f877bdfe2ed80261ea2293e4f9ad5fd8c5a94311d1564e18b58239de393750c5b2f7b579f47eb748a7c0635adc63a2396b4d1fda5071936eed5a3b3a3dbdd31eaf40ae09371ac7a910e056c0f84c1729cff8cc53f35aa68cbe97c4649e8d7c52381b3e1b5899c08bf758556149fb37bff2db4056741188036ae4e64190b843d213a090db1f0a338d0e9ace2b6b9caac158a6ba27092ff0ca082dc64aeaf748f2ae35597d184e7b5c03dcd2da11aff5ffe98f5075cc355d1214314ed256c637b762c54d038ca3f4a85d583f4bb68ea705a40481c35a0ae4de8c8ea7c417f2d1e1a101d6aec6aac87aef3dd4ace3a86a2b205ab9e98a9cf579f61c6a683820aa3c8b8eaa492800398f196e40300cc1e155d8e81344a07af407438a71c30bf4b936037312829020f4648899c9eff03f37d48373d462ce419e9dfe638437ea0e6871c4a78a93388000a759468eb8ad25bd60fa8363efe0ba826349598228402a286a1d7f95122b23cc051d325a539b5179afe1c0b049060d072ddc1635c4228ba13d768e704aadb5692e0eec1ffed5a9ea4ffbf45725b924afe2362bbf592d7b8ffcccb558374471ebd69ab9712c366b8f503e4aaf6ab9cb7c4124fa5767757f6b66bbbda7457e2bd35bc8927167e5520d81ff05d89e15891d6e8cf8b91cc8af0c02e2c82c93095504f61e8cb0e62dcde96c3ee0558921946cf7d20c9485e93269e9c44c6a6a8c5a266f1fe1610ae24a73897e05e69cfc1fef396e38d66119115dc6dd6d965eb053a5b6d7dbe8ae40b99f853ccdb7f569bf9b18d394abf2496bddd77801d4a9530c871c24b2b7a3ae4d335c7be3522aeeb7bb4ace52b7d213ccb086eb031aad103020413fb21b44dfabae7e1d95845dff10cd434c357b3b9f6f2a6c4e5c9c0f8d8490f31fe1faaa2f860c7f54453923e57d80ec26ebcacb3e79375ae7b0900f1f1eefe7bb491d079a0b561bb4a280ac1bc3daae702b2ca9e9cf7ff2804f5b98861d900f047d415e8911cd177cd691dfd079f6a439b4dfd407d3b3d78a33aa818f8948815c14e311d0fb6f32006863bd2a538177d1d9d9283ba7ec43932534900ab745cd54a6a115ee2786bfe1c3f8bb085f30c58cefceccb95f5d3388151df1af838e6711739d1a0d543b42e6d7948a5d8ce55fefd5ebe5d616cfa6d386c611f781b12d04eba65a3a57780b851daee6f038fe393d8bbdcd2d0bb706881d82ac55d0faa22e0c8756c676048f48fa8de39a2e8a5f1581ecc03045a3c90e1f5584a2db606c7d2ee0b724f7a84b0b21202b68729f4850da6723454536d43afce781198049f3dbbec600dbafa18fcbed25aef8095349595fe9ebdf75d951353b8cc6898a5bd4e7c0595920d9cdd1db426c694c119539a987888eaa9ca0767a3719eb967547636a24d1d8b0ae7006466b8b968476d7dd70fe5fd5c678bf37eff54da49f135db340448960d64bf097bc120660a27ca8d0f1fe28e9758ae7b171427a19bda0133a176c8d75b82b6b33f03a68013233ef124b8c56ac181f09563c5e07d445b383ddf275f3390ed27903bb1b58bee5d53b7fe871b8480e024caa1a2693681a8192ae992ba2578177dd9a9153d42d6fd1c952c840711d46e96ce4f0ec089d460347cef11cbee0eaabbeee8454552d404a3acf2d99c763ad9c000a4aa7e31cd61061741561ffd60b79c4a1881abe794db591de66837092ff93d4aa49deb083cdbd2b70de2edeb99b4f0b52dab10e5b5eab3e5bd12a8c1b042614266aa1bfe8511e7769a20510ed5e393144a9b72c0ec93a95f35d4f38a50253f3e244044ed24f69b149b5e7d887a5c2ca6c80e60aaef2667a63d49601e73ab9c5e2e09ca29aaf666719ff3b5ba32299749445e8e3f9563af2b95578f1995cf2814707e42640cd65f87518f1007aedc202cd401ba51efb0b1256ef43bdfc63d1bc46481c85ca1f1d938b5e0c802859efde08f3dfd27bee7d0f004b4abfd019165422f4b7fccd7ca4952850ca5c6c6079b8bed3bfc876923bb5e19dce7e672721486f496187d2928336c5f7ab6b4a32d7eb196b05795d55c8665645e9673c6f2a792a6f319cee59bf152a1482feb2ef325128bc8c22be9f47feb6693ff51c278a19d8256dfaa3b14ad4e299e8cda06bb9aa103a77c6062debaa42fab40d7b602343e74949d1f35c9fdfa0af0c86fcfc740e385e08bb30d37ad8d4d818bf4588fb0ef3cccf2133f7cd6501848f69e833d3988b9d627f693cb9ad4724427afa9efffd249fad1473074366e3e777ea67655264e1e3502b41ac628e0a6cc7577886b061643f2c61540497e04c81ec6db1bb33dfa53574b2e4a10c968b8d2d13dbe374159a189056ca052bd0cb8f95dac9aad2dc90b43831ea973b14fb642c4772005940fa5e41136660b588526684d7a62bfefb6d1549b5bedf3b262d5c27a85cd52f79c51e668c80a18ca543e4963a2970b7ddddd3297cabf1d51ed24fc3c55ee5c83dac281cfcef06a4e24fee98f0a84ed7ddbfaaccf2b2e7ef3abc0abd21fa2f0f24a494dd70d4b4ce685b31ca337393943a8db71011901d1061f08c56a672201b7726b158dca828ac9217629c66fac9adec98851412421d22caeadc7483c407566fcee45044e7aea3639fd0534c9d242d129dc4b0f1aa056f597bd3972852815d10bcdcd4149caf4eb8e29d61fda97a137b81d2d2800fd9a9cbcb2ab8d6351faf7d67e6385f98be98ea1f97fad8ba928338ccf0b249354991947b47b00196e51d6af3ec3d49b21e4b053147284e391d5beefcc92544752cff02fe03f5bf9276ed6b313d210aa55bfee3b2f72aed7eaaf03c7cb471b5f67d7fe13b8679e418807c8e82559489f3121268febe301b1361b929f8c3805e1f5909133ec381fecfc225ceb1c46ef9f2ab271900999a5ad596c79ce7f43e7d0ba82a177134c7b2e37c58e0fdc20a60055a4d0223320ffbed994cb26698722f8299f5600d069bab541819636ab6112a395152565b5e636e78858da6acb0b5b6cd373e45485b96a0b7bae1e8fc2d56658d98a1afb6b7b8d7dde8e9424c768a8e8fabc1d2e0e4f00000000000000000000000000000000000000000000000131f2d39"); - byte[] seed = Hex.decode("7c9935a0b07694aa0c6d10e4db6b1add2fd81a25ccb148032dcd739936737f2d"); + sig = Signature.getInstance("ML-DSA-EXTERNAL-MU", "BC"); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-DSA", "BC"); - SecureRandom katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null); - - kpg.initialize(MLDSAParameterSpec.ml_dsa_44, katRandom); - - KeyPair kp = kpg.generateKeyPair(); - - SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded()); - - ASN1BitString pubSeq = pubInfo.getPublicKeyData(); - - assertTrue(Arrays.areEqual(pubSeq.getOctets(), pubK)); - - PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded()); - ASN1OctetString seq = privInfo.getPrivateKey(); + sig.initVerify(kp.getPublic()); - assertTrue(Arrays.areEqual(seq.getOctets(), seed)); + sig.update(mu, 0, mu.length); - Signature sig = Signature.getInstance("ML-DSA", "BC"); + assertTrue(sig.verify(s)); - sig.initSign(kp.getPrivate()); + sig = Signature.getInstance("ML-DSA-CALCULATE-MU", "BC"); - sig.setParameter(new ContextParameterSpec(Strings.toByteArray("Hello, world!"))); + sig.initSign(new MLDSAProxyPrivateKey(kp.getPublic())); sig.update(msg, 0, msg.length); - byte[] genS = sig.sign(); - - assertTrue(Hex.toHexString(genS), Arrays.areEqual(s, genS)); - - sig = Signature.getInstance("ML-DSA", "BC"); - - sig.initVerify(kp.getPublic()); - - sig.setParameter(new ContextParameterSpec(Strings.toByteArray("Hello, world!"))); + byte[] mu2 = sig.sign(); - sig.update(msg, 0, msg.length); + assertTrue(Arrays.areEqual(mu, mu2)); + } - assertTrue(sig.verify(s)); + public void testMLDSAMuKatTest() + throws Exception + { + byte[] pk = Hex.decode("3BB5567D7049939D8A5911BBE1FEC62843DAD05447BFC37CEF917C431DD20B8EE32A985C4F681DB63186FCB455A9163559301728E6F03F9C915FBF48571CF7DC76B1D1373B1C57B1C479DCAF136EE893D04B8E8C3A86D28483E84CB6814A17DDE3FE4152B69ADFBFD40B1AF8D4CD66101070B9979E6EEEFD4ED21111D129FE959E39E8C00311EA624A54F3340FC6BE06A0A826A3E74DD4161FC9EEF6097562316E62BBAF4D482732BABBB1C5132B86C8D7D733DC9595DDB93EF6BF5D79A860885D3F3BE31908787587A99D84017D00E814E4F697F2688ADF3967AB05F61C0D0F02BD5B8C4EA51010103265F49F90F2D1D5DE55305B59CB3658146F1696F12EE25875136A234E35F10B7BE95FCCDAD326D9CEDCF64F7DA0E9F0697A9A04E4C7237CDFBAAFC6974DA04D158EA2CDC7A3F87CE0E5BE9DCD54ED84ABAFC6C9889C3427A904C2DFF70581E1BF0F544BC1954AAC852DFAB032D140AC94CACE5889DFD43BF9DB490CDF3342C15E4F88EC5F16B789828367A488CFAA6FED1E94322759EAAA211041444D10ACF8E1DF1EF840B68412603DA6BBC4FE69C8D2627C032A266475B1314119D843F54689300EAC933060D0A7106EDF58CC6B1F313B8FDE024C0179E7B67B08CC030B7B3BC610E9C2A60BFDEE54A1D5E0F53E8533456AEB4D0978DA9C7E904AC31B676222C9369D3FC74EDC8642C4F3C19E31B14F1E5EB3FCA413478E5B03DA9FB50755EECD2F0F513502232367A12A02A0B1B86C9FA8FD2990B8A7296818F9DA6E70228AC8BBC55A9374E1719BA180A29147CC1E379CF10FAFDF6FB0FFBB35CD033FBB6660042F9A61AEFBFBF6ECDBB146A3233644D5596AF68CE3C89BB77E75D60D2D044400374179483B3DC65FC029246A9C950D5AA4825C359B45EFB7B24E36C0A0B2592BD50F992484D170F4C3D77F8F7755D86FF1DE21332A7D1F70D069DAD0CFF4B4B3BBBC6A535C48E0262333AA87C22DD70D07610EA105D506BFCA77283B64C262F2A38FAAE68E96B9491A229B0A2FC6BF967F2C2DDDA1A8804F5B6E37C2AEFB768B33DC1D05B0E3C86BD4F799346101B2E44BCA78AF5CB50C8F57B104F054054CF2975DEFB661A8BE18BAA9296D3372B1460338F58E6B9CDCCF25CE371B3BF39E90E9B35037BE4F24BEA1ACF75A643ABD19E7D312DF45F27E04CD3D94E1569029F1EBB806E2617252263BD10EE898B90526675A42B90FB64F4C5B0F18B3446049B2F85BD1DD526E7AC5C41E3DF0F0920EAFAF804B808FF0E5B2E064BB39909AD39FB3BED06D1A97288A1D7F7B8EBBCD257869B736B87E18990E0E7DB4E2EB70FDE0B9B235DB741161C68F71E2C1AE9525AC68569D3AAD61584EE29EE5581C0F67439B9F1DE7EC65073929D08119A45B6C10028CC34132E57F8B969D4195095E891276822C83FA6AD3743B1F3597AE188A0324AF4C198995246338533123092A80F4B40D557B7AEF5CAA6C9F65B03E86A9D580370659F2BD76D1A79468BBE725E07CD67E0094CEB4D8CAC55C76B6AAE7C9DA8B7CD851679105B9934D8F8C5CE2F69124AC41EC8E8F4470AD4CCAA55C7F3533558D366D5A78410B4232927CAACA135166CD0792D9CDD595711633DADC81685939D1107AC085919534747095FD24026031480CC5E16BBA2A7083B0E94D3C67EF3901B30E1BF8645A96EC8DE67999E985EECD714603371C854F90F7545A45C455154E596BB9406769935022133B9195106AD5BB1BEDADF9BC05518E480832F6C961FF35F8B1C6D030CAE8CC9D47C8B573B6F8CD06510D9D9C33505EB9080089F41434E5695759B4641B2F06F33B4C8EAEA86116B7A45422FBB1E1FC0AF4C75CCFB94DEA99"); + byte[] mu = Hex.decode("ACFA27834894431BAA18EB0353DA5383BCFD8585E60F1A4382566E0D85E0519F67084AC615088A85074D901D8DBD36AE487B23281E1172F6C03C8CD31A4B683B"); + byte[] sig = Hex.decode("146E97D0704552E762FBF3B0387C255B381D84A1B98EACAF572E71EB0317133758BBF3631CA6C3412238327AEA511432CCF868841BC7F71E484DDB8158E20687AFA3381DC14B96E045036AF004955CF7C9BC9DBCDD3EE558C73E9E16AAD91603E0D839294684B358559F0B2278B5ABB6224395E02849CD7E4DC52805058809674D9CC79744A25436AFBBEB77784F6F85ABF315E963794270C763128F5EDB8E390E0CD2328B868FF6AEE3BC1DE73DC66DBD9D967E9BD1E0E96008C8678C5C28ED73349C297E86DEFC00653E97D873DD6443E4164A0D5231E8C9EFB4EA2F068FECA57BDAEA4A7989C96ED307A578013F705073E875B045CDDF8D131DC6A72DD4EB63495C0DDF53706EB43E44B7B4FAD7C835CB6E9C0D771894A11289A43D3454E4FC8301C9CEC180EAD4B763D332E4760CFE2DDCA5893D0190E6BB7E36E9B596AE714B5B30C65BA0B0675595BDED190BCEA2450063BA157E4CE7DAC45F66FC270BB0608C82196F5EAC4B53C5E2F8C59C3D18222428F935EB3F4E54C1FE7DE4BFDE305C2AFC36C91894387DDDC957C4D2737E9FCDE5C7CAE453A4C45D4FE10A811C78179D6DDB4E33F5E374245EBC3D3DEA4351C8F55E10CD0F79B70010E897BD3F376F7693937F2DF58A7BAB9A0AF5595E3383C426DEC394EBE410C026A2F3E6B2E8200BDAAF15F33DFA4ADEBD59F386AE6C8F097E1183CA9577FFC008C710705DC73A87B6EDBACC23CC8C4FE652916CF8DDFFBACB92EF6BAA668E5772A0A06A2F4DE1F307ABDF6A028BE7F82ECECDA72A411CFBF377B1B3B2AB731563611F8BC933478913A8C1FFF1BB7C76F7B6E55125A41A4FC12C306349546AEA527FA24C0815AAAF8AA3E5367654A6B2BBC886804F25A57E64EAFC0E1D3F805979500A7EF16AE8F0A6E13A3DB3B72A9A91B9D11D9C1A19A0300663C7E931A4AD5EB503EE6F4F7264B66C43C98AB26A5DC42BEFEBC5CAEDC08F7B328C5556B904AA173867737AB3EAEA09722680DF5CB5EF3A1C0D549731EF800D0C72AE8D90BD6C21BB4F4F0E2F4147181C4054F29EAB4A0AFCA49E7406C1A711F38659A638646E5CB3C142747EF843F6517A905F70BD93818816641A45C894E2D44E6CAB7DA0524C9998AF62EF0047CE1A7C5EDD490938402FB1B7015273FBDEB85E536946F0AB7051062536ACD21BAD2311E4A45AF17714426645293EF0D6266DB59692DD99286ABA0C9C77581ECE32CC4C7FBFABA55D719E35E68FC0A6C7031F999BB08153C2501FD61BEA99198DEF0C514A6A1A8FF6E5D9411BC0B7BD2B66E364AF51D007F49DC9E2A756396B1842BF6FCDDF0A2F9E8AF485AB8AF4653FB1F9570E99633DD4914624177CF3D2027053B0BA0D60FBCFEF92EAD69494C56D2717C427666AA313884FAC83BC42DAF224826E127F4B33A6340DEB52942E2792D90023FEBFC935E5B18C6EC8B2A6861C3F2C929A3FFA38C2DD23A97EBAA2CC694199BE95E93BDA5C4CBD13712D03A0C3CDC1F0A1C9B64A88F0E752A167F8F093077CA73B538A8738EA7F2B878A29FAA7D42266FCE8CF16A9BB413FD50FCF6057F77E16C916704AE7622AF72D666AD06C2596E9CE3A297786C134A430441958484EB058C8DB19D1A6E788336D67D52E877CEB4C9F204E4D995FE2685AAB6EEFCFA6D0FD1D61B0C8F532953B32642A34657BFBAD90B8F0C85A821054770C6A2E27D8CE315618DB82EA24A1D486C12934EBC9133F38B72481748B8C9D432A3D1E1AF85DEFB2BEE0C155006BE17E879811E2FE08A337D54A03E5884384000DE817A3D9BBE94941A52A58ECE851F605B9F69E1C3112CFF92AB332D6E694A65EFD58ED61F57F84947A75A5C9776A9A7FD187C5015425ED708DC242CDAA30BEE759BBD9CBB046DF3F4D54F481208216AF5CA7892150DD9829A3AB540BBFCFC2E303E9205ABB4D65D7287B5BBCC85F8987AD7B182058E36DA5C37FE5658138ED49D65B11B67360A1FEE9E44D2D2C3164BEF63B426DB495540B383AAE5F54283F91B1E543F7F965289CB9F64928E6AC208D9791DE234ABA43FC2B44D89317277136F791C782A773340998C526015C0415211676F53BDCE809974D6450E39CA2C814F644D75CB4F349D28EDF08B1CE58616D16816B4C021C5F16CCD5FB539BEFA6C9F03704FFE1010589350C20AE319545B0E39AE7CAA7FCED9A3D2151ACF6CBAB5FBB0D0E83313A45E6209046BF1A89D5F808969CC62167B014E969EAD6B2088B7738FAB3D277D1CDD6F4C6816B847AD1D30083F77564CABEB55CB4A8BB8C6BD47A59B6772DCCC8431A01C04184965B8F25BF8333281AC7686852FAFD77B374E76D8839CFE1F594E212531325F0CD6F8C2853194B4D668F843776F0E563E00CBBE6F5D6EBE4EBC11A5F70D3872F669939BD4A21A26FCD836DB79EC271CB463A521264DD62CD0A664B1EF3D7B4C84793F2B9C36369BEB651858CA9D5DCA23D6F8137C6C1F96FEE19DD3A4CD08A4FD4CD579F0F994E302A62F37121189B2A61E8591A98E0396766047B77E8D4533E62891B77AD0F7607DC0AF1D7D327E8E7B45991A508B5B22FD3398BEA7F80966EBEF5A1ACF9F5FCCF9C0C6E61A05DBB583EB048CAA41C28E87530820D21E90BFD2CFF29C8FEC2F7F1FC90605F2C84553A709CB9F53C1BDF12DC20524E76870ACB7624AD238B5BB8EEC8D5D37F02F12D1DF2384E7EC70CFDCC25831305682080326E702795ABFC6DF60BE923AB245887A35EB5EC00B7A109F86A8F7DCF2E59DBD8C4C9D645588F4D25C768F499C3FA65C98FEB48B07A4B01C7AF8AF28ADBC5C487A5C1FB059EF91B3A77C8321126978B5EAD648BB96C6210C6EF505B6E40098E415E0324D1CCD0A5B0560455BA894AD84CFA8E9B37706EFC23B00513BA3D6DF77D38E203AAD4E718286BE73A729C7CB2CB2EEC65726EA48E657DA31A548972B21642C01512421A21E2A4151A995CDC2DA9A7602E747CB62C893D555BA4455ACD880282459257622B370F3AEE7C99C2D8CD31050E6F1050340EB287BE92133C2479F07780ED355CC124FBDD2C7ADC2A129DA3A99C964F1BB32B5609C36ABB69AFABC0F1445362DFBE2A381C3D88973EDFF9D98ECD0E5EDA94D394B784ABC97470283FBB87403A5DCD4BCF55F24F4368BDE39E63E3C906FD2EA6C4103EF571FCD269700472C761B2E2C52F9F10C195C7947AE378B40724499C8EB3AE5ED4B3B06DCE02F29424662BF209AA14D39C1EEC5E3E5DE7B7CADFD1D8ED9D0AA552FF54353F0E9BD1CD02965A47D83F1359BE6FE0C0144BC0EA8BD2C37CAB4DFBEEB31833F4146316023C4D556C7C8093C3CAD4E7040B122B375963767893A9B4DEE5EDEEFAFC0409121A326F7072A2ACD5DCEEF1F2F4FD051E26373B3F464B97999A9B9FA4ABC9E2FDFE00000000000000000000000000000C1E2F42"); - // check randomisation + KeyFactory keyFactory = KeyFactory.getInstance("ML-DSA-44", "BC"); - sig.initSign(kp.getPrivate(), new SecureRandom()); + SubjectPublicKeyInfo mlDsaInfo = new SubjectPublicKeyInfo(new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_44), pk); - sig.setParameter(new ContextParameterSpec(Strings.toByteArray("Hello, world!"))); + Signature sigImpl = Signature.getInstance("ML-DSA-EXTERNAL-MU", "BC"); - sig.update(msg, 0, msg.length); + sigImpl.initVerify(keyFactory.generatePublic(new X509EncodedKeySpec(mlDsaInfo.getEncoded()))); - genS = sig.sign(); + sigImpl.update(mu, 0, mu.length); - AlgorithmParameters sp = sig.getParameters(); + assertTrue(sigImpl.verify(sig)); + } - ContextParameterSpec sspec = sp.getParameterSpec(ContextParameterSpec.class); + public void testMLDSAMuExceptionTest() + throws Exception + { + // mu shortened by 1 byte + byte[] mu = Hex.decode("FA27834894431BAA18EB0353DA5383BCFD8585E60F1A4382566E0D85E0519F67084AC615088A85074D901D8DBD36AE487B23281E1172F6C03C8CD31A4B683B"); + byte[] sig = Hex.decode("146E97D0704552E762FBF3B0387C255B381D84A1B98EACAF572E71EB0317133758BBF3631CA6C3412238327AEA511432CCF868841BC7F71E484DDB8158E20687AFA3381DC14B96E045036AF004955CF7C9BC9DBCDD3EE558C73E9E16AAD91603E0D839294684B358559F0B2278B5ABB6224395E02849CD7E4DC52805058809674D9CC79744A25436AFBBEB77784F6F85ABF315E963794270C763128F5EDB8E390E0CD2328B868FF6AEE3BC1DE73DC66DBD9D967E9BD1E0E96008C8678C5C28ED73349C297E86DEFC00653E97D873DD6443E4164A0D5231E8C9EFB4EA2F068FECA57BDAEA4A7989C96ED307A578013F705073E875B045CDDF8D131DC6A72DD4EB63495C0DDF53706EB43E44B7B4FAD7C835CB6E9C0D771894A11289A43D3454E4FC8301C9CEC180EAD4B763D332E4760CFE2DDCA5893D0190E6BB7E36E9B596AE714B5B30C65BA0B0675595BDED190BCEA2450063BA157E4CE7DAC45F66FC270BB0608C82196F5EAC4B53C5E2F8C59C3D18222428F935EB3F4E54C1FE7DE4BFDE305C2AFC36C91894387DDDC957C4D2737E9FCDE5C7CAE453A4C45D4FE10A811C78179D6DDB4E33F5E374245EBC3D3DEA4351C8F55E10CD0F79B70010E897BD3F376F7693937F2DF58A7BAB9A0AF5595E3383C426DEC394EBE410C026A2F3E6B2E8200BDAAF15F33DFA4ADEBD59F386AE6C8F097E1183CA9577FFC008C710705DC73A87B6EDBACC23CC8C4FE652916CF8DDFFBACB92EF6BAA668E5772A0A06A2F4DE1F307ABDF6A028BE7F82ECECDA72A411CFBF377B1B3B2AB731563611F8BC933478913A8C1FFF1BB7C76F7B6E55125A41A4FC12C306349546AEA527FA24C0815AAAF8AA3E5367654A6B2BBC886804F25A57E64EAFC0E1D3F805979500A7EF16AE8F0A6E13A3DB3B72A9A91B9D11D9C1A19A0300663C7E931A4AD5EB503EE6F4F7264B66C43C98AB26A5DC42BEFEBC5CAEDC08F7B328C5556B904AA173867737AB3EAEA09722680DF5CB5EF3A1C0D549731EF800D0C72AE8D90BD6C21BB4F4F0E2F4147181C4054F29EAB4A0AFCA49E7406C1A711F38659A638646E5CB3C142747EF843F6517A905F70BD93818816641A45C894E2D44E6CAB7DA0524C9998AF62EF0047CE1A7C5EDD490938402FB1B7015273FBDEB85E536946F0AB7051062536ACD21BAD2311E4A45AF17714426645293EF0D6266DB59692DD99286ABA0C9C77581ECE32CC4C7FBFABA55D719E35E68FC0A6C7031F999BB08153C2501FD61BEA99198DEF0C514A6A1A8FF6E5D9411BC0B7BD2B66E364AF51D007F49DC9E2A756396B1842BF6FCDDF0A2F9E8AF485AB8AF4653FB1F9570E99633DD4914624177CF3D2027053B0BA0D60FBCFEF92EAD69494C56D2717C427666AA313884FAC83BC42DAF224826E127F4B33A6340DEB52942E2792D90023FEBFC935E5B18C6EC8B2A6861C3F2C929A3FFA38C2DD23A97EBAA2CC694199BE95E93BDA5C4CBD13712D03A0C3CDC1F0A1C9B64A88F0E752A167F8F093077CA73B538A8738EA7F2B878A29FAA7D42266FCE8CF16A9BB413FD50FCF6057F77E16C916704AE7622AF72D666AD06C2596E9CE3A297786C134A430441958484EB058C8DB19D1A6E788336D67D52E877CEB4C9F204E4D995FE2685AAB6EEFCFA6D0FD1D61B0C8F532953B32642A34657BFBAD90B8F0C85A821054770C6A2E27D8CE315618DB82EA24A1D486C12934EBC9133F38B72481748B8C9D432A3D1E1AF85DEFB2BEE0C155006BE17E879811E2FE08A337D54A03E5884384000DE817A3D9BBE94941A52A58ECE851F605B9F69E1C3112CFF92AB332D6E694A65EFD58ED61F57F84947A75A5C9776A9A7FD187C5015425ED708DC242CDAA30BEE759BBD9CBB046DF3F4D54F481208216AF5CA7892150DD9829A3AB540BBFCFC2E303E9205ABB4D65D7287B5BBCC85F8987AD7B182058E36DA5C37FE5658138ED49D65B11B67360A1FEE9E44D2D2C3164BEF63B426DB495540B383AAE5F54283F91B1E543F7F965289CB9F64928E6AC208D9791DE234ABA43FC2B44D89317277136F791C782A773340998C526015C0415211676F53BDCE809974D6450E39CA2C814F644D75CB4F349D28EDF08B1CE58616D16816B4C021C5F16CCD5FB539BEFA6C9F03704FFE1010589350C20AE319545B0E39AE7CAA7FCED9A3D2151ACF6CBAB5FBB0D0E83313A45E6209046BF1A89D5F808969CC62167B014E969EAD6B2088B7738FAB3D277D1CDD6F4C6816B847AD1D30083F77564CABEB55CB4A8BB8C6BD47A59B6772DCCC8431A01C04184965B8F25BF8333281AC7686852FAFD77B374E76D8839CFE1F594E212531325F0CD6F8C2853194B4D668F843776F0E563E00CBBE6F5D6EBE4EBC11A5F70D3872F669939BD4A21A26FCD836DB79EC271CB463A521264DD62CD0A664B1EF3D7B4C84793F2B9C36369BEB651858CA9D5DCA23D6F8137C6C1F96FEE19DD3A4CD08A4FD4CD579F0F994E302A62F37121189B2A61E8591A98E0396766047B77E8D4533E62891B77AD0F7607DC0AF1D7D327E8E7B45991A508B5B22FD3398BEA7F80966EBEF5A1ACF9F5FCCF9C0C6E61A05DBB583EB048CAA41C28E87530820D21E90BFD2CFF29C8FEC2F7F1FC90605F2C84553A709CB9F53C1BDF12DC20524E76870ACB7624AD238B5BB8EEC8D5D37F02F12D1DF2384E7EC70CFDCC25831305682080326E702795ABFC6DF60BE923AB245887A35EB5EC00B7A109F86A8F7DCF2E59DBD8C4C9D645588F4D25C768F499C3FA65C98FEB48B07A4B01C7AF8AF28ADBC5C487A5C1FB059EF91B3A77C8321126978B5EAD648BB96C6210C6EF505B6E40098E415E0324D1CCD0A5B0560455BA894AD84CFA8E9B37706EFC23B00513BA3D6DF77D38E203AAD4E718286BE73A729C7CB2CB2EEC65726EA48E657DA31A548972B21642C01512421A21E2A4151A995CDC2DA9A7602E747CB62C893D555BA4455ACD880282459257622B370F3AEE7C99C2D8CD31050E6F1050340EB287BE92133C2479F07780ED355CC124FBDD2C7ADC2A129DA3A99C964F1BB32B5609C36ABB69AFABC0F1445362DFBE2A381C3D88973EDFF9D98ECD0E5EDA94D394B784ABC97470283FBB87403A5DCD4BCF55F24F4368BDE39E63E3C906FD2EA6C4103EF571FCD269700472C761B2E2C52F9F10C195C7947AE378B40724499C8EB3AE5ED4B3B06DCE02F29424662BF209AA14D39C1EEC5E3E5DE7B7CADFD1D8ED9D0AA552FF54353F0E9BD1CD02965A47D83F1359BE6FE0C0144BC0EA8BD2C37CAB4DFBEEB31833F4146316023C4D556C7C8093C3CAD4E7040B122B375963767893A9B4DEE5EDEEFAFC0409121A326F7072A2ACD5DCEEF1F2F4FD051E26373B3F464B97999A9B9FA4ABC9E2FDFE00000000000000000000000000000C1E2F42"); - assertTrue(Arrays.areEqual(Strings.toByteArray("Hello, world!"), sspec.getContext())); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-DSA", "BC"); - assertFalse(Arrays.areEqual(s, genS)); + kpg.initialize(MLDSAParameterSpec.ml_dsa_44, new SecureRandom()); - sig = Signature.getInstance("ML-DSA", "BC"); + final KeyPair kp = kpg.generateKeyPair(); - sig.initVerify(kp.getPublic()); + Signature sigImpl = Signature.getInstance("ML-DSA-EXTERNAL-MU", "BC"); - sig.setParameter(new ContextParameterSpec(Strings.toByteArray("Hello, world!"))); + sigImpl.initVerify(kp.getPublic()); - sig.update(msg, 0, msg.length); + sigImpl.update(mu, 0, mu.length); + try + { + sigImpl.verify(sig); + fail("no exception"); + } + catch (SignatureException e) + { + assertEquals("mu value must be 64 bytes", e.getMessage()); + } - assertTrue(sig.verify(genS)); + sigImpl.initSign(kp.getPrivate()); - AlgorithmParameters vp = sig.getParameters(); + sigImpl.update(mu, 0, mu.length); - ContextParameterSpec vspec = vp.getParameterSpec(ContextParameterSpec.class); + try + { + sigImpl.sign(); + fail("no exception"); + } + catch (Exception e) + { + assertEquals("mu value must be 64 bytes", e.getMessage()); + } - assertTrue(Arrays.areEqual(Strings.toByteArray("Hello, world!"), vspec.getContext())); } - public void testHashMLDSAKATSig() + public void testMLDSAKATSig() throws Exception { byte[] pubK = Hex.decode("dc7bc9a2e0b6dc66823ae4fbde971c0cfc46f9d96bbfbeebb3470ae0a5a0139fdd6a6ce5bc76e94faa9e9250abd4cee02cf1ee46a8e99ce12d7395781fa7519021273da3365519724efbe279add6c35f92c9d42b032832f1bf29ebbecd3ec87a3af3da33c611f7f35fa35acab174024f118979e23bf2fe069269a2ec45fbc1b9c1fb0e1f05486a6a833eb48adc2960641d9af6eb8b7381b1ec55d889f26b084ddfa1c9ed9b962d342694cede83825309d9db6bd6ba7582132534861e44a04388a694242411761d34e7c085d282b723c65948a2ac764d9702bd8ed7fe9931d7d8704a39e6508844f3f84843c305594fe6e5404e08f18ed039ac6563cbaa34b0ca38320299d6256ec0f78d421f088159d49dc439cbc539a55884a3eb4efc9cf190b42f713441cb97004245d41437a39b7b77fc602fbbfd619a42363714b265173cae68fd8a1b3ca2bd30ae60c53e5604577a4a3b1f1506e697c37432dbd883553aac8d382a3d250cf5b29e4d1be2cbcd531ff0e07e89c1f7dbc8d4529aeebe55b5ce4d0214bfdec69e080bd3ef36cca6a54933f1ef2f37867c0d38fd5865b87929115808c7e2595458e993bacc6c5a3b9f5025001e9b41447708bfbaa0462efa63876c42f769908b432f5485508a393224960551d77eadfaf4411cbc49fdff46f2f155ddd6ec30867905b709888ca0f30f935fb8d7f4803cfc7a5f7790ca181d99ca21f2621d69a5c6d49c76b4969da62740a378470332b30947ab31ccdb9ba0c7b625879eec4bd81f0200ba23504a7dc3b118bc2ab1145df13af3c8cc39f577873b84911b3d85fbbf4cb19e4d36b10a938eeb78b599dc86615fd6cec6eb7b8f7afa5f6d6be19ea81630d36ccfb2f487de50d0cf46da8d3fe3512812043c0e3ef2d7231fb0b0a35a0fb283be30a1247780f30ae0294e8b6f5897383edb895595f577524df54593cdf927b4967616ee3913e4d6b29b0dbd7c33a2a45e4ef1b1954ea5d91ce37efc1302e7ce02a97395565da2a5c5d3fdb0d87684e9b1c0ad07ec33df2dfad528e2ea0966d2a47dd5ee88e77d653c0d004fab0165f0757c4da40af327e7192536c79947a80a827aa2107dacfae3debfc8fad3d6e08076d938c510a276bdf6721a1f087cb169515028ad5ce27a1047abd92809934ca63b893f71f9a34a99c0fd30310c47e9aa37394d0ab73b254d3ca69d9c5549c9479aae24264ac5ea64d3fd821c3962ec77e709f9d30bc7b65a52e48c16e80603558caca1811411c3155d1f949fc9cf9aa9385a7199e99be77a66fad7eed91258de55b2c4c83f9a050adebea5f09758f40dac4a1c394ee8d687879150d26426895ab1938e14ae11b376254c91fc6130436996f8ed43bd27be20ec9067111c116ec94cc2b06cc91a13c5d10bbd7eecea4792f17b2b77631ef145e9fb41a83eaa11c2b72a48fb90fdbd88644c4edf8ab20dce3118364b276ac1237b36c8926e346aab5a111aa0bf341c518b7bff9e9dbb8bcb4728601b3760663e67650331e6fb54ac82fc414cb8ddfc160a25311ec5272de46217fef8b992ff89754fbee351f21bb90b6c97078b510c983350681266c8fed1f0583c5151e7b8fe3b7292319699687cc6b641fdbd689428543bc0fa1facc109de65b62784c2d985ab15d77d3af12af6d03e8d1859a553688584d75ef673a1de74093ee108c761fff32c217c231b0e2953daf521429264c0963bc8a5cdeddc617a7285b934ea51ddb5cdab23bcede86be36e001bc65c65e9a1c94baff4fab8eb5f8ed42ec377423633fe00049142467c47c5d58a7202c8e9104841c1f7f380145a6a0a828c570235e507ae5868a6062f722bb98ff6be"); byte[] privK = Hex.decode("dc7bc9a2e0b6dc66823ae4fbde971c0cfc46f9d96bbfbeebb3470ae0a5a0139ff037b84e75537e0a1cf02a517acfe323ffffe11df72e4f38430e0e66a2654b2f2ef757da47649d9f63fa03f1bf6fe6bc7c62971a98a2bd9d36eb0ec43ad4e9d940df3bb5874f5c92192aa31e0535d3cf70950bba858d11a688eaf854f63ecfc520c50d624891434265d8b0680c03061040299a104082c0910c8508d1100d44a6509408292211125b90508a2688e1302dc4021280028ac302611820851237808a000ae2040421b4910bb80550a08051b2511c28428a3672a494504910201bb45161424424a75001328181942d62a850023449ca94200b296213156408924c48122100b605030208e0060200a311e1802021116483a62898029291480801083041066613200e5b360951400c53000aa08851944842e316704ab2089b92440025121b0309418209c2a0800b290a819851c4340da4424500a0105b048e603400138928a4422648002c90202d194068e2146d19278a083746e4146914006422c660d3a03013242844965014166da0284dcc462e94367100232e1c114909a2040131060a2172c2142ada000c5a260d13228a62c444e3142d013445980224d33841c0308121a621e348720b1984d2c89108b8690887714a2884d496451a9301ca2285da30859ac851dcc00820106060465262302aa224251044640b2842988011540692144251d236719bb4900b082890188e41c469e1a469032160e01409d3020c20c88c1cb23164086218476920228ccb8470089528029550533270013405888424541041d202881aa84ccac88181008d0392899ab809d9900c9a1290614065c9322d89860c123521cc4266c8360010062411028ea3b44d44023043a0285a002ed1980c4882658922441c010212907084226e12134d011902519064113364c91806c2c04589262908b63024308cda022e0c27250b367058162c5116420b4946c1208841246c99466a04434e18a86c821661922028639409c30211029520211782d43868003460c84688e0160000a32dc0a82824b640831464c81022a2086503234ac8122ea098418c2072cc308a62c665093408412682da429089328514967081226001176d5948428ab88d592051d80892e2c0889044700ac0245a020904218a59c45094441094140820460209270c441020dcc8209212015038250c456e4a1666223770dc808ca426412222441ba3618a343099844099c42952046d88146ccb242a7cd129a8d333115c62d033b6a8357cf7cd10268ab12f16fceb7975d0a28a6c4822213c9a772df084ad91a669e2040550fc5e8d0aeb10fab2375fc9625ef9cd48c19631997a1cb6455d2c6286c569c9637add0317ce990996b28e51c3f3f717fb5907bbdd53961ad3497f2c3c473cce170906ac4c624a89aa8fbe624d99385e9c9548bf05e8cafd47d2476e41b73001f813726499e88b2b3b6f596ca311657850346598994c40e34747161e4e76264deef2a3019389d1594c942301af47b7544c23ecda2df2dece81e487d8f3f58ea89cd811d7275807ff1b0369ba86470088c174a3099fdafbe5fbb4d158801053b2b435d54059e26dee76d10a7a372f06b0b88b985b32f52052387438be8dc8bc6ae7369e2da9aa5e2585f8de403d091ccb7f790d54ddb34c608b0876f2825e9113be20a2b85867a01bda53287ac780bcd8b606d2e6d7712c56ce0142d22fe6b786de544963e134fecedfafb83d763061d799096a59e30d4472e440ae1faaabdf42640ce69740ceb9cae1a9612c21931b74af3f780236123321b205b6efd6cbb134f4c73d63c0c13e660b59d5920bc33197c355853d8d1cddc7959f7bc500ac81d985016f5b89a0eec79b0d9364ead8e38577c2a6549f2d067cb09438fdb21220aec80f6e22a476f332a2a4a0b7acbeb9e078d2b5a92ae84c924f7cb19fc7df377beb6546af97aa985c747cd111a127a674b4c26d89c14485b82e3a498a12d05406febd6c4d4b8bc051ab2cb91224b078538374b794b7dd9ddf3ac2b4a671fb7b9cf5acb78622ae2709eb2db16943aa24a9c97a81077bc784d25c0ea5991d2de883798a1f0e78f3361ed6a10dded81b1d683658331534fd7c01bc0eb00dfc4c3c84f0693046ff806bb200dd7bd4c0e6abca3f2934b4814fc0e1f8be615a2dda7c8a8d06cf9ce8566b40f4a6543b25bacddc926863fc0fa2007d6d7bf6d18dc98df696bd0865bf0be4c492b8043a32def8e3595ba7da345252f38f95be10fd7fb899b498fa01b09de5d5608eabc44a721aa04c4ef1dcb86102ac5f5f79c9708dcf5c5e896edd8c2c7bde3fa83e6ffce22d66174e31657a0b6361585e669d3031952f08631ae1f16ff90b90d0aad3c6d7e1dd0a9c41ab00a6e1c4f96af9ac5b79fcf821ffc016cb059245fb78dbe6c633d965aaab5333be07195c4b74b18e4600ce783c0a914ef4281016e80a7c9aa92d0fd789879c5e6751125ecb154432311e41cebd4fab3a31e4d2ce22d0f8c67737bf8a0dd85fe1349d5079a4d5feb3fee9378ca47ae46cc58a3f02038cfd53c4cee9cc4270cebc3d115a39c831e8ed41c4dbe4051b51d7872ba0c2bb163e0085201188eaa624a6bea9400a3a1fcc355a57f15704e61fda55a5dbaea8448fa5cb2d377a07f58305ad107e844ab4806e5bf99c1f513ee1d0a2acc04549f0801742169a77971d0adbfbfe0dd2ee5d16bc461e35748d1f3f6f4598321e8c49e79e740f990359858d2729dde007fcb26fdda9aa6e2ec4bd736f2836e7e4c83440191c849f6a53c72a4f8f830d001ea3b18f3cb4a5bd3cf066032b4932cfd2e62a9b55723fa61c688c935518af6860cd649bfbf1bf5fdc1f36dcaefaa157438d1cc8d56a150161511df82631f5e88e773e4ce263f276b7b3678d4c6fc75311d411c0d01bfdb595bb70552838e1b86517c837d909e772b428599e1fe569f77ce61531fde6fd31cdce1bdee4ba467fcbfbb9feeaad99fef67d4906e036c73662ddce158d4e5d4635e5d366f79f31a19d1b3dc4a591b0df194bb06c18147f41d88d1a409becdfb67eb063d16312266fd51b521ba9115e2e5e2aeae6ec511cede13ed4132ffbe0273f6c7039b3874f058804a54809af60557a21d9b4b831d04156a7c22dcbcdfe14f62437f449cb5ef12bf4251d485496cd835c0c2bc58bd845963dfa76ecd68519c4bdaf110be7ab052876dc3407591568c956ea3bf107c90fd5853a292f59a8d4b58b5d3fddf29bdbeac36852e3c69766fe460176a801831292b8e88a74a01ecbbe09a7b4d74cfd7fd628841944d9d556dbd60c76f96f07dc53443805ee9aa09365de4fb8179252c6b099b5dd351fdefc23dbd8090596c5d208ffd2c5661d8e5612dd574fc69045c769a969e600d77cfe192f1d3ae911289355c585811491b0ccd73692ab158824ab9edf8ac8193f0b33e6138b72c6dcd5d344f807b3da92425037de5ea4eead1c795effaa145e2ecdd327606eb2609929b9474b2bb04653602555c068385e92f06f29ca613ce5b4404f01ab1805db0acaa890330d291f40692df382509302b6dc8668f2c8f2d3a44fd58dca26e9802794f73d25b3149e6d576441"); byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - byte[] s = Hex.decode("eea01acc8fe6631c9260996def0c75d84998cf4512c7b67bc4246bbfbff165a404d02bca30da1c2b61d91d7986a467fd4b3a1131077ac138b4011ef07fc1f3ca6237e7fc6550c7e071c939f4554f265362eb26158ee1a2e57c72d20beb78168d9e2d7faf54763755a44bdc29e575884133062453a9e3e761a13a82143d7db7215ab0b8628c096e0f298491a8d67517ab8a90be7db5d311eddc7e883d50eb873decd9b3e420155008c0a3632d51f93a9c67ea336273c8f26617c7cfa2a3aa6d9aa075e75fc60fb587fb5522cb6bac4ef1979a069a15aed3171660ce5da2c27af188e9d3bc62eebdbd798f1a650c7d46411e3cabeb27be3ae787b5f4d82a2e2cf4eee84b4fc82edea4533a47bf7d3791933d1c5ce19c1792a6420c9dcd540dc3a494d9b518ce5f4f85d7747c2fa45d812d16f089682c57a96061210c942dbaca8dbde509f56f498d68f0b4e6f4a51373c9f5a5db2e20ec8254ea9d59f69d732fd1b1149fbd0b608368086a3b6acbe5de156fc508390ddc9ca28d201fdc67140a767b2d99d08051255e73d423750e91b1aa31982cc7014e46c75b69ec972f15745bafbe4878f73d8800d80ad22716f15f4d964f0468e8583add1a4ba8f544e9b83dd6c5ebf744436e254bd699e8909e712d9f6e69fbda39be69a4e0bb58cdd0ddbd369cf5a6475b1ad5fe2849c439611516bd13de14b34b26a731c5a5bde4fae538782a6daeb6fbdaf4cf1af40f3b9c7896e87ac71b3fc95eea02f2f28bf62b9d613998ad973added64515a699fc89304b8fe4d4c97759662b720835c2b28585648e54dedfbfa40fd1455e8a945a390765e3b1a2588286bd4f2995eca39ce9eca6d2e32d92e18c930e4b99109f148db96f1763703aeb431c3c815d577c2b0282181932bb182325bf45e1355d91c8ec669ccd94429dc4ea0abc562988bd2b27b39f2dd0e4ace6fc9148cd064005e9cf0f8105a6534261942774c2a02f150f8d250822745b1cc40e1d57c68dea152c0f5088712266e5a37eb7760204c2747561688990d3cf7c76660e5671727c7ebde56420c91549a48b3763062ff92a4679e7d3e8569303eeff650c0ae606234d70a350aa9862b912825b13c1ec7bd6bf346717b0f30c45c1925873f04d469fd28f82f19375531ffb83851c471ebf623c86130d929e739bd8721d97ca9a83676f26c0a75493b5b02f0921aea91baae2da96532ab9db04dc997d5f800f58a891f6ef26e5478de1ce9b4da04eccac4cee81de5c3b1010ef28242217ec737beb36815c4af1de9a4160180ea896120ce96869bf551bb6be079482f4ab5c0f7f234c50bb4139ff9fba1b594c85cc3780434fc00f7d0492cfc86c0d1889784b113650e3c29bb2e9ed6f94df5ea42afac8060856fb90fab5f4c6fb6875fd67e0438335bcd5199b72706cf358492e5f4945bf2a686aa2861908d6a71ba4e760c87e75a7ff31169993cf048817512aeac4e960771879be541b1adcd6c2da9f9d2153e728d4ee1e91acd7f704e0b472856cfd8f85e2f30b0f6e427f190dbc1079343fdc71f9ac0b8aa5e6fdfd60fe9c90e4bebd4a91dbf16378bcc2a330aeed5b7e8dd617fbf3c6ed9b2c2ac82f2e9d03c975b2a832a667864090da9ca91ad1af97278f6cfebeaf2cc681957f3d75d17a5710de85444b636cf7e0dbac06852fe669f87bc7c430ff548ee0b34f1a68e86f1b26290f8a056c0bccd18a540ce04ee7fdee47f5176b811021a89d170e71250a040e10f8f900236617c6be92217b77aa00854d6376739d5a63d32a377da20c368092367fc6afb62e0b898c01462a399aa3dba4beb0d03d7f8a2e84b499a41e7a6e50cd5e09b4d6d8cb3e8ee3a2d1b50775f9caf7335f1ea15b2312352831418ce2529542011a19c6ece5c1e6dfe7e37821933594ca6f55ca6c799b32f88b21d59744c10538ea7208eb61a04d24476c326068ac9ad4199080e02b95766f6a18738c7e4506d18e9c5c526ef4f28ef14662667dc865ffd446026cefca1b39be77cdfd7773aac0bf570647c21979b9f0ff0d67f2a9940e1e1c27e9e3296c7d890c5627e9126fa09bed1f242aa23112d828529ce431939c9ecc0d4311742a1fa5f9f283eb0135093d3e6aa9e89d4641415678f0b2ecb1210a611d062c5e17f01521aa45d778e2a0770cfda540ce1b5bbb3fabfc783601480b080f4e7275e69705b6cff043a3b503da77fbdc05702b790b1cf4dccfb6b2df00bf0ee896420175e1293a6b8fbc96cf9759a6c0e56067dc9e2522621af2cf830e2bb648f0ca3560bdf9c2c0c01bb23806455bc40889472398f9daf71f0ab9e1aab2fe8d6c8c504a1a45d99229828a9588a559a7172b041b2bbcdbe2e59b749b3e1219abf51a39164c9fac17bd8c83eab1e0e04e029550b689134194d486083b956706a6706274324d63ff79c35f37cf8c2932910e60e1da7cc6c4d9b966fb11437f7d4e94221e4b9ce51ea04325e4b75e45dbbbaadeeadd432e776c9b14cff55529c24b43211b52d1f27de0d86c0f253ec3c2262fdfb1ecb18442174321bbed4c1454522d747be4f53f9ea445d4db360c5c0ddbac51179c7f6016249bcadcce47d4abaf0604047d806f556d11aba411239a32a80d4403c72198036917b6c3b9c5fefcbb73b4d11cea0cc09b419ab8bb0a093131b4c32280fac586bee305e14a18432bbaf1ad6ffc67863edd564df4f9518c6363b80d83c59440bde98c2eeed939bfa1d8f720a805088e2090ab1af71ad5190978b2e23a7d58fc28ab2ed623f2cc65d67629a2fbbe84309a3e0447f3805728155cca522217f9e66b5b2d794fec7131b091f7f77df37e8d726f150d416018941a7b48617fe291a3a3594df80bb1927d87d8f8d5cb945c39c977e7a4f9882e3facd6f26e42390a1f7d14e55797bd22ae78ac11208084be07399d2f9cd2fa331784c5e65de766d87c3d19aad2c7993485e65f11b2c03533f265d9268f8d7f9ce14f97a76891e2b764d2e0a7baf2f81c6fcfd15c78552bba4952fe375c9872a25fddfa19a29695320858fa8a910c29d0739edff01da6d80f757906f7103984c4910c44220ce83fb5b46527c918d186b5c096ea4d1c85df71b4e7d625bb2df5a898880a18238eb4388f66f0d5daf074bdfc6e3b4695ef5faaf754ed764b80463d724d1fc41b598861207d1971cfe1e857cf2bf8dcc4afae1e44c622d96194d3f85fa5a37aed9a154074fbc54d50724658678dfba30bce2fc853bf87f7379d80865f08f0a772afedd8f45808b49605ff3d2875a6ce7b90f4a61fc55734f791bf2e6ed554309111a385158627d7e828491a2b7c6d1f00315162c42435b62656f89bbbcbfe1e6e8f0f7f9000711123b5b6ea7b0b7b8c9d2e5e9f5fc09727a9b9e9fb3d3d6e9ebf4000000000000000000000000000011253642"); + byte[] s = Hex.decode("237c7b8820733d2cf35345f8a851996061675570ce42923ee2cd437e41b4a9b391481f71ece9e0b64c584a73710d8d688a930ac0bf02abf57c6e4709e724a9e4178c629018bc0b73b37a087dd3e7ea8da65b1145bcfeed1a7c1223607eaf0aef04ab2b60d47460945c621a4f9356130bcb5e94f00c710d1cfe99c05ea0cf9e0779577f3671560316bf24ec9cf2572b13e9a50d5fbcca4ddce481f740db1d7e200268459629d66eb5a0b5603ad6468a4a04498d84df62ee394d6fc5a3a7b1ef9de0cebe88168e5d6f771efc1ea315e78b83cb2c0ef88f167ee170dffddb9acaa5df380af1f80353746b6a5530c9fde8458eec99b478dcc6673236b277c41cde9eba586b9808146ccfae6fd8bea1d0654f65cac7583ab7050711b1a322d8da6c6aad16608a9053a655580d66016fc9cefaa17fe0fed5080dbd4daa9692f96794243a2813677ad542e1e164efa9341bd0fdba956a1b4b594f1a70fb3c14aed1217b861dcb749a56b281205d7df5d472a08fb376955524dda1017bcc8be85768191d0e18570fa8f263bd592a8d5358cf7f6ac28e0c664776acf51b689cf2e96603cb7de14978cc56f00819a217b5ae5e3c083c487f5a23c07939737c9ed6b2a51e04f39ddc69da569b88054fc64769098056d83539759d0cc487a711125bf73de1f6671695f5633645534e6cb2d374645c3c9fd39c5347c4b82fb1a452fbb6137f3c470eb1fc7240a5c2a281a1dd45670807552bcc0d160a6775b6dfebbc68500eb76e1e96db1ca0f31413c96f87354ab7071c7786c9e67d0d6476282bd676af23feeb7127b7864daca72f994a85bd10f1f66ea1240882f9b62895f19c0aaad1cf35cda81b311993194d977337d9a10728a7f3d82c8d7fe35cd7047d233c8efe1d9b66b2828c9b582dc2e4605683ace6be76ba351b6d7a1db23a81854d17e9601e7dc69beaae6426ef307300508d204b433026e0534dd0f0123b06252524769f2f86771c8cf5ee82f0b3b3010828a300578871af9b6031f34342cb2d5ea4093c50b621b10248d0a32c1cd5684ca50b5f9886e2df6deca3213bd5cd79d63b5dc8266beb4d80beeed82c9ee801ed35c6a9f69947e806e791173b5b883e20192573e85e7003f99c5ab417e72f03563eb93b163f4c2300675e8c1ab9f80cf62c88b1876fd0bd4258e0e083da712e341fbbceef37d59e090f6eca0cb3e8e6b7fe1c7f35c3a9db958cd273fcc581b285e30e3c35714f01d2eda306a6e66d9609d4ae88248bf76a991acb8b833255aaafcb27498d009eff0aa5264e1874b17eb646dfce4707e8bfb946babfa4f7affe388c0656b9dc4a8bbc670e64d42676db5b3cd017ce6d52e2547d43745e66ed9b1ca2228594546b4c2c636f524edec65d9ade60a9fd3b2586af169ada64574d85594cbaac5f3827d3c4317e51722c497f09dcaa4b7c4f03bd4fef3ba847d38d252fccecd7e207830fe4d60733b49527b5d29e71d2b736a97d9d34475fb081d0bc8810507f672ae03232bc32a33c711a3f12826fe1801f40962061e3d3fdeb3368e91eab892cdac18f0e06a4312e67f445578dbeaf54f5c3cbdbae0ab2dd84525a32253b3720d83c9b3e50ecf0554c89d15bd352b0636b40b79d38fc5cca5e696c1ff0cd2f0934fb3eaadccc1b6d5fac5544b6fe5c6e0a317c4fcfff2b1f70718b7e4e7cf3db3bf1c002031ef50c049bdffc3b78358e0be20eb57ed41bae04cdd09091afefa457a8aebb3376370ee04a7f48d444b7f1170edab68e0b970e8fc2850976536ce3bb14586af06baeac171278a5e949e00af7cdb0d4b841244ccccc797ff3fd4187077d4c9d33873cab0bf6e690591b9021f80c52d47494051ac1ff75554b6b1907903dc530ec6b42d025f723d7d4e539222e683e47532541f25f14b0c007b093b7ccbfc0172e78e543517f632149d842821a2b414d0db9aac1398b5e99c269ef4e303e1373f9bcdf8211b55c65ec19f93a0422a7148cabd4c311f11a49efc757534d00cae3c84cb849e975193145538917f81225cc96457bc1a2ab8fa72afa8563dc314766ffd19a10db92dabf9a0656066728d384f598229fa94e906b8a3222b0dfe164afd9c116f31c315ee53ffb0b0d582ee0abfad259f1b4095c00a347673fd4e17ea7d8f974dbf2ed90311cb167d61aebea7b0b17a34f5b721fecafcfbc3feac7091b81851f8a5b051add8e724a503386a53b70d106d86a99813d579ef75a065cf70cc1ab9d80c39a01d3c5946049efed8d4e383b5ca65827a9cee08cba792a903347f7547a64745f8e17d71a0d40d71d15484b9a6814c86230aa05539e907cddda5efb3162c356f35829bc32a28bc80ec9454e5bfec24a6dd74675e3b913647f3d176a6773c1a0e40edd17ecd13aee3493710b1154f855f2591e62cc7073c608bbaa77104e8d4993b67cf81f65af89c8c91d695f7560daa68ad14160cb7df4e7a61b1860255320dbb813676df1285c015aec994d7bc0ce29751416b31ed15b69172968ddaa515692b8febccb4e3298e8bf169c20b965903b80f26f20a6a3bd5facd1bc38c6c817e23bf35187ff75f982ae9ed65a43f6199b61ae84683e1befcf9c0178b8ea2890f96a6e08d33d44c3ce50d9ccbd1cdf96df6b2f5e8f1c6cb04300f7f6d483108390aea8ed31b07b32c87c542ab475946d525e24c16b2d0afb86687e47cce7abb5b7fc41d6a9953a59a8b221d057b793845cfab414726b3753d87c020253fb93722263ceee93a66acf163c86eb7bd62136f70ec414b5562862f1202deeb9feaf7981416be2a09c0e7c1f18ee95314b54d0497bac2986d90e9ed3990220e96ae1622e11f2ee91c1b16128e7384a87fabc6731c7b0b00bb707fd1abe0392c95e4c435460b47d2199829b076b4ef6b11ad32825cad85794a674eefdd6173dca39dcbf397c1b9531380a72d142b7d4005d884fcbd59211827820fc5b2bc605e5c717c31e124cd1f57180d4ba598833f097056f809b71214fbee25f7fe7f14e3df8cb6bbf6c3f3de82885f71bfd874e6b7ad11db7210fd73c0ccbaa60f008a86a59a9860c0c851672da17b077d35977c52cf35bf06d450f3ec061977f627324c55aada361c6abb3de77e828a63aef6dc37cdf0caf3b98c3a409e3cdbdd2edd0dc4feb1a6ede8df7252cb658413f22728142304d7d02b06e438b10814f7731a489e79b6b8a6b0fca6b63fe9a61ff2994704bdff918e1ae6a99df07d3e18a216890465397b6eda5f47ad2f216817544b8840c6af1704d9a71a02c73b6a29fb6fb17787d97a8984790a34736050607093d3f557d9ba5afb8ced3d4dee1e8eef1f8fc0117474f558c96b2b4c2d6d9f8439198aac0cad2d3eaed0d1a243d44456486cfdce4e6f1000000000000000000000000000000000000000000000015222c39"); byte[] seed = Hex.decode("7c9935a0b07694aa0c6d10e4db6b1add2fd81a25ccb148032dcd739936737f2d"); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("HASH-ML-DSA", "BC"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-DSA", "BC"); SecureRandom katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null); kpg.initialize(MLDSAParameterSpec.ml_dsa_44, katRandom); @@ -492,9 +620,9 @@ public void testHashMLDSAKATSig() PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded()); ASN1OctetString seq = privInfo.getPrivateKey(); - assertTrue(Arrays.areEqual(seq.getOctets(), seed)); + assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(ASN1Sequence.getInstance(seq.getOctets()).getObjectAt(0)).getOctets(), seed)); - Signature sig = Signature.getInstance("HASH-ML-DSA", "BC"); + Signature sig = Signature.getInstance("ML-DSA", "BC"); sig.initSign(kp.getPrivate()); @@ -504,7 +632,7 @@ public void testHashMLDSAKATSig() assertTrue(Arrays.areEqual(s, genS)); - sig = Signature.getInstance("HASH-ML-DSA", "BC"); + sig = Signature.getInstance("ML-DSA", "BC"); sig.initVerify(kp.getPublic()); @@ -522,38 +650,7 @@ public void testHashMLDSAKATSig() assertFalse(Arrays.areEqual(s, genS)); - sig = Signature.getInstance("HASH-ML-DSA", "BC"); - - sig.initVerify(kp.getPublic()); - - sig.update(msg, 0, msg.length); - - assertTrue(sig.verify(genS)); - - AlgorithmParameters algP = sig.getParameters(); - - assertTrue(null == algP); - - // test using ml-dsa-44 for the key, should be the same. - - kpg = KeyPairGenerator.getInstance("ML-DSA", "BC"); - katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null); - - kpg.initialize(MLDSAParameterSpec.ml_dsa_44_with_sha512, katRandom); - - kp = kpg.generateKeyPair(); - - sig = Signature.getInstance("HASH-ML-DSA", "BC"); - - sig.initSign(kp.getPrivate()); - - sig.update(msg, 0, msg.length); - - genS = sig.sign(); - - assertTrue(Arrays.areEqual(s, genS)); - - sig = Signature.getInstance("HASH-ML-DSA", "BC"); + sig = Signature.getInstance("ML-DSA", "BC"); sig.initVerify(kp.getPublic()); @@ -562,16 +659,16 @@ public void testHashMLDSAKATSig() assertTrue(sig.verify(s)); } - public void testHashMLDSAKATSigWithContext() + public void testMLDSAKATSigWithContext() throws Exception { byte[] pubK = Hex.decode("dc7bc9a2e0b6dc66823ae4fbde971c0cfc46f9d96bbfbeebb3470ae0a5a0139fdd6a6ce5bc76e94faa9e9250abd4cee02cf1ee46a8e99ce12d7395781fa7519021273da3365519724efbe279add6c35f92c9d42b032832f1bf29ebbecd3ec87a3af3da33c611f7f35fa35acab174024f118979e23bf2fe069269a2ec45fbc1b9c1fb0e1f05486a6a833eb48adc2960641d9af6eb8b7381b1ec55d889f26b084ddfa1c9ed9b962d342694cede83825309d9db6bd6ba7582132534861e44a04388a694242411761d34e7c085d282b723c65948a2ac764d9702bd8ed7fe9931d7d8704a39e6508844f3f84843c305594fe6e5404e08f18ed039ac6563cbaa34b0ca38320299d6256ec0f78d421f088159d49dc439cbc539a55884a3eb4efc9cf190b42f713441cb97004245d41437a39b7b77fc602fbbfd619a42363714b265173cae68fd8a1b3ca2bd30ae60c53e5604577a4a3b1f1506e697c37432dbd883553aac8d382a3d250cf5b29e4d1be2cbcd531ff0e07e89c1f7dbc8d4529aeebe55b5ce4d0214bfdec69e080bd3ef36cca6a54933f1ef2f37867c0d38fd5865b87929115808c7e2595458e993bacc6c5a3b9f5025001e9b41447708bfbaa0462efa63876c42f769908b432f5485508a393224960551d77eadfaf4411cbc49fdff46f2f155ddd6ec30867905b709888ca0f30f935fb8d7f4803cfc7a5f7790ca181d99ca21f2621d69a5c6d49c76b4969da62740a378470332b30947ab31ccdb9ba0c7b625879eec4bd81f0200ba23504a7dc3b118bc2ab1145df13af3c8cc39f577873b84911b3d85fbbf4cb19e4d36b10a938eeb78b599dc86615fd6cec6eb7b8f7afa5f6d6be19ea81630d36ccfb2f487de50d0cf46da8d3fe3512812043c0e3ef2d7231fb0b0a35a0fb283be30a1247780f30ae0294e8b6f5897383edb895595f577524df54593cdf927b4967616ee3913e4d6b29b0dbd7c33a2a45e4ef1b1954ea5d91ce37efc1302e7ce02a97395565da2a5c5d3fdb0d87684e9b1c0ad07ec33df2dfad528e2ea0966d2a47dd5ee88e77d653c0d004fab0165f0757c4da40af327e7192536c79947a80a827aa2107dacfae3debfc8fad3d6e08076d938c510a276bdf6721a1f087cb169515028ad5ce27a1047abd92809934ca63b893f71f9a34a99c0fd30310c47e9aa37394d0ab73b254d3ca69d9c5549c9479aae24264ac5ea64d3fd821c3962ec77e709f9d30bc7b65a52e48c16e80603558caca1811411c3155d1f949fc9cf9aa9385a7199e99be77a66fad7eed91258de55b2c4c83f9a050adebea5f09758f40dac4a1c394ee8d687879150d26426895ab1938e14ae11b376254c91fc6130436996f8ed43bd27be20ec9067111c116ec94cc2b06cc91a13c5d10bbd7eecea4792f17b2b77631ef145e9fb41a83eaa11c2b72a48fb90fdbd88644c4edf8ab20dce3118364b276ac1237b36c8926e346aab5a111aa0bf341c518b7bff9e9dbb8bcb4728601b3760663e67650331e6fb54ac82fc414cb8ddfc160a25311ec5272de46217fef8b992ff89754fbee351f21bb90b6c97078b510c983350681266c8fed1f0583c5151e7b8fe3b7292319699687cc6b641fdbd689428543bc0fa1facc109de65b62784c2d985ab15d77d3af12af6d03e8d1859a553688584d75ef673a1de74093ee108c761fff32c217c231b0e2953daf521429264c0963bc8a5cdeddc617a7285b934ea51ddb5cdab23bcede86be36e001bc65c65e9a1c94baff4fab8eb5f8ed42ec377423633fe00049142467c47c5d58a7202c8e9104841c1f7f380145a6a0a828c570235e507ae5868a6062f722bb98ff6be"); byte[] privK = Hex.decode("dc7bc9a2e0b6dc66823ae4fbde971c0cfc46f9d96bbfbeebb3470ae0a5a0139ff037b84e75537e0a1cf02a517acfe323ffffe11df72e4f38430e0e66a2654b2f2ef757da47649d9f63fa03f1bf6fe6bc7c62971a98a2bd9d36eb0ec43ad4e9d940df3bb5874f5c92192aa31e0535d3cf70950bba858d11a688eaf854f63ecfc520c50d624891434265d8b0680c03061040299a104082c0910c8508d1100d44a6509408292211125b90508a2688e1302dc4021280028ac302611820851237808a000ae2040421b4910bb80550a08051b2511c28428a3672a494504910201bb45161424424a75001328181942d62a850023449ca94200b296213156408924c48122100b605030208e0060200a311e1802021116483a62898029291480801083041066613200e5b360951400c53000aa08851944842e316704ab2089b92440025121b0309418209c2a0800b290a819851c4340da4424500a0105b048e603400138928a4422648002c90202d194068e2146d19278a083746e4146914006422c660d3a03013242844965014166da0284dcc462e94367100232e1c114909a2040131060a2172c2142ada000c5a260d13228a62c444e3142d013445980224d33841c0308121a621e348720b1984d2c89108b8690887714a2884d496451a9301ca2285da30859ac851dcc00820106060465262302aa224251044640b2842988011540692144251d236719bb4900b082890188e41c469e1a469032160e01409d3020c20c88c1cb23164086218476920228ccb8470089528029550533270013405888424541041d202881aa84ccac88181008d0392899ab809d9900c9a1290614065c9322d89860c123521cc4266c8360010062411028ea3b44d44023043a0285a002ed1980c4882658922441c010212907084226e12134d011902519064113364c91806c2c04589262908b63024308cda022e0c27250b367058162c5116420b4946c1208841246c99466a04434e18a86c821661922028639409c30211029520211782d43868003460c84688e0160000a32dc0a82824b640831464c81022a2086503234ac8122ea098418c2072cc308a62c665093408412682da429089328514967081226001176d5948428ab88d592051d80892e2c0889044700ac0245a020904218a59c45094441094140820460209270c441020dcc8209212015038250c456e4a1666223770dc808ca426412222441ba3618a343099844099c42952046d88146ccb242a7cd129a8d333115c62d033b6a8357cf7cd10268ab12f16fceb7975d0a28a6c4822213c9a772df084ad91a669e2040550fc5e8d0aeb10fab2375fc9625ef9cd48c19631997a1cb6455d2c6286c569c9637add0317ce990996b28e51c3f3f717fb5907bbdd53961ad3497f2c3c473cce170906ac4c624a89aa8fbe624d99385e9c9548bf05e8cafd47d2476e41b73001f813726499e88b2b3b6f596ca311657850346598994c40e34747161e4e76264deef2a3019389d1594c942301af47b7544c23ecda2df2dece81e487d8f3f58ea89cd811d7275807ff1b0369ba86470088c174a3099fdafbe5fbb4d158801053b2b435d54059e26dee76d10a7a372f06b0b88b985b32f52052387438be8dc8bc6ae7369e2da9aa5e2585f8de403d091ccb7f790d54ddb34c608b0876f2825e9113be20a2b85867a01bda53287ac780bcd8b606d2e6d7712c56ce0142d22fe6b786de544963e134fecedfafb83d763061d799096a59e30d4472e440ae1faaabdf42640ce69740ceb9cae1a9612c21931b74af3f780236123321b205b6efd6cbb134f4c73d63c0c13e660b59d5920bc33197c355853d8d1cddc7959f7bc500ac81d985016f5b89a0eec79b0d9364ead8e38577c2a6549f2d067cb09438fdb21220aec80f6e22a476f332a2a4a0b7acbeb9e078d2b5a92ae84c924f7cb19fc7df377beb6546af97aa985c747cd111a127a674b4c26d89c14485b82e3a498a12d05406febd6c4d4b8bc051ab2cb91224b078538374b794b7dd9ddf3ac2b4a671fb7b9cf5acb78622ae2709eb2db16943aa24a9c97a81077bc784d25c0ea5991d2de883798a1f0e78f3361ed6a10dded81b1d683658331534fd7c01bc0eb00dfc4c3c84f0693046ff806bb200dd7bd4c0e6abca3f2934b4814fc0e1f8be615a2dda7c8a8d06cf9ce8566b40f4a6543b25bacddc926863fc0fa2007d6d7bf6d18dc98df696bd0865bf0be4c492b8043a32def8e3595ba7da345252f38f95be10fd7fb899b498fa01b09de5d5608eabc44a721aa04c4ef1dcb86102ac5f5f79c9708dcf5c5e896edd8c2c7bde3fa83e6ffce22d66174e31657a0b6361585e669d3031952f08631ae1f16ff90b90d0aad3c6d7e1dd0a9c41ab00a6e1c4f96af9ac5b79fcf821ffc016cb059245fb78dbe6c633d965aaab5333be07195c4b74b18e4600ce783c0a914ef4281016e80a7c9aa92d0fd789879c5e6751125ecb154432311e41cebd4fab3a31e4d2ce22d0f8c67737bf8a0dd85fe1349d5079a4d5feb3fee9378ca47ae46cc58a3f02038cfd53c4cee9cc4270cebc3d115a39c831e8ed41c4dbe4051b51d7872ba0c2bb163e0085201188eaa624a6bea9400a3a1fcc355a57f15704e61fda55a5dbaea8448fa5cb2d377a07f58305ad107e844ab4806e5bf99c1f513ee1d0a2acc04549f0801742169a77971d0adbfbfe0dd2ee5d16bc461e35748d1f3f6f4598321e8c49e79e740f990359858d2729dde007fcb26fdda9aa6e2ec4bd736f2836e7e4c83440191c849f6a53c72a4f8f830d001ea3b18f3cb4a5bd3cf066032b4932cfd2e62a9b55723fa61c688c935518af6860cd649bfbf1bf5fdc1f36dcaefaa157438d1cc8d56a150161511df82631f5e88e773e4ce263f276b7b3678d4c6fc75311d411c0d01bfdb595bb70552838e1b86517c837d909e772b428599e1fe569f77ce61531fde6fd31cdce1bdee4ba467fcbfbb9feeaad99fef67d4906e036c73662ddce158d4e5d4635e5d366f79f31a19d1b3dc4a591b0df194bb06c18147f41d88d1a409becdfb67eb063d16312266fd51b521ba9115e2e5e2aeae6ec511cede13ed4132ffbe0273f6c7039b3874f058804a54809af60557a21d9b4b831d04156a7c22dcbcdfe14f62437f449cb5ef12bf4251d485496cd835c0c2bc58bd845963dfa76ecd68519c4bdaf110be7ab052876dc3407591568c956ea3bf107c90fd5853a292f59a8d4b58b5d3fddf29bdbeac36852e3c69766fe460176a801831292b8e88a74a01ecbbe09a7b4d74cfd7fd628841944d9d556dbd60c76f96f07dc53443805ee9aa09365de4fb8179252c6b099b5dd351fdefc23dbd8090596c5d208ffd2c5661d8e5612dd574fc69045c769a969e600d77cfe192f1d3ae911289355c585811491b0ccd73692ab158824ab9edf8ac8193f0b33e6138b72c6dcd5d344f807b3da92425037de5ea4eead1c795effaa145e2ecdd327606eb2609929b9474b2bb04653602555c068385e92f06f29ca613ce5b4404f01ab1805db0acaa890330d291f40692df382509302b6dc8668f2c8f2d3a44fd58dca26e9802794f73d25b3149e6d576441"); byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - byte[] s = Hex.decode("42a2ad149a7f35856ed92005232a2d33dc4a1ad0cb0fb7b772f56956082fb9a630fd7284bca55b5cef3a55ad73c2225d7c2d143d0023cd988890b81c271b97e6ed99250bd141550e4eb0276d4a59f19023d0bd725fe2c4f3301655ae91089851db6ecd24bc448ac06c1bbad4254bb1370678858586d55ffa4a9112dd48fd14c224d35d9c2987dc8bff84578d9a5fd0a1e34f7fb34523a305f623cef1766ac8b336c6c1a062f8d273e4f5636969c8c5afb3102436f9549a68ceb5393065944f0a231eb53ef7c6d3bca1fdf2544e3637f5efa96752455e4816d8747c5af14d3996eb241b2dc28fff9a9d93d148193195a87d6763dd94a5d9dfcd8623baf73ecebf545291bd236f44a3b9c5b8d231b7d7e991f6fbd67bbf3740611ef64c66765e25dc0e968900c407565097adf82f7b2387d03f93757a88c1a7590fdca09e19579ecc124629a26e80851b1ca5f29bff6ed37fc779bfc304e93169004b7c742ff4ab9ead2e96e313f1ddd8f6f94d58298ecd2393e119f5536d46e934ff11323f06df447685fbc1f8017a1a98ed717c8c7e4aa9be3b9f0c9f4e43c802c9542a26c013a07f5dcf2cfac584e8a998712cb6f00d4e51f9a3d65bac5197b49bd5291db44fbb90160a364818548b0bb59d34f48fbfc86b7f9d765a427074bee154dacce37f2bae727e99ec55bf7b5d618eebabc73cb015d18c6ba4c45a4c5f8c8802beceb9fd183989f4ccd3964a995a19a4a4492ca043c4be3ff76505d97174db15e15d56acf3e78147c0136373e784d627360e1ad41decdbb5a92cf271cba3a969f366ef53fa1150a1514b18b8c6835a44c9139456c162dfa59e525892e38ad6864097f5108752b4b8d3f847bdc0c185f6da216da8ee00c06ee8b54d66adfa85d2f8851ecbafea5d063604d6abf28a0df4042d788cc539cbfce523f1183dd7c955990ef9709d9db2d28a0ac55382b92b3869ae40072119278e005be9acd8b30507d55a065815db29fe5ad0ded3094d9e92762b1d52a7790e146d4b4b7e81389af5e1bff9485ba72ffebf902aa343e5ad737f57bee177ed8514f0549083407f6a645234be6ece678c59f905e3af7190602e4c1d8815a28e791d476c10ecfbcfc9539e995e72c8cad9f7b515a53e0c912be7071c13c2d350b1965627ec610e17bc52c13108dd3f2e2fd703edf13d76ee62d904f45d6f89b5814a6570ab5e041b14186c63bc0b93de643aa4828ae4747c964474102cfb77aed3412248c67a8fbd2971072058ddda17df2b152449c63b164dd1ca152c893e38afd042d9f186e677969dc3caa6d2105b54d7e8dc47bda7f63606e8670f3f671b0e43d1cf0884cdde011743a9748e50b66cebacfd4595c346a8229883fd92945e65fab2c9a1dad85d6ae11ed3dcd07dbe1bf031fce1c23f5d1fc61dd970b40dec577abd5b2bb697f6b24406ef7d623b45b0a96a79a8171805d599ea99fab55682eba390c0dbd7f53999ca7cd5e4e471139b5e877be6fdcab79ba7cc7693a07bf537f4e05669a977610d2f526e7ed6edf75164b09e6ed608ec755744571694218a36ad96362381fbfb967ec0e0180fb8efd4972c8614f82e262e0628a083f360ed927dc85b9b95d5c53eb371848f3ee1c7dd069918f74e7a1f25fc6f955e72be0202a401e28c7fc20c8378469b6bc370700b6fce04224a3f3815598f15f44ad95972208c215126753db78fa84fac87b62da8b1249360ff2171643cb100c07f8caffbd9aa4d94b0b192eb49af6c9d3b68357d708d597004a178c116efe72f5ec80d2269c592e65eb12b5968f3c153bb900ea3d49a91e155dc38383844bb849f8f78c9038d30ab7b6719830a7667a725f67b6318615b37f0d0a2dedf7e2f741d1807abd4614087449ce789ff10deee23befcac04de3376245143f24df1a1f95d7442439b2e6f983959598c95577e2d262e96f8fa4cc4a1fd59e2b4d9c4394071630c2e0569c4fa3784bfb0d39f42e366c8fee583412be0c6d4c67fff9d570926210fe632fa125245496af25cd084d723994c94e2ff659637784c31e9a555a788c8fc7410839ee1c6e80544d825b79fcf238afd1c0d6be0fa32ecb8b93463d98b9f2b3495c81f25877a613227bdaf8b94342da81c0f2995872a5a75341503bfaec2bb7f95db0f340f4732a832f4effab9bf4da476528a15fbfc5104fe3dae3a5fdd05ebc42989d96f1eb056c3ffc79de35d229a55e301c33975b92c4a7de50962a2fcb83912441189ac1a4e4ad38e30ecc3df084f0ecd8745750323debdea86ab87e725d41fd044fd507f279e7dfbb6a04b34cb150ed9fda95d7393cf8e611589ec56a5dc9a9de4dc80c36e7cbcfb77501bc69b93437ce3642ee35da9a0d71b76a641847fb9798e18b1d073a7b832958f65079648b47370bfc175869dfc412b0b3074fc43d608acd2b602f7b9d2fb831c3a37de56600a34135a1d029bb5f582732b2dc45f992c4a6dcc2c3b1cad807ad4e741490b5cad74a6e7a416fe91b1ad216c428558c3f8d0797d4acca85ca864a5194cf1273622ffeed9624f702b4725a93057a90d155ee081183d87517123647fbd31216b664107a124adef5e1dbedb7e714f6b49696fa21a4a3c2c822cc675b2a171949cd64d10fa188913a9e3318dc9829aa3e6bdeac781afd2b20211c6aeda61deedc8ef7d1426f7cf464af6a700bfce3e0df99f417b1440807870ca0af461cec38cde60e6861f817901a56db98af64e9be3648585513f833a3e5c6fedc613dfff720e76a0800139d53957b1f91e7efcd0e6308613740705e589d48934f5e9a193af901b3335e767310830ebc6662ef8d33e7c87e242b65595c61212f9ac459c09995cf4a996584bf473d4c58db901c2c994f62e6022720987e653d1e3100a84db6e077b9e4387b9df33048d201969b5fb215cb142000bb21e7e5cc3e74b934cfb80e9d117fcecb1c68479390f173cb8e33853f66a51d157287324b3f8a590e40646877c5435e3251fdd5c19791471b51f07c5265dd79aeb2997545e7a3c7b6484f34734871145260d019b28692be1357ff27b9361ff90c1e5f308a1832a900dc915c3771cb83e964e99667e5e46a713c152ce2e33d45ef4050d34671391ec20f93fcb9b9597781e1ca4d4ba1762fced1f9a06311905c6bdda492f72ce9a1c9f20cc26d020aa0a3cede4bf35a7735fe41d1ae0e0ecbb5da8ccd68f37c7acaebc1f8fc764db3bed1dbf4053911b9105e09605de322fb8750717c756330856835ed2c713ff7957f8a99f7ed485e480949b2a9b9d1d8acc0eafeee71977a56a07132c495067aeb7b9dae1e7132036424b7993949cbfd2dedff91b42494a555d6a72757aa2aebfd0f0fb161a617c8890a4a5afc0d1d9dadef300000000000000000000000000000000000000000000000c1a2a39"); + byte[] s = Hex.decode("098d5709482f9975b8c5c2e04f2dd8b54b4cf14fab51794948e88ab469656e1989a76c1a67bb93f8e8ae33f691773da3a86876c850e77ae2a4f58189f0f98d4fd5c748c9f760cd75f7c1912ad06df232c6ac38d49ceb8f648bfdd5998797812d8d2326cf5a07292a9c0d8fb87ae33cf85723c2e6383f1072d0c2b96aa4f00c981fb2e0c619344fa5ebb9761b8d2f2011639724b6a66cf502a9795da237776bc5da3a0ce35da57a2f36edf365d138c013582a21c8e4e26a43b259240c2af48504fa298ca816bfe1620dedfa72ea338da2a81e03b207bda413d2bbe38f9a4939f877bdfe2ed80261ea2293e4f9ad5fd8c5a94311d1564e18b58239de393750c5b2f7b579f47eb748a7c0635adc63a2396b4d1fda5071936eed5a3b3a3dbdd31eaf40ae09371ac7a910e056c0f84c1729cff8cc53f35aa68cbe97c4649e8d7c52381b3e1b5899c08bf758556149fb37bff2db4056741188036ae4e64190b843d213a090db1f0a338d0e9ace2b6b9caac158a6ba27092ff0ca082dc64aeaf748f2ae35597d184e7b5c03dcd2da11aff5ffe98f5075cc355d1214314ed256c637b762c54d038ca3f4a85d583f4bb68ea705a40481c35a0ae4de8c8ea7c417f2d1e1a101d6aec6aac87aef3dd4ace3a86a2b205ab9e98a9cf579f61c6a683820aa3c8b8eaa492800398f196e40300cc1e155d8e81344a07af407438a71c30bf4b936037312829020f4648899c9eff03f37d48373d462ce419e9dfe638437ea0e6871c4a78a93388000a759468eb8ad25bd60fa8363efe0ba826349598228402a286a1d7f95122b23cc051d325a539b5179afe1c0b049060d072ddc1635c4228ba13d768e704aadb5692e0eec1ffed5a9ea4ffbf45725b924afe2362bbf592d7b8ffcccb558374471ebd69ab9712c366b8f503e4aaf6ab9cb7c4124fa5767757f6b66bbbda7457e2bd35bc8927167e5520d81ff05d89e15891d6e8cf8b91cc8af0c02e2c82c93095504f61e8cb0e62dcde96c3ee0558921946cf7d20c9485e93269e9c44c6a6a8c5a266f1fe1610ae24a73897e05e69cfc1fef396e38d66119115dc6dd6d965eb053a5b6d7dbe8ae40b99f853ccdb7f569bf9b18d394abf2496bddd77801d4a9530c871c24b2b7a3ae4d335c7be3522aeeb7bb4ace52b7d213ccb086eb031aad103020413fb21b44dfabae7e1d95845dff10cd434c357b3b9f6f2a6c4e5c9c0f8d8490f31fe1faaa2f860c7f54453923e57d80ec26ebcacb3e79375ae7b0900f1f1eefe7bb491d079a0b561bb4a280ac1bc3daae702b2ca9e9cf7ff2804f5b98861d900f047d415e8911cd177cd691dfd079f6a439b4dfd407d3b3d78a33aa818f8948815c14e311d0fb6f32006863bd2a538177d1d9d9283ba7ec43932534900ab745cd54a6a115ee2786bfe1c3f8bb085f30c58cefceccb95f5d3388151df1af838e6711739d1a0d543b42e6d7948a5d8ce55fefd5ebe5d616cfa6d386c611f781b12d04eba65a3a57780b851daee6f038fe393d8bbdcd2d0bb706881d82ac55d0faa22e0c8756c676048f48fa8de39a2e8a5f1581ecc03045a3c90e1f5584a2db606c7d2ee0b724f7a84b0b21202b68729f4850da6723454536d43afce781198049f3dbbec600dbafa18fcbed25aef8095349595fe9ebdf75d951353b8cc6898a5bd4e7c0595920d9cdd1db426c694c119539a987888eaa9ca0767a3719eb967547636a24d1d8b0ae7006466b8b968476d7dd70fe5fd5c678bf37eff54da49f135db340448960d64bf097bc120660a27ca8d0f1fe28e9758ae7b171427a19bda0133a176c8d75b82b6b33f03a68013233ef124b8c56ac181f09563c5e07d445b383ddf275f3390ed27903bb1b58bee5d53b7fe871b8480e024caa1a2693681a8192ae992ba2578177dd9a9153d42d6fd1c952c840711d46e96ce4f0ec089d460347cef11cbee0eaabbeee8454552d404a3acf2d99c763ad9c000a4aa7e31cd61061741561ffd60b79c4a1881abe794db591de66837092ff93d4aa49deb083cdbd2b70de2edeb99b4f0b52dab10e5b5eab3e5bd12a8c1b042614266aa1bfe8511e7769a20510ed5e393144a9b72c0ec93a95f35d4f38a50253f3e244044ed24f69b149b5e7d887a5c2ca6c80e60aaef2667a63d49601e73ab9c5e2e09ca29aaf666719ff3b5ba32299749445e8e3f9563af2b95578f1995cf2814707e42640cd65f87518f1007aedc202cd401ba51efb0b1256ef43bdfc63d1bc46481c85ca1f1d938b5e0c802859efde08f3dfd27bee7d0f004b4abfd019165422f4b7fccd7ca4952850ca5c6c6079b8bed3bfc876923bb5e19dce7e672721486f496187d2928336c5f7ab6b4a32d7eb196b05795d55c8665645e9673c6f2a792a6f319cee59bf152a1482feb2ef325128bc8c22be9f47feb6693ff51c278a19d8256dfaa3b14ad4e299e8cda06bb9aa103a77c6062debaa42fab40d7b602343e74949d1f35c9fdfa0af0c86fcfc740e385e08bb30d37ad8d4d818bf4588fb0ef3cccf2133f7cd6501848f69e833d3988b9d627f693cb9ad4724427afa9efffd249fad1473074366e3e777ea67655264e1e3502b41ac628e0a6cc7577886b061643f2c61540497e04c81ec6db1bb33dfa53574b2e4a10c968b8d2d13dbe374159a189056ca052bd0cb8f95dac9aad2dc90b43831ea973b14fb642c4772005940fa5e41136660b588526684d7a62bfefb6d1549b5bedf3b262d5c27a85cd52f79c51e668c80a18ca543e4963a2970b7ddddd3297cabf1d51ed24fc3c55ee5c83dac281cfcef06a4e24fee98f0a84ed7ddbfaaccf2b2e7ef3abc0abd21fa2f0f24a494dd70d4b4ce685b31ca337393943a8db71011901d1061f08c56a672201b7726b158dca828ac9217629c66fac9adec98851412421d22caeadc7483c407566fcee45044e7aea3639fd0534c9d242d129dc4b0f1aa056f597bd3972852815d10bcdcd4149caf4eb8e29d61fda97a137b81d2d2800fd9a9cbcb2ab8d6351faf7d67e6385f98be98ea1f97fad8ba928338ccf0b249354991947b47b00196e51d6af3ec3d49b21e4b053147284e391d5beefcc92544752cff02fe03f5bf9276ed6b313d210aa55bfee3b2f72aed7eaaf03c7cb471b5f67d7fe13b8679e418807c8e82559489f3121268febe301b1361b929f8c3805e1f5909133ec381fecfc225ceb1c46ef9f2ab271900999a5ad596c79ce7f43e7d0ba82a177134c7b2e37c58e0fdc20a60055a4d0223320ffbed994cb26698722f8299f5600d069bab541819636ab6112a395152565b5e636e78858da6acb0b5b6cd373e45485b96a0b7bae1e8fc2d56658d98a1afb6b7b8d7dde8e9424c768a8e8fabc1d2e0e4f00000000000000000000000000000000000000000000000131f2d39"); byte[] seed = Hex.decode("7c9935a0b07694aa0c6d10e4db6b1add2fd81a25ccb148032dcd739936737f2d"); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("HASH-ML-DSA", "BC"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-DSA", "BC"); SecureRandom katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null); kpg.initialize(MLDSAParameterSpec.ml_dsa_44, katRandom); @@ -587,9 +684,9 @@ public void testHashMLDSAKATSigWithContext() PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded()); ASN1OctetString seq = privInfo.getPrivateKey(); - assertTrue(Arrays.areEqual(seq.getOctets(), seed)); + assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(ASN1Sequence.getInstance(seq.getOctets()).getObjectAt(0)).getOctets(), seed)); - Signature sig = Signature.getInstance("HASH-ML-DSA", "BC"); + Signature sig = Signature.getInstance("ML-DSA", "BC"); sig.initSign(kp.getPrivate()); @@ -601,7 +698,7 @@ public void testHashMLDSAKATSigWithContext() assertTrue(Hex.toHexString(genS), Arrays.areEqual(s, genS)); - sig = Signature.getInstance("HASH-ML-DSA", "BC"); + sig = Signature.getInstance("ML-DSA", "BC"); sig.initVerify(kp.getPublic()); @@ -611,6 +708,18 @@ public void testHashMLDSAKATSigWithContext() assertTrue(sig.verify(s)); + // check reflection based context. + + sig = Signature.getInstance("ML-DSA", "BC"); + + sig.initVerify(kp.getPublic()); + + sig.setParameter(new MyContextParameterSpec(Strings.toByteArray("Hello, world!"))); + + sig.update(msg, 0, msg.length); + + assertTrue(sig.verify(s)); + // check randomisation sig.initSign(kp.getPrivate(), new SecureRandom()); @@ -621,9 +730,15 @@ public void testHashMLDSAKATSigWithContext() genS = sig.sign(); + AlgorithmParameters sp = sig.getParameters(); + + ContextParameterSpec sspec = sp.getParameterSpec(ContextParameterSpec.class); + + assertTrue(Arrays.areEqual(Strings.toByteArray("Hello, world!"), sspec.getContext())); + assertFalse(Arrays.areEqual(s, genS)); - sig = Signature.getInstance("HASH-ML-DSA", "BC"); + sig = Signature.getInstance("ML-DSA", "BC"); sig.initVerify(kp.getPublic()); @@ -632,8 +747,181 @@ public void testHashMLDSAKATSigWithContext() sig.update(msg, 0, msg.length); assertTrue(sig.verify(genS)); + + AlgorithmParameters vp = sig.getParameters(); + + ContextParameterSpec vspec = vp.getParameterSpec(ContextParameterSpec.class); + + assertTrue(Arrays.areEqual(Strings.toByteArray("Hello, world!"), vspec.getContext())); } +// public void testHashMLDSAKATSig() +// throws Exception +// { +// byte[] pubK = Hex.decode("dc7bc9a2e0b6dc66823ae4fbde971c0cfc46f9d96bbfbeebb3470ae0a5a0139fdd6a6ce5bc76e94faa9e9250abd4cee02cf1ee46a8e99ce12d7395781fa7519021273da3365519724efbe279add6c35f92c9d42b032832f1bf29ebbecd3ec87a3af3da33c611f7f35fa35acab174024f118979e23bf2fe069269a2ec45fbc1b9c1fb0e1f05486a6a833eb48adc2960641d9af6eb8b7381b1ec55d889f26b084ddfa1c9ed9b962d342694cede83825309d9db6bd6ba7582132534861e44a04388a694242411761d34e7c085d282b723c65948a2ac764d9702bd8ed7fe9931d7d8704a39e6508844f3f84843c305594fe6e5404e08f18ed039ac6563cbaa34b0ca38320299d6256ec0f78d421f088159d49dc439cbc539a55884a3eb4efc9cf190b42f713441cb97004245d41437a39b7b77fc602fbbfd619a42363714b265173cae68fd8a1b3ca2bd30ae60c53e5604577a4a3b1f1506e697c37432dbd883553aac8d382a3d250cf5b29e4d1be2cbcd531ff0e07e89c1f7dbc8d4529aeebe55b5ce4d0214bfdec69e080bd3ef36cca6a54933f1ef2f37867c0d38fd5865b87929115808c7e2595458e993bacc6c5a3b9f5025001e9b41447708bfbaa0462efa63876c42f769908b432f5485508a393224960551d77eadfaf4411cbc49fdff46f2f155ddd6ec30867905b709888ca0f30f935fb8d7f4803cfc7a5f7790ca181d99ca21f2621d69a5c6d49c76b4969da62740a378470332b30947ab31ccdb9ba0c7b625879eec4bd81f0200ba23504a7dc3b118bc2ab1145df13af3c8cc39f577873b84911b3d85fbbf4cb19e4d36b10a938eeb78b599dc86615fd6cec6eb7b8f7afa5f6d6be19ea81630d36ccfb2f487de50d0cf46da8d3fe3512812043c0e3ef2d7231fb0b0a35a0fb283be30a1247780f30ae0294e8b6f5897383edb895595f577524df54593cdf927b4967616ee3913e4d6b29b0dbd7c33a2a45e4ef1b1954ea5d91ce37efc1302e7ce02a97395565da2a5c5d3fdb0d87684e9b1c0ad07ec33df2dfad528e2ea0966d2a47dd5ee88e77d653c0d004fab0165f0757c4da40af327e7192536c79947a80a827aa2107dacfae3debfc8fad3d6e08076d938c510a276bdf6721a1f087cb169515028ad5ce27a1047abd92809934ca63b893f71f9a34a99c0fd30310c47e9aa37394d0ab73b254d3ca69d9c5549c9479aae24264ac5ea64d3fd821c3962ec77e709f9d30bc7b65a52e48c16e80603558caca1811411c3155d1f949fc9cf9aa9385a7199e99be77a66fad7eed91258de55b2c4c83f9a050adebea5f09758f40dac4a1c394ee8d687879150d26426895ab1938e14ae11b376254c91fc6130436996f8ed43bd27be20ec9067111c116ec94cc2b06cc91a13c5d10bbd7eecea4792f17b2b77631ef145e9fb41a83eaa11c2b72a48fb90fdbd88644c4edf8ab20dce3118364b276ac1237b36c8926e346aab5a111aa0bf341c518b7bff9e9dbb8bcb4728601b3760663e67650331e6fb54ac82fc414cb8ddfc160a25311ec5272de46217fef8b992ff89754fbee351f21bb90b6c97078b510c983350681266c8fed1f0583c5151e7b8fe3b7292319699687cc6b641fdbd689428543bc0fa1facc109de65b62784c2d985ab15d77d3af12af6d03e8d1859a553688584d75ef673a1de74093ee108c761fff32c217c231b0e2953daf521429264c0963bc8a5cdeddc617a7285b934ea51ddb5cdab23bcede86be36e001bc65c65e9a1c94baff4fab8eb5f8ed42ec377423633fe00049142467c47c5d58a7202c8e9104841c1f7f380145a6a0a828c570235e507ae5868a6062f722bb98ff6be"); +// byte[] privK = Hex.decode("dc7bc9a2e0b6dc66823ae4fbde971c0cfc46f9d96bbfbeebb3470ae0a5a0139ff037b84e75537e0a1cf02a517acfe323ffffe11df72e4f38430e0e66a2654b2f2ef757da47649d9f63fa03f1bf6fe6bc7c62971a98a2bd9d36eb0ec43ad4e9d940df3bb5874f5c92192aa31e0535d3cf70950bba858d11a688eaf854f63ecfc520c50d624891434265d8b0680c03061040299a104082c0910c8508d1100d44a6509408292211125b90508a2688e1302dc4021280028ac302611820851237808a000ae2040421b4910bb80550a08051b2511c28428a3672a494504910201bb45161424424a75001328181942d62a850023449ca94200b296213156408924c48122100b605030208e0060200a311e1802021116483a62898029291480801083041066613200e5b360951400c53000aa08851944842e316704ab2089b92440025121b0309418209c2a0800b290a819851c4340da4424500a0105b048e603400138928a4422648002c90202d194068e2146d19278a083746e4146914006422c660d3a03013242844965014166da0284dcc462e94367100232e1c114909a2040131060a2172c2142ada000c5a260d13228a62c444e3142d013445980224d33841c0308121a621e348720b1984d2c89108b8690887714a2884d496451a9301ca2285da30859ac851dcc00820106060465262302aa224251044640b2842988011540692144251d236719bb4900b082890188e41c469e1a469032160e01409d3020c20c88c1cb23164086218476920228ccb8470089528029550533270013405888424541041d202881aa84ccac88181008d0392899ab809d9900c9a1290614065c9322d89860c123521cc4266c8360010062411028ea3b44d44023043a0285a002ed1980c4882658922441c010212907084226e12134d011902519064113364c91806c2c04589262908b63024308cda022e0c27250b367058162c5116420b4946c1208841246c99466a04434e18a86c821661922028639409c30211029520211782d43868003460c84688e0160000a32dc0a82824b640831464c81022a2086503234ac8122ea098418c2072cc308a62c665093408412682da429089328514967081226001176d5948428ab88d592051d80892e2c0889044700ac0245a020904218a59c45094441094140820460209270c441020dcc8209212015038250c456e4a1666223770dc808ca426412222441ba3618a343099844099c42952046d88146ccb242a7cd129a8d333115c62d033b6a8357cf7cd10268ab12f16fceb7975d0a28a6c4822213c9a772df084ad91a669e2040550fc5e8d0aeb10fab2375fc9625ef9cd48c19631997a1cb6455d2c6286c569c9637add0317ce990996b28e51c3f3f717fb5907bbdd53961ad3497f2c3c473cce170906ac4c624a89aa8fbe624d99385e9c9548bf05e8cafd47d2476e41b73001f813726499e88b2b3b6f596ca311657850346598994c40e34747161e4e76264deef2a3019389d1594c942301af47b7544c23ecda2df2dece81e487d8f3f58ea89cd811d7275807ff1b0369ba86470088c174a3099fdafbe5fbb4d158801053b2b435d54059e26dee76d10a7a372f06b0b88b985b32f52052387438be8dc8bc6ae7369e2da9aa5e2585f8de403d091ccb7f790d54ddb34c608b0876f2825e9113be20a2b85867a01bda53287ac780bcd8b606d2e6d7712c56ce0142d22fe6b786de544963e134fecedfafb83d763061d799096a59e30d4472e440ae1faaabdf42640ce69740ceb9cae1a9612c21931b74af3f780236123321b205b6efd6cbb134f4c73d63c0c13e660b59d5920bc33197c355853d8d1cddc7959f7bc500ac81d985016f5b89a0eec79b0d9364ead8e38577c2a6549f2d067cb09438fdb21220aec80f6e22a476f332a2a4a0b7acbeb9e078d2b5a92ae84c924f7cb19fc7df377beb6546af97aa985c747cd111a127a674b4c26d89c14485b82e3a498a12d05406febd6c4d4b8bc051ab2cb91224b078538374b794b7dd9ddf3ac2b4a671fb7b9cf5acb78622ae2709eb2db16943aa24a9c97a81077bc784d25c0ea5991d2de883798a1f0e78f3361ed6a10dded81b1d683658331534fd7c01bc0eb00dfc4c3c84f0693046ff806bb200dd7bd4c0e6abca3f2934b4814fc0e1f8be615a2dda7c8a8d06cf9ce8566b40f4a6543b25bacddc926863fc0fa2007d6d7bf6d18dc98df696bd0865bf0be4c492b8043a32def8e3595ba7da345252f38f95be10fd7fb899b498fa01b09de5d5608eabc44a721aa04c4ef1dcb86102ac5f5f79c9708dcf5c5e896edd8c2c7bde3fa83e6ffce22d66174e31657a0b6361585e669d3031952f08631ae1f16ff90b90d0aad3c6d7e1dd0a9c41ab00a6e1c4f96af9ac5b79fcf821ffc016cb059245fb78dbe6c633d965aaab5333be07195c4b74b18e4600ce783c0a914ef4281016e80a7c9aa92d0fd789879c5e6751125ecb154432311e41cebd4fab3a31e4d2ce22d0f8c67737bf8a0dd85fe1349d5079a4d5feb3fee9378ca47ae46cc58a3f02038cfd53c4cee9cc4270cebc3d115a39c831e8ed41c4dbe4051b51d7872ba0c2bb163e0085201188eaa624a6bea9400a3a1fcc355a57f15704e61fda55a5dbaea8448fa5cb2d377a07f58305ad107e844ab4806e5bf99c1f513ee1d0a2acc04549f0801742169a77971d0adbfbfe0dd2ee5d16bc461e35748d1f3f6f4598321e8c49e79e740f990359858d2729dde007fcb26fdda9aa6e2ec4bd736f2836e7e4c83440191c849f6a53c72a4f8f830d001ea3b18f3cb4a5bd3cf066032b4932cfd2e62a9b55723fa61c688c935518af6860cd649bfbf1bf5fdc1f36dcaefaa157438d1cc8d56a150161511df82631f5e88e773e4ce263f276b7b3678d4c6fc75311d411c0d01bfdb595bb70552838e1b86517c837d909e772b428599e1fe569f77ce61531fde6fd31cdce1bdee4ba467fcbfbb9feeaad99fef67d4906e036c73662ddce158d4e5d4635e5d366f79f31a19d1b3dc4a591b0df194bb06c18147f41d88d1a409becdfb67eb063d16312266fd51b521ba9115e2e5e2aeae6ec511cede13ed4132ffbe0273f6c7039b3874f058804a54809af60557a21d9b4b831d04156a7c22dcbcdfe14f62437f449cb5ef12bf4251d485496cd835c0c2bc58bd845963dfa76ecd68519c4bdaf110be7ab052876dc3407591568c956ea3bf107c90fd5853a292f59a8d4b58b5d3fddf29bdbeac36852e3c69766fe460176a801831292b8e88a74a01ecbbe09a7b4d74cfd7fd628841944d9d556dbd60c76f96f07dc53443805ee9aa09365de4fb8179252c6b099b5dd351fdefc23dbd8090596c5d208ffd2c5661d8e5612dd574fc69045c769a969e600d77cfe192f1d3ae911289355c585811491b0ccd73692ab158824ab9edf8ac8193f0b33e6138b72c6dcd5d344f807b3da92425037de5ea4eead1c795effaa145e2ecdd327606eb2609929b9474b2bb04653602555c068385e92f06f29ca613ce5b4404f01ab1805db0acaa890330d291f40692df382509302b6dc8668f2c8f2d3a44fd58dca26e9802794f73d25b3149e6d576441"); +// byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); +// byte[] s = Hex.decode("eea01acc8fe6631c9260996def0c75d84998cf4512c7b67bc4246bbfbff165a404d02bca30da1c2b61d91d7986a467fd4b3a1131077ac138b4011ef07fc1f3ca6237e7fc6550c7e071c939f4554f265362eb26158ee1a2e57c72d20beb78168d9e2d7faf54763755a44bdc29e575884133062453a9e3e761a13a82143d7db7215ab0b8628c096e0f298491a8d67517ab8a90be7db5d311eddc7e883d50eb873decd9b3e420155008c0a3632d51f93a9c67ea336273c8f26617c7cfa2a3aa6d9aa075e75fc60fb587fb5522cb6bac4ef1979a069a15aed3171660ce5da2c27af188e9d3bc62eebdbd798f1a650c7d46411e3cabeb27be3ae787b5f4d82a2e2cf4eee84b4fc82edea4533a47bf7d3791933d1c5ce19c1792a6420c9dcd540dc3a494d9b518ce5f4f85d7747c2fa45d812d16f089682c57a96061210c942dbaca8dbde509f56f498d68f0b4e6f4a51373c9f5a5db2e20ec8254ea9d59f69d732fd1b1149fbd0b608368086a3b6acbe5de156fc508390ddc9ca28d201fdc67140a767b2d99d08051255e73d423750e91b1aa31982cc7014e46c75b69ec972f15745bafbe4878f73d8800d80ad22716f15f4d964f0468e8583add1a4ba8f544e9b83dd6c5ebf744436e254bd699e8909e712d9f6e69fbda39be69a4e0bb58cdd0ddbd369cf5a6475b1ad5fe2849c439611516bd13de14b34b26a731c5a5bde4fae538782a6daeb6fbdaf4cf1af40f3b9c7896e87ac71b3fc95eea02f2f28bf62b9d613998ad973added64515a699fc89304b8fe4d4c97759662b720835c2b28585648e54dedfbfa40fd1455e8a945a390765e3b1a2588286bd4f2995eca39ce9eca6d2e32d92e18c930e4b99109f148db96f1763703aeb431c3c815d577c2b0282181932bb182325bf45e1355d91c8ec669ccd94429dc4ea0abc562988bd2b27b39f2dd0e4ace6fc9148cd064005e9cf0f8105a6534261942774c2a02f150f8d250822745b1cc40e1d57c68dea152c0f5088712266e5a37eb7760204c2747561688990d3cf7c76660e5671727c7ebde56420c91549a48b3763062ff92a4679e7d3e8569303eeff650c0ae606234d70a350aa9862b912825b13c1ec7bd6bf346717b0f30c45c1925873f04d469fd28f82f19375531ffb83851c471ebf623c86130d929e739bd8721d97ca9a83676f26c0a75493b5b02f0921aea91baae2da96532ab9db04dc997d5f800f58a891f6ef26e5478de1ce9b4da04eccac4cee81de5c3b1010ef28242217ec737beb36815c4af1de9a4160180ea896120ce96869bf551bb6be079482f4ab5c0f7f234c50bb4139ff9fba1b594c85cc3780434fc00f7d0492cfc86c0d1889784b113650e3c29bb2e9ed6f94df5ea42afac8060856fb90fab5f4c6fb6875fd67e0438335bcd5199b72706cf358492e5f4945bf2a686aa2861908d6a71ba4e760c87e75a7ff31169993cf048817512aeac4e960771879be541b1adcd6c2da9f9d2153e728d4ee1e91acd7f704e0b472856cfd8f85e2f30b0f6e427f190dbc1079343fdc71f9ac0b8aa5e6fdfd60fe9c90e4bebd4a91dbf16378bcc2a330aeed5b7e8dd617fbf3c6ed9b2c2ac82f2e9d03c975b2a832a667864090da9ca91ad1af97278f6cfebeaf2cc681957f3d75d17a5710de85444b636cf7e0dbac06852fe669f87bc7c430ff548ee0b34f1a68e86f1b26290f8a056c0bccd18a540ce04ee7fdee47f5176b811021a89d170e71250a040e10f8f900236617c6be92217b77aa00854d6376739d5a63d32a377da20c368092367fc6afb62e0b898c01462a399aa3dba4beb0d03d7f8a2e84b499a41e7a6e50cd5e09b4d6d8cb3e8ee3a2d1b50775f9caf7335f1ea15b2312352831418ce2529542011a19c6ece5c1e6dfe7e37821933594ca6f55ca6c799b32f88b21d59744c10538ea7208eb61a04d24476c326068ac9ad4199080e02b95766f6a18738c7e4506d18e9c5c526ef4f28ef14662667dc865ffd446026cefca1b39be77cdfd7773aac0bf570647c21979b9f0ff0d67f2a9940e1e1c27e9e3296c7d890c5627e9126fa09bed1f242aa23112d828529ce431939c9ecc0d4311742a1fa5f9f283eb0135093d3e6aa9e89d4641415678f0b2ecb1210a611d062c5e17f01521aa45d778e2a0770cfda540ce1b5bbb3fabfc783601480b080f4e7275e69705b6cff043a3b503da77fbdc05702b790b1cf4dccfb6b2df00bf0ee896420175e1293a6b8fbc96cf9759a6c0e56067dc9e2522621af2cf830e2bb648f0ca3560bdf9c2c0c01bb23806455bc40889472398f9daf71f0ab9e1aab2fe8d6c8c504a1a45d99229828a9588a559a7172b041b2bbcdbe2e59b749b3e1219abf51a39164c9fac17bd8c83eab1e0e04e029550b689134194d486083b956706a6706274324d63ff79c35f37cf8c2932910e60e1da7cc6c4d9b966fb11437f7d4e94221e4b9ce51ea04325e4b75e45dbbbaadeeadd432e776c9b14cff55529c24b43211b52d1f27de0d86c0f253ec3c2262fdfb1ecb18442174321bbed4c1454522d747be4f53f9ea445d4db360c5c0ddbac51179c7f6016249bcadcce47d4abaf0604047d806f556d11aba411239a32a80d4403c72198036917b6c3b9c5fefcbb73b4d11cea0cc09b419ab8bb0a093131b4c32280fac586bee305e14a18432bbaf1ad6ffc67863edd564df4f9518c6363b80d83c59440bde98c2eeed939bfa1d8f720a805088e2090ab1af71ad5190978b2e23a7d58fc28ab2ed623f2cc65d67629a2fbbe84309a3e0447f3805728155cca522217f9e66b5b2d794fec7131b091f7f77df37e8d726f150d416018941a7b48617fe291a3a3594df80bb1927d87d8f8d5cb945c39c977e7a4f9882e3facd6f26e42390a1f7d14e55797bd22ae78ac11208084be07399d2f9cd2fa331784c5e65de766d87c3d19aad2c7993485e65f11b2c03533f265d9268f8d7f9ce14f97a76891e2b764d2e0a7baf2f81c6fcfd15c78552bba4952fe375c9872a25fddfa19a29695320858fa8a910c29d0739edff01da6d80f757906f7103984c4910c44220ce83fb5b46527c918d186b5c096ea4d1c85df71b4e7d625bb2df5a898880a18238eb4388f66f0d5daf074bdfc6e3b4695ef5faaf754ed764b80463d724d1fc41b598861207d1971cfe1e857cf2bf8dcc4afae1e44c622d96194d3f85fa5a37aed9a154074fbc54d50724658678dfba30bce2fc853bf87f7379d80865f08f0a772afedd8f45808b49605ff3d2875a6ce7b90f4a61fc55734f791bf2e6ed554309111a385158627d7e828491a2b7c6d1f00315162c42435b62656f89bbbcbfe1e6e8f0f7f9000711123b5b6ea7b0b7b8c9d2e5e9f5fc09727a9b9e9fb3d3d6e9ebf4000000000000000000000000000011253642"); +// byte[] seed = Hex.decode("7c9935a0b07694aa0c6d10e4db6b1add2fd81a25ccb148032dcd739936737f2d"); +// +// KeyPairGenerator kpg = KeyPairGenerator.getInstance("HASH-ML-DSA", "BC"); +// SecureRandom katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null); +// +// kpg.initialize(MLDSAParameterSpec.ml_dsa_44, katRandom); +// +// KeyPair kp = kpg.generateKeyPair(); +// +// SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded()); +// +// ASN1BitString pubSeq = pubInfo.getPublicKeyData(); +// +// assertTrue(Arrays.areEqual(pubSeq.getOctets(), pubK)); +// +// PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded()); +// ASN1OctetString seq = privInfo.getPrivateKey(); +// +// assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(ASN1Sequence.getInstance(seq.getOctets()).getObjectAt(0)).getOctets(), seed)); +// +// Signature sig = Signature.getInstance("HASH-ML-DSA", "BC"); +// +// sig.initSign(kp.getPrivate()); +// +// sig.update(msg, 0, msg.length); +// +// byte[] genS = sig.sign(); +// +// assertTrue(Arrays.areEqual(s, genS)); +// +// sig = Signature.getInstance("HASH-ML-DSA", "BC"); +// +// sig.initVerify(kp.getPublic()); +// +// sig.update(msg, 0, msg.length); +// +// assertTrue(sig.verify(s)); +// +// // check randomisation +// +// sig.initSign(kp.getPrivate(), new SecureRandom()); +// +// sig.update(msg, 0, msg.length); +// +// genS = sig.sign(); +// +// assertFalse(Arrays.areEqual(s, genS)); +// +// sig = Signature.getInstance("HASH-ML-DSA", "BC"); +// +// sig.initVerify(kp.getPublic()); +// +// sig.update(msg, 0, msg.length); +// +// assertTrue(sig.verify(genS)); +// +// AlgorithmParameters algP = sig.getParameters(); +// +// assertTrue(null == algP); +// +// // test using ml-dsa-44 for the key, should be the same. +// +// kpg = KeyPairGenerator.getInstance("ML-DSA", "BC"); +// katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null); +// +// kpg.initialize(MLDSAParameterSpec.ml_dsa_44_with_sha512, katRandom); +// +// kp = kpg.generateKeyPair(); +// +// sig = Signature.getInstance("HASH-ML-DSA", "BC"); +// +// sig.initSign(kp.getPrivate()); +// +// sig.update(msg, 0, msg.length); +// +// genS = sig.sign(); +// +// assertTrue(Arrays.areEqual(s, genS)); +// +// sig = Signature.getInstance("HASH-ML-DSA", "BC"); +// +// sig.initVerify(kp.getPublic()); +// +// sig.update(msg, 0, msg.length); +// +// assertTrue(sig.verify(s)); +// } + +// public void testHashMLDSAKATSigWithContext() +// throws Exception +// { +// byte[] pubK = Hex.decode("dc7bc9a2e0b6dc66823ae4fbde971c0cfc46f9d96bbfbeebb3470ae0a5a0139fdd6a6ce5bc76e94faa9e9250abd4cee02cf1ee46a8e99ce12d7395781fa7519021273da3365519724efbe279add6c35f92c9d42b032832f1bf29ebbecd3ec87a3af3da33c611f7f35fa35acab174024f118979e23bf2fe069269a2ec45fbc1b9c1fb0e1f05486a6a833eb48adc2960641d9af6eb8b7381b1ec55d889f26b084ddfa1c9ed9b962d342694cede83825309d9db6bd6ba7582132534861e44a04388a694242411761d34e7c085d282b723c65948a2ac764d9702bd8ed7fe9931d7d8704a39e6508844f3f84843c305594fe6e5404e08f18ed039ac6563cbaa34b0ca38320299d6256ec0f78d421f088159d49dc439cbc539a55884a3eb4efc9cf190b42f713441cb97004245d41437a39b7b77fc602fbbfd619a42363714b265173cae68fd8a1b3ca2bd30ae60c53e5604577a4a3b1f1506e697c37432dbd883553aac8d382a3d250cf5b29e4d1be2cbcd531ff0e07e89c1f7dbc8d4529aeebe55b5ce4d0214bfdec69e080bd3ef36cca6a54933f1ef2f37867c0d38fd5865b87929115808c7e2595458e993bacc6c5a3b9f5025001e9b41447708bfbaa0462efa63876c42f769908b432f5485508a393224960551d77eadfaf4411cbc49fdff46f2f155ddd6ec30867905b709888ca0f30f935fb8d7f4803cfc7a5f7790ca181d99ca21f2621d69a5c6d49c76b4969da62740a378470332b30947ab31ccdb9ba0c7b625879eec4bd81f0200ba23504a7dc3b118bc2ab1145df13af3c8cc39f577873b84911b3d85fbbf4cb19e4d36b10a938eeb78b599dc86615fd6cec6eb7b8f7afa5f6d6be19ea81630d36ccfb2f487de50d0cf46da8d3fe3512812043c0e3ef2d7231fb0b0a35a0fb283be30a1247780f30ae0294e8b6f5897383edb895595f577524df54593cdf927b4967616ee3913e4d6b29b0dbd7c33a2a45e4ef1b1954ea5d91ce37efc1302e7ce02a97395565da2a5c5d3fdb0d87684e9b1c0ad07ec33df2dfad528e2ea0966d2a47dd5ee88e77d653c0d004fab0165f0757c4da40af327e7192536c79947a80a827aa2107dacfae3debfc8fad3d6e08076d938c510a276bdf6721a1f087cb169515028ad5ce27a1047abd92809934ca63b893f71f9a34a99c0fd30310c47e9aa37394d0ab73b254d3ca69d9c5549c9479aae24264ac5ea64d3fd821c3962ec77e709f9d30bc7b65a52e48c16e80603558caca1811411c3155d1f949fc9cf9aa9385a7199e99be77a66fad7eed91258de55b2c4c83f9a050adebea5f09758f40dac4a1c394ee8d687879150d26426895ab1938e14ae11b376254c91fc6130436996f8ed43bd27be20ec9067111c116ec94cc2b06cc91a13c5d10bbd7eecea4792f17b2b77631ef145e9fb41a83eaa11c2b72a48fb90fdbd88644c4edf8ab20dce3118364b276ac1237b36c8926e346aab5a111aa0bf341c518b7bff9e9dbb8bcb4728601b3760663e67650331e6fb54ac82fc414cb8ddfc160a25311ec5272de46217fef8b992ff89754fbee351f21bb90b6c97078b510c983350681266c8fed1f0583c5151e7b8fe3b7292319699687cc6b641fdbd689428543bc0fa1facc109de65b62784c2d985ab15d77d3af12af6d03e8d1859a553688584d75ef673a1de74093ee108c761fff32c217c231b0e2953daf521429264c0963bc8a5cdeddc617a7285b934ea51ddb5cdab23bcede86be36e001bc65c65e9a1c94baff4fab8eb5f8ed42ec377423633fe00049142467c47c5d58a7202c8e9104841c1f7f380145a6a0a828c570235e507ae5868a6062f722bb98ff6be"); +// byte[] privK = Hex.decode("dc7bc9a2e0b6dc66823ae4fbde971c0cfc46f9d96bbfbeebb3470ae0a5a0139ff037b84e75537e0a1cf02a517acfe323ffffe11df72e4f38430e0e66a2654b2f2ef757da47649d9f63fa03f1bf6fe6bc7c62971a98a2bd9d36eb0ec43ad4e9d940df3bb5874f5c92192aa31e0535d3cf70950bba858d11a688eaf854f63ecfc520c50d624891434265d8b0680c03061040299a104082c0910c8508d1100d44a6509408292211125b90508a2688e1302dc4021280028ac302611820851237808a000ae2040421b4910bb80550a08051b2511c28428a3672a494504910201bb45161424424a75001328181942d62a850023449ca94200b296213156408924c48122100b605030208e0060200a311e1802021116483a62898029291480801083041066613200e5b360951400c53000aa08851944842e316704ab2089b92440025121b0309418209c2a0800b290a819851c4340da4424500a0105b048e603400138928a4422648002c90202d194068e2146d19278a083746e4146914006422c660d3a03013242844965014166da0284dcc462e94367100232e1c114909a2040131060a2172c2142ada000c5a260d13228a62c444e3142d013445980224d33841c0308121a621e348720b1984d2c89108b8690887714a2884d496451a9301ca2285da30859ac851dcc00820106060465262302aa224251044640b2842988011540692144251d236719bb4900b082890188e41c469e1a469032160e01409d3020c20c88c1cb23164086218476920228ccb8470089528029550533270013405888424541041d202881aa84ccac88181008d0392899ab809d9900c9a1290614065c9322d89860c123521cc4266c8360010062411028ea3b44d44023043a0285a002ed1980c4882658922441c010212907084226e12134d011902519064113364c91806c2c04589262908b63024308cda022e0c27250b367058162c5116420b4946c1208841246c99466a04434e18a86c821661922028639409c30211029520211782d43868003460c84688e0160000a32dc0a82824b640831464c81022a2086503234ac8122ea098418c2072cc308a62c665093408412682da429089328514967081226001176d5948428ab88d592051d80892e2c0889044700ac0245a020904218a59c45094441094140820460209270c441020dcc8209212015038250c456e4a1666223770dc808ca426412222441ba3618a343099844099c42952046d88146ccb242a7cd129a8d333115c62d033b6a8357cf7cd10268ab12f16fceb7975d0a28a6c4822213c9a772df084ad91a669e2040550fc5e8d0aeb10fab2375fc9625ef9cd48c19631997a1cb6455d2c6286c569c9637add0317ce990996b28e51c3f3f717fb5907bbdd53961ad3497f2c3c473cce170906ac4c624a89aa8fbe624d99385e9c9548bf05e8cafd47d2476e41b73001f813726499e88b2b3b6f596ca311657850346598994c40e34747161e4e76264deef2a3019389d1594c942301af47b7544c23ecda2df2dece81e487d8f3f58ea89cd811d7275807ff1b0369ba86470088c174a3099fdafbe5fbb4d158801053b2b435d54059e26dee76d10a7a372f06b0b88b985b32f52052387438be8dc8bc6ae7369e2da9aa5e2585f8de403d091ccb7f790d54ddb34c608b0876f2825e9113be20a2b85867a01bda53287ac780bcd8b606d2e6d7712c56ce0142d22fe6b786de544963e134fecedfafb83d763061d799096a59e30d4472e440ae1faaabdf42640ce69740ceb9cae1a9612c21931b74af3f780236123321b205b6efd6cbb134f4c73d63c0c13e660b59d5920bc33197c355853d8d1cddc7959f7bc500ac81d985016f5b89a0eec79b0d9364ead8e38577c2a6549f2d067cb09438fdb21220aec80f6e22a476f332a2a4a0b7acbeb9e078d2b5a92ae84c924f7cb19fc7df377beb6546af97aa985c747cd111a127a674b4c26d89c14485b82e3a498a12d05406febd6c4d4b8bc051ab2cb91224b078538374b794b7dd9ddf3ac2b4a671fb7b9cf5acb78622ae2709eb2db16943aa24a9c97a81077bc784d25c0ea5991d2de883798a1f0e78f3361ed6a10dded81b1d683658331534fd7c01bc0eb00dfc4c3c84f0693046ff806bb200dd7bd4c0e6abca3f2934b4814fc0e1f8be615a2dda7c8a8d06cf9ce8566b40f4a6543b25bacddc926863fc0fa2007d6d7bf6d18dc98df696bd0865bf0be4c492b8043a32def8e3595ba7da345252f38f95be10fd7fb899b498fa01b09de5d5608eabc44a721aa04c4ef1dcb86102ac5f5f79c9708dcf5c5e896edd8c2c7bde3fa83e6ffce22d66174e31657a0b6361585e669d3031952f08631ae1f16ff90b90d0aad3c6d7e1dd0a9c41ab00a6e1c4f96af9ac5b79fcf821ffc016cb059245fb78dbe6c633d965aaab5333be07195c4b74b18e4600ce783c0a914ef4281016e80a7c9aa92d0fd789879c5e6751125ecb154432311e41cebd4fab3a31e4d2ce22d0f8c67737bf8a0dd85fe1349d5079a4d5feb3fee9378ca47ae46cc58a3f02038cfd53c4cee9cc4270cebc3d115a39c831e8ed41c4dbe4051b51d7872ba0c2bb163e0085201188eaa624a6bea9400a3a1fcc355a57f15704e61fda55a5dbaea8448fa5cb2d377a07f58305ad107e844ab4806e5bf99c1f513ee1d0a2acc04549f0801742169a77971d0adbfbfe0dd2ee5d16bc461e35748d1f3f6f4598321e8c49e79e740f990359858d2729dde007fcb26fdda9aa6e2ec4bd736f2836e7e4c83440191c849f6a53c72a4f8f830d001ea3b18f3cb4a5bd3cf066032b4932cfd2e62a9b55723fa61c688c935518af6860cd649bfbf1bf5fdc1f36dcaefaa157438d1cc8d56a150161511df82631f5e88e773e4ce263f276b7b3678d4c6fc75311d411c0d01bfdb595bb70552838e1b86517c837d909e772b428599e1fe569f77ce61531fde6fd31cdce1bdee4ba467fcbfbb9feeaad99fef67d4906e036c73662ddce158d4e5d4635e5d366f79f31a19d1b3dc4a591b0df194bb06c18147f41d88d1a409becdfb67eb063d16312266fd51b521ba9115e2e5e2aeae6ec511cede13ed4132ffbe0273f6c7039b3874f058804a54809af60557a21d9b4b831d04156a7c22dcbcdfe14f62437f449cb5ef12bf4251d485496cd835c0c2bc58bd845963dfa76ecd68519c4bdaf110be7ab052876dc3407591568c956ea3bf107c90fd5853a292f59a8d4b58b5d3fddf29bdbeac36852e3c69766fe460176a801831292b8e88a74a01ecbbe09a7b4d74cfd7fd628841944d9d556dbd60c76f96f07dc53443805ee9aa09365de4fb8179252c6b099b5dd351fdefc23dbd8090596c5d208ffd2c5661d8e5612dd574fc69045c769a969e600d77cfe192f1d3ae911289355c585811491b0ccd73692ab158824ab9edf8ac8193f0b33e6138b72c6dcd5d344f807b3da92425037de5ea4eead1c795effaa145e2ecdd327606eb2609929b9474b2bb04653602555c068385e92f06f29ca613ce5b4404f01ab1805db0acaa890330d291f40692df382509302b6dc8668f2c8f2d3a44fd58dca26e9802794f73d25b3149e6d576441"); +// byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); +// byte[] s = Hex.decode("42a2ad149a7f35856ed92005232a2d33dc4a1ad0cb0fb7b772f56956082fb9a630fd7284bca55b5cef3a55ad73c2225d7c2d143d0023cd988890b81c271b97e6ed99250bd141550e4eb0276d4a59f19023d0bd725fe2c4f3301655ae91089851db6ecd24bc448ac06c1bbad4254bb1370678858586d55ffa4a9112dd48fd14c224d35d9c2987dc8bff84578d9a5fd0a1e34f7fb34523a305f623cef1766ac8b336c6c1a062f8d273e4f5636969c8c5afb3102436f9549a68ceb5393065944f0a231eb53ef7c6d3bca1fdf2544e3637f5efa96752455e4816d8747c5af14d3996eb241b2dc28fff9a9d93d148193195a87d6763dd94a5d9dfcd8623baf73ecebf545291bd236f44a3b9c5b8d231b7d7e991f6fbd67bbf3740611ef64c66765e25dc0e968900c407565097adf82f7b2387d03f93757a88c1a7590fdca09e19579ecc124629a26e80851b1ca5f29bff6ed37fc779bfc304e93169004b7c742ff4ab9ead2e96e313f1ddd8f6f94d58298ecd2393e119f5536d46e934ff11323f06df447685fbc1f8017a1a98ed717c8c7e4aa9be3b9f0c9f4e43c802c9542a26c013a07f5dcf2cfac584e8a998712cb6f00d4e51f9a3d65bac5197b49bd5291db44fbb90160a364818548b0bb59d34f48fbfc86b7f9d765a427074bee154dacce37f2bae727e99ec55bf7b5d618eebabc73cb015d18c6ba4c45a4c5f8c8802beceb9fd183989f4ccd3964a995a19a4a4492ca043c4be3ff76505d97174db15e15d56acf3e78147c0136373e784d627360e1ad41decdbb5a92cf271cba3a969f366ef53fa1150a1514b18b8c6835a44c9139456c162dfa59e525892e38ad6864097f5108752b4b8d3f847bdc0c185f6da216da8ee00c06ee8b54d66adfa85d2f8851ecbafea5d063604d6abf28a0df4042d788cc539cbfce523f1183dd7c955990ef9709d9db2d28a0ac55382b92b3869ae40072119278e005be9acd8b30507d55a065815db29fe5ad0ded3094d9e92762b1d52a7790e146d4b4b7e81389af5e1bff9485ba72ffebf902aa343e5ad737f57bee177ed8514f0549083407f6a645234be6ece678c59f905e3af7190602e4c1d8815a28e791d476c10ecfbcfc9539e995e72c8cad9f7b515a53e0c912be7071c13c2d350b1965627ec610e17bc52c13108dd3f2e2fd703edf13d76ee62d904f45d6f89b5814a6570ab5e041b14186c63bc0b93de643aa4828ae4747c964474102cfb77aed3412248c67a8fbd2971072058ddda17df2b152449c63b164dd1ca152c893e38afd042d9f186e677969dc3caa6d2105b54d7e8dc47bda7f63606e8670f3f671b0e43d1cf0884cdde011743a9748e50b66cebacfd4595c346a8229883fd92945e65fab2c9a1dad85d6ae11ed3dcd07dbe1bf031fce1c23f5d1fc61dd970b40dec577abd5b2bb697f6b24406ef7d623b45b0a96a79a8171805d599ea99fab55682eba390c0dbd7f53999ca7cd5e4e471139b5e877be6fdcab79ba7cc7693a07bf537f4e05669a977610d2f526e7ed6edf75164b09e6ed608ec755744571694218a36ad96362381fbfb967ec0e0180fb8efd4972c8614f82e262e0628a083f360ed927dc85b9b95d5c53eb371848f3ee1c7dd069918f74e7a1f25fc6f955e72be0202a401e28c7fc20c8378469b6bc370700b6fce04224a3f3815598f15f44ad95972208c215126753db78fa84fac87b62da8b1249360ff2171643cb100c07f8caffbd9aa4d94b0b192eb49af6c9d3b68357d708d597004a178c116efe72f5ec80d2269c592e65eb12b5968f3c153bb900ea3d49a91e155dc38383844bb849f8f78c9038d30ab7b6719830a7667a725f67b6318615b37f0d0a2dedf7e2f741d1807abd4614087449ce789ff10deee23befcac04de3376245143f24df1a1f95d7442439b2e6f983959598c95577e2d262e96f8fa4cc4a1fd59e2b4d9c4394071630c2e0569c4fa3784bfb0d39f42e366c8fee583412be0c6d4c67fff9d570926210fe632fa125245496af25cd084d723994c94e2ff659637784c31e9a555a788c8fc7410839ee1c6e80544d825b79fcf238afd1c0d6be0fa32ecb8b93463d98b9f2b3495c81f25877a613227bdaf8b94342da81c0f2995872a5a75341503bfaec2bb7f95db0f340f4732a832f4effab9bf4da476528a15fbfc5104fe3dae3a5fdd05ebc42989d96f1eb056c3ffc79de35d229a55e301c33975b92c4a7de50962a2fcb83912441189ac1a4e4ad38e30ecc3df084f0ecd8745750323debdea86ab87e725d41fd044fd507f279e7dfbb6a04b34cb150ed9fda95d7393cf8e611589ec56a5dc9a9de4dc80c36e7cbcfb77501bc69b93437ce3642ee35da9a0d71b76a641847fb9798e18b1d073a7b832958f65079648b47370bfc175869dfc412b0b3074fc43d608acd2b602f7b9d2fb831c3a37de56600a34135a1d029bb5f582732b2dc45f992c4a6dcc2c3b1cad807ad4e741490b5cad74a6e7a416fe91b1ad216c428558c3f8d0797d4acca85ca864a5194cf1273622ffeed9624f702b4725a93057a90d155ee081183d87517123647fbd31216b664107a124adef5e1dbedb7e714f6b49696fa21a4a3c2c822cc675b2a171949cd64d10fa188913a9e3318dc9829aa3e6bdeac781afd2b20211c6aeda61deedc8ef7d1426f7cf464af6a700bfce3e0df99f417b1440807870ca0af461cec38cde60e6861f817901a56db98af64e9be3648585513f833a3e5c6fedc613dfff720e76a0800139d53957b1f91e7efcd0e6308613740705e589d48934f5e9a193af901b3335e767310830ebc6662ef8d33e7c87e242b65595c61212f9ac459c09995cf4a996584bf473d4c58db901c2c994f62e6022720987e653d1e3100a84db6e077b9e4387b9df33048d201969b5fb215cb142000bb21e7e5cc3e74b934cfb80e9d117fcecb1c68479390f173cb8e33853f66a51d157287324b3f8a590e40646877c5435e3251fdd5c19791471b51f07c5265dd79aeb2997545e7a3c7b6484f34734871145260d019b28692be1357ff27b9361ff90c1e5f308a1832a900dc915c3771cb83e964e99667e5e46a713c152ce2e33d45ef4050d34671391ec20f93fcb9b9597781e1ca4d4ba1762fced1f9a06311905c6bdda492f72ce9a1c9f20cc26d020aa0a3cede4bf35a7735fe41d1ae0e0ecbb5da8ccd68f37c7acaebc1f8fc764db3bed1dbf4053911b9105e09605de322fb8750717c756330856835ed2c713ff7957f8a99f7ed485e480949b2a9b9d1d8acc0eafeee71977a56a07132c495067aeb7b9dae1e7132036424b7993949cbfd2dedff91b42494a555d6a72757aa2aebfd0f0fb161a617c8890a4a5afc0d1d9dadef300000000000000000000000000000000000000000000000c1a2a39"); +// byte[] seed = Hex.decode("7c9935a0b07694aa0c6d10e4db6b1add2fd81a25ccb148032dcd739936737f2d"); +// +// KeyPairGenerator kpg = KeyPairGenerator.getInstance("HASH-ML-DSA", "BC"); +// SecureRandom katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null); +// +// kpg.initialize(MLDSAParameterSpec.ml_dsa_44, katRandom); +// +// KeyPair kp = kpg.generateKeyPair(); +// +// SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded()); +// +// ASN1BitString pubSeq = pubInfo.getPublicKeyData(); +// +// assertTrue(Arrays.areEqual(pubSeq.getOctets(), pubK)); +// +// PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded()); +// ASN1OctetString seq = privInfo.getPrivateKey(); +// +// assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(ASN1Sequence.getInstance(seq.getOctets()).getObjectAt(0)).getOctets(), seed)); +// +// Signature sig = Signature.getInstance("HASH-ML-DSA", "BC"); +// +// sig.initSign(kp.getPrivate()); +// +// sig.setParameter(new ContextParameterSpec(Strings.toByteArray("Hello, world!"))); +// +// sig.update(msg, 0, msg.length); +// +// byte[] genS = sig.sign(); +// +// assertTrue(Hex.toHexString(genS), Arrays.areEqual(s, genS)); +// +// sig = Signature.getInstance("HASH-ML-DSA", "BC"); +// +// sig.initVerify(kp.getPublic()); +// +// sig.setParameter(new ContextParameterSpec(Strings.toByteArray("Hello, world!"))); +// +// sig.update(msg, 0, msg.length); +// +// assertTrue(sig.verify(s)); +// +// // check randomisation +// +// sig.initSign(kp.getPrivate(), new SecureRandom()); +// +// sig.setParameter(new ContextParameterSpec(Strings.toByteArray("Hello, world!"))); +// +// sig.update(msg, 0, msg.length); +// +// genS = sig.sign(); +// +// assertFalse(Arrays.areEqual(s, genS)); +// +// sig = Signature.getInstance("HASH-ML-DSA", "BC"); +// +// sig.initVerify(kp.getPublic()); +// +// sig.setParameter(new ContextParameterSpec(Strings.toByteArray("Hello, world!"))); +// +// sig.update(msg, 0, msg.length); +// +// assertTrue(sig.verify(genS)); +// } + private static class RiggedRandom extends SecureRandom { @@ -645,4 +933,20 @@ public void nextBytes(byte[] bytes) } } } + + public static class MyContextParameterSpec + implements AlgorithmParameterSpec + { + private final byte[] context; + + MyContextParameterSpec(byte[] context) + { + this.context = context; + } + + public byte[] getContext() + { + return context; + } + } } diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MLKEMTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MLKEMTest.java index 0ad4e0289f..4fe14f5536 100644 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MLKEMTest.java +++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MLKEMTest.java @@ -6,6 +6,7 @@ import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; +import java.security.PrivateKey; import java.security.SecureRandom; import java.security.Security; import java.security.spec.InvalidKeySpecException; @@ -18,8 +19,13 @@ import javax.crypto.spec.SecretKeySpec; import junit.framework.TestCase; +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.jcajce.SecretKeyWithEncapsulation; +import org.bouncycastle.jcajce.interfaces.MLKEMPrivateKey; import org.bouncycastle.jcajce.spec.KEMExtractSpec; import org.bouncycastle.jcajce.spec.KEMGenerateSpec; import org.bouncycastle.jcajce.spec.KTSParameterSpec; @@ -28,7 +34,9 @@ import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters; import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.util.test.FixedSecureRandom; /** * KEM tests for MLKEM with the BC provider. @@ -117,12 +125,102 @@ private void tryKeyFact(KeyFactory kFact, KeyPair kpValid, KeyPair kpInvalid, St } } + public void testDefaultPrivateKeyEncoding() + throws Exception + { + KeyPairGenerator kpGen512 = KeyPairGenerator.getInstance("ML-KEM-512", "BC"); + + byte[] seed = Hex.decode("000102030405060708090a0b0c0d0e0f" + + "100102030405060708090a0b0c0d0e0f" + + "200102030405060708090a0b0c0d0e0f" + + "300102030405060708090a0b0c0d0e0f"); + kpGen512.initialize(MLKEMParameterSpec.ml_kem_512, new FixedSecureRandom(seed)); + KeyPair kp512 = kpGen512.generateKeyPair(); + + PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp512.getPrivate().getEncoded()); + ASN1Sequence seq = ASN1Sequence.getInstance(privInfo.getPrivateKey().getOctets()); + + assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets(), seed)); + + assertTrue(Arrays.areEqual(ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets(), ((MLKEMPrivateKey)kp512.getPrivate()).getPrivateData())); + } + + public void testSeedPrivateKeyEncoding() + throws Exception + { + KeyPairGenerator kpGen512 = KeyPairGenerator.getInstance("ML-KEM-512", "BC"); + + byte[] seed = Hex.decode("000102030405060708090a0b0c0d0e0f" + + "100102030405060708090a0b0c0d0e0f" + + "200102030405060708090a0b0c0d0e0f" + + "300102030405060708090a0b0c0d0e0f"); + kpGen512.initialize(MLKEMParameterSpec.ml_kem_512, new FixedSecureRandom(seed)); + KeyPair kp512 = kpGen512.generateKeyPair(); + + PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(((MLKEMPrivateKey)kp512.getPrivate()).getPrivateKey(true).getEncoded()); + + ASN1OctetString k = ASN1OctetString.getInstance((ASN1TaggedObject)privInfo.parsePrivateKey(), false); + + assertTrue(Arrays.areEqual(k.getOctets(), seed)); + } + + public void testExpandedPrivateKeyEncoding() + throws Exception + { + KeyPairGenerator kpGen512 = KeyPairGenerator.getInstance("ML-KEM-512", "BC"); + + byte[] seed = Hex.decode("000102030405060708090a0b0c0d0e0f" + + "100102030405060708090a0b0c0d0e0f" + + "200102030405060708090a0b0c0d0e0f" + + "300102030405060708090a0b0c0d0e0f"); + byte[] expanded = Base64.decode("WCF6H9yVm+nHHlpz1fOL8Oibz2GOuXSDQhwXrSnDraa2fYB0LxV12Tsp7FggB1xmvIg+GBXJoJcJ6APDuDCqE/RtW5eSZwKLI/cqeubNablS7SCQSORrZiNuVkoGgPikT9hzUDhvDhdE7tuD+cF1UfpECGZOFDFfaKeFufJlX/kcIAwFjgXOPqJrBiUd3BUsb2G81kxyJHfEODauV3p58dAWReW4Wfwzm8CP+OXMAsUiZTlHCzJxbaXFPwCBaokc/8XBd6FUOBLHAjxbVRKvuTQS8JEJLFTHvqYtehik66hEdNUJBfSpRGFalRFjvXp8acFXmluVTQsO6eoTL5pO0nZ1fhetf0RKgzeI07G0xIherqxln1dwj7VtM6WsW6WxZcFHkBQMWFiRUitxJ1QIbqY/1Po6uBEp/YYOPEoe7qMw2hxvadNEf7KiRPq6R+oxDMwnthex94O78ZNoDHiM5PdU4WKj8EkrySo49uS+d/YUnxxGZbSSY+uzTYY7D+w7zcapr0sgmmUIHtYEU6WxmCMFA8NmABySw0xOhJaDBsk5EWK1aZqkM+eqbhYfRwIpFvrKapAi86i6jAadcwm8ASRjmyZmRfCYkevG8kisVQg44TFbP6RYoXoFHzXI3BguJCmbGBS7YFSfwHcIiOybuJWQLqxIZZkPdzlGmnMr25uimbBxyzIB4Zw7HsZfGEGQ3xdAsCRhFskQw0XDHIVWZ9IZN/pofqUlNhqqeGCC6RaRkgDMdrLE8bBeB8WUt0SyXKgCZeXJBshKa3dhZeOq1yWNt5hB/rZKDgszqPmwv+hiZxURg6VUJPEoiXaAsbHBZKWROywm7WeK8ghdsyazhGFbJMdKhAOSYKBgWIBCcUBHZMLEhtm3gNLHdzGx4DtC4dGmJHxMRhFoH5cX/ARlO+RcKteNZTcyT+hlSIgyU/wBgxzBhIwsVmkMYiuPGnmqEAF0+LI79VqrTDJFmdBYGJsdShOV8Ey4JGulmoRN3oyOtvsPPpJ8Qfl0xgJLn6Ns87KcI/MUaXtilMpeYwxS1AwFnvJZGzDKh1GxTtKD87iTzErIgiV0AFojsEZ59AkvjGmFw1jPvhSIXsF900EMc8O2oWArKHIYzXWL2AmfDmmmjFxTW4Ic5xyQejkibiolbHhAb0RYYesI1ZmUnXCjyiBSz/CpgIyFIjqVXAOxGmy5XJdMobDJbhh0xnV3uytNGXuRiYqjnaQTzVEpbNUYXbAdVoFuHfwMKfy6eHIBXoLJFnpdLOEYnYireCYv1mrGYjWsH9MY4Ys17vvIcFSia/Rc+VtH9CJk2bqgEVqK2TsV6KgREaJgDBmj0BRp8ourO/YAFMslxLcLQDqrKtA4JhGcAzhsYjpzQlBXljSlqmFKWmjCIBRFrFaMG+xv76YBaqh+0aEQKOVT2JwNyADG3SonhoUDovo+J9UlaGljwmeaAQCouQZDCXELgreKpHOFaMK7RpQHNjtlv+FuV+k7WnudORs9Nde92Kw13SRSulmQtao1SHJf0VRcvuQu3eMzLLsjluElKqEpvDZX/Cg76XgEptYaEqlMQNSa6fh30bc+GhoyFRGx3zk3zvbGrtrEWiPIacCMeQKMmieN8apjragAiZsGdpMCsfxq1xAJraHB4cMGSix3ZOp8riKumiO4EQwDhtJGu4NXbLC459JkqaEP1HTA/jNpwiIRBsHE3dlOaFE7iJk+znrMXzcG+1fHAXhDatwPEizALupyhTxAiJsCWzxctKFbzouzbwcuXAKqJbldNdRsx+ESaugoN+QKLmEJOJlpjWKFIORE4daWXpoCz4WPw1ADCTiDQ3WzTPQn46tlgDDFwTx60eJk+CAn48Q+eYM3W6SDCtqLKYgUjLlJcakdKMmKJVdIL1A66gtH3jA/oJurjNGNaHK+ZNKDm9NxKrWQ9PmmBAiHsPKqIosLR4sZ6oANC4mtVHK3lZmYz9LI/ejIfLgd7aw1INBupOPPpGmrQqA4LcGgd0mMCVRLKxEqPBRuTDaLBAI8HdJUwsgwI3GrH1ZkAsNHBhmvUdSNjicplOoWHcNYi9U4FZkIifBjHUgGUNUhmw4Mkf3IfeYtJoLtjpYOIjQ3yFH8zzdEKBY74ILHT+BSWiakAyABAgMEBQYHCAkKCwwNDg8wAQIDBAUGBwgJCgsMDQ4P"); + + kpGen512.initialize(MLKEMParameterSpec.ml_kem_512, new FixedSecureRandom(seed)); + KeyPair kp512 = kpGen512.generateKeyPair(); + + PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(((MLKEMPrivateKey)kp512.getPrivate()).getPrivateKey(false).getEncoded()); + + ASN1OctetString k = ASN1OctetString.getInstance(privInfo.parsePrivateKey()); + + assertTrue(Arrays.areEqual(k.getOctets(), expanded)); + } + + public void testPrivateKeyRecoding() + throws Exception + { + // TODO: rebuild with newer encodings. +// byte[] mlkem512_sequence = Base64.decode("MIIGvgIBADALBglghkgBZQMEBAEEggaqMIIGpgRAAAECAwQFBgcICQoLDA0ODxABAgMEBQYHCAkKCwwNDg8gAQIDBAUGBwgJCgsMDQ4PMAECAwQFBgcICQoLDA0OD4GCBmBYIXof3JWb6cceWnPV84vw6JvPYY65dINCHBetKcOtprZ9gHQvFXXZOynsWCAHXGa8iD4YFcmglwnoA8O4MKoT9G1bl5JnAosj9yp65s1puVLtIJBI5GtmI25WSgaA+KRP2HNQOG8OF0Tu24P5wXVR+kQIZk4UMV9op4W58mVf+RwgDAWOBc4+omsGJR3cFSxvYbzWTHIkd8Q4Nq5Xennx0BZF5bhZ/DObwI/45cwCxSJlOUcLMnFtpcU/AIFqiRz/xcF3oVQ4EscCPFtVEq+5NBLwkQksVMe+pi16GKTrqER01QkF9KlEYVqVEWO9enxpwVeaW5VNCw7p6hMvmk7SdnV+F61/REqDN4jTsbTEiF6urGWfV3CPtW0zpaxbpbFlwUeQFAxYWJFSK3EnVAhupj/U+jq4ESn9hg48Sh7uozDaHG9p00R/sqJE+rpH6jEMzCe2F7H3g7vxk2gMeIzk91ThYqPwSSvJKjj25L539hSfHEZltJJj67NNhjsP7DvNxqmvSyCaZQge1gRTpbGYIwUDw2YAHJLDTE6EloMGyTkRYrVpmqQz56puFh9HAikW+spqkCLzqLqMBp1zCbwBJGObJmZF8JiR68bySKxVCDjhMVs/pFihegUfNcjcGC4kKZsYFLtgVJ/AdwiI7Ju4lZAurEhlmQ93OUaacyvbm6KZsHHLMgHhnDsexl8YQZDfF0CwJGEWyRDDRcMchVZn0hk3+mh+pSU2Gqp4YILpFpGSAMx2ssTxsF4HxZS3RLJcqAJl5ckGyEprd2Fl46rXJY23mEH+tkoOCzOo+bC/6GJnFRGDpVQk8SiJdoCxscFkpZE7LCbtZ4ryCF2zJrOEYVskx0qEA5JgoGBYgEJxQEdkwsSG2beA0sd3MbHgO0Lh0aYkfExGEWgflxf8BGU75Fwq141lNzJP6GVIiDJT/AGDHMGEjCxWaQxiK48aeaoQAXT4sjv1WqtMMkWZ0FgYmx1KE5XwTLgka6WahE3ejI62+w8+knxB+XTGAkufo2zzspwj8xRpe2KUyl5jDFLUDAWe8lkbMMqHUbFO0oPzuJPMSsiCJXQAWiOwRnn0CS+MaYXDWM++FIhewX3TQQxzw7ahYCsochjNdYvYCZ8OaaaMXFNbghznHJB6OSJuKiVseEBvRFhh6wjVmZSdcKPKIFLP8KmAjIUiOpVcA7EabLlcl0yhsMluGHTGdXe7K00Ze5GJiqOdpBPNUSls1RhdsB1WgW4d/Awp/Lp4cgFegskWel0s4RidiKt4Ji/WasZiNawf0xjhizXu+8hwVKJr9Fz5W0f0ImTZuqARWorZOxXoqBERomAMGaPQFGnyi6s79gAUyyXEtwtAOqsq0DgmEZwDOGxiOnNCUFeWNKWqYUpaaMIgFEWsVowb7G/vpgFqqH7RoRAo5VPYnA3IAMbdKieGhQOi+j4n1SVoaWPCZ5oBAKi5BkMJcQuCt4qkc4VowrtGlAc2O2W/4W5X6Ttae505Gz01173YrDXdJFK6WZC1qjVIcl/RVFy+5C7d4zMsuyOW4SUqoSm8Nlf8KDvpeASm1hoSqUxA1Jrp+HfRtz4aGjIVEbHfOTfO9sau2sRaI8hpwIx5AoyaJ43xqmOtqACJmwZ2kwKx/GrXEAmtocHhwwZKLHdk6nyuIq6aI7gRDAOG0ka7g1dssLjn0mSpoQ/UdMD+M2nCIhEGwcTd2U5oUTuImT7OesxfNwb7V8cBeENq3A8SLMAu6nKFPECImwJbPFy0oVvOi7NvBy5cAqoluV011GzH4RJq6Cg35AouYQk4mWmNYoUg5ETh1pZemgLPhY/DUAMJOINDdbNM9Cfjq2WAMMXBPHrR4mT4ICfjxD55gzdbpIMK2ospiBSMuUlxqR0oyYolV0gvUDrqC0feMD+gm6uM0Y1ocr5k0oOb03EqtZD0+aYECIew8qoiiwtHixnqgA0Lia1UcreVmZjP0sj96Mh8uB3trDUg0G6k48+kaatCoDgtwaB3SYwJVEsrESo8FG5MNosEAjwd0lTCyDAjcasfVmQCw0cGGa9R1I2OJymU6hYdw1iL1TgVmQiJ8GMdSAZQ1SGbDgyR/ch95i0mgu2Olg4iNDfIUfzPN0QoFjvggsdP4FJaJqQDIAECAwQFBgcICQoLDA0ODzABAgMEBQYHCAkKCwwNDg8="); + byte[] mlkem512_seed_only = Base64.decode("MFICAQAwCwYJYIZIAWUDBAQBBEAAAQIDBAUGBwgJCgsMDQ4PEAECAwQFBgcICQoLDA0ODyABAgMEBQYHCAkKCwwNDg8wAQIDBAUGBwgJCgsMDQ4P"); + byte[] mlkem512_wrap_seed_only = Base64.decode("MFQCAQAwCwYJYIZIAWUDBAQBBEIEQAABAgMEBQYHCAkKCwwNDg8QAQIDBAUGBwgJCgsMDQ4PIAECAwQFBgcICQoLDA0ODzABAgMEBQYHCAkKCwwNDg8="); +// byte[] mlKem512_expanded_only = Base64.decode("MIIGdAIBADALBglghkgBZQMEBAEEggZgWCF6H9yVm+nHHlpz1fOL8Oibz2GOuXSDQhwXrSnDraa2fYB0LxV12Tsp7FggB1xmvIg+GBXJoJcJ6APDuDCqE/RtW5eSZwKLI/cqeubNablS7SCQSORrZiNuVkoGgPikT9hzUDhvDhdE7tuD+cF1UfpECGZOFDFfaKeFufJlX/kcIAwFjgXOPqJrBiUd3BUsb2G81kxyJHfEODauV3p58dAWReW4Wfwzm8CP+OXMAsUiZTlHCzJxbaXFPwCBaokc/8XBd6FUOBLHAjxbVRKvuTQS8JEJLFTHvqYtehik66hEdNUJBfSpRGFalRFjvXp8acFXmluVTQsO6eoTL5pO0nZ1fhetf0RKgzeI07G0xIherqxln1dwj7VtM6WsW6WxZcFHkBQMWFiRUitxJ1QIbqY/1Po6uBEp/YYOPEoe7qMw2hxvadNEf7KiRPq6R+oxDMwnthex94O78ZNoDHiM5PdU4WKj8EkrySo49uS+d/YUnxxGZbSSY+uzTYY7D+w7zcapr0sgmmUIHtYEU6WxmCMFA8NmABySw0xOhJaDBsk5EWK1aZqkM+eqbhYfRwIpFvrKapAi86i6jAadcwm8ASRjmyZmRfCYkevG8kisVQg44TFbP6RYoXoFHzXI3BguJCmbGBS7YFSfwHcIiOybuJWQLqxIZZkPdzlGmnMr25uimbBxyzIB4Zw7HsZfGEGQ3xdAsCRhFskQw0XDHIVWZ9IZN/pofqUlNhqqeGCC6RaRkgDMdrLE8bBeB8WUt0SyXKgCZeXJBshKa3dhZeOq1yWNt5hB/rZKDgszqPmwv+hiZxURg6VUJPEoiXaAsbHBZKWROywm7WeK8ghdsyazhGFbJMdKhAOSYKBgWIBCcUBHZMLEhtm3gNLHdzGx4DtC4dGmJHxMRhFoH5cX/ARlO+RcKteNZTcyT+hlSIgyU/wBgxzBhIwsVmkMYiuPGnmqEAF0+LI79VqrTDJFmdBYGJsdShOV8Ey4JGulmoRN3oyOtvsPPpJ8Qfl0xgJLn6Ns87KcI/MUaXtilMpeYwxS1AwFnvJZGzDKh1GxTtKD87iTzErIgiV0AFojsEZ59AkvjGmFw1jPvhSIXsF900EMc8O2oWArKHIYzXWL2AmfDmmmjFxTW4Ic5xyQejkibiolbHhAb0RYYesI1ZmUnXCjyiBSz/CpgIyFIjqVXAOxGmy5XJdMobDJbhh0xnV3uytNGXuRiYqjnaQTzVEpbNUYXbAdVoFuHfwMKfy6eHIBXoLJFnpdLOEYnYireCYv1mrGYjWsH9MY4Ys17vvIcFSia/Rc+VtH9CJk2bqgEVqK2TsV6KgREaJgDBmj0BRp8ourO/YAFMslxLcLQDqrKtA4JhGcAzhsYjpzQlBXljSlqmFKWmjCIBRFrFaMG+xv76YBaqh+0aEQKOVT2JwNyADG3SonhoUDovo+J9UlaGljwmeaAQCouQZDCXELgreKpHOFaMK7RpQHNjtlv+FuV+k7WnudORs9Nde92Kw13SRSulmQtao1SHJf0VRcvuQu3eMzLLsjluElKqEpvDZX/Cg76XgEptYaEqlMQNSa6fh30bc+GhoyFRGx3zk3zvbGrtrEWiPIacCMeQKMmieN8apjragAiZsGdpMCsfxq1xAJraHB4cMGSix3ZOp8riKumiO4EQwDhtJGu4NXbLC459JkqaEP1HTA/jNpwiIRBsHE3dlOaFE7iJk+znrMXzcG+1fHAXhDatwPEizALupyhTxAiJsCWzxctKFbzouzbwcuXAKqJbldNdRsx+ESaugoN+QKLmEJOJlpjWKFIORE4daWXpoCz4WPw1ADCTiDQ3WzTPQn46tlgDDFwTx60eJk+CAn48Q+eYM3W6SDCtqLKYgUjLlJcakdKMmKJVdIL1A66gtH3jA/oJurjNGNaHK+ZNKDm9NxKrWQ9PmmBAiHsPKqIosLR4sZ6oANC4mtVHK3lZmYz9LI/ejIfLgd7aw1INBupOPPpGmrQqA4LcGgd0mMCVRLKxEqPBRuTDaLBAI8HdJUwsgwI3GrH1ZkAsNHBhmvUdSNjicplOoWHcNYi9U4FZkIifBjHUgGUNUhmw4Mkf3IfeYtJoLtjpYOIjQ3yFH8zzdEKBY74ILHT+BSWiakAyABAgMEBQYHCAkKCwwNDg8wAQIDBAUGBwgJCgsMDQ4P"); +// byte[] mlKem512_wrap_expanded_only = Base64.decode("MIIGeAIBADALBglghkgBZQMEBAEEggZkBIIGYFgheh/clZvpxx5ac9Xzi/Dom89hjrl0g0IcF60pw62mtn2AdC8Vddk7KexYIAdcZryIPhgVyaCXCegDw7gwqhP0bVuXkmcCiyP3KnrmzWm5Uu0gkEjka2YjblZKBoD4pE/Yc1A4bw4XRO7bg/nBdVH6RAhmThQxX2inhbnyZV/5HCAMBY4Fzj6iawYlHdwVLG9hvNZMciR3xDg2rld6efHQFkXluFn8M5vAj/jlzALFImU5RwsycW2lxT8AgWqJHP/FwXehVDgSxwI8W1USr7k0EvCRCSxUx76mLXoYpOuoRHTVCQX0qURhWpURY716fGnBV5pblU0LDunqEy+aTtJ2dX4XrX9ESoM3iNOxtMSIXq6sZZ9XcI+1bTOlrFulsWXBR5AUDFhYkVIrcSdUCG6mP9T6OrgRKf2GDjxKHu6jMNocb2nTRH+yokT6ukfqMQzMJ7YXsfeDu/GTaAx4jOT3VOFio/BJK8kqOPbkvnf2FJ8cRmW0kmPrs02GOw/sO83Gqa9LIJplCB7WBFOlsZgjBQPDZgAcksNMToSWgwbJORFitWmapDPnqm4WH0cCKRb6ymqQIvOouowGnXMJvAEkY5smZkXwmJHrxvJIrFUIOOExWz+kWKF6BR81yNwYLiQpmxgUu2BUn8B3CIjsm7iVkC6sSGWZD3c5RppzK9ubopmwccsyAeGcOx7GXxhBkN8XQLAkYRbJEMNFwxyFVmfSGTf6aH6lJTYaqnhggukWkZIAzHayxPGwXgfFlLdEslyoAmXlyQbISmt3YWXjqtcljbeYQf62Sg4LM6j5sL/oYmcVEYOlVCTxKIl2gLGxwWSlkTssJu1nivIIXbMms4RhWyTHSoQDkmCgYFiAQnFAR2TCxIbZt4DSx3cxseA7QuHRpiR8TEYRaB+XF/wEZTvkXCrXjWU3Mk/oZUiIMlP8AYMcwYSMLFZpDGIrjxp5qhABdPiyO/Vaq0wyRZnQWBibHUoTlfBMuCRrpZqETd6Mjrb7Dz6SfEH5dMYCS5+jbPOynCPzFGl7YpTKXmMMUtQMBZ7yWRswyodRsU7Sg/O4k8xKyIIldABaI7BGefQJL4xphcNYz74UiF7BfdNBDHPDtqFgKyhyGM11i9gJnw5ppoxcU1uCHOcckHo5Im4qJWx4QG9EWGHrCNWZlJ1wo8ogUs/wqYCMhSI6lVwDsRpsuVyXTKGwyW4YdMZ1d7srTRl7kYmKo52kE81RKWzVGF2wHVaBbh38DCn8unhyAV6CyRZ6XSzhGJ2Iq3gmL9ZqxmI1rB/TGOGLNe77yHBUomv0XPlbR/QiZNm6oBFaitk7FeioERGiYAwZo9AUafKLqzv2ABTLJcS3C0A6qyrQOCYRnAM4bGI6c0JQV5Y0paphSlpowiAURaxWjBvsb++mAWqoftGhECjlU9icDcgAxt0qJ4aFA6L6PifVJWhpY8JnmgEAqLkGQwlxC4K3iqRzhWjCu0aUBzY7Zb/hblfpO1p7nTkbPTXXvdisNd0kUrpZkLWqNUhyX9FUXL7kLt3jMyy7I5bhJSqhKbw2V/woO+l4BKbWGhKpTEDUmun4d9G3PhoaMhURsd85N872xq7axFojyGnAjHkCjJonjfGqY62oAImbBnaTArH8atcQCa2hweHDBkosd2TqfK4irpojuBEMA4bSRruDV2ywuOfSZKmhD9R0wP4zacIiEQbBxN3ZTmhRO4iZPs56zF83BvtXxwF4Q2rcDxIswC7qcoU8QIibAls8XLShW86Ls28HLlwCqiW5XTXUbMfhEmroKDfkCi5hCTiZaY1ihSDkROHWll6aAs+Fj8NQAwk4g0N1s0z0J+OrZYAwxcE8etHiZPggJ+PEPnmDN1ukgwraiymIFIy5SXGpHSjJiiVXSC9QOuoLR94wP6Cbq4zRjWhyvmTSg5vTcSq1kPT5pgQIh7DyqiKLC0eLGeqADQuJrVRyt5WZmM/SyP3oyHy4He2sNSDQbqTjz6Rpq0KgOC3BoHdJjAlUSysRKjwUbkw2iwQCPB3SVMLIMCNxqx9WZALDRwYZr1HUjY4nKZTqFh3DWIvVOBWZCInwYx1IBlDVIZsODJH9yH3mLSaC7Y6WDiI0N8hR/M83RCgWO+CCx0/gUlompAMgAQIDBAUGBwgJCgsMDQ4PMAECAwQFBgcICQoLDA0ODw=="); +// byte[] mlkem512_seed_with_pub_key = Base64.decode("MIIDdwIBATALBglghkgBZQMEBAEEQAABAgMEBQYHCAkKCwwNDg8QAQIDBAUGBwgJCgsMDQ4PIAECAwQFBgcICQoLDA0ODzABAgMEBQYHCAkKCwwNDg+BggMhAPOynCPzFGl7YpTKXmMMUtQMBZ7yWRswyodRsU7Sg/O4k8xKyIIldABaI7BGefQJL4xphcNYz74UiF7BfdNBDHPDtqFgKyhyGM11i9gJnw5ppoxcU1uCHOcckHo5Im4qJWx4QG9EWGHrCNWZlJ1wo8ogUs/wqYCMhSI6lVwDsRpsuVyXTKGwyW4YdMZ1d7srTRl7kYmKo52kE81RKWzVGF2wHVaBbh38DCn8unhyAV6CyRZ6XSzhGJ2Iq3gmL9ZqxmI1rB/TGOGLNe77yHBUomv0XPlbR/QiZNm6oBFaitk7FeioERGiYAwZo9AUafKLqzv2ABTLJcS3C0A6qyrQOCYRnAM4bGI6c0JQV5Y0paphSlpowiAURaxWjBvsb++mAWqoftGhECjlU9icDcgAxt0qJ4aFA6L6PifVJWhpY8JnmgEAqLkGQwlxC4K3iqRzhWjCu0aUBzY7Zb/hblfpO1p7nTkbPTXXvdisNd0kUrpZkLWqNUhyX9FUXL7kLt3jMyy7I5bhJSqhKbw2V/woO+l4BKbWGhKpTEDUmun4d9G3PhoaMhURsd85N872xq7axFojyGnAjHkCjJonjfGqY62oAImbBnaTArH8atcQCa2hweHDBkosd2TqfK4irpojuBEMA4bSRruDV2ywuOfSZKmhD9R0wP4zacIiEQbBxN3ZTmhRO4iZPs56zF83BvtXxwF4Q2rcDxIswC7qcoU8QIibAls8XLShW86Ls28HLlwCqiW5XTXUbMfhEmroKDfkCi5hCTiZaY1ihSDkROHWll6aAs+Fj8NQAwk4g0N1s0z0J+OrZYAwxcE8etHiZPggJ+PEPnmDN1ukgwraiymIFIy5SXGpHSjJiiVXSC9QOuoLR94wP6Cbq4zRjWhyvmTSg5vTcSq1kPT5pgQIh7DyqiKLC0eLGeqADQuJrVRyt5WZmM/SyP3oyHy4He2sNSDQbqTjz6Rpq0KgOC3BoHdJjAlUSysRKjwUbkw2iwQCPB3SVMLIMCNxqx9WZALDRwYZr1HUjY4nKZTqFh3DWIvVOBWZCInwYx1IBlDVIZsODJH9"); + + KeyFactory kFact = KeyFactory.getInstance("ML-KEM", "BC"); + +// checkEncodeRecode(kFact, mlkem512_sequence); + checkEncodeRecode(kFact, mlkem512_seed_only); + checkEncodeRecode(kFact, mlkem512_wrap_seed_only); +// checkEncodeRecode(kFact, mlKem512_expanded_only); +// checkEncodeRecode(kFact, mlKem512_wrap_expanded_only); +// checkEncodeRecode(kFact, mlkem512_seed_with_pub_key); + } + + private void checkEncodeRecode(KeyFactory kFact, byte[] encoding) + throws Exception + { + PrivateKey key = kFact.generatePrivate(new PKCS8EncodedKeySpec(encoding)); + + assertTrue(Arrays.areEqual(encoding, key.getEncoded())); + } + public void testBasicKEMCamellia() throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("ML-KEM", "BC"); kpg.initialize(MLKEMParameterSpec.ml_kem_512, new SecureRandom()); + kpg.generateKeyPair().getPrivate().getEncoded(); performKEMScipher(kpg.generateKeyPair(), "ML-KEM", new KTSParameterSpec.Builder("Camellia", 128).withNoKdf().build()); performKEMScipher(kpg.generateKeyPair(), "ML-KEM", new KTSParameterSpec.Builder("Camellia-KWP", 128).withNoKdf().build()); } diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MayoKeyPairGeneratorTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MayoKeyPairGeneratorTest.java new file mode 100644 index 0000000000..454722219c --- /dev/null +++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MayoKeyPairGeneratorTest.java @@ -0,0 +1,63 @@ +package org.bouncycastle.pqc.jcajce.provider.test; + +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.Security; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.pqc.jcajce.spec.MayoParameterSpec; + +public class MayoKeyPairGeneratorTest + extends KeyPairGeneratorTest +{ + public static void main(String[] args) + throws Exception + { + MayoKeyPairGeneratorTest test = new MayoKeyPairGeneratorTest(); + test.setUp(); + test.testKeyFactory(); + test.testKeyPairEncoding(); + } + + protected void setUp() + { + super.setUp(); + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastleProvider()); + } + } + + public void testKeyFactory() + throws Exception + { + kf = KeyFactory.getInstance("Mayo", "BCPQC"); + KeyFactory kf1 = KeyFactory.getInstance("MAYO_1", "BCPQC"); + KeyFactory kf2 = KeyFactory.getInstance("MAYO_2", "BCPQC"); + KeyFactory kf3 = KeyFactory.getInstance("MAYO_3", "BCPQC"); + KeyFactory kf5 = KeyFactory.getInstance("MAYO_5", "BCPQC"); + } + + public void testKeyPairEncoding() + throws Exception + { + MayoParameterSpec[] specs = + new MayoParameterSpec[] + { + MayoParameterSpec.mayo1, + MayoParameterSpec.mayo2, + MayoParameterSpec.mayo3, + MayoParameterSpec.mayo5 + }; + kf = KeyFactory.getInstance("Mayo", "BCPQC"); + + kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC"); + + for (int i = 0; i != specs.length; i++) + { + kpg.initialize(specs[i], new SecureRandom()); + performKeyPairEncodingTest(specs[i].getName(), kpg.generateKeyPair()); + } + } +} diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MayoTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MayoTest.java new file mode 100644 index 0000000000..58d433f0c3 --- /dev/null +++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/MayoTest.java @@ -0,0 +1,276 @@ +package org.bouncycastle.pqc.jcajce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.InvalidKeyException; +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.pqc.jcajce.interfaces.MayoKey; +import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; +import org.bouncycastle.pqc.jcajce.spec.MayoParameterSpec; +import org.bouncycastle.util.Strings; + +public class MayoTest + extends TestCase +{ + public static void main(String[] args) + throws Exception + { + MayoTest test = new MayoTest(); + test.setUp(); + test.testMayo3(); + test.testMayo5(); + test.testMayoRandomSig(); + test.testPrivateKeyRecovery(); + test.testPublicKeyRecovery(); + test.testRestrictedKeyPairGen(); + } + + byte[] msg = Strings.toByteArray("Hello World!"); + + public void setUp() + { + if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastlePQCProvider()); + } + } + + public void testPrivateKeyRecovery() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC"); + + kpg.initialize(MayoParameterSpec.mayo1, new RiggedRandom()); + + KeyPair kp = kpg.generateKeyPair(); + + KeyFactory kFact = KeyFactory.getInstance("Mayo", "BCPQC"); + + MayoKey privKey = (MayoKey)kFact.generatePrivate(new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded())); + + assertEquals(kp.getPrivate(), privKey); + assertEquals(kp.getPrivate().getAlgorithm(), privKey.getAlgorithm()); + assertEquals(kp.getPrivate().hashCode(), privKey.hashCode()); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(privKey); + + oOut.close(); + + ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + MayoKey privKey2 = (MayoKey)oIn.readObject(); + + assertEquals(privKey, privKey2); + assertEquals(privKey.getAlgorithm(), privKey2.getAlgorithm()); + assertEquals(privKey.hashCode(), privKey2.hashCode()); + } + + public void testPublicKeyRecovery() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC"); + + kpg.initialize(MayoParameterSpec.mayo2, new MayoTest.RiggedRandom()); + + KeyPair kp = kpg.generateKeyPair(); + + KeyFactory kFact = KeyFactory.getInstance("Mayo_2", "BCPQC"); + + MayoKey pubKey = (MayoKey)kFact.generatePublic(new X509EncodedKeySpec(kp.getPublic().getEncoded())); + + assertEquals(kp.getPublic(), pubKey); + assertEquals(kp.getPublic().getAlgorithm(), pubKey.getAlgorithm()); + assertEquals(kp.getPublic().hashCode(), pubKey.hashCode()); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(pubKey); + + oOut.close(); + + ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + MayoKey pubKey2 = (MayoKey)oIn.readObject(); + + assertEquals(pubKey, pubKey2); + assertEquals(pubKey.getAlgorithm(), pubKey2.getAlgorithm()); + assertEquals(pubKey.hashCode(), pubKey2.hashCode()); + } + + public void testMayo5() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC"); + + kpg.initialize(MayoParameterSpec.mayo5, new SecureRandom()); + + KeyPair kp = kpg.generateKeyPair(); + + Signature sig = Signature.getInstance("MAYO_5", "BCPQC"); + + sig.initSign(kp.getPrivate(), new SecureRandom()); + + sig.update(msg, 0, msg.length); + + byte[] s = sig.sign(); + + sig = Signature.getInstance("MAYO_5", "BCPQC"); + + assertEquals("MAYO_5", Strings.toUpperCase(sig.getAlgorithm())); + + sig.initVerify(kp.getPublic()); + + sig.update(msg, 0, msg.length); + + assertTrue(sig.verify(s)); + + kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC"); + + kpg.initialize(MayoParameterSpec.mayo1, new SecureRandom()); + + kp = kpg.generateKeyPair(); + + try + { + sig.initVerify(kp.getPublic()); + fail("no exception"); + } + catch (InvalidKeyException e) + { + assertEquals("signature configured for MAYO_5", e.getMessage()); + } + } + + public void testMayo3() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC"); + + kpg.initialize(MayoParameterSpec.mayo3, new SecureRandom()); + + KeyPair kp = kpg.generateKeyPair(); + + Signature sig = Signature.getInstance("MAYO_3", "BCPQC"); + + sig.initSign(kp.getPrivate(), new SecureRandom()); + + sig.update(msg, 0, msg.length); + + byte[] s = sig.sign(); + + sig = Signature.getInstance("MAYO_3", "BCPQC"); + + assertEquals("MAYO_3", Strings.toUpperCase(sig.getAlgorithm())); + + sig.initVerify(kp.getPublic()); + + sig.update(msg, 0, msg.length); + + assertTrue(sig.verify(s)); + + kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC"); + + kpg.initialize(MayoParameterSpec.mayo5, new SecureRandom()); + + kp = kpg.generateKeyPair(); + + try + { + sig.initVerify(kp.getPublic()); + fail("no exception"); + } + catch (InvalidKeyException e) + { + assertEquals("signature configured for MAYO_3", e.getMessage()); + } + } + + public void testRestrictedKeyPairGen() + throws Exception + { + doTestRestrictedKeyPairGen(MayoParameterSpec.mayo1); + doTestRestrictedKeyPairGen(MayoParameterSpec.mayo2); + doTestRestrictedKeyPairGen(MayoParameterSpec.mayo3); + doTestRestrictedKeyPairGen(MayoParameterSpec.mayo5); + } + + private void doTestRestrictedKeyPairGen(MayoParameterSpec spec) + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance(spec.getName(), "BCPQC"); + + kpg.initialize(spec, new SecureRandom()); + + KeyPair kp = kpg.generateKeyPair(); + + assertEquals(spec.getName(), kp.getPublic().getAlgorithm()); + assertEquals(spec.getName(), kp.getPrivate().getAlgorithm()); + + //kpg = KeyPairGenerator.getInstance(spec.getName(), "BCPQC"); + +// try +// { +// kpg.initialize(altSpec, new SecureRandom()); +// fail("no exception"); +// } +// catch (InvalidAlgorithmParameterException e) +// { +// assertEquals("key pair generator locked to " + spec.getName(), e.getMessage()); +// } + } + + public void testMayoRandomSig() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("Mayo", "BCPQC"); + + kpg.initialize(MayoParameterSpec.mayo2, new SecureRandom()); + + KeyPair kp = kpg.generateKeyPair(); + + Signature sig = Signature.getInstance("Mayo", "BCPQC"); + + sig.initSign(kp.getPrivate(), new SecureRandom()); + + sig.update(msg, 0, msg.length); + + byte[] s = sig.sign(); + + sig = Signature.getInstance("Mayo", "BCPQC"); + + sig.initVerify(kp.getPublic()); + + sig.update(msg, 0, msg.length); + + assertTrue(sig.verify(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/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2KeyPairGeneratorTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2KeyPairGeneratorTest.java deleted file mode 100644 index ecb06beebe..0000000000 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2KeyPairGeneratorTest.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.test; - -import java.security.KeyFactory; -import java.security.KeyPairGenerator; - -import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; -import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2KeyGenParameterSpec; - - -public class McElieceCCA2KeyPairGeneratorTest - extends KeyPairGeneratorTest -{ - - protected void setUp() - { - super.setUp(); - } - - 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"); - McElieceCCA2KeyGenParameterSpec params = new McElieceCCA2KeyGenParameterSpec(9, 33); - kpg.initialize(params); - performKeyPairEncodingTest(kpg.generateKeyPair()); - } -} diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2PrimitivesTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2PrimitivesTest.java deleted file mode 100644 index 8ba21c20f6..0000000000 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCCA2PrimitivesTest.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.test; - -import java.security.KeyPair; -import java.security.KeyPairGenerator; -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.McElieceKeyGenParameterSpec; -import org.bouncycastle.pqc.legacy.math.linearalgebra.GF2Vector; - - -public class McElieceCCA2PrimitivesTest - extends FlexiTest -{ - - KeyPairGenerator kpg; - - protected void setUp() - { - super.setUp(); - try - { - kpg = KeyPairGenerator.getInstance("McElieceKobaraImai"); - } - catch (NoSuchAlgorithmException e) - { - e.printStackTrace(); - } - } - - public void testPrimitives() - throws Exception - { - int m = 11; - int t = 50; - initKPG(m, t); - int n = 1 << m; - - KeyPair pair = kpg.genKeyPair(); - BCMcElieceCCA2PublicKey pubKey = (BCMcElieceCCA2PublicKey)pair.getPublic(); - BCMcElieceCCA2PrivateKey privKey = (BCMcElieceCCA2PrivateKey)pair - .getPrivate(); - - GF2Vector plaintext = new GF2Vector(pubKey.getK(), sr); - GF2Vector errors = new GF2Vector(n, t, sr); - - GF2Vector ciphertext = McElieceCCA2Primitives.encryptionPrimitive( - pubKey, plaintext, errors); - - GF2Vector[] dec = McElieceCCA2Primitives.decryptionPrimitive(privKey, - ciphertext); - GF2Vector plaintextAgain = dec[0]; - GF2Vector errorsAgain = dec[1]; - - assertEquals(plaintext, plaintextAgain); - assertEquals(errors, errorsAgain); - } - - /** - * Initialize the key pair generator with the given parameters. - */ - private void initKPG(int m, int t) - throws Exception - { - McElieceKeyGenParameterSpec params = new McElieceKeyGenParameterSpec(m, t); - kpg.initialize(params); - } - -} diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCipherTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCipherTest.java deleted file mode 100644 index 9e6f7ba466..0000000000 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceCipherTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.test; - -import java.security.KeyPairGenerator; - -import javax.crypto.Cipher; - -import org.bouncycastle.pqc.jcajce.spec.McElieceKeyGenParameterSpec; - -public class McElieceCipherTest - extends AsymmetricBlockCipherTest -{ - - protected void setUp() - { - super.setUp(); - - try - { - kpg = KeyPairGenerator.getInstance("McEliece"); - cipher = Cipher.getInstance("McEliece"); - } - catch (Exception e) - { - e.printStackTrace(); - } - - - } - - public void testEnDecryption_9_33() - throws Exception - { - McElieceKeyGenParameterSpec params = new McElieceKeyGenParameterSpec(9, 33); - kpg.initialize(params); - performEnDecryptionTest(2, 10, params); - } - - public void testEnDecryption_11_50() - throws Exception - { - McElieceKeyGenParameterSpec params = new McElieceKeyGenParameterSpec(11, 50); - kpg.initialize(params); - performEnDecryptionTest(2, 10, params); - } - - -} diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceFujisakiCipherTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceFujisakiCipherTest.java deleted file mode 100644 index 671dbbf74f..0000000000 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceFujisakiCipherTest.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.test; - -import java.security.KeyPairGenerator; - -import javax.crypto.Cipher; - -import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2KeyGenParameterSpec; - - -public class McElieceFujisakiCipherTest - extends AsymmetricHybridCipherTest -{ - - protected void setUp() - { - super.setUp(); - try - { - kpg = KeyPairGenerator.getInstance("McElieceFujisaki"); - cipher = Cipher.getInstance("McElieceFujisaki"); - } - catch (Exception e) - { - e.printStackTrace(); - } - - } - - /** - * Test encryption and decryption performance for SHA256 message digest and parameters - * m=11, t=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 - 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/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKeyPairGeneratorTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKeyPairGeneratorTest.java deleted file mode 100644 index 15e56d407c..0000000000 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKeyPairGeneratorTest.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.test; - -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.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; - -import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; -import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2KeyGenParameterSpec; -import org.bouncycastle.pqc.jcajce.spec.McElieceKeyGenParameterSpec; - - -public class McElieceKeyPairGeneratorTest - extends KeyPairGeneratorTest -{ - - protected void setUp() - { - super.setUp(); - } - - public void testKeyFactory() - throws Exception - { - kf = KeyFactory.getInstance("McEliece"); - kf = KeyFactory.getInstance(PQCObjectIdentifiers.mcEliece.getId()); - } - - public void testKeyPairEncoding_9_33() - throws Exception - { - kf = KeyFactory.getInstance("McEliece"); - - kpg = KeyPairGenerator.getInstance("McEliece"); - McElieceKeyGenParameterSpec params = new McElieceKeyGenParameterSpec(9, 33); - kpg.initialize(params); - simpleKeyPairEncodingTest(kpg.generateKeyPair()); - - kpg = KeyPairGenerator.getInstance("McEliece"); - kpg.initialize(params, new SecureRandom()); - simpleKeyPairEncodingTest(kpg.generateKeyPair()); - } - - private void simpleKeyPairEncodingTest(KeyPair keyPair) - { - try - { - PublicKey pubKey = keyPair.getPublic(); - PrivateKey privKey = keyPair.getPrivate(); - - byte[] encPubKey = pubKey.getEncoded(); - byte[] encPrivKey = privKey.getEncoded(); - - X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encPubKey); - PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(encPrivKey); - - PublicKey decPubKey = kf.generatePublic(pubKeySpec); - PrivateKey decPrivKey = kf.generatePrivate(privKeySpec); - - assertEquals(pubKey, decPubKey); - assertEquals(privKey, decPrivKey); - } - catch (Exception e) - { - e.printStackTrace(); - fail(e); - } - } - - public void testKeyPairEncoding_CCA2() - throws Exception - { - kf = KeyFactory.getInstance("McEliece-CCA2"); - - kpg = KeyPairGenerator.getInstance("McEliece-CCA2"); - McElieceCCA2KeyGenParameterSpec params = new McElieceCCA2KeyGenParameterSpec(9, 33); - kpg.initialize(params); - performKeyPairEncodingTest(kpg.generateKeyPair()); - - kpg = KeyPairGenerator.getInstance("McEliece-CCA2"); - kpg.initialize(params, new SecureRandom()); - performKeyPairEncodingTest(kpg.generateKeyPair()); - } -} diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKobaraImaiCipherTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKobaraImaiCipherTest.java deleted file mode 100644 index 944b62c1f0..0000000000 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McElieceKobaraImaiCipherTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.test; - -import java.security.KeyPairGenerator; -import java.security.spec.AlgorithmParameterSpec; - -import javax.crypto.Cipher; - -import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2KeyGenParameterSpec; - - -public class McElieceKobaraImaiCipherTest - extends AsymmetricHybridCipherTest -{ - - protected void setUp() - { - super.setUp(); - try - { - kpg = KeyPairGenerator.getInstance("McElieceKobaraImai"); - cipher = Cipher.getInstance("McElieceKobaraImai"); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - - /** - * Test encryption and decryption performance for SHA256 message digest and parameters - * m=11, t=50. - */ - public void testEnDecryption_SHA256_11_50() - throws Exception - { - // initialize key pair generator - AlgorithmParameterSpec kpgParams = new McElieceCCA2KeyGenParameterSpec(11, 50); - kpg.initialize(kpgParams); - - performEnDecryptionTest(0, 10, 32, null); // TODO: McElieceKobaraImai is broken - } - -} diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McEliecePointchevalCipherTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McEliecePointchevalCipherTest.java deleted file mode 100644 index d1af36ee35..0000000000 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/McEliecePointchevalCipherTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.test; - -import java.security.KeyPairGenerator; -import java.security.spec.AlgorithmParameterSpec; - -import javax.crypto.Cipher; - -import org.bouncycastle.pqc.jcajce.spec.McElieceCCA2KeyGenParameterSpec; - -public class McEliecePointchevalCipherTest - extends AsymmetricHybridCipherTest -{ - - protected void setUp() - { - super.setUp(); - try - { - kpg = KeyPairGenerator.getInstance("McEliecePointcheval"); - cipher = Cipher.getInstance("McEliecePointcheval"); - } - catch (Exception e) - { - e.printStackTrace(); - } - } - - /** - * Test encryption and decryption performance for SHA256 message digest and parameters - * m=11, t=50. - */ - public void testEnDecryption_SHA256_11_50() - throws Exception - { - // initialize key pair generator - AlgorithmParameterSpec kpgParams = new McElieceCCA2KeyGenParameterSpec(11, 50); - kpg.initialize(kpgParams); - - // perform test - performEnDecryptionTest(1, 10, 32, null); - } - -} diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NTRUPlusKeyPairGeneratorTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NTRUPlusKeyPairGeneratorTest.java new file mode 100644 index 0000000000..4b9d768cd0 --- /dev/null +++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NTRUPlusKeyPairGeneratorTest.java @@ -0,0 +1,47 @@ +package org.bouncycastle.pqc.jcajce.provider.test; + +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; + +import org.bouncycastle.asn1.bc.BCObjectIdentifiers; +import org.bouncycastle.pqc.jcajce.spec.NTRUPlusParameterSpec; + +public class NTRUPlusKeyPairGeneratorTest + extends KeyPairGeneratorTest +{ + + protected void setUp() + { + super.setUp(); + } + + public void testKeyFactory() + throws Exception + { + kf = KeyFactory.getInstance("NTRUPLUS", "BCPQC"); + kf = KeyFactory.getInstance(BCObjectIdentifiers.pqc_kem_hqc.getId(), "BCPQC"); + } + + public void testKeyPairEncoding() + throws Exception + { + NTRUPlusParameterSpec[] specs = + new NTRUPlusParameterSpec[] + { + NTRUPlusParameterSpec.ntruplus_768, + NTRUPlusParameterSpec.ntruplus_864, + NTRUPlusParameterSpec.ntruplus_1152 + }; + kf = KeyFactory.getInstance("NTRUPLUS", "BCPQC"); + + kpg = KeyPairGenerator.getInstance("NTRUPLUS", "BCPQC"); + + for (int i = 0; i != specs.length; i++) + { + kpg.initialize(specs[i], new SecureRandom()); + performKeyPairEncodingTest(kpg.generateKeyPair()); + } + } + +} diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NTRUPlusTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NTRUPlusTest.java new file mode 100644 index 0000000000..1c3c27e9ed --- /dev/null +++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NTRUPlusTest.java @@ -0,0 +1,160 @@ +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.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import junit.framework.TestCase; +import org.bouncycastle.jcajce.SecretKeyWithEncapsulation; +import org.bouncycastle.jcajce.spec.KEMExtractSpec; +import org.bouncycastle.jcajce.spec.KEMGenerateSpec; +import org.bouncycastle.jcajce.spec.KEMParameterSpec; +import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; +import org.bouncycastle.pqc.jcajce.spec.NTRUPlusParameterSpec; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.encoders.Hex; + +public class NTRUPlusTest + extends TestCase +{ + + public void setUp() + { + if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastlePQCProvider()); + } + } + + public void testBasicKEMAES() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRUPLUS", "BCPQC"); + kpg.initialize(NTRUPlusParameterSpec.ntruplus_768, new SecureRandom()); + + performKEMScipher(kpg.generateKeyPair(), "NTRUPLUS", new KEMParameterSpec("AES")); + performKEMScipher(kpg.generateKeyPair(), "NTRUPLUS", new KEMParameterSpec("AES-KWP")); + + kpg.initialize(NTRUPlusParameterSpec.ntruplus_864, new SecureRandom()); + KeyPair hqcKp = kpg.generateKeyPair(); + performKEMScipher(hqcKp, "NTRUPLUS", new KEMParameterSpec("AES")); + performKEMScipher(hqcKp, "NTRUPLUS", new KEMParameterSpec("AES-KWP")); + } + + public void testBasicKEMCamellia() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRUPLUS", "BCPQC"); + kpg.initialize(NTRUPlusParameterSpec.ntruplus_768, new SecureRandom()); + + performKEMScipher(kpg.generateKeyPair(), "NTRUPLUS", new KEMParameterSpec("Camellia")); + performKEMScipher(kpg.generateKeyPair(), "NTRUPLUS", new KEMParameterSpec("Camellia-KWP")); + } + + public void testBasicKEMSEED() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRUPLUS", "BCPQC"); + kpg.initialize(NTRUPlusParameterSpec.ntruplus_768, new SecureRandom()); + + performKEMScipher(kpg.generateKeyPair(), "NTRUPLUS", new KEMParameterSpec("SEED")); + } + + public void testBasicKEMARIA() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRUPLUS", "BCPQC"); + kpg.initialize(NTRUPlusParameterSpec.ntruplus_768, new SecureRandom()); + + performKEMScipher(kpg.generateKeyPair(), "NTRUPLUS", new KEMParameterSpec("ARIA")); + performKEMScipher(kpg.generateKeyPair(), "NTRUPLUS", new KEMParameterSpec("ARIA-KWP")); + } + + private void performKEMScipher(KeyPair kp, String algorithm, KEMParameterSpec ktsParameterSpec) + throws Exception + { + Cipher w1 = Cipher.getInstance(algorithm, "BCPQC"); + + byte[] keyBytes; + if (algorithm.endsWith("KWP")) + { + keyBytes = Hex.decode("000102030405060708090a0b0c0d0e0faa"); + } + else + { + keyBytes = Hex.decode("000102030405060708090a0b0c0d0e0f"); + } + SecretKey key = new SecretKeySpec(keyBytes, "AES"); + + w1.init(Cipher.WRAP_MODE, kp.getPublic(), ktsParameterSpec); + + byte[] data = w1.wrap(key); + + Cipher w2 = Cipher.getInstance(algorithm, "BCPQC"); + + w2.init(Cipher.UNWRAP_MODE, kp.getPrivate(), ktsParameterSpec); + + Key k = w2.unwrap(data, "AES", Cipher.SECRET_KEY); + + assertTrue(Arrays.areEqual(keyBytes, k.getEncoded())); + } + + public void testGenerateAES() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRUPLUS", "BCPQC"); + kpg.initialize(NTRUPlusParameterSpec.ntruplus_768, new SecureRandom()); + + KeyPair kp = kpg.generateKeyPair(); + + KeyGenerator keyGen = KeyGenerator.getInstance("NTRUPLUS", "BCPQC"); + + keyGen.init(new KEMGenerateSpec(kp.getPublic(), "AES"), new SecureRandom()); + + SecretKeyWithEncapsulation secEnc1 = (SecretKeyWithEncapsulation)keyGen.generateKey(); + + assertEquals("AES", secEnc1.getAlgorithm()); + assertEquals(32, secEnc1.getEncoded().length); + + keyGen.init(new KEMExtractSpec(kp.getPrivate(), secEnc1.getEncapsulation(), "AES")); + + SecretKeyWithEncapsulation secEnc2 = (SecretKeyWithEncapsulation)keyGen.generateKey(); + + assertEquals("AES", secEnc2.getAlgorithm()); + + assertTrue(Arrays.areEqual(secEnc1.getEncoded(), secEnc2.getEncoded())); + } + + public void testGenerateAES256() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRUPLUS", "BCPQC"); + kpg.initialize(NTRUPlusParameterSpec.ntruplus_864, new SecureRandom()); + + KeyPair kp = kpg.generateKeyPair(); + + KeyGenerator keyGen = KeyGenerator.getInstance("NTRUPLUS", "BCPQC"); + + keyGen.init(new KEMGenerateSpec(kp.getPublic(), "AES"), new SecureRandom()); + + SecretKeyWithEncapsulation secEnc1 = (SecretKeyWithEncapsulation)keyGen.generateKey(); + + assertEquals("AES", secEnc1.getAlgorithm()); + assertEquals(32, secEnc1.getEncoded().length); + + keyGen.init(new KEMExtractSpec(kp.getPrivate(), secEnc1.getEncapsulation(), "AES")); + + SecretKeyWithEncapsulation secEnc2 = (SecretKeyWithEncapsulation)keyGen.generateKey(); + + assertEquals("AES", secEnc2.getAlgorithm()); + + assertTrue(Arrays.areEqual(secEnc1.getEncoded(), secEnc2.getEncoded())); + } +} diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowKeyPairGeneratorTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowKeyPairGeneratorTest.java deleted file mode 100644 index 44ad589782..0000000000 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowKeyPairGeneratorTest.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.test; - -import java.security.KeyFactory; -import java.security.KeyPairGenerator; -import java.security.SecureRandom; - -import org.bouncycastle.pqc.jcajce.spec.RainbowParameterSpec; - -/** - * KeyFactory/KeyPairGenerator tests for Falcon with BCPQC provider. - */ -public class RainbowKeyPairGeneratorTest - extends KeyPairGeneratorTest -{ - protected void setUp() - { - super.setUp(); - } - - public void testKeyFactory() - throws Exception - { - kf = KeyFactory.getInstance("Rainbow", "BCPQC"); - } - - public void testKeyPairEncoding() - throws Exception - { - RainbowParameterSpec[] specs = - new RainbowParameterSpec[] - { - RainbowParameterSpec.rainbowIIIclassic, - RainbowParameterSpec.rainbowIIIcircumzenithal, - RainbowParameterSpec.rainbowIIIcompressed, - RainbowParameterSpec.rainbowVclassic, - RainbowParameterSpec.rainbowVcircumzenithal, - RainbowParameterSpec.rainbowVcompressed, - }; - kf = KeyFactory.getInstance("Rainbow", "BCPQC"); - - kpg = KeyPairGenerator.getInstance("Rainbow", "BCPQC"); - - for (int i = 0; i != specs.length; i++) - { - kpg.initialize(specs[i], new SecureRandom()); - performKeyPairEncodingTest(kpg.generateKeyPair()); - } - } - -} diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowTest.java deleted file mode 100644 index a6fd39d1ab..0000000000 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/RainbowTest.java +++ /dev/null @@ -1,393 +0,0 @@ -package org.bouncycastle.pqc.jcajce.provider.test; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -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.SecureRandom; -import java.security.Security; -import java.security.Signature; -import java.security.SignatureException; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; - -import junit.framework.TestCase; -import org.bouncycastle.asn1.ASN1OctetString; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.pqc.jcajce.interfaces.RainbowKey; -import org.bouncycastle.pqc.jcajce.interfaces.RainbowPrivateKey; -import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; -import org.bouncycastle.pqc.jcajce.spec.RainbowParameterSpec; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Strings; -import org.bouncycastle.util.encoders.Hex; - -public class RainbowTest - extends TestCase -{ - byte[] msg = Strings.toByteArray("Hello World!"); - - public void setUp() - { - if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) - { - Security.addProvider(new BouncyCastlePQCProvider()); - } - } - - public void testPrivateKeyRecovery() - throws Exception - { - KeyPairGenerator kpg = KeyPairGenerator.getInstance("Rainbow", "BCPQC"); - - kpg.initialize(RainbowParameterSpec.rainbowIIIclassic, new RainbowTest.RiggedRandom()); - - KeyPair kp = kpg.generateKeyPair(); - - KeyFactory kFact = KeyFactory.getInstance("Rainbow", "BCPQC"); - - RainbowKey privKey = (RainbowKey)kFact.generatePrivate(new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded())); - - assertEquals(kp.getPrivate(), privKey); - assertEquals(kp.getPrivate().getAlgorithm(), privKey.getAlgorithm()); - assertEquals(kp.getPrivate().hashCode(), privKey.hashCode()); - - assertEquals(((RainbowPrivateKey)kp.getPrivate()).getPublicKey(), ((RainbowPrivateKey)privKey).getPublicKey()); - - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ObjectOutputStream oOut = new ObjectOutputStream(bOut); - - oOut.writeObject(privKey); - - oOut.close(); - - ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); - - RainbowKey privKey2 = (RainbowKey)oIn.readObject(); - - assertEquals(privKey, privKey2); - assertEquals(privKey.getAlgorithm(), privKey2.getAlgorithm()); - assertEquals(privKey.hashCode(), privKey2.hashCode()); - - assertEquals(kp.getPublic(), ((RainbowPrivateKey)privKey2).getPublicKey()); - assertEquals(((RainbowPrivateKey)privKey).getPublicKey(), ((RainbowPrivateKey)privKey2).getPublicKey()); - } - - public void testPublicKeyRecovery() - throws Exception - { - KeyPairGenerator kpg = KeyPairGenerator.getInstance("Rainbow", "BCPQC"); - - kpg.initialize(RainbowParameterSpec.rainbowVclassic, new RainbowTest.RiggedRandom()); - - KeyPair kp = kpg.generateKeyPair(); - - KeyFactory kFact = KeyFactory.getInstance("Rainbow", "BCPQC"); - - RainbowKey pubKey = (RainbowKey)kFact.generatePublic(new X509EncodedKeySpec(kp.getPublic().getEncoded())); - - assertEquals(kp.getPublic(), pubKey); - assertEquals(kp.getPublic().getAlgorithm(), pubKey.getAlgorithm()); - assertEquals(kp.getPublic().hashCode(), pubKey.hashCode()); - - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ObjectOutputStream oOut = new ObjectOutputStream(bOut); - - oOut.writeObject(pubKey); - - oOut.close(); - - ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); - - RainbowKey pubKey2 = (RainbowKey)oIn.readObject(); - - assertEquals(pubKey, pubKey2); - assertEquals(pubKey.getAlgorithm(), pubKey2.getAlgorithm()); - assertEquals(pubKey.hashCode(), pubKey2.hashCode()); - } - - public void testRainbowIIIclassic() - throws Exception - { - doConfSigTest("Rainbow-III-Classic", RainbowParameterSpec.rainbowIIIclassic, RainbowParameterSpec.rainbowVclassic); - } - - public void testRainbowIIIcircum() - throws Exception - { - doConfSigTest("Rainbow-III-Circumzenithal", RainbowParameterSpec.rainbowIIIcircumzenithal, RainbowParameterSpec.rainbowVclassic); - } - - public void testRainbowIIIcomp() - throws Exception - { - doConfSigTest("Rainbow-III-Compressed", RainbowParameterSpec.rainbowIIIcompressed, RainbowParameterSpec.rainbowVclassic); - } - - public void testRainbowVclassic() - throws Exception - { - doConfSigTest("Rainbow-V-Classic", RainbowParameterSpec.rainbowVclassic, RainbowParameterSpec.rainbowIIIclassic); - } - - public void testRainbowVcircum() - throws Exception - { - doConfSigTest("Rainbow-V-Circumzenithal", RainbowParameterSpec.rainbowVcircumzenithal, RainbowParameterSpec.rainbowIIIclassic); - } - - public void testRainbowVcompressed() - throws Exception - { - doConfSigTest("Rainbow-V-Compressed", RainbowParameterSpec.rainbowVcompressed, RainbowParameterSpec.rainbowIIIclassic); - } - - private void doConfSigTest(String algorithmName, AlgorithmParameterSpec algSpec, AlgorithmParameterSpec altSpec) - throws Exception - { - KeyPairGenerator kpg = KeyPairGenerator.getInstance("Rainbow", "BCPQC"); - - kpg.initialize(algSpec, new SecureRandom()); - - KeyPair kp = kpg.generateKeyPair(); - - Signature sig = Signature.getInstance("Rainbow", "BCPQC"); - - sig.initSign(kp.getPrivate(), new SecureRandom()); - - sig.update(msg, 0, msg.length); - - byte[] s = sig.sign(); - - sig = Signature.getInstance(algorithmName, "BCPQC"); - - assertEquals(Strings.toUpperCase(algorithmName), Strings.toUpperCase(sig.getAlgorithm())); - - sig.initVerify(kp.getPublic()); - - sig.update(msg, 0, msg.length); - - assertTrue(sig.verify(s)); - - kpg = KeyPairGenerator.getInstance("Rainbow", "BCPQC"); - - kpg.initialize(altSpec, new SecureRandom()); - - kp = kpg.generateKeyPair(); - - try - { - sig.initVerify(kp.getPublic()); - fail("no exception"); - } - catch (InvalidKeyException e) - { - assertEquals("signature configured for " + Strings.toUpperCase(algorithmName), e.getMessage()); - } - } - - public void testRestrictedKeyPairGen() - throws Exception - { - doTestRestrictedKeyPairGen(RainbowParameterSpec.rainbowIIIclassic, RainbowParameterSpec.rainbowVclassic); - doTestRestrictedKeyPairGen(RainbowParameterSpec.rainbowIIIcircumzenithal, RainbowParameterSpec.rainbowVclassic); - doTestRestrictedKeyPairGen(RainbowParameterSpec.rainbowIIIcompressed, RainbowParameterSpec.rainbowVclassic); - doTestRestrictedKeyPairGen(RainbowParameterSpec.rainbowVclassic, RainbowParameterSpec.rainbowIIIclassic); - doTestRestrictedKeyPairGen(RainbowParameterSpec.rainbowVcircumzenithal, RainbowParameterSpec.rainbowIIIclassic); - doTestRestrictedKeyPairGen(RainbowParameterSpec.rainbowVcompressed, RainbowParameterSpec.rainbowIIIclassic); - } - - private void doTestRestrictedKeyPairGen(RainbowParameterSpec spec, RainbowParameterSpec altSpec) - throws Exception - { - KeyPairGenerator kpg = KeyPairGenerator.getInstance(spec.getName(), "BCPQC"); - - kpg.initialize(spec, new SecureRandom()); - - KeyPair kp = kpg.generateKeyPair(); - - assertEquals(spec.getName(), kp.getPublic().getAlgorithm()); - assertEquals(spec.getName(), kp.getPrivate().getAlgorithm()); - - kpg = KeyPairGenerator.getInstance(spec.getName(), "BCPQC"); - - try - { - kpg.initialize(altSpec, new SecureRandom()); - fail("no exception"); - } - catch (InvalidAlgorithmParameterException e) - { - assertEquals("key pair generator locked to " + spec.getName(), e.getMessage()); - } - } - - public void testRainbowRandomSig() - throws Exception - { - KeyPairGenerator kpg = KeyPairGenerator.getInstance("Rainbow", "BCPQC"); - - kpg.initialize(RainbowParameterSpec.rainbowIIIcompressed, new SecureRandom()); - - KeyPair kp = kpg.generateKeyPair(); - - Signature sig = Signature.getInstance("Rainbow", "BCPQC"); - - sig.initSign(kp.getPrivate(), new SecureRandom()); - - sig.update(msg, 0, msg.length); - - byte[] s = sig.sign(); - - sig = Signature.getInstance("Rainbow", "BCPQC"); - - sig.initVerify(kp.getPublic()); - - sig.update(msg, 0, msg.length); - - assertTrue(sig.verify(s)); - } - - /** - * count = 0 - * seed = 061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1 - * No public key as it's a bit "big". - */ - public void testRainbowKATSigCompressedIII() - throws Exception - { - byte[] privK = Hex.decode("8626ED79D451140800E03B59B956F8210E556067407D13DC90FA9E8B872BFB8F7C9935A0B07694AA0C6D10E4DB6B1ADD2FD81A25CCB148032DCD739936737F2D"); - byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - byte[] s = Hex.decode(" 451F524FEF128EDBE93814C041D5EDD2C8A0226E05E13942B5B832C864A96184261745A5B530D09D51773C3E6F3C8297E3A8E6E4DBD23E56BDA10B5C3A491F7A5D9EA819D712FC6565429F965FD7264041E5F2007085DE29930B20B187BB9E5BC4BCAC01C35CABC97F5EC6476C42138C3D18A1DBD23BA22B31B21BDBE5421AC1B837A793123C80E2B5028A0763872E76E45F6AA9D675E2D667E6F68024D5EF1143D21713"); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("Rainbow", "BCPQC"); - SecureRandom katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null); - - kpg.initialize(RainbowParameterSpec.rainbowIIIcompressed, katRandom); - - KeyPair kp = kpg.generateKeyPair(); - - PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded()); - - ASN1OctetString privEnc = ASN1OctetString.getInstance(privInfo.parsePrivateKey()); - - assertTrue(Arrays.areEqual(privK, privEnc.getOctets())); - - doKatTest(kp, msg, s, katRandom); - } - - public void testRainbowKATSigCompressedV() - throws Exception - { - byte[] privK = Hex.decode("8626ED79D451140800E03B59B956F8210E556067407D13DC90FA9E8B872BFB8F7C9935A0B07694AA0C6D10E4DB6B1ADD2FD81A25CCB148032DCD739936737F2D"); - byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - byte[] s = Hex.decode(" D1F97D1310F57AF3509F66307985B7F341234CE8F7516E4B61F9E53B1282CE66B9526321C66954E1753D1A9C8BA4012B9C5A211F0287C72705141F71A9AAEC350E81F6EC67ED10E1BD61DCDFA4AC87553563E0FEE31927E5877741D5DCDF03C44E50CF80BB3D15856AF49F2C68A7EDAC52FD2957F96A7113DCE51785EDF0AB8538C1EAAD694E8514CDC7872664412BCF9884C185BADE87781016826E32E08C1EC6275C6F8588A11FF6575D704505D4AB794D047BEC1104C00DAD3BCFC2DE42267B3552BD74090543C9478050169FCCFBC0E9BA11"); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("Rainbow", "BCPQC"); - SecureRandom katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null); - - kpg.initialize(RainbowParameterSpec.rainbowVcompressed, katRandom); - - KeyPair kp = kpg.generateKeyPair(); - - PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded()); - - ASN1OctetString privEnc = ASN1OctetString.getInstance(privInfo.parsePrivateKey()); - - assertTrue(Arrays.areEqual(privK, privEnc.getOctets())); - - doKatTest(kp, msg, s, katRandom); - } - - public void testRainbowKATSigClassicIII() - throws Exception - { - byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - byte[] s = Hex.decode("6033C99A65042BE545EED707341BD14F73CA178F2A5B244A87E847DCAB29A9086676D7A7A4B35E3904A9EDD7B399B1BD104A19373A415029BCCD4C707B416EED683F13A9189EF0BDC151116CBF6D6A9D4BC019FAA58FD770B6F567A410C700B48C488A375C33866F3FEBB8DEDF239C64FF9A36F092E3D6192B9A0726B06672A540A892FA7BA47DBE7F3E66BF394ED328A107B8EDCEB39AD2E43C6EE441F39ECE871397AC"); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("Rainbow", "BCPQC"); - SecureRandom katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null); - - kpg.initialize(RainbowParameterSpec.rainbowIIIclassic, katRandom); - - doKatTest(kpg.generateKeyPair(), msg, s, katRandom); - } - - public void testRainbowKATSigClassicV() - throws Exception - { - byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - byte[] s = Hex.decode("15040F890F2BF56F8B04B1D8B9BA21D303C490868A0A10C9FFC04A2AF9D1F3122D14F7C6D5E0B1D914CC23D763C061B2FD34DF8CB0D75F12111244241FA7A136C440C2D40782390FE5EF3C15ED5539285B437DA0447E361853E98982E1F16AA0506BABFFBBA8282BAA0A307C50EBA79596AD26EBECE897E7B4DE3B601A515C08775526522915ED03F08BAA23AFED4224C8E50ED67FBCCFAB62C58872CE880C850D3A03F21B2703C5C085FA410A5FCB3559E50D6BBC6A06FABA309962F2922E0D014C5EB074090543C9478050169FCCFBC0E9BA11"); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("Rainbow", "BCPQC"); - SecureRandom katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null); - - kpg.initialize(RainbowParameterSpec.rainbowVclassic, katRandom); - - doKatTest(kpg.generateKeyPair(), msg, s, katRandom); - } - - public void testRainbowKATSigCircumIII() - throws Exception - { - byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - byte[] s = Hex.decode("451F524FEF128EDBE93814C041D5EDD2C8A0226E05E13942B5B832C864A96184261745A5B530D09D51773C3E6F3C8297E3A8E6E4DBD23E56BDA10B5C3A491F7A5D9EA819D712FC6565429F965FD7264041E5F2007085DE29930B20B187BB9E5BC4BCAC01C35CABC97F5EC6476C42138C3D18A1DBD23BA22B31B21BDBE5421AC1B837A793123C80E2B5028A0763872E76E45F6AA9D675E2D667E6F68024D5EF1143D21713"); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("Rainbow", "BCPQC"); - SecureRandom katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null); - - kpg.initialize(RainbowParameterSpec.rainbowIIIcircumzenithal, katRandom); - - doKatTest(kpg.generateKeyPair(), msg, s, katRandom); - } - - public void testRainbowKATSigCircumV() - throws Exception - { - byte[] msg = Hex.decode("D81C4D8D734FCBFBEADE3D3F8A039FAA2A2C9957E835AD55B22E75BF57BB556AC8"); - byte[] s = Hex.decode("D1F97D1310F57AF3509F66307985B7F341234CE8F7516E4B61F9E53B1282CE66B9526321C66954E1753D1A9C8BA4012B9C5A211F0287C72705141F71A9AAEC350E81F6EC67ED10E1BD61DCDFA4AC87553563E0FEE31927E5877741D5DCDF03C44E50CF80BB3D15856AF49F2C68A7EDAC52FD2957F96A7113DCE51785EDF0AB8538C1EAAD694E8514CDC7872664412BCF9884C185BADE87781016826E32E08C1EC6275C6F8588A11FF6575D704505D4AB794D047BEC1104C00DAD3BCFC2DE42267B3552BD74090543C9478050169FCCFBC0E9BA11"); - KeyPairGenerator kpg = KeyPairGenerator.getInstance("Rainbow", "BCPQC"); - SecureRandom katRandom = new NISTSecureRandom(Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1"), null); - - kpg.initialize(RainbowParameterSpec.rainbowVcircumzenithal, katRandom); - - doKatTest(kpg.generateKeyPair(), msg, s, katRandom); - } - - private static void doKatTest(KeyPair kp, byte[] msg, byte[] s, SecureRandom katRandom) - throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException - { - Signature sig = Signature.getInstance("Rainbow", "BCPQC"); - - sig.initSign(kp.getPrivate(), katRandom); - - sig.update(msg, 0, msg.length); - - byte[] genS = sig.sign(); - - assertTrue(Arrays.areEqual(s, genS)); - - sig = Signature.getInstance("Rainbow", "BCPQC"); - - sig.initVerify(kp.getPublic()); - - sig.update(msg, 0, msg.length); - - assertTrue(sig.verify(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/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/SLHDSATest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/SLHDSATest.java index 58b8d6cdea..fa9c6c5cef 100644 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/SLHDSATest.java +++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/SLHDSATest.java @@ -11,6 +11,7 @@ import java.security.SecureRandom; import java.security.Security; import java.security.Signature; +import java.security.spec.AlgorithmParameterSpec; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; @@ -151,7 +152,7 @@ public void testKeyFactory() NISTObjectIdentifiers.id_hash_slh_dsa_shake_256f_with_shake256, NISTObjectIdentifiers.id_hash_slh_dsa_shake_256s_with_shake256, }; - + for (int i = 0; i != names.length; i++) { KeyPairGenerator kpGen = KeyPairGenerator.getInstance(names[i]); @@ -458,6 +459,18 @@ public void testSphincsRandomSigSHA2WithContext() ContextParameterSpec vspec = vp.getParameterSpec(ContextParameterSpec.class); assertTrue(Arrays.areEqual(Strings.toByteArray("Hello, world!"), vspec.getContext())); + + // check reflection based context. + + sig = Signature.getInstance("SLH-DSA", "BC"); + + sig.initVerify(kp.getPublic()); + + sig.setParameter(new MyContextParameterSpec(Strings.toByteArray("Hello, world!"))); + + sig.update(msg, 0, msg.length); + + assertTrue(sig.verify(s)); } public void testSLHDSARandomSigSHA2() @@ -658,5 +671,21 @@ public void nextBytes(byte[] bytes) } } } + + public static class MyContextParameterSpec + implements AlgorithmParameterSpec + { + private final byte[] context; + + MyContextParameterSpec(byte[] context) + { + this.context = context; + } + + public byte[] getContext() + { + return context; + } + } } diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/SnovaTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/SnovaTest.java new file mode 100644 index 0000000000..4dd563ca1f --- /dev/null +++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/SnovaTest.java @@ -0,0 +1,318 @@ +package org.bouncycastle.pqc.jcajce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.InvalidKeyException; +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.pqc.jcajce.interfaces.SnovaKey; +import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; +import org.bouncycastle.pqc.jcajce.spec.SnovaParameterSpec; +import org.bouncycastle.util.Strings; + +public class SnovaTest + extends TestCase +{ + public static void main(String[] args) + throws Exception + { + SnovaTest test = new SnovaTest(); + test.setUp(); + test.testPrivateKeyRecovery(); + test.testPublicKeyRecovery(); + test.testRestrictedKeyPairGen(); + test.testSnovaRandomSig(); + test.testSnovaSign(); + } + + byte[] msg = Strings.toByteArray("Hello World!"); + + public void setUp() + { + if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastlePQCProvider()); + } + } + + public void testPrivateKeyRecovery() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("Snova", "BCPQC"); + + kpg.initialize(SnovaParameterSpec.SNOVA_24_5_4_ESK, new RiggedRandom()); + + KeyPair kp = kpg.generateKeyPair(); + + KeyFactory kFact = KeyFactory.getInstance("Snova", "BCPQC"); + + SnovaKey privKey = (SnovaKey)kFact.generatePrivate(new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded())); + + assertEquals(kp.getPrivate(), privKey); + assertEquals(kp.getPrivate().getAlgorithm(), privKey.getAlgorithm()); + assertEquals(kp.getPrivate().hashCode(), privKey.hashCode()); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(privKey); + + oOut.close(); + + ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + SnovaKey privKey2 = (SnovaKey)oIn.readObject(); + + assertEquals(privKey, privKey2); + assertEquals(privKey.getAlgorithm(), privKey2.getAlgorithm()); + assertEquals(privKey.hashCode(), privKey2.hashCode()); + } + + public void testPublicKeyRecovery() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("Snova", "BCPQC"); + + kpg.initialize(SnovaParameterSpec.SNOVA_25_8_3_ESK, new SnovaTest.RiggedRandom()); + + KeyPair kp = kpg.generateKeyPair(); + + KeyFactory kFact = KeyFactory.getInstance(SnovaParameterSpec.SNOVA_25_8_3_ESK.getName(), "BCPQC"); + + SnovaKey pubKey = (SnovaKey)kFact.generatePublic(new X509EncodedKeySpec(kp.getPublic().getEncoded())); + + assertEquals(kp.getPublic(), pubKey); + assertEquals(kp.getPublic().getAlgorithm(), pubKey.getAlgorithm()); + assertEquals(kp.getPublic().hashCode(), pubKey.hashCode()); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(pubKey); + + oOut.close(); + + ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + SnovaKey pubKey2 = (SnovaKey)oIn.readObject(); + + assertEquals(pubKey, pubKey2); + assertEquals(pubKey.getAlgorithm(), pubKey2.getAlgorithm()); + assertEquals(pubKey.hashCode(), pubKey2.hashCode()); + } + + public void testSnovaSign() + throws Exception + { + testSnova(SnovaParameterSpec.SNOVA_24_5_4_ESK, SnovaParameterSpec.SNOVA_24_5_4_SSK); + testSnova(SnovaParameterSpec.SNOVA_24_5_4_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_24_5_4_SHAKE_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_24_5_4_SHAKE_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_24_5_5_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_24_5_5_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_24_5_5_SHAKE_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_24_5_5_SHAKE_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_25_8_3_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_25_8_3_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_25_8_3_SHAKE_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_25_8_3_SHAKE_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_29_6_5_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_29_6_5_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_29_6_5_SHAKE_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_29_6_5_SHAKE_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_37_8_4_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_37_8_4_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_37_8_4_SHAKE_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_37_8_4_SHAKE_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_37_17_2_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_37_17_2_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_37_17_2_SHAKE_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_37_17_2_SHAKE_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_49_11_3_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_49_11_3_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_49_11_3_SHAKE_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_49_11_3_SHAKE_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_56_25_2_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_56_25_2_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_56_25_2_SHAKE_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_56_25_2_SHAKE_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_60_10_4_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_60_10_4_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_60_10_4_SHAKE_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_60_10_4_SHAKE_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_66_15_3_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_66_15_3_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_66_15_3_SHAKE_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_66_15_3_SHAKE_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_75_33_2_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_75_33_2_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_75_33_2_SHAKE_ESK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + testSnova(SnovaParameterSpec.SNOVA_75_33_2_SHAKE_SSK, SnovaParameterSpec.SNOVA_24_5_4_ESK); + } + + private void testSnova(SnovaParameterSpec spec, SnovaParameterSpec wrongSpec) + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("Snova", "BCPQC"); + + kpg.initialize(spec, new SecureRandom()); + + KeyPair kp = kpg.generateKeyPair(); + + Signature sig = Signature.getInstance(spec.getName(), "BCPQC"); + + sig.initSign(kp.getPrivate(), new SecureRandom()); + + sig.update(msg, 0, msg.length); + + byte[] s = sig.sign(); + + sig = Signature.getInstance(spec.getName(), "BCPQC"); + + assertEquals(spec.getName(), Strings.toUpperCase(sig.getAlgorithm())); + + sig.initVerify(kp.getPublic()); + + sig.update(msg, 0, msg.length); + + assertTrue(sig.verify(s)); + + kpg = KeyPairGenerator.getInstance("Snova", "BCPQC"); + + kpg.initialize(wrongSpec, new SecureRandom()); + + kp = kpg.generateKeyPair(); + + try + { + sig.initVerify(kp.getPublic()); + fail("no exception"); + } + catch (InvalidKeyException e) + { + assertEquals("signature configured for " + spec.getName(), e.getMessage()); + } + } + + public void testRestrictedKeyPairGen() + throws Exception + { + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_24_5_4_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_24_5_4_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_24_5_4_SHAKE_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_24_5_4_SHAKE_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_24_5_5_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_24_5_5_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_24_5_5_SHAKE_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_24_5_5_SHAKE_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_25_8_3_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_25_8_3_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_25_8_3_SHAKE_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_25_8_3_SHAKE_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_29_6_5_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_29_6_5_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_29_6_5_SHAKE_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_29_6_5_SHAKE_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_37_8_4_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_37_8_4_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_37_8_4_SHAKE_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_37_8_4_SHAKE_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_37_17_2_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_37_17_2_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_37_17_2_SHAKE_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_37_17_2_SHAKE_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_49_11_3_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_49_11_3_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_49_11_3_SHAKE_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_49_11_3_SHAKE_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_56_25_2_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_56_25_2_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_56_25_2_SHAKE_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_56_25_2_SHAKE_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_60_10_4_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_60_10_4_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_60_10_4_SHAKE_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_60_10_4_SHAKE_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_66_15_3_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_66_15_3_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_66_15_3_SHAKE_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_66_15_3_SHAKE_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_75_33_2_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_75_33_2_SSK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_75_33_2_SHAKE_ESK); + doTestRestrictedKeyPairGen(SnovaParameterSpec.SNOVA_75_33_2_SHAKE_SSK); + } + + private void doTestRestrictedKeyPairGen(SnovaParameterSpec spec) + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance(spec.getName(), "BCPQC"); + + kpg.initialize(spec, new SecureRandom()); + + KeyPair kp = kpg.generateKeyPair(); + + assertEquals(spec.getName(), kp.getPublic().getAlgorithm()); + assertEquals(spec.getName(), kp.getPrivate().getAlgorithm()); + + //kpg = KeyPairGenerator.getInstance(spec.getName(), "BCPQC"); + +// try +// { +// kpg.initialize(altSpec, new SecureRandom()); +// fail("no exception"); +// } +// catch (InvalidAlgorithmParameterException e) +// { +// assertEquals("key pair generator locked to " + spec.getName(), e.getMessage()); +// } + } + + public void testSnovaRandomSig() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("Snova", "BCPQC"); + + kpg.initialize(SnovaParameterSpec.SNOVA_24_5_5_SHAKE_SSK, new SecureRandom()); + + KeyPair kp = kpg.generateKeyPair(); + + Signature sig = Signature.getInstance("Snova", "BCPQC"); + + sig.initSign(kp.getPrivate(), new SecureRandom()); + + sig.update(msg, 0, msg.length); + + byte[] s = sig.sign(); + + sig = Signature.getInstance("Snova", "BCPQC"); + + sig.initVerify(kp.getPublic()); + + sig.update(msg, 0, msg.length); + + assertTrue(sig.verify(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/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/XMSSTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/XMSSTest.java index 44fb024f26..706a41dc6d 100644 --- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/XMSSTest.java +++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/XMSSTest.java @@ -488,7 +488,7 @@ public void testKeyRebuild() { KeyPairGenerator kpg = KeyPairGenerator.getInstance("XMSS", "BCPQC"); - kpg.initialize(new XMSSParameterSpec(10, XMSSParameterSpec.SHA256), new SecureRandom()); + kpg.initialize(new XMSSParameterSpec(3, XMSSParameterSpec.SHA256), new SecureRandom()); KeyPair kp = kpg.generateKeyPair(); @@ -496,11 +496,11 @@ public void testKeyRebuild() assertTrue(sig instanceof StateAwareSignature); - PrivateKey pKey1 = ((XMSSPrivateKey)kp.getPrivate()).extractKeyShard(5); + PrivateKey pKey1 = ((XMSSPrivateKey)kp.getPrivate()).extractKeyShard(7); sig.initSign(pKey1); - for (int i = 0; i != 5; i++) + for (int i = 0; i != 7; i++) { sig.update(msg, 0, msg.length); diff --git a/prov/src/test/jdk1.1/org/bouncycastle/jce/provider/test/RSATest.java b/prov/src/test/jdk1.1/org/bouncycastle/jce/provider/test/RSATest.java index e756f401a5..16e36be2d9 100644 --- a/prov/src/test/jdk1.1/org/bouncycastle/jce/provider/test/RSATest.java +++ b/prov/src/test/jdk1.1/org/bouncycastle/jce/provider/test/RSATest.java @@ -12,6 +12,7 @@ import javax.crypto.Cipher; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTestResult; import org.bouncycastle.util.test.Test; @@ -50,27 +51,6 @@ public void nextBytes( } } - private boolean arrayEquals( - byte[] a, - byte[] b) - { - if (a.length != b.length) - { - return false; - } - - for (int i = 0; i != a.length; i++) - { - if (a[i] != b[i]) - { - return false; - } - } - - return true; - } - - private RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec( new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), new BigInteger("11", 16)); @@ -115,7 +95,7 @@ public TestResult perform() byte[] out = c.doFinal(input); - if (!arrayEquals(out, output[0])) + if (!Arrays.areEqual(out, output[0])) { return new SimpleTestResult(false, "NoPadding test failed on encrypt expected " + new String(Hex.encode(output[0])) + " got " + new String(Hex.encode(out))); } @@ -124,7 +104,7 @@ public TestResult perform() out = c.doFinal(out); - if (!arrayEquals(out, input)) + if (!Arrays.areEqual(out, input)) { return new SimpleTestResult(false, "NoPadding test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); } @@ -138,7 +118,7 @@ public TestResult perform() out = c.doFinal(input); - if (!arrayEquals(out, output[1])) + if (!Arrays.areEqual(out, output[1])) { return new SimpleTestResult(false, "PKCS1 test failed on encrypt expected " + new String(Hex.encode(output[1])) + " got " + new String(Hex.encode(out))); } @@ -147,7 +127,7 @@ public TestResult perform() out = c.doFinal(out); - if (!arrayEquals(out, input)) + if (!Arrays.areEqual(out, input)) { return new SimpleTestResult(false, "PKCS1 test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); } @@ -161,7 +141,7 @@ public TestResult perform() out = c.doFinal(input); - if (!arrayEquals(out, output[2])) + if (!Arrays.areEqual(out, output[2])) { return new SimpleTestResult(false, "OAEP test failed on encrypt expected " + new String(Hex.encode(output[2])) + " got " + new String(Hex.encode(out))); } @@ -170,7 +150,7 @@ public TestResult perform() out = c.doFinal(out); - if (!arrayEquals(out, input)) + if (!Arrays.areEqual(out, input)) { return new SimpleTestResult(false, "OAEP test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); } diff --git a/prov/src/test/jdk1.3/org/bouncycastle/jce/provider/test/PSSTest.java b/prov/src/test/jdk1.3/org/bouncycastle/jce/provider/test/PSSTest.java index bd1dc32f35..f0d567501a 100644 --- a/prov/src/test/jdk1.3/org/bouncycastle/jce/provider/test/PSSTest.java +++ b/prov/src/test/jdk1.3/org/bouncycastle/jce/provider/test/PSSTest.java @@ -11,6 +11,7 @@ import java.security.spec.RSAPublicKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTestResult; import org.bouncycastle.util.test.Test; @@ -38,27 +39,6 @@ public void nextBytes( } } - private boolean arrayEquals( - byte[] a, - byte[] b) - { - if (a.length != b.length) - { - return false; - } - - for (int i = 0; i != a.length; i++) - { - if (a[i] != b[i]) - { - return false; - } - } - - return true; - } - - private RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec( new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), new BigInteger("010001",16)); @@ -98,7 +78,7 @@ public TestResult perform() s.update(msg1a); byte[] sig = s.sign(); - if (!arrayEquals(sig1a, sig)) + if (!Arrays.areEqual(sig1a, sig)) { return new SimpleTestResult(false, "PSS Sign test expected " + new String(Hex.encode(sig1a)) + " got " + new String(Hex.encode(sig))); } @@ -118,7 +98,7 @@ public TestResult perform() s.update(msg1a); sig = s.sign(); - if (!arrayEquals(sig1b, sig)) + if (!Arrays.areEqual(sig1b, sig)) { return new SimpleTestResult(false, "PSS Sign test expected " + new String(Hex.encode(sig1b)) + " got " + new String(Hex.encode(sig))); } diff --git a/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/DHTest.java b/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/DHTest.java index 19c30d6cef..b394a1572a 100644 --- a/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/DHTest.java +++ b/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/DHTest.java @@ -26,6 +26,7 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ECParameterSpec; import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTestResult; import org.bouncycastle.util.test.Test; @@ -252,7 +253,7 @@ private TestResult testRandom( // a and a2 should be equivalent! byte[] encodeParams_2 = a2.getEncoded(); - if (!arrayEquals(encodeParams, encodeParams_2)) + if (!Arrays.areEqual(encodeParams, encodeParams_2)) { return new SimpleTestResult(false, this.getName() + ": encode/decode parameters failed"); } @@ -474,27 +475,6 @@ private TestResult testExceptions() return new SimpleTestResult(true, this.getName() + ": Okay"); } - - private boolean arrayEquals( - byte[] a, - byte[] b) - { - if (a.length != b.length) - { - return false; - } - - for (int i = 0; i != a.length; i++) - { - if (a[i] != b[i]) - { - return false; - } - } - - return true; - } - public TestResult perform() { diff --git a/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/PSSTest.java b/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/PSSTest.java index 3cba08eb79..672a6b9760 100644 --- a/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/PSSTest.java +++ b/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/PSSTest.java @@ -15,6 +15,7 @@ import java.security.spec.RSAPublicKeySpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Arrays; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.test.SimpleTestResult; import org.bouncycastle.util.test.Test; @@ -41,27 +42,6 @@ public void nextBytes( } } - private boolean arrayEquals( - byte[] a, - byte[] b) - { - if (a.length != b.length) - { - return false; - } - - for (int i = 0; i != a.length; i++) - { - if (a[i] != b[i]) - { - return false; - } - } - - return true; - } - - private RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec( new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), new BigInteger("010001",16)); @@ -103,7 +83,7 @@ public TestResult perform() s.update(msg1a); byte[] sig = s.sign(); - if (!arrayEquals(sig1a, sig)) + if (!Arrays.areEqual(sig1a, sig)) { return new SimpleTestResult(false, "PSS Sign test expected " + new String(Hex.encode(sig1a)) + " got " + new String(Hex.encode(sig))); } @@ -129,7 +109,7 @@ public TestResult perform() } AlgorithmParameters pss = s.getParameters(); - if (!arrayEquals(pss.getEncoded(), new byte[] { 0x30, 0x00 })) + if (!Arrays.areEqual(pss.getEncoded(), new byte[] { 0x30, 0x00 })) { return new SimpleTestResult(false, "failed default encoding test."); } @@ -142,7 +122,7 @@ public TestResult perform() pss = s.getParameters(); - if (!arrayEquals(sig1b, sig)) + if (!Arrays.areEqual(sig1b, sig)) { return new SimpleTestResult(false, "PSS Sign test expected " + new String(Hex.encode(sig1b)) + " got " + new String(Hex.encode(sig))); } @@ -171,7 +151,7 @@ public TestResult perform() pss = s.getParameters(); - if (!arrayEquals(sig1c, sig)) + if (!Arrays.areEqual(sig1c, sig)) { return new SimpleTestResult(false, "PSS Sign test expected " + new String(Hex.encode(sig1c)) + " got " + new String(Hex.encode(sig))); } diff --git a/prov/src/test/jdk1.5/org/bouncycastle/jce/provider/test/RegressionTest.java b/prov/src/test/jdk1.5/org/bouncycastle/jce/provider/test/RegressionTest.java new file mode 100644 index 0000000000..ed0954e26b --- /dev/null +++ b/prov/src/test/jdk1.5/org/bouncycastle/jce/provider/test/RegressionTest.java @@ -0,0 +1,115 @@ +package org.bouncycastle.jce.provider.test; + +import java.security.Security; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.test.SimpleTest; +import org.bouncycastle.util.test.Test; + +public class RegressionTest +{ + public static Test[] tests = { + new AEADTest(), + new AESSICTest(), + new AESTest(), + new AlgorithmParametersTest(), + new ARIATest(), + new BCFKSStoreTest(), + new BlockCipherTest(), + new CamelliaTest(), + new CertLocaleTest(), + new CertPathBuilderTest(), + new CertPathTest(), + new CertPathValidatorTest(), + new CertStoreTest(), + new CertTest(), + new CertUniqueIDTest(), + new ChaCha20Poly1305Test(), + new CipherStreamTest(), + new CipherStreamTest2(), + new CMacTest(), + new CRL5Test(), + new DESedeTest(), + new DetDSATest(), + new DHIESTest(), + new DHTest(), + new DigestTest(), + new DoFinalTest(), + new DRBGTest(), + new DSATest(), + new DSTU4145Test(), + new DSTU7624Test(), + new ECDSA5Test(), + new ECEncodingTest(), + new ECIESTest(), + new ECIESVectorTest(), + new ECNRTest(), + new EdECTest(), + new ElGamalTest(), + new EncryptedPrivateKeyInfoTest(), + new FIPSDESTest(), + new GMacTest(), + new GOST28147Test(), + new GOST3410KeyPairTest(), + new GOST3410Test(), + new GOST3412Test(), + new HMacTest(), + new IESTest(), + new ImplicitlyCaTest(), + new KeccakTest(), + new KeyStoreTest(), + new MacTest(), + new MQVTest(), + new MultiCertStoreTest(), + new NamedCurveTest(), + new NetscapeCertRequestTest(), + new NISTCertPathTest(), + new NoekeonTest(), + new OCBTest(), + new OpenSSHSpecTests(), + new PBETest(), + new PKCS10CertRequestTest(), + new PKCS12StorePBETest(), + new PKCS12StoreTest(), + new PKIXNameConstraintsTest(), + new PKIXPolicyMappingTest(), + new PKIXTest(), + new Poly1305Test(), + new PQCDHTest(), + new PSSTest(), + new RSATest(), + new SealedTest(), + new SEEDTest(), + new SerialisationTest(), + new Shacal2Test(), + new SigNameTest(), + new SignatureTest(), + new SigTest(), + new SipHash128Test(), + new SipHashTest(), + new SkeinTest(), + new SlotTwoTest(), + new SM2CipherTest(), + new SM2SignatureTest(), + new SM4Test(), + new ThreefishTest(), + new TLSKDFTest(), + new WrapTest(), + new X509CertificatePairTest(), + new X509StreamParserTest(), + new XIESTest(), + new XOFTest(), + new ZucTest(), + }; + + public static void main(String[] args) + { + System.setProperty("org.bouncycastle.bks.enable_v1", "true"); + + Security.addProvider(new BouncyCastleProvider()); + + System.out.println("Testing " + Security.getProvider("BC").getInfo() + " version: " + Security.getProvider("BC").getVersion()); + + SimpleTest.runTests(tests); + } +} diff --git a/prov/src/test/jdk1.5/org/bouncycastle/test/JVMVersionTest.java b/prov/src/test/jdk1.5/org/bouncycastle/test/JVMVersionTest.java index 06e26c6851..ca7db6a612 100644 --- a/prov/src/test/jdk1.5/org/bouncycastle/test/JVMVersionTest.java +++ b/prov/src/test/jdk1.5/org/bouncycastle/test/JVMVersionTest.java @@ -12,7 +12,7 @@ * if -Dtest.java.version.prefix=17 and System.getProperty("java.version") = 17.0.4.1 * Then this test will pass. */ -public class JVMVersionTestProv extends TestCase +public class JVMVersionTest extends TestCase { private static final String expectedVersionPropName = "test.java.version.prefix"; diff --git a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/AllTests21.java b/prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/AllTests17.java similarity index 74% rename from prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/AllTests21.java rename to prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/AllTests17.java index b9e25bf8b5..00ff4869bf 100644 --- a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/AllTests21.java +++ b/prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/AllTests17.java @@ -1,4 +1,4 @@ -package org.bouncycastle.jcacje.provider.test; +package org.bouncycastle.jcajce.provider.test; import junit.framework.Test; import junit.framework.TestCase; @@ -6,21 +6,21 @@ import org.bouncycastle.test.PrintTestResult; -public class AllTests21 +public class AllTests17 extends TestCase { public static void main(String[] args) { - PrintTestResult.printResult(junit.textui.TestRunner.run(suite())); } public static Test suite() { - TestSuite suite = new TestSuite("JDK21 Provider Tests"); + TestSuite suite = new TestSuite("JDK17 Provider Tests"); suite.addTestSuite(NTRUKEMTest.class); suite.addTestSuite(SNTRUPrimeKEMTest.class); suite.addTestSuite(MLKEMTest.class); + suite.addTestSuite(HQCTest.class); return suite; } } diff --git a/prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/HQCTest.java b/prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/HQCTest.java new file mode 100644 index 0000000000..563464619e --- /dev/null +++ b/prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/HQCTest.java @@ -0,0 +1,174 @@ +package org.bouncycastle.jcajce.provider.test; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; + +import javax.crypto.KEM; +import javax.crypto.SecretKey; + +import org.bouncycastle.jcajce.spec.KEMParameterSpec; +import org.bouncycastle.jcajce.spec.KTSParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; +import org.bouncycastle.pqc.jcajce.spec.HQCParameterSpec; +import org.bouncycastle.util.Arrays; + +import junit.framework.TestCase; + +public class HQCTest + extends TestCase +{ + public static void main(String[] args) + throws Exception + { + HQCTest test = new HQCTest(); + test.setUp(); + test.testKEM(); + } + + public void setUp() + { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastleProvider()); + } + if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastlePQCProvider()); + } + } + + public void testKEM() + throws Exception + { + // Receiver side + KeyPairGenerator g = KeyPairGenerator.getInstance("HQC", "BCPQC"); + + g.initialize(HQCParameterSpec.hqc192, new SecureRandom()); + + KeyPair kp = g.generateKeyPair(); + PublicKey pkR = kp.getPublic(); + + // Sender side + KEM kemS = KEM.getInstance("HQC", "BCPQC"); + KTSParameterSpec ktsSpec = null; + KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsSpec, null); + KEM.Encapsulated enc = e.encapsulate(); + SecretKey secS = enc.key(); + byte[] em = enc.encapsulation(); + byte[] params = enc.params(); + + // Receiver side + KEM kemR = KEM.getInstance("HQC", "BCPQC"); + KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsSpec); + SecretKey secR = d.decapsulate(em); + + // secS and secR will be identical + assertEquals(secS.getAlgorithm(), secR.getAlgorithm()); + assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded())); + } + + public void testBasicKEMAES() + throws Exception + { + if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastlePQCProvider()); + } + KeyPairGenerator kpg = KeyPairGenerator.getInstance("HQC", "BCPQC"); + kpg.initialize(HQCParameterSpec.hqc192, new SecureRandom()); + + performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES")); + performKEM(kpg.generateKeyPair(), 0, 16, "AES", new KEMParameterSpec("AES")); + performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES-KWP")); + + try + { + performKEM(kpg.generateKeyPair(), 0, 16, "AES-KWP", new KEMParameterSpec("AES")); + fail(); + } + catch (Exception ex) + { + } + + kpg.initialize(HQCParameterSpec.hqc256, new SecureRandom()); + performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES")); + + } + + public void testBasicKEMCamellia() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("HQC", "BCPQC"); + kpg.initialize(HQCParameterSpec.hqc128, new SecureRandom()); + + performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("Camellia", 256).build()); + performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("Camellia-KWP", 256).build()); + } + + public void testBasicKEMSEED() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("HQC", "BCPQC"); + kpg.initialize(HQCParameterSpec.hqc192, new SecureRandom()); + + performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("SEED", 128).build()); + } + + public void testBasicKEMARIA() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("HQC", "BCPQC"); + kpg.initialize(HQCParameterSpec.hqc192, new SecureRandom()); + + performKEM(kpg.generateKeyPair(), new KEMParameterSpec("ARIA")); + performKEM(kpg.generateKeyPair(), new KEMParameterSpec("ARIA-KWP")); + } + + private void performKEM(KeyPair kp, int from, int to, String algorithm, KTSParameterSpec ktsParameterSpec) + throws Exception + { + PublicKey pkR = kp.getPublic(); + + // Sender side + KEM kemS = KEM.getInstance("HQC", "BCPQC"); + KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null); + KEM.Encapsulated enc = e.encapsulate(from, to, algorithm); + SecretKey secS = enc.key(); + byte[] em = enc.encapsulation(); + + // Receiver side + KEM kemR = KEM.getInstance("HQC", "BCPQC"); + KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec); + SecretKey secR = d.decapsulate(em, from, to, algorithm); + + // secS and secR will be identical + assertEquals(secS.getAlgorithm(), secR.getAlgorithm()); + assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded())); + } + + private void performKEM(KeyPair kp, KTSParameterSpec ktsParameterSpec) + throws Exception + { + PublicKey pkR = kp.getPublic(); + + // Sender side + KEM kemS = KEM.getInstance("HQC", "BCPQC"); + KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null); + KEM.Encapsulated enc = e.encapsulate(); + SecretKey secS = enc.key(); + byte[] em = enc.encapsulation(); + + // Receiver side + KEM kemR = KEM.getInstance("HQC", "BCPQC"); + KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec); + SecretKey secR = d.decapsulate(em); + + // secS and secR will be identical + assertEquals(secS.getAlgorithm(), secR.getAlgorithm()); + assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded())); + } +} diff --git a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/MLKEMTest.java b/prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/MLKEMTest.java similarity index 93% rename from prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/MLKEMTest.java rename to prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/MLKEMTest.java index d2dfd9d8d8..fad061b140 100644 --- a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/MLKEMTest.java +++ b/prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/MLKEMTest.java @@ -1,6 +1,14 @@ -package org.bouncycastle.jcacje.provider.test; +package org.bouncycastle.jcajce.provider.test; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; + +import javax.crypto.KEM; +import javax.crypto.SecretKey; -import junit.framework.TestCase; import org.bouncycastle.jcajce.spec.KEMParameterSpec; import org.bouncycastle.jcajce.spec.KTSParameterSpec; import org.bouncycastle.jcajce.spec.MLKEMParameterSpec; @@ -8,14 +16,7 @@ import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; import org.bouncycastle.util.Arrays; -import javax.crypto.KEM; -import javax.crypto.SecretKey; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.Security; - +import junit.framework.TestCase; public class MLKEMTest extends TestCase @@ -40,7 +41,7 @@ public void testKEM() PublicKey pkR = kp.getPublic(); // Sender side - KEM kemS = KEM.getInstance("ML-KEM"); + KEM kemS = KEM.getInstance("ML-KEM", "BC"); KTSParameterSpec ktsSpec = null; KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsSpec, null); KEM.Encapsulated enc = e.encapsulate(); @@ -49,7 +50,7 @@ public void testKEM() byte[] params = enc.params(); // Receiver side - KEM kemR = KEM.getInstance("ML-KEM"); + KEM kemR = KEM.getInstance("ML-KEM", "BC"); KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsSpec); SecretKey secR = d.decapsulate(em); @@ -123,14 +124,14 @@ private void performKEM(KeyPair kp, int from, int to, String algorithm, KTSParam PublicKey pkR = kp.getPublic(); // Sender side - KEM kemS = KEM.getInstance("ML-KEM"); + KEM kemS = KEM.getInstance("ML-KEM", "BC"); KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null); KEM.Encapsulated enc = e.encapsulate(from, to, algorithm); SecretKey secS = enc.key(); byte[] em = enc.encapsulation(); // Receiver side - KEM kemR = KEM.getInstance("ML-KEM"); + KEM kemR = KEM.getInstance("ML-KEM", "BC"); KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec); SecretKey secR = d.decapsulate(em, from, to, algorithm); @@ -145,14 +146,14 @@ private void performKEM(KeyPair kp, KTSParameterSpec ktsParameterSpec) PublicKey pkR = kp.getPublic(); // Sender side - KEM kemS = KEM.getInstance("ML-KEM"); + KEM kemS = KEM.getInstance("ML-KEM", "BC"); KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null); KEM.Encapsulated enc = e.encapsulate(); SecretKey secS = enc.key(); byte[] em = enc.encapsulation(); // Receiver side - KEM kemR = KEM.getInstance("ML-KEM"); + KEM kemR = KEM.getInstance("ML-KEM", "BC"); KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec); SecretKey secR = d.decapsulate(em); diff --git a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/NTRUKEMTest.java b/prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/NTRUKEMTest.java similarity index 98% rename from prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/NTRUKEMTest.java rename to prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/NTRUKEMTest.java index 0b95b45d07..8d50bf9c68 100644 --- a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/NTRUKEMTest.java +++ b/prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/NTRUKEMTest.java @@ -1,4 +1,4 @@ -package org.bouncycastle.jcacje.provider.test; +package org.bouncycastle.jcajce.provider.test; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -9,15 +9,15 @@ import javax.crypto.KEM; import javax.crypto.SecretKey; -import junit.framework.TestCase; import org.bouncycastle.jcajce.spec.KEMParameterSpec; import org.bouncycastle.jcajce.spec.KTSParameterSpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; import org.bouncycastle.pqc.jcajce.spec.NTRUParameterSpec; -import org.bouncycastle.pqc.jcajce.interfaces.NTRUKey; import org.bouncycastle.util.Arrays; +import junit.framework.TestCase; + public class NTRUKEMTest extends TestCase @@ -47,13 +47,13 @@ public void setUp() // FixedSecureRandom fixedRandom = new FixedSecureRandom(fixedRandomBytes); // // // Receiver side -// KeyPairGenerator g = KeyPairGenerator.getInstance("NTRU"); +// KeyPairGenerator g = KeyPairGenerator.getInstance("NTRU", "BCPQC"); // g.initialize(NTRUParameterSpec.sntrup653, fixedRandom); // KeyPair kp = g.generateKeyPair(); // NTRUKey pkR = (NTRUKey)kp.getPublic(); // // // Sender side -// KEM kemS = KEM.getInstance("NTRU"); +// KEM kemS = KEM.getInstance("NTRU", "BCPQC"); // KTSParameterSpec ktsSpec = null; // KEM.Encapsulator e = kemS.newEncapsulator((PublicKey)pkR, ktsSpec, fixedRandom); // KEM.Encapsulated enc = e.encapsulate(); @@ -65,7 +65,7 @@ public void setUp() // assertTrue(Arrays.areEqual(enc.key().getEncoded(), ss)); // // // Receiver side -// KEM kemR = KEM.getInstance("NTRU"); +// KEM kemR = KEM.getInstance("NTRU", "BCPQC"); // KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsSpec); // SecretKey secR = d.decapsulate(em); // @@ -86,7 +86,7 @@ public void testKEM() PublicKey pkR = kp.getPublic(); // Sender side - KEM kemS = KEM.getInstance("NTRU"); + KEM kemS = KEM.getInstance("NTRU", "BCPQC"); KTSParameterSpec ktsSpec = null; KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsSpec, null); KEM.Encapsulated enc = e.encapsulate(); @@ -95,8 +95,8 @@ public void testKEM() byte[] params = enc.params(); // Receiver side - KEM kemR = KEM.getInstance("NTRU"); -// AlgorithmParameters algParams = AlgorithmParameters.getInstance("NTRU"); + KEM kemR = KEM.getInstance("NTRU", "BCPQC"); +// AlgorithmParameters algParams = AlgorithmParameters.getInstance("NTRU", "BCPQC"); // algParams.init(params); // NTRUParameterSpec specR = algParams.getParameterSpec(NTRUParameterSpec.class); KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsSpec); @@ -114,7 +114,7 @@ public void testBasicKEMAES() { Security.addProvider(new BouncyCastlePQCProvider()); } - KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRU", "BC"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRU", "BCPQC"); kpg.initialize(NTRUParameterSpec.ntruhps2048509, new SecureRandom()); performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES")); @@ -172,14 +172,14 @@ private void performKEM(KeyPair kp, int from, int to, String algorithm, KTSParam PublicKey pkR = kp.getPublic(); // Sender side - KEM kemS = KEM.getInstance("NTRU"); + KEM kemS = KEM.getInstance("NTRU", "BCPQC"); KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null); KEM.Encapsulated enc = e.encapsulate(from, to, algorithm); SecretKey secS = enc.key(); byte[] em = enc.encapsulation(); // Receiver side - KEM kemR = KEM.getInstance("NTRU"); + KEM kemR = KEM.getInstance("NTRU", "BCPQC"); KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec); SecretKey secR = d.decapsulate(em, from, to, algorithm); @@ -194,14 +194,14 @@ private void performKEM(KeyPair kp, KTSParameterSpec ktsParameterSpec) PublicKey pkR = kp.getPublic(); // Sender side - KEM kemS = KEM.getInstance("NTRU"); + KEM kemS = KEM.getInstance("NTRU", "BCPQC"); KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null); KEM.Encapsulated enc = e.encapsulate(); SecretKey secS = enc.key(); byte[] em = enc.encapsulation(); // Receiver side - KEM kemR = KEM.getInstance("NTRU"); + KEM kemR = KEM.getInstance("NTRU", "BCPQC"); // KTSParameterSpec RktsParameterSpec = new KTSParameterSpec.Builder( // ktsParameterSpec.getKeyAlgorithmName(), // enc.key().getEncoded().length diff --git a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java b/prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/SNTRUPrimeKEMTest.java similarity index 97% rename from prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java rename to prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/SNTRUPrimeKEMTest.java index e20c3838dd..03fea2cadd 100644 --- a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java +++ b/prov/src/test/jdk17/org/bouncycastle/jcajce/provider/test/SNTRUPrimeKEMTest.java @@ -1,4 +1,4 @@ -package org.bouncycastle.jcacje.provider.test; +package org.bouncycastle.jcajce.provider.test; import java.security.KeyPair; import java.security.KeyPairGenerator; @@ -48,13 +48,13 @@ public void testKEMVec() FixedSecureRandom fixedRandom = new FixedSecureRandom(fixedRandomBytes); // Receiver side - KeyPairGenerator g = KeyPairGenerator.getInstance("SNTRUPrime"); + KeyPairGenerator g = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC"); g.initialize(SNTRUPrimeParameterSpec.sntrup653, fixedRandom); KeyPair kp = g.generateKeyPair(); SNTRUPrimeKey pkR = (SNTRUPrimeKey)kp.getPublic(); // Sender side - KEM kemS = KEM.getInstance("SNTRUPrime"); //Should the name be "SNTRUPrime-KEM" ? + KEM kemS = KEM.getInstance("SNTRUPrime", "BCPQC"); //Should the name be "SNTRUPrime-KEM" ? KTSParameterSpec ktsSpec = null; KEM.Encapsulator e = kemS.newEncapsulator((PublicKey)pkR, ktsSpec, fixedRandom); KEM.Encapsulated enc = e.encapsulate(); @@ -66,7 +66,7 @@ public void testKEMVec() assertTrue(Arrays.areEqual(enc.key().getEncoded(), ss)); // Receiver side - KEM kemR = KEM.getInstance("SNTRUPrime"); + KEM kemR = KEM.getInstance("SNTRUPrime", "BCPQC"); KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsSpec); SecretKey secR = d.decapsulate(em); @@ -79,7 +79,7 @@ public void testKEM() throws Exception { // Receiver side - KeyPairGenerator g = KeyPairGenerator.getInstance("SNTRUPrime"); + KeyPairGenerator g = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC"); g.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom()); @@ -87,7 +87,7 @@ public void testKEM() PublicKey pkR = kp.getPublic(); // Sender side - KEM kemS = KEM.getInstance("SNTRUPrime"); //Should the name be "SNTRUPrime-KEM" ? + KEM kemS = KEM.getInstance("SNTRUPrime", "BCPQC"); //Should the name be "SNTRUPrime-KEM" ? KTSParameterSpec ktsSpec = null; KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsSpec, null); KEM.Encapsulated enc = e.encapsulate(); @@ -96,8 +96,8 @@ public void testKEM() byte[] params = enc.params(); // Receiver side - KEM kemR = KEM.getInstance("SNTRUPrime"); -// AlgorithmParameters algParams = AlgorithmParameters.getInstance("SNTRUPrime"); + KEM kemR = KEM.getInstance("SNTRUPrime", "BCPQC"); +// AlgorithmParameters algParams = AlgorithmParameters.getInstance("SNTRUPrime", "BCPQC"); // algParams.init(params); // SNTRUPrimeParameterSpec specR = algParams.getParameterSpec(SNTRUPrimeParameterSpec.class); KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsSpec); @@ -173,14 +173,14 @@ private void performKEM(KeyPair kp, int from, int to, String algorithm, KTSParam PublicKey pkR = kp.getPublic(); // Sender side - KEM kemS = KEM.getInstance("SNTRUPrime"); + KEM kemS = KEM.getInstance("SNTRUPrime", "BCPQC"); KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null); KEM.Encapsulated enc = e.encapsulate(from, to, algorithm); SecretKey secS = enc.key(); byte[] em = enc.encapsulation(); // Receiver side - KEM kemR = KEM.getInstance("SNTRUPrime"); + KEM kemR = KEM.getInstance("SNTRUPrime", "BCPQC"); KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec); SecretKey secR = d.decapsulate(em, from, to, algorithm); @@ -195,14 +195,14 @@ private void performKEM(KeyPair kp, KTSParameterSpec ktsParameterSpec) PublicKey pkR = kp.getPublic(); // Sender side - KEM kemS = KEM.getInstance("SNTRUPrime"); + KEM kemS = KEM.getInstance("SNTRUPrime", "BCPQC"); KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null); KEM.Encapsulated enc = e.encapsulate(); SecretKey secS = enc.key(); byte[] em = enc.encapsulation(); // Receiver side - KEM kemR = KEM.getInstance("SNTRUPrime"); + KEM kemR = KEM.getInstance("SNTRUPrime", "BCPQC"); // KTSParameterSpec RktsParameterSpec = new KTSParameterSpec.Builder( // ktsParameterSpec.getKeyAlgorithmName(), // enc.key().getEncoded().length diff --git a/prov/src/test/jdk25/org/bouncycastle/jcajce/provider/kdf/test/AllTests25.java b/prov/src/test/jdk25/org/bouncycastle/jcajce/provider/kdf/test/AllTests25.java new file mode 100644 index 0000000000..03617e48a7 --- /dev/null +++ b/prov/src/test/jdk25/org/bouncycastle/jcajce/provider/kdf/test/AllTests25.java @@ -0,0 +1,25 @@ +package org.bouncycastle.jcajce.provider.kdf.test; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; +import org.bouncycastle.test.PrintTestResult; + +public class AllTests25 + extends TestCase +{ + public static void main(String[] args) + { + PrintTestResult.printResult(junit.textui.TestRunner.run(suite())); + } + + public static Test suite() + { + TestSuite suite = new TestSuite("JDK25 Provider Tests"); + suite.addTestSuite(HKDFTest.class); + suite.addTestSuite(PBEPBKDF2Test.class); + suite.addTestSuite(ScryptTest.class); + return suite; + } +} + diff --git a/prov/src/test/jdk25/org/bouncycastle/jcajce/provider/kdf/test/HKDFTest.java b/prov/src/test/jdk25/org/bouncycastle/jcajce/provider/kdf/test/HKDFTest.java new file mode 100644 index 0000000000..d4e5c1c45f --- /dev/null +++ b/prov/src/test/jdk25/org/bouncycastle/jcajce/provider/kdf/test/HKDFTest.java @@ -0,0 +1,297 @@ +package org.bouncycastle.jcajce.provider.kdf.test; + +import junit.framework.TestCase; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jcajce.spec.PBKDF2ParameterSpec; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Hex; +import javax.crypto.spec.HKDFParameterSpec; + +import javax.crypto.KDF; +import javax.crypto.KDFParameters; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; + +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.security.Security; + +import static org.bouncycastle.util.Arrays.areEqual; + +public class HKDFTest + extends TestCase +{ + public void setUp() + { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastleProvider()); + } + } + + public void testKDF() + throws Exception + { + + setUp(); + KDF kdfHkdf = KDF.getInstance("HKDF-SHA256", "BC"); + + byte[] ikm = Hex.decode("c702e7d0a9e064b09ba55245fb733cf3"); + byte[] salt = Strings.toByteArray("The Cryptographic Message Syntax"); + byte[] info = Hex.decode("301b0609608648016503040106300e040c5c79058ba2f43447639d29e2"); + byte[] okm = Hex.decode("2124ffb29fac4e0fbbc7d5d87492bff3"); + byte[] genOkm; + HKDFParameterSpec.ExtractThenExpand hkdfParams1 = HKDFParameterSpec.ofExtract().addIKM(ikm) + .addSalt(salt).thenExpand(info, okm.length); + + genOkm = kdfHkdf.deriveData(hkdfParams1); + + if (!areEqual(genOkm, okm)) + { + fail("HKDF failed generator test"); + } + + // Extract Only + ikm = Hex.decode("c702e7d0a9e064b09ba55245fb733cf3"); + salt = Strings.toByteArray("The Cryptographic Message Syntax"); + okm = Hex.decode("4d757351dc7a354f041aacd288c8957e341ac8903ba8b4debde8e856f1b58e31"); + + HKDFParameterSpec.Extract hkdfParams2 = HKDFParameterSpec.ofExtract().addIKM(ikm).addSalt(salt).extractOnly(); + + genOkm = kdfHkdf.deriveData(hkdfParams2); + + if (!areEqual(genOkm, okm)) + { + fail("HKDF failed generator test"); + } + + //TODO: make test for derived keys +// kdfHkdf.deriveKey("AES", hkdfParams); + + //TODO: do we want users to initialize the digest? + //KDF kdf = KDF.getInstance("HKDF", "BC"); + //kdf.init(new KDFParameter(new SHA1Digest())); + //kdf.deriveData(hkdfParams); + } + + private boolean doComparison(String algorithm, byte[] ikm, byte[] salt, byte[] info) + throws Exception + { + KDF kdf = KDF.getInstance(algorithm, "BC"); + HKDFParameterSpec.ExtractThenExpand spec = HKDFParameterSpec.ofExtract().addIKM(ikm) + .addSalt(salt).thenExpand(info, ikm.length); + + org.bouncycastle.jcajce.spec.HKDFParameterSpec pre25spec = new org.bouncycastle.jcajce.spec.HKDFParameterSpec(ikm, salt, info, ikm.length); + byte[] kdfSecret = kdf.deriveData(spec); + + SecretKeyFactory fact = SecretKeyFactory.getInstance(algorithm, "BC"); + SecretKey factSecret = fact.generateSecret(pre25spec); + + return Arrays.areEqual(kdfSecret, factSecret.getEncoded()); + } + + public void testSecretKeyFactoryComparison() + throws Exception + { + setUp(); + String[] algorithms = new String[]{ + "HKDF-SHA256", + "HKDF-SHA384", + "HKDF-SHA512", + }; + byte[] ikm = new byte[16]; + byte[] salt = new byte[16]; + byte[] info = new byte[16]; + SecureRandom random = new SecureRandom(); + for (String algorithm : algorithms) + { + random.nextBytes(ikm); + random.nextBytes(salt); + random.nextBytes(info); + if (!doComparison(algorithm, ikm, salt, info)) + { + fail("failed to generate same secret using kdf and secret key factory for: " + algorithm); + } + } + } + + public void testExceptionHandling() + { + setUp(); + try + { + KDF kdf = KDF.getInstance("NonExistentAlgorithm", "BC"); + fail("Exception was not thrown for nonexistent algorithm"); + } + catch (Exception e) + { + assertTrue(e instanceof NoSuchAlgorithmException); + } + try + { + KDF kdf = KDF.getInstance("HKDF-SHA256", "NonExistentProvider"); + fail("Exception was not thrown for nonexistent provider"); + } + catch (Exception e) + { + assertTrue(e instanceof NoSuchProviderException); + } + try + { + KDF kdf = KDF.getInstance(null, "BC"); + fail("Exception was not thrown for null algorithm"); + } + catch (Exception e) + { + assertTrue(e instanceof NullPointerException); + } + try + { + KDFParameters kdfParameters = new InvalidKDFParameters(); + KDF kdf = KDF.getInstance("HKDF-SHA256", kdfParameters, "BC"); + fail("Exception was not thrown for valid algorithm, but invalid parameters"); + } + catch (Exception e) + { + assertTrue(e instanceof InvalidAlgorithmParameterException); + } + try + { + KDF kdf = KDF.getInstance("HKDF-SHA256", "BC"); + PBKDF2ParameterSpec pbepbkdf2ParameterSpec = new PBKDF2ParameterSpec(new char[16], new byte[16], 16); + kdf.deriveData(pbepbkdf2ParameterSpec); + fail("Exception was not thrown for invalid derivation spec"); + } + catch (Exception e) + { + assertTrue(e instanceof InvalidAlgorithmParameterException); + } + //TODO: check if the derived keying material is not extractable +// try +// { +// KDF kdf = KDF.getInstance("HKDF-SHA256", "BC"); +// HKDFParameterSpec hkdfParameterSpec = HKDFParameterSpec.skipExtractParameters(new byte[16], new byte[16]); +// kdf.deriveData(hkdfParameterSpec); +// fail("Exception was not thrown for invalid derivation spec"); +// } +// catch (Exception e) +// { +// assertTrue(e instanceof InvalidAlgorithmParameterException); +// } + } + + public void testExtractWithConcatenatedIKMAndSalts() + throws Exception + { + setUp(); + KDF kdfHkdf = KDF.getInstance("HKDF-SHA256", "BC"); + + byte[][] ikms = new byte[][] + { + Hex.decode("000102030405060708090a0b0c0d0e0f"), + Hex.decode("101112131415161718191a1b1c1d1e1f"), + Hex.decode("202122232425262728292a2b2c2d2e2f"), + Hex.decode("303132333435363738393a3b3c3d3e3f"), + Hex.decode("404142434445464748494a4b4c4d4e4f"), + }; + + byte[][] salts = new byte[][] + { + Hex.decode("606162636465666768696a6b6c6d6e6f"), + Hex.decode("707172737475767778797a7b7c7d7e7f"), + Hex.decode("808182838485868788898a8b8c8d8e8f"), + Hex.decode("909192939495969798999a9b9c9d9e9f"), + Hex.decode("a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"), + }; + byte[] info = Hex.decode("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); + byte[] okm = Hex.decode( + "b11e398dc80327a1c8e7f78c596a4934" + + "4f012eda2d4efad8a050cc4c19afa97c" + + "59045a99cac7827271cb41c65e590e09" + + "da3275600c2f09b8367793a9aca3db71" + + "cc30c58179ec3e87c14c01d5c1f3434f" + + "1d87"); + + HKDFParameterSpec.ExtractThenExpand hkdfParams1 = HKDFParameterSpec.ofExtract() + .addIKM(ikms[0]).addIKM(ikms[1]).addIKM(ikms[2]).addIKM(ikms[3]).addIKM(ikms[4]) + .addSalt(salts[0]).addSalt(salts[1]).addSalt(salts[2]).addSalt(salts[3]).addSalt(salts[4]) + .thenExpand(info, okm.length); + + byte[] genOkm = kdfHkdf.deriveData(hkdfParams1); + + if (!areEqual(genOkm, okm)) + { + fail("HKDF failed for multiple ikms/salts"); + } + + HKDFParameterSpec.Extract hkdfParams2 = HKDFParameterSpec.ofExtract() + .addIKM(ikms[0]).addIKM(ikms[1]).addIKM(ikms[2]).addIKM(ikms[3]).addIKM(ikms[4]) + .addSalt(salts[0]).addSalt(salts[1]).addSalt(salts[2]).addSalt(salts[3]).addSalt(salts[4]) + .extractOnly(); + + okm = Hex.decode("06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244"); + genOkm = kdfHkdf.deriveData(hkdfParams2); + + if (!areEqual(genOkm, okm)) + { + fail("HKDF failed for multiple ikms/salts"); + } + } + + /** + * Helper method to concatenate two byte arrays. + */ + private byte[] concatenate(byte[] first, byte[] second) + { + byte[] result = new byte[first.length + second.length]; + System.arraycopy(first, 0, result, 0, first.length); + System.arraycopy(second, 0, result, first.length, second.length); + return result; + } + + private static class InvalidKDFParameters + implements KDFParameters + { + + public InvalidKDFParameters() + { + super(); + } + + + @Override + public int hashCode() + { + return super.hashCode(); + } + + + @Override + public boolean equals(Object obj) + { + return super.equals(obj); + } + + + @Override + protected Object clone() throws CloneNotSupportedException + { + return super.clone(); + } + + + @Override + public String toString() + { + return super.toString(); + } + + } +} diff --git a/prov/src/test/jdk25/org/bouncycastle/jcajce/provider/kdf/test/PBEPBKDF2Test.java b/prov/src/test/jdk25/org/bouncycastle/jcajce/provider/kdf/test/PBEPBKDF2Test.java new file mode 100644 index 0000000000..1a352ec6b7 --- /dev/null +++ b/prov/src/test/jdk25/org/bouncycastle/jcajce/provider/kdf/test/PBEPBKDF2Test.java @@ -0,0 +1,246 @@ +package org.bouncycastle.jcajce.provider.kdf.test; + +import junit.framework.TestCase; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.jcajce.spec.HKDFParameterSpec; +import org.bouncycastle.jcajce.spec.PBKDF2ParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Hex; + +import javax.crypto.KDF; +import javax.crypto.KDFParameters; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.security.Security; + +import static org.bouncycastle.util.Arrays.areEqual; + +public class PBEPBKDF2Test + extends TestCase +{ + public void setUp() + { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastleProvider()); + } + } + + public void testKDF() + throws Exception + { + + setUp(); + KDF kdf = KDF.getInstance("PBKDF2WITH8BIT", "BC"); + // + // RFC 3211 tests + // + char[] password = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd' }; + byte[] salt = Hex.decode("1234567878563412"); + + PBKDF2ParameterSpec spec = new PBKDF2ParameterSpec(password, salt, 5, 64); + +// if (!areEqual((kdf.deriveKey("AES", spec).getEncoded()), Hex.decode("d1daa78615f287e6"))) + if (!areEqual(kdf.deriveData(spec), Hex.decode("d1daa78615f287e6"))) + { + fail("64 test failed"); + } + + password = "All n-entities must communicate with other n-entities via n-1 entiteeheehees".toCharArray(); + spec = new PBKDF2ParameterSpec(password, salt, 500, 192); + + + if (!areEqual((kdf.deriveData(spec)), Hex.decode("6a8970bf68c92caea84a8df28510858607126380cc47ab2d"))) + { + fail("192 test failed"); + } + + spec = new PBKDF2ParameterSpec(password, salt, 60000, 192); + if (!areEqual((kdf.deriveData(spec)), Hex.decode("29aaef810c12ecd2236bbcfb55407f9852b5573dc1c095bb"))) + { + fail("192 (60000) test failed"); + } + } + + private boolean doComparison(String algorithm, char[] password, byte[] salt, int iterCount, int keyLen) + throws Exception + { + KDF kdf = KDF.getInstance(algorithm, "BC"); + PBKDF2ParameterSpec spec = new PBKDF2ParameterSpec(password, salt, iterCount, keyLen); + byte[] kdfSecret = kdf.deriveData(spec); + + SecretKeyFactory fact = SecretKeyFactory.getInstance(algorithm, "BC"); + SecretKey factSecret = fact.generateSecret(spec); + + return Arrays.areEqual(kdfSecret, factSecret.getEncoded()); + } + + public void test8BitOnUTF() + throws Exception + { + char[] glyph1_utf16 = { 0xd801, 0xdc00 }; + byte[] salt = Strings.toByteArray("salt"); + int iter = 100; + int keySize = 128; + + PBEKeySpec pbeks = new PBEKeySpec(glyph1_utf16, salt, iter, keySize); + SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA1AND8BIT", "BC"); + + SecretKey sKey = skf.generateSecret(pbeks); + + if (!Arrays.areEqual(Hex.decode("470310cc8533df28b6f74fff81707b5a"), sKey.getEncoded())) + { + fail("8bit key mismatch"); + } + + KDF kdf = KDF.getInstance("PBKDF2WITHHMACSHA1AND8BIT", "BC"); + + PBKDF2ParameterSpec spec = new PBKDF2ParameterSpec(glyph1_utf16, salt, iter, keySize); + + byte[] kdfSecret = kdf.deriveData(spec); + + if (!Arrays.areEqual(Hex.decode("470310cc8533df28b6f74fff81707b5a"), kdfSecret)) + { + fail("KDF 8bit key mismatch"); + } + } + + public void testSecretKeyFactoryComparison() + throws Exception + { + setUp(); + String[] algorithms = new String[] { + "PBKDF2", + "PBKDF2WITHHMACSHA1", + "PBKDF2WITHHMACSHA1ANDUTF8", + PKCSObjectIdentifiers.id_PBKDF2.toString(), + "PBKDF2WITHASCII", + "PBKDF2WITH8BIT", + "PBKDF2WITHHMACSHA1AND8BIT", + "PBKDF2WITHHMACSHA224", + "PBKDF2WITHHMACSHA256", + "PBKDF2WITHHMACSHA384", + "PBKDF2WITHHMACSHA512", + "PBKDF2WITHHMACSHA512-224", + "PBKDF2WITHHMACSHA512-256", + "PBKDF2WITHHMACSHA3-224", + "PBKDF2WITHHMACSHA3-256", + "PBKDF2WITHHMACSHA3-384", + "PBKDF2WITHHMACSHA3-512", + "PBKDF2WITHHMACGOST3411", + "PBKDF2WITHHMACSM3", + }; +// char[] password = new char[] {'p', 'a', 's', 's', 'w', 'o', 'r', 'd'}; + byte[] password = new byte[16]; + byte[] salt = new byte[8]; + SecureRandom random = new SecureRandom(); + for (String algorithm: algorithms) + { + random.nextBytes(password); + random.nextBytes(salt); + if(!doComparison(algorithm, Hex.toHexString(password).toCharArray(), salt, 16, 64)) + { + fail("failed to generate same secret using kdf and secret key factory for: " + algorithm); + } + } + } + + public void testExceptionHandling() + { + setUp(); + try + { + KDF kdf = KDF.getInstance("NonExistentAlgorithm", "BC"); + fail("Exception was not thrown for nonexistent algorithm"); + } + catch (Exception e) + { + assertTrue(e instanceof NoSuchAlgorithmException); + } + try + { + KDF kdf = KDF.getInstance("PBKDF2", "NonExistentProvider"); + fail("Exception was not thrown for nonexistent provider"); + } + catch (Exception e) + { + assertTrue(e instanceof NoSuchProviderException); + } + try + { + KDF kdf = KDF.getInstance(null, "BC"); + fail("Exception was not thrown for null algorithm"); + } + catch (Exception e) + { + assertTrue(e instanceof NullPointerException); + } + try + { + KDFParameters kdfParameters = new InvalidKDFParameters(); + KDF kdf = KDF.getInstance("PBKDF2", kdfParameters, "BC"); + fail("Exception was not thrown for valid algorithm, but invalid parameters"); + } + catch (Exception e) + { + assertTrue(e instanceof InvalidAlgorithmParameterException); + } + try + { + KDF kdf = KDF.getInstance("PBKDF2", "BC"); + HKDFParameterSpec hkdfParameterSpec = new HKDFParameterSpec(new byte[16], new byte[16], new byte[16], 16); + kdf.deriveData(hkdfParameterSpec); + fail("Exception was not thrown for invalid derivation spec"); + } + catch (Exception e) + { + assertTrue(e instanceof InvalidAlgorithmParameterException); + } + } + + private class InvalidKDFParameters + implements KDFParameters + { + + public InvalidKDFParameters() + { + super(); + } + + + @Override + public int hashCode() + { + return super.hashCode(); + } + + + @Override + public boolean equals(Object obj) + { + return super.equals(obj); + } + + + @Override + protected Object clone() throws CloneNotSupportedException + { + return super.clone(); + } + + + @Override + public String toString() + { + return super.toString(); + } + + } +} diff --git a/prov/src/test/jdk25/org/bouncycastle/jcajce/provider/kdf/test/ScryptTest.java b/prov/src/test/jdk25/org/bouncycastle/jcajce/provider/kdf/test/ScryptTest.java new file mode 100644 index 0000000000..0cf9a6fc7e --- /dev/null +++ b/prov/src/test/jdk25/org/bouncycastle/jcajce/provider/kdf/test/ScryptTest.java @@ -0,0 +1,231 @@ +package org.bouncycastle.jcajce.provider.kdf.test; + +import junit.framework.TestCase; +import org.bouncycastle.jcajce.spec.ScryptParameterSpec; +import org.bouncycastle.jcajce.spec.HKDFParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.Strings; +import org.bouncycastle.util.encoders.Hex; + +import javax.crypto.KDF; +import javax.crypto.KDFParameters; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.security.Security; + +import static org.bouncycastle.util.Arrays.areEqual; + +public class ScryptTest + extends TestCase +{ + public void setUp() + { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) + { + Security.addProvider(new BouncyCastleProvider()); + } + } + + public void testKDF() + throws Exception + { + setUp(); + KDF kdf = KDF.getInstance("Scrypt", "BC"); + + byte[] expected = Hex.decode("77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906"); + ScryptParameterSpec spec = new ScryptParameterSpec( + "".toCharArray(), + Strings.toByteArray(""), + 16, + 1, + 1, + 64*8 + ); + if(!areEqual(kdf.deriveData(spec), expected)) + { + fail("Scrypt failed test"); + } + + expected = Hex.decode("fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640"); + spec = new ScryptParameterSpec( + "password".toCharArray(), + Strings.toByteArray("NaCl"), + 1024, + 8, + 16, + 64*8 + ); + if(!areEqual(kdf.deriveData(spec), expected)) + { + fail("Scrypt failed test"); + } + + expected = Hex.decode("7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887"); + spec = new ScryptParameterSpec( + "pleaseletmein".toCharArray(), + Strings.toByteArray("SodiumChloride"), + 16384, + 8, + 1, + 64*8 + ); + if(!areEqual(kdf.deriveData(spec), expected)) + { + fail("Scrypt failed test"); + } + + expected = Hex.decode("2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049e8a952fbcbf45c6fa77a41a4"); + spec = new ScryptParameterSpec( + "pleaseletmein".toCharArray(), + Strings.toByteArray("SodiumChloride"), + 1048576, + 8, + 1, + 64*8 + ); + if(!areEqual(kdf.deriveData(spec), expected)) + { + fail("Scrypt failed test"); + } + + + } + + public void testSecretKeyFactoryComparison() + throws Exception + { + + setUp(); + KDF kdf = KDF.getInstance("Scrypt", "BC"); + byte[] password = new byte[16]; + byte[] salt = new byte[8]; + + SecureRandom random = new SecureRandom(); + random.nextBytes(password); + random.nextBytes(salt); + + ScryptParameterSpec spec = new ScryptParameterSpec( + Hex.toHexString(password).toCharArray(), + salt, + 1024, + 8, + 16, + 64 + ); + byte[] kdfSecret = kdf.deriveData(spec); + + SecretKeyFactory fact = SecretKeyFactory.getInstance("SCRYPT", "BC"); + + spec = new ScryptParameterSpec( + Hex.toHexString(password).toCharArray(), + salt, + 1024, + 8, + 16, + 64 + ); + SecretKey factSecret = fact.generateSecret(spec); + byte[] byteSecret = factSecret.getEncoded(); + + if(!areEqual(kdfSecret, byteSecret)) + { + fail("failed to generate same secret using kdf and secret key factory for: " + "Scrypt"); + } + } + + public void testExceptionHandling() + { + setUp(); + try + { + KDF kdf = KDF.getInstance("NonExistentAlgorithm", "BC"); + fail("Exception was not thrown for nonexistent algorithm"); + } + catch (Exception e) + { + assertTrue(e instanceof NoSuchAlgorithmException); + } + try + { + KDF kdf = KDF.getInstance("SCRYPT", "NonExistentProvider"); + fail("Exception was not thrown for nonexistent provider"); + } + catch (Exception e) + { + assertTrue(e instanceof NoSuchProviderException); + } + try + { + KDF kdf = KDF.getInstance(null, "BC"); + fail("Exception was not thrown for null algorithm"); + } + catch (Exception e) + { + assertTrue(e instanceof NullPointerException); + } + try + { + KDFParameters kdfParameters = new InvalidKDFParameters(); + KDF kdf = KDF.getInstance("SCRYPT", kdfParameters, "BC"); + fail("Exception was not thrown for valid algorithm, but invalid parameters"); + } + catch (Exception e) + { + assertTrue(e instanceof InvalidAlgorithmParameterException); + } + try + { + KDF kdf = KDF.getInstance("SCRYPT", "BC"); + HKDFParameterSpec hkdfParameterSpec = new HKDFParameterSpec(new byte[16], new byte[16], new byte[16], 16); + kdf.deriveData(hkdfParameterSpec); + fail("Exception was not thrown for invalid derivation spec"); + } + catch (Exception e) + { + assertTrue(e instanceof InvalidAlgorithmParameterException); + } + } + + private class InvalidKDFParameters + implements KDFParameters + { + + public InvalidKDFParameters() + { + super(); + } + + + @Override + public int hashCode() + { + return super.hashCode(); + } + + + @Override + public boolean equals(Object obj) + { + return super.equals(obj); + } + + + @Override + protected Object clone() throws CloneNotSupportedException + { + return super.clone(); + } + + + @Override + public String toString() + { + return super.toString(); + } + + } +} diff --git a/publish.gradle b/publish.gradle new file mode 100644 index 0000000000..d1d1a506ce --- /dev/null +++ b/publish.gradle @@ -0,0 +1,3 @@ +gradle.projectsEvaluated { + +} diff --git a/run_mtt.sh b/run_mtt.sh new file mode 100755 index 0000000000..912fdab700 --- /dev/null +++ b/run_mtt.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +set -e + +export script_loc=$( cd -- "$( dirname -- "$0" )" &> /dev/null && pwd ) +version=$(fgrep version "$script_loc/gradle.properties" | sed -e "s/version=//") + +echo "" +echo "Module dependency testing" +echo "" + +# +# This is an internal tool used to verify that classes needed by one module +# are correctly exported by another module. +# + +levels=( "9" "11" "17" "21" "25" ) + +for level in "${levels[@]}" +do +echo "---------------------------------------------------------------------" +echo "Start ${level}" + +( + echo "With Jakarta mail.." + modtest \ + -scan "${script_loc}/jmail/build/libs/bcjmail-jdk18on-${version}.jar" \ + -scan "${script_loc}/mls/build/libs/bcmls-jdk18on-${version}.jar" \ + -scan "${script_loc}/pg/build/libs/bcpg-jdk18on-${version}.jar" \ + -scan "${script_loc}/pkix/build/libs/bcpkix-jdk18on-${version}.jar" \ + -scan "${script_loc}/prov/build/libs/bcprov-jdk18on-${version}.jar" \ + -scan "${script_loc}/tls/build/libs/bctls-jdk18on-${version}.jar" \ + -scan "${script_loc}/util/build/libs/bcutil-jdk18on-${version}.jar" \ + -include "^org\.bouncycastle\..*" \ + -ignore "^java\..*" \ + -ignore "^javax\..*" \ + -ignore "^jakarta\..*" \ + -ignore "^io\.grpc\..*" \ + -ignore "^com\.google\..*" \ + -ignore "^com\.sun\..*" \ + -jvmlevel ${level} +) + +( # mail + echo "With Java mail.." + modtest \ + -scan "${script_loc}/mail/build/libs/bcmail-jdk18on-${version}.jar" \ + -scan "${script_loc}/mls/build/libs/bcmls-jdk18on-${version}.jar" \ + -scan "${script_loc}/pg/build/libs/bcpg-jdk18on-${version}.jar" \ + -scan "${script_loc}/pkix/build/libs/bcpkix-jdk18on-${version}.jar" \ + -scan "${script_loc}/prov/build/libs/bcprov-jdk18on-${version}.jar" \ + -scan "${script_loc}/tls/build/libs/bctls-jdk18on-${version}.jar" \ + -scan "${script_loc}/util/build/libs/bcutil-jdk18on-${version}.jar" \ + -include "^org\.bouncycastle\..*" \ + -ignore "^java\..*" \ + -ignore "^javax\..*" \ + -ignore "^jakarta\..*" \ + -ignore "^io\.grpc\..*" \ + -ignore "^com\.google\..*" \ + -ignore "^com\.sun\..*" \ + -jvmlevel ${level} +) + echo "End java ${level}" + echo "" +done \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index c54949b153..cf2608deed 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,4 @@ +include "bom" include "core" include "util" include "pg" diff --git a/test/src/main/java/org/bouncycastle/test/est/ESTServerUtils.java b/test/src/main/java/org/bouncycastle/test/est/ESTServerUtils.java index c48e0a3b8e..dea7abc90a 100644 --- a/test/src/main/java/org/bouncycastle/test/est/ESTServerUtils.java +++ b/test/src/main/java/org/bouncycastle/test/est/ESTServerUtils.java @@ -2,6 +2,7 @@ import java.io.File; import java.io.IOException; +import java.net.InetAddress; import java.net.Socket; import java.util.Arrays; import java.util.List; @@ -94,7 +95,7 @@ public static void waitForSocket(int port) try { Thread.sleep(100); - sock = new Socket("127.0.0.1", port); + sock = new Socket(InetAddress.getLoopbackAddress(), port); break; } catch (Exception ex) diff --git a/test/src/main/java/org/bouncycastle/test/est/examples/EnrollExample.java b/test/src/main/java/org/bouncycastle/test/est/examples/EnrollExample.java index 4ed8eec77a..1c9885940c 100644 --- a/test/src/main/java/org/bouncycastle/test/est/examples/EnrollExample.java +++ b/test/src/main/java/org/bouncycastle/test/est/examples/EnrollExample.java @@ -355,7 +355,6 @@ else if (credentials.length == 2) } t += 1000; Thread.sleep(t); - continue; } } while (!enrollmentResponse.isCompleted()); diff --git a/test/src/test/java/org/bouncycastle/test/est/TestCACertsFetch.java b/test/src/test/java/org/bouncycastle/test/est/TestCACertsFetch.java index fa78758fd9..d39dba8d58 100644 --- a/test/src/test/java/org/bouncycastle/test/est/TestCACertsFetch.java +++ b/test/src/test/java/org/bouncycastle/test/est/TestCACertsFetch.java @@ -52,7 +52,7 @@ public class TestCACertsFetch - extends SimpleTest +// extends SimpleTest { public String getName() @@ -60,11 +60,11 @@ public String getName() return "TestCACertsFetch"; } - public void performTest() - throws Exception - { - ESTTestUtils.runJUnit(TestCACertsFetch.class); - } +// public void performTest() +// throws Exception +// { +// ESTTestUtils.runJUnit(TestCACertsFetch.class); +// } private ESTServerUtils.ServerInstance startDefaultServer() throws Exception @@ -1778,12 +1778,12 @@ public void testCertResponseWithLabelApplication() res.getFinished().await(5, TimeUnit.SECONDS); } - - - public static void main(String[] args) - throws Exception - { - ESTTestUtils.ensureProvider(); - runTest(new TestCACertsFetch()); - } +// +// +// public static void main(String[] args) +// throws Exception +// { +// ESTTestUtils.ensureProvider(); +// runTest(new TestCACertsFetch()); +// } } diff --git a/test/src/test/java/org/bouncycastle/test/est/TestESTServiceFails.java b/test/src/test/java/org/bouncycastle/test/est/TestESTServiceFails.java index e5ea2c925e..73339f7be4 100644 --- a/test/src/test/java/org/bouncycastle/test/est/TestESTServiceFails.java +++ b/test/src/test/java/org/bouncycastle/test/est/TestESTServiceFails.java @@ -25,18 +25,18 @@ * Test illegal state exceptions are thrown when expected. */ public class TestESTServiceFails - extends SimpleTest +// extends SimpleTest { public String getName() { return "ESTServiceFails"; } - public void performTest() - throws Exception - { - ESTTestUtils.runJUnit(TestESTServiceFails.class); - } +// public void performTest() +// throws Exception +// { +// ESTTestUtils.runJUnit(TestESTServiceFails.class); +// } @Test(expected = NullPointerException.class) diff --git a/test/src/test/java/org/bouncycastle/test/est/TestEnroll.java b/test/src/test/java/org/bouncycastle/test/est/TestEnroll.java index 372aad81b4..07fc78c0ae 100644 --- a/test/src/test/java/org/bouncycastle/test/est/TestEnroll.java +++ b/test/src/test/java/org/bouncycastle/test/est/TestEnroll.java @@ -55,7 +55,7 @@ import org.junit.Test; public class TestEnroll - extends SimpleTest +// extends SimpleTest { public String getName() @@ -63,11 +63,12 @@ public String getName() return "TestEnroll"; } - public void performTest() - throws Exception - { - ESTTestUtils.runJUnit(TestEnroll.class); - } + +// public void performTest() +// throws Exception +// { +// ESTTestUtils.runJUnit(TestEnroll.class); +// } // Start a server instance that uses basic auth. @@ -2323,8 +2324,8 @@ public static void main(String[] args) // } // } - ESTTestUtils.ensureProvider(); - runTest(new TestEnroll()); +// ESTTestUtils.ensureProvider(); +// runTest(new TestEnroll()); } } diff --git a/test/src/test/java/org/bouncycastle/test/est/TestGetCSRAttrs.java b/test/src/test/java/org/bouncycastle/test/est/TestGetCSRAttrs.java index 69ec97ed2e..813f125081 100644 --- a/test/src/test/java/org/bouncycastle/test/est/TestGetCSRAttrs.java +++ b/test/src/test/java/org/bouncycastle/test/est/TestGetCSRAttrs.java @@ -23,7 +23,7 @@ public class TestGetCSRAttrs - extends SimpleTest +// extends SimpleTest { public String getName() @@ -54,12 +54,11 @@ private ESTServerUtils.ServerInstance startDefaultServer() } - - public void performTest() - throws Exception - { - ESTTestUtils.runJUnit(TestGetCSRAttrs.class); - } +// public void performTest() +// throws Exception +// { +// ESTTestUtils.runJUnit(TestGetCSRAttrs.class); +// } /** @@ -750,10 +749,10 @@ public void testFetchCSRWithLabel() } - public static void main(String[] args) - throws Exception - { - ESTTestUtils.ensureProvider(); - runTest(new TestGetCSRAttrs()); - } +// public static void main(String[] args) +// throws Exception +// { +// ESTTestUtils.ensureProvider(); +// runTest(new TestGetCSRAttrs()); +// } } diff --git a/test/src/test/java/org/bouncycastle/test/est/TestIllegalPathSegments.java b/test/src/test/java/org/bouncycastle/test/est/TestIllegalPathSegments.java index b7ed2b8cb3..28f7624ebe 100644 --- a/test/src/test/java/org/bouncycastle/test/est/TestIllegalPathSegments.java +++ b/test/src/test/java/org/bouncycastle/test/est/TestIllegalPathSegments.java @@ -8,18 +8,18 @@ import org.junit.Test; public class TestIllegalPathSegments - extends SimpleTest +// extends SimpleTest { public String getName() { return "TestIllegalPathSegments"; } - public void performTest() - throws Exception - { - ESTTestUtils.runJUnit(TestIllegalPathSegments.class); - } +// public void performTest() +// throws Exception +// { +// ESTTestUtils.runJUnit(TestIllegalPathSegments.class); +// } @Test(expected = IllegalArgumentException.class) public void testPathSegment_4800() diff --git a/test/src/test/java/org/bouncycastle/test/est/TestKeyUsage.java b/test/src/test/java/org/bouncycastle/test/est/TestKeyUsage.java index 988986bd59..691837afb1 100644 --- a/test/src/test/java/org/bouncycastle/test/est/TestKeyUsage.java +++ b/test/src/test/java/org/bouncycastle/test/est/TestKeyUsage.java @@ -28,7 +28,7 @@ public class TestKeyUsage - extends SimpleTest +// extends SimpleTest { private static int[] keyUsage = new int[]{ KeyUsage.digitalSignature, @@ -75,11 +75,11 @@ public String getName() return "TestKeyUsage"; } - public void performTest() - throws Exception - { - ESTTestUtils.runJUnit(TestKeyUsage.class); - } +// public void performTest() +// throws Exception +// { +// ESTTestUtils.runJUnit(TestKeyUsage.class); +// } public static void matrix() diff --git a/test/src/test/java/org/bouncycastle/test/est/TestServerKeyGeneration.java b/test/src/test/java/org/bouncycastle/test/est/TestServerKeyGeneration.java index e5b01bece8..8b4e4fc897 100644 --- a/test/src/test/java/org/bouncycastle/test/est/TestServerKeyGeneration.java +++ b/test/src/test/java/org/bouncycastle/test/est/TestServerKeyGeneration.java @@ -21,12 +21,13 @@ import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.test.SimpleTest; +import org.junit.Assert; import org.junit.Assume; import org.junit.Before; import org.junit.Test; public class TestServerKeyGeneration - extends SimpleTest +// extends SimpleTest { @@ -41,11 +42,12 @@ public String getName() return "test against globalsign est server"; } - public void performTest() - throws Exception - { - testServerGenWithoutEncryption(); - } + +// public void performTest() +// throws Exception +// { +// testServerGenWithoutEncryption(); +// } @Test @@ -103,13 +105,13 @@ public void testServerGenWithoutEncryption() // if (pki == null) { - fail("expecting pki"); + Assert.fail("expecting pki"); } X509CertificateHolder enrolledAsHolder = ESTService.storeToArray(enr.getStore())[0]; if (enrolledAsHolder == null) { - fail("expecting certificate"); + Assert.fail("expecting certificate"); } } catch (ESTException estException) @@ -122,11 +124,11 @@ public void testServerGenWithoutEncryption() } - public static void main(String[] args) - throws Exception - { - ESTTestUtils.ensureProvider(); - runTest(new TestServerKeyGeneration()); - } +// public static void main(String[] args) +// throws Exception +// { +// ESTTestUtils.ensureProvider(); +// runTest(new TestServerKeyGeneration()); +// } } diff --git a/tls/build.gradle b/tls/build.gradle index c413bd6221..ecfd90f17d 100644 --- a/tls/build.gradle +++ b/tls/build.gradle @@ -1,6 +1,6 @@ plugins { - id "biz.aQute.bnd.builder" version "7.0.0" + id "biz.aQute.bnd.builder" version "7.1.0" } jar.archiveBaseName = "bctls-$vmrange" @@ -18,6 +18,12 @@ sourceSets { } } + java25 { + java { + srcDirs = ['src/main/jdk25'] + } + } + test11 { java { compileClasspath += main.output + test.output @@ -42,6 +48,13 @@ sourceSets { } } + test25 { + java { + compileClasspath += main.output + test.output + runtimeClasspath += test.output + srcDir(files("src/test/jdk25")) + } + } } dependencies { @@ -57,10 +70,17 @@ dependencies { builtBy compileJava } + java25Implementation project(':prov') + java25Implementation project(':util') + java25Implementation project(':pkix') + java25Implementation files([sourceSets.main.output.classesDirs, sourceSets.java9.output]) { + builtBy compileJava + } + test11Implementation group: 'junit', name: 'junit', version: '4.13.2' test15Implementation group: 'junit', name: 'junit', version: '4.13.2' test21Implementation group: 'junit', name: 'junit', version: '4.13.2' - + test25Implementation group: 'junit', name: 'junit', version: '4.13.2' test11Implementation project(':prov') test11Implementation project(':util') @@ -74,6 +94,9 @@ dependencies { test21Implementation project(':util') test21Implementation project(':pkix') + test25Implementation project(':prov') + test25Implementation project(':util') + test25Implementation project(':pkix') } @@ -118,6 +141,21 @@ compileTest21Java { options.sourcepath = files(['src/test/java', 'src/test/jdk21']) } +compileJava25Java { + + options.release = 25 + + def prov_jar="${project(":prov").jar.outputs.files.getFiles().getAt(0)}" + def util_jar="${project(":util").jar.outputs.files.getFiles().getAt(0)}" + def pkix_jar="${project(":pkix").jar.outputs.files.getFiles().getAt(0)}" + + + options.compilerArgs += [ + '--module-path', "${prov_jar}${File.pathSeparator}${util_jar}${File.pathSeparator}${pkix_jar}" + ] + + options.sourcepath = files(['src/main/java', 'src/main/jdk25']) +} task sourcesJar(type: Jar) { @@ -128,6 +166,9 @@ task sourcesJar(type: Jar) { into('META-INF/versions/9') { from sourceSets.java9.allSource } + into('META-INF/versions/25') { + from sourceSets.java25.allSource + } } jar { @@ -135,6 +176,9 @@ jar { into('META-INF/versions/9') { from sourceSets.java9.output } + into('META-INF/versions/25') { + from sourceSets.java25.output + } String v = "${rootProject.extensions.ext.bundle_version}" manifest.attributes('Multi-Release': 'true') manifest.attributes('Bundle-Name': 'bctls') @@ -143,6 +187,11 @@ jar { manifest.attributes('Export-Package': "org.bouncycastle.{jsse|tls}.*;version=${v}") manifest.attributes('Import-Package': "java.*;resolution:=optional,javax.*;resolution:=optional,!org.bouncycastle.{jsse|tls}.*,org.bouncycastle.*;version=\"[${v},${maxVersion})\"") manifest.attributes('Bundle-Version': "${v}") + manifest.attributes('Permissions': 'all-permissions') + manifest.attributes('Codebase': '*') + manifest.attributes('Application-Library-Allowable-Codebase': '*') + manifest.attributes('Caller-Allowable-Codebase': '*') + manifest.attributes('Trusted-Library': 'true') } @@ -301,6 +350,40 @@ task test21(type: Test) { } } +task test25(type: Test) { + + // This is testing the 21 code base + onlyIf {System.getenv("BC_JDK25") != null} + dependsOn jar + + testClassesDirs = sourceSets.test25.output.classesDirs + classpath = sourceSets.test25.runtimeClasspath + files(jar.archiveFile) + + forkEvery = 1; + maxParallelForks = 8; + + systemProperty 'bc.test.data.home', bcTestDataHome + maxHeapSize = "1536m" + testLogging.showStandardStreams = false + + javaLauncher = javaToolchains.launcherFor { + languageVersion = JavaLanguageVersion.of(25) + } + + jvmArgs = ['-Dtest.java.version.prefix=25'] + + + finalizedBy jacocoTestReport + + filter { + includeTestsMatching "AllTest*" + if (project.hasProperty('excludeTests')) { + excludeTestsMatching "${excludeTests}" + } + } +} + + if (System.getenv("BC_JDK8") != null) { System.out.println("${project.name}: Adding test8 as dependency for test task because BC_JDK8 is defined") test.dependsOn("test8") @@ -321,6 +404,10 @@ if (System.getenv("BC_JDK21") != null) { test.dependsOn("test21") } +if (System.getenv("BC_JDK25") != null) { + System.out.println("${project.name}: Adding test25 as dependency for test task because BC_JDK25 is defined") + test.dependsOn("test25") +} -compileJava9Java.dependsOn([":prov:jar", ":util:jar",":pkix:jar"]) \ No newline at end of file +compileJava9Java.dependsOn([":prov:jar", ":util:jar",":pkix:jar"]) diff --git a/tls/docs/GnuTLSSetup.html b/tls/docs/GnuTLSSetup.html index be72efa7cf..91041c67de 100644 --- a/tls/docs/GnuTLSSetup.html +++ b/tls/docs/GnuTLSSetup.html @@ -8,7 +8,7 @@

    Instructions for setting up a GnuTLS server for use with DTLSClientTest, Tls
  • Unpack to folder and add ${GNUTLS_HOME}/bin to PATH -
  • Make a working folder somewhere and copy the x509-*.pem from this package (in src/test/resources) to there. +
  • Make a working folder somewhere and copy the x509-*.pem from the bc-test-data repository (in tls/credentials) to there.
  • Go to working folder and start GnuTLS server (defaults to port 5556):
      diff --git a/tls/docs/OpenSSLSetup.html b/tls/docs/OpenSSLSetup.html index b8f9f9f994..e5b1b310eb 100644 --- a/tls/docs/OpenSSLSetup.html +++ b/tls/docs/OpenSSLSetup.html @@ -7,7 +7,7 @@

      Instructions for setting up an OpenSSL server for use with DTLSClientTest, D
      • Download and Install OpenSSL (exercise for the reader) -
      • Make a working folder somewhere and copy the x509-*.pem from this package (in src/test/resources) to there. +
      • Make a working folder somewhere and copy the x509-*.pem from the bc-test-data repository (in tls/credentials) to there.
      • Go to working folder and start OpenSSL client or server:
          diff --git a/tls/src/main/java/org/bouncycastle/jsse/BCExtendedSSLSession.java b/tls/src/main/java/org/bouncycastle/jsse/BCExtendedSSLSession.java index 6578016415..0d5e939180 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/BCExtendedSSLSession.java +++ b/tls/src/main/java/org/bouncycastle/jsse/BCExtendedSSLSession.java @@ -3,10 +3,23 @@ import java.util.Collections; import java.util.List; +import javax.crypto.SecretKey; +import javax.net.ssl.SSLKeyException; import javax.net.ssl.SSLSession; public abstract class BCExtendedSSLSession implements SSLSession { + public byte[] exportKeyingMaterialData(String label, byte[] context, int length) throws SSLKeyException + { + throw new UnsupportedOperationException(); + } + + public SecretKey exportKeyingMaterialKey(String keyAlg, String label, byte[] context, int length) + throws SSLKeyException + { + throw new UnsupportedOperationException(); + } + public abstract String[] getLocalSupportedSignatureAlgorithms(); public String[] getLocalSupportedSignatureAlgorithmsBC() diff --git a/tls/src/main/java/org/bouncycastle/jsse/BCSSLConnection.java b/tls/src/main/java/org/bouncycastle/jsse/BCSSLConnection.java index 430b7ec5e3..3961036125 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/BCSSLConnection.java +++ b/tls/src/main/java/org/bouncycastle/jsse/BCSSLConnection.java @@ -21,7 +21,7 @@ public interface BCSSLConnection * @param channelBinding * An IANA-registered "Channel-binding unique prefix" valid for TLS e.g. * "tls-unique" or "tls-server-end-point". - * @return A copy of the channel binding data as a {@link byte[]}, or null if the binding is + * @return A copy of the channel binding data as a byte[], or null if the binding is * unavailable for this connection. */ byte[] getChannelBinding(String channelBinding); diff --git a/tls/src/main/java/org/bouncycastle/jsse/BCSSLParameters.java b/tls/src/main/java/org/bouncycastle/jsse/BCSSLParameters.java index 0936596a90..26d8856a7b 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/BCSSLParameters.java +++ b/tls/src/main/java/org/bouncycastle/jsse/BCSSLParameters.java @@ -37,12 +37,14 @@ private static List copyList(Collection list) private List serverNames; private List sniMatchers; private boolean useCipherSuitesOrder; + private boolean useNamedGroupsOrder; private boolean enableRetransmissions = true; private int maximumPacketSize = 0; private String[] applicationProtocols = TlsUtils.EMPTY_STRINGS; private String[] signatureSchemes = null; private String[] signatureSchemesCert = null; private String[] namedGroups = null; + private String[] earlyKeyShares = null; public BCSSLParameters() { @@ -189,6 +191,16 @@ public void setUseCipherSuitesOrder(boolean useCipherSuitesOrder) this.useCipherSuitesOrder = useCipherSuitesOrder; } + public boolean getUseNamedGroupsOrder() + { + return useNamedGroupsOrder; + } + + public void setUseNamedGroupsOrder(boolean useNamedGroupsOrder) + { + this.useNamedGroupsOrder = useNamedGroupsOrder; + } + public boolean getEnableRetransmissions() { return enableRetransmissions; @@ -315,4 +327,34 @@ public void setNamedGroups(String[] namedGroups) this.namedGroups = check; } + + public String[] getEarlyKeyShares() + { + return TlsUtils.clone(earlyKeyShares); + } + + public void setEarlyKeyShares(String[] earlyKeyShares) + { + String[] check = null; + + if (earlyKeyShares != null) + { + check = TlsUtils.clone(earlyKeyShares); + HashSet seenEntries = new HashSet(); + for (String entry : check) + { + if (TlsUtils.isNullOrEmpty(entry)) + { + throw new IllegalArgumentException("'earlyKeyShares' entries cannot be null or empty strings"); + } + + if (!seenEntries.add(entry)) + { + throw new IllegalArgumentException("'earlyKeyShares' contains duplicate entry: " + entry); + } + } + } + + this.earlyKeyShares = check; + } } diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/AbstractAlgorithmConstraints.java b/tls/src/main/java/org/bouncycastle/jsse/provider/AbstractAlgorithmConstraints.java index b8f05338ae..bb1ae365cc 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/AbstractAlgorithmConstraints.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/AbstractAlgorithmConstraints.java @@ -14,31 +14,12 @@ abstract class AbstractAlgorithmConstraints implements BCAlgorithmConstraints AbstractAlgorithmConstraints(AlgorithmDecomposer decomposer) { - this.decomposer = decomposer; - } - - protected void checkAlgorithmName(String algorithm) - { - if (!JsseUtils.isNameSpecified(algorithm)) - { - throw new IllegalArgumentException("No algorithm name specified"); - } - } - - protected void checkKey(Key key) - { - if (null == key) + if (decomposer == null) { - throw new NullPointerException("'key' cannot be null"); + throw new NullPointerException("'decomposer' cannot be null"); } - } - protected void checkPrimitives(Set primitives) - { - if (!isPrimitivesSpecified(primitives)) - { - throw new IllegalArgumentException("No cryptographic primitive specified"); - } + this.decomposer = decomposer; } protected boolean containsAnyPartIgnoreCase(Set elements, String algorithm) @@ -53,21 +34,42 @@ protected boolean containsAnyPartIgnoreCase(Set elements, String algorit return true; } - if (null != decomposer) + for (String part : decomposer.decompose(algorithm)) { - for (String part : decomposer.decompose(algorithm)) + if (containsIgnoreCase(elements, part)) { - if (containsIgnoreCase(elements, part)) - { - return true; - } + return true; } } return false; } - protected boolean containsIgnoreCase(Set elements, String s) + static void checkAlgorithmName(String algorithm) + { + if (!JsseUtils.isNameSpecified(algorithm)) + { + throw new IllegalArgumentException("No algorithm name specified"); + } + } + + static void checkKey(Key key) + { + if (null == key) + { + throw new NullPointerException("'key' cannot be null"); + } + } + + static void checkPrimitives(Set primitives) + { + if (!isPrimitivesSpecified(primitives)) + { + throw new IllegalArgumentException("No cryptographic primitive specified"); + } + } + + static boolean containsIgnoreCase(Set elements, String s) { for (String element : elements) { @@ -79,12 +81,12 @@ protected boolean containsIgnoreCase(Set elements, String s) return false; } - protected boolean isPrimitivesSpecified(Set primitives) + static boolean isPrimitivesSpecified(Set primitives) { return null != primitives && !primitives.isEmpty(); } - protected static Set asUnmodifiableSet(String[] algorithms) + static Set asUnmodifiableSet(String[] algorithms) { if (null != algorithms && algorithms.length > 0) { @@ -97,7 +99,7 @@ protected static Set asUnmodifiableSet(String[] algorithms) return Collections. emptySet(); } - protected static Set asSet(String[] algorithms) + static Set asSet(String[] algorithms) { Set result = new HashSet(); if (null != algorithms) diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java b/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java index 9ad9564429..6c89fc5b20 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java @@ -26,8 +26,8 @@ public class BouncyCastleJsseProvider private static final String JSSE_CONFIG_PROPERTY = "org.bouncycastle.jsse.config"; - private static final double PROVIDER_VERSION = 1.0020; - private static final String PROVIDER_INFO = "Bouncy Castle JSSE Provider Version 1.0.20"; + private static final double PROVIDER_VERSION = 1.0023; + private static final String PROVIDER_INFO = "Bouncy Castle JSSE Provider Version 1.0.23"; private final Map serviceMap = new ConcurrentHashMap(); private final Map creatorMap = new HashMap(); @@ -73,6 +73,7 @@ public BouncyCastleJsseProvider(String config) boolean fipsMode = false; String cryptoName = config; + String altCryptoName = null; int colonPos = config.indexOf(':'); if (colonPos >= 0) @@ -81,13 +82,24 @@ public BouncyCastleJsseProvider(String config) String second = config.substring(colonPos + 1).trim(); fipsMode = first.equalsIgnoreCase("fips"); - cryptoName = second; + config = second; + } + + int commaPos = config.indexOf(','); + if (commaPos >= 0) + { + cryptoName = config.substring(0, commaPos).trim(); + altCryptoName = config.substring(commaPos + 1).trim(); + } + else + { + cryptoName = config; } JcaTlsCryptoProvider cryptoProvider; try { - cryptoProvider = createCryptoProvider(cryptoName); + cryptoProvider = createCryptoProvider(cryptoName, altCryptoName); } catch (GeneralSecurityException e) { @@ -116,7 +128,7 @@ public Provider configure(String configArg) return new BouncyCastleJsseProvider(configArg); } - private JcaTlsCryptoProvider createCryptoProvider(String cryptoName) + private JcaTlsCryptoProvider createCryptoProvider(String cryptoName, String altCryptoName) throws GeneralSecurityException { if (cryptoName.equalsIgnoreCase("default")) @@ -127,9 +139,18 @@ private JcaTlsCryptoProvider createCryptoProvider(String cryptoName) Provider provider = Security.getProvider(cryptoName); if (provider != null) { - return new JcaTlsCryptoProvider().setProvider(provider); + JcaTlsCryptoProvider cryptoProvider = new JcaTlsCryptoProvider().setProvider(provider); + + if (altCryptoName != null) + { + // this has to be done by name as a PKCS#11 login may be required. + cryptoProvider.setAlternateProvider(altCryptoName); + } + + return cryptoProvider; } + // TODO: should we support alt name here? try { Class cryptoProviderClass = Class.forName(cryptoName); @@ -234,7 +255,8 @@ public Object createInstance(Object constructorParameter) addAlgorithmImplementation("SSLContext.DEFAULT", "org.bouncycastle.jsse.provider.SSLContext.Default", new EngineCreator() { - public Object createInstance(Object constructorParameter) throws GeneralSecurityException + public Object createInstance(Object constructorParameter) + throws GeneralSecurityException { return new DefaultSSLContextSpi(fipsMode, cryptoProvider); } @@ -281,7 +303,7 @@ public final Provider.Service getService(String type, String algorithm) { String upperCaseAlgName = Strings.toUpperCase(algorithm); String serviceKey = type + "." + upperCaseAlgName; - + BcJsseService service = serviceMap.get(serviceKey); if (service == null) @@ -340,12 +362,12 @@ public final Provider.Service getService(String type, String algorithm) return service; } - public synchronized final Set getServices() + public final synchronized Set getServices() { Set serviceSet = super.getServices(); Set bcServiceSet = new HashSet(); - for (Provider.Service service: serviceSet) + for (Provider.Service service : serviceSet) { bcServiceSet.add(getService(service.getType(), service.getAlgorithm())); } @@ -405,7 +427,7 @@ private static class BcJsseService * @param attributes Map of attributes or null if this implementation * has no attributes * @throws NullPointerException if provider, type, algorithm, or - * className is null + * className is null */ public BcJsseService(Provider provider, String type, String algorithm, String className, List aliases, Map attributes, EngineCreator creator) { diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java b/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java index ddf774ec17..d03fb0542f 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java @@ -155,6 +155,14 @@ private static void decomposeEncryptionAlgorithm(Set decomposition, int case EncryptionAlgorithm.NULL: decomposition.add("C_NULL"); break; + case EncryptionAlgorithm.NULL_HMAC_SHA256: + decomposition.add("C_NULL_HMAC"); + decomposeHmacSHA256(decomposition); + break; + case EncryptionAlgorithm.NULL_HMAC_SHA384: + decomposition.add("C_NULL_HMAC"); + decomposeHmacSHA384(decomposition); + break; case EncryptionAlgorithm.SM4_CBC: decomposition.add("SM4_CBC"); break; @@ -174,14 +182,14 @@ private static void decomposeHashAlgorithm(Set decomposition, int crypto switch (cryptoHashAlgorithm) { case CryptoHashAlgorithm.sha256: - addAll(decomposition, "SHA256", "SHA-256", "HmacSHA256"); + decomposeHmacSHA256(decomposition); break; case CryptoHashAlgorithm.sha384: - addAll(decomposition, "SHA384", "SHA-384", "HmacSHA384"); + decomposeHmacSHA384(decomposition); + break; + case CryptoHashAlgorithm.sha512: + decomposeHmacSHA512(decomposition); break; -// case CryptoHashAlgorithm.sha512: -// addAll(decomposition, "SHA512", "SHA-512", "HmacSHA512"); -// break; case CryptoHashAlgorithm.sm3: addAll(decomposition, "SM3", "HmacSM3"); break; @@ -190,6 +198,21 @@ private static void decomposeHashAlgorithm(Set decomposition, int crypto } } + private static void decomposeHmacSHA256(Set decomposition) + { + addAll(decomposition, "SHA256", "SHA-256", "HmacSHA256"); + } + + private static void decomposeHmacSHA384(Set decomposition) + { + addAll(decomposition, "SHA384", "SHA-384", "HmacSHA384"); + } + + private static void decomposeHmacSHA512(Set decomposition) + { + addAll(decomposition, "SHA512", "SHA-512", "HmacSHA512"); + } + private static void decomposeKeyExchangeAlgorithm(Set decomposition, int keyExchangeAlgorithm) { switch (keyExchangeAlgorithm) @@ -263,14 +286,14 @@ private static void decomposeMACAlgorithm(Set decomposition, int cipherT addAll(decomposition, "SHA1", "SHA-1", "HmacSHA1"); break; case MACAlgorithm.hmac_sha256: - addAll(decomposition, "SHA256", "SHA-256", "HmacSHA256"); + decomposeHmacSHA256(decomposition); break; case MACAlgorithm.hmac_sha384: - addAll(decomposition, "SHA384", "SHA-384", "HmacSHA384"); + decomposeHmacSHA384(decomposition); + break; + case MACAlgorithm.hmac_sha512: + decomposeHmacSHA512(decomposition); break; -// case MACAlgorithm.hmac_sha512: -// addAll(decomposition, "SHA512", "SHA-512", "HmacSHA512"); -// break; default: throw new IllegalArgumentException(); } @@ -381,6 +404,7 @@ private static int getCryptoHashAlgorithm(int cipherSuite) case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256: case CipherSuite.TLS_RSA_WITH_NULL_SHA256: + case CipherSuite.TLS_SHA256_SHA256: return CryptoHashAlgorithm.sha256; case CipherSuite.TLS_AES_256_GCM_SHA384: @@ -412,6 +436,7 @@ private static int getCryptoHashAlgorithm(int cipherSuite) case CipherSuite.TLS_RSA_WITH_ARIA_256_CBC_SHA384: case CipherSuite.TLS_RSA_WITH_ARIA_256_GCM_SHA384: case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_SHA384_SHA384: return CryptoHashAlgorithm.sha384; case CipherSuite.TLS_SM4_CCM_SM3: @@ -455,6 +480,8 @@ private static String getTransformation(int encryptionAlgorithm) case EncryptionAlgorithm.CHACHA20_POLY1305: return "ChaCha20-Poly1305"; case EncryptionAlgorithm.NULL: + case EncryptionAlgorithm.NULL_HMAC_SHA256: + case EncryptionAlgorithm.NULL_HMAC_SHA384: return "NULL"; case EncryptionAlgorithm.SM4_CBC: return "SM4/CBC/NoPadding"; diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ContextData.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ContextData.java index 11eab8b6b9..cf56db6522 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ContextData.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ContextData.java @@ -36,6 +36,7 @@ final class ContextData private final ProvSSLSessionContext serverSessionContext; private final NamedGroupInfo.PerContext namedGroups; private final SignatureSchemeInfo.PerContext signatureSchemes; + private final int maxHandshakeMessageSize; ContextData(boolean fipsMode, JcaTlsCrypto crypto, BCX509ExtendedKeyManager x509KeyManager, BCX509ExtendedTrustManager x509TrustManager, Map supportedCipherSuites, @@ -56,6 +57,8 @@ final class ContextData this.serverSessionContext = new ProvSSLSessionContext(this); this.namedGroups = NamedGroupInfo.createPerContext(fipsMode, crypto); this.signatureSchemes = SignatureSchemeInfo.createPerContext(fipsMode, crypto, namedGroups); + this.maxHandshakeMessageSize = PropertyUtils.getIntegerSystemProperty( + "jdk.tls.maxHandshakeMessageSize", 32768, 1024, Integer.MAX_VALUE); } int[] getActiveCipherSuites(JcaTlsCrypto crypto, ProvSSLParameters sslParameters, @@ -191,9 +194,9 @@ ProvSSLParameters getDefaultSSLParameters(boolean isClient) return new ProvSSLParameters(this, implGetDefaultCipherSuites(isClient), implGetDefaultProtocols(isClient)); } - ProvSSLParameters getSupportedSSLParameters(boolean isClient) + int getMaxHandshakeMessageSize() { - return new ProvSSLParameters(this, getSupportedCipherSuites(), getSupportedProtocols()); + return maxHandshakeMessageSize; } NamedGroupInfo.PerConnection getNamedGroupsClient(ProvSSLParameters sslParameters, @@ -213,6 +216,11 @@ ProvSSLSessionContext getServerSessionContext() return serverSessionContext; } + List getSignatureSchemes(Vector sigAndHashAlgs) + { + return SignatureSchemeInfo.getSignatureSchemes(signatureSchemes, sigAndHashAlgs); + } + SignatureSchemeInfo.PerConnection getSignatureSchemesClient(ProvSSLParameters sslParameters, ProtocolVersion[] activeProtocolVersions, NamedGroupInfo.PerConnection namedGroups) { @@ -227,11 +235,6 @@ SignatureSchemeInfo.PerConnection getSignatureSchemesServer(ProvSSLParameters ss namedGroups); } - List getSignatureSchemes(Vector sigAndHashAlgs) - { - return SignatureSchemeInfo.getSignatureSchemes(signatureSchemes, sigAndHashAlgs); - } - String[] getSupportedCipherSuites() { return JsseUtils.getKeysArray(supportedCipherSuites); @@ -267,6 +270,11 @@ String[] getSupportedProtocols() return JsseUtils.getKeysArray(supportedProtocols); } + ProvSSLParameters getSupportedSSLParameters(boolean isClient) + { + return new ProvSSLParameters(this, getSupportedCipherSuites(), getSupportedProtocols()); + } + BCX509ExtendedKeyManager getX509KeyManager() { return x509KeyManager; diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/FipsUtils.java b/tls/src/main/java/org/bouncycastle/jsse/provider/FipsUtils.java index 86cfb3a70c..18af560105 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/FipsUtils.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/FipsUtils.java @@ -168,10 +168,17 @@ static boolean isFipsNamedGroup(int namedGroup) case NamedGroup.ffdhe4096: case NamedGroup.ffdhe6144: case NamedGroup.ffdhe8192: + case NamedGroup.SecP256r1MLKEM768: + case NamedGroup.SecP384r1MLKEM1024: return true; case NamedGroup.x25519: case NamedGroup.x448: + case NamedGroup.MLKEM512: + case NamedGroup.MLKEM768: + case NamedGroup.MLKEM1024: + case NamedGroup.X25519MLKEM768: + case NamedGroup.curveSM2MLKEM768: default: return false; } @@ -209,6 +216,21 @@ static boolean isFipsSignatureScheme(int signatureScheme) case SignatureScheme.ed25519: case SignatureScheme.ed448: + case SignatureScheme.mldsa44: + case SignatureScheme.mldsa65: + case SignatureScheme.mldsa87: + case SignatureScheme.DRAFT_slhdsa_sha2_128s: + case SignatureScheme.DRAFT_slhdsa_sha2_128f: + case SignatureScheme.DRAFT_slhdsa_sha2_192s: + case SignatureScheme.DRAFT_slhdsa_sha2_192f: + case SignatureScheme.DRAFT_slhdsa_sha2_256s: + case SignatureScheme.DRAFT_slhdsa_sha2_256f: + case SignatureScheme.DRAFT_slhdsa_shake_128s: + case SignatureScheme.DRAFT_slhdsa_shake_128f: + case SignatureScheme.DRAFT_slhdsa_shake_192s: + case SignatureScheme.DRAFT_slhdsa_shake_192f: + case SignatureScheme.DRAFT_slhdsa_shake_256s: + case SignatureScheme.DRAFT_slhdsa_shake_256f: default: return false; } diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/HostnameUtil.java b/tls/src/main/java/org/bouncycastle/jsse/provider/HostnameUtil.java index 92ca2aeca1..3aee3c5593 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/HostnameUtil.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/HostnameUtil.java @@ -30,39 +30,52 @@ static void checkHostname(String hostname, X509Certificate certificate, boolean throw new CertificateException("No hostname specified for HTTPS endpoint ID check"); } - if (IPAddress.isValid(hostname)) + boolean hostnameIsIPv4 = IPAddress.isValidIPv4(hostname); + boolean hostnameIsIPv6 = !hostnameIsIPv4 && IPAddress.isValidIPv6(hostname); + + if (hostnameIsIPv4 || hostnameIsIPv6) { Collection> subjectAltNames = certificate.getSubjectAlternativeNames(); if (null != subjectAltNames) { + InetAddress hostnameInetAddress = null; + for (List subjectAltName : subjectAltNames) { - int type = ((Integer)subjectAltName.get(0)).intValue(); - if (GeneralName.iPAddress != type) + if (!isAltNameType(subjectAltName, GeneralName.iPAddress)) + { + continue; + } + + String ipAddress = getAltNameValue(subjectAltName); + if (ipAddress == null) { continue; } - String ipAddress = (String)subjectAltName.get(1); if (hostname.equalsIgnoreCase(ipAddress)) { return; } - try + // In case of IPv6 addresses, convert to InetAddress to handle abbreviated forms correctly + if (hostnameIsIPv6 && IPAddress.isValidIPv6(ipAddress)) { - if (InetAddress.getByName(hostname).equals(InetAddress.getByName(ipAddress))) + try { - return; + if (hostnameInetAddress == null) + { + hostnameInetAddress = InetAddress.getByName(hostname); + } + if (hostnameInetAddress.equals(InetAddress.getByName(ipAddress))) + { + return; + } + } + catch (UnknownHostException e) + { + // Ignore } - } - catch (UnknownHostException e) - { - // Ignore - } - catch (SecurityException e) - { - // Ignore } } } @@ -76,15 +89,19 @@ else if (isValidDomainName(hostname)) boolean foundAnyDNSNames = false; for (List subjectAltName : subjectAltNames) { - int type = ((Integer)subjectAltName.get(0)).intValue(); - if (GeneralName.dNSName != type) + if (!isAltNameType(subjectAltName, GeneralName.dNSName)) { continue; } foundAnyDNSNames = true; - String dnsName = (String)subjectAltName.get(1); + String dnsName = getAltNameValue(subjectAltName); + if (dnsName == null) + { + continue; + } + if (matchesDNSName(hostname, dnsName, allWildcards)) { return; @@ -134,6 +151,19 @@ private static ASN1Primitive findMostSpecificCN(X500Principal principal) return null; } + private static String getAltNameValue(List subjectAltName) + { + if (subjectAltName != null && subjectAltName.size() >= 2) + { + Object objValue = subjectAltName.get(1); + if (objValue instanceof String) + { + return (String)objValue; + } + } + return null; + } + private static String getLabel(String s, int begin) { int end = s.indexOf('.', begin); @@ -144,6 +174,19 @@ private static String getLabel(String s, int begin) return s.substring(begin, end); } + private static boolean isAltNameType(List subjectAltName, int type) + { + if (subjectAltName != null && subjectAltName.size() >= 1) + { + Object objValue = subjectAltName.get(0); + if (objValue instanceof Integer) + { + return ((Integer)objValue).intValue() == type; + } + } + return false; + } + private static boolean isValidDomainName(String name) { try diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/JcaAlgorithmDecomposer.java b/tls/src/main/java/org/bouncycastle/jsse/provider/JcaAlgorithmDecomposer.java index a8c2521e01..9fc04d7b1c 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/JcaAlgorithmDecomposer.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/JcaAlgorithmDecomposer.java @@ -1,26 +1,85 @@ package org.bouncycastle.jsse.provider; -import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.regex.Pattern; class JcaAlgorithmDecomposer implements AlgorithmDecomposer { + private static final Map SHA_DIGEST_MAP = createSHADigestMap(); + private static final Pattern PATTERN = Pattern.compile("with|and|(? decompose(String algorithm) { - if (algorithm.indexOf('/') < 0) + Set result = new HashSet(); + + if (JsseUtils.isNameSpecified(algorithm)) { - return Collections.emptySet(); + implDecompose(result, algorithm); + + if (algorithm.contains("SHA")) + { + for (Map.Entry entry : SHA_DIGEST_MAP.entrySet()) + { + includeBothIfEither(result, entry.getKey(), entry.getValue()); + } + } } + return result; + } + + static String decomposeDigestName(String algorithm) + { + String result = SHA_DIGEST_MAP.get(algorithm); + if (result == null) + { + result = algorithm; + } + return result; + } + + static Set decomposeName(String algorithm) + { Set result = new HashSet(); + if (JsseUtils.isNameSpecified(algorithm)) + { + implDecompose(result, algorithm); + + if (algorithm.contains("SHA")) + { + for (Map.Entry entry : SHA_DIGEST_MAP.entrySet()) + { + replaceFirstWithSecond(result, entry.getKey(), entry.getValue()); + } + } + } + + return result; + } + + private static Map createSHADigestMap() + { + Map result = new HashMap(); + result.put("SHA-1", "SHA1"); + result.put("SHA-224", "SHA224"); + result.put("SHA-256", "SHA256"); + result.put("SHA-384", "SHA384"); + result.put("SHA-512", "SHA512"); + result.put("SHA-512/224", "SHA512/224"); + result.put("SHA-512/256", "SHA512/256"); + return result; + } + + private static void implDecompose(Set result, String algorithm) + { for (String section : algorithm.split("/")) { if (section.length() > 0) @@ -34,22 +93,25 @@ public Set decompose(String algorithm) } } } + } - ensureBothIfEither(result, "SHA1", "SHA-1"); - ensureBothIfEither(result, "SHA224", "SHA-224"); - ensureBothIfEither(result, "SHA256", "SHA-256"); - ensureBothIfEither(result, "SHA384", "SHA-384"); - ensureBothIfEither(result, "SHA512", "SHA-512"); - - return result; + private static void includeBothIfEither(Set elements, String a, String b) + { + if (elements.contains(a)) + { + elements.add(b); + } + else if (elements.contains(b)) + { + elements.add(a); + } } - private static void ensureBothIfEither(Set elements, String a, String b) + private static void replaceFirstWithSecond(Set elements, String a, String b) { - boolean hasA = elements.contains(a), hasB = elements.contains(b); - if (hasA ^ hasB) + if (elements.remove(a)) { - elements.add(hasA ? b : a); + elements.add(b); } } } diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/JsseUtils.java b/tls/src/main/java/org/bouncycastle/jsse/provider/JsseUtils.java index deb109461d..2fc0f6dc6e 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/JsseUtils.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/JsseUtils.java @@ -45,6 +45,7 @@ import org.bouncycastle.tls.CertificateStatus; import org.bouncycastle.tls.CertificateStatusType; import org.bouncycastle.tls.ClientCertificateType; +import org.bouncycastle.tls.ExtensionType; import org.bouncycastle.tls.IdentifierType; import org.bouncycastle.tls.KeyExchangeAlgorithm; import org.bouncycastle.tls.NamedGroup; @@ -72,10 +73,6 @@ abstract class JsseUtils PropertyUtils.getBooleanSystemProperty("jdk.tls.allowLegacyMasterSecret", true); private static final boolean provTlsAllowLegacyResumption = PropertyUtils.getBooleanSystemProperty("jdk.tls.allowLegacyResumption", false); - private static final int provTlsMaxCertificateChainLength = - PropertyUtils.getIntegerSystemProperty("jdk.tls.maxCertificateChainLength", 10, 1, Integer.MAX_VALUE); - private static final int provTlsMaxHandshakeMessageSize = - PropertyUtils.getIntegerSystemProperty("jdk.tls.maxHandshakeMessageSize", 32768, 1024, Integer.MAX_VALUE); private static final boolean provTlsRequireCloseNotify = PropertyUtils.getBooleanSystemProperty("com.sun.net.ssl.requireCloseNotify", true); private static final boolean provTlsUseCompatibilityMode = @@ -84,6 +81,9 @@ abstract class JsseUtils private static final boolean provTlsUseExtendedMasterSecret = PropertyUtils.getBooleanSystemProperty("jdk.tls.useExtendedMasterSecret", true); + private static final int provTlsClientMaxInboundCertChainLen; + private static final int provTlsServerMaxInboundCertChainLen; + static final Set KEY_AGREEMENT_CRYPTO_PRIMITIVES_BC = Collections.unmodifiableSet(EnumSet.of(BCCryptoPrimitive.KEY_AGREEMENT)); static final Set KEY_ENCAPSULATION_CRYPTO_PRIMITIVES_BC = @@ -102,6 +102,25 @@ static class BCUnknownServerName extends BCSNIServerName } } + static + { + int clientDefaultValue = 10; + int serverDefaultValue = 8; + + int provTlsMaxCertificateChainLength = PropertyUtils.getIntegerSystemProperty( + "jdk.tls.maxCertificateChainLength", 0, 1, Integer.MAX_VALUE); + if (provTlsMaxCertificateChainLength > 0) + { + clientDefaultValue = provTlsMaxCertificateChainLength; + serverDefaultValue = provTlsMaxCertificateChainLength; + } + + provTlsClientMaxInboundCertChainLen = PropertyUtils.getIntegerSystemProperty( + "jdk.tls.client.maxInboundCertificateChainLength", clientDefaultValue, 1, Integer.MAX_VALUE); + provTlsServerMaxInboundCertChainLen = PropertyUtils.getIntegerSystemProperty( + "jdk.tls.server.maxInboundCertificateChainLength", serverDefaultValue, 1, Integer.MAX_VALUE); + } + static boolean allowLegacyMasterSecret() { return provTlsAllowLegacyMasterSecret; @@ -140,6 +159,24 @@ static String[] getArray(Collection c) return c.toArray(new String[c.size()]); } + static String getExtensionsReport(String title, Hashtable extensions) + { + StringBuilder sb = new StringBuilder(title); + sb.append(':'); + if (extensions != null) + { + Enumeration e = extensions.keys(); + while (e.hasMoreElements()) + { + Integer extType = (Integer)e.nextElement(); + + sb.append(' '); + sb.append(ExtensionType.getText(extType.intValue())); + } + } + return sb.toString(); + } + static String[] getKeysArray(Map m) { return getArray(m.keySet()); @@ -270,14 +307,14 @@ static boolean equals(Object a, Object b) return a == b || (null != a && null != b && a.equals(b)); } - static int getMaxCertificateChainLength() + static int getMaxInboundCertChainLenClient() { - return provTlsMaxCertificateChainLength; + return provTlsClientMaxInboundCertChainLen; } - static int getMaxHandshakeMessageSize() + static int getMaxInboundCertChainLenServer() { - return provTlsMaxHandshakeMessageSize; + return provTlsServerMaxInboundCertChainLen; } static ASN1ObjectIdentifier getNamedCurveOID(PublicKey publicKey) @@ -937,6 +974,19 @@ private static String stripOuterChars(String s, char openChar, char closeChar) return s; } + static String stripTrailingDot(String s) + { + if (s != null) + { + int sLast = s.length() - 1; + if (sLast >= 0 && s.charAt(sLast) == '.') + { + return s.substring(0, sLast); + } + } + return s; + } + static boolean useCompatibilityMode() { return provTlsUseCompatibilityMode; diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java b/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java index f2af7facd9..f94d9b14d1 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java @@ -1,6 +1,7 @@ package org.bouncycastle.jsse.provider; import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; @@ -28,6 +29,8 @@ class NamedGroupInfo private static final String PROPERTY_NAMED_GROUPS = "jdk.tls.namedGroups"; + private static final String PROPERTY_BC_EARLY_KEY_SHARES = "org.bouncycastle.jsse.client.earlyKeyShares"; + // NOTE: Not all of these are necessarily enabled/supported; it will be checked at runtime private enum All { @@ -81,13 +84,20 @@ private enum All OQS_mlkem1024(NamedGroup.OQS_mlkem1024, "ML-KEM"), MLKEM512(NamedGroup.MLKEM512, "ML-KEM"), MLKEM768(NamedGroup.MLKEM768, "ML-KEM"), - MLKEM1024(NamedGroup.MLKEM1024, "ML-KEM"); + MLKEM1024(NamedGroup.MLKEM1024, "ML-KEM"), + + SecP256r1MLKEM768(NamedGroup.SecP256r1MLKEM768, "EC", "ML-KEM"), + X25519MLKEM768(NamedGroup.X25519MLKEM768, "ML-KEM", "XDH"), + SecP384r1MLKEM1024(NamedGroup.SecP384r1MLKEM1024, "EC", "ML-KEM"), + curveMLKEM768(NamedGroup.curveSM2MLKEM768, "EC", "ML-KEM"); private final int namedGroup; private final String name; private final String text; - private final String jcaAlgorithm; - private final String jcaGroup; + private final String jcaAlgorithm1; + private final String jcaAlgorithm2; + private final String jcaGroup1; + private final String jcaGroup2; private final boolean char2; private final boolean supportedPost13; private final boolean supportedPre13; @@ -96,17 +106,45 @@ private enum All private All(int namedGroup, String jcaAlgorithm) { + if (NamedGroup.refersToASpecificHybrid(namedGroup)) + { + throw new IllegalArgumentException("Non-hybrid constructor only"); + } + this.namedGroup = namedGroup; this.name = NamedGroup.getName(namedGroup); this.text = NamedGroup.getText(namedGroup); - this.jcaAlgorithm = jcaAlgorithm; - this.jcaGroup = NamedGroup.getStandardName(namedGroup); + this.jcaAlgorithm1 = jcaAlgorithm; + this.jcaAlgorithm2 = null; + this.jcaGroup1 = NamedGroup.getStandardName(namedGroup); + this.jcaGroup2 = null; this.supportedPost13 = NamedGroup.canBeNegotiated(namedGroup, ProtocolVersion.TLSv13); this.supportedPre13 = NamedGroup.canBeNegotiated(namedGroup, ProtocolVersion.TLSv12); this.char2 = NamedGroup.isChar2Curve(namedGroup); this.bitsECDH = NamedGroup.getCurveBits(namedGroup); this.bitsFFDHE = NamedGroup.getFiniteFieldBits(namedGroup); } + + private All(int namedGroup, String jcaAlgorithm1, String jcaAlgorithm2) + { + if (!NamedGroup.refersToASpecificHybrid(namedGroup)) + { + throw new IllegalArgumentException("Hybrid constructor only"); + } + + this.namedGroup = namedGroup; + this.name = NamedGroup.getName(namedGroup); + this.text = NamedGroup.getText(namedGroup); + this.jcaAlgorithm1 = jcaAlgorithm1; + this.jcaAlgorithm2 = jcaAlgorithm2; + this.jcaGroup1 = NamedGroup.getStandardName(NamedGroup.getHybridFirst(namedGroup)); + this.jcaGroup2 = NamedGroup.getStandardName(NamedGroup.getHybridSecond(namedGroup)); + this.supportedPost13 = NamedGroup.canBeNegotiated(namedGroup, ProtocolVersion.TLSv13); + this.supportedPre13 = NamedGroup.canBeNegotiated(namedGroup, ProtocolVersion.TLSv12); + this.char2 = false; + this.bitsECDH = -1; + this.bitsFFDHE = -1; + } } private static final int[] CANDIDATES_DEFAULT = { @@ -121,15 +159,17 @@ private All(int namedGroup, String jcaAlgorithm) NamedGroup.ffdhe2048, NamedGroup.ffdhe3072, NamedGroup.ffdhe4096, + NamedGroup.X25519MLKEM768, }; static class PerConnection { - private final LinkedHashMap local; + private final Map local; + private final Vector localEarly; private final boolean localECDSA; private final AtomicReference> peer; - PerConnection(LinkedHashMap local, boolean localECDSA) + PerConnection(Map local, Vector localEarly, boolean localECDSA) { if (local == null) { @@ -137,10 +177,16 @@ static class PerConnection } this.local = local; + this.localEarly = localEarly; this.localECDSA = localECDSA; this.peer = new AtomicReference>(); } + Vector getLocalEarly() + { + return localEarly; + } + List getPeer() { return peer.get(); @@ -159,11 +205,13 @@ static class PerContext { private final Map index; private final int[] candidates; + private final int[] earlyCandidates; - PerContext(Map index, int[] candidates) + PerContext(Map index, int[] candidates, int[] earlyCandidates) { this.index = index; this.candidates = candidates; + this.earlyCandidates = earlyCandidates; } } @@ -240,15 +288,52 @@ private static PerConnection createPerConnection(PerContext perContext, ProvSSLP boolean localECDSA = hasAnyECDSA(local); - return new PerConnection(local, localECDSA); + Vector localEarly = null; + { + String[] earlyKeyShares = sslParameters.getEarlyKeyShares(); + + int[] earlyCandidates; + if (earlyKeyShares == null) + { + earlyCandidates = perContext.earlyCandidates; + } + else + { + earlyCandidates = createEarlyCandidates(perContext.index, earlyKeyShares, + "BCSSLParameters.earlyKeyShares"); + } + + if (earlyCandidates != null) + { + int earlyCount = earlyCandidates.length; + localEarly = new Vector(earlyCount); + for (int i = 0; i < earlyCount; ++i) + { + Integer earlyCandidate = Integers.valueOf(earlyCandidates[i]); + + NamedGroupInfo earlyNamedGroupInfo = local.get(earlyCandidate); + if (earlyNamedGroupInfo == null || !earlyNamedGroupInfo.isEnabled()) + { + LOG.warning("Candidate early key share not an enabled named group: " + + NamedGroup.getName(earlyCandidates[i])); + continue; + } + + localEarly.add(earlyCandidate); + } + } + } + + return new PerConnection(local, localEarly, localECDSA); } static PerContext createPerContext(boolean isFipsContext, JcaTlsCrypto crypto) { Map index = createIndex(isFipsContext, crypto); int[] candidates = createCandidatesFromProperty(index, PROPERTY_NAMED_GROUPS); + int[] earlyCandidates = createEarlyCandidatesFromProperty(index, PROPERTY_BC_EARLY_KEY_SHARES); - return new PerContext(index, candidates); + return new PerContext(index, candidates, earlyCandidates); } static DefaultedResult getMaximumBitsServerECDH(PerConnection perConnection) @@ -439,23 +524,37 @@ private static void addNamedGroup(boolean isFipsContext, JcaTlsCrypto crypto, bo boolean disable = (disableChar2 && all.char2) || (disableFFDHE && all.bitsFFDHE > 0); - boolean enabled = !disable && (null != all.jcaGroup) && crypto.hasNamedGroup(namedGroup); + boolean enabled = !disable && (null != all.jcaGroup1) && (null == all.jcaAlgorithm2 || null != all.jcaGroup2) + && TlsUtils.isSupportedNamedGroup(crypto, namedGroup); + + AlgorithmParameters algorithmParameters1 = null; + AlgorithmParameters algorithmParameters2 = null; - AlgorithmParameters algorithmParameters = null; if (enabled) { - // TODO[jsse] Consider also fetching 'jcaAlgorithm' + // TODO[jsse] Consider also fetching 'jcaAlgorithm1', 'jcaAlgorithm2' + try { - algorithmParameters = crypto.getNamedGroupAlgorithmParameters(namedGroup); + if (NamedGroup.refersToASpecificHybrid(namedGroup)) + { + algorithmParameters1 = getAlgorithmParameters(crypto, NamedGroup.getHybridFirst(namedGroup)); + algorithmParameters2 = getAlgorithmParameters(crypto, NamedGroup.getHybridSecond(namedGroup)); + } + else + { + algorithmParameters1 = getAlgorithmParameters(crypto, namedGroup); + } } catch (Exception e) { enabled = false; + algorithmParameters1 = null; + algorithmParameters2 = null; } } - NamedGroupInfo namedGroupInfo = new NamedGroupInfo(all, algorithmParameters, enabled); + NamedGroupInfo namedGroupInfo = new NamedGroupInfo(all, algorithmParameters1, algorithmParameters2, enabled); if (null != ng.put(namedGroup, namedGroupInfo)) { @@ -487,7 +586,7 @@ private static int[] createCandidates(Map index, String continue; } - NamedGroupInfo namedGroupInfo = index.get(namedGroup); + NamedGroupInfo namedGroupInfo = index.get(Integers.valueOf(namedGroup)); if (null == namedGroupInfo) { LOG.warning("'" + description + "' contains unsupported NamedGroup: " + name); @@ -513,6 +612,52 @@ private static int[] createCandidates(Map index, String return result; } + private static int[] createEarlyCandidatesFromProperty(Map index, String propertyName) + { + String[] names = PropertyUtils.getStringArraySystemProperty(propertyName); + if (null == names) + { + return null; + } + + return createEarlyCandidates(index, names, propertyName); + } + + private static int[] createEarlyCandidates(Map index, String[] names, String description) + { + int[] result = new int[names.length]; + int count = 0; + for (String name : names) + { + int namedGroup = getNamedGroupByName(name); + if (namedGroup < 0) + { + LOG.warning("'" + description + "' contains unrecognised NamedGroup: " + name); + continue; + } + + NamedGroupInfo namedGroupInfo = index.get(Integers.valueOf(namedGroup)); + if (null == namedGroupInfo) + { + LOG.warning("'" + description + "' contains unsupported NamedGroup: " + name); + continue; + } + + if (!namedGroupInfo.isEnabled()) + { + LOG.warning("'" + description + "' contains disabled NamedGroup: " + name); + continue; + } + + result[count++] = namedGroup; + } + if (count < result.length) + { + result = Arrays.copyOf(result, count); + } + return result; + } + private static Map createIndex(boolean isFipsContext, JcaTlsCrypto crypto) { Map ng = new TreeMap(); @@ -531,6 +676,12 @@ private static Map createIndex(boolean isFipsContext, J return ng; } + private static AlgorithmParameters getAlgorithmParameters(JcaTlsCrypto crypto, int namedGroup) + throws GeneralSecurityException + { + return crypto.getNamedGroupAlgorithmParameters(namedGroup); + } + private static int getNamedGroupByName(String name) { for (All all : All.values()) @@ -562,7 +713,7 @@ private static List getNamedGroupInfos(Map local) } private final All all; - private final AlgorithmParameters algorithmParameters; + private final AlgorithmParameters algorithmParameters1; + private final AlgorithmParameters algorithmParameters2; private final boolean enabled; - NamedGroupInfo(All all, AlgorithmParameters algorithmParameters, boolean enabled) + NamedGroupInfo(All all, AlgorithmParameters algorithmParameters1, AlgorithmParameters algorithmParameters2, + boolean enabled) { this.all = all; - this.algorithmParameters = algorithmParameters; + this.algorithmParameters1 = algorithmParameters1; + this.algorithmParameters2 = algorithmParameters2; this.enabled = enabled; } @@ -609,16 +763,6 @@ int getBitsFFDHE() return all.bitsFFDHE; } - String getJcaAlgorithm() - { - return all.jcaAlgorithm; - } - - String getJcaGroup() - { - return all.jcaGroup; - } - int getNamedGroup() { return all.namedGroup; @@ -656,7 +800,21 @@ private boolean isPermittedBy(BCAlgorithmConstraints algorithmConstraints) { Set primitives = JsseUtils.KEY_AGREEMENT_CRYPTO_PRIMITIVES_BC; - return algorithmConstraints.permits(primitives, getJcaGroup(), null) - && algorithmConstraints.permits(primitives, getJcaAlgorithm(), algorithmParameters); + if (!algorithmConstraints.permits(primitives, all.jcaGroup1, null) || + !algorithmConstraints.permits(primitives, all.jcaAlgorithm1, algorithmParameters1)) + { + return false; + } + + if (all.jcaAlgorithm2 != null) + { + if (!algorithmConstraints.permits(primitives, all.jcaGroup2, null) || + !algorithmConstraints.permits(primitives, all.jcaAlgorithm2, algorithmParameters2)) + { + return false; + } + } + + return true; } } diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvAlgorithmChecker.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvAlgorithmChecker.java index 8a46a9ff11..74627b43b8 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvAlgorithmChecker.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvAlgorithmChecker.java @@ -68,6 +68,24 @@ private static Map createSigAlgNames() names.put(EdECObjectIdentifiers.id_Ed25519.getId(), "Ed25519"); names.put(EdECObjectIdentifiers.id_Ed448.getId(), "Ed448"); + + names.put(NISTObjectIdentifiers.id_ml_dsa_44.getId(), "ML-DSA-44"); + names.put(NISTObjectIdentifiers.id_ml_dsa_65.getId(), "ML-DSA-65"); + names.put(NISTObjectIdentifiers.id_ml_dsa_87.getId(), "ML-DSA-87"); + + names.put(NISTObjectIdentifiers.id_slh_dsa_sha2_128s.getId(), "SLH-DSA-SHA2-128S"); + names.put(NISTObjectIdentifiers.id_slh_dsa_sha2_128f.getId(), "SLH-DSA-SHA2-128F"); + names.put(NISTObjectIdentifiers.id_slh_dsa_sha2_192s.getId(), "SLH-DSA-SHA2-192S"); + names.put(NISTObjectIdentifiers.id_slh_dsa_sha2_192f.getId(), "SLH-DSA-SHA2-192F"); + names.put(NISTObjectIdentifiers.id_slh_dsa_sha2_256s.getId(), "SLH-DSA-SHA2-256S"); + names.put(NISTObjectIdentifiers.id_slh_dsa_sha2_256f.getId(), "SLH-DSA-SHA2-256F"); + names.put(NISTObjectIdentifiers.id_slh_dsa_shake_128s.getId(), "SLH-DSA-SHAKE-128S"); + names.put(NISTObjectIdentifiers.id_slh_dsa_shake_128f.getId(), "SLH-DSA-SHAKE-128F"); + names.put(NISTObjectIdentifiers.id_slh_dsa_shake_192s.getId(), "SLH-DSA-SHAKE-192S"); + names.put(NISTObjectIdentifiers.id_slh_dsa_shake_192f.getId(), "SLH-DSA-SHAKE-192F"); + names.put(NISTObjectIdentifiers.id_slh_dsa_shake_256s.getId(), "SLH-DSA-SHAKE-256S"); + names.put(NISTObjectIdentifiers.id_slh_dsa_shake_256f.getId(), "SLH-DSA-SHAKE-256F"); + names.put(OIWObjectIdentifiers.dsaWithSHA1.getId(), "SHA1withDSA"); names.put(X9ObjectIdentifiers.id_dsa_with_sha1.getId(), "SHA1withDSA"); diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvAlgorithmConstraints.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvAlgorithmConstraints.java index f473c930db..57281660ba 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvAlgorithmConstraints.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvAlgorithmConstraints.java @@ -10,7 +10,7 @@ import org.bouncycastle.jsse.java.security.BCCryptoPrimitive; class ProvAlgorithmConstraints - extends AbstractAlgorithmConstraints + implements BCAlgorithmConstraints { private static final Logger LOG = Logger.getLogger(ProvAlgorithmConstraints.class.getName()); @@ -43,8 +43,6 @@ class ProvAlgorithmConstraints ProvAlgorithmConstraints(BCAlgorithmConstraints configAlgorithmConstraints, boolean enableX509Constraints) { - super(null); - this.configAlgorithmConstraints = configAlgorithmConstraints; this.supportedSignatureAlgorithms = null; this.enableX509Constraints = enableX509Constraints; @@ -53,17 +51,15 @@ class ProvAlgorithmConstraints ProvAlgorithmConstraints(BCAlgorithmConstraints configAlgorithmConstraints, String[] supportedSignatureAlgorithms, boolean enableX509Constraints) { - super(null); - this.configAlgorithmConstraints = configAlgorithmConstraints; - this.supportedSignatureAlgorithms = asUnmodifiableSet(supportedSignatureAlgorithms); + this.supportedSignatureAlgorithms = AbstractAlgorithmConstraints.asUnmodifiableSet(supportedSignatureAlgorithms); this.enableX509Constraints = enableX509Constraints; } public boolean permits(Set primitives, String algorithm, AlgorithmParameters parameters) { - checkPrimitives(primitives); - checkAlgorithmName(algorithm); + AbstractAlgorithmConstraints.checkPrimitives(primitives); + AbstractAlgorithmConstraints.checkAlgorithmName(algorithm); if (null != supportedSignatureAlgorithms) { @@ -105,8 +101,8 @@ public boolean permits(Set primitives, String algorithm, Algo public boolean permits(Set primitives, Key key) { - checkPrimitives(primitives); - checkKey(key); + AbstractAlgorithmConstraints.checkPrimitives(primitives); + AbstractAlgorithmConstraints.checkKey(key); if (null != configAlgorithmConstraints && !configAlgorithmConstraints.permits(primitives, key)) { @@ -129,9 +125,9 @@ public boolean permits(Set primitives, Key key) public boolean permits(Set primitives, String algorithm, Key key, AlgorithmParameters parameters) { - checkPrimitives(primitives); - checkAlgorithmName(algorithm); - checkKey(key); + AbstractAlgorithmConstraints.checkPrimitives(primitives); + AbstractAlgorithmConstraints.checkAlgorithmName(algorithm); + AbstractAlgorithmConstraints.checkKey(key); if (null != supportedSignatureAlgorithms) { @@ -175,6 +171,6 @@ private String getAlgorithm(String algorithmBC) private boolean isSupportedSignatureAlgorithm(String algorithmBC) { - return containsIgnoreCase(supportedSignatureAlgorithms, algorithmBC); + return AbstractAlgorithmConstraints.containsIgnoreCase(supportedSignatureAlgorithms, algorithmBC); } } diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java index 829fe367df..3fc9d4bf24 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java @@ -181,6 +181,9 @@ private static Map createSupportedCipherSuiteMap() addCipherSuite(cs, "TLS_AES_256_GCM_SHA384", CipherSuite.TLS_AES_256_GCM_SHA384); addCipherSuite(cs, "TLS_CHACHA20_POLY1305_SHA256", CipherSuite.TLS_CHACHA20_POLY1305_SHA256); + addCipherSuite(cs, "TLS_SHA256_SHA256", CipherSuite.TLS_SHA256_SHA256); + addCipherSuite(cs, "TLS_SHA384_SHA384", CipherSuite.TLS_SHA384_SHA384); + // TLS 1.2- addCipherSuite(cs, "TLS_DH_anon_WITH_AES_128_CBC_SHA", CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA); addCipherSuite(cs, "TLS_DH_anon_WITH_AES_128_CBC_SHA256", CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256); @@ -339,9 +342,11 @@ private static Map createSupportedProtocolMapFips( } private static String[] getDefaultEnabledCipherSuites(Map supportedCipherSuiteMap, - List defaultCipherSuiteList, boolean disableDHDefaultSuites, String cipherSuitesPropertyName) + List defaultCipherSuiteList, boolean disableDHDefaultSuites, String cipherSuitesPropertyName, + String title) { List candidates = getJdkTlsCipherSuites(cipherSuitesPropertyName, defaultCipherSuiteList); + boolean disableDHSuites = disableDHDefaultSuites && candidates == defaultCipherSuiteList; String[] result = new String[candidates.size()]; int count = 0; @@ -352,15 +357,15 @@ private static String[] getDefaultEnabledCipherSuites(Map supportedCipherSuiteMap, @@ -386,7 +391,7 @@ private static String[] getDefaultEnabledCipherSuitesServer(Map supportedProtocolMap, diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLEngine.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLEngine.java index 4d27cf8f36..d0a0b8bf35 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLEngine.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLEngine.java @@ -57,6 +57,7 @@ class ProvSSLEngine protected TlsProtocol protocol = null; protected ProvTlsPeer protocolPeer = null; protected ProvSSLConnection connection = null; + protected ProvSSLSession dummySession = null; protected ProvSSLSessionHandshake handshakeSession = null; protected SSLException deferredException = null; @@ -225,7 +226,12 @@ public synchronized BCApplicationProtocolSelector getBCHandshakeAppli return sslParameters.getEngineAPSelector(); } - public synchronized BCExtendedSSLSession getBCHandshakeSession() + public BCExtendedSSLSession getBCHandshakeSession() + { + return getBCHandshakeSessionImpl(); + } + + public synchronized ProvSSLSessionHandshake getBCHandshakeSessionImpl() { return handshakeSession; } @@ -703,7 +709,7 @@ public synchronized void notifyHandshakeSession(ProvSSLSessionContext sslSession if (null != resumedSession) { this.handshakeSession = new ProvSSLSessionResumed(sslSessionContext, peerHost, peerPort, securityParameters, - jsseSecurityParameters, resumedSession.getTlsSession(), resumedSession.getJsseSessionParameters()); + jsseSecurityParameters, resumedSession); } else { @@ -717,9 +723,19 @@ public synchronized String selectApplicationProtocol(List protocols) return sslParameters.getEngineAPSelector().select(this, protocols); } - ProvSSLSession getSessionImpl() + synchronized ProvSSLSession getSessionImpl() { - return null == connection ? ProvSSLSession.NULL_SESSION : connection.getSession(); + if (connection != null) + { + return connection.getSession(); + } + + if (dummySession == null) + { + dummySession = ProvSSLSession.createDummySession(); + } + + return dummySession; } private RecordPreview getRecordPreview(ByteBuffer src) diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLParameters.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLParameters.java index d1a191b418..f5855a4e14 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLParameters.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLParameters.java @@ -39,13 +39,15 @@ private static List copyList(Collection list) private BCAlgorithmConstraints algorithmConstraints = ProvAlgorithmConstraints.DEFAULT; private List sniServerNames; private List sniMatchers; - private boolean useCipherSuitesOrder = true; + private boolean useCipherSuitesOrder = false; + private boolean useNamedGroupsOrder = false; private boolean enableRetransmissions = true; private int maximumPacketSize = 0; private String[] applicationProtocols = TlsUtils.EMPTY_STRINGS; private String[] signatureSchemes = null; private String[] signatureSchemesCert = null; private String[] namedGroups = null; + private String[] earlyKeyShares = null; private BCApplicationProtocolSelector engineAPSelector; private BCApplicationProtocolSelector socketAPSelector; @@ -69,12 +71,14 @@ ProvSSLParameters copy() p.sniServerNames = sniServerNames; p.sniMatchers = sniMatchers; p.useCipherSuitesOrder = useCipherSuitesOrder; + p.useNamedGroupsOrder = useNamedGroupsOrder; p.enableRetransmissions = enableRetransmissions; p.maximumPacketSize = maximumPacketSize; p.applicationProtocols = applicationProtocols; p.signatureSchemes = signatureSchemes; p.signatureSchemesCert = signatureSchemesCert; p.namedGroups = namedGroups; + p.earlyKeyShares = earlyKeyShares; p.engineAPSelector = engineAPSelector; p.socketAPSelector = socketAPSelector; p.sessionToResume = sessionToResume; @@ -214,6 +218,16 @@ public void setUseCipherSuitesOrder(boolean useCipherSuitesOrder) this.useCipherSuitesOrder = useCipherSuitesOrder; } + public boolean getUseNamedGroupsOrder() + { + return useNamedGroupsOrder; + } + + public void setUseNamedGroupsOrder(boolean useNamedGroupsOrder) + { + this.useNamedGroupsOrder = useNamedGroupsOrder; + } + public boolean getEnableRetransmissions() { return enableRetransmissions; @@ -279,6 +293,16 @@ public void setNamedGroups(String[] namedGroups) this.namedGroups = TlsUtils.clone(namedGroups); } + public String[] getEarlyKeyShares() + { + return TlsUtils.clone(earlyKeyShares); + } + + public void setEarlyKeyShares(String[] earlyKeyShares) + { + this.earlyKeyShares = TlsUtils.clone(earlyKeyShares); + } + public BCApplicationProtocolSelector getEngineAPSelector() { return engineAPSelector; diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSession.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSession.java index ea6bfc5c44..88f921ea70 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSession.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSession.java @@ -1,6 +1,8 @@ package org.bouncycastle.jsse.provider; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; import org.bouncycastle.jsse.BCSNIServerName; import org.bouncycastle.tls.CipherSuite; @@ -11,23 +13,31 @@ class ProvSSLSession extends ProvSSLSessionBase { - // TODO[jsse] Ensure this behaves according to the javadoc for SSLSocket.getSession and SSLEngine.getSession - // TODO[jsse] This would make more sense as a ProvSSLSessionHandshake - static final ProvSSLSession NULL_SESSION = new ProvSSLSession(null, null, -1, null, - new JsseSessionParameters(null, null)); - protected final TlsSession tlsSession; protected final SessionParameters sessionParameters; protected final JsseSessionParameters jsseSessionParameters; + protected final AtomicLong lastAccessedTime; - ProvSSLSession(ProvSSLSessionContext sslSessionContext, String peerHost, int peerPort, TlsSession tlsSession, - JsseSessionParameters jsseSessionParameters) + ProvSSLSession(ProvSSLSessionContext sslSessionContext, ConcurrentHashMap valueMap, String peerHost, + int peerPort, long creationTime, TlsSession tlsSession, JsseSessionParameters jsseSessionParameters) { - super(sslSessionContext, peerHost, peerPort); + super(sslSessionContext, valueMap, peerHost, peerPort, creationTime); this.tlsSession = tlsSession; this.sessionParameters = tlsSession == null ? null : tlsSession.exportSessionParameters(); this.jsseSessionParameters = jsseSessionParameters; + this.lastAccessedTime = new AtomicLong(creationTime); + } + + long access() + { + long accessTime = getCurrentTime(), previous; + do + { + previous = lastAccessedTime.get(); + } + while (accessTime > previous && !lastAccessedTime.compareAndSet(previous, accessTime)); + return accessTime; } @Override @@ -54,6 +64,11 @@ protected JsseSessionParameters getJsseSessionParameters() return jsseSessionParameters; } + public long getLastAccessedTime() + { + return lastAccessedTime.get(); + } + @Override protected org.bouncycastle.tls.Certificate getLocalCertificateTLS() { @@ -110,4 +125,11 @@ public boolean isValid() { return super.isValid() && null != tlsSession && tlsSession.isResumable(); } + + static final ProvSSLSession createDummySession() + { + // NB: Allow session value binding on failed connections for SunJSSE compatibility + return new ProvSSLSession(null, createValueMap(), null, -1, getCurrentTime(), null, + new JsseSessionParameters(null, null)); + } } diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionBase.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionBase.java index a0ca7f1010..bd1a477062 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionBase.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionBase.java @@ -3,10 +3,7 @@ import java.security.Principal; import java.security.cert.Certificate; import java.security.cert.X509Certificate; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; import javax.net.ssl.SSLPeerUnverifiedException; @@ -27,27 +24,26 @@ abstract class ProvSSLSessionBase extends BCExtendedSSLSession { - protected final Map valueMap = Collections.synchronizedMap(new HashMap()); - protected final AtomicReference sslSessionContext; + protected final ConcurrentHashMap valueMap; protected final boolean fipsMode; protected final JcaTlsCrypto crypto; protected final String peerHost; protected final int peerPort; protected final long creationTime; protected final SSLSession exportSSLSession; - protected final AtomicLong lastAccessedTime; - ProvSSLSessionBase(ProvSSLSessionContext sslSessionContext, String peerHost, int peerPort) + ProvSSLSessionBase(ProvSSLSessionContext sslSessionContext, ConcurrentHashMap valueMap, + String peerHost, int peerPort, long creationTime) { this.sslSessionContext = new AtomicReference(sslSessionContext); + this.valueMap = valueMap; this.fipsMode = (null == sslSessionContext) ? false : sslSessionContext.getContextData().isFipsMode(); this.crypto = (null == sslSessionContext) ? null : sslSessionContext.getContextData().getCrypto(); this.peerHost = peerHost; this.peerPort = peerPort; - this.creationTime = System.currentTimeMillis(); + this.creationTime = creationTime; this.exportSSLSession = SSLSessionUtil.exportSSLSession(this); - this.lastAccessedTime = new AtomicLong(creationTime); } protected abstract int getCipherSuiteTLS(); @@ -71,15 +67,6 @@ SSLSession getExportSSLSession() return exportSSLSession; } - void accessedAt(long accessTime) - { - long current = lastAccessedTime.get(); - if (accessTime > current) - { - lastAccessedTime.compareAndSet(current, accessTime); - } - } - @Override public boolean equals(Object obj) { @@ -118,11 +105,6 @@ public byte[] getId() return TlsUtils.isNullOrEmpty(id) ? TlsUtils.EMPTY_BYTES : id.clone(); } - public long getLastAccessedTime() - { - return lastAccessedTime.get(); - } - public Certificate[] getLocalCertificates() { if (null != crypto) @@ -237,15 +219,22 @@ public SSLSessionContext getSessionContext() public Object getValue(String name) { + if (name == null) + { + throw new IllegalArgumentException("'name' cannot be null"); + } + return valueMap.get(name); } + ConcurrentHashMap getValueMap() + { + return valueMap; + } + public String[] getValueNames() { - synchronized (valueMap) - { - return valueMap.keySet().toArray(new String[valueMap.size()]); - } + return valueMap.keySet().toArray(new String[0]); } @Override @@ -287,12 +276,26 @@ public boolean isValid() public void putValue(String name, Object value) { + if (name == null) + { + throw new IllegalArgumentException("'name' cannot be null"); + } + if (value == null) + { + throw new IllegalArgumentException("'value' cannot be null"); + } + notifyUnbound(name, valueMap.put(name, value)); notifyBound(name, value); } public void removeValue(String name) { + if (name == null) + { + throw new IllegalArgumentException("'name' cannot be null"); + } + notifyUnbound(name, valueMap.remove(name)); } @@ -337,4 +340,14 @@ private void implInvalidate(boolean removeFromSessionContext) invalidateTLS(); } + + protected static ConcurrentHashMap createValueMap() + { + return new ConcurrentHashMap(); + } + + protected static long getCurrentTime() + { + return System.currentTimeMillis(); + } } diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionContext.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionContext.java index da88a753a6..352440c575 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionContext.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionContext.java @@ -63,7 +63,7 @@ synchronized ProvSSLSession getSessionImpl(byte[] sessionID) { processQueue(); - return accessSession(mapGet(sessionsByID, makeSessionID(sessionID))); + return getSessionImpl(mapGet(sessionsByID, makeSessionID(sessionID))); } synchronized ProvSSLSession getSessionImpl(String hostName, int port) @@ -71,7 +71,7 @@ synchronized ProvSSLSession getSessionImpl(String hostName, int port) processQueue(); SessionEntry sessionEntry = mapGet(sessionsByPeer, makePeerKey(hostName, port)); - ProvSSLSession session = accessSession(sessionEntry); + ProvSSLSession session = getSessionImpl(sessionEntry); if (session != null) { // NOTE: For the current simple cache implementation, need to 'access' the sessionByIDs entry @@ -89,14 +89,15 @@ synchronized void removeSession(byte[] sessionID) } } - synchronized ProvSSLSession reportSession(String peerHost, int peerPort, TlsSession tlsSession, - JsseSessionParameters jsseSessionParameters, boolean addToCache) + synchronized ProvSSLSession reportSession(ProvSSLSessionHandshake handshakeSession, String peerHost, int peerPort, + TlsSession tlsSession, JsseSessionParameters jsseSessionParameters, boolean addToCache) { processQueue(); if (!addToCache) { - return new ProvSSLSession(this, peerHost, peerPort, tlsSession, jsseSessionParameters); + return new ProvSSLSession(this, handshakeSession.getValueMap(), peerHost, peerPort, + handshakeSession.getCreationTime(), tlsSession, jsseSessionParameters); } SessionID sessionID = makeSessionID(tlsSession.getSessionID()); @@ -105,7 +106,8 @@ synchronized ProvSSLSession reportSession(String peerHost, int peerPort, TlsSess ProvSSLSession session = sessionEntry == null ? null : sessionEntry.get(); if (null == session || session.getTlsSession() != tlsSession) { - session = new ProvSSLSession(this, peerHost, peerPort, tlsSession, jsseSessionParameters); + session = new ProvSSLSession(this, handshakeSession.getValueMap(), peerHost, peerPort, + handshakeSession.getCreationTime(), tlsSession, jsseSessionParameters); if (null != sessionID) { @@ -205,17 +207,15 @@ public synchronized void setSessionTimeout(int seconds) throws IllegalArgumentEx removeAllExpiredSessions(); } - private ProvSSLSession accessSession(SessionEntry sessionEntry) + private ProvSSLSession getSessionImpl(SessionEntry sessionEntry) { if (sessionEntry != null) { ProvSSLSession session = sessionEntry.get(); if (session != null) { - long currentTimeMillis = System.currentTimeMillis(); - if (!invalidateIfCreatedBefore(sessionEntry, getCreationTimeLimit(currentTimeMillis))) + if (!invalidateIfCreatedBefore(sessionEntry, getCreationTimeLimit())) { - session.accessedAt(currentTimeMillis); return session; } } @@ -225,9 +225,9 @@ private ProvSSLSession accessSession(SessionEntry sessionEntry) return null; } - private long getCreationTimeLimit(long expiryTimeMillis) + private long getCreationTimeLimit() { - return sessionTimeoutSeconds < 1 ? Long.MIN_VALUE : (expiryTimeMillis - 1000L * sessionTimeoutSeconds); + return sessionTimeoutSeconds < 1 ? Long.MIN_VALUE : (System.currentTimeMillis() - 1000L * sessionTimeoutSeconds); } private boolean invalidateIfCreatedBefore(SessionEntry sessionEntry, long creationTimeLimit) @@ -265,7 +265,7 @@ private void removeAllExpiredSessions() { processQueue(); - long creationTimeLimit = getCreationTimeLimit(System.currentTimeMillis()); + long creationTimeLimit = getCreationTimeLimit(); Iterator iter = sessionsByID.values().iterator(); while (iter.hasNext()) diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionHandshake.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionHandshake.java index 6e708de145..207b3c65ac 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionHandshake.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionHandshake.java @@ -4,6 +4,7 @@ import java.util.Collections; import java.util.List; import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; import org.bouncycastle.jsse.BCSNIServerName; import org.bouncycastle.tls.ProtocolVersion; @@ -19,7 +20,15 @@ class ProvSSLSessionHandshake ProvSSLSessionHandshake(ProvSSLSessionContext sslSessionContext, String peerHost, int peerPort, SecurityParameters securityParameters, JsseSecurityParameters jsseSecurityParameters) { - super(sslSessionContext, peerHost, peerPort); + this(sslSessionContext, createValueMap(), peerHost, peerPort, getCurrentTime(), securityParameters, + jsseSecurityParameters); + } + + protected ProvSSLSessionHandshake(ProvSSLSessionContext sslSessionContext, + ConcurrentHashMap valueMap, String peerHost, int peerPort, long creationTime, + SecurityParameters securityParameters, JsseSecurityParameters jsseSecurityParameters) + { + super(sslSessionContext, valueMap, peerHost, peerPort, creationTime); this.securityParameters = securityParameters; this.jsseSecurityParameters = jsseSecurityParameters; @@ -54,6 +63,11 @@ protected JsseSessionParameters getJsseSessionParameters() return null; } + public long getLastAccessedTime() + { + return getCreationTime(); + } + @Override protected org.bouncycastle.tls.Certificate getLocalCertificateTLS() { diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionResumed.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionResumed.java index bae57aa13f..45c787210a 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionResumed.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionResumed.java @@ -11,16 +11,19 @@ class ProvSSLSessionResumed protected final TlsSession tlsSession; protected final SessionParameters sessionParameters; protected final JsseSessionParameters jsseSessionParameters; + protected final long lastAccessedTime; ProvSSLSessionResumed(ProvSSLSessionContext sslSessionContext, String peerHost, int peerPort, - SecurityParameters securityParameters, JsseSecurityParameters jsseSecurityParameters, TlsSession tlsSession, - JsseSessionParameters jsseSessionParameters) + SecurityParameters securityParameters, JsseSecurityParameters jsseSecurityParameters, + ProvSSLSession resumedSession) { - super(sslSessionContext, peerHost, peerPort, securityParameters, jsseSecurityParameters); + super(sslSessionContext, resumedSession.getValueMap(), peerHost, peerPort, resumedSession.getCreationTime(), + securityParameters, jsseSecurityParameters); - this.tlsSession = tlsSession; + this.tlsSession = resumedSession.getTlsSession(); this.sessionParameters = tlsSession.exportSessionParameters(); - this.jsseSessionParameters = jsseSessionParameters; + this.jsseSessionParameters = resumedSession.getJsseSessionParameters(); + this.lastAccessedTime = resumedSession.access(); } @Override @@ -35,6 +38,11 @@ protected byte[] getIDArray() return tlsSession.getSessionID(); } + public long getLastAccessedTime() + { + return lastAccessedTime; + } + @Override protected JsseSessionParameters getJsseSessionParameters() { diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java index 889ab1b60b..442e8a4f76 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java @@ -51,6 +51,7 @@ class ProvSSLSocketDirect protected TlsProtocol protocol = null; protected ProvTlsPeer protocolPeer = null; protected ProvSSLConnection connection = null; + protected ProvSSLSession dummySession = null; protected ProvSSLSessionHandshake handshakeSession = null; /** This constructor is the one used (only) by ProvSSLServerSocket */ @@ -183,7 +184,12 @@ public synchronized BCApplicationProtocolSelector getBCHandshakeAppli return sslParameters.getSocketAPSelector(); } - public synchronized BCExtendedSSLSession getBCHandshakeSession() + public BCExtendedSSLSession getBCHandshakeSession() + { + return getBCHandshakeSessionImpl(); + } + + public synchronized ProvSSLSessionHandshake getBCHandshakeSessionImpl() { return handshakeSession; } @@ -490,7 +496,7 @@ public synchronized void notifyHandshakeSession(ProvSSLSessionContext sslSession if (null != resumedSession) { this.handshakeSession = new ProvSSLSessionResumed(sslSessionContext, peerHost, peerPort, securityParameters, - jsseSecurityParameters, resumedSession.getTlsSession(), resumedSession.getJsseSessionParameters()); + jsseSecurityParameters, resumedSession); } else { @@ -508,7 +514,17 @@ synchronized ProvSSLSession getSessionImpl() { getConnection(); - return null == connection ? ProvSSLSession.NULL_SESSION : connection.getSession(); + if (connection != null) + { + return connection.getSession(); + } + + if (dummySession == null) + { + dummySession = ProvSSLSession.createDummySession(); + } + + return dummySession; } synchronized void handshakeIfNecessary(boolean resumable) throws IOException diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketWrap.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketWrap.java index e793543054..70a00905ad 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketWrap.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketWrap.java @@ -68,6 +68,7 @@ private static Socket checkSocket(Socket s) throws SocketException protected TlsProtocol protocol = null; protected ProvTlsPeer protocolPeer = null; protected ProvSSLConnection connection = null; + protected ProvSSLSession dummySession = null; protected ProvSSLSessionHandshake handshakeSession = null; protected ProvSSLSocketWrap(ContextData contextData, Socket s, InputStream consumed, boolean autoClose) @@ -188,7 +189,12 @@ public synchronized BCApplicationProtocolSelector getBCHandshakeAppli return sslParameters.getSocketAPSelector(); } - public synchronized BCExtendedSSLSession getBCHandshakeSession() + public BCExtendedSSLSession getBCHandshakeSession() + { + return getBCHandshakeSessionImpl(); + } + + public synchronized ProvSSLSessionHandshake getBCHandshakeSessionImpl() { return handshakeSession; } @@ -679,7 +685,7 @@ public synchronized void notifyHandshakeSession(ProvSSLSessionContext sslSession if (null != resumedSession) { this.handshakeSession = new ProvSSLSessionResumed(sslSessionContext, peerHost, peerPort, securityParameters, - jsseSecurityParameters, resumedSession.getTlsSession(), resumedSession.getJsseSessionParameters()); + jsseSecurityParameters, resumedSession); } else { @@ -697,7 +703,17 @@ synchronized ProvSSLSession getSessionImpl() { getConnection(); - return null == connection ? ProvSSLSession.NULL_SESSION : connection.getSession(); + if (connection != null) + { + return connection.getSession(); + } + + if (dummySession == null) + { + dummySession = ProvSSLSession.createDummySession(); + } + + return dummySession; } synchronized void handshakeIfNecessary(boolean resumable) throws IOException diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsClient.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsClient.java index f26afc0652..7dd0254a6a 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsClient.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsClient.java @@ -174,7 +174,11 @@ protected Vector getSNIServerNames() List sniServerNames = sslParameters.getServerNames(); if (null == sniServerNames) { - String peerHostSNI = manager.getPeerHostSNI(); + /* + * A fully qualified domain name (FQDN) may contain a trailing dot. We remove it for the + * purpose of SNI and endpoint ID checks (e.g. SNIHostName doesn't permit it). + */ + String peerHostSNI = JsseUtils.stripTrailingDot(manager.getPeerHostSNI()); /* * TODO[jsse] Consider removing the restriction that the name must contain a '.' @@ -210,7 +214,7 @@ protected Vector getSNIServerNames() @Override protected int[] getSupportedCipherSuites() { - return manager.getContextData().getActiveCipherSuites(getCrypto(), sslParameters, getProtocolVersions()); + return null; } @Override @@ -236,7 +240,7 @@ protected Vector getSupportedSignatureAlgorithmsCert( @Override protected ProtocolVersion[] getSupportedVersions() { - return manager.getContextData().getActiveProtocolVersions(sslParameters); + return null; } @Override @@ -389,16 +393,28 @@ public JcaTlsCrypto getCrypto() return manager.getContextData().getCrypto(); } + @Override + public Vector getEarlyKeyShareGroups() + { + Vector jsse = jsseSecurityParameters.namedGroups.getLocalEarly(); + if (jsse != null) + { + return jsse; + } + + return super.getEarlyKeyShareGroups(); + } + @Override public int getMaxCertificateChainLength() { - return JsseUtils.getMaxCertificateChainLength(); + return JsseUtils.getMaxInboundCertChainLenClient(); } @Override public int getMaxHandshakeMessageSize() { - return JsseUtils.getMaxHandshakeMessageSize(); + return manager.getContextData().getMaxHandshakeMessageSize(); } @Override @@ -477,9 +493,9 @@ public void notifyConnectionClosed() { super.notifyConnectionClosed(); - if (LOG.isLoggable(Level.INFO)) + if (LOG.isLoggable(Level.FINE)) { - LOG.info(clientID + " disconnected from " + JsseUtils.getPeerReport(manager)); + LOG.fine(clientID + " disconnected from " + JsseUtils.getPeerReport(manager)); } } @@ -488,13 +504,30 @@ public void notifyHandshakeBeginning() throws IOException { super.notifyHandshakeBeginning(); - if (LOG.isLoggable(Level.INFO)) + ContextData contextData = manager.getContextData(); + ProtocolVersion[] activeProtocolVersions; + + if (context.getSecurityParametersHandshake().isRenegotiating()) { - LOG.info(clientID + " opening connection to " + JsseUtils.getPeerReport(manager)); + if (LOG.isLoggable(Level.FINE)) + { + LOG.fine(clientID + " renegotiating connection to " + JsseUtils.getPeerReport(manager)); + } + + activeProtocolVersions = context.getSecurityParametersConnection().getNegotiatedVersion().only(); } + else + { + if (LOG.isLoggable(Level.FINE)) + { + LOG.fine(clientID + " opening connection to " + JsseUtils.getPeerReport(manager)); + } - ContextData contextData = manager.getContextData(); - ProtocolVersion[] activeProtocolVersions = getProtocolVersions(); + activeProtocolVersions = contextData.getActiveProtocolVersions(sslParameters); + } + + this.protocolVersions = activeProtocolVersions; + this.cipherSuites = contextData.getActiveCipherSuites(getCrypto(), sslParameters, activeProtocolVersions); jsseSecurityParameters.namedGroups = contextData.getNamedGroupsClient(sslParameters, activeProtocolVersions); @@ -509,9 +542,9 @@ public synchronized void notifyHandshakeComplete() throws IOException this.handshakeComplete = true; - if (LOG.isLoggable(Level.INFO)) + if (LOG.isLoggable(Level.FINE)) { - LOG.info(clientID + " established connection with " + JsseUtils.getPeerReport(manager)); + LOG.fine(clientID + " established connection with " + JsseUtils.getPeerReport(manager)); } TlsSession connectionTlsSession = context.getSession(); @@ -526,8 +559,8 @@ public synchronized void notifyHandshakeComplete() throws IOException // TODO[tls13] Resumption/PSK boolean addToCache = provClientEnableSessionResumption && !TlsUtils.isTLSv13(context); - this.sslSession = sslSessionContext.reportSession(peerHost, peerPort, connectionTlsSession, - jsseSessionParameters, addToCache); + this.sslSession = sslSessionContext.reportSession(manager.getBCHandshakeSessionImpl(), peerHost, peerPort, + connectionTlsSession, jsseSessionParameters, addToCache); } manager.notifyHandshakeComplete(new ProvSSLConnection(this)); @@ -892,7 +925,7 @@ protected TlsCredentials selectClientCredentialsLegacy(Principal[] issuers, shor return JsseUtils.createCredentialedSigner(context, getCrypto(), x509Key, null); } - private void handleKeyManagerMisses(LinkedHashMap keyTypeMap, String selectedKeyType) + private void handleKeyManagerMisses(Map keyTypeMap, String selectedKeyType) { for (Map.Entry entry : keyTypeMap.entrySet()) { diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsClientProtocol.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsClientProtocol.java index 2ea5384d4c..de8e7e1ae1 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsClientProtocol.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsClientProtocol.java @@ -1,15 +1,23 @@ package org.bouncycastle.jsse.provider; +import java.io.ByteArrayInputStream; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.bouncycastle.tls.HandshakeMessageInput; +import org.bouncycastle.tls.HandshakeType; import org.bouncycastle.tls.RenegotiationPolicy; +import org.bouncycastle.tls.ServerHello; import org.bouncycastle.tls.TlsClientProtocol; class ProvTlsClientProtocol extends TlsClientProtocol { + private static final Logger LOG = Logger.getLogger(ProvTlsClientProtocol.class.getName()); + private static final boolean provAcceptRenegotiation = PropertyUtils.getBooleanSystemProperty( "org.bouncycastle.jsse.client.acceptRenegotiation", false); @@ -33,4 +41,47 @@ protected int getRenegotiationPolicy() { return provAcceptRenegotiation ? RenegotiationPolicy.ACCEPT : RenegotiationPolicy.DENY; } + + @Override + protected void handleHandshakeMessage(short type, HandshakeMessageInput buf) throws IOException + { + if (LOG.isLoggable(Level.FINEST)) + { + int length = buf.available(); + LOG.finest(getClientID() + " inbound handshake message: " + HandshakeType.getText(type) + "[" + length + "]"); + } + + super.handleHandshakeMessage(type, buf); + } + + @Override + protected ServerHello receiveServerHelloMessage(ByteArrayInputStream buf) throws IOException + { + ServerHello serverHello = super.receiveServerHelloMessage(buf); + + if (LOG.isLoggable(Level.FINEST)) + { + String title = getClientID() + " ServerHello extensions"; + LOG.finest(JsseUtils.getExtensionsReport(title, serverHello.getExtensions())); + } + + return serverHello; + } + + @Override + protected void sendClientHelloMessage() throws IOException + { + if (LOG.isLoggable(Level.FINEST)) + { + String title = getClientID() + " ClientHello extensions"; + LOG.finest(JsseUtils.getExtensionsReport(title, clientHello.getExtensions())); + } + + super.sendClientHelloMessage(); + } + + private String getClientID() + { + return ((ProvTlsClient)tlsClient).getID(); + } } diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsManager.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsManager.java index bea7262ca9..ed107bbf0b 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsManager.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsManager.java @@ -18,10 +18,12 @@ interface ProvTlsManager BCX509Key chooseServerKey(String[] keyTypes, Principal[] issuers); - boolean getEnableSessionCreation(); + ProvSSLSessionHandshake getBCHandshakeSessionImpl(); ContextData getContextData(); + boolean getEnableSessionCreation(); + String getPeerHost(); String getPeerHostSNI(); diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsServer.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsServer.java index 44d991ad5a..493e324f08 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsServer.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsServer.java @@ -313,6 +313,12 @@ protected boolean preferLocalCipherSuites() return sslParameters.getUseCipherSuitesOrder(); } + @Override + public boolean preferLocalSupportedGroups() + { + return sslParameters.getUseNamedGroupsOrder(); + } + @Override protected boolean selectCipherSuite(int cipherSuite) throws IOException { @@ -334,12 +340,10 @@ protected boolean selectCipherSuite(int cipherSuite) throws IOException } } - boolean result = super.selectCipherSuite(cipherSuite); - if (result) - { - this.credentials = cipherSuiteCredentials; - } - return result; + this.selectedCipherSuite = cipherSuite; + this.credentials = cipherSuiteCredentials; + + return true; } @Override @@ -442,13 +446,13 @@ public boolean allowLegacyResumption() @Override public int getMaxCertificateChainLength() { - return JsseUtils.getMaxCertificateChainLength(); + return JsseUtils.getMaxInboundCertChainLenServer(); } @Override public int getMaxHandshakeMessageSize() { - return JsseUtils.getMaxHandshakeMessageSize(); + return manager.getContextData().getMaxHandshakeMessageSize(); } public synchronized boolean isHandshakeComplete() @@ -903,8 +907,8 @@ public synchronized void notifyHandshakeComplete() throws IOException // TODO[tls13] Resumption/PSK boolean addToCache = provServerEnableSessionResumption && !TlsUtils.isTLSv13(context); - this.sslSession = sslSessionContext.reportSession(peerHost, peerPort, connectionTlsSession, - jsseSessionParameters, addToCache); + this.sslSession = sslSessionContext.reportSession(manager.getBCHandshakeSessionImpl(), peerHost, peerPort, + connectionTlsSession, jsseSessionParameters, addToCache); } manager.notifyHandshakeComplete(new ProvSSLConnection(this)); @@ -1293,7 +1297,7 @@ protected TlsCredentials selectServerCredentialsLegacy(Principal[] issuers, int return JsseUtils.createCredentialedSigner(context, getCrypto(), x509Key, null); } - private void handleKeyManagerMisses(LinkedHashMap keyTypeMap, String selectedKeyType) + private void handleKeyManagerMisses(Map keyTypeMap, String selectedKeyType) { for (Map.Entry entry : keyTypeMap.entrySet()) { diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509KeyManager.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509KeyManager.java index 23ec3438aa..e8e2c45d36 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509KeyManager.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509KeyManager.java @@ -158,6 +158,23 @@ private static Map createFiltersClient() addFilter(filters, "Ed25519"); addFilter(filters, "Ed448"); + addFilter(filters, "ML-DSA-44"); + addFilter(filters, "ML-DSA-65"); + addFilter(filters, "ML-DSA-87"); + + addFilter(filters, "SLH-DSA-SHA2-128S"); + addFilter(filters, "SLH-DSA-SHA2-128F"); + addFilter(filters, "SLH-DSA-SHA2-192S"); + addFilter(filters, "SLH-DSA-SHA2-192F"); + addFilter(filters, "SLH-DSA-SHA2-256S"); + addFilter(filters, "SLH-DSA-SHA2-256F"); + addFilter(filters, "SLH-DSA-SHAKE-128S"); + addFilter(filters, "SLH-DSA-SHAKE-128F"); + addFilter(filters, "SLH-DSA-SHAKE-192S"); + addFilter(filters, "SLH-DSA-SHAKE-192F"); + addFilter(filters, "SLH-DSA-SHAKE-256S"); + addFilter(filters, "SLH-DSA-SHAKE-256F"); + addECFilter13(filters, NamedGroup.brainpoolP256r1tls13); addECFilter13(filters, NamedGroup.brainpoolP384r1tls13); addECFilter13(filters, NamedGroup.brainpoolP512r1tls13); @@ -183,6 +200,23 @@ private static Map createFiltersServer() addFilter(filters, "Ed25519"); addFilter(filters, "Ed448"); + addFilter(filters, "ML-DSA-44"); + addFilter(filters, "ML-DSA-65"); + addFilter(filters, "ML-DSA-87"); + + addFilter(filters, "SLH-DSA-SHA2-128S"); + addFilter(filters, "SLH-DSA-SHA2-128F"); + addFilter(filters, "SLH-DSA-SHA2-192S"); + addFilter(filters, "SLH-DSA-SHA2-192F"); + addFilter(filters, "SLH-DSA-SHA2-256S"); + addFilter(filters, "SLH-DSA-SHA2-256F"); + addFilter(filters, "SLH-DSA-SHAKE-128S"); + addFilter(filters, "SLH-DSA-SHAKE-128F"); + addFilter(filters, "SLH-DSA-SHAKE-192S"); + addFilter(filters, "SLH-DSA-SHAKE-192F"); + addFilter(filters, "SLH-DSA-SHAKE-256S"); + addFilter(filters, "SLH-DSA-SHAKE-256F"); + addECFilter13(filters, NamedGroup.brainpoolP256r1tls13); addECFilter13(filters, NamedGroup.brainpoolP384r1tls13); addECFilter13(filters, NamedGroup.brainpoolP512r1tls13); diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509TrustManager.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509TrustManager.java index 4e19c6452d..2c8246b4a5 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509TrustManager.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvX509TrustManager.java @@ -427,6 +427,13 @@ private static void checkEndpointID(X509Certificate certificate, String endpoint BCExtendedSSLSession sslSession) throws CertificateException { String peerHost = sslSession.getPeerHost(); + + /* + * A fully qualified domain name (FQDN) may contain a trailing dot. We remove it for the purpose of + * SNI and endpoint ID checks (e.g. SNIHostName doesn't permit it). + */ + peerHost = JsseUtils.stripTrailingDot(peerHost); + if (checkServerTrusted) { BCSNIHostName sniHostName = JsseUtils.getSNIHostName(sslSession.getRequestedServerNames()); @@ -449,7 +456,20 @@ private static void checkEndpointID(X509Certificate certificate, String endpoint } } - checkEndpointID(peerHost, certificate, endpointIDAlg); + try + { + checkEndpointID(peerHost, certificate, endpointIDAlg); + } + catch (CertificateException e) + { + // Special case for SunJSSE compatibility + if (!checkServerTrusted && "HTTPS".equalsIgnoreCase(endpointIDAlg)) + { + throw new CertificateException("Endpoint ID algorithm 'HTTPS' is not supported on the server side"); + } + + throw e; + } } private static X509CertSelector createTargetCertConstraints(final X509Certificate eeCert, diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/SignatureSchemeInfo.java b/tls/src/main/java/org/bouncycastle/jsse/provider/SignatureSchemeInfo.java index 08eea6bdde..21f52237e5 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/SignatureSchemeInfo.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/SignatureSchemeInfo.java @@ -43,8 +43,8 @@ class SignatureSchemeInfo // NOTE: Not all of these are necessarily enabled/supported; it will be checked at runtime private enum All { - ed25519(SignatureScheme.ed25519, "Ed25519", "Ed25519"), - ed448(SignatureScheme.ed448, "Ed448", "Ed448"), + ed25519(SignatureScheme.ed25519, "Ed25519", true), + ed448(SignatureScheme.ed448, "Ed448", true), ecdsa_secp256r1_sha256(SignatureScheme.ecdsa_secp256r1_sha256, "SHA256withECDSA", "EC"), ecdsa_secp384r1_sha384(SignatureScheme.ecdsa_secp384r1_sha384, "SHA384withECDSA", "EC"), @@ -64,13 +64,31 @@ private enum All rsa_pss_rsae_sha384(SignatureScheme.rsa_pss_rsae_sha384, "SHA384withRSAandMGF1", "RSA"), rsa_pss_rsae_sha512(SignatureScheme.rsa_pss_rsae_sha512, "SHA512withRSAandMGF1", "RSA"), + // NOTE: Not supported pre-13, but that is enforced by TLS protocol code rather than at the (BC)JSSE level. + mldsa44(SignatureScheme.mldsa44, "ML-DSA-44", false), + mldsa65(SignatureScheme.mldsa65, "ML-DSA-65", false), + mldsa87(SignatureScheme.mldsa87, "ML-DSA-87", false), + + slhdsa_sha2_128s(SignatureScheme.DRAFT_slhdsa_sha2_128s, "SLH-DSA-SHA2-128S", false), + slhdsa_sha2_128f(SignatureScheme.DRAFT_slhdsa_sha2_128f, "SLH-DSA-SHA2-128F", false), + slhdsa_sha2_192s(SignatureScheme.DRAFT_slhdsa_sha2_192s, "SLH-DSA-SHA2-192S", false), + slhdsa_sha2_192f(SignatureScheme.DRAFT_slhdsa_sha2_192f, "SLH-DSA-SHA2-192F", false), + slhdsa_sha2_256s(SignatureScheme.DRAFT_slhdsa_sha2_256s, "SLH-DSA-SHA2-256S", false), + slhdsa_sha2_256f(SignatureScheme.DRAFT_slhdsa_sha2_256f, "SLH-DSA-SHA2-256F", false), + slhdsa_shake_128s(SignatureScheme.DRAFT_slhdsa_shake_128s, "SLH-DSA-SHAKE-128S", false), + slhdsa_shake_128f(SignatureScheme.DRAFT_slhdsa_shake_128f, "SLH-DSA-SHAKE-128F", false), + slhdsa_shake_192s(SignatureScheme.DRAFT_slhdsa_shake_192s, "SLH-DSA-SHAKE-192S", false), + slhdsa_shake_192f(SignatureScheme.DRAFT_slhdsa_shake_192f, "SLH-DSA-SHAKE-192F", false), + slhdsa_shake_256s(SignatureScheme.DRAFT_slhdsa_shake_256s, "SLH-DSA-SHAKE-256S", false), + slhdsa_shake_256f(SignatureScheme.DRAFT_slhdsa_shake_256f, "SLH-DSA-SHAKE-256F", false), + + sm2sig_sm3(SignatureScheme.sm2sig_sm3, "SM3withSM2", "EC"), + // Deprecated: only for certs in 1.3 rsa_pkcs1_sha256(SignatureScheme.rsa_pkcs1_sha256, "SHA256withRSA", "RSA", true), rsa_pkcs1_sha384(SignatureScheme.rsa_pkcs1_sha384, "SHA384withRSA", "RSA", true), rsa_pkcs1_sha512(SignatureScheme.rsa_pkcs1_sha512, "SHA512withRSA", "RSA", true), - sm2sig_sm3(SignatureScheme.sm2sig_sm3, "SM3withSM2", "EC"), - /* * Legacy/Historical: mostly not supported in 1.3, except ecdsa_sha1 and rsa_pkcs1_sha1 are * still permitted as a last resort for certs. @@ -91,43 +109,48 @@ private enum All private final String jcaSignatureAlgorithmBC; private final String keyAlgorithm; private final String keyType13; - private final boolean supportedPost13; private final boolean supportedPre13; + private final boolean supportedPost13; private final boolean supportedCerts13; private final int namedGroup13; - private All(int signatureScheme, String jcaSignatureAlgorithm, String keyAlgorithm) + private All(int signatureScheme, String algorithm, boolean supportedPre13) { - this(signatureScheme, jcaSignatureAlgorithm, keyAlgorithm, true, true, + this(signatureScheme, algorithm, algorithm, supportedPre13, true, true, SignatureScheme.getNamedGroup(signatureScheme)); } - // Deprecated/Legacy - private All(int signatureScheme, String jcaSignatureAlgorithm, String keyAlgorithm, boolean supportedCerts13) + private All(int signatureScheme, String jcaSignatureAlgorithm, String keyAlgorithm) { - this(signatureScheme, jcaSignatureAlgorithm, keyAlgorithm, false, supportedCerts13, -1); + this(signatureScheme, jcaSignatureAlgorithm, keyAlgorithm, true, true, true, + SignatureScheme.getNamedGroup(signatureScheme)); } - private All(int signatureScheme, String jcaSignatureAlgorithm, String keyAlgorithm, boolean supportedPost13, - boolean supportedCerts13, int namedGroup13) + private All(int signatureScheme, String jcaSignatureAlgorithm, String keyAlgorithm, boolean supportedPre13, + boolean supportedPost13, boolean supportedCerts13, int namedGroup13) { this(signatureScheme, SignatureScheme.getName(signatureScheme), jcaSignatureAlgorithm, keyAlgorithm, - supportedPost13, supportedCerts13, namedGroup13); + supportedPre13, supportedPost13, supportedCerts13, namedGroup13); + } + + // Deprecated/Legacy + private All(int signatureScheme, String jcaSignatureAlgorithm, String keyAlgorithm, boolean supportedCerts13) + { + this(signatureScheme, jcaSignatureAlgorithm, keyAlgorithm, true, false, supportedCerts13, -1); } // Historical private All(int signatureScheme, String name, String jcaSignatureAlgorithm, String keyAlgorithm) { - this(signatureScheme, name, jcaSignatureAlgorithm, keyAlgorithm, false, false, -1); + this(signatureScheme, name, jcaSignatureAlgorithm, keyAlgorithm, true, false, false, -1); } private All(int signatureScheme, String name, String jcaSignatureAlgorithm, String keyAlgorithm, - boolean supportedPost13, boolean supportedCerts13, int namedGroup13) + boolean supportedPre13, boolean supportedPost13, boolean supportedCerts13, int namedGroup13) { String keyType13 = JsseUtils.getKeyType13(keyAlgorithm, namedGroup13); String jcaSignatureAlgorithmBC = JsseUtils.getJcaSignatureAlgorithmBC(jcaSignatureAlgorithm, keyAlgorithm); - this.signatureScheme = signatureScheme; this.name = name; this.text = name + "(0x" + Integer.toHexString(signatureScheme) + ")"; @@ -135,8 +158,9 @@ private All(int signatureScheme, String name, String jcaSignatureAlgorithm, Stri this.jcaSignatureAlgorithmBC = jcaSignatureAlgorithmBC; this.keyAlgorithm = keyAlgorithm; this.keyType13 = keyType13; + this.supportedPre13 = supportedPre13 && + (namedGroup13 < 0 || NamedGroup.canBeNegotiated(namedGroup13, ProtocolVersion.TLSv12)); this.supportedPost13 = supportedPost13; - this.supportedPre13 = (namedGroup13 < 0) || NamedGroup.canBeNegotiated(namedGroup13, ProtocolVersion.TLSv12); this.supportedCerts13 = supportedCerts13; this.namedGroup13 = namedGroup13; } @@ -566,10 +590,27 @@ private static int[] createCandidates(Map index, S private static int[] createCandidatesDefault() { All[] values = All.values(); - int[] result = new int[values.length]; - for (int i = 0; i < values.length; ++i) + int count = values.length, pos = 0; + int[] result = new int[count]; + for (int i = 0; i < count; ++i) + { + int signatureScheme = values[i].signatureScheme; + + if (SignatureScheme.isMLDSA(signatureScheme) || + SignatureScheme.isSLHDSA(signatureScheme)) + { + // For the time being, do not enable stand-alone PQ schemes by default + } + else + { + result[pos++] = signatureScheme; + } + } + if (pos < count) { - result[i] = values[i].signatureScheme; + int[] tmp = new int[pos]; + System.arraycopy(result, 0, tmp, 0, pos); + return tmp; } return result; } diff --git a/tls/src/main/java/org/bouncycastle/tls/AbstractTlsContext.java b/tls/src/main/java/org/bouncycastle/tls/AbstractTlsContext.java index 401579b2c2..7f19fa9875 100644 --- a/tls/src/main/java/org/bouncycastle/tls/AbstractTlsContext.java +++ b/tls/src/main/java/org/bouncycastle/tls/AbstractTlsContext.java @@ -16,7 +16,7 @@ abstract class AbstractTlsContext { private static long counter = Times.nanoTime(); - private synchronized static long nextCounterValue() + private static synchronized long nextCounterValue() { return ++counter; } diff --git a/tls/src/main/java/org/bouncycastle/tls/AbstractTlsServer.java b/tls/src/main/java/org/bouncycastle/tls/AbstractTlsServer.java index 1214988396..f6a8b27697 100644 --- a/tls/src/main/java/org/bouncycastle/tls/AbstractTlsServer.java +++ b/tls/src/main/java/org/bouncycastle/tls/AbstractTlsServer.java @@ -68,6 +68,8 @@ protected boolean allowTrustedCAIndication() } /** @deprecated Use 'serverExtensions' directly, it is now never null */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") protected Hashtable checkServerExtensions() { return serverExtensions; @@ -155,6 +157,11 @@ protected boolean preferLocalCipherSuites() return false; } + public boolean preferLocalSupportedGroups() + { + return false; + } + protected boolean selectCipherSuite(int cipherSuite) throws IOException { this.selectedCipherSuite = cipherSuite; diff --git a/tls/src/main/java/org/bouncycastle/tls/Certificate.java b/tls/src/main/java/org/bouncycastle/tls/Certificate.java index 2056b04a4f..43e4f02a41 100644 --- a/tls/src/main/java/org/bouncycastle/tls/Certificate.java +++ b/tls/src/main/java/org/bouncycastle/tls/Certificate.java @@ -245,6 +245,8 @@ public void encode(TlsContext context, OutputStream messageOutput, OutputStream * @throws IOException * @deprecated Use version taking a {@link ParseOptions} argument instead. */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public static Certificate parse(TlsContext context, InputStream messageInput, OutputStream endPointHashOutput) throws IOException { diff --git a/tls/src/main/java/org/bouncycastle/tls/CipherSuite.java b/tls/src/main/java/org/bouncycastle/tls/CipherSuite.java index 42b1e38de7..511d121d8b 100644 --- a/tls/src/main/java/org/bouncycastle/tls/CipherSuite.java +++ b/tls/src/main/java/org/bouncycastle/tls/CipherSuite.java @@ -451,6 +451,12 @@ public static boolean isSCSV(int cipherSuite) public static final int TLS_SM4_GCM_SM3 = 0x00C6; public static final int TLS_SM4_CCM_SM3 = 0x00C7; + /* + * RFC 9150 + */ + public static final int TLS_SHA256_SHA256 = 0xC0B4; + public static final int TLS_SHA384_SHA384 = 0xC0B5; + /* * RFC 9189 */ diff --git a/tls/src/main/java/org/bouncycastle/tls/ClientHello.java b/tls/src/main/java/org/bouncycastle/tls/ClientHello.java index 915cca31d1..21249baa78 100644 --- a/tls/src/main/java/org/bouncycastle/tls/ClientHello.java +++ b/tls/src/main/java/org/bouncycastle/tls/ClientHello.java @@ -44,6 +44,7 @@ public int[] getCipherSuites() /** * @deprecated Use {@link #getVersion()} instead. */ + @Deprecated public ProtocolVersion getClientVersion() { return version; diff --git a/tls/src/main/java/org/bouncycastle/tls/DTLSClientProtocol.java b/tls/src/main/java/org/bouncycastle/tls/DTLSClientProtocol.java index e3bce90b85..c12be15830 100644 --- a/tls/src/main/java/org/bouncycastle/tls/DTLSClientProtocol.java +++ b/tls/src/main/java/org/bouncycastle/tls/DTLSClientProtocol.java @@ -34,10 +34,6 @@ public DTLSTransport connect(TlsClient client, DatagramTransport transport) TlsClientContextImpl clientContext = new TlsClientContextImpl(client.getCrypto()); - ClientHandshakeState state = new ClientHandshakeState(); - state.client = client; - state.clientContext = clientContext; - client.init(clientContext); clientContext.handshakeBeginning(client); @@ -47,23 +43,34 @@ public DTLSTransport connect(TlsClient client, DatagramTransport transport) DTLSRecordLayer recordLayer = new DTLSRecordLayer(clientContext, client, transport); client.notifyCloseHandle(recordLayer); + ClientHandshakeState state = new ClientHandshakeState(); + state.client = client; + state.clientContext = clientContext; + state.recordLayer = recordLayer; + try { - return clientHandshake(state, recordLayer); + return clientHandshake(state); + } + catch (TlsFatalAlertReceived fatalAlertReceived) + { +// assert recordLayer.isFailed(); + invalidateSession(state); + throw fatalAlertReceived; } catch (TlsFatalAlert fatalAlert) { - abortClientHandshake(state, recordLayer, fatalAlert.getAlertDescription()); + abortClientHandshake(state, fatalAlert.getAlertDescription()); throw fatalAlert; } catch (IOException e) { - abortClientHandshake(state, recordLayer, AlertDescription.internal_error); + abortClientHandshake(state, AlertDescription.internal_error); throw e; } catch (RuntimeException e) { - abortClientHandshake(state, recordLayer, AlertDescription.internal_error); + abortClientHandshake(state, AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } finally @@ -72,17 +79,18 @@ public DTLSTransport connect(TlsClient client, DatagramTransport transport) } } - protected void abortClientHandshake(ClientHandshakeState state, DTLSRecordLayer recordLayer, short alertDescription) + protected void abortClientHandshake(ClientHandshakeState state, short alertDescription) { - recordLayer.fail(alertDescription); + state.recordLayer.fail(alertDescription); invalidateSession(state); } - protected DTLSTransport clientHandshake(ClientHandshakeState state, DTLSRecordLayer recordLayer) + protected DTLSTransport clientHandshake(ClientHandshakeState state) throws IOException { TlsClient client = state.client; TlsClientContextImpl clientContext = state.clientContext; + DTLSRecordLayer recordLayer = state.recordLayer; SecurityParameters securityParameters = clientContext.getSecurityParametersHandshake(); DTLSReliableHandshake handshake = new DTLSReliableHandshake(clientContext, recordLayer, @@ -144,7 +152,8 @@ protected DTLSTransport clientHandshake(ClientHandshakeState state, DTLSRecordLa handshake.finish(); - if (securityParameters.isExtendedMasterSecret()) + if (securityParameters.isExtendedMasterSecret() && + ProtocolVersion.DTLSv12.isEqualOrLaterVersionOf(securityParameters.getNegotiatedVersion())) { securityParameters.tlsUnique = securityParameters.getPeerVerifyData(); } @@ -263,6 +272,8 @@ protected DTLSTransport clientHandshake(ClientHandshakeState state, DTLSRecordLa securityParameters.getNegotiatedVersion(), clientAuthSigner); clientAuthStreamSigner = clientAuthSigner.getStreamSigner(); + TlsUtils.verify12SignatureAlgorithm(clientAuthAlgorithm, AlertDescription.internal_error); + if (ProtocolVersion.DTLSv12.equals(securityParameters.getNegotiatedVersion())) { TlsUtils.verifySupportedSignatureAlgorithm(securityParameters.getServerSigAlgs(), @@ -311,6 +322,8 @@ protected DTLSTransport clientHandshake(ClientHandshakeState state, DTLSRecordLa securityParameters.sessionHash = TlsUtils.getCurrentPRFHash(handshake.getHandshakeHash()); TlsProtocol.establishMasterSecret(clientContext, state.keyExchange); + state.keyExchange = null; + recordLayer.initPendingEpoch(TlsUtils.initCipher(clientContext)); if (clientAuthSigner != null) @@ -372,7 +385,10 @@ protected DTLSTransport clientHandshake(ClientHandshakeState state, DTLSRecordLa state.tlsSession = TlsUtils.importSession(securityParameters.getSessionID(), state.sessionParameters); - securityParameters.tlsUnique = securityParameters.getLocalVerifyData(); + if (ProtocolVersion.DTLSv12.isEqualOrLaterVersionOf(securityParameters.getNegotiatedVersion())) + { + securityParameters.tlsUnique = securityParameters.getLocalVerifyData(); + } clientContext.handshakeComplete(client, state.tlsSession); @@ -420,10 +436,11 @@ protected byte[] generateClientHello(ClientHandshakeState state) TlsSession sessionToResume = offeringDTLSv12Minus ? client.getSessionToResume() : null; - boolean fallback = client.isFallback(); - + // NOTE: Client is free to modify the cipher suites up until getSessionToResume state.offeredCipherSuites = client.getCipherSuites(); + boolean fallback = client.isFallback(); + state.clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(client.getClientExtensions()); final boolean shouldUseEMS = client.shouldUseExtendedMasterSecret(); @@ -517,19 +534,27 @@ protected byte[] generateClientHello(ClientHandshakeState state) state.clientExtensions.remove(TlsExtensionsUtils.EXT_extended_master_secret); } - // Cipher Suites (and SCSV) + // NOT renegotiating + if (offeringDTLSv12Minus) { /* - * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension, - * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the - * ClientHello. Including both is NOT RECOMMENDED. + * RFC 5746 3.4. Client Behavior: Initial Handshake (both full and session-resumption) + */ + + /* + * The client MUST include either an empty "renegotiation_info" extension, or the + * TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the ClientHello. + * Including both is NOT RECOMMENDED. */ - boolean noRenegExt = (null == TlsUtils.getExtensionData(state.clientExtensions, TlsProtocol.EXT_RenegotiationInfo)); - boolean noRenegSCSV = !Arrays.contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); + boolean noRenegExt = (null == TlsUtils.getExtensionData(state.clientExtensions, + TlsProtocol.EXT_RenegotiationInfo)); + boolean noRenegSCSV = !Arrays.contains(state.offeredCipherSuites, + CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); if (noRenegExt && noRenegSCSV) { - state.offeredCipherSuites = Arrays.append(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); + state.offeredCipherSuites = Arrays.append(state.offeredCipherSuites, + CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); } } @@ -724,7 +749,7 @@ protected void processServerCertificate(ClientHandshakeState state, byte[] body) throws IOException { state.authentication = TlsUtils.receiveServerCertificate(state.clientContext, state.client, - new ByteArrayInputStream(body), state.serverExtensions); + new ByteArrayInputStream(body)); } protected void processServerHello(ClientHandshakeState state, byte[] body) @@ -860,7 +885,8 @@ protected void processServerHello(ClientHandshakeState state, byte[] body) */ if (null == TlsUtils.getExtensionData(state.clientExtensions, extType)) { - throw new TlsFatalAlert(AlertDescription.unsupported_extension); + throw new TlsFatalAlert(AlertDescription.unsupported_extension, + "Unrequested extension in ServerHello: " + ExtensionType.getText(extType.intValue())); } /* @@ -1135,6 +1161,7 @@ protected static class ClientHandshakeState { TlsClient client = null; TlsClientContextImpl clientContext = null; + DTLSRecordLayer recordLayer = null; TlsSession tlsSession = null; SessionParameters sessionParameters = null; TlsSecret sessionMasterSecret = null; diff --git a/tls/src/main/java/org/bouncycastle/tls/DTLSRecordLayer.java b/tls/src/main/java/org/bouncycastle/tls/DTLSRecordLayer.java index abdcd29f35..06ec7f28c5 100644 --- a/tls/src/main/java/org/bouncycastle/tls/DTLSRecordLayer.java +++ b/tls/src/main/java/org/bouncycastle/tls/DTLSRecordLayer.java @@ -150,6 +150,11 @@ boolean isClosed() return closed; } + boolean isFailed() + { + return failed; + } + void resetAfterHelloVerifyRequestServer(long recordSeq) { this.inConnection = true; @@ -283,6 +288,9 @@ public int receive(byte[] buf, int off, int len, int waitMillis) return receive(buf, off, len, waitMillis, null); } + /** + * A waitMillis of zero is interpreted as an infinite timeout. + */ int receive(byte[] buf, int off, int len, int waitMillis, DTLSRecordCallback recordCallback) throws IOException { @@ -740,7 +748,7 @@ else if (null != retransmitEpoch && epoch == retransmitEpoch.getEpoch()) if (alertLevel == AlertLevel.fatal) { failed(); - throw new TlsFatalAlert(alertDescription); + throw new TlsFatalAlertReceived(alertDescription); } // TODO Can close_notify be a fatal alert? diff --git a/tls/src/main/java/org/bouncycastle/tls/DTLSReliableHandshake.java b/tls/src/main/java/org/bouncycastle/tls/DTLSReliableHandshake.java index 9d3fbb2034..503f588d7a 100644 --- a/tls/src/main/java/org/bouncycastle/tls/DTLSReliableHandshake.java +++ b/tls/src/main/java/org/bouncycastle/tls/DTLSReliableHandshake.java @@ -100,15 +100,17 @@ static void sendHelloVerifyRequest(DatagramSender sender, long recordSeq, byte[] DTLSReliableHandshake(TlsContext context, DTLSRecordLayer transport, int timeoutMillis, int initialResendMillis, DTLSRequest request) { + long currentTimeMillis = System.currentTimeMillis(); + this.recordLayer = transport; this.handshakeHash = new DeferredHash(context); - this.handshakeTimeout = Timeout.forWaitMillis(timeoutMillis); + this.handshakeTimeout = Timeout.forWaitMillis(timeoutMillis, currentTimeMillis); this.initialResendMillis = initialResendMillis; if (null != request) { resendMillis = initialResendMillis; - resendTimeout = new Timeout(resendMillis); + resendTimeout = new Timeout(resendMillis, currentTimeMillis); long recordSeq = request.getRecordSeq(); int messageSeq = request.getMessageSeq(); diff --git a/tls/src/main/java/org/bouncycastle/tls/DTLSServerProtocol.java b/tls/src/main/java/org/bouncycastle/tls/DTLSServerProtocol.java index bda746305b..fb58beaa15 100644 --- a/tls/src/main/java/org/bouncycastle/tls/DTLSServerProtocol.java +++ b/tls/src/main/java/org/bouncycastle/tls/DTLSServerProtocol.java @@ -50,10 +50,6 @@ public DTLSTransport accept(TlsServer server, DatagramTransport transport, DTLSR TlsServerContextImpl serverContext = new TlsServerContextImpl(server.getCrypto()); - ServerHandshakeState state = new ServerHandshakeState(); - state.server = server; - state.serverContext = serverContext; - server.init(serverContext); serverContext.handshakeBeginning(server); @@ -63,23 +59,34 @@ public DTLSTransport accept(TlsServer server, DatagramTransport transport, DTLSR DTLSRecordLayer recordLayer = new DTLSRecordLayer(serverContext, server, transport); server.notifyCloseHandle(recordLayer); + ServerHandshakeState state = new ServerHandshakeState(); + state.server = server; + state.serverContext = serverContext; + state.recordLayer = recordLayer; + try { - return serverHandshake(state, recordLayer, request); + return serverHandshake(state, request); + } + catch (TlsFatalAlertReceived fatalAlertReceived) + { +// assert recordLayer.isFailed(); + invalidateSession(state); + throw fatalAlertReceived; } catch (TlsFatalAlert fatalAlert) { - abortServerHandshake(state, recordLayer, fatalAlert.getAlertDescription()); + abortServerHandshake(state, fatalAlert.getAlertDescription()); throw fatalAlert; } catch (IOException e) { - abortServerHandshake(state, recordLayer, AlertDescription.internal_error); + abortServerHandshake(state, AlertDescription.internal_error); throw e; } catch (RuntimeException e) { - abortServerHandshake(state, recordLayer, AlertDescription.internal_error); + abortServerHandshake(state, AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } finally @@ -88,17 +95,17 @@ public DTLSTransport accept(TlsServer server, DatagramTransport transport, DTLSR } } - protected void abortServerHandshake(ServerHandshakeState state, DTLSRecordLayer recordLayer, short alertDescription) + protected void abortServerHandshake(ServerHandshakeState state, short alertDescription) { - recordLayer.fail(alertDescription); + state.recordLayer.fail(alertDescription); invalidateSession(state); } - protected DTLSTransport serverHandshake(ServerHandshakeState state, DTLSRecordLayer recordLayer, - DTLSRequest request) throws IOException + protected DTLSTransport serverHandshake(ServerHandshakeState state, DTLSRequest request) throws IOException { TlsServer server = state.server; TlsServerContextImpl serverContext = state.serverContext; + DTLSRecordLayer recordLayer = state.recordLayer; SecurityParameters securityParameters = serverContext.getSecurityParametersHandshake(); DTLSReliableHandshake handshake = new DTLSReliableHandshake(serverContext, recordLayer, @@ -110,9 +117,6 @@ protected DTLSTransport serverHandshake(ServerHandshakeState state, DTLSRecordLa { clientMessage = handshake.receiveMessage(); - // NOTE: DTLSRecordLayer requires any DTLS version, we don't otherwise constrain this -// ProtocolVersion recordLayerVersion = recordLayer.getReadVersion(); - if (clientMessage.getType() == HandshakeType.client_hello) { processClientHello(state, clientMessage.getBody()); @@ -132,14 +136,7 @@ protected DTLSTransport serverHandshake(ServerHandshakeState state, DTLSRecordLa } { - byte[] serverHelloBody = generateServerHello(state, recordLayer); - - // TODO[dtls13] Ideally, move this into generateServerHello once legacy_record_version clarified - { - ProtocolVersion recordLayerVersion = serverContext.getServerVersion(); - recordLayer.setReadVersion(recordLayerVersion); - recordLayer.setWriteVersion(recordLayerVersion); - } + byte[] serverHelloBody = generateServerHello(state); handshake.sendMessage(HandshakeType.server_hello, serverHelloBody); } @@ -164,7 +161,8 @@ protected DTLSTransport serverHandshake(ServerHandshakeState state, DTLSRecordLa handshake.finish(); - if (securityParameters.isExtendedMasterSecret()) + if (securityParameters.isExtendedMasterSecret() && + ProtocolVersion.DTLSv12.isEqualOrLaterVersionOf(securityParameters.getNegotiatedVersion())) { securityParameters.tlsUnique = securityParameters.getLocalVerifyData(); } @@ -190,11 +188,11 @@ protected DTLSTransport serverHandshake(ServerHandshakeState state, DTLSRecordLa state.keyExchange = TlsUtils.initKeyExchangeServer(serverContext, server); - state.serverCredentials = null; + TlsCredentials serverCredentials = null; if (!KeyExchangeAlgorithm.isAnonymous(securityParameters.getKeyExchangeAlgorithm())) { - state.serverCredentials = TlsUtils.establishServerCredentials(server); + serverCredentials = TlsUtils.establishServerCredentials(server); } // Server certificate @@ -202,15 +200,15 @@ protected DTLSTransport serverHandshake(ServerHandshakeState state, DTLSRecordLa Certificate serverCertificate = null; ByteArrayOutputStream endPointHash = new ByteArrayOutputStream(); - if (state.serverCredentials == null) + if (serverCredentials == null) { state.keyExchange.skipServerCredentials(); } else { - state.keyExchange.processServerCredentials(state.serverCredentials); + state.keyExchange.processServerCredentials(serverCredentials); - serverCertificate = state.serverCredentials.getCertificate(); + serverCertificate = serverCredentials.getCertificate(); sendCertificateMessage(serverContext, handshake, serverCertificate, endPointHash); } @@ -239,7 +237,7 @@ protected DTLSTransport serverHandshake(ServerHandshakeState state, DTLSRecordLa handshake.sendMessage(HandshakeType.server_key_exchange, serverKeyExchange); } - if (state.serverCredentials != null) + if (serverCredentials != null) { state.certificateRequest = server.getCertificateRequest(); @@ -347,6 +345,8 @@ protected DTLSTransport serverHandshake(ServerHandshakeState state, DTLSRecordLa securityParameters.sessionHash = TlsUtils.getCurrentPRFHash(handshake.getHandshakeHash()); TlsProtocol.establishMasterSecret(serverContext, state.keyExchange); + state.keyExchange = null; + recordLayer.initPendingEpoch(TlsUtils.initCipher(serverContext)); /* @@ -412,7 +412,10 @@ protected DTLSTransport serverHandshake(ServerHandshakeState state, DTLSRecordLa state.tlsSession = TlsUtils.importSession(securityParameters.getSessionID(), state.sessionParameters); - securityParameters.tlsUnique = securityParameters.getPeerVerifyData(); + if (ProtocolVersion.DTLSv12.isEqualOrLaterVersionOf(securityParameters.getNegotiatedVersion())) + { + securityParameters.tlsUnique = securityParameters.getPeerVerifyData(); + } serverContext.handshakeComplete(server, state.tlsSession); @@ -446,15 +449,13 @@ protected byte[] generateNewSessionTicket(ServerHandshakeState state, NewSession return buf.toByteArray(); } - protected byte[] generateServerHello(ServerHandshakeState state, DTLSRecordLayer recordLayer) + protected byte[] generateServerHello(ServerHandshakeState state) throws IOException { TlsServer server = state.server; TlsServerContextImpl serverContext = state.serverContext; SecurityParameters securityParameters = serverContext.getSecurityParametersHandshake(); - // TODO[dtls13] Negotiate cipher suite first? - ProtocolVersion serverVersion; // NOT renegotiating @@ -470,7 +471,7 @@ protected byte[] generateServerHello(ServerHandshakeState state, DTLSRecordLayer // ? ProtocolVersion.DTLSv12 // : server_version; // -// recordLayer.setWriteVersion(legacy_record_version); +// state.recordLayer.setWriteVersion(legacy_record_version); securityParameters.negotiatedVersion = serverVersion; } @@ -478,14 +479,16 @@ protected byte[] generateServerHello(ServerHandshakeState state, DTLSRecordLayer // if (ProtocolVersion.DTLSv13.isEqualOrEarlierVersionOf(serverVersion)) // { // // See RFC 8446 D.4. -// recordStream.setIgnoreChangeCipherSpec(true); +// state.recordLayer.setIgnoreChangeCipherSpec(true); // -// recordStream.setWriteVersion(ProtocolVersion.DTLSv12); +// state.recordLayer.setReadVersion(ProtocolVersion.DTLSv12); +// state.recordLayer.setWriteVersion(ProtocolVersion.DTLSv12); // // return generate13ServerHello(clientHello, clientHelloMessage, false); // } -// -// recordStream.setWriteVersion(serverVersion); + + state.recordLayer.setReadVersion(serverVersion); + state.recordLayer.setWriteVersion(serverVersion); { boolean useGMTUnixTime = server.shouldUseGMTUnixTime(); @@ -704,7 +707,7 @@ else if (TlsUtils.hasExpectedEmptyExtensionData(state.serverExtensions, state.clientHello = null; - applyMaxFragmentLengthExtension(recordLayer, securityParameters.getMaxFragmentLength()); + applyMaxFragmentLengthExtension(state.recordLayer, securityParameters.getMaxFragmentLength()); ByteArrayOutputStream buf = new ByteArrayOutputStream(); serverHello.encode(serverContext, buf); @@ -838,6 +841,8 @@ protected void processClientHello(ServerHandshakeState state, byte[] body) protected void processClientHello(ServerHandshakeState state, ClientHello clientHello) throws IOException { + state.recordLayer.setWriteVersion(ProtocolVersion.DTLSv10); + state.clientHello = clientHello; // TODO Read RFCs for guidance on the expected record layer version number @@ -1014,6 +1019,7 @@ protected static class ServerHandshakeState { TlsServer server = null; TlsServerContextImpl serverContext = null; + DTLSRecordLayer recordLayer = null; TlsSession tlsSession = null; SessionParameters sessionParameters = null; TlsSecret sessionMasterSecret = null; @@ -1022,7 +1028,6 @@ protected static class ServerHandshakeState Hashtable serverExtensions = null; boolean expectSessionTicket = false; TlsKeyExchange keyExchange = null; - TlsCredentials serverCredentials = null; CertificateRequest certificateRequest = null; TlsHeartbeat heartbeat = null; short heartbeatPolicy = HeartbeatMode.peer_not_allowed_to_send; diff --git a/tls/src/main/java/org/bouncycastle/tls/DTLSTransport.java b/tls/src/main/java/org/bouncycastle/tls/DTLSTransport.java index bd51764b04..448cd92ebc 100644 --- a/tls/src/main/java/org/bouncycastle/tls/DTLSTransport.java +++ b/tls/src/main/java/org/bouncycastle/tls/DTLSTransport.java @@ -31,6 +31,9 @@ public int receive(byte[] buf, int off, int len, int waitMillis) return receive(buf, off, len, waitMillis, null); } + /** + * A waitMillis of zero is interpreted as an infinite timeout. + */ public int receive(byte[] buf, int off, int len, int waitMillis, DTLSRecordCallback recordCallback) throws IOException { @@ -55,6 +58,11 @@ public int receive(byte[] buf, int off, int len, int waitMillis, DTLSRecordCallb { return recordLayer.receive(buf, off, len, waitMillis, recordCallback); } + catch (TlsFatalAlertReceived fatalAlertReceived) + { +// assert recordLayer.isFailed(); + throw fatalAlertReceived; + } catch (TlsFatalAlert fatalAlert) { if (AlertDescription.bad_record_mac == fatalAlert.getAlertDescription()) @@ -107,6 +115,11 @@ public int receivePending(byte[] buf, int off, int len, DTLSRecordCallback recor { return recordLayer.receivePending(buf, off, len, recordCallback); } + catch (TlsFatalAlertReceived fatalAlertReceived) + { +// assert recordLayer.isFailed(); + throw fatalAlertReceived; + } catch (TlsFatalAlert fatalAlert) { if (AlertDescription.bad_record_mac == fatalAlert.getAlertDescription()) diff --git a/tls/src/main/java/org/bouncycastle/tls/DatagramReceiver.java b/tls/src/main/java/org/bouncycastle/tls/DatagramReceiver.java index b20bbe502f..2c131330d6 100644 --- a/tls/src/main/java/org/bouncycastle/tls/DatagramReceiver.java +++ b/tls/src/main/java/org/bouncycastle/tls/DatagramReceiver.java @@ -6,5 +6,8 @@ public interface DatagramReceiver { int getReceiveLimit() throws IOException; + /** + * A waitMillis of zero is interpreted as an infinite timeout. + */ int receive(byte[] buf, int off, int len, int waitMillis) throws IOException; } diff --git a/tls/src/main/java/org/bouncycastle/tls/EncryptionAlgorithm.java b/tls/src/main/java/org/bouncycastle/tls/EncryptionAlgorithm.java index a1e44979ab..2ace85fc12 100644 --- a/tls/src/main/java/org/bouncycastle/tls/EncryptionAlgorithm.java +++ b/tls/src/main/java/org/bouncycastle/tls/EncryptionAlgorithm.java @@ -84,4 +84,10 @@ public class EncryptionAlgorithm public static final int KUZNYECHIK_CTR_OMAC = 29; public static final int MAGMA_CTR_OMAC = 30; public static final int _28147_CNT_IMIT = 31; + + /* + * RFC 9150 + */ + public static final int NULL_HMAC_SHA256 = 32; + public static final int NULL_HMAC_SHA384 = 33; } diff --git a/tls/src/main/java/org/bouncycastle/tls/HandshakeType.java b/tls/src/main/java/org/bouncycastle/tls/HandshakeType.java index b87f24c9ce..8901144bf7 100644 --- a/tls/src/main/java/org/bouncycastle/tls/HandshakeType.java +++ b/tls/src/main/java/org/bouncycastle/tls/HandshakeType.java @@ -42,11 +42,27 @@ public class HandshakeType public static final short key_update = 24; public static final short message_hash = 254; + /* + * RFC 8870 + */ + public static final short ekt_key = 26; + /* * RFC 8879 */ public static final short compressed_certificate = 25; + /* + * RFC 9147 + */ + public static final short request_connection_id = 9; + public static final short new_connection_id = 10; + + /* + * RFC 9261 + */ + public static final short client_certificate_request = 17; + public static String getName(short handshakeType) { switch (handshakeType) @@ -91,8 +107,16 @@ public static String getName(short handshakeType) return "key_update"; case message_hash: return "message_hash"; + case ekt_key: + return "ekt_key"; case compressed_certificate: return "compressed_certificate"; + case request_connection_id: + return "request_connection_id"; + case new_connection_id: + return "new_connection_id"; + case client_certificate_request: + return "client_certificate_request"; default: return "UNKNOWN"; } @@ -127,7 +151,11 @@ public static boolean isRecognized(short handshakeType) case encrypted_extensions: case key_update: case message_hash: + case ekt_key: case compressed_certificate: + case request_connection_id: + case new_connection_id: + case client_certificate_request: return true; default: return false; diff --git a/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java b/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java index b8fc46d1c5..39926abdd6 100644 --- a/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java +++ b/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java @@ -103,18 +103,33 @@ public class NamedGroup public static final int arbitrary_explicit_char2_curves = 0xFF02; /** @deprecated Experimental API (unstable): unofficial value from Open Quantum Safe project. */ + @Deprecated public static final int OQS_mlkem512 = 0x0247; /** @deprecated Experimental API (unstable): unofficial value from Open Quantum Safe project. */ + @Deprecated public static final int OQS_mlkem768 = 0x0248; /** @deprecated Experimental API (unstable): unofficial value from Open Quantum Safe project. */ + @Deprecated public static final int OQS_mlkem1024 = 0x0249; /* - * draft-connolly-tls-mlkem-key-agreement-03 + * draft-connolly-tls-mlkem-key-agreement-05 */ - public static final int MLKEM512 = 0x0512; - public static final int MLKEM768 = 0x0768; - public static final int MLKEM1024 = 0x1024; + public static final int MLKEM512 = 0x0200; + public static final int MLKEM768 = 0x0201; + public static final int MLKEM1024 = 0x0202; + + /* + * draft-ietf-tls-ecdhe-mlkem-00 + */ + public static final int SecP256r1MLKEM768 = 0x11EB; + public static final int X25519MLKEM768 = 0x11EC; + public static final int SecP384r1MLKEM1024 = 0x11ED; + + /* + * draft-yang-tls-hybrid-sm2-mlkem-03 + */ + public static final int curveSM2MLKEM768 = 0x11EE; /* Names of the actual underlying elliptic curves (not necessarily matching the NamedGroup names). */ private static final String[] CURVE_NAMES = new String[]{ "sect163k1", "sect163r1", "sect163r2", "sect193r1", @@ -163,7 +178,7 @@ public static boolean canBeNegotiated(int namedGroup, ProtocolVersion version) } } - if (refersToASpecificKem(namedGroup)) + if (refersToASpecificHybrid(namedGroup) || refersToASpecificKem(namedGroup)) { return isTLSv13; } @@ -297,6 +312,72 @@ public static String getFiniteFieldName(int namedGroup) return null; } + public static int getHybridFirst(int namedGroup) + { + switch (namedGroup) + { + case SecP256r1MLKEM768: + return secp256r1; + case X25519MLKEM768: + return MLKEM768; + case SecP384r1MLKEM1024: + return secp384r1; + case curveSM2MLKEM768: + return curveSM2; + default: + return -1; + } + } + + public static int getHybridSecond(int namedGroup) + { + switch (namedGroup) + { + case SecP256r1MLKEM768: + return MLKEM768; + case X25519MLKEM768: + return x25519; + case SecP384r1MLKEM1024: + return MLKEM1024; + case curveSM2MLKEM768: + return MLKEM768; + default: + return -1; + } + } + + // TODO Temporary until crypto implementations become more self-documenting around lengths + static int getHybridSplitClientShare(int namedGroup) + { + switch (namedGroup) + { + case curveSM2: + case secp256r1: + return 65; + case secp384r1: + return 97; + case MLKEM768: + return 1184; + } + return -1; + } + + // TODO Temporary until crypto implementations become more self-documenting around lengths + static int getHybridSplitServerShare(int namedGroup) + { + switch (namedGroup) + { + case curveSM2: + case secp256r1: + return 65; + case secp384r1: + return 97; + case MLKEM768: + return 1088; + } + return -1; + } + public static String getKemName(int namedGroup) { switch (namedGroup) @@ -382,6 +463,14 @@ public static String getName(int namedGroup) return "MLKEM768"; case MLKEM1024: return "MLKEM1024"; + case SecP256r1MLKEM768: + return "SecP256r1MLKEM768"; + case X25519MLKEM768: + return "X25519MLKEM768"; + case SecP384r1MLKEM1024: + return "SecP384r1MLKEM1024"; + case curveSM2MLKEM768: + return "curveSM2MLKEM768"; case arbitrary_explicit_prime_curves: return "arbitrary_explicit_prime_curves"; case arbitrary_explicit_char2_curves: @@ -489,9 +578,24 @@ public static boolean refersToASpecificGroup(int namedGroup) { return refersToASpecificCurve(namedGroup) || refersToASpecificFiniteField(namedGroup) + || refersToASpecificHybrid(namedGroup) || refersToASpecificKem(namedGroup); } + public static boolean refersToASpecificHybrid(int namedGroup) + { + switch (namedGroup) + { + case SecP256r1MLKEM768: + case X25519MLKEM768: + case SecP384r1MLKEM1024: + case curveSM2MLKEM768: + return true; + default: + return false; + } + } + public static boolean refersToASpecificKem(int namedGroup) { switch (namedGroup) diff --git a/tls/src/main/java/org/bouncycastle/tls/PskKeyExchangeMode.java b/tls/src/main/java/org/bouncycastle/tls/PskKeyExchangeMode.java index d4d648df2e..f8f90d6f93 100644 --- a/tls/src/main/java/org/bouncycastle/tls/PskKeyExchangeMode.java +++ b/tls/src/main/java/org/bouncycastle/tls/PskKeyExchangeMode.java @@ -26,4 +26,16 @@ public static String getText(short pskKeyExchangeMode) { return getName(pskKeyExchangeMode) + "(" + pskKeyExchangeMode + ")"; } + + public static boolean isRecognized(short pskKeyExchangeMode) + { + switch (pskKeyExchangeMode) + { + case psk_ke: + case psk_dhe_ke: + return true; + default: + return false; + } + } } diff --git a/tls/src/main/java/org/bouncycastle/tls/RecordPreview.java b/tls/src/main/java/org/bouncycastle/tls/RecordPreview.java index fc5900ae08..84a7a5906b 100644 --- a/tls/src/main/java/org/bouncycastle/tls/RecordPreview.java +++ b/tls/src/main/java/org/bouncycastle/tls/RecordPreview.java @@ -22,6 +22,7 @@ static RecordPreview extendRecordSize(RecordPreview a, int recordSize) } /** @deprecated Use {@link #getContentLimit} instead */ + @Deprecated public int getApplicationDataLimit() { return contentLimit; diff --git a/tls/src/main/java/org/bouncycastle/tls/SRTPProtectionProfile.java b/tls/src/main/java/org/bouncycastle/tls/SRTPProtectionProfile.java index da20248824..1b8bc019b0 100644 --- a/tls/src/main/java/org/bouncycastle/tls/SRTPProtectionProfile.java +++ b/tls/src/main/java/org/bouncycastle/tls/SRTPProtectionProfile.java @@ -7,6 +7,16 @@ public class SRTPProtectionProfile */ public static final int SRTP_AES128_CM_HMAC_SHA1_80 = 0x0001; public static final int SRTP_AES128_CM_HMAC_SHA1_32 = 0x0002; + + /** + * Removed by draft-ietf-avt-dtls-srtp-04. IANA: Unassigned. + */ + public static final int DRAFT_SRTP_AES256_CM_SHA1_80 = 0x0003; + /** + * Removed by draft-ietf-avt-dtls-srtp-04. IANA: Unassigned. + */ + public static final int DRAFT_SRTP_AES256_CM_SHA1_32 = 0x0004; + public static final int SRTP_NULL_HMAC_SHA1_80 = 0x0005; public static final int SRTP_NULL_HMAC_SHA1_32 = 0x0006; @@ -15,4 +25,20 @@ public class SRTPProtectionProfile */ public static final int SRTP_AEAD_AES_128_GCM = 0x0007; public static final int SRTP_AEAD_AES_256_GCM = 0x0008; + + /* + * RFC 8723 10.1. + */ + public static final int DOUBLE_AEAD_AES_128_GCM_AEAD_AES_128_GCM = 0x0009; + public static final int DOUBLE_AEAD_AES_256_GCM_AEAD_AES_256_GCM = 0x000A; + + /* + * RFC 8269 6.1. + */ + public static final int SRTP_ARIA_128_CTR_HMAC_SHA1_80 = 0x000B; + public static final int SRTP_ARIA_128_CTR_HMAC_SHA1_32 = 0x000C; + public static final int SRTP_ARIA_256_CTR_HMAC_SHA1_80 = 0x000D; + public static final int SRTP_ARIA_256_CTR_HMAC_SHA1_32 = 0x000E; + public static final int SRTP_AEAD_ARIA_128_GCM = 0x000F; + public static final int SRTP_AEAD_ARIA_256_GCM = 0x0010; } diff --git a/tls/src/main/java/org/bouncycastle/tls/SecurityParameters.java b/tls/src/main/java/org/bouncycastle/tls/SecurityParameters.java index 3a933d2858..cfd27c49f0 100644 --- a/tls/src/main/java/org/bouncycastle/tls/SecurityParameters.java +++ b/tls/src/main/java/org/bouncycastle/tls/SecurityParameters.java @@ -55,6 +55,7 @@ public class SecurityParameters Certificate localCertificate = null; Certificate peerCertificate = null; ProtocolVersion negotiatedVersion = null; + int negotiatedGroup = -1; int statusRequestVersion = 0; short clientCertificateType = CertificateType.X509; short serverCertificateType = CertificateType.X509; @@ -177,6 +178,8 @@ public int[] getServerSupportedGroups() * * @deprecated Will be removed. Use constant CompressionMethod._null instead. */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public short getCompressionAlgorithm() { return CompressionMethod._null; @@ -193,6 +196,7 @@ public short getMaxFragmentLength() /** * @deprecated Use {@link #getPRFAlgorithm()} instead. */ + @Deprecated public int getPrfAlgorithm() { return prfAlgorithm; @@ -369,6 +373,17 @@ public ProtocolVersion getNegotiatedVersion() return negotiatedVersion; } + /** + * The named group selected by the server for key exchange (if any), or -1 when not negotiated. + *
          + * See {@link NamedGroup} for group constants. Currently not set (i.e. -1) when pre-1.3 version negotiated. Not all + * TLS 1.3 key exchanges negotiate a group (e.g. PskKeyExchangeMode.psk_ke). + */ + public int getNegotiatedGroup() + { + return negotiatedGroup; + } + public int getStatusRequestVersion() { return statusRequestVersion; diff --git a/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java b/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java index f4b8e0d5af..fc1071ccf0 100644 --- a/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java +++ b/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java @@ -15,14 +15,15 @@ public class SignatureAndHashAlgorithm create(SignatureScheme.ecdsa_brainpoolP384r1tls13_sha384); public static final SignatureAndHashAlgorithm ecdsa_brainpoolP512r1tls13_sha512 = create(SignatureScheme.ecdsa_brainpoolP512r1tls13_sha512); - public static final SignatureAndHashAlgorithm ed25519 = - create(SignatureScheme.ed25519); - public static final SignatureAndHashAlgorithm ed448 = - create(SignatureScheme.ed448); + public static final SignatureAndHashAlgorithm ed25519 = create(SignatureScheme.ed25519); + public static final SignatureAndHashAlgorithm ed448 = create(SignatureScheme.ed448); public static final SignatureAndHashAlgorithm gostr34102012_256 = create(HashAlgorithm.Intrinsic, SignatureAlgorithm.gostr34102012_256); public static final SignatureAndHashAlgorithm gostr34102012_512 = create(HashAlgorithm.Intrinsic, SignatureAlgorithm.gostr34102012_512); + public static final SignatureAndHashAlgorithm mldsa44 = create(SignatureScheme.mldsa44); + public static final SignatureAndHashAlgorithm mldsa65 = create(SignatureScheme.mldsa65); + public static final SignatureAndHashAlgorithm mldsa87 = create(SignatureScheme.mldsa87); public static final SignatureAndHashAlgorithm rsa_pss_rsae_sha256 = create(SignatureScheme.rsa_pss_rsae_sha256); public static final SignatureAndHashAlgorithm rsa_pss_rsae_sha384 = @@ -35,6 +36,18 @@ public class SignatureAndHashAlgorithm create(SignatureScheme.rsa_pss_pss_sha384); public static final SignatureAndHashAlgorithm rsa_pss_pss_sha512 = create(SignatureScheme.rsa_pss_pss_sha512); + public static final SignatureAndHashAlgorithm slhdsa_sha2_128s = create(SignatureScheme.DRAFT_slhdsa_sha2_128s); + public static final SignatureAndHashAlgorithm slhdsa_sha2_128f = create(SignatureScheme.DRAFT_slhdsa_sha2_128f); + public static final SignatureAndHashAlgorithm slhdsa_sha2_192s = create(SignatureScheme.DRAFT_slhdsa_sha2_192s); + public static final SignatureAndHashAlgorithm slhdsa_sha2_192f = create(SignatureScheme.DRAFT_slhdsa_sha2_192f); + public static final SignatureAndHashAlgorithm slhdsa_sha2_256s = create(SignatureScheme.DRAFT_slhdsa_sha2_256s); + public static final SignatureAndHashAlgorithm slhdsa_sha2_256f = create(SignatureScheme.DRAFT_slhdsa_sha2_256f); + public static final SignatureAndHashAlgorithm slhdsa_shake_128s = create(SignatureScheme.DRAFT_slhdsa_shake_128s); + public static final SignatureAndHashAlgorithm slhdsa_shake_128f = create(SignatureScheme.DRAFT_slhdsa_shake_128f); + public static final SignatureAndHashAlgorithm slhdsa_shake_192s = create(SignatureScheme.DRAFT_slhdsa_shake_192s); + public static final SignatureAndHashAlgorithm slhdsa_shake_192f = create(SignatureScheme.DRAFT_slhdsa_shake_192f); + public static final SignatureAndHashAlgorithm slhdsa_shake_256s = create(SignatureScheme.DRAFT_slhdsa_shake_256s); + public static final SignatureAndHashAlgorithm slhdsa_shake_256f = create(SignatureScheme.DRAFT_slhdsa_shake_256f); public static SignatureAndHashAlgorithm getInstance(short hashAlgorithm, short signatureAlgorithm) { diff --git a/tls/src/main/java/org/bouncycastle/tls/SignatureScheme.java b/tls/src/main/java/org/bouncycastle/tls/SignatureScheme.java index 2a980300fc..015a75afa8 100644 --- a/tls/src/main/java/org/bouncycastle/tls/SignatureScheme.java +++ b/tls/src/main/java/org/bouncycastle/tls/SignatureScheme.java @@ -45,6 +45,36 @@ public class SignatureScheme public static final int sm2sig_sm3 = 0x0708; + /* + * draft-ietf-tls-mldsa-00 + */ + public static final int mldsa44 = 0x0904; + public static final int mldsa65 = 0x0905; + public static final int mldsa87 = 0x0906; + + /** @deprecated Use 'mldsa44' instead. */ + public static final int DRAFT_mldsa44 = mldsa44; + /** @deprecated Use 'mldsa65' instead. */ + public static final int DRAFT_mldsa65 = mldsa65; + /** @deprecated Use 'mldsa87' instead. */ + public static final int DRAFT_mldsa87 = mldsa87; + + /* + * draft-reddy-tls-slhdsa-01 + */ + public static final int DRAFT_slhdsa_sha2_128s = 0x0911; + public static final int DRAFT_slhdsa_sha2_128f = 0x0912; + public static final int DRAFT_slhdsa_sha2_192s = 0x0913; + public static final int DRAFT_slhdsa_sha2_192f = 0x0914; + public static final int DRAFT_slhdsa_sha2_256s = 0x0915; + public static final int DRAFT_slhdsa_sha2_256f = 0x0916; + public static final int DRAFT_slhdsa_shake_128s = 0x0917; + public static final int DRAFT_slhdsa_shake_128f = 0x0918; + public static final int DRAFT_slhdsa_shake_192s = 0x0919; + public static final int DRAFT_slhdsa_shake_192f = 0x091A; + public static final int DRAFT_slhdsa_shake_256s = 0x091B; + public static final int DRAFT_slhdsa_shake_256f = 0x091C; + /* * RFC 8446 reserved for private use (0xFE00..0xFFFF) */ @@ -70,6 +100,21 @@ public static int getCryptoHashAlgorithm(int signatureScheme) { case ed25519: case ed448: + case mldsa44: + case mldsa65: + case mldsa87: + case DRAFT_slhdsa_sha2_128s: + case DRAFT_slhdsa_sha2_128f: + case DRAFT_slhdsa_sha2_192s: + case DRAFT_slhdsa_sha2_192f: + case DRAFT_slhdsa_sha2_256s: + case DRAFT_slhdsa_sha2_256f: + case DRAFT_slhdsa_shake_128s: + case DRAFT_slhdsa_shake_128f: + case DRAFT_slhdsa_shake_192s: + case DRAFT_slhdsa_shake_192f: + case DRAFT_slhdsa_shake_256s: + case DRAFT_slhdsa_shake_256f: return -1; case ecdsa_brainpoolP256r1tls13_sha256: case rsa_pss_pss_sha256: @@ -146,6 +191,36 @@ public static String getName(int signatureScheme) return "ecdsa_brainpoolP512r1tls13_sha512"; case sm2sig_sm3: return "sm2sig_sm3"; + case mldsa44: + return "mldsa44"; + case mldsa65: + return "mldsa65"; + case mldsa87: + return "mldsa87"; + case DRAFT_slhdsa_sha2_128s: + return "slhdsa_sha2_128s"; + case DRAFT_slhdsa_sha2_128f: + return "slhdsa_sha2_128f"; + case DRAFT_slhdsa_sha2_192s: + return "slhdsa_sha2_192s"; + case DRAFT_slhdsa_sha2_192f: + return "slhdsa_sha2_192f"; + case DRAFT_slhdsa_sha2_256s: + return "slhdsa_sha2_256s"; + case DRAFT_slhdsa_sha2_256f: + return "slhdsa_sha2_256f"; + case DRAFT_slhdsa_shake_128s: + return "slhdsa_shake_128s"; + case DRAFT_slhdsa_shake_128f: + return "slhdsa_shake_128f"; + case DRAFT_slhdsa_shake_192s: + return "slhdsa_shake_192s"; + case DRAFT_slhdsa_shake_192f: + return "slhdsa_shake_192f"; + case DRAFT_slhdsa_shake_256s: + return "slhdsa_shake_256s"; + case DRAFT_slhdsa_shake_256f: + return "slhdsa_shake_256f"; default: return "UNKNOWN"; } @@ -179,6 +254,7 @@ public static int getNamedGroup(int signatureScheme) } /** @deprecated Use {@link #getCryptoHashAlgorithm(int)} instead. */ + @Deprecated public static int getRSAPSSCryptoHashAlgorithm(int signatureScheme) { switch (signatureScheme) @@ -210,9 +286,47 @@ public static short getSignatureAlgorithm(int signatureScheme) public static SignatureAndHashAlgorithm getSignatureAndHashAlgorithm(int signatureScheme) { - return SignatureAndHashAlgorithm.getInstance( - getHashAlgorithm(signatureScheme), - getSignatureAlgorithm(signatureScheme)); + switch (signatureScheme) + { + case ed25519: + return SignatureAndHashAlgorithm.ed25519; + case ed448: + return SignatureAndHashAlgorithm.ed448; + case mldsa44: + return SignatureAndHashAlgorithm.mldsa44; + case mldsa65: + return SignatureAndHashAlgorithm.mldsa65; + case mldsa87: + return SignatureAndHashAlgorithm.mldsa87; + case DRAFT_slhdsa_sha2_128s: + return SignatureAndHashAlgorithm.slhdsa_sha2_128s; + case DRAFT_slhdsa_sha2_128f: + return SignatureAndHashAlgorithm.slhdsa_sha2_128f; + case DRAFT_slhdsa_sha2_192s: + return SignatureAndHashAlgorithm.slhdsa_sha2_192s; + case DRAFT_slhdsa_sha2_192f: + return SignatureAndHashAlgorithm.slhdsa_sha2_192f; + case DRAFT_slhdsa_sha2_256s: + return SignatureAndHashAlgorithm.slhdsa_sha2_256s; + case DRAFT_slhdsa_sha2_256f: + return SignatureAndHashAlgorithm.slhdsa_sha2_256f; + case DRAFT_slhdsa_shake_128s: + return SignatureAndHashAlgorithm.slhdsa_shake_128s; + case DRAFT_slhdsa_shake_128f: + return SignatureAndHashAlgorithm.slhdsa_shake_128f; + case DRAFT_slhdsa_shake_192s: + return SignatureAndHashAlgorithm.slhdsa_shake_192s; + case DRAFT_slhdsa_shake_192f: + return SignatureAndHashAlgorithm.slhdsa_shake_192f; + case DRAFT_slhdsa_shake_256s: + return SignatureAndHashAlgorithm.slhdsa_shake_256s; + case DRAFT_slhdsa_shake_256f: + return SignatureAndHashAlgorithm.slhdsa_shake_256f; + default: + return SignatureAndHashAlgorithm.getInstance( + getHashAlgorithm(signatureScheme), + getSignatureAlgorithm(signatureScheme)); + } } public static String getText(int signatureScheme) @@ -238,6 +352,19 @@ public static boolean isECDSA(int signatureScheme) } } + public static boolean isMLDSA(int signatureScheme) + { + switch (signatureScheme) + { + case mldsa44: + case mldsa65: + case mldsa87: + return true; + default: + return false; + } + } + public static boolean isRSAPSS(int signatureScheme) { switch (signatureScheme) @@ -253,4 +380,26 @@ public static boolean isRSAPSS(int signatureScheme) return false; } } + + public static boolean isSLHDSA(int signatureScheme) + { + switch (signatureScheme) + { + case DRAFT_slhdsa_sha2_128s: + case DRAFT_slhdsa_sha2_128f: + case DRAFT_slhdsa_sha2_192s: + case DRAFT_slhdsa_sha2_192f: + case DRAFT_slhdsa_sha2_256s: + case DRAFT_slhdsa_sha2_256f: + case DRAFT_slhdsa_shake_128s: + case DRAFT_slhdsa_shake_128f: + case DRAFT_slhdsa_shake_192s: + case DRAFT_slhdsa_shake_192f: + case DRAFT_slhdsa_shake_256s: + case DRAFT_slhdsa_shake_256f: + return true; + default: + return false; + } + } } diff --git a/tls/src/main/java/org/bouncycastle/tls/Timeout.java b/tls/src/main/java/org/bouncycastle/tls/Timeout.java index 8f28abca3d..2f3c12ccf7 100644 --- a/tls/src/main/java/org/bouncycastle/tls/Timeout.java +++ b/tls/src/main/java/org/bouncycastle/tls/Timeout.java @@ -16,11 +16,6 @@ class Timeout this.startMillis = Math.max(0, currentTimeMillis); } -// long remainingMillis() -// { -// return remainingMillis(System.currentTimeMillis()); -// } - synchronized long remainingMillis(long currentTimeMillis) { // If clock jumped backwards, reset start time @@ -42,11 +37,6 @@ synchronized long remainingMillis(long currentTimeMillis) return remaining; } -// static int constrainWaitMillis(int waitMillis, Timeout timeout) -// { -// return constrainWaitMillis(waitMillis, timeout, System.currentTimeMillis()); -// } - static int constrainWaitMillis(int waitMillis, Timeout timeout, long currentTimeMillis) { if (waitMillis < 0) @@ -72,11 +62,6 @@ static int constrainWaitMillis(int waitMillis, Timeout timeout, long currentTime return Math.min(waitMillis, timeoutMillis); } - static Timeout forWaitMillis(int waitMillis) - { - return forWaitMillis(waitMillis, System.currentTimeMillis()); - } - static Timeout forWaitMillis(int waitMillis, long currentTimeMillis) { if (waitMillis < 0) @@ -90,11 +75,6 @@ static Timeout forWaitMillis(int waitMillis, long currentTimeMillis) return null; } -// static int getWaitMillis(Timeout timeout) -// { -// return getWaitMillis(timeout, System.currentTimeMillis()); -// } - static int getWaitMillis(Timeout timeout, long currentTimeMillis) { if (null == timeout) @@ -113,11 +93,6 @@ static int getWaitMillis(Timeout timeout, long currentTimeMillis) return (int)remainingMillis; } -// static boolean hasExpired(Timeout timeout) -// { -// return hasExpired(timeout, System.currentTimeMillis()); -// } - static boolean hasExpired(Timeout timeout, long currentTimeMillis) { return null != timeout && timeout.remainingMillis(currentTimeMillis) < 1L; diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java b/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java index d581f10ae8..0b9fc3e351 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java @@ -408,7 +408,7 @@ protected void handleHandshakeMessage(short type, HandshakeMessageInput buf) * NOTE: Certificate processing (including authentication) is delayed to allow for a * possible CertificateStatus message. */ - this.authentication = TlsUtils.receiveServerCertificate(tlsClientContext, tlsClient, buf, serverExtensions); + this.authentication = TlsUtils.receiveServerCertificate(tlsClientContext, tlsClient, buf); break; } default: @@ -484,22 +484,34 @@ protected void handleHandshakeMessage(short type, HandshakeMessageInput buf) { process13HelloRetryRequest(serverHello); handshakeHash.notifyPRFDetermined(); - handshakeHash.sealHashAlgorithms(); + TlsUtils.adjustTranscriptForRetry(handshakeHash); + buf.updateHash(handshakeHash); this.connection_state = CS_SERVER_HELLO_RETRY_REQUEST; send13ClientHelloRetry(); this.connection_state = CS_CLIENT_HELLO_RETRY; + + /* + * PSK binders (if any) when retrying ClientHello currently require handshakeHash buffering + */ + handshakeHash.sealHashAlgorithms(); } else { processServerHello(serverHello); handshakeHash.notifyPRFDetermined(); + if (TlsUtils.isTLSv13(securityParameters.getNegotiatedVersion())) { handshakeHash.sealHashAlgorithms(); } + else + { + // For pre-1.3 wait until ServerHelloDone is received + } + buf.updateHash(handshakeHash); this.connection_state = CS_SERVER_HELLO; @@ -551,7 +563,7 @@ protected void handleHandshakeMessage(short type, HandshakeMessageInput buf) handleServerCertificate(); // There was no server key exchange message; check it's OK - this.keyExchange.skipServerKeyExchange(); + keyExchange.skipServerKeyExchange(); // NB: Fall through to next case label } @@ -582,6 +594,8 @@ protected void handleHandshakeMessage(short type, HandshakeMessageInput buf) securityParameters.getNegotiatedVersion(), clientAuthSigner); clientAuthStreamSigner = clientAuthSigner.getStreamSigner(); + TlsUtils.verify12SignatureAlgorithm(clientAuthAlgorithm, AlertDescription.internal_error); + if (ProtocolVersion.TLSv12.equals(securityParameters.getNegotiatedVersion())) { TlsUtils.verifySupportedSignatureAlgorithm(securityParameters.getServerSigAlgs(), @@ -643,6 +657,8 @@ protected void handleHandshakeMessage(short type, HandshakeMessageInput buf) establishMasterSecret(tlsClientContext, keyExchange); } + this.keyExchange = null; + recordStream.setPendingCipher(TlsUtils.initCipher(tlsClientContext)); if (clientAuthSigner != null) @@ -686,7 +702,7 @@ protected void handleHandshakeMessage(short type, HandshakeMessageInput buf) { handleServerCertificate(); - this.keyExchange.processServerKeyExchange(buf); + keyExchange.processServerKeyExchange(buf); assertEmpty(buf); break; @@ -708,7 +724,7 @@ protected void handleHandshakeMessage(short type, HandshakeMessageInput buf) handleServerCertificate(); // There was no server key exchange message; check it's OK - this.keyExchange.skipServerKeyExchange(); + keyExchange.skipServerKeyExchange(); // NB: Fall through to next case label } @@ -840,7 +856,7 @@ protected void process13HelloRetryRequest(ServerHello helloRetryRequest) final Hashtable extensions = helloRetryRequest.getExtensions(); if (null == extensions) { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); + throw new TlsFatalAlert(AlertDescription.illegal_parameter, "no extensions found"); } TlsUtils.checkExtensionData13(extensions, HandshakeType.hello_retry_request, AlertDescription.illegal_parameter); @@ -855,15 +871,17 @@ protected void process13HelloRetryRequest(ServerHello helloRetryRequest) while (e.hasMoreElements()) { Integer extType = (Integer)e.nextElement(); + int extensionType = extType.intValue(); - if (ExtensionType.cookie == extType.intValue()) + if (ExtensionType.cookie == extensionType) { continue; } if (null == TlsUtils.getExtensionData(clientExtensions, extType)) { - throw new TlsFatalAlert(AlertDescription.unsupported_extension); + throw new TlsFatalAlert(AlertDescription.unsupported_extension, + "Unrequested extension in HelloRetryRequest: " + ExtensionType.getText(extensionType)); } } } @@ -871,14 +889,19 @@ protected void process13HelloRetryRequest(ServerHello helloRetryRequest) final ProtocolVersion server_version = TlsExtensionsUtils.getSupportedVersionsExtensionServer(extensions); if (null == server_version) { - throw new TlsFatalAlert(AlertDescription.missing_extension); + throw new TlsFatalAlert(AlertDescription.missing_extension, + "missing extension response: " + ExtensionType.getText(ExtensionType.supported_versions)); } if (!ProtocolVersion.TLSv13.isEqualOrEarlierVersionOf(server_version) || - !ProtocolVersion.contains(tlsClientContext.getClientSupportedVersions(), server_version) || - !TlsUtils.isValidVersionForCipherSuite(cipherSuite, server_version)) + !ProtocolVersion.contains(tlsClientContext.getClientSupportedVersions(), server_version)) { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); + throw new TlsFatalAlert(AlertDescription.illegal_parameter, "invalid version selected: " + server_version); + } + + if (!TlsUtils.isValidVersionForCipherSuite(cipherSuite, server_version)) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter, "invalid cipher suite for selected version"); } if (null != clientBinders) @@ -891,6 +914,20 @@ protected void process13HelloRetryRequest(ServerHello helloRetryRequest) } } + final int selectedGroup = TlsExtensionsUtils.getKeyShareHelloRetryRequest(extensions); + + /* + * TODO[tls:psk_ke] + * + * RFC 8446 4.2.8. Servers [..] MUST NOT send a KeyShareEntry when using the "psk_ke" + * PskKeyExchangeMode. + */ + if (selectedGroup < 0) + { + throw new TlsFatalAlert(AlertDescription.missing_extension, + "missing extension response: " + ExtensionType.getText(ExtensionType.key_share)); + } + /* * RFC 8446 4.2.8. Upon receipt of this [Key Share] extension in a HelloRetryRequest, the * client MUST verify that (1) the selected_group field corresponds to a group which was @@ -899,12 +936,10 @@ protected void process13HelloRetryRequest(ServerHello helloRetryRequest) * extension in the original ClientHello. If either of these checks fails, then the client * MUST abort the handshake with an "illegal_parameter" alert. */ - final int selected_group = TlsExtensionsUtils.getKeyShareHelloRetryRequest(extensions); - if (!TlsUtils.isValidKeyShareSelection(server_version, securityParameters.getClientSupportedGroups(), - clientAgreements, selected_group)) + clientAgreements, selectedGroup)) { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); + throw new TlsFatalAlert(AlertDescription.illegal_parameter, "invalid key_share selected"); } final byte[] cookie = TlsExtensionsUtils.getCookieExtension(extensions); @@ -921,9 +956,11 @@ protected void process13HelloRetryRequest(ServerHello helloRetryRequest) TlsUtils.negotiatedCipherSuite(securityParameters, cipherSuite); tlsClient.notifySelectedCipherSuite(cipherSuite); + securityParameters.negotiatedGroup = selectedGroup; + this.clientAgreements = null; this.retryCookie = cookie; - this.retryGroup = selected_group; + this.retryGroup = selectedGroup; } protected void process13ServerHello(ServerHello serverHello, boolean afterHelloRetryRequest) @@ -1028,33 +1065,39 @@ protected void process13ServerHello(ServerHello serverHello, boolean afterHelloR TlsSecret sharedSecret = null; { - KeyShareEntry keyShareEntry = TlsExtensionsUtils.getKeyShareServerHello(extensions); - if (null == keyShareEntry) + KeyShareEntry serverShare = TlsExtensionsUtils.getKeyShareServerHello(extensions); + if (null == serverShare) { - if (afterHelloRetryRequest - || null == pskEarlySecret - || !Arrays.contains(clientBinders.pskKeyExchangeModes, PskKeyExchangeMode.psk_ke)) + if (afterHelloRetryRequest || + pskEarlySecret == null || + !Arrays.contains(clientBinders.pskKeyExchangeModes, PskKeyExchangeMode.psk_ke)) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } } else { - if (null != pskEarlySecret - && !Arrays.contains(clientBinders.pskKeyExchangeModes, PskKeyExchangeMode.psk_dhe_ke)) + if (pskEarlySecret != null && + !Arrays.contains(clientBinders.pskKeyExchangeModes, PskKeyExchangeMode.psk_dhe_ke)) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } - int namedGroup = keyShareEntry.getNamedGroup(); + int namedGroup = serverShare.getNamedGroup(); + TlsAgreement agreement = (TlsAgreement)clientAgreements.get(Integers.valueOf(namedGroup)); if (null == agreement) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } - agreement.receivePeerValue(keyShareEntry.getKeyExchange()); + agreement.receivePeerValue(serverShare.getKeyExchange()); sharedSecret = agreement.calculateSecret(); + + if (!afterHelloRetryRequest) + { + securityParameters.negotiatedGroup = namedGroup; + } } } @@ -1096,6 +1139,7 @@ protected void process13ServerHelloCoda(ServerHello serverHello, boolean afterHe protected void processServerHello(ServerHello serverHello) throws IOException { + Hashtable clientHelloExtensions = clientHello.getExtensions(); Hashtable serverHelloExtensions = serverHello.getExtensions(); final ProtocolVersion legacy_version = serverHello.getVersion(); @@ -1118,6 +1162,11 @@ protected void processServerHello(ServerHello serverHello) server_version = supported_version; } + if (!ProtocolVersion.contains(tlsClientContext.getClientSupportedVersions(), server_version)) + { + throw new TlsFatalAlert(AlertDescription.protocol_version); + } + final SecurityParameters securityParameters = tlsClientContext.getSecurityParametersHandshake(); if (securityParameters.isRenegotiating()) @@ -1130,11 +1179,6 @@ protected void processServerHello(ServerHello serverHello) } else { - if (!ProtocolVersion.contains(tlsClientContext.getClientSupportedVersions(), server_version)) - { - throw new TlsFatalAlert(AlertDescription.protocol_version); - } - ProtocolVersion legacy_record_version = server_version.isLaterVersionOf(ProtocolVersion.TLSv12) ? ProtocolVersion.TLSv12 : server_version; @@ -1234,7 +1278,7 @@ protected void processServerHello(ServerHello serverHello) * associated ClientHello, it MUST abort the handshake with an unsupported_extension * fatal alert. */ - if (null == TlsUtils.getExtensionData(this.clientExtensions, extType)) + if (null == TlsUtils.getExtensionData(clientHelloExtensions, extType)) { throw new TlsFatalAlert(AlertDescription.unsupported_extension, "Unrequested extension in ServerHello: " + ExtensionType.getText(extType.intValue())); @@ -1336,7 +1380,7 @@ protected void processServerHello(ServerHello serverHello) { boolean negotiatedEMS = false; - if (TlsExtensionsUtils.hasExtendedMasterSecretExtension(clientExtensions)) + if (TlsExtensionsUtils.hasExtendedMasterSecretExtension(clientHelloExtensions)) { negotiatedEMS = TlsExtensionsUtils.hasExtendedMasterSecretExtension(serverHelloExtensions); @@ -1377,7 +1421,7 @@ protected void processServerHello(ServerHello serverHello) securityParameters.applicationProtocol = TlsExtensionsUtils.getALPNExtensionServer(serverHelloExtensions); securityParameters.applicationProtocolSet = true; - Hashtable sessionClientExtensions = clientExtensions, sessionServerExtensions = serverHelloExtensions; + Hashtable sessionClientExtensions = clientHelloExtensions, sessionServerExtensions = serverHelloExtensions; if (securityParameters.isResumedSession()) { sessionClientExtensions = null; @@ -1506,14 +1550,14 @@ protected void receive13EncryptedExtensions(ByteArrayInputStream buf) if (null == TlsUtils.getExtensionData(clientExtensions, extType)) { - throw new TlsFatalAlert(AlertDescription.unsupported_extension); + throw new TlsFatalAlert(AlertDescription.unsupported_extension, + "Unrequested extension in EncryptedExtensions: " + ExtensionType.getText(extType.intValue())); } } } final SecurityParameters securityParameters = tlsClientContext.getSecurityParametersHandshake(); - final ProtocolVersion negotiatedVersion = securityParameters.getNegotiatedVersion(); securityParameters.applicationProtocol = TlsExtensionsUtils.getALPNExtensionServer(serverExtensions); securityParameters.applicationProtocolSet = true; @@ -1591,7 +1635,7 @@ protected void receive13ServerCertificate(ByteArrayInputStream buf) throw new TlsFatalAlert(AlertDescription.unexpected_message); } - this.authentication = TlsUtils.receive13ServerCertificate(tlsClientContext, tlsClient, buf, serverExtensions); + this.authentication = TlsUtils.receive13ServerCertificate(tlsClientContext, tlsClient, buf); // NOTE: In TLS 1.3 we don't have to wait for a possible CertificateStatus message. handleServerCertificate(); @@ -1740,21 +1784,10 @@ protected void sendClientHello() { SecurityParameters securityParameters = tlsClientContext.getSecurityParametersHandshake(); - ProtocolVersion[] supportedVersions; - ProtocolVersion earliestVersion, latestVersion; + ProtocolVersion[] supportedVersions = tlsClient.getProtocolVersions(); - if (securityParameters.isRenegotiating()) - { - ProtocolVersion clientVersion = tlsClientContext.getClientVersion(); - - supportedVersions = clientVersion.only(); - earliestVersion = clientVersion; - latestVersion = clientVersion; - } - else + if (!securityParameters.isRenegotiating()) { - supportedVersions = tlsClient.getProtocolVersions(); - if (ProtocolVersion.contains(supportedVersions, ProtocolVersion.SSLv3)) { // TODO[tls13] Prevent offering SSLv3 AND TLSv13? @@ -1764,18 +1797,17 @@ protected void sendClientHello() { recordStream.setWriteVersion(ProtocolVersion.TLSv10); } + } - earliestVersion = ProtocolVersion.getEarliestTLS(supportedVersions); - latestVersion = ProtocolVersion.getLatestTLS(supportedVersions); + ProtocolVersion earliestVersion = ProtocolVersion.getEarliestTLS(supportedVersions); + ProtocolVersion latestVersion = ProtocolVersion.getLatestTLS(supportedVersions); - if (!ProtocolVersion.isSupportedTLSVersionClient(latestVersion)) - { - throw new TlsFatalAlert(AlertDescription.internal_error); - } - - tlsClientContext.setClientVersion(latestVersion); + if (!ProtocolVersion.isSupportedTLSVersionClient(latestVersion)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); } - + + tlsClientContext.setClientVersion(latestVersion); tlsClientContext.setClientSupportedVersions(supportedVersions); final boolean offeringTLSv12Minus = ProtocolVersion.TLSv12.isEqualOrLaterVersionOf(earliestVersion); @@ -1789,10 +1821,11 @@ protected void sendClientHello() TlsSession sessionToResume = offeringTLSv12Minus ? tlsClient.getSessionToResume() : null; - boolean fallback = tlsClient.isFallback(); - + // NOTE: Client is free to modify the cipher suites up until getSessionToResume int[] offeredCipherSuites = tlsClient.getCipherSuites(); + boolean fallback = tlsClient.isFallback(); + this.clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(tlsClient.getClientExtensions()); final boolean shouldUseEMS = tlsClient.shouldUseExtendedMasterSecret(); @@ -1898,18 +1931,24 @@ protected void sendClientHello() */ if (!securityParameters.isSecureRenegotiation()) { - throw new TlsFatalAlert(AlertDescription.internal_error); + throw new TlsFatalAlert(AlertDescription.internal_error, "Renegotiation requires secure_renegotiation"); } /* * The client MUST include the "renegotiation_info" extension in the ClientHello, * containing the saved client_verify_data. The SCSV MUST NOT be included. */ + if (Arrays.contains(offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) + { + throw new TlsFatalAlert(AlertDescription.internal_error, + "Renegotiation cannot use TLS_EMPTY_RENEGOTIATION_INFO_SCSV"); + } + SecurityParameters saved = tlsClientContext.getSecurityParametersConnection(); this.clientExtensions.put(EXT_RenegotiationInfo, createRenegotiationInfo(saved.getLocalVerifyData())); } - else + else if (offeringTLSv12Minus) { /* * RFC 5746 3.4. Client Behavior: Initial Handshake (both full and session-resumption) @@ -1925,7 +1964,6 @@ protected void sendClientHello() if (noRenegExt && noRenegSCSV) { - // TODO[tls13] Probably want to not add this if no pre-TLSv13 versions offered? offeredCipherSuites = Arrays.append(offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); } } @@ -1972,7 +2010,7 @@ protected void sendClientKeyExchange() throws IOException { HandshakeMessageOutput message = new HandshakeMessageOutput(HandshakeType.client_key_exchange); - this.keyExchange.generateClientKeyExchange(message); + keyExchange.generateClientKeyExchange(message); message.send(this); } diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsContext.java b/tls/src/main/java/org/bouncycastle/tls/TlsContext.java index 05779220a7..137709102d 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsContext.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsContext.java @@ -63,7 +63,7 @@ public interface TlsContext * * @param channelBinding * A {@link ChannelBinding} constant specifying the channel binding to export. - * @return A copy of the channel binding data as a {@link byte[]}, or null if the binding could + * @return A copy of the channel binding data as a byte[], or null if the binding could * not be determined. */ byte[] exportChannelBinding(int channelBinding); diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsDHEKeyExchange.java b/tls/src/main/java/org/bouncycastle/tls/TlsDHEKeyExchange.java index 23a82a5f35..39e8edc95d 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsDHEKeyExchange.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsDHEKeyExchange.java @@ -82,7 +82,7 @@ public byte[] generateServerKeyExchange() throws IOException TlsUtils.writeOpaque16(y, digestBuffer); - TlsUtils.generateServerKeyExchangeSignature(context, serverCredentials, null, digestBuffer); + TlsUtils.generateServerKeyExchangeSignature(context, serverCredentials, digestBuffer); return digestBuffer.toByteArray(); } @@ -96,7 +96,7 @@ public void processServerKeyExchange(InputStream input) throws IOException byte[] y = TlsUtils.readOpaque16(teeIn, 1); - TlsUtils.verifyServerKeyExchangeSignature(context, input, serverCertificate, null, digestBuffer); + TlsUtils.verifyServerKeyExchangeSignature(context, input, serverCertificate, digestBuffer); this.agreement = context.getCrypto().createDHDomain(dhConfig).createDH(); diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsECDHEKeyExchange.java b/tls/src/main/java/org/bouncycastle/tls/TlsECDHEKeyExchange.java index 5d2701b545..76190b2b38 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsECDHEKeyExchange.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsECDHEKeyExchange.java @@ -76,7 +76,7 @@ public byte[] generateServerKeyExchange() throws IOException generateEphemeral(digestBuffer); - TlsUtils.generateServerKeyExchangeSignature(context, serverCredentials, null, digestBuffer); + TlsUtils.generateServerKeyExchangeSignature(context, serverCredentials, digestBuffer); return digestBuffer.toByteArray(); } @@ -90,7 +90,7 @@ public void processServerKeyExchange(InputStream input) throws IOException byte[] point = TlsUtils.readOpaque8(teeIn, 1); - TlsUtils.verifyServerKeyExchangeSignature(context, input, serverCertificate, null, digestBuffer); + TlsUtils.verifyServerKeyExchangeSignature(context, input, serverCertificate, digestBuffer); this.agreement = context.getCrypto().createECDomain(ecConfig).createECDH(); diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsExtensionsUtils.java b/tls/src/main/java/org/bouncycastle/tls/TlsExtensionsUtils.java index a44904459e..9f53a226dc 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsExtensionsUtils.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsExtensionsUtils.java @@ -250,6 +250,11 @@ public static void addSupportedGroupsExtension(Hashtable extensions, Vector name extensions.put(EXT_supported_groups, createSupportedGroupsExtension(namedGroups)); } + public static void addSupportedGroupsExtension(Hashtable extensions, int[] namedGroups) throws IOException + { + extensions.put(EXT_supported_groups, createSupportedGroupsExtension(namedGroups)); + } + public static void addSupportedPointFormatsExtension(Hashtable extensions, short[] ecPointFormats) throws IOException { @@ -320,6 +325,7 @@ public static short getClientCertificateTypeExtensionServer(Hashtable extensions /** * @deprecated Use version without defaultValue instead */ + @Deprecated public static short getClientCertificateTypeExtensionServer(Hashtable extensions, short defaultValue) throws IOException { @@ -447,6 +453,7 @@ public static short getServerCertificateTypeExtensionServer(Hashtable extensions /** * @deprecated Use version without defaultValue instead */ + @Deprecated public static short getServerCertificateTypeExtensionServer(Hashtable extensions, short defaultValue) throws IOException { @@ -934,6 +941,16 @@ public static byte[] createSupportedGroupsExtension(Vector namedGroups) throws I return TlsUtils.encodeUint16ArrayWithUint16Length(values); } + public static byte[] createSupportedGroupsExtension(int[] namedGroups) throws IOException + { + if (TlsUtils.isNullOrEmpty(namedGroups)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + return TlsUtils.encodeUint16ArrayWithUint16Length(namedGroups); + } + public static byte[] createSupportedPointFormatsExtension(short[] ecPointFormats) throws IOException { if (ecPointFormats == null || !Arrays.contains(ecPointFormats, ECPointFormat.uncompressed)) diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsPeer.java b/tls/src/main/java/org/bouncycastle/tls/TlsPeer.java index 777d61857d..ea0434df4c 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsPeer.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsPeer.java @@ -92,6 +92,7 @@ public interface TlsPeer * {@link TlsUtils#checkPeerSigAlgs(TlsContext, TlsCertificate[])} once a complete * CertPath has been determined (i.e. as part of chain validation). */ + @Deprecated boolean shouldCheckSigAlgOfPeerCerts(); boolean shouldUseExtendedMasterSecret(); diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsProtocol.java b/tls/src/main/java/org/bouncycastle/tls/TlsProtocol.java index ce2630bb8c..a639d1fd24 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsProtocol.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsProtocol.java @@ -144,7 +144,7 @@ protected boolean isTLSv13ConnectionState() private TlsOutputStream tlsOutputStream = null; private volatile boolean closed = false; - private volatile boolean failedWithError = false; + private volatile boolean failed = false; private volatile boolean appDataReady = false; private volatile boolean appDataSplitEnabled = true; private volatile boolean keyUpdateEnabled = false; @@ -158,6 +158,7 @@ protected boolean isTLSv13ConnectionState() protected TlsSecret sessionMasterSecret = null; protected byte[] retryCookie = null; + // TODO[api] Remove and manage via SecurityParameters.negotiatedGroup protected int retryGroup = -1; protected Hashtable clientExtensions = null; protected Hashtable serverExtensions = null; @@ -324,7 +325,7 @@ protected void handleException(short alertDescription, String message, Throwable protected void handleFailure() throws IOException { this.closed = true; - this.failedWithError = true; + this.failed = true; /* * RFC 2246 7.2.1. The session becomes unresumable if any connection is terminated @@ -570,7 +571,7 @@ protected void processRecord(short protocol, byte[] buf, int off, int len) throw new TlsFatalAlert(AlertDescription.unexpected_message); } applicationDataQueue.addData(buf, off, len); - processApplicationDataQueue(); +// processApplicationDataQueue(); break; } case ContentType.change_cipher_spec: @@ -716,15 +717,6 @@ private void processHandshakeQueue(ByteQueue queue) } } - private void processApplicationDataQueue() - { - /* - * There is nothing we need to do here. - * - * This function could be used for callbacks when application data arrives in the future. - */ - } - private void processAlertQueue() throws IOException { @@ -828,7 +820,7 @@ public int readApplicationData(byte[] buf, int off, int len) { if (this.closed) { - if (this.failedWithError) + if (this.failed) { throw new IOException("Cannot read application data on failed TLS connection"); } @@ -894,7 +886,7 @@ protected void safeReadRecord() } catch (TlsFatalAlertReceived e) { - // Connection failure already handled at source +// assert isFailed(); throw e; } catch (TlsFatalAlert e) @@ -925,6 +917,11 @@ protected boolean safeReadFullRecord(byte[] input, int inputOff, int inputLen) { return recordStream.readFullRecord(input, inputOff, inputLen); } + catch (TlsFatalAlertReceived e) + { +// assert isFailed(); + throw e; + } catch (TlsFatalAlert e) { handleException(e.getAlertDescription(), "Failed to process record", e); @@ -947,7 +944,7 @@ protected void safeWriteRecord(short type, byte[] buf, int offset, int len) { try { - recordStream.writeRecord(type, buf, offset, len); + writeRecord(type, buf, offset, len); } catch (TlsFatalAlert e) { @@ -966,6 +963,12 @@ protected void safeWriteRecord(short type, byte[] buf, int offset, int len) } } + protected void writeRecord(short type, byte[] buf, int off, int len) + throws IOException + { + recordStream.writeRecord(type, buf, off, len); + } + /** * Write some application data. Fragmentation is handled internally. Usable in both blocking/non-blocking * modes.
          @@ -1703,7 +1706,7 @@ protected void raiseAlertFatal(short alertDescription, String message, Throwable try { - recordStream.writeRecord(ContentType.alert, alert, 0, 2); + writeRecord(ContentType.alert, alert, 0, 2); } catch (Exception e) { @@ -1926,6 +1929,11 @@ public boolean isConnected() return null != context && context.isConnected(); } + public boolean isFailed() + { + return failed; + } + public boolean isHandshaking() { if (closed) @@ -1941,6 +1949,7 @@ public boolean isHandshaking() /** * @deprecated Will be removed. */ + @Deprecated protected short processMaxFragmentLengthExtension(Hashtable clientExtensions, Hashtable serverExtensions, short alertDescription) throws IOException diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsSRPKeyExchange.java b/tls/src/main/java/org/bouncycastle/tls/TlsSRPKeyExchange.java index 08ad56d425..60d442b0fc 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsSRPKeyExchange.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsSRPKeyExchange.java @@ -110,7 +110,7 @@ public byte[] generateServerKeyExchange() throws IOException if (serverCredentials != null) { - TlsUtils.generateServerKeyExchangeSignature(context, serverCredentials, null, digestBuffer); + TlsUtils.generateServerKeyExchangeSignature(context, serverCredentials, digestBuffer); } return digestBuffer.toByteArray(); @@ -131,7 +131,7 @@ public void processServerKeyExchange(InputStream input) throws IOException if (digestBuffer != null) { - TlsUtils.verifyServerKeyExchangeSignature(context, input, serverCertificate, null, digestBuffer); + TlsUtils.verifyServerKeyExchangeSignature(context, input, serverCertificate, digestBuffer); } TlsSRPConfig config = new TlsSRPConfig(); diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsServer.java b/tls/src/main/java/org/bouncycastle/tls/TlsServer.java index ee78dfbde5..8f092eeaf2 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsServer.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsServer.java @@ -13,6 +13,8 @@ public interface TlsServer extends TlsPeer { + boolean preferLocalSupportedGroups(); + void init(TlsServerContext context); /** diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java b/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java index 3ace602565..9acb7a637d 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java @@ -10,9 +10,6 @@ import org.bouncycastle.tls.crypto.TlsAgreement; import org.bouncycastle.tls.crypto.TlsCrypto; -import org.bouncycastle.tls.crypto.TlsDHConfig; -import org.bouncycastle.tls.crypto.TlsECConfig; -import org.bouncycastle.tls.crypto.TlsKemConfig; import org.bouncycastle.tls.crypto.TlsSecret; import org.bouncycastle.util.Arrays; @@ -173,8 +170,8 @@ protected ServerHello generate13ServerHello(ClientHello clientHello, HandshakeMe clientHelloExtensions, clientHelloMessage, handshakeHash, afterHelloRetryRequest); Vector clientShares = TlsExtensionsUtils.getKeyShareClientHello(clientHelloExtensions); - KeyShareEntry clientShare = null; + KeyShareEntry clientShare; if (afterHelloRetryRequest) { if (retryGroup < 0) @@ -219,7 +216,7 @@ protected ServerHello generate13ServerHello(ClientHello clientHello, HandshakeMe } this.retryCookie = null; - clientShare = TlsUtils.selectKeyShare(clientShares, retryGroup); + clientShare = TlsUtils.getRetryKeyShare(clientShares, retryGroup); if (null == clientShare) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); @@ -296,39 +293,27 @@ protected ServerHello generate13ServerHello(ClientHello clientHello, HandshakeMe int[] clientSupportedGroups = securityParameters.getClientSupportedGroups(); int[] serverSupportedGroups = securityParameters.getServerSupportedGroups(); + boolean useServerOrder = tlsServer.preferLocalSupportedGroups(); - clientShare = TlsUtils.selectKeyShare(crypto, serverVersion, clientShares, clientSupportedGroups, - serverSupportedGroups); + int selectedGroup = TlsUtils.selectKeyShareGroup(crypto, serverVersion, clientSupportedGroups, + serverSupportedGroups, useServerOrder); + if (selectedGroup < 0) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + + securityParameters.negotiatedGroup = selectedGroup; + + clientShare = TlsUtils.findEarlyKeyShare(clientShares, selectedGroup); if (null == clientShare) { - this.retryGroup = TlsUtils.selectKeyShareGroup(crypto, serverVersion, clientSupportedGroups, - serverSupportedGroups); - if (retryGroup < 0) - { - throw new TlsFatalAlert(AlertDescription.handshake_failure); - } + this.retryGroup = selectedGroup; this.retryCookie = tlsServerContext.getNonceGenerator().generateNonce(16); return generate13HelloRetryRequest(clientHello); } - - if (clientShare.getNamedGroup() != serverSupportedGroups[0]) - { - /* - * TODO[tls13] RFC 8446 4.2.7. As of TLS 1.3, servers are permitted to send the - * "supported_groups" extension to the client. Clients MUST NOT act upon any - * information found in "supported_groups" prior to successful completion of the - * handshake but MAY use the information learned from a successfully completed - * handshake to change what groups they use in their "key_share" extension in - * subsequent connections. If the server has a group it prefers to the ones in the - * "key_share" extension but is still willing to accept the ClientHello, it SHOULD - * send "supported_groups" to update the client's view of its preferences; this - * extension SHOULD contain all groups the server supports, regardless of whether - * they are currently supported by the client. - */ - } } @@ -337,6 +322,25 @@ protected ServerHello generate13ServerHello(ClientHello clientHello, HandshakeMe tlsServer.getServerExtensionsForConnection(serverEncryptedExtensions); + /* + * RFC 8446 4.2.7. As of TLS 1.3, servers are permitted to send the "supported_groups" extension to + * the client. [..] If the server has a group it prefers to the ones in the "key_share" extension + * but is still willing to accept the ClientHello, it SHOULD send "supported_groups" to update the + * client's view of its preferences; this extension SHOULD contain all groups the server supports, + * regardless of whether they are currently supported by the client. + */ + if (!afterHelloRetryRequest) + { + int[] serverSupportedGroups = securityParameters.getServerSupportedGroups(); + + if (!TlsUtils.isNullOrEmpty(serverSupportedGroups) && + serverSupportedGroups[0] != securityParameters.getNegotiatedGroup() && + !serverEncryptedExtensions.containsKey(TlsExtensionsUtils.EXT_supported_groups)) + { + TlsExtensionsUtils.addSupportedGroupsExtension(serverEncryptedExtensions, serverSupportedGroups); + } + } + ProtocolVersion serverLegacyVersion = ProtocolVersion.TLSv12; TlsExtensionsUtils.addSupportedVersionsExtensionServer(serverHelloExtensions, serverVersion); @@ -395,22 +399,15 @@ protected ServerHello generate13ServerHello(ClientHello clientHello, HandshakeMe TlsSecret sharedSecret; { - int namedGroup = clientShare.getNamedGroup(); - - TlsAgreement agreement; - if (NamedGroup.refersToAnECDHCurve(namedGroup)) - { - agreement = crypto.createECDomain(new TlsECConfig(namedGroup)).createECDH(); - } - else if (NamedGroup.refersToASpecificFiniteField(namedGroup)) - { - agreement = crypto.createDHDomain(new TlsDHConfig(namedGroup, true)).createDH(); - } - else if (NamedGroup.refersToASpecificKem(namedGroup)) + int negotiatedGroup = securityParameters.getNegotiatedGroup(); + + if (clientShare.getNamedGroup() != negotiatedGroup) { - agreement = crypto.createKemDomain(new TlsKemConfig(namedGroup, true)).createKem(); + throw new TlsFatalAlert(AlertDescription.illegal_parameter); } - else + + TlsAgreement agreement = TlsUtils.createKeyShare(crypto, negotiatedGroup, true); + if (agreement == null) { throw new TlsFatalAlert(AlertDescription.internal_error); } @@ -418,7 +415,7 @@ else if (NamedGroup.refersToASpecificKem(namedGroup)) agreement.receivePeerValue(clientShare.getKeyExchange()); byte[] key_exchange = agreement.generateEphemeral(); - KeyShareEntry serverShare = new KeyShareEntry(namedGroup, key_exchange); + KeyShareEntry serverShare = new KeyShareEntry(negotiatedGroup, key_exchange); TlsExtensionsUtils.addKeyShareServerHello(serverHelloExtensions, serverShare); sharedSecret = agreement.calculateSecret(); @@ -1131,11 +1128,11 @@ protected void handleHandshakeMessage(short type, HandshakeMessageInput buf) ByteArrayOutputStream endPointHash = new ByteArrayOutputStream(); if (null == serverCredentials) { - this.keyExchange.skipServerCredentials(); + keyExchange.skipServerCredentials(); } else { - this.keyExchange.processServerCredentials(serverCredentials); + keyExchange.processServerCredentials(serverCredentials); serverCertificate = serverCredentials.getCertificate(); sendCertificateMessage(serverCertificate, endPointHash); @@ -1161,7 +1158,7 @@ protected void handleHandshakeMessage(short type, HandshakeMessageInput buf) } } - byte[] serverKeyExchange = this.keyExchange.generateServerKeyExchange(); + byte[] serverKeyExchange = keyExchange.generateServerKeyExchange(); if (serverKeyExchange != null) { sendServerKeyExchangeMessage(serverKeyExchange); @@ -1191,7 +1188,7 @@ protected void handleHandshakeMessage(short type, HandshakeMessageInput buf) throw new TlsFatalAlert(AlertDescription.internal_error); } - this.certificateRequest = TlsUtils.validateCertificateRequest(this.certificateRequest, this.keyExchange); + this.certificateRequest = TlsUtils.validateCertificateRequest(certificateRequest, keyExchange); TlsUtils.establishServerSigAlgs(securityParameters, certificateRequest); @@ -1280,7 +1277,7 @@ protected void handleHandshakeMessage(short type, HandshakeMessageInput buf) { if (null == certificateRequest) { - this.keyExchange.skipClientCredentials(); + keyExchange.skipClientCredentials(); } else if (TlsUtils.isTLSv12(tlsServerContext)) { @@ -1546,6 +1543,8 @@ protected void receiveClientKeyExchangeMessage(ByteArrayInputStream buf) establishMasterSecret(tlsServerContext, keyExchange); } + this.keyExchange = null; + recordStream.setPendingCipher(TlsUtils.initCipher(tlsServerContext)); if (!expectCertificateVerifyMessage()) @@ -1603,7 +1602,7 @@ protected void send13ServerHelloCoda(ServerHello serverHello, boolean afterHello this.connection_state = CS_SERVER_CERTIFICATE_REQUEST; } } - + TlsCredentialedSigner serverCredentials = TlsUtils.establish13ServerCredentials(tlsServer); if (null == serverCredentials) { diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java index 005bf51c8a..2b538904d0 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java @@ -40,6 +40,7 @@ import org.bouncycastle.tls.crypto.TlsEncryptor; import org.bouncycastle.tls.crypto.TlsHash; import org.bouncycastle.tls.crypto.TlsHashOutputStream; +import org.bouncycastle.tls.crypto.TlsHybridAgreement; import org.bouncycastle.tls.crypto.TlsKemConfig; import org.bouncycastle.tls.crypto.TlsSecret; import org.bouncycastle.tls.crypto.TlsStreamSigner; @@ -62,7 +63,7 @@ public class TlsUtils // Map OID strings to HashAlgorithm values private static final Hashtable CERT_SIG_ALG_OIDS = createCertSigAlgOIDs(); private static final Vector DEFAULT_SUPPORTED_SIG_ALGS = createDefaultSupportedSigAlgs(); - + private static void addCertSigAlgOID(Hashtable h, ASN1ObjectIdentifier oid, SignatureAndHashAlgorithm sigAndHash) { h.put(oid.getId(), sigAndHash); @@ -115,6 +116,23 @@ private static Hashtable createCertSigAlgOIDs() addCertSigAlgOID(h, EdECObjectIdentifiers.id_Ed25519, SignatureAndHashAlgorithm.ed25519); addCertSigAlgOID(h, EdECObjectIdentifiers.id_Ed448, SignatureAndHashAlgorithm.ed448); + addCertSigAlgOID(h, NISTObjectIdentifiers.id_ml_dsa_44, SignatureAndHashAlgorithm.mldsa44); + addCertSigAlgOID(h, NISTObjectIdentifiers.id_ml_dsa_65, SignatureAndHashAlgorithm.mldsa65); + addCertSigAlgOID(h, NISTObjectIdentifiers.id_ml_dsa_87, SignatureAndHashAlgorithm.mldsa87); + + addCertSigAlgOID(h, NISTObjectIdentifiers.id_slh_dsa_sha2_128s, SignatureAndHashAlgorithm.slhdsa_sha2_128s); + addCertSigAlgOID(h, NISTObjectIdentifiers.id_slh_dsa_sha2_128f, SignatureAndHashAlgorithm.slhdsa_sha2_128f); + addCertSigAlgOID(h, NISTObjectIdentifiers.id_slh_dsa_sha2_192s, SignatureAndHashAlgorithm.slhdsa_sha2_192s); + addCertSigAlgOID(h, NISTObjectIdentifiers.id_slh_dsa_sha2_192f, SignatureAndHashAlgorithm.slhdsa_sha2_192f); + addCertSigAlgOID(h, NISTObjectIdentifiers.id_slh_dsa_sha2_256s, SignatureAndHashAlgorithm.slhdsa_sha2_256s); + addCertSigAlgOID(h, NISTObjectIdentifiers.id_slh_dsa_sha2_256f, SignatureAndHashAlgorithm.slhdsa_sha2_256f); + addCertSigAlgOID(h, NISTObjectIdentifiers.id_slh_dsa_shake_128s, SignatureAndHashAlgorithm.slhdsa_shake_128s); + addCertSigAlgOID(h, NISTObjectIdentifiers.id_slh_dsa_shake_128f, SignatureAndHashAlgorithm.slhdsa_shake_128f); + addCertSigAlgOID(h, NISTObjectIdentifiers.id_slh_dsa_shake_192s, SignatureAndHashAlgorithm.slhdsa_shake_192s); + addCertSigAlgOID(h, NISTObjectIdentifiers.id_slh_dsa_shake_192f, SignatureAndHashAlgorithm.slhdsa_shake_192f); + addCertSigAlgOID(h, NISTObjectIdentifiers.id_slh_dsa_shake_256s, SignatureAndHashAlgorithm.slhdsa_shake_256s); + addCertSigAlgOID(h, NISTObjectIdentifiers.id_slh_dsa_shake_256f, SignatureAndHashAlgorithm.slhdsa_shake_256f); + addCertSigAlgOID(h, RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256, SignatureAndHashAlgorithm.gostr34102012_256); addCertSigAlgOID(h, RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512, @@ -134,12 +152,15 @@ private static Vector createDefaultSupportedSigAlgs() result.addElement(SignatureAndHashAlgorithm.getInstance(HashAlgorithm.sha256, SignatureAlgorithm.ecdsa)); result.addElement(SignatureAndHashAlgorithm.getInstance(HashAlgorithm.sha384, SignatureAlgorithm.ecdsa)); result.addElement(SignatureAndHashAlgorithm.getInstance(HashAlgorithm.sha512, SignatureAlgorithm.ecdsa)); - result.addElement(SignatureAndHashAlgorithm.rsa_pss_rsae_sha256); - result.addElement(SignatureAndHashAlgorithm.rsa_pss_rsae_sha384); - result.addElement(SignatureAndHashAlgorithm.rsa_pss_rsae_sha512); result.addElement(SignatureAndHashAlgorithm.rsa_pss_pss_sha256); result.addElement(SignatureAndHashAlgorithm.rsa_pss_pss_sha384); result.addElement(SignatureAndHashAlgorithm.rsa_pss_pss_sha512); + result.addElement(SignatureAndHashAlgorithm.rsa_pss_rsae_sha256); + result.addElement(SignatureAndHashAlgorithm.rsa_pss_rsae_sha384); + result.addElement(SignatureAndHashAlgorithm.rsa_pss_rsae_sha512); + result.addElement(SignatureAndHashAlgorithm.mldsa44); + result.addElement(SignatureAndHashAlgorithm.mldsa65); + result.addElement(SignatureAndHashAlgorithm.mldsa87); result.addElement(SignatureAndHashAlgorithm.getInstance(HashAlgorithm.sha256, SignatureAlgorithm.rsa)); result.addElement(SignatureAndHashAlgorithm.getInstance(HashAlgorithm.sha384, SignatureAlgorithm.rsa)); result.addElement(SignatureAndHashAlgorithm.getInstance(HashAlgorithm.sha512, SignatureAlgorithm.rsa)); @@ -1093,6 +1114,7 @@ public static ASN1Primitive readASN1Object(byte[] encoding) throws IOException } /** @deprecated Will be removed. Use readASN1Object in combination with requireDEREncoding instead */ + @Deprecated public static ASN1Primitive readDERObject(byte[] encoding) throws IOException { /* @@ -1149,7 +1171,7 @@ public static void addIfSupported(Vector supportedAlgs, TlsCrypto crypto, Signat public static void addIfSupported(Vector supportedGroups, TlsCrypto crypto, int namedGroup) { - if (crypto.hasNamedGroup(namedGroup)) + if (isSupportedNamedGroup(crypto, namedGroup)) { supportedGroups.addElement(Integers.valueOf(namedGroup)); } @@ -1243,6 +1265,8 @@ public static Vector getSupportedSignatureAlgorithms(TlsContext context, Vector /** * @deprecated Will be removed */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public static SignatureAndHashAlgorithm getSignatureAndHashAlgorithm(TlsContext context, TlsCredentialedSigner signerCredentials) throws IOException @@ -1531,6 +1555,26 @@ public static Vector parseSupportedSignatureAlgorithms(InputStream input) return supportedSignatureAlgorithms; } + static void verify12SignatureAlgorithm(SignatureAndHashAlgorithm signatureAlgorithm, short alertDescription) + throws IOException + { + if (signatureAlgorithm != null) + { + int signatureScheme = SignatureScheme.from(signatureAlgorithm); + + // TODO In future there might be more cases, so we'd need a more general method. + if (SignatureScheme.isMLDSA(signatureScheme) || + SignatureScheme.isSLHDSA(signatureScheme)) + { + throw new TlsFatalAlert(alertDescription); + } + } + } + + /** + * @deprecated Will be removed. + */ + @Deprecated public static void verifySupportedSignatureAlgorithm(Vector supportedSignatureAlgorithms, SignatureAndHashAlgorithm signatureAlgorithm) throws IOException { @@ -1597,6 +1641,8 @@ public static TlsSecret PRF(SecurityParameters securityParameters, TlsSecret sec /** * @deprecated Use {@link #PRF(SecurityParameters, TlsSecret, String, byte[], int)} instead. */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public static TlsSecret PRF(TlsContext context, TlsSecret secret, String asciiLabel, byte[] seed, int length) { return PRF(context.getSecurityParametersHandshake(), secret, asciiLabel, seed, length); @@ -1998,6 +2044,7 @@ static int getPRFAlgorithm(SecurityParameters securityParameters, int cipherSuit case CipherSuite.TLS_AES_128_CCM_8_SHA256: case CipherSuite.TLS_AES_128_GCM_SHA256: case CipherSuite.TLS_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_SHA256_SHA256: { if (isTLSv13) { @@ -2007,6 +2054,7 @@ static int getPRFAlgorithm(SecurityParameters securityParameters, int cipherSuit } case CipherSuite.TLS_AES_256_GCM_SHA384: + case CipherSuite.TLS_SHA384_SHA384: { if (isTLSv13) { @@ -2286,9 +2334,11 @@ static int getPRFAlgorithm13(int cipherSuite) case CipherSuite.TLS_AES_128_CCM_8_SHA256: case CipherSuite.TLS_AES_128_GCM_SHA256: case CipherSuite.TLS_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_SHA256_SHA256: return PRFAlgorithm.tls13_hkdf_sha256; case CipherSuite.TLS_AES_256_GCM_SHA384: + case CipherSuite.TLS_SHA384_SHA384: return PRFAlgorithm.tls13_hkdf_sha384; case CipherSuite.TLS_SM4_CCM_SM3: @@ -2317,8 +2367,7 @@ static int[] getPRFAlgorithms13(int[] cipherSuites) return truncate(result, count); } - static byte[] calculateSignatureHash(TlsContext context, SignatureAndHashAlgorithm algorithm, - byte[] extraSignatureInput, DigestInputBuffer buf) + static byte[] calculateSignatureHash(TlsContext context, SignatureAndHashAlgorithm algorithm, DigestInputBuffer buf) { TlsCrypto crypto = context.getCrypto(); @@ -2331,29 +2380,18 @@ static byte[] calculateSignatureHash(TlsContext context, SignatureAndHashAlgorit byte[] randoms = Arrays.concatenate(sp.getClientRandom(), sp.getServerRandom()); h.update(randoms, 0, randoms.length); - if (null != extraSignatureInput) - { - h.update(extraSignatureInput, 0, extraSignatureInput.length); - } - buf.updateDigest(h); return h.calculateHash(); } - static void sendSignatureInput(TlsContext context, byte[] extraSignatureInput, DigestInputBuffer buf, - OutputStream output) throws IOException + static void sendSignatureInput(TlsContext context, DigestInputBuffer buf, OutputStream output) throws IOException { SecurityParameters sp = context.getSecurityParametersHandshake(); // NOTE: The implicit copy here is intended (and important) byte[] randoms = Arrays.concatenate(sp.getClientRandom(), sp.getServerRandom()); output.write(randoms); - if (null != extraSignatureInput) - { - output.write(extraSignatureInput); - } - buf.copyInputTo(output); output.close(); @@ -2455,7 +2493,10 @@ static void verifyCertificateVerifyClient(TlsServerContext serverContext, Certif } else { - verifySupportedSignatureAlgorithm(securityParameters.getServerSigAlgs(), sigAndHashAlg); + verify12SignatureAlgorithm(sigAndHashAlg, AlertDescription.illegal_parameter); + + verifySupportedSignatureAlgorithm(securityParameters.getServerSigAlgs(), sigAndHashAlg, + AlertDescription.illegal_parameter); signatureAlgorithm = sigAndHashAlg.getSignature(); @@ -2540,7 +2581,7 @@ private static void verify13CertificateVerify(Vector supportedAlgorithms, String int signatureScheme = certificateVerify.getAlgorithm(); SignatureAndHashAlgorithm algorithm = SignatureScheme.getSignatureAndHashAlgorithm(signatureScheme); - verifySupportedSignatureAlgorithm(supportedAlgorithms, algorithm); + verifySupportedSignatureAlgorithm(supportedAlgorithms, algorithm, AlertDescription.illegal_parameter); Tls13Verifier verifier = certificate.createVerifier(signatureScheme); @@ -2585,7 +2626,7 @@ private static byte[] getCertificateVerifyHeader(String contextString) } static void generateServerKeyExchangeSignature(TlsContext context, TlsCredentialedSigner credentials, - byte[] extraSignatureInput, DigestInputBuffer digestBuffer) throws IOException + DigestInputBuffer digestBuffer) throws IOException { /* * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 @@ -2596,12 +2637,12 @@ static void generateServerKeyExchangeSignature(TlsContext context, TlsCredential byte[] signature; if (streamSigner != null) { - sendSignatureInput(context, extraSignatureInput, digestBuffer, streamSigner.getOutputStream()); + sendSignatureInput(context, digestBuffer, streamSigner.getOutputStream()); signature = streamSigner.getSignature(); } else { - byte[] hash = calculateSignatureHash(context, algorithm, extraSignatureInput, digestBuffer); + byte[] hash = calculateSignatureHash(context, algorithm, digestBuffer); signature = credentials.generateRawSignature(hash); } @@ -2611,7 +2652,7 @@ static void generateServerKeyExchangeSignature(TlsContext context, TlsCredential } static void verifyServerKeyExchangeSignature(TlsContext context, InputStream signatureInput, - TlsCertificate serverCertificate, byte[] extraSignatureInput, DigestInputBuffer digestBuffer) + TlsCertificate serverCertificate, DigestInputBuffer digestBuffer) throws IOException { DigitallySigned digitallySigned = DigitallySigned.parse(context, signatureInput); @@ -2635,7 +2676,10 @@ static void verifyServerKeyExchangeSignature(TlsContext context, InputStream sig throw new TlsFatalAlert(AlertDescription.illegal_parameter); } - verifySupportedSignatureAlgorithm(securityParameters.getClientSigAlgs(), sigAndHashAlg); + verify12SignatureAlgorithm(sigAndHashAlg, AlertDescription.illegal_parameter); + + verifySupportedSignatureAlgorithm(securityParameters.getClientSigAlgs(), sigAndHashAlg, + AlertDescription.illegal_parameter); } TlsVerifier verifier = serverCertificate.createVerifier(signatureAlgorithm); @@ -2644,12 +2688,12 @@ static void verifyServerKeyExchangeSignature(TlsContext context, InputStream sig boolean verified; if (streamVerifier != null) { - sendSignatureInput(context, extraSignatureInput, digestBuffer, streamVerifier.getOutputStream()); + sendSignatureInput(context, digestBuffer, streamVerifier.getOutputStream()); verified = streamVerifier.isVerified(); } else { - byte[] hash = calculateSignatureHash(context, sigAndHashAlg, extraSignatureInput, digestBuffer); + byte[] hash = calculateSignatureHash(context, sigAndHashAlg, digestBuffer); verified = verifier.verifyRawSignature(digitallySigned, hash); } @@ -3052,6 +3096,12 @@ public static int getEncryptionAlgorithm(int cipherSuite) case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384: return EncryptionAlgorithm.NULL; + case CipherSuite.TLS_SHA256_SHA256: + return EncryptionAlgorithm.NULL_HMAC_SHA256; + + case CipherSuite.TLS_SHA384_SHA384: + return EncryptionAlgorithm.NULL_HMAC_SHA384; + case CipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA: case CipherSuite.TLS_DH_DSS_WITH_SEED_CBC_SHA: case CipherSuite.TLS_DH_RSA_WITH_SEED_CBC_SHA: @@ -3086,6 +3136,8 @@ public static int getEncryptionAlgorithmType(int encryptionAlgorithm) case EncryptionAlgorithm.CAMELLIA_128_GCM: case EncryptionAlgorithm.CAMELLIA_256_GCM: case EncryptionAlgorithm.CHACHA20_POLY1305: + case EncryptionAlgorithm.NULL_HMAC_SHA256: + case EncryptionAlgorithm.NULL_HMAC_SHA384: case EncryptionAlgorithm.SM4_CCM: case EncryptionAlgorithm.SM4_GCM: return CipherType.aead; @@ -3365,6 +3417,8 @@ public static int getKeyExchangeAlgorithm(int cipherSuite) case CipherSuite.TLS_AES_128_GCM_SHA256: case CipherSuite.TLS_AES_256_GCM_SHA384: case CipherSuite.TLS_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_SHA256_SHA256: + case CipherSuite.TLS_SHA384_SHA384: case CipherSuite.TLS_SM4_CCM_SM3: case CipherSuite.TLS_SM4_GCM_SM3: return KeyExchangeAlgorithm.NULL; @@ -3593,6 +3647,8 @@ public static int getMACAlgorithm(int cipherSuite) case CipherSuite.TLS_RSA_WITH_ARIA_256_GCM_SHA384: case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_SHA256_SHA256: + case CipherSuite.TLS_SHA384_SHA384: case CipherSuite.TLS_SM4_CCM_SM3: case CipherSuite.TLS_SM4_GCM_SM3: return MACAlgorithm._null; @@ -3792,6 +3848,8 @@ public static ProtocolVersion getMinimumVersion(int cipherSuite) case CipherSuite.TLS_AES_128_GCM_SHA256: case CipherSuite.TLS_AES_256_GCM_SHA384: case CipherSuite.TLS_CHACHA20_POLY1305_SHA256: + case CipherSuite.TLS_SHA256_SHA256: + case CipherSuite.TLS_SHA384_SHA384: case CipherSuite.TLS_SM4_CCM_SM3: case CipherSuite.TLS_SM4_GCM_SM3: return ProtocolVersion.TLSv13; @@ -4097,6 +4155,8 @@ public static boolean isValidCipherSuiteForSignatureAlgorithms(int cipherSuite, /** * @deprecated Use {@link #isValidVersionForCipherSuite(int, ProtocolVersion)} instead. */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public static boolean isValidCipherSuiteForVersion(int cipherSuite, ProtocolVersion version) { return isValidVersionForCipherSuite(cipherSuite, version); @@ -4341,6 +4401,8 @@ public static int[] getSupportedCipherSuites(TlsCrypto crypto, int[] suites) /** * @deprecated Use {@link #getSupportedCipherSuites(TlsCrypto, int[], int, int)} instead. */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public static int[] getSupportedCipherSuites(TlsCrypto crypto, int[] suites, int suitesCount) { return getSupportedCipherSuites(crypto, suites, 0, suitesCount); @@ -4449,6 +4511,17 @@ public static boolean isSupportedKeyExchange(TlsCrypto crypto, int keyExchangeAl } } + public static boolean isSupportedNamedGroup(TlsCrypto crypto, int namedGroup) + { + if (!NamedGroup.refersToASpecificHybrid(namedGroup)) + { + return crypto.hasNamedGroup(namedGroup); + } + + return crypto.hasNamedGroup(NamedGroup.getHybridFirst(namedGroup)) + && crypto.hasNamedGroup(NamedGroup.getHybridSecond(namedGroup)); + } + static boolean hasAnyRSASigAlgs(TlsCrypto crypto) { return crypto.hasSignatureAlgorithm(SignatureAlgorithm.rsa) @@ -5047,34 +5120,34 @@ static int[] truncate(int[] a, int n) static TlsCredentialedAgreement requireAgreementCredentials(TlsCredentials credentials) throws IOException { - if (!(credentials instanceof TlsCredentialedAgreement)) + if (credentials instanceof TlsCredentialedAgreement) { - throw new TlsFatalAlert(AlertDescription.internal_error); + return (TlsCredentialedAgreement)credentials; } - return (TlsCredentialedAgreement)credentials; + throw new TlsFatalAlert(AlertDescription.internal_error); } static TlsCredentialedDecryptor requireDecryptorCredentials(TlsCredentials credentials) throws IOException { - if (!(credentials instanceof TlsCredentialedDecryptor)) + if (credentials instanceof TlsCredentialedDecryptor) { - throw new TlsFatalAlert(AlertDescription.internal_error); + return (TlsCredentialedDecryptor)credentials; } - return (TlsCredentialedDecryptor)credentials; + throw new TlsFatalAlert(AlertDescription.internal_error); } static TlsCredentialedSigner requireSignerCredentials(TlsCredentials credentials) throws IOException { - if (!(credentials instanceof TlsCredentialedSigner)) + if (credentials instanceof TlsCredentialedSigner) { - throw new TlsFatalAlert(AlertDescription.internal_error); + return (TlsCredentialedSigner)credentials; } - return (TlsCredentialedSigner)credentials; + throw new TlsFatalAlert(AlertDescription.internal_error); } private static void checkClientCertificateType(CertificateRequest certificateRequest, short clientCertificateType, @@ -5175,7 +5248,7 @@ private static boolean isSafeRenegotiationServerCertificate(TlsClientContext cli } static TlsAuthentication receiveServerCertificate(TlsClientContext clientContext, TlsClient client, - ByteArrayInputStream buf, Hashtable serverExtensions) throws IOException + ByteArrayInputStream buf) throws IOException { SecurityParameters securityParameters = clientContext.getSecurityParametersHandshake(); if (KeyExchangeAlgorithm.isAnonymous(securityParameters.getKeyExchangeAlgorithm()) @@ -5219,7 +5292,7 @@ static TlsAuthentication receiveServerCertificate(TlsClientContext clientContext } static TlsAuthentication receive13ServerCertificate(TlsClientContext clientContext, TlsClient client, - ByteArrayInputStream buf, Hashtable serverExtensions) throws IOException + ByteArrayInputStream buf) throws IOException { SecurityParameters securityParameters = clientContext.getSecurityParametersHandshake(); if (null != securityParameters.getPeerCertificate()) @@ -5362,48 +5435,98 @@ private static void collectKeyShares(TlsCrypto crypto, int[] supportedGroups, Ve int supportedGroup = supportedGroups[i]; Integer supportedGroupElement = Integers.valueOf(supportedGroup); - if (!keyShareGroups.contains(supportedGroupElement) - || clientAgreements.containsKey(supportedGroupElement) - || !crypto.hasNamedGroup(supportedGroup)) + if (!keyShareGroups.contains(supportedGroupElement) || + clientAgreements.containsKey(supportedGroupElement)) { continue; } - TlsAgreement agreement = null; - if (NamedGroup.refersToAnECDHCurve(supportedGroup)) + TlsAgreement agreement = createKeyShare(crypto, supportedGroup, false); + if (agreement != null) + { + byte[] key_exchange = agreement.generateEphemeral(); + KeyShareEntry clientShare = new KeyShareEntry(supportedGroup, key_exchange); + + clientShares.addElement(clientShare); + clientAgreements.put(supportedGroupElement, agreement); + } + } + } + + static TlsAgreement createKeyShare(TlsCrypto crypto, int keyShareGroup, boolean isServer) + { + if (!NamedGroup.refersToASpecificHybrid(keyShareGroup)) + { + return createKeyShareSimple(crypto, keyShareGroup, isServer); + } + + int hybridFirst = NamedGroup.getHybridFirst(keyShareGroup); + TlsAgreement firstAgreement = createKeyShareSimple(crypto, hybridFirst, isServer); + if (firstAgreement == null) + { + return null; + } + + int hybridSecond = NamedGroup.getHybridSecond(keyShareGroup); + TlsAgreement secondAgreement = createKeyShareSimple(crypto, hybridSecond, isServer); + if (secondAgreement == null) + { + return null; + } + + int peerValueSplit = isServer + ? NamedGroup.getHybridSplitClientShare(hybridFirst) + : NamedGroup.getHybridSplitServerShare(hybridFirst); + + return new TlsHybridAgreement(crypto, firstAgreement, secondAgreement, peerValueSplit); + } + + private static TlsAgreement createKeyShareSimple(TlsCrypto crypto, int keyShareGroup, boolean isServer) + { + if (crypto.hasNamedGroup(keyShareGroup)) + { + if (NamedGroup.refersToAnECDHCurve(keyShareGroup)) { if (crypto.hasECDHAgreement()) { - agreement = crypto.createECDomain(new TlsECConfig(supportedGroup)).createECDH(); + return crypto.createECDomain(new TlsECConfig(keyShareGroup)).createECDH(); } } - else if (NamedGroup.refersToASpecificFiniteField(supportedGroup)) + else if (NamedGroup.refersToASpecificFiniteField(keyShareGroup)) { if (crypto.hasDHAgreement()) { - agreement = crypto.createDHDomain(new TlsDHConfig(supportedGroup, true)).createDH(); + return crypto.createDHDomain(new TlsDHConfig(keyShareGroup, true)).createDH(); } } - else if (NamedGroup.refersToASpecificKem(supportedGroup)) + else if (NamedGroup.refersToASpecificKem(keyShareGroup)) { if (crypto.hasKemAgreement()) { - agreement = crypto.createKemDomain(new TlsKemConfig(supportedGroup, false)).createKem(); + return crypto.createKemDomain(new TlsKemConfig(keyShareGroup, isServer)).createKem(); } } + } + return null; + } - if (null != agreement) + static KeyShareEntry findEarlyKeyShare(Vector clientShares, int keyShareGroup) + { + if (null != clientShares) + { + for (int i = 0; i < clientShares.size(); ++i) { - byte[] key_exchange = agreement.generateEphemeral(); - KeyShareEntry clientShare = new KeyShareEntry(supportedGroup, key_exchange); - - clientShares.addElement(clientShare); - clientAgreements.put(supportedGroupElement, agreement); + KeyShareEntry clientShare = (KeyShareEntry)clientShares.elementAt(i); + if (null != clientShare && clientShare.getNamedGroup() == keyShareGroup) + { + return clientShare; + } } } + return null; } - static KeyShareEntry selectKeyShare(Vector clientShares, int keyShareGroup) + static KeyShareEntry getRetryKeyShare(Vector clientShares, int keyShareGroup) { if (null != clientShares && 1 == clientShares.size()) { @@ -5416,77 +5539,58 @@ static KeyShareEntry selectKeyShare(Vector clientShares, int keyShareGroup) return null; } - static KeyShareEntry selectKeyShare(TlsCrypto crypto, ProtocolVersion negotiatedVersion, Vector clientShares, - int[] clientSupportedGroups, int[] serverSupportedGroups) + static int selectKeyShareGroup(TlsCrypto crypto, ProtocolVersion negotiatedVersion, + int[] clientSupportedGroups, int[] serverSupportedGroups, boolean useServerOrder) { - if (null != clientShares && !isNullOrEmpty(clientSupportedGroups) && !isNullOrEmpty(serverSupportedGroups)) + if (!isNullOrEmpty(clientSupportedGroups) && !isNullOrEmpty(serverSupportedGroups)) { - for (int i = 0; i < clientShares.size(); ++i) - { - KeyShareEntry clientShare = (KeyShareEntry)clientShares.elementAt(i); - - int group = clientShare.getNamedGroup(); - - if (!NamedGroup.canBeNegotiated(group, negotiatedVersion)) - { - continue; - } - - if (!Arrays.contains(serverSupportedGroups, group) || - !Arrays.contains(clientSupportedGroups, group)) - { - continue; - } + int[] ordered = useServerOrder ? serverSupportedGroups : clientSupportedGroups; + int[] unordered = useServerOrder ? clientSupportedGroups : serverSupportedGroups; - if (!crypto.hasNamedGroup(group)) - { - continue; - } + for (int i = 0; i < ordered.length; ++i) + { + int candidate = ordered[i]; - if ((NamedGroup.refersToAnECDHCurve(group) && crypto.hasECDHAgreement()) || - (NamedGroup.refersToASpecificFiniteField(group) && crypto.hasDHAgreement()) || - (NamedGroup.refersToASpecificKem(group) && crypto.hasKemAgreement())) + if (Arrays.contains(unordered, candidate) && + NamedGroup.canBeNegotiated(candidate, negotiatedVersion) && + supportsKeyShareGroup(crypto, candidate)) { - return clientShare; + return candidate; } } } - return null; + return -1; } - static int selectKeyShareGroup(TlsCrypto crypto, ProtocolVersion negotiatedVersion, - int[] clientSupportedGroups, int[] serverSupportedGroups) + private static boolean supportsKeyShareGroup(TlsCrypto crypto, int keyShareGroup) { - if (!isNullOrEmpty(clientSupportedGroups) && !isNullOrEmpty(serverSupportedGroups)) + if (!NamedGroup.refersToASpecificHybrid(keyShareGroup)) { - for (int i = 0; i < clientSupportedGroups.length; ++i) - { - int group = clientSupportedGroups[i]; - - if (!NamedGroup.canBeNegotiated(group, negotiatedVersion)) - { - continue; - } - - if (!Arrays.contains(serverSupportedGroups, group)) - { - continue; - } + return supportsKeyShareGroupSimple(crypto, keyShareGroup); + } - if (!crypto.hasNamedGroup(group)) - { - continue; - } + return supportsKeyShareGroupSimple(crypto, NamedGroup.getHybridFirst(keyShareGroup)) + && supportsKeyShareGroupSimple(crypto, NamedGroup.getHybridSecond(keyShareGroup)); + } - if ((NamedGroup.refersToAnECDHCurve(group) && crypto.hasECDHAgreement()) || - (NamedGroup.refersToASpecificFiniteField(group) && crypto.hasDHAgreement()) || - (NamedGroup.refersToASpecificKem(group) && crypto.hasKemAgreement())) - { - return group; - } + private static boolean supportsKeyShareGroupSimple(TlsCrypto crypto, int keyShareGroup) + { + if (crypto.hasNamedGroup(keyShareGroup)) + { + if (NamedGroup.refersToAnECDHCurve(keyShareGroup)) + { + return crypto.hasECDHAgreement(); + } + else if (NamedGroup.refersToASpecificFiniteField(keyShareGroup)) + { + return crypto.hasDHAgreement(); + } + else if (NamedGroup.refersToASpecificKem(keyShareGroup)) + { + return crypto.hasKemAgreement(); } } - return -1; + return false; } static byte[] readEncryptedPMS(TlsContext context, InputStream input) throws IOException @@ -6031,8 +6135,6 @@ static OfferedPsks.SelectedConfig selectPreSharedKey(TlsServerContext serverCont Hashtable clientHelloExtensions, HandshakeMessageInput clientHelloMessage, TlsHandshakeHash handshakeHash, boolean afterHelloRetryRequest) throws IOException { - boolean handshakeHashUpdated = false; - OfferedPsks offeredPsks = TlsExtensionsUtils.getPreSharedKeyClientHello(clientHelloExtensions); if (null != offeredPsks) { @@ -6042,8 +6144,14 @@ static OfferedPsks.SelectedConfig selectPreSharedKey(TlsServerContext serverCont throw new TlsFatalAlert(AlertDescription.missing_extension); } + // TODO[tls13] Fetch these from 'server' + short[] serverSupportedModes = { PskKeyExchangeMode.psk_dhe_ke }; + boolean useServerOrder = false; + + short selectedMode = selectPreSharedKeyMode(pskKeyExchangeModes, serverSupportedModes, useServerOrder); + // TODO[tls13] Add support for psk_ke? - if (Arrays.contains(pskKeyExchangeModes, PskKeyExchangeMode.psk_dhe_ke)) + if (PskKeyExchangeMode.psk_dhe_ke == selectedMode) { // TODO[tls13] Prefer to get the exact index from the server? TlsPSKExternal psk = server.getExternalPSK(offeredPsks.getIdentities()); @@ -6052,6 +6160,14 @@ static OfferedPsks.SelectedConfig selectPreSharedKey(TlsServerContext serverCont int index = offeredPsks.getIndexOfIdentity(new PskIdentity(psk.getIdentity(), 0L)); if (index >= 0) { + /* + * RFC 8446 4.2.11. Prior to accepting PSK key establishment, the server MUST validate the + * corresponding binder value [..]. If this value is not present or does not validate, the + * server MUST abort the handshake. Servers SHOULD NOT attempt to validate multiple + * binders; rather, they SHOULD select a single PSK and validate solely the binder that + * corresponds to that PSK. + */ + byte[] binder = (byte[])offeredPsks.getBinders().elementAt(index); TlsCrypto crypto = serverContext.getCrypto(); @@ -6063,7 +6179,6 @@ static OfferedPsks.SelectedConfig selectPreSharedKey(TlsServerContext serverCont byte[] transcriptHash; { - handshakeHashUpdated = true; int bindersSize = offeredPsks.getBindersSize(); clientHelloMessage.updateHashPrefix(handshakeHash, bindersSize); @@ -6084,21 +6199,41 @@ static OfferedPsks.SelectedConfig selectPreSharedKey(TlsServerContext serverCont byte[] calculatedBinder = calculatePSKBinder(crypto, isExternalPSK, pskCryptoHashAlgorithm, earlySecret, transcriptHash); - if (Arrays.constantTimeAreEqual(calculatedBinder, binder)) + if (!Arrays.constantTimeAreEqual(calculatedBinder, binder)) { - return new OfferedPsks.SelectedConfig(index, psk, pskKeyExchangeModes, earlySecret); + throw new TlsFatalAlert(AlertDescription.decrypt_error, "Invalid PSK binder"); } + + return new OfferedPsks.SelectedConfig(index, psk, pskKeyExchangeModes, earlySecret); } } } } - if (!handshakeHashUpdated) + clientHelloMessage.updateHash(handshakeHash); + return null; + } + + private static short selectPreSharedKeyMode(short[] clientSupportedModes, short[] serverSupportedModes, + boolean useServerOrder) + { + if (!isNullOrEmpty(clientSupportedModes) && !isNullOrEmpty(serverSupportedModes)) { - clientHelloMessage.updateHash(handshakeHash); - } + short[] ordered = useServerOrder ? serverSupportedModes : clientSupportedModes; + short[] unordered = useServerOrder ? clientSupportedModes : serverSupportedModes; - return null; + for (int i = 0; i < ordered.length; ++i) + { + short candidate = ordered[i]; + + if (Arrays.contains(unordered, candidate) && + PskKeyExchangeMode.isRecognized(candidate)) + { + return candidate; + } + } + } + return -1; } static TlsSecret getPSKEarlySecret(TlsCrypto crypto, TlsPSK psk) diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCrypto.java b/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCrypto.java index ff08bc607f..46b41a1d23 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCrypto.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCrypto.java @@ -146,6 +146,8 @@ public interface TlsCrypto */ boolean hasSRPAuthentication(); + TlsSecret createHybridSecret(TlsSecret s1, TlsSecret s2); + /** * Create a TlsSecret object based on provided data. * diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/TlsHybridAgreement.java b/tls/src/main/java/org/bouncycastle/tls/crypto/TlsHybridAgreement.java new file mode 100644 index 0000000000..88d06b0395 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/TlsHybridAgreement.java @@ -0,0 +1,48 @@ +package org.bouncycastle.tls.crypto; + +import java.io.IOException; + +import org.bouncycastle.util.Arrays; + +public class TlsHybridAgreement + implements TlsAgreement +{ + private final TlsCrypto crypto; + private final TlsAgreement firstAgreement; + private final TlsAgreement secondAgreement; + private final int peerValueSplit; + + public TlsHybridAgreement(TlsCrypto crypto, TlsAgreement firstAgreement, TlsAgreement secondAgreement, + int peerValueSplit) + { + this.crypto = crypto; + this.firstAgreement = firstAgreement; + this.secondAgreement = secondAgreement; + this.peerValueSplit = peerValueSplit; + } + + public byte[] generateEphemeral() throws IOException + { + byte[] firstEphemeral = firstAgreement.generateEphemeral(); + byte[] secondEphemeral = secondAgreement.generateEphemeral(); + return Arrays.concatenate(firstEphemeral, secondEphemeral); + } + + public void receivePeerValue(byte[] peerValue) throws IOException + { + if (peerValue.length < peerValueSplit) + { + throw new IllegalArgumentException("'peerValue' is too short"); + } + + this.firstAgreement.receivePeerValue(Arrays.copyOfRange(peerValue, 0, peerValueSplit)); + this.secondAgreement.receivePeerValue(Arrays.copyOfRange(peerValue, peerValueSplit, peerValue.length)); + } + + public TlsSecret calculateSecret() throws IOException + { + TlsSecret firstSecret = firstAgreement.calculateSecret(); + TlsSecret secondSecret = secondAgreement.calculateSecret(); + return crypto.createHybridSecret(firstSecret, secondSecret); + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/PQCUtil.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/PQCUtil.java new file mode 100644 index 0000000000..7d519af659 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/PQCUtil.java @@ -0,0 +1,145 @@ +package org.bouncycastle.tls.crypto.impl; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.pqc.crypto.mldsa.MLDSAParameters; +import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAParameters; +import org.bouncycastle.tls.SignatureScheme; + +public class PQCUtil +{ + public static ASN1ObjectIdentifier getMLDSAObjectidentifier(int signatureScheme) + { + switch (signatureScheme) + { + case SignatureScheme.mldsa44: + return NISTObjectIdentifiers.id_ml_dsa_44; + case SignatureScheme.mldsa65: + return NISTObjectIdentifiers.id_ml_dsa_65; + case SignatureScheme.mldsa87: + return NISTObjectIdentifiers.id_ml_dsa_87; + default: + throw new IllegalArgumentException(); + } + } + + public static int getMLDSASignatureScheme(MLDSAParameters parameters) + { + if (MLDSAParameters.ml_dsa_44 == parameters) + { + return SignatureScheme.mldsa44; + } + if (MLDSAParameters.ml_dsa_65 == parameters) + { + return SignatureScheme.mldsa65; + } + if (MLDSAParameters.ml_dsa_87 == parameters) + { + return SignatureScheme.mldsa87; + } + throw new IllegalArgumentException(); + } + + public static ASN1ObjectIdentifier getSLHDSAObjectidentifier(int signatureScheme) + { + switch (signatureScheme) + { + case SignatureScheme.DRAFT_slhdsa_sha2_128s: + return NISTObjectIdentifiers.id_slh_dsa_sha2_128s; + case SignatureScheme.DRAFT_slhdsa_sha2_128f: + return NISTObjectIdentifiers.id_slh_dsa_sha2_128f; + case SignatureScheme.DRAFT_slhdsa_sha2_192s: + return NISTObjectIdentifiers.id_slh_dsa_sha2_192s; + case SignatureScheme.DRAFT_slhdsa_sha2_192f: + return NISTObjectIdentifiers.id_slh_dsa_sha2_192f; + case SignatureScheme.DRAFT_slhdsa_sha2_256s: + return NISTObjectIdentifiers.id_slh_dsa_sha2_256s; + case SignatureScheme.DRAFT_slhdsa_sha2_256f: + return NISTObjectIdentifiers.id_slh_dsa_sha2_256f; + case SignatureScheme.DRAFT_slhdsa_shake_128s: + return NISTObjectIdentifiers.id_slh_dsa_shake_128s; + case SignatureScheme.DRAFT_slhdsa_shake_128f: + return NISTObjectIdentifiers.id_slh_dsa_shake_128f; + case SignatureScheme.DRAFT_slhdsa_shake_192s: + return NISTObjectIdentifiers.id_slh_dsa_shake_192s; + case SignatureScheme.DRAFT_slhdsa_shake_192f: + return NISTObjectIdentifiers.id_slh_dsa_shake_192f; + case SignatureScheme.DRAFT_slhdsa_shake_256s: + return NISTObjectIdentifiers.id_slh_dsa_shake_256s; + case SignatureScheme.DRAFT_slhdsa_shake_256f: + return NISTObjectIdentifiers.id_slh_dsa_shake_256f; + default: + throw new IllegalArgumentException(); + } + } + + public static int getSLHDSASignatureScheme(SLHDSAParameters parameters) + { + if (SLHDSAParameters.sha2_128s == parameters) + { + return SignatureScheme.DRAFT_slhdsa_sha2_128s; + } + if (SLHDSAParameters.sha2_128f == parameters) + { + return SignatureScheme.DRAFT_slhdsa_sha2_128f; + } + if (SLHDSAParameters.sha2_192s == parameters) + { + return SignatureScheme.DRAFT_slhdsa_sha2_192s; + } + if (SLHDSAParameters.sha2_192f == parameters) + { + return SignatureScheme.DRAFT_slhdsa_sha2_192f; + } + if (SLHDSAParameters.sha2_256s == parameters) + { + return SignatureScheme.DRAFT_slhdsa_sha2_256s; + } + if (SLHDSAParameters.sha2_256f == parameters) + { + return SignatureScheme.DRAFT_slhdsa_sha2_256f; + } + if (SLHDSAParameters.shake_128s == parameters) + { + return SignatureScheme.DRAFT_slhdsa_shake_128s; + } + if (SLHDSAParameters.shake_128f == parameters) + { + return SignatureScheme.DRAFT_slhdsa_shake_128f; + } + if (SLHDSAParameters.shake_192s == parameters) + { + return SignatureScheme.DRAFT_slhdsa_shake_192s; + } + if (SLHDSAParameters.shake_192f == parameters) + { + return SignatureScheme.DRAFT_slhdsa_shake_192f; + } + if (SLHDSAParameters.shake_256s == parameters) + { + return SignatureScheme.DRAFT_slhdsa_shake_256s; + } + if (SLHDSAParameters.shake_256f == parameters) + { + return SignatureScheme.DRAFT_slhdsa_shake_256f; + } + throw new IllegalArgumentException(); + } + + public static boolean supportsMLDSA(AlgorithmIdentifier pubKeyAlgID, ASN1ObjectIdentifier mlDsaAlgOid) + { + return hasOidWithNullParameters(pubKeyAlgID, mlDsaAlgOid); + } + + public static boolean supportsSLHDSA(AlgorithmIdentifier pubKeyAlgID, ASN1ObjectIdentifier slhDsaAlgOid) + { + return hasOidWithNullParameters(pubKeyAlgID, slhDsaAlgOid); + } + + private static boolean hasOidWithNullParameters(AlgorithmIdentifier algID, ASN1ObjectIdentifier algOid) + { + return algID.getAlgorithm().equals(algOid) + && algID.getParameters() == null; + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/RSAUtil.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/RSAUtil.java index 2a7a2ec815..94522f666d 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/RSAUtil.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/RSAUtil.java @@ -43,11 +43,11 @@ public class RSAUtil AlgorithmIdentifier mgf1SHA384Identifier_B = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, sha384Identifier_B); AlgorithmIdentifier mgf1SHA512Identifier_B = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, sha512Identifier_B); - ASN1Integer sha256Size = new ASN1Integer(TlsCryptoUtils.getHashOutputSize(CryptoHashAlgorithm.sha256)); - ASN1Integer sha384Size = new ASN1Integer(TlsCryptoUtils.getHashOutputSize(CryptoHashAlgorithm.sha384)); - ASN1Integer sha512Size = new ASN1Integer(TlsCryptoUtils.getHashOutputSize(CryptoHashAlgorithm.sha512)); + ASN1Integer sha256Size = ASN1Integer.valueOf(TlsCryptoUtils.getHashOutputSize(CryptoHashAlgorithm.sha256)); + ASN1Integer sha384Size = ASN1Integer.valueOf(TlsCryptoUtils.getHashOutputSize(CryptoHashAlgorithm.sha384)); + ASN1Integer sha512Size = ASN1Integer.valueOf(TlsCryptoUtils.getHashOutputSize(CryptoHashAlgorithm.sha512)); - ASN1Integer trailerField = new ASN1Integer(1); + ASN1Integer trailerField = RSASSAPSSparams.DEFAULT_TRAILER_FIELD; try { diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/Tls13NullCipher.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/Tls13NullCipher.java new file mode 100644 index 0000000000..f721f241ae --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/Tls13NullCipher.java @@ -0,0 +1,249 @@ +package org.bouncycastle.tls.crypto.impl; + +import java.io.IOException; + +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.ContentType; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SecurityParameters; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCipher; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsCryptoUtils; +import org.bouncycastle.tls.crypto.TlsDecodeResult; +import org.bouncycastle.tls.crypto.TlsEncodeResult; +import org.bouncycastle.tls.crypto.TlsHMAC; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Bytes; + +/** + * A generic TLS 1.3 "integrity-only" cipher. + */ +public final class Tls13NullCipher + implements TlsCipher +{ + private final TlsCryptoParameters cryptoParams; + + private final TlsHMAC readHMAC, writeHMAC; + private final byte[] readNonce, writeNonce; + + public Tls13NullCipher(TlsCryptoParameters cryptoParams, TlsHMAC readHMAC, TlsHMAC writeHMAC) + throws IOException + { + final SecurityParameters securityParameters = cryptoParams.getSecurityParametersHandshake(); + + if (!TlsImplUtils.isTLSv13(securityParameters.getNegotiatedVersion())) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + this.cryptoParams = cryptoParams; + this.readHMAC = readHMAC; + this.writeHMAC = writeHMAC; + + this.readNonce = new byte[readHMAC.getMacLength()]; + this.writeNonce = new byte[writeHMAC.getMacLength()]; + + final boolean isServer = cryptoParams.isServer(); + rekeyHmac(securityParameters, readHMAC, readNonce, !isServer); + rekeyHmac(securityParameters, writeHMAC, writeNonce, isServer); + } + + public int getCiphertextDecodeLimit(int plaintextLimit) + { + return plaintextLimit + 1 + readHMAC.getMacLength(); + } + + public int getCiphertextEncodeLimit(int plaintextLimit) + { + return plaintextLimit + 1 + writeHMAC.getMacLength(); + } + + public int getPlaintextDecodeLimit(int ciphertextLimit) + { + return ciphertextLimit - readHMAC.getMacLength() - 1; + } + + public int getPlaintextEncodeLimit(int ciphertextLimit) + { + return ciphertextLimit - writeHMAC.getMacLength() - 1; + } + + public TlsEncodeResult encodePlaintext(long seqNo, short contentType, ProtocolVersion recordVersion, + int headerAllocation, byte[] plaintext, int plaintextOffset, int plaintextLength) throws IOException + { + int macLength = writeHMAC.getMacLength(); + + // TODO Possibly redundant if we reset after any failures (i.e. DTLS) + writeHMAC.reset(); + + byte[] nonce = createRecordNonce(writeNonce, seqNo); + writeHMAC.update(nonce, 0, nonce.length); + + // TODO[tls13, cid] If we support adding padding to (D)TLSInnerPlaintext, this will need review + int innerPlaintextLength = plaintextLength + 1; + int ciphertextLength = innerPlaintextLength + macLength; + byte[] output = new byte[headerAllocation + ciphertextLength]; + int outputPos = headerAllocation; + + short recordType = ContentType.application_data; + + byte[] additionalData = getAdditionalData(seqNo, recordType, recordVersion, ciphertextLength); + + try + { + System.arraycopy(plaintext, plaintextOffset, output, outputPos, plaintextLength); + output[outputPos + plaintextLength] = (byte)contentType; + + writeHMAC.update(additionalData, 0, additionalData.length); + writeHMAC.update(output, outputPos, innerPlaintextLength); + writeHMAC.calculateMAC(output, outputPos + innerPlaintextLength); + outputPos += innerPlaintextLength + macLength; + } + catch (RuntimeException e) + { + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + + if (outputPos != output.length) + { + // NOTE: The additional data mechanism for AEAD ciphers requires exact output size prediction. + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + return new TlsEncodeResult(output, 0, output.length, recordType); + } + + public TlsDecodeResult decodeCiphertext(long seqNo, short recordType, ProtocolVersion recordVersion, + byte[] ciphertext, int ciphertextOffset, int ciphertextLength) throws IOException + { + int macLength = readHMAC.getMacLength(); + + int innerPlaintextLength = ciphertextLength - macLength; + if (innerPlaintextLength < 1) + { + throw new TlsFatalAlert(AlertDescription.decode_error); + } + + // TODO Possibly redundant if we reset after any failures (i.e. DTLS) + readHMAC.reset(); + + byte[] nonce = createRecordNonce(readNonce, seqNo); + readHMAC.update(nonce, 0, nonce.length); + + byte[] additionalData = getAdditionalData(seqNo, recordType, recordVersion, ciphertextLength); + + try + { + readHMAC.update(additionalData, 0, additionalData.length); + readHMAC.update(ciphertext, ciphertextOffset, innerPlaintextLength); + byte[] calculated = readHMAC.calculateMAC(); + if (!Arrays.constantTimeAreEqual(macLength, calculated, 0, ciphertext, ciphertextOffset + innerPlaintextLength)) + { + throw new TlsFatalAlert(AlertDescription.bad_record_mac); + } + } + catch (RuntimeException e) + { + throw new TlsFatalAlert(AlertDescription.bad_record_mac, e); + } + + short contentType = recordType; + int plaintextLength = innerPlaintextLength; + + // Strip padding and read true content type from TLSInnerPlaintext + for (;;) + { + if (--plaintextLength < 0) + { + throw new TlsFatalAlert(AlertDescription.unexpected_message); + } + + byte octet = ciphertext[ciphertextOffset + plaintextLength]; + if (0 != octet) + { + contentType = (short)(octet & 0xFF); + break; + } + } + + return new TlsDecodeResult(ciphertext, ciphertextOffset, plaintextLength, contentType); + } + + public void rekeyDecoder() throws IOException + { + rekeyHmac(cryptoParams.getSecurityParametersConnection(), readHMAC, readNonce, !cryptoParams.isServer()); + } + + public void rekeyEncoder() throws IOException + { + rekeyHmac(cryptoParams.getSecurityParametersConnection(), writeHMAC, writeNonce, cryptoParams.isServer()); + } + + public boolean usesOpaqueRecordTypeDecode() + { + return true; + } + + public boolean usesOpaqueRecordTypeEncode() + { + return true; + } + + private void rekeyHmac(SecurityParameters securityParameters, TlsHMAC hmac, byte[] nonce, boolean serverSecret) + throws IOException + { + TlsSecret secret = serverSecret + ? securityParameters.getTrafficSecretServer() + : securityParameters.getTrafficSecretClient(); + + // TODO[tls13] For early data, have to disable server->client + if (null == secret) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + setupHmac(hmac, nonce, secret, securityParameters.getPRFCryptoHashAlgorithm()); + } + + private void setupHmac(TlsHMAC hmac, byte[] nonce, TlsSecret secret, int cryptoHashAlgorithm) + throws IOException + { + int length = hmac.getMacLength(); + byte[] key = hkdfExpandLabel(secret, cryptoHashAlgorithm, "key", length).extract(); + byte[] iv = hkdfExpandLabel(secret, cryptoHashAlgorithm, "iv", length).extract(); + + hmac.setKey(key, 0, length); + System.arraycopy(iv, 0, nonce, 0, length); + } + + private static byte[] createRecordNonce(byte[] fixedNonce, long seqNo) + { + int nonceLength = fixedNonce.length; + byte[] nonce = new byte[nonceLength]; + TlsUtils.writeUint64(seqNo, nonce, nonceLength - 8); + Bytes.xorTo(nonceLength, fixedNonce, nonce); + return nonce; + } + + private static byte[] getAdditionalData(long seqNo, short recordType, ProtocolVersion recordVersion, + int ciphertextLength) throws IOException + { + /* + * TLSCiphertext.opaque_type || TLSCiphertext.legacy_record_version || TLSCiphertext.length + */ + byte[] additional_data = new byte[5]; + TlsUtils.writeUint8(recordType, additional_data, 0); + TlsUtils.writeVersion(recordVersion, additional_data, 1); + TlsUtils.writeUint16(ciphertextLength, additional_data, 3); + return additional_data; + } + + private static TlsSecret hkdfExpandLabel(TlsSecret secret, int cryptoHashAlgorithm, String label, int length) + throws IOException + { + return TlsCryptoUtils.hkdfExpandLabel(secret, cryptoHashAlgorithm, label, TlsUtils.EMPTY_BYTES, length); + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsAEADCipher.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsAEADCipher.java index 8ac3ccec6b..92cad80395 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsAEADCipher.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsAEADCipher.java @@ -47,7 +47,9 @@ public final class TlsAEADCipher private final int nonceMode; private final AEADNonceGenerator nonceGenerator; - /** @deprecated Use version with extra 'nonceGeneratorFactory' parameter */ + /** @deprecated Use version with extra 'nonceGeneratorFactory' parameter */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public TlsAEADCipher(TlsCryptoParameters cryptoParams, TlsAEADCipherImpl encryptCipher, TlsAEADCipherImpl decryptCipher, int keySize, int macSize, int aeadType) throws IOException { @@ -434,8 +436,8 @@ private void rekeyCipher(SecurityParameters securityParameters, TlsAEADCipherImp private void setup13Cipher(TlsAEADCipherImpl cipher, byte[] nonce, TlsSecret secret, int cryptoHashAlgorithm) throws IOException { - byte[] key = TlsCryptoUtils.hkdfExpandLabel(secret, cryptoHashAlgorithm, "key", TlsUtils.EMPTY_BYTES, keySize).extract(); - byte[] iv = TlsCryptoUtils.hkdfExpandLabel(secret, cryptoHashAlgorithm, "iv", TlsUtils.EMPTY_BYTES, fixed_iv_length).extract(); + byte[] key = hkdfExpandLabel(secret, cryptoHashAlgorithm, "key", keySize).extract(); + byte[] iv = hkdfExpandLabel(secret, cryptoHashAlgorithm, "iv", fixed_iv_length).extract(); cipher.setKey(key, 0, keySize); System.arraycopy(iv, 0, nonce, 0, fixed_iv_length); @@ -456,4 +458,10 @@ private static int getNonceMode(boolean isTLSv13, int aeadType) throws IOExcepti throw new TlsFatalAlert(AlertDescription.internal_error); } } + + private static TlsSecret hkdfExpandLabel(TlsSecret secret, int cryptoHashAlgorithm, String label, int length) + throws IOException + { + return TlsCryptoUtils.hkdfExpandLabel(secret, cryptoHashAlgorithm, label, TlsUtils.EMPTY_BYTES, length); + } } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedSigner.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedSigner.java index 82b6dc79ac..a0d0c637aa 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedSigner.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedSigner.java @@ -6,6 +6,8 @@ import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; import org.bouncycastle.crypto.params.Ed448PrivateKeyParameters; import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.pqc.crypto.mldsa.MLDSAPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPrivateKeyParameters; import org.bouncycastle.tls.Certificate; import org.bouncycastle.tls.DefaultTlsCredentialedSigner; import org.bouncycastle.tls.SignatureAndHashAlgorithm; @@ -22,7 +24,6 @@ public class BcDefaultTlsCredentialedSigner private static TlsSigner makeSigner(BcTlsCrypto crypto, AsymmetricKeyParameter privateKey, Certificate certificate, SignatureAndHashAlgorithm signatureAndHashAlgorithm) { - TlsSigner signer; if (privateKey instanceof RSAKeyParameters) { RSAKeyParameters privKeyRSA = (RSAKeyParameters)privateKey; @@ -36,11 +37,11 @@ private static TlsSigner makeSigner(BcTlsCrypto crypto, AsymmetricKeyParameter p } } - signer = new BcTlsRSASigner(crypto, privKeyRSA); + return new BcTlsRSASigner(crypto, privKeyRSA); } else if (privateKey instanceof DSAPrivateKeyParameters) { - signer = new BcTlsDSASigner(crypto, (DSAPrivateKeyParameters)privateKey); + return new BcTlsDSASigner(crypto, (DSAPrivateKeyParameters)privateKey); } else if (privateKey instanceof ECPrivateKeyParameters) { @@ -63,22 +64,48 @@ else if (privateKey instanceof ECPrivateKeyParameters) } } - signer = new BcTlsECDSASigner(crypto, privKeyEC); + return new BcTlsECDSASigner(crypto, privKeyEC); } else if (privateKey instanceof Ed25519PrivateKeyParameters) { - signer = new BcTlsEd25519Signer(crypto, (Ed25519PrivateKeyParameters)privateKey); + return new BcTlsEd25519Signer(crypto, (Ed25519PrivateKeyParameters)privateKey); } else if (privateKey instanceof Ed448PrivateKeyParameters) { - signer = new BcTlsEd448Signer(crypto, (Ed448PrivateKeyParameters)privateKey); + return new BcTlsEd448Signer(crypto, (Ed448PrivateKeyParameters)privateKey); + } + else if (privateKey instanceof MLDSAPrivateKeyParameters) + { + if (signatureAndHashAlgorithm != null) + { + TlsSigner signer = BcTlsMLDSASigner.create(crypto, (MLDSAPrivateKeyParameters)privateKey, + SignatureScheme.from(signatureAndHashAlgorithm)); + if (signer != null) + { + return signer; + } + } + + throw new IllegalArgumentException("ML-DSA private key of wrong type for signature algorithm"); + } + else if (privateKey instanceof SLHDSAPrivateKeyParameters) + { + if (signatureAndHashAlgorithm != null) + { + TlsSigner signer = BcTlsSLHDSASigner.create(crypto, (SLHDSAPrivateKeyParameters)privateKey, + SignatureScheme.from(signatureAndHashAlgorithm)); + if (signer != null) + { + return signer; + } + } + + throw new IllegalArgumentException("SLH-DSA private key of wrong type for signature algorithm"); } else { throw new IllegalArgumentException("'privateKey' type not supported: " + privateKey.getClass().getName()); } - - return signer; } public BcDefaultTlsCredentialedSigner(TlsCryptoParameters cryptoParams, BcTlsCrypto crypto, diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java index 9207c2f544..0fc1642150 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java @@ -64,6 +64,7 @@ import org.bouncycastle.tls.crypto.TlsSRPConfig; import org.bouncycastle.tls.crypto.TlsSecret; import org.bouncycastle.tls.crypto.impl.AbstractTlsCrypto; +import org.bouncycastle.tls.crypto.impl.Tls13NullCipher; import org.bouncycastle.tls.crypto.impl.TlsAEADCipher; import org.bouncycastle.tls.crypto.impl.TlsBlockCipher; import org.bouncycastle.tls.crypto.impl.TlsImplUtils; @@ -178,6 +179,12 @@ public TlsCipher createCipher(TlsCryptoParameters cryptoParams, int encryptionAl return createChaCha20Poly1305(cryptoParams); case EncryptionAlgorithm.NULL: return createNullCipher(cryptoParams, macAlgorithm); + case EncryptionAlgorithm.NULL_HMAC_SHA256: + // NOTE: Ignores macAlgorithm + return create13NullCipher(cryptoParams, MACAlgorithm.hmac_sha256); + case EncryptionAlgorithm.NULL_HMAC_SHA384: + // NOTE: Ignores macAlgorithm + return create13NullCipher(cryptoParams, MACAlgorithm.hmac_sha384); case EncryptionAlgorithm.SM4_CCM: // NOTE: Ignores macAlgorithm return createCipher_SM4_CCM(cryptoParams); @@ -345,6 +352,12 @@ public boolean hasEncryptionAlgorithm(int encryptionAlgorithm) case EncryptionAlgorithm.SM4_GCM: return true; + case EncryptionAlgorithm.NULL_HMAC_SHA256: + return hasMacAlgorithm(MACAlgorithm.hmac_sha256); + + case EncryptionAlgorithm.NULL_HMAC_SHA384: + return hasMacAlgorithm(MACAlgorithm.hmac_sha384); + case EncryptionAlgorithm._28147_CNT_IMIT: case EncryptionAlgorithm.DES_CBC: case EncryptionAlgorithm.DES40_CBC: @@ -397,7 +410,9 @@ public boolean hasMacAlgorithm(int macAlgorithm) public boolean hasNamedGroup(int namedGroup) { - return NamedGroup.refersToASpecificGroup(namedGroup); + return NamedGroup.refersToASpecificCurve(namedGroup) + || NamedGroup.refersToASpecificFiniteField(namedGroup) + || NamedGroup.refersToASpecificKem(namedGroup); } public boolean hasRSAEncryption() @@ -439,6 +454,13 @@ public boolean hasSignatureAlgorithm(short signatureAlgorithm) public boolean hasSignatureAndHashAlgorithm(SignatureAndHashAlgorithm sigAndHashAlgorithm) { + int signatureScheme = SignatureScheme.from(sigAndHashAlgorithm); + if (SignatureScheme.isMLDSA(signatureScheme) || + SignatureScheme.isSLHDSA(signatureScheme)) + { + return hasSignatureScheme(signatureScheme); + } + short signature = sigAndHashAlgorithm.getSignature(); switch (sigAndHashAlgorithm.getHash()) @@ -456,6 +478,22 @@ public boolean hasSignatureScheme(int signatureScheme) { case SignatureScheme.sm2sig_sm3: return false; + case SignatureScheme.mldsa44: + case SignatureScheme.mldsa65: + case SignatureScheme.mldsa87: + case SignatureScheme.DRAFT_slhdsa_sha2_128s: + case SignatureScheme.DRAFT_slhdsa_sha2_128f: + case SignatureScheme.DRAFT_slhdsa_sha2_192s: + case SignatureScheme.DRAFT_slhdsa_sha2_192f: + case SignatureScheme.DRAFT_slhdsa_sha2_256s: + case SignatureScheme.DRAFT_slhdsa_sha2_256f: + case SignatureScheme.DRAFT_slhdsa_shake_128s: + case SignatureScheme.DRAFT_slhdsa_shake_128f: + case SignatureScheme.DRAFT_slhdsa_shake_192s: + case SignatureScheme.DRAFT_slhdsa_shake_192f: + case SignatureScheme.DRAFT_slhdsa_shake_256s: + case SignatureScheme.DRAFT_slhdsa_shake_256f: + return true; default: { short signature = SignatureScheme.getSignatureAlgorithm(signatureScheme); @@ -476,6 +514,11 @@ public boolean hasSRPAuthentication() return true; } + public TlsSecret createHybridSecret(TlsSecret s1, TlsSecret s2) + { + return adoptLocalSecret(Arrays.concatenate(s1.extract(), s2.extract())); + } + public TlsSecret createSecret(byte[] data) { try @@ -664,6 +707,12 @@ protected TlsAEADCipher createCipher_SM4_GCM(TlsCryptoParameters cryptoParams) return new TlsAEADCipher(cryptoParams, encrypt, decrypt, 16, 16, TlsAEADCipher.AEAD_GCM, null); } + protected Tls13NullCipher create13NullCipher(TlsCryptoParameters cryptoParams, int macAlgorithm) + throws IOException + { + return new Tls13NullCipher(cryptoParams, createHMAC(macAlgorithm), createHMAC(macAlgorithm)); + } + protected TlsNullCipher createNullCipher(TlsCryptoParameters cryptoParams, int macAlgorithm) throws IOException { @@ -703,7 +752,7 @@ protected BlockCipher createSM4Engine() protected AEADBlockCipher createCCMMode(BlockCipher engine) { - return new CCMBlockCipher(engine); + return CCMBlockCipher.newInstance(engine); } protected AEADBlockCipher createGCMMode(BlockCipher engine) diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDHDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDHDomain.java index 9a66fa2e97..34567de251 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDHDomain.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsDHDomain.java @@ -57,20 +57,20 @@ public static DHParameters getDomainParameters(TlsDHConfig dhConfig) return new DHParameters(dhGroup.getP(), dhGroup.getG(), dhGroup.getQ(), dhGroup.getL()); } - protected BcTlsCrypto crypto; - protected TlsDHConfig config; - protected DHParameters domainParameters; + protected final BcTlsCrypto crypto; + protected final DHParameters domainParameters; + protected final boolean isPadded; public BcTlsDHDomain(BcTlsCrypto crypto, TlsDHConfig dhConfig) { this.crypto = crypto; - this.config = dhConfig; this.domainParameters = getDomainParameters(dhConfig); + this.isPadded = dhConfig.isPadded(); } public BcTlsSecret calculateDHAgreement(DHPrivateKeyParameters privateKey, DHPublicKeyParameters publicKey) { - return calculateDHAgreement(crypto, privateKey, publicKey, config.isPadded()); + return calculateDHAgreement(crypto, privateKey, publicKey, isPadded); } public TlsAgreement createDH() @@ -80,7 +80,7 @@ public TlsAgreement createDH() public BigInteger decodeParameter(byte[] encoding) throws IOException { - if (config.isPadded() && getValueLength(domainParameters) != encoding.length) + if (isPadded && getValueLength(domainParameters) != encoding.length) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } @@ -109,7 +109,7 @@ public DHPublicKeyParameters decodePublicKey(byte[] encoding) throws IOException public byte[] encodeParameter(BigInteger x) { - return encodeValue(domainParameters, config.isPadded(), x); + return encodeValue(domainParameters, isPadded, x); } public byte[] encodePublicKey(DHPublicKeyParameters publicKey) diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDomain.java index 0714878296..2aab2663fb 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDomain.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsECDomain.java @@ -79,13 +79,11 @@ public static ECDomainParameters getDomainParameters(int namedGroup) } protected final BcTlsCrypto crypto; - protected final TlsECConfig config; protected final ECDomainParameters domainParameters; public BcTlsECDomain(BcTlsCrypto crypto, TlsECConfig ecConfig) { this.crypto = crypto; - this.config = ecConfig; this.domainParameters = getDomainParameters(ecConfig); } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsEd25519Signer.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsEd25519Signer.java index cdf6ec4fcc..de3df46357 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsEd25519Signer.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsEd25519Signer.java @@ -1,7 +1,5 @@ package org.bouncycastle.tls.crypto.impl.bc; -import java.io.IOException; - import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; import org.bouncycastle.crypto.signers.Ed25519Signer; import org.bouncycastle.tls.SignatureAndHashAlgorithm; @@ -16,11 +14,6 @@ public BcTlsEd25519Signer(BcTlsCrypto crypto, Ed25519PrivateKeyParameters privat super(crypto, privateKey); } - public byte[] generateRawSignature(SignatureAndHashAlgorithm algorithm, byte[] hash) throws IOException - { - throw new UnsupportedOperationException(); - } - public TlsStreamSigner getStreamSigner(SignatureAndHashAlgorithm algorithm) { if (algorithm == null || SignatureScheme.from(algorithm) != SignatureScheme.ed25519) diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsEd448Signer.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsEd448Signer.java index a6decb17cc..e7810861ce 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsEd448Signer.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsEd448Signer.java @@ -1,7 +1,5 @@ package org.bouncycastle.tls.crypto.impl.bc; -import java.io.IOException; - import org.bouncycastle.crypto.params.Ed448PrivateKeyParameters; import org.bouncycastle.crypto.signers.Ed448Signer; import org.bouncycastle.tls.SignatureAndHashAlgorithm; @@ -17,11 +15,6 @@ public BcTlsEd448Signer(BcTlsCrypto crypto, Ed448PrivateKeyParameters privateKey super(crypto, privateKey); } - public byte[] generateRawSignature(SignatureAndHashAlgorithm algorithm, byte[] hash) throws IOException - { - throw new UnsupportedOperationException(); - } - public TlsStreamSigner getStreamSigner(SignatureAndHashAlgorithm algorithm) { if (algorithm == null || SignatureScheme.from(algorithm) != SignatureScheme.ed448) diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLDSASigner.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLDSASigner.java new file mode 100644 index 0000000000..97cb03b817 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLDSASigner.java @@ -0,0 +1,53 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.pqc.crypto.mldsa.MLDSAPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.mldsa.MLDSASigner; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.SignatureScheme; +import org.bouncycastle.tls.crypto.TlsStreamSigner; +import org.bouncycastle.tls.crypto.impl.PQCUtil; + +public class BcTlsMLDSASigner + extends BcTlsSigner +{ + public static BcTlsMLDSASigner create(BcTlsCrypto crypto, MLDSAPrivateKeyParameters privateKey, int signatureScheme) + { + if (signatureScheme != PQCUtil.getMLDSASignatureScheme(privateKey.getParameters())) + { + return null; + } + + return new BcTlsMLDSASigner(crypto, privateKey, signatureScheme); + } + + private final int signatureScheme; + + private BcTlsMLDSASigner(BcTlsCrypto crypto, MLDSAPrivateKeyParameters privateKey, int signatureScheme) + { + super(crypto, privateKey); + + if (!SignatureScheme.isMLDSA(signatureScheme)) + { + throw new IllegalArgumentException("signatureScheme"); + } + + this.signatureScheme = signatureScheme; + } + + public TlsStreamSigner getStreamSigner(SignatureAndHashAlgorithm algorithm) + { + if (algorithm == null || SignatureScheme.from(algorithm) != signatureScheme) + { + throw new IllegalStateException("Invalid algorithm: " + algorithm); + } + + /* + * draft-ietf-tls-mldsa-00 3. The context parameter [..] MUST be the empty string. + */ + MLDSASigner signer = new MLDSASigner(); + signer.init(true, new ParametersWithRandom(privateKey, crypto.getSecureRandom())); + + return new BcTlsStreamSigner(signer); + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLKemDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLKemDomain.java index 4b2fc43294..bda0607a85 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLKemDomain.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMLKemDomain.java @@ -35,14 +35,12 @@ public static MLKEMParameters getDomainParameters(TlsKemConfig kemConfig) } protected final BcTlsCrypto crypto; - protected final TlsKemConfig config; protected final MLKEMParameters domainParameters; protected final boolean isServer; public BcTlsMLKemDomain(BcTlsCrypto crypto, TlsKemConfig kemConfig) { this.crypto = crypto; - this.config = kemConfig; this.domainParameters = getDomainParameters(kemConfig); this.isServer = kemConfig.isServer(); } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsRawKeyCertificate.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsRawKeyCertificate.java index b975a720ba..2e61441fdf 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsRawKeyCertificate.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsRawKeyCertificate.java @@ -26,6 +26,11 @@ import org.bouncycastle.crypto.signers.PSSSigner; import org.bouncycastle.crypto.signers.RSADigestSigner; import org.bouncycastle.crypto.util.PublicKeyFactory; +import org.bouncycastle.pqc.crypto.MessageSignerAdapter; +import org.bouncycastle.pqc.crypto.mldsa.MLDSAPublicKeyParameters; +import org.bouncycastle.pqc.crypto.mldsa.MLDSASigner; +import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPublicKeyParameters; +import org.bouncycastle.pqc.crypto.slhdsa.SLHDSASigner; import org.bouncycastle.tls.AlertDescription; import org.bouncycastle.tls.HashAlgorithm; import org.bouncycastle.tls.SignatureAlgorithm; @@ -39,6 +44,7 @@ import org.bouncycastle.tls.crypto.TlsEncryptor; import org.bouncycastle.tls.crypto.TlsVerifier; import org.bouncycastle.tls.crypto.impl.LegacyTls13Verifier; +import org.bouncycastle.tls.crypto.impl.PQCUtil; import org.bouncycastle.tls.crypto.impl.RSAUtil; /** @@ -247,6 +253,45 @@ public Tls13Verifier createVerifier(int signatureScheme) throws IOException // return new BcTls13Verifier(verifier); // } + case SignatureScheme.mldsa44: + case SignatureScheme.mldsa65: + case SignatureScheme.mldsa87: + { + ASN1ObjectIdentifier mlDsaAlgOid = PQCUtil.getMLDSAObjectidentifier(signatureScheme); + validateMLDSA(mlDsaAlgOid); + + MLDSAPublicKeyParameters publicKey = getPubKeyMLDSA(); + + MLDSASigner verifier = new MLDSASigner(); + verifier.init(false, publicKey); + + return new BcTls13Verifier(verifier); + } + + case SignatureScheme.DRAFT_slhdsa_sha2_128s: + case SignatureScheme.DRAFT_slhdsa_sha2_128f: + case SignatureScheme.DRAFT_slhdsa_sha2_192s: + case SignatureScheme.DRAFT_slhdsa_sha2_192f: + case SignatureScheme.DRAFT_slhdsa_sha2_256s: + case SignatureScheme.DRAFT_slhdsa_sha2_256f: + case SignatureScheme.DRAFT_slhdsa_shake_128s: + case SignatureScheme.DRAFT_slhdsa_shake_128f: + case SignatureScheme.DRAFT_slhdsa_shake_192s: + case SignatureScheme.DRAFT_slhdsa_shake_192f: + case SignatureScheme.DRAFT_slhdsa_shake_256s: + case SignatureScheme.DRAFT_slhdsa_shake_256f: + { + ASN1ObjectIdentifier slhDsaAlgOid = PQCUtil.getSLHDSAObjectidentifier(signatureScheme); + validateSLHDSA(slhDsaAlgOid); + + SLHDSAPublicKeyParameters publicKey = getPubKeySLHDSA(); + + SLHDSASigner verifier = new SLHDSASigner(); + verifier.init(false, publicKey); + + return new BcTls13Verifier(new MessageSignerAdapter(verifier)); + } + default: throw new TlsFatalAlert(AlertDescription.internal_error); } @@ -387,6 +432,43 @@ public Ed448PublicKeyParameters getPubKeyEd448() throws IOException } } + public MLDSAPublicKeyParameters getPubKeyMLDSA() throws IOException + { + try + { + return (MLDSAPublicKeyParameters)getPQCPublicKey(); + } + catch (ClassCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, "Public key not ML-DSA", e); + } + } + + public SLHDSAPublicKeyParameters getPubKeySLHDSA() throws IOException + { + try + { + return (SLHDSAPublicKeyParameters)getPQCPublicKey(); + } + catch (ClassCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, "Public key not SLH-DSA", e); + } + } + + protected AsymmetricKeyParameter getPQCPublicKey() throws IOException + { + try + { + return org.bouncycastle.pqc.crypto.util.PublicKeyFactory.createKey(keyInfo); + } + catch (RuntimeException e) + { + throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e); + } + } + + public RSAKeyParameters getPubKeyRSA() throws IOException { try @@ -448,6 +530,12 @@ protected boolean supportsKeyUsage(int keyUsageBit) return true; } + protected boolean supportsMLDSA(ASN1ObjectIdentifier mlDsaAlgOid) + { + AlgorithmIdentifier pubKeyAlgID = keyInfo.getAlgorithm(); + return PQCUtil.supportsMLDSA(pubKeyAlgID, mlDsaAlgOid); + } + protected boolean supportsRSA_PKCS1() { AlgorithmIdentifier pubKeyAlgID = keyInfo.getAlgorithm(); @@ -466,6 +554,12 @@ protected boolean supportsRSA_PSS_RSAE() return RSAUtil.supportsPSS_RSAE(pubKeyAlgID); } + protected boolean supportsSLHDSA(ASN1ObjectIdentifier slhDsaAlgOid) + { + AlgorithmIdentifier pubKeyAlgID = keyInfo.getAlgorithm(); + return PQCUtil.supportsSLHDSA(pubKeyAlgID, slhDsaAlgOid); + } + protected boolean supportsSignatureAlgorithm(short signatureAlgorithm, int keyUsage) throws IOException { if (!supportsKeyUsage(keyUsage)) @@ -539,6 +633,15 @@ public void validateKeyUsage(int keyUsageBit) } } + protected void validateMLDSA(ASN1ObjectIdentifier mlDsaAlgOid) + throws IOException + { + if (!supportsMLDSA(mlDsaAlgOid)) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, "No support for ML-DSA signature scheme"); + } + } + protected void validateRSA_PKCS1() throws IOException { @@ -567,4 +670,13 @@ protected void validateRSA_PSS_RSAE() "No support for rsa_pss_rsae signature schemes"); } } + + protected void validateSLHDSA(ASN1ObjectIdentifier slhDsaAlgOid) + throws IOException + { + if (!supportsSLHDSA(slhDsaAlgOid)) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, "No support for SLH-DSA signature scheme"); + } + } } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSLHDSASigner.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSLHDSASigner.java new file mode 100644 index 0000000000..fb2f8dba52 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSLHDSASigner.java @@ -0,0 +1,54 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.pqc.crypto.MessageSignerAdapter; +import org.bouncycastle.pqc.crypto.slhdsa.SLHDSAPrivateKeyParameters; +import org.bouncycastle.pqc.crypto.slhdsa.SLHDSASigner; +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.SignatureScheme; +import org.bouncycastle.tls.crypto.TlsStreamSigner; +import org.bouncycastle.tls.crypto.impl.PQCUtil; + +public class BcTlsSLHDSASigner + extends BcTlsSigner +{ + public static BcTlsSLHDSASigner create(BcTlsCrypto crypto, SLHDSAPrivateKeyParameters privateKey, int signatureScheme) + { + if (signatureScheme != PQCUtil.getSLHDSASignatureScheme(privateKey.getParameters())) + { + return null; + } + + return new BcTlsSLHDSASigner(crypto, privateKey, signatureScheme); + } + + private final int signatureScheme; + + private BcTlsSLHDSASigner(BcTlsCrypto crypto, SLHDSAPrivateKeyParameters privateKey, int signatureScheme) + { + super(crypto, privateKey); + + if (!SignatureScheme.isSLHDSA(signatureScheme)) + { + throw new IllegalArgumentException("signatureScheme"); + } + + this.signatureScheme = signatureScheme; + } + + public TlsStreamSigner getStreamSigner(SignatureAndHashAlgorithm algorithm) + { + if (algorithm == null || SignatureScheme.from(algorithm) != signatureScheme) + { + throw new IllegalStateException("Invalid algorithm: " + algorithm); + } + + /* + * draft-reddy-tls-slhdsa-01 2. [..], the context parameter [..] MUST be set to the empty string. + */ + SLHDSASigner signer = new SLHDSASigner(); + signer.init(true, new ParametersWithRandom(privateKey, crypto.getSecureRandom())); + + return new BcTlsStreamSigner(new MessageSignerAdapter(signer)); + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSM2Signer.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSM2Signer.java index 6d964a4902..e7203411e9 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSM2Signer.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSM2Signer.java @@ -1,7 +1,5 @@ package org.bouncycastle.tls.crypto.impl.bc; -import java.io.IOException; - import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ParametersWithID; import org.bouncycastle.crypto.params.ParametersWithRandom; @@ -22,11 +20,6 @@ public BcTlsSM2Signer(BcTlsCrypto crypto, ECPrivateKeyParameters privateKey, byt this.identifier = Arrays.clone(identifier); } - public byte[] generateRawSignature(SignatureAndHashAlgorithm algorithm, byte[] hash) throws IOException - { - throw new UnsupportedOperationException(); - } - public TlsStreamSigner getStreamSigner(SignatureAndHashAlgorithm algorithm) { if (algorithm == null diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSigner.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSigner.java index 8b76ab7730..1c20f74445 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSigner.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSigner.java @@ -1,5 +1,7 @@ package org.bouncycastle.tls.crypto.impl.bc; +import java.io.IOException; + import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.tls.SignatureAndHashAlgorithm; import org.bouncycastle.tls.crypto.TlsSigner; @@ -30,6 +32,11 @@ protected BcTlsSigner(BcTlsCrypto crypto, AsymmetricKeyParameter privateKey) this.privateKey = privateKey; } + public byte[] generateRawSignature(SignatureAndHashAlgorithm algorithm, byte[] hash) throws IOException + { + throw new UnsupportedOperationException(); + } + public TlsStreamSigner getStreamSigner(SignatureAndHashAlgorithm algorithm) { return null; diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcX25519.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcX25519.java index e2928c878e..fa382ebfa8 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcX25519.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcX25519.java @@ -25,10 +25,10 @@ public BcX25519(BcTlsCrypto crypto) public byte[] generateEphemeral() throws IOException { - crypto.getSecureRandom().nextBytes(privateKey); + X25519.generatePrivateKey(crypto.getSecureRandom(), privateKey); byte[] publicKey = new byte[X25519.POINT_SIZE]; - X25519.scalarMultBase(privateKey, 0, publicKey, 0); + X25519.generatePublicKey(privateKey, 0, publicKey, 0); return publicKey; } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcX448.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcX448.java index ec3bd1d617..85e2cf5082 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcX448.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcX448.java @@ -25,10 +25,10 @@ public BcX448(BcTlsCrypto crypto) public byte[] generateEphemeral() throws IOException { - crypto.getSecureRandom().nextBytes(privateKey); + X448.generatePrivateKey(crypto.getSecureRandom(), privateKey); byte[] publicKey = new byte[X448.POINT_SIZE]; - X448.scalarMultBase(privateKey, 0, publicKey, 0); + X448.generatePublicKey(privateKey, 0, publicKey, 0); return publicKey; } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/Exceptions.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/Exceptions.java index 9614a0ec2b..177c83d241 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/Exceptions.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/Exceptions.java @@ -1,5 +1,7 @@ package org.bouncycastle.tls.crypto.impl.jcajce; +import java.io.IOException; + /** * In earlier JDK's these do not allow nested exceptions */ @@ -14,4 +16,9 @@ static IllegalArgumentException illegalArgumentException(String message, Throwab { return new IllegalArgumentException(message, cause); } + + static IOException ioException(String message, Throwable cause) + { + return new IOException(message, cause); + } } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaDefaultTlsCredentialedSigner.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaDefaultTlsCredentialedSigner.java index bea3fed4a2..e55b9153fe 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaDefaultTlsCredentialedSigner.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaDefaultTlsCredentialedSigner.java @@ -66,6 +66,66 @@ else if ("Ed448".equalsIgnoreCase(algorithm)) { signer = new JcaTlsEd448Signer(crypto, privateKey); } + else if ("ML-DSA-44".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsMLDSASigner(crypto, privateKey, SignatureScheme.mldsa44); + } + else if ("ML-DSA-65".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsMLDSASigner(crypto, privateKey, SignatureScheme.mldsa65); + } + else if ("ML-DSA-87".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsMLDSASigner(crypto, privateKey, SignatureScheme.mldsa87); + } + else if ("SLH-DSA-SHA2-128S".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsSLHDSASigner(crypto, privateKey, SignatureScheme.DRAFT_slhdsa_sha2_128s); + } + else if ("SLH-DSA-SHA2-128F".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsSLHDSASigner(crypto, privateKey, SignatureScheme.DRAFT_slhdsa_sha2_128f); + } + else if ("SLH-DSA-SHA2-192S".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsSLHDSASigner(crypto, privateKey, SignatureScheme.DRAFT_slhdsa_sha2_192s); + } + else if ("SLH-DSA-SHA2-192F".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsSLHDSASigner(crypto, privateKey, SignatureScheme.DRAFT_slhdsa_sha2_192f); + } + else if ("SLH-DSA-SHA2-256S".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsSLHDSASigner(crypto, privateKey, SignatureScheme.DRAFT_slhdsa_sha2_256s); + } + else if ("SLH-DSA-SHA2-256F".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsSLHDSASigner(crypto, privateKey, SignatureScheme.DRAFT_slhdsa_sha2_256f); + } + else if ("SLH-DSA-SHAKE-128S".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsSLHDSASigner(crypto, privateKey, SignatureScheme.DRAFT_slhdsa_shake_128s); + } + else if ("SLH-DSA-SHAKE-128F".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsSLHDSASigner(crypto, privateKey, SignatureScheme.DRAFT_slhdsa_shake_128f); + } + else if ("SLH-DSA-SHAKE-192S".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsSLHDSASigner(crypto, privateKey, SignatureScheme.DRAFT_slhdsa_shake_192s); + } + else if ("SLH-DSA-SHAKE-192F".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsSLHDSASigner(crypto, privateKey, SignatureScheme.DRAFT_slhdsa_shake_192f); + } + else if ("SLH-DSA-SHAKE-256S".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsSLHDSASigner(crypto, privateKey, SignatureScheme.DRAFT_slhdsa_shake_256s); + } + else if ("SLH-DSA-SHAKE-256F".equalsIgnoreCase(algorithm)) + { + signer = new JcaTlsSLHDSASigner(crypto, privateKey, SignatureScheme.DRAFT_slhdsa_shake_256f); + } else { throw new IllegalArgumentException("'privateKey' type not supported: " + privateKey.getClass().getName()); diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCertificate.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCertificate.java index e88b99302d..d8e4bf4795 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCertificate.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCertificate.java @@ -274,6 +274,25 @@ public Tls13Verifier createVerifier(int signatureScheme) throws IOException // TODO[RFC 8998] // case SignatureScheme.sm2sig_sm3: + case SignatureScheme.mldsa44: + case SignatureScheme.mldsa65: + case SignatureScheme.mldsa87: + return crypto.createTls13Verifier("ML-DSA", null, getPubKeyMLDSA()); + + case SignatureScheme.DRAFT_slhdsa_sha2_128s: + case SignatureScheme.DRAFT_slhdsa_sha2_128f: + case SignatureScheme.DRAFT_slhdsa_sha2_192s: + case SignatureScheme.DRAFT_slhdsa_sha2_192f: + case SignatureScheme.DRAFT_slhdsa_sha2_256s: + case SignatureScheme.DRAFT_slhdsa_sha2_256f: + case SignatureScheme.DRAFT_slhdsa_shake_128s: + case SignatureScheme.DRAFT_slhdsa_shake_128f: + case SignatureScheme.DRAFT_slhdsa_shake_192s: + case SignatureScheme.DRAFT_slhdsa_shake_192f: + case SignatureScheme.DRAFT_slhdsa_shake_256s: + case SignatureScheme.DRAFT_slhdsa_shake_256f: + return crypto.createTls13Verifier("SLH-DSA", null, getPubKeySLHDSA()); + default: throw new TlsFatalAlert(AlertDescription.internal_error); } @@ -392,6 +411,16 @@ PublicKey getPubKeyRSA() throws IOException return getPublicKey(); } + PublicKey getPubKeyMLDSA() throws IOException + { + return getPublicKey(); + } + + PublicKey getPubKeySLHDSA() throws IOException + { + return getPublicKey(); + } + public short getLegacySignatureAlgorithm() throws IOException { PublicKey publicKey = getPublicKey(); diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java index d89b0257ec..d6fb48e227 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java @@ -61,6 +61,7 @@ import org.bouncycastle.tls.crypto.impl.AEADNonceGenerator; import org.bouncycastle.tls.crypto.impl.AEADNonceGeneratorFactory; import org.bouncycastle.tls.crypto.impl.AbstractTlsCrypto; +import org.bouncycastle.tls.crypto.impl.Tls13NullCipher; import org.bouncycastle.tls.crypto.impl.TlsAEADCipher; import org.bouncycastle.tls.crypto.impl.TlsAEADCipherImpl; import org.bouncycastle.tls.crypto.impl.TlsBlockCipher; @@ -77,31 +78,48 @@ /** * Class for providing cryptographic services for TLS based on implementations in the JCA/JCE. *

          - * This class provides default implementations for everything. If you need to customise it, extend the class - * and override the appropriate methods. + * This class provides default implementations for everything. If you need to customise it, extend the class + * and override the appropriate methods. *

          */ public class JcaTlsCrypto extends AbstractTlsCrypto { private final JcaJceHelper helper; + private final JcaJceHelper altHelper; private final SecureRandom entropySource; private final SecureRandom nonceEntropySource; private final Hashtable supportedEncryptionAlgorithms = new Hashtable(); private final Hashtable supportedNamedGroups = new Hashtable(); private final Hashtable supportedOther = new Hashtable(); + private final Hashtable supportedSignatureSchemes = new Hashtable(); /** * Base constructor. * - * @param helper a JCA/JCE helper configured for the class's default provider. - * @param entropySource primary entropy source, used for key generation. + * @param helper a JCA/JCE helper configured for the class's default provider. + * @param entropySource primary entropy source, used for key generation. * @param nonceEntropySource secondary entropy source, used for nonce and IV generation. */ protected JcaTlsCrypto(JcaJceHelper helper, SecureRandom entropySource, SecureRandom nonceEntropySource) + { + this(helper, null, entropySource, nonceEntropySource); + } + + /** + * Base constructor. + * + * @param helper a JCA/JCE helper configured for the class's default provider. + * @param altHelper a JCA/JCE helper configured for the class's secondary provider (tried for private keys). + * @param entropySource primary entropy source, used for key generation. + * @param nonceEntropySource secondary entropy source, used for nonce and IV generation. + */ + protected JcaTlsCrypto(JcaJceHelper helper, JcaJceHelper altHelper, SecureRandom entropySource, + SecureRandom nonceEntropySource) { this.helper = helper; + this.altHelper = altHelper; this.entropySource = entropySource; this.nonceEntropySource = nonceEntropySource; } @@ -111,7 +129,8 @@ JceTlsSecret adoptLocalSecret(byte[] data) return new JceTlsSecret(this, data); } - Cipher createRSAEncryptionCipher() throws GeneralSecurityException + Cipher createRSAEncryptionCipher() + throws GeneralSecurityException { try { @@ -228,6 +247,12 @@ public TlsCipher createCipher(TlsCryptoParameters cryptoParams, int encryptionAl return createChaCha20Poly1305(cryptoParams); case EncryptionAlgorithm.NULL: return createNullCipher(cryptoParams, macAlgorithm); + case EncryptionAlgorithm.NULL_HMAC_SHA256: + // NOTE: Ignores macAlgorithm + return create13NullCipher(cryptoParams, MACAlgorithm.hmac_sha256); + case EncryptionAlgorithm.NULL_HMAC_SHA384: + // NOTE: Ignores macAlgorithm + return create13NullCipher(cryptoParams, MACAlgorithm.hmac_sha384); case EncryptionAlgorithm.SEED_CBC: return createCipher_CBC(cryptoParams, "SEED", 16, macAlgorithm); case EncryptionAlgorithm.SM4_CBC: @@ -326,7 +351,7 @@ public TlsSRP6Client createSRP6Client(TlsSRPConfig srpConfig) final SRP6Client srpClient = new SRP6Client(); BigInteger[] ng = srpConfig.getExplicitNG(); - SRP6Group srpGroup= new SRP6Group(ng[0], ng[1]); + SRP6Group srpGroup = new SRP6Group(ng[0], ng[1]); srpClient.init(srpGroup, createHash(CryptoHashAlgorithm.sha1), this.getSecureRandom()); return new TlsSRP6Client() @@ -355,7 +380,7 @@ public TlsSRP6Server createSRP6Server(TlsSRPConfig srpConfig, BigInteger srpVeri { final SRP6Server srpServer = new SRP6Server(); BigInteger[] ng = srpConfig.getExplicitNG(); - SRP6Group srpGroup= new SRP6Group(ng[0], ng[1]); + SRP6Group srpGroup = new SRP6Group(ng[0], ng[1]); srpServer.init(srpGroup, srpVerifier, createHash(CryptoHashAlgorithm.sha1), this.getSecureRandom()); return new TlsSRP6Server() { @@ -420,24 +445,20 @@ String getHMACAlgorithmName(int cryptoHashAlgorithm) } } - public AlgorithmParameters getNamedGroupAlgorithmParameters(int namedGroup) throws GeneralSecurityException + public AlgorithmParameters getNamedGroupAlgorithmParameters(int namedGroup) + throws GeneralSecurityException { if (NamedGroup.refersToAnXDHCurve(namedGroup)) { - switch (namedGroup) - { /* - * TODO Return AlgorithmParameters to check against disabled algorithms - * + * TODO Return AlgorithmParameters to check against disabled algorithms? + * * NOTE: The JDK doesn't even support AlgorithmParameters for XDH, so SunJSSE also winds * up using null AlgorithmParameters when checking algorithm constraints. */ - case NamedGroup.x25519: - case NamedGroup.x448: - return null; - } + return null; } - else if (NamedGroup.refersToAnECDSACurve(namedGroup)) + else if (NamedGroup.refersToASpecificCurve(namedGroup)) { return ECUtil.getAlgorithmParameters(this, NamedGroup.getCurveName(namedGroup)); } @@ -447,19 +468,12 @@ else if (NamedGroup.refersToASpecificFiniteField(namedGroup)) } else if (NamedGroup.refersToASpecificKem(namedGroup)) { - switch (namedGroup) - { /* - * TODO[tls-kem] Return AlgorithmParameters to check against disabled algorithms? + * TODO Return AlgorithmParameters to check against disabled algorithms? + * + * NOTE: See what the JDK/SunJSSE implementation does. */ - case NamedGroup.OQS_mlkem512: - case NamedGroup.OQS_mlkem768: - case NamedGroup.OQS_mlkem1024: - case NamedGroup.MLKEM512: - case NamedGroup.MLKEM768: - case NamedGroup.MLKEM1024: - return null; - } + return null; } throw new IllegalArgumentException("NamedGroup not supported: " + NamedGroup.getText(namedGroup)); @@ -759,6 +773,13 @@ public boolean hasSignatureAlgorithm(short signatureAlgorithm) public boolean hasSignatureAndHashAlgorithm(SignatureAndHashAlgorithm sigAndHashAlgorithm) { + int signatureScheme = SignatureScheme.from(sigAndHashAlgorithm); + if (SignatureScheme.isMLDSA(signatureScheme) || + SignatureScheme.isSLHDSA(signatureScheme)) + { + return hasSignatureScheme(signatureScheme); + } + short signature = sigAndHashAlgorithm.getSignature(); switch (sigAndHashAlgorithm.getHash()) @@ -775,26 +796,35 @@ public boolean hasSignatureAndHashAlgorithm(SignatureAndHashAlgorithm sigAndHash public boolean hasSignatureScheme(int signatureScheme) { - switch (signatureScheme) + final Integer key = Integers.valueOf(signatureScheme); + synchronized (supportedSignatureSchemes) + { + Boolean cached = (Boolean)supportedSignatureSchemes.get(key); + if (cached != null) + { + return cached.booleanValue(); + } + } + + Boolean supported = isSupportedSignatureScheme(signatureScheme); + if (null == supported) { - case SignatureScheme.sm2sig_sm3: return false; - default: + } + + synchronized (supportedSignatureSchemes) { - short signature = SignatureScheme.getSignatureAlgorithm(signatureScheme); + Boolean cached = (Boolean)supportedSignatureSchemes.put(key, supported); - switch(SignatureScheme.getCryptoHashAlgorithm(signatureScheme)) + // Unlikely, but we want a consistent result + if (null != cached && supported != cached) { - case CryptoHashAlgorithm.md5: - return SignatureAlgorithm.rsa == signature && hasSignatureAlgorithm(signature); - case CryptoHashAlgorithm.sha224: - // Somewhat overkill, but simpler for now. It's also consistent with SunJSSE behaviour. - return !JcaUtils.isSunMSCAPIProviderActive() && hasSignatureAlgorithm(signature); - default: - return hasSignatureAlgorithm(signature); + supportedSignatureSchemes.put(key, cached); + supported = cached; } } - } + + return supported.booleanValue(); } public boolean hasSRPAuthentication() @@ -802,6 +832,11 @@ public boolean hasSRPAuthentication() return true; } + public TlsSecret createHybridSecret(TlsSecret s1, TlsSecret s2) + { + return adoptLocalSecret(Arrays.concatenate(s1.extract(), s2.extract())); + } + public TlsSecret createSecret(byte[] data) { try @@ -855,7 +890,7 @@ public TlsECDomain createECDomain(TlsECConfig ecConfig) return new JceTlsECDomain(this, ecConfig); } } - + public TlsKemDomain createKemDomain(TlsKemConfig kemConfig) { return new JceTlsMLKemDomain(this, kemConfig); @@ -893,8 +928,7 @@ protected TlsAEADCipherImpl createAEADCipher(String cipherName, String algorithm * @throws GeneralSecurityException in case of failure. */ protected TlsBlockCipherImpl createBlockCipher(String cipherName, String algorithm, int keySize, - boolean isEncrypting) - throws GeneralSecurityException + boolean isEncrypting) throws GeneralSecurityException { return new JceBlockCipherImpl(this, helper.createCipher(cipherName), algorithm, keySize, isEncrypting); } @@ -910,8 +944,7 @@ protected TlsBlockCipherImpl createBlockCipher(String cipherName, String algorit * @throws GeneralSecurityException in case of failure. */ protected TlsBlockCipherImpl createBlockCipherWithCBCImplicitIV(String cipherName, String algorithm, int keySize, - boolean isEncrypting) - throws GeneralSecurityException + boolean isEncrypting) throws GeneralSecurityException { return new JceBlockCipherWithCBCImplicitIVImpl(this, helper.createCipher(cipherName), algorithm, isEncrypting); } @@ -929,12 +962,18 @@ protected TlsHash createHash(String digestName) return new JcaTlsHash(helper.createDigest(digestName)); } + protected Tls13NullCipher create13NullCipher(TlsCryptoParameters cryptoParams, int macAlgorithm) + throws IOException + { + return new Tls13NullCipher(cryptoParams, createHMAC(macAlgorithm), createHMAC(macAlgorithm)); + } + /** * To disable the null cipher suite, override this method with one that throws an IOException. * * @param macAlgorithm the name of the algorithm supporting the MAC. * @return a null cipher suite implementation. - * @throws IOException in case of failure. + * @throws IOException in case of failure. * @throws GeneralSecurityException in case of a specific failure in the JCA/JCE layer. */ protected TlsNullCipher createNullCipher(TlsCryptoParameters cryptoParams, int macAlgorithm) @@ -955,51 +994,89 @@ protected TlsStreamSigner createStreamSigner(SignatureAndHashAlgorithm algorithm protected TlsStreamSigner createStreamSigner(String algorithmName, AlgorithmParameterSpec parameter, PrivateKey privateKey, boolean needsRandom) throws IOException { + SecureRandom random = needsRandom ? getSecureRandom() : null; + try { - SecureRandom random = needsRandom ? getSecureRandom() : null; - - JcaJceHelper helper = getHelper(); - try { - if (null != parameter) + return createStreamSigner(getHelper(), algorithmName, parameter, privateKey, random); + } + catch (InvalidKeyException e) + { + JcaJceHelper altHelper = getAltHelper(); + if (altHelper == null) { - Signature dummySigner = helper.createSignature(algorithmName); - dummySigner.initSign(privateKey, random); - helper = new ProviderJcaJceHelper(dummySigner.getProvider()); + throw e; } - Signature signer = helper.createSignature(algorithmName); - if (null != parameter) - { - signer.setParameter(parameter); - } - signer.initSign(privateKey, random); - return new JcaTlsStreamSigner(signer); + return createStreamSigner(altHelper, algorithmName, parameter, privateKey, random); } - catch (InvalidKeyException e) + } + catch (GeneralSecurityException e) + { + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } + + protected TlsStreamSigner createStreamSigner(JcaJceHelper helper, String algorithmName, + AlgorithmParameterSpec parameter, PrivateKey privateKey, SecureRandom random) throws GeneralSecurityException + { + try + { + if (null != parameter) { - String upperAlg = Strings.toUpperCase(algorithmName); - if (upperAlg.endsWith("MGF1")) + Signature dummySigner; + try { - // ANDMGF1 has vanished from the Sun PKCS11 provider. - algorithmName = upperAlg.replace("ANDMGF1", "SSA-PSS"); - return createStreamSigner(algorithmName, parameter, privateKey, needsRandom); + dummySigner = helper.createSignature(algorithmName); } - else + catch (NoSuchAlgorithmException e) { - throw e; + // more PKCS#11 mischief + String upperAlg = Strings.toUpperCase(algorithmName); + if (upperAlg.endsWith("ANDMGF1")) + { + // ANDMGF1 has vanished from the Sun PKCS11 provider. + algorithmName = upperAlg.replace("ANDMGF1", "SSA-PSS"); + dummySigner = helper.createSignature(algorithmName); + } + else + { + throw e; + } } + + dummySigner.initSign(privateKey, random); + helper = new ProviderJcaJceHelper(dummySigner.getProvider()); + } + + Signature signer = helper.createSignature(algorithmName); + if (null != parameter) + { + signer.setParameter(parameter); } + signer.initSign(privateKey, random); + return new JcaTlsStreamSigner(signer); } - catch (GeneralSecurityException e) + catch (InvalidKeyException e) { - throw new TlsFatalAlert(AlertDescription.internal_error, e); + String upperAlg = Strings.toUpperCase(algorithmName); + if (upperAlg.endsWith("ANDMGF1")) + { + // ANDMGF1 has vanished from the Sun PKCS11 provider. + algorithmName = upperAlg.replace("ANDMGF1", "SSA-PSS"); + return createStreamSigner(helper, algorithmName, parameter, privateKey, random); + } + else + { + throw e; + } } } - protected TlsStreamVerifier createStreamVerifier(DigitallySigned digitallySigned, PublicKey publicKey) throws IOException + protected TlsStreamVerifier createStreamVerifier(DigitallySigned digitallySigned, PublicKey publicKey) + throws IOException { String algorithmName = JcaUtils.getJcaAlgorithmName(digitallySigned.getAlgorithm()); @@ -1109,6 +1186,12 @@ protected Boolean isSupportedEncryptionAlgorithm(int encryptionAlgorithm) case EncryptionAlgorithm.SM4_GCM: return isUsableCipher("SM4/GCM/NoPadding", 128); + case EncryptionAlgorithm.NULL_HMAC_SHA256: + return hasMacAlgorithm(MACAlgorithm.hmac_sha256); + + case EncryptionAlgorithm.NULL_HMAC_SHA384: + return hasMacAlgorithm(MACAlgorithm.hmac_sha384); + case EncryptionAlgorithm._28147_CNT_IMIT: case EncryptionAlgorithm.DES_CBC: case EncryptionAlgorithm.DES40_CBC: @@ -1155,12 +1238,7 @@ protected Boolean isSupportedNamedGroup(int namedGroup) } } } - else if (NamedGroup.refersToASpecificKem(namedGroup)) - { - // TODO[tls-kem] When implemented via provider, need to check for support dynamically - return Boolean.TRUE; - } - else if (NamedGroup.refersToAnECDSACurve(namedGroup)) + else if (NamedGroup.refersToASpecificCurve(namedGroup)) { return Boolean.valueOf(ECUtil.isCurveSupported(this, NamedGroup.getCurveName(namedGroup))); } @@ -1168,6 +1246,10 @@ else if (NamedGroup.refersToASpecificFiniteField(namedGroup)) { return Boolean.valueOf(DHUtil.isGroupSupported(this, TlsDHUtils.getNamedDHGroup(namedGroup))); } + else if (NamedGroup.refersToASpecificKem(namedGroup)) + { + return Boolean.valueOf(KemUtil.isKemSupported(this, NamedGroup.getKemName(namedGroup))); + } } catch (GeneralSecurityException e) { @@ -1178,6 +1260,50 @@ else if (NamedGroup.refersToASpecificFiniteField(namedGroup)) return null; } + protected Boolean isSupportedSignatureScheme(int signatureScheme) + { + try + { + if (SignatureScheme.isMLDSA(signatureScheme)) + { + helper.createSignature("ML-DSA"); + return Boolean.TRUE; + } + + if (SignatureScheme.isSLHDSA(signatureScheme)) + { + helper.createSignature("SLH-DSA"); + return Boolean.TRUE; + } + + switch (signatureScheme) + { + case SignatureScheme.sm2sig_sm3: + return Boolean.FALSE; + + default: + { + short signature = SignatureScheme.getSignatureAlgorithm(signatureScheme); + + switch (SignatureScheme.getCryptoHashAlgorithm(signatureScheme)) + { + case CryptoHashAlgorithm.md5: + return Boolean.valueOf(SignatureAlgorithm.rsa == signature && hasSignatureAlgorithm(signature)); + case CryptoHashAlgorithm.sha224: + // Somewhat overkill, but simpler for now. It's also consistent with SunJSSE behaviour. + return Boolean.valueOf(!JcaUtils.isSunMSCAPIProviderActive() && hasSignatureAlgorithm(signature)); + default: + return Boolean.valueOf(hasSignatureAlgorithm(signature)); + } + } + } + } + catch (GeneralSecurityException e) + { + return Boolean.FALSE; + } + } + protected boolean isUsableCipher(String cipherAlgorithm, int keySize) { try @@ -1209,6 +1335,11 @@ public JcaJceHelper getHelper() return helper; } + public JcaJceHelper getAltHelper() + { + return altHelper; + } + protected TlsBlockCipherImpl createCBCBlockCipherImpl(TlsCryptoParameters cryptoParams, String algorithm, int cipherKeySize, boolean forEncryption) throws GeneralSecurityException { diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCryptoProvider.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCryptoProvider.java index 8368e8682c..9b5d81f364 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCryptoProvider.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCryptoProvider.java @@ -20,6 +20,7 @@ public class JcaTlsCryptoProvider implements TlsCryptoProvider { private JcaJceHelper helper = new DefaultJcaJceHelper(); + private JcaJceHelper altHelper = null; public JcaTlsCryptoProvider() { @@ -34,6 +35,21 @@ public JcaTlsCryptoProvider() public JcaTlsCryptoProvider setProvider(Provider provider) { this.helper = new ProviderJcaJceHelper(provider); + this.altHelper = null; + + return this; + } + + /** + * Set the alternate provider of cryptographic services for any JcaTlsCrypto we build (usually points to a + * HSM). + * + * @param provider the provider class to source cryptographic services from. + * @return the current builder instance. + */ + public JcaTlsCryptoProvider setAlternateProvider(Provider provider) + { + this.altHelper = new ProviderJcaJceHelper(provider); return this; } @@ -47,6 +63,20 @@ public JcaTlsCryptoProvider setProvider(Provider provider) public JcaTlsCryptoProvider setProvider(String providerName) { this.helper = new NamedJcaJceHelper(providerName); + this.altHelper = null; + + return this; + } + + /** + * Set the provider of cryptographic services for any JcaTlsCrypto we build by name (usually refers to a HSM). + * + * @param providerName the name of the provider class to source cryptographic services from. + * @return the current builder instance. + */ + public JcaTlsCryptoProvider setAlternateProvider(String providerName) + { + this.altHelper = new NamedJcaJceHelper(providerName); return this; } @@ -92,7 +122,7 @@ public JcaTlsCrypto create(SecureRandom random) */ public JcaTlsCrypto create(SecureRandom keyRandom, SecureRandom nonceRandom) { - return new JcaTlsCrypto(getHelper(), keyRandom, nonceRandom); + return new JcaTlsCrypto(getHelper(), getAltHelper(), keyRandom, nonceRandom); } public JcaJceHelper getHelper() @@ -100,6 +130,11 @@ public JcaJceHelper getHelper() return helper; } + public JcaJceHelper getAltHelper() + { + return altHelper; + } + @SuppressWarnings("serial") private static class NonceEntropySource extends SecureRandom diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsECDSA13Signer.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsECDSA13Signer.java index 6e97fd5b16..804a8932dc 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsECDSA13Signer.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsECDSA13Signer.java @@ -2,9 +2,12 @@ import java.io.IOException; import java.security.GeneralSecurityException; +import java.security.InvalidKeyException; import java.security.PrivateKey; +import java.security.SecureRandom; import java.security.Signature; +import org.bouncycastle.jcajce.util.JcaJceHelper; import org.bouncycastle.tls.AlertDescription; import org.bouncycastle.tls.SignatureAndHashAlgorithm; import org.bouncycastle.tls.SignatureScheme; @@ -50,12 +53,25 @@ public byte[] generateRawSignature(SignatureAndHashAlgorithm algorithm, byte[] h throw new IllegalStateException("Invalid algorithm: " + algorithm); } + SecureRandom random = crypto.getSecureRandom(); + try { - Signature signer = crypto.getHelper().createSignature("NoneWithECDSA"); - signer.initSign(privateKey, crypto.getSecureRandom()); - signer.update(hash, 0, hash.length); - return signer.sign(); + try + { + return implGenerateRawSignature(crypto.getHelper(), privateKey, random, hash); + } + catch (InvalidKeyException e) + { + // try with PKCS#11 (usually) alternative provider + JcaJceHelper altHelper = crypto.getAltHelper(); + if (altHelper == null) + { + throw e; + } + + return implGenerateRawSignature(altHelper, privateKey, random, hash); + } } catch (GeneralSecurityException e) { @@ -68,4 +84,13 @@ public TlsStreamSigner getStreamSigner(SignatureAndHashAlgorithm algorithm) { return null; } + + private static byte[] implGenerateRawSignature(JcaJceHelper helper, PrivateKey privateKey, SecureRandom random, + byte[] hash) throws GeneralSecurityException + { + Signature signer = helper.createSignature("NoneWithECDSA"); + signer.initSign(privateKey, random); + signer.update(hash, 0, hash.length); + return signer.sign(); + } } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsMLDSASigner.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsMLDSASigner.java new file mode 100644 index 0000000000..13ed5c1392 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsMLDSASigner.java @@ -0,0 +1,52 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.IOException; +import java.security.PrivateKey; + +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.SignatureScheme; +import org.bouncycastle.tls.crypto.TlsSigner; +import org.bouncycastle.tls.crypto.TlsStreamSigner; + +public class JcaTlsMLDSASigner + implements TlsSigner +{ + private final JcaTlsCrypto crypto; + private final PrivateKey privateKey; + private final int signatureScheme; + + public JcaTlsMLDSASigner(JcaTlsCrypto crypto, PrivateKey privateKey, int signatureScheme) + { + if (null == crypto) + { + throw new NullPointerException("crypto"); + } + if (null == privateKey) + { + throw new NullPointerException("privateKey"); + } + if (!SignatureScheme.isMLDSA(signatureScheme)) + { + throw new IllegalArgumentException("signatureScheme"); + } + + this.crypto = crypto; + this.privateKey = privateKey; + this.signatureScheme = signatureScheme; + } + + public byte[] generateRawSignature(SignatureAndHashAlgorithm algorithm, byte[] hash) throws IOException + { + throw new UnsupportedOperationException(); + } + + public TlsStreamSigner getStreamSigner(SignatureAndHashAlgorithm algorithm) throws IOException + { + if (algorithm == null || SignatureScheme.from(algorithm) != signatureScheme) + { + throw new IllegalStateException("Invalid algorithm: " + algorithm); + } + + return crypto.createStreamSigner("ML-DSA", null, privateKey, false); + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSASigner.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSASigner.java index 584bf44f14..bc1260a34c 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSASigner.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSASigner.java @@ -6,6 +6,7 @@ import java.security.PublicKey; import java.security.Signature; +import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.DigestInfo; @@ -31,6 +32,8 @@ public class JcaTlsRSASigner /** * @deprecated Use constructor without 'publicKey' parameter. */ + @Deprecated + @SuppressWarnings("InlineMeSuggester") public JcaTlsRSASigner(JcaTlsCrypto crypto, PrivateKey privateKey, PublicKey publicKey) { this(crypto, privateKey); @@ -71,7 +74,7 @@ public byte[] generateRawSignature(SignatureAndHashAlgorithm algorithm, byte[] h */ AlgorithmIdentifier algID = new AlgorithmIdentifier( TlsUtils.getOIDForHashAlgorithm(algorithm.getHash()), DERNull.INSTANCE); - input = new DigestInfo(algID, hash).getEncoded(); + input = new DigestInfo(algID, hash).getEncoded(ASN1Encoding.DER); } else { diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSAVerifier.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSAVerifier.java index a78458bf83..d3d0532bc5 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSAVerifier.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsRSAVerifier.java @@ -5,6 +5,7 @@ import java.security.PublicKey; import java.security.Signature; +import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.DigestInfo; @@ -80,7 +81,7 @@ public boolean verifyRawSignature(DigitallySigned digitallySigned, byte[] hash) */ AlgorithmIdentifier algID = new AlgorithmIdentifier( TlsUtils.getOIDForHashAlgorithm(algorithm.getHash()), DERNull.INSTANCE); - byte[] digestInfo = new DigestInfo(algID, hash).getEncoded(); + byte[] digestInfo = new DigestInfo(algID, hash).getEncoded(ASN1Encoding.DER); verifier.update(digestInfo, 0, digestInfo.length); } else diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsSLHDSASigner.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsSLHDSASigner.java new file mode 100644 index 0000000000..de3ceb135b --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsSLHDSASigner.java @@ -0,0 +1,52 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.IOException; +import java.security.PrivateKey; + +import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.SignatureScheme; +import org.bouncycastle.tls.crypto.TlsSigner; +import org.bouncycastle.tls.crypto.TlsStreamSigner; + +public class JcaTlsSLHDSASigner + implements TlsSigner +{ + private final JcaTlsCrypto crypto; + private final PrivateKey privateKey; + private final int signatureScheme; + + public JcaTlsSLHDSASigner(JcaTlsCrypto crypto, PrivateKey privateKey, int signatureScheme) + { + if (null == crypto) + { + throw new NullPointerException("crypto"); + } + if (null == privateKey) + { + throw new NullPointerException("privateKey"); + } + if (!SignatureScheme.isSLHDSA(signatureScheme)) + { + throw new IllegalArgumentException("signatureScheme"); + } + + this.crypto = crypto; + this.privateKey = privateKey; + this.signatureScheme = signatureScheme; + } + + public byte[] generateRawSignature(SignatureAndHashAlgorithm algorithm, byte[] hash) throws IOException + { + throw new UnsupportedOperationException(); + } + + public TlsStreamSigner getStreamSigner(SignatureAndHashAlgorithm algorithm) throws IOException + { + if (algorithm == null || SignatureScheme.from(algorithm) != signatureScheme) + { + throw new IllegalStateException("Invalid algorithm: " + algorithm); + } + + return crypto.createStreamSigner("SLH-DSA", null, privateKey, false); + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceAEADCipherImpl.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceAEADCipherImpl.java index 978acfaeb7..4d52dc7794 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceAEADCipherImpl.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceAEADCipherImpl.java @@ -6,6 +6,7 @@ import java.security.GeneralSecurityException; import java.security.PrivilegedAction; import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; import javax.crypto.Cipher; import javax.crypto.SecretKey; @@ -43,6 +44,7 @@ public Object run() }); } + // TODO[tls] Once Java 7 or higher is the baseline, this will always be true private static final boolean canDoAEAD = checkForAEAD(); private static String getAlgParamsName(JcaJceHelper helper, String cipherName) @@ -68,8 +70,10 @@ private static String getAlgParamsName(JcaJceHelper helper, String cipherName) private final String algorithmParamsName; private SecretKey key; - private byte[] nonce; - private int macSize; + + // TODO[tls] These two are only needed while the baseline is pre-Java7 + private byte[] noncePre7; + private int macSizePre7; public JceAEADCipherImpl(JcaTlsCrypto crypto, JcaJceHelper helper, String cipherName, String algorithm, int keySize, boolean isEncrypting) @@ -120,10 +124,27 @@ public void init(byte[] nonce, int macSize) } else { - // Otherwise fall back to the BC-specific AEADParameterSpec - cipher.init(cipherMode, key, new AEADParameterSpec(nonce, macSize * 8, null), random); - this.nonce = Arrays.clone(nonce); - this.macSize = macSize; + /* + * Otherwise fall back to the BC-specific AEADParameterSpec. Since updateAAD is not available, we + * need to use init to pass the associated data (in doFinal), but in order to call getOutputSize we + * technically need to init the cipher first. So we init with a dummy nonce to avoid duplicate nonce + * error from the init in doFinal. + */ + + if (this.noncePre7 == null || this.noncePre7.length != nonce.length) + { + this.noncePre7 = new byte[nonce.length]; + } + + System.arraycopy(nonce, 0, this.noncePre7, 0, nonce.length); + this.macSizePre7 = macSize; + + this.noncePre7[0] ^= 0x80; + + AlgorithmParameterSpec params = new AEADParameterSpec(noncePre7, macSizePre7 * 8, null); + cipher.init(cipherMode, key, params, random); + + this.noncePre7[0] ^= 0x80; } } catch (Exception e) @@ -150,11 +171,15 @@ public int doFinal(byte[] additionalData, byte[] input, int inputOffset, int inp { try { - cipher.init(cipherMode, key, new AEADParameterSpec(nonce, macSize * 8, additionalData)); + // NOTE: Shouldn't need a SecureRandom, but this is cheaper if the provider would auto-create one + SecureRandom random = crypto.getSecureRandom(); + + AlgorithmParameterSpec params = new AEADParameterSpec(noncePre7, macSizePre7 * 8, additionalData); + cipher.init(cipherMode, key, params, random); } catch (Exception e) { - throw new IOException(e); + throw Exceptions.ioException(e.getMessage(), e); } } } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsDHDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsDHDomain.java index 578f3d486d..b7e1d96f1a 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsDHDomain.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsDHDomain.java @@ -71,8 +71,8 @@ public static JceTlsSecret calculateDHAgreement(JcaTlsCrypto crypto, DHPrivateKe } protected final JcaTlsCrypto crypto; - protected final TlsDHConfig dhConfig; protected final DHParameterSpec dhSpec; + protected final boolean isPadded; public JceTlsDHDomain(JcaTlsCrypto crypto, TlsDHConfig dhConfig) { @@ -83,8 +83,8 @@ public JceTlsDHDomain(JcaTlsCrypto crypto, TlsDHConfig dhConfig) if (null != spec) { this.crypto = crypto; - this.dhConfig = dhConfig; this.dhSpec = spec; + this.isPadded = dhConfig.isPadded(); return; } } @@ -95,7 +95,7 @@ public JceTlsDHDomain(JcaTlsCrypto crypto, TlsDHConfig dhConfig) public JceTlsSecret calculateDHAgreement(DHPrivateKey privateKey, DHPublicKey publicKey) throws IOException { - return calculateDHAgreement(crypto, privateKey, publicKey, dhConfig.isPadded()); + return calculateDHAgreement(crypto, privateKey, publicKey, isPadded); } public TlsAgreement createDH() @@ -105,7 +105,7 @@ public TlsAgreement createDH() public BigInteger decodeParameter(byte[] encoding) throws IOException { - if (dhConfig.isPadded() && getValueLength(dhSpec) != encoding.length) + if (isPadded && getValueLength(dhSpec) != encoding.length) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } @@ -140,7 +140,7 @@ public DHPublicKey decodePublicKey(byte[] encoding) throws IOException public byte[] encodeParameter(BigInteger x) throws IOException { - return encodeValue(dhSpec, dhConfig.isPadded(), x); + return encodeValue(dhSpec, isPadded, x); } public byte[] encodePublicKey(DHPublicKey publicKey) throws IOException diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java index 8c332cbf04..084a1a658f 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java @@ -29,7 +29,6 @@ public class JceTlsECDomain implements TlsECDomain { protected final JcaTlsCrypto crypto; - protected final TlsECConfig ecConfig; protected final ECParameterSpec ecSpec; protected final ECCurve ecCurve; @@ -42,7 +41,6 @@ public JceTlsECDomain(JcaTlsCrypto crypto, TlsECConfig ecConfig) if (null != spec) { this.crypto = crypto; - this.ecConfig = ecConfig; this.ecSpec = spec; this.ecCurve = ECUtil.convertCurve(spec.getCurve(), spec.getOrder(), spec.getCofactor()); return; diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKem.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKem.java index 44f73f2bbb..330280d125 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKem.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKem.java @@ -1,11 +1,11 @@ package org.bouncycastle.tls.crypto.impl.jcajce; import java.io.IOException; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.SecretWithEncapsulation; -import org.bouncycastle.pqc.crypto.mlkem.MLKEMPrivateKeyParameters; -import org.bouncycastle.pqc.crypto.mlkem.MLKEMPublicKeyParameters; +import org.bouncycastle.jcajce.SecretKeyWithEncapsulation; import org.bouncycastle.tls.crypto.TlsAgreement; import org.bouncycastle.tls.crypto.TlsSecret; @@ -13,8 +13,8 @@ public class JceTlsMLKem implements TlsAgreement { protected final JceTlsMLKemDomain domain; - protected MLKEMPrivateKeyParameters privateKey; - protected MLKEMPublicKeyParameters publicKey; + protected PrivateKey privateKey; + protected PublicKey publicKey; protected TlsSecret secret; public JceTlsMLKem(JceTlsMLKemDomain domain) @@ -26,16 +26,16 @@ public byte[] generateEphemeral() throws IOException { if (domain.isServer()) { - SecretWithEncapsulation encap = domain.encapsulate(publicKey); + SecretKeyWithEncapsulation encap = domain.encapsulate(publicKey); this.publicKey = null; - this.secret = domain.adoptLocalSecret(encap.getSecret()); + this.secret = domain.adoptLocalSecret(encap.getEncoded()); return encap.getEncapsulation(); } else { - AsymmetricCipherKeyPair kp = domain.generateKeyPair(); - this.privateKey = (MLKEMPrivateKeyParameters)kp.getPrivate(); - return domain.encodePublicKey((MLKEMPublicKeyParameters)kp.getPublic()); + KeyPair kp = domain.generateKeyPair(); + this.privateKey = kp.getPrivate(); + return domain.encodePublicKey(kp.getPublic()); } } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKemDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKemDomain.java index 5aaf97b7db..f85528070b 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKemDomain.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMLKemDomain.java @@ -1,14 +1,18 @@ package org.bouncycastle.tls.crypto.impl.jcajce; -import org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import org.bouncycastle.crypto.SecretWithEncapsulation; -import org.bouncycastle.pqc.crypto.mlkem.MLKEMExtractor; -import org.bouncycastle.pqc.crypto.mlkem.MLKEMGenerator; -import org.bouncycastle.pqc.crypto.mlkem.MLKEMKeyGenerationParameters; -import org.bouncycastle.pqc.crypto.mlkem.MLKEMKeyPairGenerator; -import org.bouncycastle.pqc.crypto.mlkem.MLKEMParameters; -import org.bouncycastle.pqc.crypto.mlkem.MLKEMPrivateKeyParameters; -import org.bouncycastle.pqc.crypto.mlkem.MLKEMPublicKeyParameters; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; + +import javax.crypto.KeyGenerator; + +import org.bouncycastle.jcajce.SecretKeyWithEncapsulation; +import org.bouncycastle.jcajce.spec.KEMExtractSpec; +import org.bouncycastle.jcajce.spec.KEMGenerateSpec; +import org.bouncycastle.jcajce.spec.MLKEMParameterSpec; import org.bouncycastle.tls.NamedGroup; import org.bouncycastle.tls.crypto.TlsAgreement; import org.bouncycastle.tls.crypto.TlsKemConfig; @@ -16,34 +20,14 @@ public class JceTlsMLKemDomain implements TlsKemDomain { - public static MLKEMParameters getDomainParameters(TlsKemConfig kemConfig) - { - switch (kemConfig.getNamedGroup()) - { - case NamedGroup.OQS_mlkem512: - case NamedGroup.MLKEM512: - return MLKEMParameters.ml_kem_512; - case NamedGroup.OQS_mlkem768: - case NamedGroup.MLKEM768: - return MLKEMParameters.ml_kem_768; - case NamedGroup.OQS_mlkem1024: - case NamedGroup.MLKEM1024: - return MLKEMParameters.ml_kem_1024; - default: - throw new IllegalArgumentException("No ML-KEM configuration provided"); - } - } - protected final JcaTlsCrypto crypto; - protected final TlsKemConfig config; - protected final MLKEMParameters domainParameters; + protected final String kemName; protected final boolean isServer; public JceTlsMLKemDomain(JcaTlsCrypto crypto, TlsKemConfig kemConfig) { this.crypto = crypto; - this.config = kemConfig; - this.domainParameters = getDomainParameters(kemConfig); + this.kemName = NamedGroup.getKemName(kemConfig.getNamedGroup()); this.isServer = kemConfig.isServer(); } @@ -57,34 +41,64 @@ public TlsAgreement createKem() return new JceTlsMLKem(this); } - public JceTlsSecret decapsulate(MLKEMPrivateKeyParameters privateKey, byte[] ciphertext) + public JceTlsSecret decapsulate(PrivateKey privateKey, byte[] ciphertext) { - MLKEMExtractor kemExtract = new MLKEMExtractor(privateKey); - byte[] secret = kemExtract.extractSecret(ciphertext); - return adoptLocalSecret(secret); + try + { + KeyGenerator keyGenerator = crypto.getHelper().createKeyGenerator(kemName); + keyGenerator.init(new KEMExtractSpec.Builder(privateKey, ciphertext, "DEF", 256).withNoKdf().build()); + SecretKeyWithEncapsulation secEnc = (SecretKeyWithEncapsulation)keyGenerator.generateKey(); + return adoptLocalSecret(secEnc.getEncoded()); + } + catch (Exception e) + { + throw Exceptions.illegalArgumentException("invalid key: " + e.getMessage(), e); + } } - public MLKEMPublicKeyParameters decodePublicKey(byte[] encoding) + public PublicKey decodePublicKey(byte[] encoding) + throws IOException { - return new MLKEMPublicKeyParameters(domainParameters, encoding); + return KemUtil.decodePublicKey(crypto, kemName, encoding); } - public SecretWithEncapsulation encapsulate(MLKEMPublicKeyParameters publicKey) + public SecretKeyWithEncapsulation encapsulate(PublicKey publicKey) { - MLKEMGenerator kemGen = new MLKEMGenerator(crypto.getSecureRandom()); - return kemGen.generateEncapsulated(publicKey); + try + { + KeyGenerator keyGenerator = crypto.getHelper().createKeyGenerator(kemName); + keyGenerator.init(new KEMGenerateSpec.Builder(publicKey, "DEF", 256).withNoKdf().build()); + return (SecretKeyWithEncapsulation)keyGenerator.generateKey(); + } + catch (Exception e) + { + throw Exceptions.illegalArgumentException("invalid key: " + e.getMessage(), e); + } } - public byte[] encodePublicKey(MLKEMPublicKeyParameters publicKey) + public byte[] encodePublicKey(PublicKey publicKey) + throws IOException { - return publicKey.getEncoded(); + return KemUtil.encodePublicKey(publicKey); } - public AsymmetricCipherKeyPair generateKeyPair() + public KeyPair generateKeyPair() { - MLKEMKeyPairGenerator keyPairGenerator = new MLKEMKeyPairGenerator(); - keyPairGenerator.init(new MLKEMKeyGenerationParameters(crypto.getSecureRandom(), domainParameters)); - return keyPairGenerator.generateKeyPair(); + try + { + // TODO How to pass only the SecureRandom to initialize if we use the full name in the getInstance? +// KeyPairGenerator keyPairGenerator = KemUtil.getKeyPairGenerator(crypto, kemName); +// keyPairGenerator.initialize((AlgorithmParameterSpec)null, crypto.getSecureRandom()); +// return keyPairGenerator.generateKeyPair(); + + KeyPairGenerator keyPairGenerator = crypto.getHelper().createKeyPairGenerator("ML-KEM"); + keyPairGenerator.initialize(MLKEMParameterSpec.fromName(kemName), crypto.getSecureRandom()); + return keyPairGenerator.generateKeyPair(); + } + catch (GeneralSecurityException e) + { + throw Exceptions.illegalStateException("unable to create key pair: " + e.getMessage(), e); + } } public boolean isServer() diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/KemUtil.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/KemUtil.java new file mode 100644 index 0000000000..d543f96b74 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/KemUtil.java @@ -0,0 +1,166 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.io.IOException; +import java.security.KeyFactory; +import java.security.KeyPairGenerator; +import java.security.PublicKey; +import java.security.spec.EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import javax.crypto.KeyGenerator; + +import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.jcajce.interfaces.MLKEMPublicKey; +import org.bouncycastle.jcajce.spec.MLKEMParameterSpec; +import org.bouncycastle.jcajce.spec.MLKEMPublicKeySpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.TlsFatalAlert; + +class KemUtil +{ + static PublicKey decodePublicKey(JcaTlsCrypto crypto, String kemName, byte[] encoding) throws TlsFatalAlert + { + try + { + KeyFactory kf = crypto.getHelper().createKeyFactory(kemName); + + // More efficient BC-specific method + if (kf.getProvider() instanceof BouncyCastleProvider) + { + try + { + // TODO Add RawEncodedKeySpec support to BC? + + MLKEMParameterSpec params = MLKEMParameterSpec.fromName(kemName); + MLKEMPublicKeySpec keySpec = new MLKEMPublicKeySpec(params, encoding); + return kf.generatePublic(keySpec); + } + catch (Exception e) + { + // Fallback to X.509 + } + } + + EncodedKeySpec keySpec = createX509EncodedKeySpec(getAlgorithmOID(kemName), encoding); + return kf.generatePublic(keySpec); + } + catch (Exception e) + { + throw new TlsFatalAlert(AlertDescription.illegal_parameter, e); + } + } + + static byte[] encodePublicKey(PublicKey publicKey) throws TlsFatalAlert + { + // More efficient BC-specific method + if (publicKey instanceof MLKEMPublicKey) + { + return ((MLKEMPublicKey)publicKey).getPublicData(); + } + + if (!"X.509".equals(publicKey.getFormat())) + { + throw new TlsFatalAlert(AlertDescription.internal_error, "Public key format unrecognized"); + } + + try + { + SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()); + return spki.getPublicKeyData().getOctets(); + } + catch (Exception e) + { + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } + + static KeyFactory getKeyFactory(JcaTlsCrypto crypto, String kemName) + + { + try + { + return crypto.getHelper().createKeyFactory(kemName); + } + catch (AssertionError e) + { + } + catch (Exception e) + { + } + + return null; + } + + static KeyGenerator getKeyGenerator(JcaTlsCrypto crypto, String kemName) + { + try + { + return crypto.getHelper().createKeyGenerator(kemName); + } + catch (AssertionError e) + { + } + catch (Exception e) + { + } + + return null; + } + + static KeyPairGenerator getKeyPairGenerator(JcaTlsCrypto crypto, String kemName) + { + try + { + KeyPairGenerator keyPairGenerator = crypto.getHelper().createKeyPairGenerator("ML-KEM"); + keyPairGenerator.initialize(MLKEMParameterSpec.fromName(kemName), crypto.getSecureRandom()); + return keyPairGenerator; + } + catch (AssertionError e) + { + } + catch (Exception e) + { + } + + return null; + } + + static boolean isKemSupported(JcaTlsCrypto crypto, String kemName) + { + return kemName != null + && getKeyFactory(crypto, kemName) != null + && getKeyGenerator(crypto, kemName) != null + && getKeyPairGenerator(crypto, kemName) != null; + } + + private static X509EncodedKeySpec createX509EncodedKeySpec(ASN1ObjectIdentifier oid, byte[] encoding) + throws IOException + { + AlgorithmIdentifier algID = new AlgorithmIdentifier(oid); + SubjectPublicKeyInfo spki = new SubjectPublicKeyInfo(algID, encoding); + return new X509EncodedKeySpec(spki.getEncoded(ASN1Encoding.DER)); + } + + private static ASN1ObjectIdentifier getAlgorithmOID(String kemName) + { + if ("ML-KEM-512".equalsIgnoreCase(kemName)) + { + return NISTObjectIdentifiers.id_alg_ml_kem_512; + } + if ("ML-KEM-768".equalsIgnoreCase(kemName)) + { + return NISTObjectIdentifiers.id_alg_ml_kem_768; + } + if ("ML-KEM-1024".equalsIgnoreCase(kemName)) + { + return NISTObjectIdentifiers.id_alg_ml_kem_1024; + } + + throw new IllegalArgumentException("unknown kem name " + kemName); + } +} diff --git a/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/Exceptions.java b/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/Exceptions.java index 35d8c47f0b..7ec9f8a3d1 100644 --- a/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/Exceptions.java +++ b/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/Exceptions.java @@ -1,5 +1,7 @@ package org.bouncycastle.tls.crypto.impl.jcajce; +import java.io.IOException; + class Exceptions { static IllegalStateException illegalStateException(String message, Throwable cause) @@ -11,4 +13,9 @@ static IllegalArgumentException illegalArgumentException(String message, Throwab { return new org.bouncycastle.tls.exception.IllegalArgumentException(message, cause); } + + static IOException ioException(String message, Throwable cause) + { + return new org.bouncycastle.tls.exception.IOException(message, cause); + } } diff --git a/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCertificate.java b/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCertificate.java index f0d9fed6c3..dcf39c79fe 100644 --- a/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCertificate.java +++ b/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCertificate.java @@ -274,6 +274,11 @@ public Tls13Verifier createVerifier(int signatureScheme) throws IOException // TODO[RFC 8998] // case SignatureScheme.sm2sig_sm3: + case SignatureScheme.mldsa44: + case SignatureScheme.mldsa65: + case SignatureScheme.mldsa87: + return crypto.createTls13Verifier("ML-DSA", null, getPubKeyMLDSA()); + default: throw new TlsFatalAlert(AlertDescription.internal_error); } @@ -392,6 +397,11 @@ PublicKey getPubKeyRSA() throws IOException return getPublicKey(); } + PublicKey getPubKeyMLDSA() throws IOException + { + return getPublicKey(); + } + public short getLegacySignatureAlgorithm() throws IOException { PublicKey publicKey = getPublicKey(); diff --git a/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java b/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java index 5f5f6c7716..87619cbbdc 100644 --- a/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java +++ b/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java @@ -58,7 +58,10 @@ import org.bouncycastle.tls.crypto.TlsSecret; import org.bouncycastle.tls.crypto.TlsStreamSigner; import org.bouncycastle.tls.crypto.TlsStreamVerifier; +import org.bouncycastle.tls.crypto.impl.AEADNonceGenerator; +import org.bouncycastle.tls.crypto.impl.AEADNonceGeneratorFactory; import org.bouncycastle.tls.crypto.impl.AbstractTlsCrypto; +import org.bouncycastle.tls.crypto.impl.Tls13NullCipher; import org.bouncycastle.tls.crypto.impl.TlsAEADCipher; import org.bouncycastle.tls.crypto.impl.TlsAEADCipherImpl; import org.bouncycastle.tls.crypto.impl.TlsBlockCipher; @@ -75,14 +78,15 @@ /** * Class for providing cryptographic services for TLS based on implementations in the JCA/JCE. *

          - * This class provides default implementations for everything. If you need to customise it, extend the class - * and override the appropriate methods. + * This class provides default implementations for everything. If you need to customise it, extend the class + * and override the appropriate methods. *

          */ public class JcaTlsCrypto extends AbstractTlsCrypto { private final JcaJceHelper helper; + private final JcaJceHelper altHelper; private final SecureRandom entropySource; private final SecureRandom nonceEntropySource; @@ -93,13 +97,28 @@ public class JcaTlsCrypto /** * Base constructor. * - * @param helper a JCA/JCE helper configured for the class's default provider. - * @param entropySource primary entropy source, used for key generation. + * @param helper a JCA/JCE helper configured for the class's default provider. + * @param entropySource primary entropy source, used for key generation. * @param nonceEntropySource secondary entropy source, used for nonce and IV generation. */ protected JcaTlsCrypto(JcaJceHelper helper, SecureRandom entropySource, SecureRandom nonceEntropySource) + { + this(helper, null, entropySource, nonceEntropySource); + } + + /** + * Base constructor. + * + * @param helper a JCA/JCE helper configured for the class's default provider. + * @param altHelper a JCA/JCE helper configured for the class's secondary provider (tried for private keys). + * @param entropySource primary entropy source, used for key generation. + * @param nonceEntropySource secondary entropy source, used for nonce and IV generation. + */ + protected JcaTlsCrypto(JcaJceHelper helper, JcaJceHelper altHelper, SecureRandom entropySource, + SecureRandom nonceEntropySource) { this.helper = helper; + this.altHelper = altHelper; this.entropySource = entropySource; this.nonceEntropySource = nonceEntropySource; } @@ -109,7 +128,8 @@ JceTlsSecret adoptLocalSecret(byte[] data) return new JceTlsSecret(this, data); } - Cipher createRSAEncryptionCipher() throws GeneralSecurityException + Cipher createRSAEncryptionCipher() + throws GeneralSecurityException { try { @@ -226,6 +246,12 @@ public TlsCipher createCipher(TlsCryptoParameters cryptoParams, int encryptionAl return createChaCha20Poly1305(cryptoParams); case EncryptionAlgorithm.NULL: return createNullCipher(cryptoParams, macAlgorithm); + case EncryptionAlgorithm.NULL_HMAC_SHA256: + // NOTE: Ignores macAlgorithm + return create13NullCipher(cryptoParams, MACAlgorithm.hmac_sha256); + case EncryptionAlgorithm.NULL_HMAC_SHA384: + // NOTE: Ignores macAlgorithm + return create13NullCipher(cryptoParams, MACAlgorithm.hmac_sha384); case EncryptionAlgorithm.SEED_CBC: return createCipher_CBC(cryptoParams, "SEED", 16, macAlgorithm); case EncryptionAlgorithm.SM4_CBC: @@ -324,7 +350,7 @@ public TlsSRP6Client createSRP6Client(TlsSRPConfig srpConfig) final SRP6Client srpClient = new SRP6Client(); BigInteger[] ng = srpConfig.getExplicitNG(); - SRP6Group srpGroup= new SRP6Group(ng[0], ng[1]); + SRP6Group srpGroup = new SRP6Group(ng[0], ng[1]); srpClient.init(srpGroup, createHash(CryptoHashAlgorithm.sha1), this.getSecureRandom()); return new TlsSRP6Client() @@ -353,7 +379,7 @@ public TlsSRP6Server createSRP6Server(TlsSRPConfig srpConfig, BigInteger srpVeri { final SRP6Server srpServer = new SRP6Server(); BigInteger[] ng = srpConfig.getExplicitNG(); - SRP6Group srpGroup= new SRP6Group(ng[0], ng[1]); + SRP6Group srpGroup = new SRP6Group(ng[0], ng[1]); srpServer.init(srpGroup, srpVerifier, createHash(CryptoHashAlgorithm.sha1), this.getSecureRandom()); return new TlsSRP6Server() { @@ -418,22 +444,18 @@ String getHMACAlgorithmName(int cryptoHashAlgorithm) } } - public AlgorithmParameters getNamedGroupAlgorithmParameters(int namedGroup) throws GeneralSecurityException + public AlgorithmParameters getNamedGroupAlgorithmParameters(int namedGroup) + throws GeneralSecurityException { if (NamedGroup.refersToAnXDHCurve(namedGroup)) { - switch (namedGroup) - { /* - * TODO Return AlgorithmParameters to check against disabled algorithms - * + * TODO Return AlgorithmParameters to check against disabled algorithms? + * * NOTE: The JDK doesn't even support AlgorithmParameters for XDH, so SunJSSE also winds * up using null AlgorithmParameters when checking algorithm constraints. */ - case NamedGroup.x25519: - case NamedGroup.x448: - return null; - } + return null; } else if (NamedGroup.refersToAnECDSACurve(namedGroup)) { @@ -445,19 +467,12 @@ else if (NamedGroup.refersToASpecificFiniteField(namedGroup)) } else if (NamedGroup.refersToASpecificKem(namedGroup)) { - switch (namedGroup) - { /* - * TODO[tls-kem] Return AlgorithmParameters to check against disabled algorithms? + * TODO Return AlgorithmParameters to check against disabled algorithms? + * + * NOTE: See what the JDK/SunJSSE implementation does. */ - case NamedGroup.OQS_mlkem512: - case NamedGroup.OQS_mlkem768: - case NamedGroup.OQS_mlkem1024: - case NamedGroup.MLKEM512: - case NamedGroup.MLKEM768: - case NamedGroup.MLKEM1024: - return null; - } + return null; } throw new IllegalArgumentException("NamedGroup not supported: " + NamedGroup.getText(namedGroup)); @@ -582,11 +597,6 @@ public boolean hasECDHAgreement() { return true; } - - public boolean hasKemAgreement() - { - return true; - } public boolean hasEncryptionAlgorithm(int encryptionAlgorithm) { @@ -636,6 +646,11 @@ public boolean hasHKDFAlgorithm(int cryptoHashAlgorithm) } } + public boolean hasKemAgreement() + { + return true; + } + public boolean hasMacAlgorithm(int macAlgorithm) { switch (macAlgorithm) @@ -757,6 +772,12 @@ public boolean hasSignatureAlgorithm(short signatureAlgorithm) public boolean hasSignatureAndHashAlgorithm(SignatureAndHashAlgorithm sigAndHashAlgorithm) { + int signatureScheme = SignatureScheme.from(sigAndHashAlgorithm); + if (SignatureScheme.isMLDSA(signatureScheme)) + { + return true; + } + short signature = sigAndHashAlgorithm.getSignature(); switch (sigAndHashAlgorithm.getHash()) @@ -777,11 +798,15 @@ public boolean hasSignatureScheme(int signatureScheme) { case SignatureScheme.sm2sig_sm3: return false; + case SignatureScheme.mldsa44: + case SignatureScheme.mldsa65: + case SignatureScheme.mldsa87: + return true; default: { short signature = SignatureScheme.getSignatureAlgorithm(signatureScheme); - switch(SignatureScheme.getCryptoHashAlgorithm(signatureScheme)) + switch (SignatureScheme.getCryptoHashAlgorithm(signatureScheme)) { case CryptoHashAlgorithm.md5: return SignatureAlgorithm.rsa == signature && hasSignatureAlgorithm(signature); @@ -800,6 +825,11 @@ public boolean hasSRPAuthentication() return true; } + public TlsSecret createHybridSecret(TlsSecret s1, TlsSecret s2) + { + return adoptLocalSecret(Arrays.concatenate(s1.extract(), s2.extract())); + } + public TlsSecret createSecret(byte[] data) { try @@ -853,7 +883,7 @@ public TlsECDomain createECDomain(TlsECConfig ecConfig) return new JceTlsECDomain(this, ecConfig); } } - + public TlsKemDomain createKemDomain(TlsKemConfig kemConfig) { return new JceTlsMLKemDomain(this, kemConfig); @@ -891,8 +921,7 @@ protected TlsAEADCipherImpl createAEADCipher(String cipherName, String algorithm * @throws GeneralSecurityException in case of failure. */ protected TlsBlockCipherImpl createBlockCipher(String cipherName, String algorithm, int keySize, - boolean isEncrypting) - throws GeneralSecurityException + boolean isEncrypting) throws GeneralSecurityException { return new JceBlockCipherImpl(this, helper.createCipher(cipherName), algorithm, keySize, isEncrypting); } @@ -908,8 +937,7 @@ protected TlsBlockCipherImpl createBlockCipher(String cipherName, String algorit * @throws GeneralSecurityException in case of failure. */ protected TlsBlockCipherImpl createBlockCipherWithCBCImplicitIV(String cipherName, String algorithm, int keySize, - boolean isEncrypting) - throws GeneralSecurityException + boolean isEncrypting) throws GeneralSecurityException { return new JceBlockCipherWithCBCImplicitIVImpl(this, helper.createCipher(cipherName), algorithm, isEncrypting); } @@ -927,12 +955,18 @@ protected TlsHash createHash(String digestName) return new JcaTlsHash(helper.createDigest(digestName)); } + protected Tls13NullCipher create13NullCipher(TlsCryptoParameters cryptoParams, int macAlgorithm) + throws IOException + { + return new Tls13NullCipher(cryptoParams, createHMAC(macAlgorithm), createHMAC(macAlgorithm)); + } + /** * To disable the null cipher suite, override this method with one that throws an IOException. * * @param macAlgorithm the name of the algorithm supporting the MAC. * @return a null cipher suite implementation. - * @throws IOException in case of failure. + * @throws IOException in case of failure. * @throws GeneralSecurityException in case of a specific failure in the JCA/JCE layer. */ protected TlsNullCipher createNullCipher(TlsCryptoParameters cryptoParams, int macAlgorithm) @@ -953,32 +987,77 @@ protected TlsStreamSigner createStreamSigner(SignatureAndHashAlgorithm algorithm protected TlsStreamSigner createStreamSigner(String algorithmName, AlgorithmParameterSpec parameter, PrivateKey privateKey, boolean needsRandom) throws IOException { + SecureRandom random = needsRandom ? getSecureRandom() : null; + try { - SecureRandom random = needsRandom ? getSecureRandom() : null; - - JcaJceHelper helper = getHelper(); - try { - if (null != parameter) + return createStreamSigner(getHelper(), algorithmName, parameter, privateKey, random); + } + catch (InvalidKeyException e) + { + JcaJceHelper altHelper = getAltHelper(); + if (altHelper == null) { - Signature dummySigner = helper.createSignature(algorithmName); - dummySigner.initSign(privateKey, random); - helper = new ProviderJcaJceHelper(dummySigner.getProvider()); + throw e; } - Signature signer = helper.createSignature(algorithmName); - if (null != parameter) + return createStreamSigner(altHelper, algorithmName, parameter, privateKey, random); + } + } + catch (GeneralSecurityException e) + { + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } + + protected TlsStreamSigner createStreamSigner(JcaJceHelper helper, String algorithmName, + AlgorithmParameterSpec parameter, PrivateKey privateKey, SecureRandom random) throws GeneralSecurityException + { + try + { + if (null != parameter) + { + Signature dummySigner; + try { - signer.setParameter(parameter); + dummySigner = helper.createSignature(algorithmName); } - signer.initSign(privateKey, random); - return new JcaTlsStreamSigner(signer); + catch (NoSuchAlgorithmException e) + { +// // more PKCS#11 mischief +// String upperAlg = Strings.toUpperCase(algorithmName); +// if (upperAlg.endsWith("ANDMGF1")) +// { +// // ANDMGF1 has vanished from the Sun PKCS11 provider. +// algorithmName = upperAlg.replace("ANDMGF1", "SSA-PSS"); +// dummySigner = helper.createSignature(algorithmName); +// } +// else +// { + throw e; +// } + } + + dummySigner.initSign(privateKey, random); + helper = new ProviderJcaJceHelper(dummySigner.getProvider()); } - catch (InvalidKeyException e) + + Signature signer = helper.createSignature(algorithmName); + if (null != parameter) { - // not a concern in 1.4 it's all over if we get here. + signer.setParameter(parameter); + } + signer.initSign(privateKey, random); + return new JcaTlsStreamSigner(signer); + } + catch (InvalidKeyException e) + { + // not a concern in 1.4 it's all over if we get here. +// String upperAlg = Strings.toUpperCase(algorithmName); +// if (upperAlg.endsWith("ANDMGF1")) +// { // String upperAlg = Strings.toUpperCase(algorithmName); // if (upperAlg.endsWith("MGF1")) // { @@ -990,15 +1069,12 @@ protected TlsStreamSigner createStreamSigner(String algorithmName, AlgorithmPara // { throw e; // } - } - } - catch (GeneralSecurityException e) - { - throw new TlsFatalAlert(AlertDescription.internal_error, e); +// } } } - protected TlsStreamVerifier createStreamVerifier(DigitallySigned digitallySigned, PublicKey publicKey) throws IOException + protected TlsStreamVerifier createStreamVerifier(DigitallySigned digitallySigned, PublicKey publicKey) + throws IOException { String algorithmName = JcaUtils.getJcaAlgorithmName(digitallySigned.getAlgorithm()); @@ -1108,6 +1184,12 @@ protected Boolean isSupportedEncryptionAlgorithm(int encryptionAlgorithm) case EncryptionAlgorithm.SM4_GCM: return Boolean.valueOf(isUsableCipher("SM4/GCM/NoPadding", 128)); + case EncryptionAlgorithm.NULL_HMAC_SHA256: + return Boolean.valueOf(hasMacAlgorithm(MACAlgorithm.hmac_sha256)); + + case EncryptionAlgorithm.NULL_HMAC_SHA384: + return Boolean.valueOf(hasMacAlgorithm(MACAlgorithm.hmac_sha384)); + case EncryptionAlgorithm._28147_CNT_IMIT: case EncryptionAlgorithm.DES_CBC: case EncryptionAlgorithm.DES40_CBC: @@ -1156,8 +1238,7 @@ protected Boolean isSupportedNamedGroup(int namedGroup) } else if (NamedGroup.refersToASpecificKem(namedGroup)) { - // TODO[tls-kem] When implemented via provider, need to check for support dynamically - return Boolean.TRUE; + return Boolean.valueOf(KemUtil.isKemSupported(this, NamedGroup.getKemName(namedGroup))); } else if (NamedGroup.refersToAnECDSACurve(namedGroup)) { @@ -1210,6 +1291,11 @@ public JcaJceHelper getHelper() return helper; } + public JcaJceHelper getAltHelper() + { + return altHelper; + } + protected TlsBlockCipherImpl createCBCBlockCipherImpl(TlsCryptoParameters cryptoParams, String algorithm, int cipherKeySize, boolean forEncryption) throws GeneralSecurityException { @@ -1229,7 +1315,7 @@ private TlsCipher createChaCha20Poly1305(TlsCryptoParameters cryptoParams) throws IOException, GeneralSecurityException { return new TlsAEADCipher(cryptoParams, new JceChaCha20Poly1305(this, helper, true), - new JceChaCha20Poly1305(this, helper, false), 32, 16, TlsAEADCipher.AEAD_CHACHA20_POLY1305); + new JceChaCha20Poly1305(this, helper, false), 32, 16, TlsAEADCipher.AEAD_CHACHA20_POLY1305, null); } private TlsAEADCipher createCipher_AES_CCM(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) @@ -1237,7 +1323,7 @@ private TlsAEADCipher createCipher_AES_CCM(TlsCryptoParameters cryptoParams, int { return new TlsAEADCipher(cryptoParams, createAEADCipher("AES/CCM/NoPadding", "AES", cipherKeySize, true), createAEADCipher("AES/CCM/NoPadding", "AES", cipherKeySize, false), cipherKeySize, macSize, - TlsAEADCipher.AEAD_CCM); + TlsAEADCipher.AEAD_CCM, null); } private TlsAEADCipher createCipher_AES_GCM(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) @@ -1245,7 +1331,7 @@ private TlsAEADCipher createCipher_AES_GCM(TlsCryptoParameters cryptoParams, int { return new TlsAEADCipher(cryptoParams, createAEADCipher("AES/GCM/NoPadding", "AES", cipherKeySize, true), createAEADCipher("AES/GCM/NoPadding", "AES", cipherKeySize, false), cipherKeySize, macSize, - TlsAEADCipher.AEAD_GCM); + TlsAEADCipher.AEAD_GCM, getFipsGCMNonceGeneratorFactory()); } private TlsAEADCipher createCipher_ARIA_GCM(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) @@ -1253,7 +1339,7 @@ private TlsAEADCipher createCipher_ARIA_GCM(TlsCryptoParameters cryptoParams, in { return new TlsAEADCipher(cryptoParams, createAEADCipher("ARIA/GCM/NoPadding", "ARIA", cipherKeySize, true), createAEADCipher("ARIA/GCM/NoPadding", "ARIA", cipherKeySize, false), cipherKeySize, macSize, - TlsAEADCipher.AEAD_GCM); + TlsAEADCipher.AEAD_GCM, getFipsGCMNonceGeneratorFactory()); } private TlsAEADCipher createCipher_Camellia_GCM(TlsCryptoParameters cryptoParams, int cipherKeySize, int macSize) @@ -1262,7 +1348,7 @@ private TlsAEADCipher createCipher_Camellia_GCM(TlsCryptoParameters cryptoParams return new TlsAEADCipher(cryptoParams, createAEADCipher("Camellia/GCM/NoPadding", "Camellia", cipherKeySize, true), createAEADCipher("Camellia/GCM/NoPadding", "Camellia", cipherKeySize, false), cipherKeySize, macSize, - TlsAEADCipher.AEAD_GCM); + TlsAEADCipher.AEAD_GCM, getFipsGCMNonceGeneratorFactory()); } protected TlsCipher createCipher_CBC(TlsCryptoParameters cryptoParams, String algorithm, int cipherKeySize, @@ -1283,7 +1369,7 @@ private TlsAEADCipher createCipher_SM4_CCM(TlsCryptoParameters cryptoParams) int cipherKeySize = 16, macSize = 16; return new TlsAEADCipher(cryptoParams, createAEADCipher("SM4/CCM/NoPadding", "SM4", cipherKeySize, true), createAEADCipher("SM4/CCM/NoPadding", "SM4", cipherKeySize, false), cipherKeySize, macSize, - TlsAEADCipher.AEAD_CCM); + TlsAEADCipher.AEAD_CCM, null); } private TlsAEADCipher createCipher_SM4_GCM(TlsCryptoParameters cryptoParams) @@ -1292,7 +1378,27 @@ private TlsAEADCipher createCipher_SM4_GCM(TlsCryptoParameters cryptoParams) int cipherKeySize = 16, macSize = 16; return new TlsAEADCipher(cryptoParams, createAEADCipher("SM4/GCM/NoPadding", "SM4", cipherKeySize, true), createAEADCipher("SM4/GCM/NoPadding", "SM4", cipherKeySize, false), cipherKeySize, macSize, - TlsAEADCipher.AEAD_GCM); + TlsAEADCipher.AEAD_GCM, getFipsGCMNonceGeneratorFactory()); + } + + /** + * Optionally return an {@link AEADNonceGeneratorFactory} that creates {@link AEADNonceGenerator} + * instances suitable for generating TLS 1.2 GCM nonces in a FIPS approved way (or null). It is not needed + * or intended to be used in a non-FIPS context. + *

          + * Clients of this {@link JcaTlsCrypto} instance MAY assume from a non-null return value that the + * resulting {@link AEADNonceGenerator} implementation(s) are FIPS compliant; implementations that violate + * this assumption risk FIPS compliance failures. + *

          + * In particular, when BCJSSE is configured in FIPS mode, GCM cipher suites are enabled for TLS 1.2 if + * (and only if) a call to this method returns a non-null value. This can be achieved by configuring + * BCJSSE with a user-defined {@link JcaTlsCryptoProvider} subclass, which in turn creates instances of a + * {@link JcaTlsCrypto} subclass, with this method overridden to return a suitable + * {@link AEADNonceGeneratorFactory}. + */ + public AEADNonceGeneratorFactory getFipsGCMNonceGeneratorFactory() + { + return GCMFipsUtil.getDefaultFipsGCMNonceGeneratorFactory(); } String getDigestName(int cryptoHashAlgorithm) diff --git a/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JceAEADCipherImpl.java b/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JceAEADCipherImpl.java index e7000f5102..e80256a6f4 100644 --- a/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JceAEADCipherImpl.java +++ b/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JceAEADCipherImpl.java @@ -6,6 +6,7 @@ import java.security.GeneralSecurityException; import java.security.PrivilegedAction; import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; import javax.crypto.Cipher; import javax.crypto.SecretKey; @@ -68,6 +69,9 @@ private static String getAlgParamsName(JcaJceHelper helper, String cipherName) private SecretKey key; + private byte[] noncePre7; + private int macSizePre7; + public JceAEADCipherImpl(JcaTlsCrypto crypto, JcaJceHelper helper, String cipherName, String algorithm, int keySize, boolean isEncrypting) throws GeneralSecurityException @@ -91,9 +95,6 @@ public void setKey(byte[] key, int keyOff, int keyLen) this.key = new SecretKeySpec(key, keyOff, keyLen, algorithm); } - private byte[] nonce; - private int macSize; - public void init(byte[] nonce, int macSize) { // NOTE: Shouldn't need a SecureRandom, but this is cheaper if the provider would auto-create one @@ -104,23 +105,44 @@ public void init(byte[] nonce, int macSize) // if (canDoAEAD && algorithmParamsName != null) // { // AlgorithmParameters algParams = helper.createAlgorithmParameters(algorithmParamsName); -// -// // fortunately CCM and GCM parameters have the same ASN.1 structure -// algParams.init(new GCMParameters(nonce, macSize).getEncoded()); -// -// cipher.init(cipherMode, key, algParams); -// -// if (additionalData != null && additionalData.length > 0) +// +// // believe it or not but there are things out there that do not support the ASN.1 encoding... +// if (GCMUtil.isGCMParameterSpecAvailable()) +// { +// algParams.init(GCMUtil.createGCMParameterSpec(macSize * 8, nonce)); +// } +// else // { -// cipher.updateAAD(additionalData); +// // fortunately CCM and GCM parameters have the same ASN.1 structure +// algParams.init(new GCMParameters(nonce, macSize).getEncoded()); // } +// +// cipher.init(cipherMode, key, algParams, random); // } // else // { - // Otherwise fall back to the BC-specific AEADParameterSpec - this.nonce = Arrays.clone(nonce); - this.macSize = macSize; - // } + /* + * Otherwise fall back to the BC-specific AEADParameterSpec. Since updateAAD is not available, we + * need to use init to pass the associated data (in doFinal), but in order to call getOutputSize we + * technically need to init the cipher first. So we init with a dummy nonce to avoid duplicate nonce + * error from the init in doFinal. + */ + + if (this.noncePre7 == null || this.noncePre7.length != nonce.length) + { + this.noncePre7 = new byte[nonce.length]; + } + + System.arraycopy(nonce, 0, this.noncePre7, 0, nonce.length); + this.macSizePre7 = macSize; + + this.noncePre7[0] ^= 0x80; + + AlgorithmParameterSpec params = new AEADParameterSpec(noncePre7, macSizePre7 * 8, null); + cipher.init(cipherMode, key, params, random); + + this.noncePre7[0] ^= 0x80; +// } } catch (Exception e) { @@ -136,20 +158,27 @@ public int getOutputSize(int inputLength) public int doFinal(byte[] additionalData, byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset) throws IOException { - try - { - if (!Arrays.isNullOrEmpty(additionalData)) - { - cipher.init(cipherMode, key, new AEADParameterSpec(nonce, macSize * 8, additionalData)); - } - else - { - cipher.init(cipherMode, key, new AEADParameterSpec(nonce, macSize * 8, null)); - } - } - catch (Exception e) + if (!Arrays.isNullOrEmpty(additionalData)) { - throw new IOException(e.toString()); +// if (canDoAEAD) +// { +// cipher.updateAAD(additionalData); +// } +// else +// { + try + { + // NOTE: Shouldn't need a SecureRandom, but this is cheaper if the provider would auto-create one + SecureRandom random = crypto.getSecureRandom(); + + AlgorithmParameterSpec params = new AEADParameterSpec(noncePre7, macSizePre7 * 8, additionalData); + cipher.init(cipherMode, key, params, random); + } + catch (Exception e) + { + throw Exceptions.ioException(e.getMessage(), e); + } +// } } /* diff --git a/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java b/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java index ea31085d2e..6bd4b34fca 100644 --- a/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java +++ b/tls/src/main/jdk1.4/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsECDomain.java @@ -32,9 +32,6 @@ public class JceTlsECDomain implements TlsECDomain { protected final JcaTlsCrypto crypto; - protected final TlsECConfig ecConfig; - - protected ECNamedCurveGenParameterSpec ecGenSpec; protected ECParameterSpec ecParameterSpec; protected ECCurve ecCurve; @@ -42,7 +39,6 @@ public class JceTlsECDomain public JceTlsECDomain(JcaTlsCrypto crypto, TlsECConfig ecConfig) { this.crypto = crypto; - this.ecConfig = ecConfig; init(ecConfig.getNamedGroup()); } diff --git a/tls/src/main/jdk1.4/org/bouncycastle/tls/exception/IOException.java b/tls/src/main/jdk1.4/org/bouncycastle/tls/exception/IOException.java new file mode 100644 index 0000000000..5d1567d155 --- /dev/null +++ b/tls/src/main/jdk1.4/org/bouncycastle/tls/exception/IOException.java @@ -0,0 +1,30 @@ +package org.bouncycastle.tls.exception; + +public class IOException + extends java.io.IOException +{ + final Throwable cause; + + public IOException(Throwable cause) + { + this.cause = cause; + } + + public IOException(String message, Throwable cause) + { + super(message); + this.cause = cause; + } + + + public IOException(String s) + { + super(s); + this.cause = null; + } + + public Throwable getCause() + { + return cause; + } +} diff --git a/tls/src/main/jdk1.5/org/bouncycastle/jsse/provider/SSLParametersUtil.java b/tls/src/main/jdk1.5/org/bouncycastle/jsse/provider/SSLParametersUtil.java index 237ca8cf24..f60ca572aa 100644 --- a/tls/src/main/jdk1.5/org/bouncycastle/jsse/provider/SSLParametersUtil.java +++ b/tls/src/main/jdk1.5/org/bouncycastle/jsse/provider/SSLParametersUtil.java @@ -79,12 +79,14 @@ static BCSSLParameters getParameters(ProvSSLParameters prov) ssl.setServerNames(prov.getServerNames()); ssl.setSNIMatchers(prov.getSNIMatchers()); ssl.setUseCipherSuitesOrder(prov.getUseCipherSuitesOrder()); + ssl.setUseNamedGroupsOrder(prov.getUseNamedGroupsOrder()); ssl.setApplicationProtocols(prov.getApplicationProtocols()); ssl.setEnableRetransmissions(prov.getEnableRetransmissions()); ssl.setMaximumPacketSize(prov.getMaximumPacketSize()); ssl.setSignatureSchemes(prov.getSignatureSchemes()); ssl.setSignatureSchemesCert(prov.getSignatureSchemesCert()); ssl.setNamedGroups(prov.getNamedGroups()); + ssl.setEarlyKeyShares(prov.getEarlyKeyShares()); return ssl; } @@ -180,6 +182,16 @@ static SSLParameters getSSLParameters(ProvSSLParameters prov) // Unsupported as of JDK 21 +// if (null != setEarlyKeyShares) +// { +// set(ssl, setEarlyKeyShares, prov.getEarlyKeyShares()); +// } + +// if (null != setUseNamedGroupsOrder) +// { +// set(ssl, setUseNamedGroupsOrder, prov.getUseNamedGroupsOrder()); +// } + // if (null != setSignatureSchemesCert) // { // set(ssl, setSignatureSchemesCert, prov.getSignatureSchemesCert()); @@ -286,6 +298,16 @@ static BCSSLParameters importSSLParameters(SSLParameters ssl) // Unsupported as of JDK 21 +// if (null != getEarlyKeyShares) +// { +// bc.setEarlyKeyShares((String[])get(ssl, getEarlyKeyShares)); +// } + +// if (null != getUseNamedGroupsOrder) +// { +// bc.setUseNamedGroupsOrder((Boolean)get(ssl, getUseNamedGroupsOrder)); +// } + // if (null != getSignatureSchemesCert) // { // bc.setSignatureSchemesCert((String[])get(ssl, getSignatureSchemesCert)); @@ -344,6 +366,8 @@ static void setParameters(ProvSSLParameters prov, BCSSLParameters ssl) prov.setUseCipherSuitesOrder(ssl.getUseCipherSuitesOrder()); + prov.setUseNamedGroupsOrder(ssl.getUseNamedGroupsOrder()); + String[] applicationProtocols = ssl.getApplicationProtocols(); if (null != applicationProtocols) { @@ -358,6 +382,8 @@ static void setParameters(ProvSSLParameters prov, BCSSLParameters ssl) prov.setNamedGroups(ssl.getNamedGroups()); + prov.setEarlyKeyShares(ssl.getEarlyKeyShares()); + prov.setSignatureSchemesCert(ssl.getSignatureSchemesCert()); } @@ -469,6 +495,16 @@ static void setSSLParameters(ProvSSLParameters prov, SSLParameters ssl) // Unsupported as of JDK 21 +// if (null != getEarlyKeyShares) +// { +// prov.setEarlyKeyShares((String[])get(ssl, getEarlyKeyShares)); +// } + +// if (null != getUseNamedGroupsOrder) +// { +// prov.setUseNamedGroupsOrder((Boolean)get(ssl, getUseNamedGroupsOrder)); +// } + // if (null != getSignatureSchemesCert) // { // prov.setSignatureSchemesCert((String[])get(ssl, getSignatureSchemesCert)); diff --git a/tls/src/main/jdk1.5/org/bouncycastle/tls/crypto/impl/jcajce/PrivateKeyUtil.java b/tls/src/main/jdk1.5/org/bouncycastle/tls/crypto/impl/jcajce/PrivateKeyUtil.java new file mode 100644 index 0000000000..333fed9825 --- /dev/null +++ b/tls/src/main/jdk1.5/org/bouncycastle/tls/crypto/impl/jcajce/PrivateKeyUtil.java @@ -0,0 +1,22 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.PrivateKey; + +import javax.security.auth.Destroyable; + +abstract class PrivateKeyUtil +{ + static void destroy(PrivateKey privateKey) + { + if (privateKey instanceof Destroyable) + { + try + { + ((Destroyable)privateKey).destroy(); + } + catch (Exception e) + { + } + } + } +} diff --git a/tls/src/main/jdk1.5/org/bouncycastle/tls/crypto/impl/jcajce/SecretKeyUtil.java b/tls/src/main/jdk1.5/org/bouncycastle/tls/crypto/impl/jcajce/SecretKeyUtil.java new file mode 100644 index 0000000000..b8f3573387 --- /dev/null +++ b/tls/src/main/jdk1.5/org/bouncycastle/tls/crypto/impl/jcajce/SecretKeyUtil.java @@ -0,0 +1,21 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import javax.crypto.SecretKey; +import javax.security.auth.Destroyable; + +abstract class SecretKeyUtil +{ + static void destroy(SecretKey secretKey) + { + if (secretKey instanceof Destroyable) + { + try + { + ((Destroyable)secretKey).destroy(); + } + catch (Exception e) + { + } + } + } +} diff --git a/tls/src/main/jdk1.9/org/bouncycastle/jsse/provider/SSLParametersUtil.java b/tls/src/main/jdk1.9/org/bouncycastle/jsse/provider/SSLParametersUtil.java index 02ae707506..98923a4045 100644 --- a/tls/src/main/jdk1.9/org/bouncycastle/jsse/provider/SSLParametersUtil.java +++ b/tls/src/main/jdk1.9/org/bouncycastle/jsse/provider/SSLParametersUtil.java @@ -50,12 +50,14 @@ static BCSSLParameters getParameters(ProvSSLParameters prov) ssl.setServerNames(prov.getServerNames()); ssl.setSNIMatchers(prov.getSNIMatchers()); ssl.setUseCipherSuitesOrder(prov.getUseCipherSuitesOrder()); + ssl.setUseNamedGroupsOrder(prov.getUseNamedGroupsOrder()); ssl.setApplicationProtocols(prov.getApplicationProtocols()); ssl.setEnableRetransmissions(prov.getEnableRetransmissions()); ssl.setMaximumPacketSize(prov.getMaximumPacketSize()); ssl.setSignatureSchemes(prov.getSignatureSchemes()); ssl.setSignatureSchemesCert(prov.getSignatureSchemesCert()); ssl.setNamedGroups(prov.getNamedGroups()); + ssl.setEarlyKeyShares(prov.getEarlyKeyShares()); return ssl; } @@ -132,6 +134,16 @@ static SSLParameters getSSLParameters(ProvSSLParameters prov) // Unsupported as of JDK 21 +// if (null != setEarlyKeyShares) +// { +// set(ssl, setEarlyKeyShares, prov.getEarlyKeyShares()); +// } + +// if (null != setUseNamedGroupsOrder) +// { +// set(ssl, setUseNamedGroupsOrder, prov.getUseNamedGroupsOrder()); +// } + // if (null != setSignatureSchemesCert) // { // set(ssl, setSignatureSchemesCert, prov.getSignatureSchemesCert()); @@ -224,6 +236,16 @@ static BCSSLParameters importSSLParameters(SSLParameters ssl) // Unsupported as of JDK 21 +// if (null != getEarlyKeyShares) +// { +// bc.setEarlyKeyShares((String[])get(ssl, getEarlyKeyShares)); +// } + +// if (null != getUseNamedGroupsOrder) +// { +// bc.setUseNamedGroupsOrder((Boolean)get(ssl, getUseNamedGroupsOrder)); +// } + // if (null != getSignatureSchemesCert) // { // bc.setSignatureSchemesCert((String[])get(ssl, getSignatureSchemesCert)); @@ -282,6 +304,8 @@ static void setParameters(ProvSSLParameters prov, BCSSLParameters ssl) prov.setUseCipherSuitesOrder(ssl.getUseCipherSuitesOrder()); + prov.setUseNamedGroupsOrder(ssl.getUseNamedGroupsOrder()); + String[] applicationProtocols = ssl.getApplicationProtocols(); if (null != applicationProtocols) { @@ -296,6 +320,8 @@ static void setParameters(ProvSSLParameters prov, BCSSLParameters ssl) prov.setNamedGroups(ssl.getNamedGroups()); + prov.setEarlyKeyShares(ssl.getEarlyKeyShares()); + prov.setSignatureSchemesCert(ssl.getSignatureSchemesCert()); } @@ -393,6 +419,16 @@ static void setSSLParameters(ProvSSLParameters prov, SSLParameters ssl) // Unsupported as of JDK 21 +// if (null != getEarlyKeyShares) +// { +// prov.setEarlyKeyShares((String[])get(ssl, getEarlyKeyShares)); +// } + +// if (null != getUseNamedGroupsOrder) +// { +// prov.setUseNamedGroupsOrder((Boolean)get(ssl, getUseNamedGroupsOrder)); +// } + // if (null != getSignatureSchemesCert) // { // prov.setSignatureSchemesCert((String[])get(ssl, getSignatureSchemesCert)); diff --git a/tls/src/main/jdk1.9/org/bouncycastle/tls/crypto/impl/jcajce/PrivateKeyUtil.java b/tls/src/main/jdk1.9/org/bouncycastle/tls/crypto/impl/jcajce/PrivateKeyUtil.java new file mode 100644 index 0000000000..3b9b40ed36 --- /dev/null +++ b/tls/src/main/jdk1.9/org/bouncycastle/tls/crypto/impl/jcajce/PrivateKeyUtil.java @@ -0,0 +1,20 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import java.security.PrivateKey; + +abstract class PrivateKeyUtil +{ + void destroy(PrivateKey privateKey) + { + if (privateKey != null) + { + try + { + privateKey.destroy(); + } + catch (Exception e) + { + } + } + } +} diff --git a/tls/src/main/jdk1.9/org/bouncycastle/tls/crypto/impl/jcajce/SecretKeyUtil.java b/tls/src/main/jdk1.9/org/bouncycastle/tls/crypto/impl/jcajce/SecretKeyUtil.java new file mode 100644 index 0000000000..e335edc6be --- /dev/null +++ b/tls/src/main/jdk1.9/org/bouncycastle/tls/crypto/impl/jcajce/SecretKeyUtil.java @@ -0,0 +1,21 @@ +package org.bouncycastle.tls.crypto.impl.jcajce; + +import javax.crypto.SecretKey; +import javax.security.auth.Destroyable; + +abstract class SecretKeyUtil +{ + static void destroy(SecretKey secretKey) + { + if (secretKey != null) + { + try + { + ((Destroyable)secretKey).destroy(); + } + catch (Exception e) + { + } + } + } +} diff --git a/tls/src/main/jdk25/org/bouncycastle/jsse/provider/ExportSSLSession_25.java b/tls/src/main/jdk25/org/bouncycastle/jsse/provider/ExportSSLSession_25.java new file mode 100644 index 0000000000..a02ed7532f --- /dev/null +++ b/tls/src/main/jdk25/org/bouncycastle/jsse/provider/ExportSSLSession_25.java @@ -0,0 +1,28 @@ +package org.bouncycastle.jsse.provider; + +import javax.crypto.SecretKey; +import javax.net.ssl.SSLKeyException; + +import org.bouncycastle.jsse.BCExtendedSSLSession; + +class ExportSSLSession_25 + extends ExportSSLSession_9 +{ + ExportSSLSession_25(BCExtendedSSLSession sslSession) + { + super(sslSession); + } + + @Override + public byte[] exportKeyingMaterialData(String label, byte[] context, int length) throws SSLKeyException + { + return sslSession.exportKeyingMaterialData(label, context, length); + } + + @Override + public SecretKey exportKeyingMaterialKey(String keyAlg, String label, byte[] context, int length) + throws SSLKeyException + { + return sslSession.exportKeyingMaterialKey(keyAlg, label, context, length); + } +} diff --git a/tls/src/main/jdk25/org/bouncycastle/jsse/provider/ImportSSLSession_25.java b/tls/src/main/jdk25/org/bouncycastle/jsse/provider/ImportSSLSession_25.java new file mode 100644 index 0000000000..4e170a1eb5 --- /dev/null +++ b/tls/src/main/jdk25/org/bouncycastle/jsse/provider/ImportSSLSession_25.java @@ -0,0 +1,27 @@ +package org.bouncycastle.jsse.provider; + +import javax.crypto.SecretKey; +import javax.net.ssl.ExtendedSSLSession; +import javax.net.ssl.SSLKeyException; + +class ImportSSLSession_25 + extends ImportSSLSession_9 +{ + ImportSSLSession_25(ExtendedSSLSession sslSession) + { + super(sslSession); + } + + @Override + public byte[] exportKeyingMaterialData(String label, byte[] context, int length) throws SSLKeyException + { + return sslSession.exportKeyingMaterialData(label, context, length); + } + + @Override + public SecretKey exportKeyingMaterialKey(String keyAlg, String label, byte[] context, int length) + throws SSLKeyException + { + return sslSession.exportKeyingMaterialKey(keyAlg, label, context, length); + } +} diff --git a/tls/src/main/jdk25/org/bouncycastle/jsse/provider/SSLSessionUtil.java b/tls/src/main/jdk25/org/bouncycastle/jsse/provider/SSLSessionUtil.java new file mode 100644 index 0000000000..3bd223ab80 --- /dev/null +++ b/tls/src/main/jdk25/org/bouncycastle/jsse/provider/SSLSessionUtil.java @@ -0,0 +1,39 @@ +package org.bouncycastle.jsse.provider; + +import javax.net.ssl.ExtendedSSLSession; +import javax.net.ssl.SSLSession; + +import org.bouncycastle.jsse.BCExtendedSSLSession; + +abstract class SSLSessionUtil +{ + static SSLSession exportSSLSession(BCExtendedSSLSession sslSession) + { + if (sslSession instanceof ImportSSLSession) + { + return ((ImportSSLSession)sslSession).unwrap(); + } + + return new ExportSSLSession_25(sslSession); + } + + static BCExtendedSSLSession importSSLSession(SSLSession sslSession) + { + if (sslSession instanceof BCExtendedSSLSession) + { + return (BCExtendedSSLSession)sslSession; + } + + if (sslSession instanceof ExportSSLSession) + { + return ((ExportSSLSession)sslSession).unwrap(); + } + + if (sslSession instanceof ExtendedSSLSession) + { + return new ImportSSLSession_25((ExtendedSSLSession)sslSession); + } + + return new ImportSSLSession_5(sslSession); + } +} diff --git a/tls/src/test/java/org/bouncycastle/jsse/provider/test/AllTests.java b/tls/src/test/java/org/bouncycastle/jsse/provider/test/AllTests.java index 3207896b59..cfc1048fe6 100644 --- a/tls/src/test/java/org/bouncycastle/jsse/provider/test/AllTests.java +++ b/tls/src/test/java/org/bouncycastle/jsse/provider/test/AllTests.java @@ -4,6 +4,7 @@ import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; + import org.bouncycastle.test.PrintTestResult; public class AllTests @@ -27,7 +28,9 @@ public static Test suite() suite.addTestSuite(EdDSACredentialsTest.class); suite.addTestSuite(InstanceTest.class); suite.addTestSuite(KeyManagerFactoryTest.class); + suite.addTestSuite(MLDSACredentialsTest.class); suite.addTestSuite(PSSCredentialsTest.class); + suite.addTestSuite(SLHDSACredentialsTest.class); suite.addTestSuite(SSLServerSocketTest.class); suite.addTestSuite(SSLSocketTest.class); diff --git a/tls/src/test/java/org/bouncycastle/jsse/provider/test/BCJSSEClientTest.java b/tls/src/test/java/org/bouncycastle/jsse/provider/test/BCJSSEClientTest.java index e799f74ef9..cb8b50f5bc 100644 --- a/tls/src/test/java/org/bouncycastle/jsse/provider/test/BCJSSEClientTest.java +++ b/tls/src/test/java/org/bouncycastle/jsse/provider/test/BCJSSEClientTest.java @@ -265,7 +265,7 @@ private static void writeUTF8Line(OutputStream output, String line) System.out.println(">>> " + line); } - private static KeyStore createKeyStore() throws Exception + static KeyStore createKeyStore() throws Exception { // KeyStore keyStore = KeyStore.getInstance("PKCS12"); KeyStore keyStore = KeyStore.getInstance("PKCS12", ProviderUtils.PROVIDER_NAME_BC); @@ -273,14 +273,14 @@ private static KeyStore createKeyStore() throws Exception return keyStore; } - private static X509Certificate loadCertificate(String certPath) throws Exception + static X509Certificate loadCertificate(String certPath) throws Exception { byte[] certEncoding = loadPEMContents(certPath, "CERTIFICATE"); CertificateFactory cf = CertificateFactory.getInstance("X.509"); return (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(certEncoding)); } - private static PrivateKey loadKey(String keyPath) throws Exception + static PrivateKey loadKey(String keyPath) throws Exception { byte[] keyEncoding = loadPEMContents(keyPath, "PRIVATE KEY"); @@ -305,7 +305,7 @@ private static PrivateKey loadKey(String keyPath) throws Exception // } } - private static KeyStore loadKeyStore(String alias, String certPath, String keyPath) throws Exception + static KeyStore loadKeyStore(String alias, String certPath, String keyPath) throws Exception { X509Certificate cert = loadCertificate(certPath); PrivateKey key = loadKey(keyPath); @@ -315,7 +315,7 @@ private static KeyStore loadKeyStore(String alias, String certPath, String keyPa return keyStore; } - private static KeyStore loadTrustStore(String caPath) throws Exception + static KeyStore loadTrustStore(String caPath) throws Exception { X509Certificate caCert = loadCertificate(caPath); @@ -325,7 +325,7 @@ private static KeyStore loadTrustStore(String caPath) throws Exception return trustStore; } - private static byte[] loadPEMContents(String path, String type) throws IOException + static byte[] loadPEMContents(String path, String type) throws IOException { InputStream s = new FileInputStream(path); PemReader p = new PemReader(new InputStreamReader(s)); diff --git a/tls/src/test/java/org/bouncycastle/jsse/provider/test/CipherSuitesEngineTestSuite.java b/tls/src/test/java/org/bouncycastle/jsse/provider/test/CipherSuitesEngineTestSuite.java index e67985c24b..2022028861 100644 --- a/tls/src/test/java/org/bouncycastle/jsse/provider/test/CipherSuitesEngineTestSuite.java +++ b/tls/src/test/java/org/bouncycastle/jsse/provider/test/CipherSuitesEngineTestSuite.java @@ -35,7 +35,7 @@ public boolean isIgnored(String cipherSuite) * we could modify that security property when running this test suite. */ return cipherSuite.contains("_WITH_NULL_") || cipherSuite.contains("_WITH_3DES_EDE_CBC_") - || cipherSuite.contains("_anon_"); + || cipherSuite.contains("_anon_") || cipherSuite.startsWith("TLS_SHA"); } public boolean isPermitted(String cipherSuite) diff --git a/tls/src/test/java/org/bouncycastle/jsse/provider/test/CipherSuitesTestSuite.java b/tls/src/test/java/org/bouncycastle/jsse/provider/test/CipherSuitesTestSuite.java index a9393f884b..7107fe2b3e 100644 --- a/tls/src/test/java/org/bouncycastle/jsse/provider/test/CipherSuitesTestSuite.java +++ b/tls/src/test/java/org/bouncycastle/jsse/provider/test/CipherSuitesTestSuite.java @@ -34,7 +34,7 @@ public boolean isIgnored(String cipherSuite) * we could modify that security property when running this test suite. */ return cipherSuite.contains("_WITH_NULL_") || cipherSuite.contains("_WITH_3DES_EDE_CBC_") - || cipherSuite.contains("_anon_"); + || cipherSuite.contains("_anon_") || cipherSuite.startsWith("TLS_SHA"); } public boolean isPermitted(String cipherSuite) diff --git a/tls/src/test/java/org/bouncycastle/jsse/provider/test/EdDSACredentialsTest.java b/tls/src/test/java/org/bouncycastle/jsse/provider/test/EdDSACredentialsTest.java index a5bb4a4281..8e4c265257 100644 --- a/tls/src/test/java/org/bouncycastle/jsse/provider/test/EdDSACredentialsTest.java +++ b/tls/src/test/java/org/bouncycastle/jsse/provider/test/EdDSACredentialsTest.java @@ -28,10 +28,10 @@ protected void setUp() } private static final String HOST = "localhost"; - private static final int PORT_NO_12_ED25519 = 9020; - private static final int PORT_NO_12_ED448 = 9021; - private static final int PORT_NO_13_ED25519 = 9022; - private static final int PORT_NO_13_ED448 = 9023; + private static final int PORT_NO_12_ED25519 = 9050; + private static final int PORT_NO_12_ED448 = 9051; + private static final int PORT_NO_13_ED25519 = 9052; + private static final int PORT_NO_13_ED448 = 9053; static class EdDSAClient implements TestProtocolUtil.BlockingCallable diff --git a/tls/src/test/java/org/bouncycastle/jsse/provider/test/FipsJcaTlsCrypto.java b/tls/src/test/java/org/bouncycastle/jsse/provider/test/FipsJcaTlsCrypto.java index a7fceeb31f..a7b1a4fef4 100644 --- a/tls/src/test/java/org/bouncycastle/jsse/provider/test/FipsJcaTlsCrypto.java +++ b/tls/src/test/java/org/bouncycastle/jsse/provider/test/FipsJcaTlsCrypto.java @@ -14,6 +14,12 @@ public FipsJcaTlsCrypto(JcaJceHelper helper, SecureRandom entropySource, SecureR super(helper, entropySource, nonceEntropySource); } + public FipsJcaTlsCrypto(JcaJceHelper helper, JcaJceHelper altHelper, SecureRandom entropySource, + SecureRandom nonceEntropySource) + { + super(helper, altHelper, entropySource, nonceEntropySource); + } + @Override public AEADNonceGeneratorFactory getFipsGCMNonceGeneratorFactory() { diff --git a/tls/src/test/java/org/bouncycastle/jsse/provider/test/FipsJcaTlsCryptoProvider.java b/tls/src/test/java/org/bouncycastle/jsse/provider/test/FipsJcaTlsCryptoProvider.java index 8bb004e806..4781f119db 100644 --- a/tls/src/test/java/org/bouncycastle/jsse/provider/test/FipsJcaTlsCryptoProvider.java +++ b/tls/src/test/java/org/bouncycastle/jsse/provider/test/FipsJcaTlsCryptoProvider.java @@ -10,6 +10,6 @@ public class FipsJcaTlsCryptoProvider extends JcaTlsCryptoProvider @Override public JcaTlsCrypto create(SecureRandom keyRandom, SecureRandom nonceRandom) { - return new FipsJcaTlsCrypto(getHelper(), keyRandom, nonceRandom); + return new FipsJcaTlsCrypto(getHelper(), getAltHelper(), keyRandom, nonceRandom); } } diff --git a/tls/src/test/java/org/bouncycastle/jsse/provider/test/KeyManagerFactoryTest.java b/tls/src/test/java/org/bouncycastle/jsse/provider/test/KeyManagerFactoryTest.java index 3da5f13b4f..956a4ecb3c 100644 --- a/tls/src/test/java/org/bouncycastle/jsse/provider/test/KeyManagerFactoryTest.java +++ b/tls/src/test/java/org/bouncycastle/jsse/provider/test/KeyManagerFactoryTest.java @@ -16,12 +16,11 @@ import javax.net.ssl.TrustManagerFactory; import javax.security.auth.x500.X500Principal; +import junit.framework.TestCase; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.jsse.BCX509ExtendedKeyManager; import org.bouncycastle.jsse.BCX509Key; -import junit.framework.TestCase; - public class KeyManagerFactoryTest extends TestCase { @@ -58,6 +57,11 @@ public void testBasicRSA() public void testRSAServer() throws Exception { + // TLS_RSA is disabled in Java 25. + if (System.getProperty("java.version").startsWith("25")) + { + return; + } KeyStore ks = getRsaKeyStore(true); KeyStore trustStore = KeyStore.getInstance("JKS"); @@ -93,6 +97,11 @@ public void testRSAServer() public void testRSAServerTrustEE() throws Exception { + // TLS_RSA is disabled in Java 25. + if (System.getProperty("java.version").startsWith("25")) + { + return; + } KeyStore ks = getRsaKeyStore(true); KeyStore trustStore = KeyStore.getInstance("JKS"); @@ -104,7 +113,7 @@ public void testRSAServerTrustEE() /* * For this variation we add the server's certificate to the client's trust store directly, * instead of the root (TA). - * + * * NOTE: For TLS 1.3 with certificate_authorities in ClientHello, or earlier versions with * trusted_ca_keys in ClientHello, this test only works when a) there are no actual CA * certificates in the client trust store, AND/OR b) the server is willing to (eventually) @@ -138,6 +147,11 @@ public void testRSAServerTrustEE() public void testRSAServerWithClientAuth() throws Exception { + // TLS_RSA is disabled in Java 25. + if (System.getProperty("java.version").startsWith("25")) + { + return; + } KeyStore clientKS = getRsaKeyStore(false); KeyStore serverKS = getRsaKeyStore(true); diff --git a/tls/src/test/java/org/bouncycastle/jsse/provider/test/MLDSACredentialsTest.java b/tls/src/test/java/org/bouncycastle/jsse/provider/test/MLDSACredentialsTest.java new file mode 100644 index 0000000000..0b8bafdc48 --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/jsse/provider/test/MLDSACredentialsTest.java @@ -0,0 +1,235 @@ +package org.bouncycastle.jsse.provider.test; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.util.concurrent.CountDownLatch; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManagerFactory; + +import junit.framework.TestCase; + +public class MLDSACredentialsTest + extends TestCase +{ + private static final String PROPERTY_CLIENT_SIGNATURE_SCHEMES = "jdk.tls.client.SignatureSchemes"; + private static final String PROPERTY_SERVER_SIGNATURE_SCHEMES = "jdk.tls.server.SignatureSchemes"; + + protected void setUp() + { + ProviderUtils.setupLowPriority(false); + + String signatureSchemes = "mldsa44, mldsa65, mldsa87"; + + System.setProperty(PROPERTY_CLIENT_SIGNATURE_SCHEMES, signatureSchemes); + System.setProperty(PROPERTY_SERVER_SIGNATURE_SCHEMES, signatureSchemes); + } + + protected void tearDown() + { + System.clearProperty(PROPERTY_CLIENT_SIGNATURE_SCHEMES); + System.clearProperty(PROPERTY_SERVER_SIGNATURE_SCHEMES); + } + + private static final String HOST = "localhost"; + private static final int PORT_NO_13_MLDSA44 = 9060; + private static final int PORT_NO_13_MLDSA65 = 9061; + private static final int PORT_NO_13_MLDSA87 = 9062; + + static class MLDSAClient + implements TestProtocolUtil.BlockingCallable + { + private final int port; + private final String protocol; + private final KeyStore trustStore; + private final KeyStore clientStore; + private final char[] clientKeyPass; + private final CountDownLatch latch; + + MLDSAClient(int port, String protocol, KeyStore clientStore, char[] clientKeyPass, + X509Certificate trustAnchor) throws GeneralSecurityException, IOException + { + KeyStore trustStore = createKeyStore(); + trustStore.setCertificateEntry("server", trustAnchor); + + this.port = port; + this.protocol = protocol; + this.trustStore = trustStore; + this.clientStore = clientStore; + this.clientKeyPass = clientKeyPass; + this.latch = new CountDownLatch(1); + } + + public Exception call() throws Exception + { + try + { + TrustManagerFactory trustMgrFact = TrustManagerFactory.getInstance("PKIX", + ProviderUtils.PROVIDER_NAME_BCJSSE); + trustMgrFact.init(trustStore); + + KeyManagerFactory keyMgrFact = KeyManagerFactory.getInstance("PKIX", + ProviderUtils.PROVIDER_NAME_BCJSSE); + keyMgrFact.init(clientStore, clientKeyPass); + + SSLContext clientContext = SSLContext.getInstance("TLS", ProviderUtils.PROVIDER_NAME_BCJSSE); + clientContext.init(keyMgrFact.getKeyManagers(), trustMgrFact.getTrustManagers(), + SecureRandom.getInstance("DEFAULT", ProviderUtils.PROVIDER_NAME_BC)); + + SSLSocketFactory fact = clientContext.getSocketFactory(); + SSLSocket cSock = (SSLSocket)fact.createSocket(HOST, port); + cSock.setEnabledProtocols(new String[]{ protocol }); + + SSLSession session = cSock.getSession(); + assertNotNull(session); + assertFalse("SSL_NULL_WITH_NULL_NULL".equals(session.getCipherSuite())); + assertEquals("CN=Test CA Certificate", session.getLocalPrincipal().getName()); + assertEquals("CN=Test CA Certificate", session.getPeerPrincipal().getName()); + + TestProtocolUtil.doClientProtocol(cSock, "Hello"); + } + finally + { + latch.countDown(); + } + + return null; + } + + public void await() + throws InterruptedException + { + latch.await(); + } + } + + static class MLDSAServer + implements TestProtocolUtil.BlockingCallable + { + private final int port; + private final String protocol; + private final KeyStore serverStore; + private final char[] keyPass; + private final KeyStore trustStore; + private final CountDownLatch latch; + + MLDSAServer(int port, String protocol, KeyStore serverStore, char[] keyPass, X509Certificate trustAnchor) + throws GeneralSecurityException, IOException + { + KeyStore trustStore = createKeyStore(); + trustStore.setCertificateEntry("client", trustAnchor); + + this.port = port; + this.protocol = protocol; + this.serverStore = serverStore; + this.keyPass = keyPass; + this.trustStore = trustStore; + this.latch = new CountDownLatch(1); + } + + public Exception call() throws Exception + { + try + { + KeyManagerFactory keyMgrFact = KeyManagerFactory.getInstance("PKIX", + ProviderUtils.PROVIDER_NAME_BCJSSE); + keyMgrFact.init(serverStore, keyPass); + + TrustManagerFactory trustMgrFact = TrustManagerFactory.getInstance("PKIX", + ProviderUtils.PROVIDER_NAME_BCJSSE); + trustMgrFact.init(trustStore); + + SSLContext serverContext = SSLContext.getInstance("TLS", ProviderUtils.PROVIDER_NAME_BCJSSE); + serverContext.init(keyMgrFact.getKeyManagers(), trustMgrFact.getTrustManagers(), + SecureRandom.getInstance("DEFAULT", ProviderUtils.PROVIDER_NAME_BC)); + + SSLServerSocketFactory fact = serverContext.getServerSocketFactory(); + SSLServerSocket sSock = (SSLServerSocket)fact.createServerSocket(port); + + SSLUtils.enableAll(sSock); + sSock.setNeedClientAuth(true); + + latch.countDown(); + + SSLSocket sslSock = (SSLSocket)sSock.accept(); + sslSock.setEnabledProtocols(new String[]{ protocol }); + + SSLSession session = sslSock.getSession(); + assertNotNull(session); + assertFalse("SSL_NULL_WITH_NULL_NULL".equals(session.getCipherSuite())); + assertEquals("CN=Test CA Certificate", session.getLocalPrincipal().getName()); + assertEquals("CN=Test CA Certificate", session.getPeerPrincipal().getName()); + + TestProtocolUtil.doServerProtocol(sslSock, "World"); + + sslSock.close(); + sSock.close(); + } + finally + { + latch.countDown(); + } + + return null; + } + + public void await() throws InterruptedException + { + latch.await(); + } + } + + public void test13_MLDSA44() throws Exception + { + implTestMLDSACredentials(PORT_NO_13_MLDSA44, "TLSv1.3", TestUtils.generateMLDSAKeyPair("ML-DSA-44")); + } + + public void test13_MLDSA65() throws Exception + { + implTestMLDSACredentials(PORT_NO_13_MLDSA65, "TLSv1.3", TestUtils.generateMLDSAKeyPair("ML-DSA-65")); + } + + public void test13_MLDSA87() throws Exception + { + implTestMLDSACredentials(PORT_NO_13_MLDSA87, "TLSv1.3", TestUtils.generateMLDSAKeyPair("ML-DSA-87")); + } + + private void implTestMLDSACredentials(int port, String protocol, KeyPair caKeyPair) throws Exception + { + char[] keyPass = "keyPassword".toCharArray(); + + X509Certificate caCert = TestUtils.generateRootCert(caKeyPair); + + KeyStore serverKs = createKeyStore(); + serverKs.setKeyEntry("server", caKeyPair.getPrivate(), keyPass, new X509Certificate[]{ caCert }); + + KeyStore clientKs = createKeyStore(); + clientKs.setKeyEntry("client", caKeyPair.getPrivate(), keyPass, new X509Certificate[]{ caCert }); + + TestProtocolUtil.runClientAndServer(new MLDSAServer(port, protocol, serverKs, keyPass, caCert), + new MLDSAClient(port, protocol, clientKs, keyPass, caCert)); + } + + private static KeyStore createKeyStore() throws GeneralSecurityException, IOException + { + /* + * NOTE: At the time of writing, default JKS implementation can't recover PKCS8 private keys + * with version != 0, which e.g. is the case when a public key is included, which the BC + * provider currently does for MLDSA. + */ +// KeyStore keyStore = KeyStore.getInstance("JKS"); + KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC"); + keyStore.load(null, null); + return keyStore; + } +} diff --git a/tls/src/test/java/org/bouncycastle/jsse/provider/test/SLHDSACredentialsTest.java b/tls/src/test/java/org/bouncycastle/jsse/provider/test/SLHDSACredentialsTest.java new file mode 100644 index 0000000000..797269c359 --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/jsse/provider/test/SLHDSACredentialsTest.java @@ -0,0 +1,316 @@ +package org.bouncycastle.jsse.provider.test; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.util.concurrent.CountDownLatch; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManagerFactory; + +import junit.framework.TestCase; + +public class SLHDSACredentialsTest + extends TestCase +{ + private static final String PROPERTY_CLIENT_SIGNATURE_SCHEMES = "jdk.tls.client.SignatureSchemes"; + private static final String PROPERTY_SERVER_SIGNATURE_SCHEMES = "jdk.tls.server.SignatureSchemes"; + + private static final String PROPERTY_MAX_HANDSHAKE_MESSAGE_SIZE = "jdk.tls.maxHandshakeMessageSize"; + + protected void setUp() + { + ProviderUtils.setupLowPriority(false); + + String signatureSchemes = + "slhdsa_sha2_128s, slhdsa_sha2_128f, " + + "slhdsa_sha2_192s, slhdsa_sha2_192f, " + + "slhdsa_sha2_256s, slhdsa_sha2_256f, " + + "slhdsa_shake_128s, slhdsa_shake_128f, " + + "slhdsa_shake_192s, slhdsa_shake_192f, " + + "slhdsa_shake_256s, slhdsa_shake_256f"; + + System.setProperty(PROPERTY_CLIENT_SIGNATURE_SCHEMES, signatureSchemes); + System.setProperty(PROPERTY_SERVER_SIGNATURE_SCHEMES, signatureSchemes); + + System.setProperty(PROPERTY_MAX_HANDSHAKE_MESSAGE_SIZE, "65536"); + } + + protected void tearDown() + { + System.clearProperty(PROPERTY_CLIENT_SIGNATURE_SCHEMES); + System.clearProperty(PROPERTY_SERVER_SIGNATURE_SCHEMES); + + System.clearProperty(PROPERTY_MAX_HANDSHAKE_MESSAGE_SIZE); + } + + private static final String HOST = "localhost"; + private static final int PORT_NO_13_SLHDSA_SHA2_128F = 9070; + private static final int PORT_NO_13_SLHDSA_SHA2_192F = 9071; + private static final int PORT_NO_13_SLHDSA_SHA2_256F = 9072; + private static final int PORT_NO_13_SLHDSA_SHAKE_128F = 9073; + private static final int PORT_NO_13_SLHDSA_SHAKE_192F = 9074; + private static final int PORT_NO_13_SLHDSA_SHAKE_256F = 9075; +// private static final int PORT_NO_13_SLHDSA_SHA2_128S = 9080; +// private static final int PORT_NO_13_SLHDSA_SHA2_192S = 9081; +// private static final int PORT_NO_13_SLHDSA_SHA2_256S = 9082; +// private static final int PORT_NO_13_SLHDSA_SHAKE_128S = 9083; +// private static final int PORT_NO_13_SLHDSA_SHAKE_192S = 9084; +// private static final int PORT_NO_13_SLHDSA_SHAKE_256S = 9085; + + static class SLHDSAClient + implements TestProtocolUtil.BlockingCallable + { + private final int port; + private final String protocol; + private final KeyStore trustStore; + private final KeyStore clientStore; + private final char[] clientKeyPass; + private final CountDownLatch latch; + + SLHDSAClient(int port, String protocol, KeyStore clientStore, char[] clientKeyPass, + X509Certificate trustAnchor) throws GeneralSecurityException, IOException + { + KeyStore trustStore = createKeyStore(); + trustStore.setCertificateEntry("server", trustAnchor); + + this.port = port; + this.protocol = protocol; + this.trustStore = trustStore; + this.clientStore = clientStore; + this.clientKeyPass = clientKeyPass; + this.latch = new CountDownLatch(1); + } + + public Exception call() throws Exception + { + try + { + TrustManagerFactory trustMgrFact = TrustManagerFactory.getInstance("PKIX", + ProviderUtils.PROVIDER_NAME_BCJSSE); + trustMgrFact.init(trustStore); + + KeyManagerFactory keyMgrFact = KeyManagerFactory.getInstance("PKIX", + ProviderUtils.PROVIDER_NAME_BCJSSE); + keyMgrFact.init(clientStore, clientKeyPass); + + SSLContext clientContext = SSLContext.getInstance("TLS", ProviderUtils.PROVIDER_NAME_BCJSSE); + clientContext.init(keyMgrFact.getKeyManagers(), trustMgrFact.getTrustManagers(), + SecureRandom.getInstance("DEFAULT", ProviderUtils.PROVIDER_NAME_BC)); + + SSLSocketFactory fact = clientContext.getSocketFactory(); + SSLSocket cSock = (SSLSocket)fact.createSocket(HOST, port); + cSock.setEnabledProtocols(new String[]{ protocol }); + + SSLSession session = cSock.getSession(); + assertNotNull(session); + assertFalse("SSL_NULL_WITH_NULL_NULL".equals(session.getCipherSuite())); + assertEquals("CN=Test CA Certificate", session.getLocalPrincipal().getName()); + assertEquals("CN=Test CA Certificate", session.getPeerPrincipal().getName()); + + TestProtocolUtil.doClientProtocol(cSock, "Hello"); + } + finally + { + latch.countDown(); + } + + return null; + } + + public void await() + throws InterruptedException + { + latch.await(); + } + } + + static class SLHDSAServer + implements TestProtocolUtil.BlockingCallable + { + private final int port; + private final String protocol; + private final KeyStore serverStore; + private final char[] keyPass; + private final KeyStore trustStore; + private final CountDownLatch latch; + + SLHDSAServer(int port, String protocol, KeyStore serverStore, char[] keyPass, X509Certificate trustAnchor) + throws GeneralSecurityException, IOException + { + KeyStore trustStore = createKeyStore(); + trustStore.setCertificateEntry("client", trustAnchor); + + this.port = port; + this.protocol = protocol; + this.serverStore = serverStore; + this.keyPass = keyPass; + this.trustStore = trustStore; + this.latch = new CountDownLatch(1); + } + + public Exception call() throws Exception + { + try + { + KeyManagerFactory keyMgrFact = KeyManagerFactory.getInstance("PKIX", + ProviderUtils.PROVIDER_NAME_BCJSSE); + keyMgrFact.init(serverStore, keyPass); + + TrustManagerFactory trustMgrFact = TrustManagerFactory.getInstance("PKIX", + ProviderUtils.PROVIDER_NAME_BCJSSE); + trustMgrFact.init(trustStore); + + SSLContext serverContext = SSLContext.getInstance("TLS", ProviderUtils.PROVIDER_NAME_BCJSSE); + serverContext.init(keyMgrFact.getKeyManagers(), trustMgrFact.getTrustManagers(), + SecureRandom.getInstance("DEFAULT", ProviderUtils.PROVIDER_NAME_BC)); + + SSLServerSocketFactory fact = serverContext.getServerSocketFactory(); + SSLServerSocket sSock = (SSLServerSocket)fact.createServerSocket(port); + + SSLUtils.enableAll(sSock); + sSock.setNeedClientAuth(true); + + latch.countDown(); + + SSLSocket sslSock = (SSLSocket)sSock.accept(); + sslSock.setEnabledProtocols(new String[]{ protocol }); + + SSLSession session = sslSock.getSession(); + assertNotNull(session); + assertFalse("SSL_NULL_WITH_NULL_NULL".equals(session.getCipherSuite())); + assertEquals("CN=Test CA Certificate", session.getLocalPrincipal().getName()); + assertEquals("CN=Test CA Certificate", session.getPeerPrincipal().getName()); + + TestProtocolUtil.doServerProtocol(sslSock, "World"); + + sslSock.close(); + sSock.close(); + } + finally + { + latch.countDown(); + } + + return null; + } + + public void await() throws InterruptedException + { + latch.await(); + } + } + + public void test13_SLHDSA_SHA2_128F() throws Exception + { + implTestSLHDSACredentials(PORT_NO_13_SLHDSA_SHA2_128F, "TLSv1.3", + TestUtils.generateSLHDSAKeyPair("SLH-DSA-SHA2-128F")); + } + + public void test13_SLHDSA_SHA2_192F() throws Exception + { + implTestSLHDSACredentials(PORT_NO_13_SLHDSA_SHA2_192F, "TLSv1.3", + TestUtils.generateSLHDSAKeyPair("SLH-DSA-SHA2-192F")); + } + + public void test13_SLHDSA_SHA2_256F() throws Exception + { + implTestSLHDSACredentials(PORT_NO_13_SLHDSA_SHA2_256F, "TLSv1.3", + TestUtils.generateSLHDSAKeyPair("SLH-DSA-SHA2-256F")); + } + + public void test13_SLHDSA_SHAKE_128F() throws Exception + { + implTestSLHDSACredentials(PORT_NO_13_SLHDSA_SHAKE_128F, "TLSv1.3", + TestUtils.generateSLHDSAKeyPair("SLH-DSA-SHAKE-128F")); + } + + public void test13_SLHDSA_SHAKE_192F() throws Exception + { + implTestSLHDSACredentials(PORT_NO_13_SLHDSA_SHAKE_192F, "TLSv1.3", + TestUtils.generateSLHDSAKeyPair("SLH-DSA-SHAKE-192F")); + } + + public void test13_SLHDSA_SHAKE_256F() throws Exception + { + implTestSLHDSACredentials(PORT_NO_13_SLHDSA_SHAKE_256F, "TLSv1.3", + TestUtils.generateSLHDSAKeyPair("SLH-DSA-SHAKE-256F")); + } + + // TODO[tls-slhdsa] Too slow to run routinely +/* + public void test13_SLHDSA_SHA2_128S() throws Exception + { + implTestSLHDSACredentials(PORT_NO_13_SLHDSA_SHA2_128S, "TLSv1.3", + TestUtils.generateSLHDSAKeyPair("SLH-DSA-SHA2-128S")); + } + + public void test13_SLHDSA_SHA2_192S() throws Exception + { + implTestSLHDSACredentials(PORT_NO_13_SLHDSA_SHA2_192S, "TLSv1.3", + TestUtils.generateSLHDSAKeyPair("SLH-DSA-SHA2-192S")); + } + + public void test13_SLHDSA_SHA2_256S() throws Exception + { + implTestSLHDSACredentials(PORT_NO_13_SLHDSA_SHA2_256S, "TLSv1.3", + TestUtils.generateSLHDSAKeyPair("SLH-DSA-SHA2-256S")); + } + + public void test13_SLHDSA_SHAKE_128S() throws Exception + { + implTestSLHDSACredentials(PORT_NO_13_SLHDSA_SHAKE_128S, "TLSv1.3", + TestUtils.generateSLHDSAKeyPair("SLH-DSA-SHAKE-128S")); + } + + public void test13_SLHDSA_SHAKE_192S() throws Exception + { + implTestSLHDSACredentials(PORT_NO_13_SLHDSA_SHAKE_192S, "TLSv1.3", + TestUtils.generateSLHDSAKeyPair("SLH-DSA-SHAKE-192S")); + } + + public void test13_SLHDSA_SHAKE_256S() throws Exception + { + implTestSLHDSACredentials(PORT_NO_13_SLHDSA_SHAKE_256S, "TLSv1.3", + TestUtils.generateSLHDSAKeyPair("SLH-DSA-SHAKE-256S")); + } +*/ + + private void implTestSLHDSACredentials(int port, String protocol, KeyPair caKeyPair) throws Exception + { + char[] keyPass = "keyPassword".toCharArray(); + + X509Certificate caCert = TestUtils.generateRootCert(caKeyPair); + + KeyStore serverKs = createKeyStore(); + serverKs.setKeyEntry("server", caKeyPair.getPrivate(), keyPass, new X509Certificate[]{ caCert }); + + KeyStore clientKs = createKeyStore(); + clientKs.setKeyEntry("client", caKeyPair.getPrivate(), keyPass, new X509Certificate[]{ caCert }); + + TestProtocolUtil.runClientAndServer(new SLHDSAServer(port, protocol, serverKs, keyPass, caCert), + new SLHDSAClient(port, protocol, clientKs, keyPass, caCert)); + } + + private static KeyStore createKeyStore() throws GeneralSecurityException, IOException + { + /* + * NOTE: At the time of writing, default JKS implementation can't recover PKCS8 private keys + * with version != 0, which e.g. is the case when a public key is included, which the BC + * provider currently does for MLDSA. + */ +// KeyStore keyStore = KeyStore.getInstance("JKS"); + KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC"); + keyStore.load(null, null); + return keyStore; + } +} diff --git a/tls/src/test/java/org/bouncycastle/jsse/provider/test/TestUtils.java b/tls/src/test/java/org/bouncycastle/jsse/provider/test/TestUtils.java index 05963eb4b6..4d2d65a312 100644 --- a/tls/src/test/java/org/bouncycastle/jsse/provider/test/TestUtils.java +++ b/tls/src/test/java/org/bouncycastle/jsse/provider/test/TestUtils.java @@ -40,6 +40,7 @@ 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.DERNull; import org.bouncycastle.asn1.DERSequence; @@ -63,6 +64,8 @@ import org.bouncycastle.asn1.x509.Time; import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator; import org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import org.bouncycastle.jcajce.spec.MLDSAParameterSpec; +import org.bouncycastle.jcajce.spec.SLHDSAParameterSpec; import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; import org.bouncycastle.jsse.BCSSLConnection; import org.bouncycastle.jsse.BCSSLEngine; @@ -70,6 +73,8 @@ import org.bouncycastle.jsse.BCSSLSocket; import org.bouncycastle.jsse.java.security.BCAlgorithmConstraints; import org.bouncycastle.jsse.java.security.BCCryptoPrimitive; +import org.bouncycastle.tls.crypto.CryptoHashAlgorithm; +import org.bouncycastle.tls.crypto.TlsCryptoUtils; /** * Test Utils @@ -80,10 +85,15 @@ class TestUtils private static AtomicLong serialNumber = new AtomicLong(System.currentTimeMillis()); private static Map algIDs = createAlgIDs(); + private static Set simpleAlgNames = createSimpleAlgNames(); private static Set tlsUniqueProtocols = createTlsUniqueProtocols(); private static Map createAlgIDs() { + ASN1ObjectIdentifier id_sha256 = NISTObjectIdentifiers.id_sha256; + AlgorithmIdentifier sha256Identifier = new AlgorithmIdentifier(id_sha256, DERNull.INSTANCE); + int sha256OutputSize = TlsCryptoUtils.getHashOutputSize(CryptoHashAlgorithm.sha256); + HashMap algIDs = new HashMap(); algIDs.put("SHA1withDSA", new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa_with_sha1)); @@ -92,21 +102,62 @@ private static Map createAlgIDs() algIDs.put("SHA1withRSA", new AlgorithmIdentifier(PKCSObjectIdentifiers.sha1WithRSAEncryption, DERNull.INSTANCE)); algIDs.put("SHA224withRSA", new AlgorithmIdentifier(PKCSObjectIdentifiers.sha224WithRSAEncryption, DERNull.INSTANCE)); algIDs.put("SHA256withRSA", new AlgorithmIdentifier(PKCSObjectIdentifiers.sha256WithRSAEncryption, DERNull.INSTANCE)); - algIDs.put("SHA256withRSAandMGF1", - new AlgorithmIdentifier(PKCSObjectIdentifiers.id_RSASSA_PSS, - new RSASSAPSSparams(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256), - new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, - new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256)), - new ASN1Integer(32), new ASN1Integer(1)))); + algIDs.put("SHA256withRSAandMGF1", new AlgorithmIdentifier( + PKCSObjectIdentifiers.id_RSASSA_PSS, + new RSASSAPSSparams( + sha256Identifier, + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, sha256Identifier), + ASN1Integer.valueOf(sha256OutputSize), + RSASSAPSSparams.DEFAULT_TRAILER_FIELD))); algIDs.put("SHA1withECDSA", new AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA1)); algIDs.put("SHA224withECDSA", new AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA224)); algIDs.put("SHA256withECDSA", new AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA256)); algIDs.put("Ed25519", new AlgorithmIdentifier(TestOIDs.id_Ed25519)); algIDs.put("Ed448", new AlgorithmIdentifier(TestOIDs.id_Ed448)); + algIDs.put("ML-DSA-44", new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_44)); + algIDs.put("ML-DSA-65", new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_65)); + algIDs.put("ML-DSA-87", new AlgorithmIdentifier(NISTObjectIdentifiers.id_ml_dsa_87)); + algIDs.put("SLH-DSA-SHA2-128S", new AlgorithmIdentifier(NISTObjectIdentifiers.id_slh_dsa_sha2_128s)); + algIDs.put("SLH-DSA-SHA2-128F", new AlgorithmIdentifier(NISTObjectIdentifiers.id_slh_dsa_sha2_128f)); + algIDs.put("SLH-DSA-SHA2-192S", new AlgorithmIdentifier(NISTObjectIdentifiers.id_slh_dsa_sha2_192s)); + algIDs.put("SLH-DSA-SHA2-192F", new AlgorithmIdentifier(NISTObjectIdentifiers.id_slh_dsa_sha2_192f)); + algIDs.put("SLH-DSA-SHA2-256S", new AlgorithmIdentifier(NISTObjectIdentifiers.id_slh_dsa_sha2_256s)); + algIDs.put("SLH-DSA-SHA2-256F", new AlgorithmIdentifier(NISTObjectIdentifiers.id_slh_dsa_sha2_256f)); + algIDs.put("SLH-DSA-SHAKE-128S", new AlgorithmIdentifier(NISTObjectIdentifiers.id_slh_dsa_shake_128s)); + algIDs.put("SLH-DSA-SHAKE-128F", new AlgorithmIdentifier(NISTObjectIdentifiers.id_slh_dsa_shake_128f)); + algIDs.put("SLH-DSA-SHAKE-192S", new AlgorithmIdentifier(NISTObjectIdentifiers.id_slh_dsa_shake_192s)); + algIDs.put("SLH-DSA-SHAKE-192F", new AlgorithmIdentifier(NISTObjectIdentifiers.id_slh_dsa_shake_192f)); + algIDs.put("SLH-DSA-SHAKE-256S", new AlgorithmIdentifier(NISTObjectIdentifiers.id_slh_dsa_shake_256s)); + algIDs.put("SLH-DSA-SHAKE-256F", new AlgorithmIdentifier(NISTObjectIdentifiers.id_slh_dsa_shake_256f)); return Collections.unmodifiableMap(algIDs); } + private static Set createSimpleAlgNames() + { + HashSet s = new HashSet(); + + s.add("Ed25519"); + s.add("Ed448"); + s.add("ML-DSA-44"); + s.add("ML-DSA-65"); + s.add("ML-DSA-87"); + s.add("SLH-DSA-SHA2-128S"); + s.add("SLH-DSA-SHA2-128F"); + s.add("SLH-DSA-SHA2-192S"); + s.add("SLH-DSA-SHA2-192F"); + s.add("SLH-DSA-SHA2-256S"); + s.add("SLH-DSA-SHA2-256F"); + s.add("SLH-DSA-SHAKE-128S"); + s.add("SLH-DSA-SHAKE-128F"); + s.add("SLH-DSA-SHAKE-192S"); + s.add("SLH-DSA-SHAKE-192F"); + s.add("SLH-DSA-SHAKE-256S"); + s.add("SLH-DSA-SHAKE-256F"); + + return Collections.unmodifiableSet(s); + } + private static Set createTlsUniqueProtocols() { /* @@ -153,7 +204,7 @@ public static X509Certificate createSelfSignedCert(X500Name dn, String sigName, long time = System.currentTimeMillis(); - certGen.setSerialNumber(new ASN1Integer(serialNumber.getAndIncrement())); + certGen.setSerialNumber(ASN1Integer.valueOf(serialNumber.getAndIncrement())); certGen.setIssuer(dn); certGen.setSubject(dn); certGen.setStartDate(new Time(new Date(time - 5000))); @@ -193,7 +244,7 @@ public static X509Certificate createCert(X500Name signerName, PrivateKey signerK long time = System.currentTimeMillis(); - certGen.setSerialNumber(new ASN1Integer(serialNumber.getAndIncrement())); + certGen.setSerialNumber(ASN1Integer.valueOf(serialNumber.getAndIncrement())); certGen.setIssuer(signerName); certGen.setSubject(dn); certGen.setStartDate(new Time(new Date(time - 5000))); @@ -231,27 +282,27 @@ public static KeyPair generateDSAKeyPair() } /** - * Create a random 1024 bit RSA key pair + * Create a random 2048 bit RSA key pair */ public static KeyPair generateRSAKeyPair() throws Exception { KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", ProviderUtils.PROVIDER_NAME_BC); - kpGen.initialize(1024, RANDOM); + kpGen.initialize(2048, RANDOM); return kpGen.generateKeyPair(); } /** - * Create a random 1024 bit RSASSA-PSS key pair + * Create a random 2048 bit RSASSA-PSS key pair */ public static KeyPair generatePSSKeyPair() throws Exception { KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSASSA-PSS", ProviderUtils.PROVIDER_NAME_BC); - kpGen.initialize(1024, RANDOM); + kpGen.initialize(2048, RANDOM); return kpGen.generateKeyPair(); } @@ -292,10 +343,46 @@ public static KeyPair generateEd448KeyPair() return kpGen.generateKeyPair(); } + public static KeyPair generateMLDSAKeyPair(String name) + throws Exception + { + return generateMLDSAKeyPair(MLDSAParameterSpec.fromName(name)); + } + + private static KeyPair generateMLDSAKeyPair(MLDSAParameterSpec spec) + throws Exception + { + // TODO How to pass only the SecureRandom to initialize if we use the full name in the getInstance? + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("ML-DSA", ProviderUtils.PROVIDER_NAME_BC); + kpGen.initialize(spec, RANDOM); + return kpGen.generateKeyPair(); + } + + public static KeyPair generateSLHDSAKeyPair(String name) + throws Exception + { + return generateSLHDSAKeyPair(SLHDSAParameterSpec.fromName(name)); + } + + private static KeyPair generateSLHDSAKeyPair(SLHDSAParameterSpec spec) + throws Exception + { + // TODO How to pass only the SecureRandom to initialize if we use the full name in the getInstance? + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("SLH-DSA", ProviderUtils.PROVIDER_NAME_BC); + kpGen.initialize(spec, RANDOM); + return kpGen.generateKeyPair(); + } + public static X509Certificate generateRootCert(KeyPair pair) throws Exception { String alg = pair.getPublic().getAlgorithm(); + + if (simpleAlgNames.contains(alg)) + { + return createSelfSignedCert("CN=Test CA Certificate", alg, pair); + } + if (alg.equals("DSA")) { return createSelfSignedCert("CN=Test CA Certificate", "SHA256withDSA", pair); @@ -312,14 +399,6 @@ else if (alg.equals("EC")) { return createSelfSignedCert("CN=Test CA Certificate", "SHA256withECDSA", pair); } - else if (alg.equals("Ed25519")) - { - return createSelfSignedCert("CN=Test CA Certificate", "Ed25519", pair); - } - else if (alg.equals("Ed448")) - { - return createSelfSignedCert("CN=Test CA Certificate", "Ed448", pair); - } else { throw new IllegalArgumentException(); diff --git a/tls/src/test/java/org/bouncycastle/test/TestResourceFinder.java b/tls/src/test/java/org/bouncycastle/test/TestResourceFinder.java new file mode 100644 index 0000000000..14214bafae --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/test/TestResourceFinder.java @@ -0,0 +1,39 @@ +package org.bouncycastle.test; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; + +public class TestResourceFinder +{ + private static final String dataDirName = "bc-test-data"; + + /** + * We search starting at the working directory looking for the bc-test-data directory. + * + * @throws FileNotFoundException + */ + public static InputStream findTestResource(String homeDir, String fileName) + throws FileNotFoundException + { + String wrkDirName = System.getProperty("user.dir"); + String separator = System.getProperty("file.separator"); + File wrkDir = new File(wrkDirName); + File dataDir = new File(wrkDir, dataDirName); + while (!dataDir.exists() && wrkDirName.length() > 1) + { + wrkDirName = wrkDirName.substring(0, wrkDirName.lastIndexOf(separator)); + wrkDir = new File(wrkDirName); + dataDir = new File(wrkDir, dataDirName); + } + + if (!dataDir.exists()) + { + String ln = System.getProperty("line.separator"); + throw new FileNotFoundException("Test data directory " + dataDirName + " not found." + ln + "Test data available from: https://github.com/bcgit/bc-test-data.git"); + } + + return new FileInputStream(new File(dataDir, homeDir + separator + fileName)); + } +} diff --git a/tls/src/test/java/org/bouncycastle/tls/crypto/test/BcTlsCryptoTest.java b/tls/src/test/java/org/bouncycastle/tls/crypto/test/BcTlsCryptoTest.java index 96f70b3903..5f9917cf77 100644 --- a/tls/src/test/java/org/bouncycastle/tls/crypto/test/BcTlsCryptoTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/crypto/test/BcTlsCryptoTest.java @@ -1,7 +1,5 @@ package org.bouncycastle.tls.crypto.test; -import java.security.SecureRandom; - import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; public class BcTlsCryptoTest diff --git a/tls/src/test/java/org/bouncycastle/tls/crypto/test/TlsCryptoTest.java b/tls/src/test/java/org/bouncycastle/tls/crypto/test/TlsCryptoTest.java index ed2689c571..325e6b5655 100644 --- a/tls/src/test/java/org/bouncycastle/tls/crypto/test/TlsCryptoTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/crypto/test/TlsCryptoTest.java @@ -187,6 +187,12 @@ protected TlsCredentialedSigner loadCredentialedSigner13(TlsCryptoParameters cry case SignatureScheme.rsa_pss_rsae_sha384: case SignatureScheme.rsa_pss_rsae_sha512: return loadCredentialedSigner(cryptoParams, "rsa-sign", signatureAndHashAlgorithm); + case SignatureScheme.mldsa44: + return loadCredentialedSigner(cryptoParams, "ml_dsa_44", signatureAndHashAlgorithm); + case SignatureScheme.mldsa65: + return loadCredentialedSigner(cryptoParams, "ml_dsa_65", signatureAndHashAlgorithm); + case SignatureScheme.mldsa87: + return loadCredentialedSigner(cryptoParams, "ml_dsa_87", signatureAndHashAlgorithm); // TODO[tls] Add test resources for these case SignatureScheme.ecdsa_brainpoolP256r1tls13_sha256: @@ -195,6 +201,21 @@ protected TlsCredentialedSigner loadCredentialedSigner13(TlsCryptoParameters cry case SignatureScheme.ecdsa_secp384r1_sha384: case SignatureScheme.ecdsa_secp521r1_sha512: case SignatureScheme.sm2sig_sm3: + return null; + + // TODO[tls-slhdsa] Add test resources for these + case SignatureScheme.DRAFT_slhdsa_sha2_128s: + case SignatureScheme.DRAFT_slhdsa_sha2_128f: + case SignatureScheme.DRAFT_slhdsa_sha2_192s: + case SignatureScheme.DRAFT_slhdsa_sha2_192f: + case SignatureScheme.DRAFT_slhdsa_sha2_256s: + case SignatureScheme.DRAFT_slhdsa_sha2_256f: + case SignatureScheme.DRAFT_slhdsa_shake_128s: + case SignatureScheme.DRAFT_slhdsa_shake_128f: + case SignatureScheme.DRAFT_slhdsa_shake_192s: + case SignatureScheme.DRAFT_slhdsa_shake_192f: + case SignatureScheme.DRAFT_slhdsa_shake_256s: + case SignatureScheme.DRAFT_slhdsa_shake_256f: default: return null; @@ -218,6 +239,14 @@ public void testDHDomain() throws Exception implTestDHDomain(new TlsDHConfig(namedGroup, false)); implTestDHDomain(new TlsDHConfig(namedGroup, true)); } + } + + public void testDHExplicit() throws Exception + { + if (!crypto.hasDHAgreement()) + { + return; + } new DefaultTlsDHGroupVerifier() {{ @@ -233,9 +262,10 @@ public void testDHDomain() throws Exception assertSame(dhGroup, TlsDHUtils.getStandardGroupForDHParameters(p, g)); int namedGroup = TlsDHUtils.getNamedGroupForDHParameters(p, g); + + // Named groups tested elsewhere if (NamedGroup.refersToASpecificFiniteField(namedGroup)) { - // Already tested the named groups continue; } @@ -594,6 +624,13 @@ public void testSignatures13() throws Exception SignatureScheme.rsa_pss_pss_sha256, SignatureScheme.rsa_pss_pss_sha384, SignatureScheme.rsa_pss_pss_sha512, SignatureScheme.rsa_pss_rsae_sha256, SignatureScheme.rsa_pss_rsae_sha384, SignatureScheme.rsa_pss_rsae_sha512, SignatureScheme.sm2sig_sm3, + SignatureScheme.mldsa44, SignatureScheme.mldsa65, SignatureScheme.mldsa87, + SignatureScheme.DRAFT_slhdsa_sha2_128s, SignatureScheme.DRAFT_slhdsa_sha2_128f, + SignatureScheme.DRAFT_slhdsa_sha2_192s, SignatureScheme.DRAFT_slhdsa_sha2_192f, + SignatureScheme.DRAFT_slhdsa_sha2_256s, SignatureScheme.DRAFT_slhdsa_sha2_256f, + SignatureScheme.DRAFT_slhdsa_shake_128s, SignatureScheme.DRAFT_slhdsa_shake_128f, + SignatureScheme.DRAFT_slhdsa_shake_192s, SignatureScheme.DRAFT_slhdsa_shake_192f, + SignatureScheme.DRAFT_slhdsa_shake_256s, SignatureScheme.DRAFT_slhdsa_shake_256f, // These are only used for certs in 1.3 (cert verification is not done by TlsCrypto) // SignatureScheme.ecdsa_sha1, SignatureScheme.rsa_pkcs1_sha1, SignatureScheme.rsa_pkcs1_sha256, // SignatureScheme.rsa_pkcs1_sha384, SignatureScheme.rsa_pkcs1_sha512, diff --git a/tls/src/test/java/org/bouncycastle/tls/test/AllTests.java b/tls/src/test/java/org/bouncycastle/tls/test/AllTests.java index 64b985fe45..224d241e9b 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/AllTests.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/AllTests.java @@ -22,12 +22,16 @@ public static Test suite() TestSuite suite = new TestSuite("TLS tests"); suite.addTestSuite(BasicTlsTest.class); + suite.addTestSuite(BcTlsProtocolHybridTest.class); + suite.addTestSuite(BcTlsProtocolKemTest.class); suite.addTestSuite(ByteQueueInputStreamTest.class); suite.addTestSuite(DTLSAggregatedHandshakeRetransmissionTest.class); suite.addTestSuite(DTLSHandshakeRetransmissionTest.class); suite.addTestSuite(DTLSProtocolTest.class); suite.addTestSuite(DTLSPSKProtocolTest.class); suite.addTestSuite(DTLSRawKeysProtocolTest.class); + suite.addTestSuite(JcaTlsProtocolHybridTest.class); + suite.addTestSuite(JcaTlsProtocolKemTest.class); suite.addTestSuite(OCSPTest.class); suite.addTestSuite(PRFTest.class); suite.addTestSuite(Tls13PSKProtocolTest.class); diff --git a/tls/src/test/java/org/bouncycastle/tls/test/BcTlsProtocolHybridTest.java b/tls/src/test/java/org/bouncycastle/tls/test/BcTlsProtocolHybridTest.java new file mode 100644 index 0000000000..8499f7ad5e --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/tls/test/BcTlsProtocolHybridTest.java @@ -0,0 +1,12 @@ +package org.bouncycastle.tls.test; + +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; + +public class BcTlsProtocolHybridTest + extends TlsProtocolHybridTest +{ + public BcTlsProtocolHybridTest() + { + super(new BcTlsCrypto()); + } +} diff --git a/tls/src/test/java/org/bouncycastle/tls/test/BcTlsProtocolKemTest.java b/tls/src/test/java/org/bouncycastle/tls/test/BcTlsProtocolKemTest.java new file mode 100644 index 0000000000..e99d8d01e3 --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/tls/test/BcTlsProtocolKemTest.java @@ -0,0 +1,12 @@ +package org.bouncycastle.tls.test; + +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; + +public class BcTlsProtocolKemTest + extends TlsProtocolKemTest +{ + public BcTlsProtocolKemTest() + { + super(new BcTlsCrypto()); + } +} diff --git a/tls/src/test/java/org/bouncycastle/tls/test/DTLSAggregatedHandshakeRetransmissionTest.java b/tls/src/test/java/org/bouncycastle/tls/test/DTLSAggregatedHandshakeRetransmissionTest.java index 1181654938..ae762e755b 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/DTLSAggregatedHandshakeRetransmissionTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/DTLSAggregatedHandshakeRetransmissionTest.java @@ -6,8 +6,8 @@ import org.bouncycastle.tls.DTLSTransport; import org.bouncycastle.tls.DTLSVerifier; import org.bouncycastle.tls.DatagramTransport; +import org.bouncycastle.tls.TlsServer; import org.bouncycastle.tls.crypto.TlsCrypto; -import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; @@ -18,12 +18,15 @@ public class DTLSAggregatedHandshakeRetransmissionTest { public void testClientServer() throws Exception { + MockDTLSClient client = new MockDTLSClient(null); + MockDTLSServer server = new MockDTLSServer(); + DTLSClientProtocol clientProtocol = new DTLSClientProtocol(); DTLSServerProtocol serverProtocol = new DTLSServerProtocol(); MockDatagramAssociation network = new MockDatagramAssociation(1500); - ServerThread serverThread = new ServerThread(serverProtocol, network.getServer()); + ServerThread serverThread = new ServerThread(serverProtocol, server, network.getServer()); serverThread.start(); DatagramTransport clientTransport = network.getClient(); @@ -34,8 +37,6 @@ public void testClientServer() throws Exception clientTransport = new MinimalHandshakeAggregator(clientTransport, false, true); - MockDTLSClient client = new MockDTLSClient(null); - client.setHandshakeTimeoutMillis(30000); // Test gets stuck, so we need it to time out. DTLSTransport dtlsClient = clientProtocol.connect(client, clientTransport); @@ -61,12 +62,14 @@ static class ServerThread extends Thread { private final DTLSServerProtocol serverProtocol; + private final TlsServer server; private final DatagramTransport serverTransport; private volatile boolean isShutdown = false; - ServerThread(DTLSServerProtocol serverProtocol, DatagramTransport serverTransport) + ServerThread(DTLSServerProtocol serverProtocol, TlsServer server, DatagramTransport serverTransport) { this.serverProtocol = serverProtocol; + this.server = server; this.serverTransport = serverTransport; } @@ -74,7 +77,7 @@ public void run() { try { - TlsCrypto serverCrypto = new BcTlsCrypto(); + TlsCrypto serverCrypto = server.getCrypto(); DTLSRequest request = null; @@ -105,7 +108,6 @@ public void run() // NOTE: A real server would handle each DTLSRequest in a new task/thread and continue accepting { - MockDTLSServer server = new MockDTLSServer(serverCrypto); DTLSTransport dtlsTransport = serverProtocol.accept(server, serverTransport, request); byte[] buf = new byte[dtlsTransport.getReceiveLimit()]; while (!isShutdown) diff --git a/tls/src/test/java/org/bouncycastle/tls/test/DTLSHandshakeRetransmissionTest.java b/tls/src/test/java/org/bouncycastle/tls/test/DTLSHandshakeRetransmissionTest.java index 7d6de6df6c..8b9de0213c 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/DTLSHandshakeRetransmissionTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/DTLSHandshakeRetransmissionTest.java @@ -6,8 +6,8 @@ import org.bouncycastle.tls.DTLSTransport; import org.bouncycastle.tls.DTLSVerifier; import org.bouncycastle.tls.DatagramTransport; +import org.bouncycastle.tls.TlsServer; import org.bouncycastle.tls.crypto.TlsCrypto; -import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; @@ -18,12 +18,15 @@ public class DTLSHandshakeRetransmissionTest { public void testClientServer() throws Exception { + MockDTLSClient client = new MockDTLSClient(null); + MockDTLSServer server = new MockDTLSServer(); + DTLSClientProtocol clientProtocol = new DTLSClientProtocol(); DTLSServerProtocol serverProtocol = new DTLSServerProtocol(); MockDatagramAssociation network = new MockDatagramAssociation(1500); - ServerThread serverThread = new ServerThread(serverProtocol, network.getServer()); + ServerThread serverThread = new ServerThread(serverProtocol, server, network.getServer()); serverThread.start(); DatagramTransport clientTransport = network.getClient(); @@ -32,8 +35,6 @@ public void testClientServer() throws Exception clientTransport = new LoggingDatagramTransport(clientTransport, System.out); - MockDTLSClient client = new MockDTLSClient(null); - DTLSTransport dtlsClient = clientProtocol.connect(client, clientTransport); for (int i = 1; i <= 10; ++i) @@ -57,12 +58,14 @@ static class ServerThread extends Thread { private final DTLSServerProtocol serverProtocol; + private final TlsServer server; private final DatagramTransport serverTransport; private volatile boolean isShutdown = false; - ServerThread(DTLSServerProtocol serverProtocol, DatagramTransport serverTransport) + ServerThread(DTLSServerProtocol serverProtocol, TlsServer server, DatagramTransport serverTransport) { this.serverProtocol = serverProtocol; + this.server = server; this.serverTransport = serverTransport; } @@ -70,7 +73,7 @@ public void run() { try { - TlsCrypto serverCrypto = new BcTlsCrypto(); + TlsCrypto serverCrypto = server.getCrypto(); DTLSRequest request = null; @@ -101,7 +104,6 @@ public void run() // NOTE: A real server would handle each DTLSRequest in a new task/thread and continue accepting { - MockDTLSServer server = new MockDTLSServer(serverCrypto); DTLSTransport dtlsTransport = serverProtocol.accept(server, serverTransport, request); byte[] buf = new byte[dtlsTransport.getReceiveLimit()]; while (!isShutdown) diff --git a/tls/src/test/java/org/bouncycastle/tls/test/DTLSPSKProtocolTest.java b/tls/src/test/java/org/bouncycastle/tls/test/DTLSPSKProtocolTest.java index 1ee37bbe1f..a8f27d9764 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/DTLSPSKProtocolTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/DTLSPSKProtocolTest.java @@ -1,11 +1,11 @@ package org.bouncycastle.tls.test; -import java.security.SecureRandom; - import org.bouncycastle.tls.DTLSClientProtocol; import org.bouncycastle.tls.DTLSServerProtocol; import org.bouncycastle.tls.DTLSTransport; import org.bouncycastle.tls.DatagramTransport; +import org.bouncycastle.tls.TlsServer; +import org.bouncycastle.tls.TlsTimeoutException; import org.bouncycastle.util.Arrays; import junit.framework.TestCase; @@ -13,26 +13,41 @@ public class DTLSPSKProtocolTest extends TestCase { + public void testBadClientKeyTimeout() throws Exception + { + MockPSKDTLSClient client = new MockPSKDTLSClient(null, true); + MockPSKDTLSServer server = new MockPSKDTLSServer(); + + implTestKeyMismatch(client, server); + } + + public void testBadServerKeyTimeout() throws Exception + { + MockPSKDTLSClient client = new MockPSKDTLSClient(null); + MockPSKDTLSServer server = new MockPSKDTLSServer(true); + + implTestKeyMismatch(client, server); + } + public void testClientServer() throws Exception { - SecureRandom secureRandom = new SecureRandom(); + MockPSKDTLSClient client = new MockPSKDTLSClient(null); + MockPSKDTLSServer server = new MockPSKDTLSServer(); DTLSClientProtocol clientProtocol = new DTLSClientProtocol(); DTLSServerProtocol serverProtocol = new DTLSServerProtocol(); MockDatagramAssociation network = new MockDatagramAssociation(1500); - ServerThread serverThread = new ServerThread(serverProtocol, network.getServer()); + ServerThread serverThread = new ServerThread(serverProtocol, server, network.getServer()); serverThread.start(); DatagramTransport clientTransport = network.getClient(); - clientTransport = new UnreliableDatagramTransport(clientTransport, secureRandom, 0, 0); + clientTransport = new UnreliableDatagramTransport(clientTransport, client.getCrypto().getSecureRandom(), 0, 0); clientTransport = new LoggingDatagramTransport(clientTransport, System.out); - MockPSKDTLSClient client = new MockPSKDTLSClient(null); - DTLSTransport dtlsClient = clientProtocol.connect(client, clientTransport); for (int i = 1; i <= 10; ++i) @@ -52,16 +67,59 @@ public void testClientServer() throws Exception serverThread.shutdown(); } + private void implTestKeyMismatch(MockPSKDTLSClient client, MockPSKDTLSServer server) throws Exception + { + DTLSClientProtocol clientProtocol = new DTLSClientProtocol(); + DTLSServerProtocol serverProtocol = new DTLSServerProtocol(); + + MockDatagramAssociation network = new MockDatagramAssociation(1500); + + ServerThread serverThread = new ServerThread(serverProtocol, server, network.getServer()); + serverThread.start(); + + DatagramTransport clientTransport = network.getClient(); + + // Don't use unreliable transport because we are focused on timeout due to bad PSK +// clientTransport = new UnreliableDatagramTransport(clientTransport, client.getCrypto().getSecureRandom(), 0, 0); + + clientTransport = new LoggingDatagramTransport(clientTransport, System.out); + + boolean correctException = false; + + try + { + DTLSTransport dtlsClient = clientProtocol.connect(client, clientTransport); + dtlsClient.close(); + } + catch (TlsTimeoutException e) + { + correctException = true; + } + catch (Exception e) + { + } + finally + { + clientTransport.close(); + } + + serverThread.shutdown(); + + assertTrue(correctException); + } + static class ServerThread extends Thread { private final DTLSServerProtocol serverProtocol; + private final TlsServer server; private final DatagramTransport serverTransport; private volatile boolean isShutdown = false; - ServerThread(DTLSServerProtocol serverProtocol, DatagramTransport serverTransport) + ServerThread(DTLSServerProtocol serverProtocol, TlsServer server, DatagramTransport serverTransport) { this.serverProtocol = serverProtocol; + this.server = server; this.serverTransport = serverTransport; } @@ -69,7 +127,6 @@ public void run() { try { - MockPSKDTLSServer server = new MockPSKDTLSServer(); DTLSTransport dtlsServer = serverProtocol.accept(server, serverTransport); byte[] buf = new byte[dtlsServer.getReceiveLimit()]; while (!isShutdown) diff --git a/tls/src/test/java/org/bouncycastle/tls/test/DTLSProtocolTest.java b/tls/src/test/java/org/bouncycastle/tls/test/DTLSProtocolTest.java index 3bb3a51254..faa58ecd5b 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/DTLSProtocolTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/DTLSProtocolTest.java @@ -1,6 +1,6 @@ package org.bouncycastle.tls.test; -import java.security.SecureRandom; +import java.util.Random; import org.bouncycastle.tls.DTLSClientProtocol; import org.bouncycastle.tls.DTLSRequest; @@ -8,8 +8,8 @@ import org.bouncycastle.tls.DTLSTransport; import org.bouncycastle.tls.DTLSVerifier; import org.bouncycastle.tls.DatagramTransport; +import org.bouncycastle.tls.TlsServer; import org.bouncycastle.tls.crypto.TlsCrypto; -import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Strings; @@ -20,24 +20,23 @@ public class DTLSProtocolTest { public void testClientServer() throws Exception { - SecureRandom secureRandom = new SecureRandom(); + MockDTLSClient client = new MockDTLSClient(null); + MockDTLSServer server = new MockDTLSServer(); DTLSClientProtocol clientProtocol = new DTLSClientProtocol(); DTLSServerProtocol serverProtocol = new DTLSServerProtocol(); MockDatagramAssociation network = new MockDatagramAssociation(1500); - ServerThread serverThread = new ServerThread(serverProtocol, network.getServer()); + ServerThread serverThread = new ServerThread(serverProtocol, server, network.getServer()); serverThread.start(); DatagramTransport clientTransport = network.getClient(); - clientTransport = new UnreliableDatagramTransport(clientTransport, secureRandom, 0, 0); + clientTransport = new UnreliableDatagramTransport(clientTransport, new Random(), 0, 0); clientTransport = new LoggingDatagramTransport(clientTransport, System.out); - MockDTLSClient client = new MockDTLSClient(null); - DTLSTransport dtlsClient = clientProtocol.connect(client, clientTransport); for (int i = 1; i <= 10; ++i) @@ -61,12 +60,14 @@ static class ServerThread extends Thread { private final DTLSServerProtocol serverProtocol; + private final TlsServer server; private final DatagramTransport serverTransport; private volatile boolean isShutdown = false; - ServerThread(DTLSServerProtocol serverProtocol, DatagramTransport serverTransport) + ServerThread(DTLSServerProtocol serverProtocol, TlsServer server, DatagramTransport serverTransport) { this.serverProtocol = serverProtocol; + this.server = server; this.serverTransport = serverTransport; } @@ -74,7 +75,7 @@ public void run() { try { - TlsCrypto serverCrypto = new BcTlsCrypto(); + TlsCrypto serverCrypto = server.getCrypto(); DTLSRequest request = null; @@ -105,7 +106,6 @@ public void run() // NOTE: A real server would handle each DTLSRequest in a new task/thread and continue accepting { - MockDTLSServer server = new MockDTLSServer(serverCrypto); DTLSTransport dtlsTransport = serverProtocol.accept(server, serverTransport, request); byte[] buf = new byte[dtlsTransport.getReceiveLimit()]; while (!isShutdown) diff --git a/tls/src/test/java/org/bouncycastle/tls/test/DTLSRawKeysProtocolTest.java b/tls/src/test/java/org/bouncycastle/tls/test/DTLSRawKeysProtocolTest.java index 98565948ba..77ddea132c 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/DTLSRawKeysProtocolTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/DTLSRawKeysProtocolTest.java @@ -3,6 +3,7 @@ import java.security.SecureRandom; import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; +import org.bouncycastle.tls.AlertDescription; import org.bouncycastle.tls.CertificateType; import org.bouncycastle.tls.DTLSClientProtocol; import org.bouncycastle.tls.DTLSRequest; @@ -13,6 +14,7 @@ import org.bouncycastle.tls.ProtocolVersion; import org.bouncycastle.tls.TlsClient; import org.bouncycastle.tls.TlsExtensionsUtils; +import org.bouncycastle.tls.TlsFatalAlertReceived; import org.bouncycastle.tls.TlsServer; import org.bouncycastle.tls.crypto.TlsCrypto; import org.bouncycastle.util.Arrays; @@ -206,8 +208,6 @@ private void testServerUsesX509AndClientUsesRawKey(ProtocolVersion tlsVersion) t pumpData(client, server); } - // NOTE: Test disabled because of problems getting a clean exit of the DTLS server after a fatal alert. -/* public void testClientSendsClientCertExtensionButServerHasNoCommonTypes() throws Exception { testClientSendsClientCertExtensionButServerHasNoCommonTypes(ProtocolVersion.DTLSv12); @@ -244,10 +244,7 @@ private void testClientSendsClientCertExtensionButServerHasNoCommonTypes(Protoco assertEquals("Should have caused unsupported_certificate alert", alert.getAlertDescription(), AlertDescription.unsupported_certificate); } } -*/ - // NOTE: Test disabled because of problems getting a clean exit of the DTLS server after a fatal alert. -/* public void testClientSendsServerCertExtensionButServerHasNoCommonTypes() throws Exception { testClientSendsServerCertExtensionButServerHasNoCommonTypes(ProtocolVersion.DTLSv12); @@ -284,7 +281,6 @@ private void testClientSendsServerCertExtensionButServerHasNoCommonTypes(Protoco assertEquals("Should have caused unsupported_certificate alert", alert.getAlertDescription(), AlertDescription.unsupported_certificate); } } -*/ private Ed25519PrivateKeyParameters generateKeyPair() { @@ -348,23 +344,23 @@ public void run() TlsCrypto serverCrypto = server.getCrypto(); DTLSRequest request = null; - + // Use DTLSVerifier to require a HelloVerifyRequest cookie exchange before accepting { DTLSVerifier verifier = new DTLSVerifier(serverCrypto); - + // NOTE: Test value only - would typically be the client IP address byte[] clientID = Strings.toUTF8ByteArray("MockRawKeysTlsClient"); - + int receiveLimit = serverTransport.getReceiveLimit(); int dummyOffset = serverCrypto.getSecureRandom().nextInt(16) + 1; byte[] buf = new byte[dummyOffset + serverTransport.getReceiveLimit()]; - + do { if (isShutdown) return; - + int length = serverTransport.receive(buf, dummyOffset, receiveLimit, 100); if (length > 0) { diff --git a/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestSuite.java b/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestSuite.java index d493c959a9..759b83dcb5 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestSuite.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/DTLSTestSuite.java @@ -43,20 +43,14 @@ private static void addFallbackTests(TestSuite testSuite) addTestCase(testSuite, c, "FallbackGood"); } - /* - * NOTE: Temporarily disabled automatic test runs because of problems getting a clean exit - * of the DTLS server after a fatal alert. As of writing, manual runs show the correct - * alerts being raised - */ + { + TlsTestConfig c = createDTLSTestConfig(ProtocolVersion.DTLSv12); + c.clientFallback = true; + c.clientSupportedVersions = ProtocolVersion.DTLSv10.only(); + c.expectServerFatalAlert(AlertDescription.inappropriate_fallback); -// { -// TlsTestConfig c = createDTLSTestConfig(ProtocolVersion.DTLSv12); -// c.clientFallback = true; -// c.clientSupportedVersions = ProtocolVersion.DTLSv10.only(); -// c.expectServerFatalAlert(AlertDescription.inappropriate_fallback); -// -// addTestCase(testSuite, c, "FallbackBad"); -// } + addTestCase(testSuite, c, "FallbackBad"); + } { TlsTestConfig c = createDTLSTestConfig(ProtocolVersion.DTLSv12); diff --git a/tls/src/test/java/org/bouncycastle/tls/test/JcaTlsProtocolHybridTest.java b/tls/src/test/java/org/bouncycastle/tls/test/JcaTlsProtocolHybridTest.java new file mode 100644 index 0000000000..85c35d87be --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/tls/test/JcaTlsProtocolHybridTest.java @@ -0,0 +1,15 @@ +package org.bouncycastle.tls.test; + +import java.security.SecureRandom; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider; + +public class JcaTlsProtocolHybridTest + extends TlsProtocolHybridTest +{ + public JcaTlsProtocolHybridTest() + { + super(new JcaTlsCryptoProvider().setProvider(new BouncyCastleProvider()).create(new SecureRandom())); + } +} diff --git a/tls/src/test/java/org/bouncycastle/tls/test/JcaTlsProtocolKemTest.java b/tls/src/test/java/org/bouncycastle/tls/test/JcaTlsProtocolKemTest.java new file mode 100644 index 0000000000..ae23d5a57f --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/tls/test/JcaTlsProtocolKemTest.java @@ -0,0 +1,15 @@ +package org.bouncycastle.tls.test; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.tls.crypto.impl.jcajce.JcaTlsCryptoProvider; + +import java.security.SecureRandom; + +public class JcaTlsProtocolKemTest + extends TlsProtocolKemTest +{ + public JcaTlsProtocolKemTest() + { + super(new JcaTlsCryptoProvider().setProvider(new BouncyCastleProvider()).create(new SecureRandom())); + } +} diff --git a/tls/src/test/java/org/bouncycastle/tls/test/LoggingDatagramTransport.java b/tls/src/test/java/org/bouncycastle/tls/test/LoggingDatagramTransport.java index 1f2449009d..72b6d0a7e4 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/LoggingDatagramTransport.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/LoggingDatagramTransport.java @@ -9,6 +9,7 @@ public class LoggingDatagramTransport implements DatagramTransport { + private static final boolean ENABLE_DUMPS = false; private static final String HEX_CHARS = "0123456789ABCDEF"; @@ -62,6 +63,11 @@ public void close() private void dumpDatagram(String verb, byte[] buf, int off, int len) throws IOException { + if (!ENABLE_DUMPS) + { + return; + } + long timestamp = System.currentTimeMillis() - launchTimestamp; StringBuffer sb = new StringBuffer("(+" + timestamp + "ms) " + verb + " " + len + " byte datagram:"); for (int pos = 0; pos < len; ++pos) diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSClient.java b/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSClient.java index 16c178e12a..0f0e8713cd 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSClient.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSClient.java @@ -80,7 +80,7 @@ public void notifyServerVersion(ProtocolVersion serverVersion) throws IOExceptio { super.notifyServerVersion(serverVersion); - System.out.println("DTLS client negotiated " + serverVersion); + System.out.println("DTLS client negotiated version " + serverVersion); } public TlsAuthentication getAuthentication() throws IOException @@ -110,6 +110,7 @@ public void notifyServerCertificate(TlsServerCertificate serverCertificate) thro String[] trustedCertResources = new String[]{ "x509-server-dsa.pem", "x509-server-ecdh.pem", "x509-server-ecdsa.pem", "x509-server-ed25519.pem", "x509-server-ed448.pem", + "x509-server-ml_dsa_44.pem", "x509-server-ml_dsa_65.pem", "x509-server-ml_dsa_87.pem", "x509-server-rsa_pss_256.pem", "x509-server-rsa_pss_384.pem", "x509-server-rsa_pss_512.pem", "x509-server-rsa-enc.pem", "x509-server-rsa-sign.pem" }; diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSServer.java b/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSServer.java index b4995fcd5e..938e24c3ce 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSServer.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockDTLSServer.java @@ -64,7 +64,7 @@ public ProtocolVersion getServerVersion() throws IOException { ProtocolVersion serverVersion = super.getServerVersion(); - System.out.println("DTLS server negotiated " + serverVersion); + System.out.println("DTLS server negotiated version " + serverVersion); return serverVersion; } @@ -112,7 +112,8 @@ public void notifyClientCertificate(org.bouncycastle.tls.Certificate clientCerti } String[] trustedCertResources = new String[]{ "x509-client-dsa.pem", "x509-client-ecdh.pem", - "x509-client-ecdsa.pem", "x509-client-ed25519.pem", "x509-client-ed448.pem", "x509-client-rsa_pss_256.pem", + "x509-client-ecdsa.pem", "x509-client-ed25519.pem", "x509-client-ed448.pem", "x509-client-ml_dsa_44.pem", + "x509-client-ml_dsa_65.pem", "x509-client-ml_dsa_87.pem", "x509-client-rsa_pss_256.pem", "x509-client-rsa_pss_384.pem", "x509-client-rsa_pss_512.pem", "x509-client-rsa.pem" }; TlsCertificate[] certPath = TlsTestUtils.getTrustedCertPath(context.getCrypto(), chain[0], diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockDatagramAssociation.java b/tls/src/test/java/org/bouncycastle/tls/test/MockDatagramAssociation.java index 662fc2ea23..782d52a601 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockDatagramAssociation.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockDatagramAssociation.java @@ -22,6 +22,11 @@ public MockDatagramAssociation(int mtu) this.server = new MockDatagramTransport(serverQueue, clientQueue); } + public int getMTU() + { + return mtu; + } + public DatagramTransport getClient() { return client; @@ -35,7 +40,7 @@ public DatagramTransport getServer() private class MockDatagramTransport implements DatagramTransport { - private Vector receiveQueue, sendQueue; + private final Vector receiveQueue, sendQueue; MockDatagramTransport(Vector receiveQueue, Vector sendQueue) { @@ -46,13 +51,13 @@ private class MockDatagramTransport public int getReceiveLimit() throws IOException { - return mtu; + return getMTU(); } public int getSendLimit() throws IOException { - return mtu; + return getMTU(); } public int receive(byte[] buf, int off, int len, int waitMillis) @@ -85,7 +90,7 @@ public int receive(byte[] buf, int off, int len, int waitMillis) public void send(byte[] buf, int off, int len) throws IOException { - if (len > mtu) + if (len > getMTU()) { // TODO Simulate rejection? } diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockPSKDTLSClient.java b/tls/src/test/java/org/bouncycastle/tls/test/MockPSKDTLSClient.java index c4efb99fa4..258bd3f3f2 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockPSKDTLSClient.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockPSKDTLSClient.java @@ -32,7 +32,12 @@ class MockPSKDTLSClient MockPSKDTLSClient(TlsSession session) { - this(session, new BasicTlsPSKIdentity("client", Strings.toUTF8ByteArray("TLS_TEST_PSK"))); + this(session, false); + } + + MockPSKDTLSClient(TlsSession session, boolean badKey) + { + this(session, TlsTestUtils.createDefaultPSKIdentity(badKey)); } MockPSKDTLSClient(TlsSession session, TlsPSKIdentity pskIdentity) @@ -42,6 +47,16 @@ class MockPSKDTLSClient this.session = session; } + public int getHandshakeTimeoutMillis() + { + return 1000; + } + + public int getHandshakeResendTimeMillis() + { + return 100; // Fast resend only for tests! + } + public TlsSession getSessionToResume() { return this.session; @@ -73,7 +88,7 @@ public void notifyServerVersion(ProtocolVersion serverVersion) throws IOExceptio { super.notifyServerVersion(serverVersion); - System.out.println("DTLS-PSK client negotiated " + serverVersion); + System.out.println("DTLS-PSK client negotiated version " + serverVersion); } public TlsAuthentication getAuthentication() throws IOException diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockPSKDTLSServer.java b/tls/src/test/java/org/bouncycastle/tls/test/MockPSKDTLSServer.java index 453887e30e..8cc88acb5b 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockPSKDTLSServer.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockPSKDTLSServer.java @@ -22,7 +22,22 @@ class MockPSKDTLSServer { MockPSKDTLSServer() { - super(new BcTlsCrypto(), new MyIdentityManager()); + this(false); + } + + MockPSKDTLSServer(boolean badKey) + { + super(new BcTlsCrypto(), new MyIdentityManager(badKey)); + } + + public int getHandshakeTimeoutMillis() + { + return 1000; + } + + public int getHandshakeResendTimeMillis() + { + return 100; // Fast resend only for tests! } public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) @@ -51,7 +66,7 @@ public ProtocolVersion getServerVersion() throws IOException { ProtocolVersion serverVersion = super.getServerVersion(); - System.out.println("DTLS-PSK server negotiated " + serverVersion); + System.out.println("DTLS-PSK server negotiated version " + serverVersion); return serverVersion; } @@ -129,6 +144,13 @@ protected ProtocolVersion[] getSupportedVersions() static class MyIdentityManager implements TlsPSKIdentityManager { + private final boolean badKey; + + MyIdentityManager(boolean badKey) + { + this.badKey = badKey; + } + public byte[] getHint() { return Strings.toUTF8ByteArray("hint"); @@ -141,7 +163,7 @@ public byte[] getPSK(byte[] identity) String name = Strings.fromUTF8ByteArray(identity); if (name.equals("client")) { - return Strings.toUTF8ByteArray("TLS_TEST_PSK"); + return TlsTestUtils.getPSKPasswordUTF8(badKey); } } return null; diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTls13Client.java b/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTls13Client.java index 6efd1815ac..d4e0ef8d01 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTls13Client.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTls13Client.java @@ -10,9 +10,11 @@ import org.bouncycastle.tls.AlertLevel; import org.bouncycastle.tls.BasicTlsPSKExternal; import org.bouncycastle.tls.CipherSuite; +import org.bouncycastle.tls.NamedGroup; import org.bouncycastle.tls.PRFAlgorithm; import org.bouncycastle.tls.ProtocolName; import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SecurityParameters; import org.bouncycastle.tls.TlsAuthentication; import org.bouncycastle.tls.TlsFatalAlert; import org.bouncycastle.tls.TlsPSK; @@ -24,9 +26,18 @@ class MockPSKTls13Client extends AbstractTlsClient { + private final boolean badKey; + MockPSKTls13Client() + { + this(false); + } + + MockPSKTls13Client(boolean badKey) { super(new BcTlsCrypto()); + + this.badKey = badKey; } // public Vector getEarlyKeyShareGroups() @@ -60,7 +71,7 @@ protected ProtocolVersion[] getSupportedVersions() public Vector getExternalPSKs() { byte[] identity = Strings.toUTF8ByteArray("client"); - TlsSecret key = getCrypto().createSecret(Strings.toUTF8ByteArray("TLS_TEST_PSK")); + TlsSecret key = getCrypto().createSecret(TlsTestUtils.getPSKPasswordUTF8(badKey)); int prfAlgorithm = PRFAlgorithm.tls13_hkdf_sha256; return TlsUtils.vectorOfOne(new BasicTlsPSKExternal(identity, key, prfAlgorithm)); @@ -100,7 +111,7 @@ public void notifyServerVersion(ProtocolVersion serverVersion) throws IOExceptio { super.notifyServerVersion(serverVersion); - System.out.println("TLS 1.3 PSK client negotiated " + serverVersion); + System.out.println("TLS 1.3 PSK client negotiated version " + serverVersion); } public TlsAuthentication getAuthentication() throws IOException @@ -112,11 +123,19 @@ public void notifyHandshakeComplete() throws IOException { super.notifyHandshakeComplete(); - ProtocolName protocolName = context.getSecurityParametersConnection().getApplicationProtocol(); + SecurityParameters securityParameters = context.getSecurityParametersConnection(); + + ProtocolName protocolName = securityParameters.getApplicationProtocol(); if (protocolName != null) { System.out.println("Client ALPN: " + protocolName.getUtf8Decoding()); } + + int negotiatedGroup = securityParameters.getNegotiatedGroup(); + if (negotiatedGroup >= 0) + { + System.out.println("Client negotiated group: " + NamedGroup.getText(negotiatedGroup)); + } } public Hashtable getClientExtensions() throws IOException diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTls13Server.java b/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTls13Server.java index b177af6e77..44994120ac 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTls13Server.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTls13Server.java @@ -10,10 +10,12 @@ import org.bouncycastle.tls.AlertLevel; import org.bouncycastle.tls.BasicTlsPSKExternal; import org.bouncycastle.tls.CipherSuite; +import org.bouncycastle.tls.NamedGroup; import org.bouncycastle.tls.PRFAlgorithm; import org.bouncycastle.tls.ProtocolName; import org.bouncycastle.tls.ProtocolVersion; import org.bouncycastle.tls.PskIdentity; +import org.bouncycastle.tls.SecurityParameters; import org.bouncycastle.tls.TlsCredentials; import org.bouncycastle.tls.TlsFatalAlert; import org.bouncycastle.tls.TlsPSKExternal; @@ -25,9 +27,18 @@ class MockPSKTls13Server extends AbstractTlsServer { + private final boolean badKey; + MockPSKTls13Server() + { + this(false); + } + + MockPSKTls13Server(boolean badKey) { super(new BcTlsCrypto()); + + this.badKey = badKey; } public TlsCredentials getCredentials() throws IOException @@ -59,7 +70,7 @@ public ProtocolVersion getServerVersion() throws IOException { ProtocolVersion serverVersion = super.getServerVersion(); - System.out.println("TLS 1.3 PSK server negotiated " + serverVersion); + System.out.println("TLS 1.3 PSK server negotiated version " + serverVersion); return serverVersion; } @@ -75,7 +86,7 @@ public TlsPSKExternal getExternalPSK(Vector identities) { if (matchIdentity.equals(identities.elementAt(i))) { - TlsSecret key = getCrypto().createSecret(Strings.toUTF8ByteArray("TLS_TEST_PSK")); + TlsSecret key = getCrypto().createSecret(TlsTestUtils.getPSKPasswordUTF8(badKey)); int prfAlgorithm = PRFAlgorithm.tls13_hkdf_sha256; return new BasicTlsPSKExternal(identity, key, prfAlgorithm); @@ -110,11 +121,19 @@ public void notifyHandshakeComplete() throws IOException { super.notifyHandshakeComplete(); - ProtocolName protocolName = context.getSecurityParametersConnection().getApplicationProtocol(); + SecurityParameters securityParameters = context.getSecurityParametersConnection(); + + ProtocolName protocolName = securityParameters.getApplicationProtocol(); if (protocolName != null) { System.out.println("Server ALPN: " + protocolName.getUtf8Decoding()); } + + int negotiatedGroup = securityParameters.getNegotiatedGroup(); + if (negotiatedGroup >= 0) + { + System.out.println("Server negotiated group: " + NamedGroup.getText(negotiatedGroup)); + } } public void processClientExtensions(Hashtable clientExtensions) throws IOException diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsClient.java b/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsClient.java index 99261f1d32..beda7f03d7 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsClient.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsClient.java @@ -35,7 +35,12 @@ class MockPSKTlsClient MockPSKTlsClient(TlsSession session) { - this(session, new BasicTlsPSKIdentity("client", Strings.toUTF8ByteArray("TLS_TEST_PSK"))); + this(session, false); + } + + MockPSKTlsClient(TlsSession session, boolean badKey) + { + this(session, TlsTestUtils.createDefaultPSKIdentity(badKey)); } MockPSKTlsClient(TlsSession session, TlsPSKIdentity pskIdentity) @@ -103,7 +108,7 @@ public void notifyServerVersion(ProtocolVersion serverVersion) throws IOExceptio { super.notifyServerVersion(serverVersion); - System.out.println("TLS-PSK client negotiated " + serverVersion); + System.out.println("TLS-PSK client negotiated version " + serverVersion); } public TlsAuthentication getAuthentication() throws IOException diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsServer.java b/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsServer.java index 69bdfd20f3..93d42ba27c 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsServer.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockPSKTlsServer.java @@ -23,7 +23,12 @@ class MockPSKTlsServer { MockPSKTlsServer() { - super(new BcTlsCrypto(), new MyIdentityManager()); + this(false); + } + + MockPSKTlsServer(boolean badKey) + { + super(new BcTlsCrypto(), new MyIdentityManager(badKey)); } protected Vector getProtocolNames() @@ -60,7 +65,7 @@ public ProtocolVersion getServerVersion() throws IOException { ProtocolVersion serverVersion = super.getServerVersion(); - System.out.println("TLS-PSK server negotiated " + serverVersion); + System.out.println("TLS-PSK server negotiated version " + serverVersion); return serverVersion; } @@ -138,6 +143,13 @@ protected ProtocolVersion[] getSupportedVersions() static class MyIdentityManager implements TlsPSKIdentityManager { + private final boolean badKey; + + MyIdentityManager(boolean badKey) + { + this.badKey = badKey; + } + public byte[] getHint() { return Strings.toUTF8ByteArray("hint"); @@ -150,7 +162,7 @@ public byte[] getPSK(byte[] identity) String name = Strings.fromUTF8ByteArray(identity); if (name.equals("client")) { - return Strings.toUTF8ByteArray("TLS_TEST_PSK"); + return TlsTestUtils.getPSKPasswordUTF8(badKey); } } return null; diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsClient.java b/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsClient.java index 74126f1b40..f02953766c 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsClient.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsClient.java @@ -96,7 +96,7 @@ public void notifyServerVersion(ProtocolVersion serverVersion) throws IOExceptio { super.notifyServerVersion(serverVersion); - System.out.println("TLS-SRP client negotiated " + serverVersion); + System.out.println("TLS-SRP client negotiated version " + serverVersion); } public TlsAuthentication getAuthentication() throws IOException diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsServer.java b/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsServer.java index 3b01c4c1fa..bb9b8d0369 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsServer.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockSRPTlsServer.java @@ -87,7 +87,7 @@ public ProtocolVersion getServerVersion() throws IOException { ProtocolVersion serverVersion = super.getServerVersion(); - System.out.println("TLS-SRP server negotiated " + serverVersion); + System.out.println("TLS-SRP server negotiated version " + serverVersion); return serverVersion; } diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsClient.java b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsClient.java index 5adb80ab24..fe5b6b560c 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsClient.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsClient.java @@ -98,7 +98,7 @@ public void notifyServerVersion(ProtocolVersion serverVersion) throws IOExceptio { super.notifyServerVersion(serverVersion); - System.out.println("TLS client negotiated " + serverVersion); + System.out.println("TLS client negotiated version " + serverVersion); } public TlsAuthentication getAuthentication() throws IOException @@ -128,6 +128,7 @@ public void notifyServerCertificate(TlsServerCertificate serverCertificate) thro String[] trustedCertResources = new String[]{ "x509-server-dsa.pem", "x509-server-ecdh.pem", "x509-server-ecdsa.pem", "x509-server-ed25519.pem", "x509-server-ed448.pem", + "x509-server-ml_dsa_44.pem", "x509-server-ml_dsa_65.pem", "x509-server-ml_dsa_87.pem", "x509-server-rsa_pss_256.pem", "x509-server-rsa_pss_384.pem", "x509-server-rsa_pss_512.pem", "x509-server-rsa-enc.pem", "x509-server-rsa-sign.pem" }; diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsHybridClient.java b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsHybridClient.java new file mode 100644 index 0000000000..26b3eebf13 --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsHybridClient.java @@ -0,0 +1,255 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.AlertLevel; +import org.bouncycastle.tls.CertificateRequest; +import org.bouncycastle.tls.ChannelBinding; +import org.bouncycastle.tls.ClientCertificateType; +import org.bouncycastle.tls.DefaultTlsClient; +import org.bouncycastle.tls.MaxFragmentLength; +import org.bouncycastle.tls.NamedGroup; +import org.bouncycastle.tls.NamedGroupRole; +import org.bouncycastle.tls.ProtocolName; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SecurityParameters; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.TlsAuthentication; +import org.bouncycastle.tls.TlsCredentials; +import org.bouncycastle.tls.TlsExtensionsUtils; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsServerCertificate; +import org.bouncycastle.tls.TlsSession; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Integers; +import org.bouncycastle.util.encoders.Hex; + +class MockTlsHybridClient + extends DefaultTlsClient +{ + TlsSession session; + + int[] namedGroups = new int[] + { + NamedGroup.SecP256r1MLKEM768, + NamedGroup.X25519MLKEM768, + NamedGroup.SecP384r1MLKEM1024, + NamedGroup.curveSM2MLKEM768, + }; + + MockTlsHybridClient(TlsCrypto crypto, TlsSession session) + { + super(crypto); + + this.session = session; + } + + protected Vector getProtocolNames() + { + Vector protocolNames = new Vector(); + protocolNames.addElement(ProtocolName.HTTP_1_1); + protocolNames.addElement(ProtocolName.HTTP_2_TLS); + return protocolNames; + } + + void setNamedGroups(int[] namedGroups) + { + this.namedGroups = namedGroups; + } + + protected Vector getSupportedGroups(Vector namedGroupRoles) { + TlsCrypto crypto = getCrypto(); + Vector supportedGroups = new Vector(); + + if (namedGroupRoles.contains(Integers.valueOf(NamedGroupRole.kem))) + { + TlsUtils.addIfSupported(supportedGroups, crypto, this.namedGroups); + } + return supportedGroups; + } + + public TlsSession getSessionToResume() + { + return this.session; + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS hybrid client raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS hybrid client received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + + public Hashtable getClientExtensions() throws IOException + { + if (context.getSecurityParametersHandshake().getClientRandom() == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + Hashtable clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(super.getClientExtensions()); + { + /* + * 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.getCrypto().getSecureRandom().nextInt(16)); + TlsExtensionsUtils.addTruncatedHMacExtension(clientExtensions); + } + return clientExtensions; + } + + public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException + { + super.notifyServerVersion(serverVersion); + + System.out.println("TLS hybrid client negotiated version " + serverVersion); + } + + public TlsAuthentication getAuthentication() throws IOException + { + return new TlsAuthentication() + { + public void notifyServerCertificate(TlsServerCertificate serverCertificate) throws IOException + { + TlsCertificate[] chain = serverCertificate.getCertificate().getCertificateList(); + + System.out.println("TLS hybrid client received server certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = Certificate.getInstance(chain[i].getEncoded()); + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + + boolean isEmpty = serverCertificate == null || serverCertificate.getCertificate() == null + || serverCertificate.getCertificate().isEmpty(); + + if (isEmpty) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + + String[] trustedCertResources = new String[]{ "x509-server-dsa.pem", "x509-server-ecdh.pem", + "x509-server-ecdsa.pem", "x509-server-ed25519.pem", "x509-server-ed448.pem", + "x509-server-ml_dsa_44.pem", "x509-server-ml_dsa_65.pem", "x509-server-ml_dsa_87.pem", + "x509-server-rsa_pss_256.pem", "x509-server-rsa_pss_384.pem", "x509-server-rsa_pss_512.pem", + "x509-server-rsa-enc.pem", "x509-server-rsa-sign.pem" }; + + TlsCertificate[] certPath = TlsTestUtils.getTrustedCertPath(context.getCrypto(), chain[0], + trustedCertResources); + + if (null == certPath) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + + TlsUtils.checkPeerSigAlgs(context, certPath); + } + + public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException + { + short[] certificateTypes = certificateRequest.getCertificateTypes(); + if (certificateTypes == null || !Arrays.contains(certificateTypes, ClientCertificateType.rsa_sign)) + { + return null; + } + + return TlsTestUtils.loadSignerCredentials(context, certificateRequest.getSupportedSignatureAlgorithms(), + SignatureAlgorithm.rsa, "x509-client-rsa.pem", "x509-client-key-rsa.pem"); + } + }; + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + SecurityParameters securityParameters = context.getSecurityParametersConnection(); + + ProtocolName protocolName = securityParameters.getApplicationProtocol(); + if (protocolName != null) + { + System.out.println("Client ALPN: " + protocolName.getUtf8Decoding()); + } + + int negotiatedGroup = securityParameters.getNegotiatedGroup(); + if (negotiatedGroup >= 0) + { + System.out.println("Client negotiated group: " + NamedGroup.getText(negotiatedGroup)); + } + + TlsSession newSession = context.getSession(); + if (newSession != null) + { + if (newSession.isResumable()) + { + byte[] newSessionID = newSession.getSessionID(); + String hex = hex(newSessionID); + + if (this.session != null && Arrays.areEqual(this.session.getSessionID(), newSessionID)) + { + System.out.println("Client resumed session: " + hex); + } + else + { + System.out.println("Client established session: " + hex); + } + + this.session = newSession; + } + + byte[] tlsServerEndPoint = context.exportChannelBinding(ChannelBinding.tls_server_end_point); + if (null != tlsServerEndPoint) + { + System.out.println("Client 'tls-server-end-point': " + hex(tlsServerEndPoint)); + } + + byte[] tlsUnique = context.exportChannelBinding(ChannelBinding.tls_unique); + System.out.println("Client 'tls-unique': " + hex(tlsUnique)); + + byte[] tlsExporter = context.exportChannelBinding(ChannelBinding.tls_exporter); + System.out.println("Client 'tls-exporter': " + hex(tlsExporter)); + } + } + + public void processServerExtensions(Hashtable serverExtensions) throws IOException + { + if (context.getSecurityParametersHandshake().getServerRandom() == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + super.processServerExtensions(serverExtensions); + } + + protected String hex(byte[] data) + { + return data == null ? "(null)" : Hex.toHexString(data); + } +} + diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsHybridServer.java b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsHybridServer.java new file mode 100644 index 0000000000..045017839c --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsHybridServer.java @@ -0,0 +1,256 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.Hashtable; +import java.util.Vector; + +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.Certificate; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.AlertLevel; +import org.bouncycastle.tls.CertificateRequest; +import org.bouncycastle.tls.ChannelBinding; +import org.bouncycastle.tls.ClientCertificateType; +import org.bouncycastle.tls.DefaultTlsServer; +import org.bouncycastle.tls.NamedGroup; +import org.bouncycastle.tls.ProtocolName; +import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SecurityParameters; +import org.bouncycastle.tls.SignatureAlgorithm; +import org.bouncycastle.tls.TlsCredentialedDecryptor; +import org.bouncycastle.tls.TlsCredentialedSigner; +import org.bouncycastle.tls.TlsCredentials; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.util.encoders.Hex; + +class MockTlsHybridServer + extends DefaultTlsServer +{ + int[] namedGroups = new int[] + { + NamedGroup.SecP256r1MLKEM768, + NamedGroup.X25519MLKEM768, + NamedGroup.SecP384r1MLKEM1024, + NamedGroup.curveSM2MLKEM768, + NamedGroup.x25519, + }; + + MockTlsHybridServer(TlsCrypto crypto) + { + super(crypto); + } + + protected Vector getProtocolNames() + { + Vector protocolNames = new Vector(); + protocolNames.addElement(ProtocolName.HTTP_2_TLS); + protocolNames.addElement(ProtocolName.HTTP_1_1); + return protocolNames; + } + + void setNamedGroups(int[] namedGroups) + { + this.namedGroups = namedGroups; + } + + public int[] getSupportedGroups() throws IOException + { + return namedGroups; + } + + public TlsCredentials getCredentials() throws IOException + { + /* + * TODO[tls13] Should really be finding the first client-supported signature scheme that the + * server also supports and has credentials for. + */ + if (TlsUtils.isTLSv13(context)) + { + return getRSASignerCredentials(); + } + + return super.getCredentials(); + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS hybrid server raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS hybrid server received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + + public ProtocolVersion getServerVersion() throws IOException + { + ProtocolVersion serverVersion = super.getServerVersion(); + + System.out.println("TLS hybrid server negotiated version " + serverVersion); + + return serverVersion; + } + + public CertificateRequest getCertificateRequest() throws IOException + { + Vector serverSigAlgs = null; + if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(context.getServerVersion())) + { + serverSigAlgs = TlsUtils.getDefaultSupportedSignatureAlgorithms(context); + } + + Vector certificateAuthorities = new Vector(); +// certificateAuthorities.addElement(TlsTestUtils.loadBcCertificateResource("x509-ca-dsa.pem").getSubject()); +// certificateAuthorities.addElement(TlsTestUtils.loadBcCertificateResource("x509-ca-ecdsa.pem").getSubject()); +// certificateAuthorities.addElement(TlsTestUtils.loadBcCertificateResource("x509-ca-rsa.pem").getSubject()); + + // All the CA certificates are currently configured with this subject + certificateAuthorities.addElement(new X500Name("CN=BouncyCastle TLS Test CA")); + + if (TlsUtils.isTLSv13(context)) + { + // TODO[tls13] Support for non-empty request context + byte[] certificateRequestContext = TlsUtils.EMPTY_BYTES; + + // TODO[tls13] Add TlsTestConfig.serverCertReqSigAlgsCert + Vector serverSigAlgsCert = null; + + return new CertificateRequest(certificateRequestContext, serverSigAlgs, serverSigAlgsCert, + certificateAuthorities); + } + else + { + short[] certificateTypes = new short[]{ ClientCertificateType.rsa_sign, + ClientCertificateType.dss_sign, ClientCertificateType.ecdsa_sign }; + + return new CertificateRequest(certificateTypes, serverSigAlgs, certificateAuthorities); + } + } + + public void notifyClientCertificate(org.bouncycastle.tls.Certificate clientCertificate) throws IOException + { + TlsCertificate[] chain = clientCertificate.getCertificateList(); + + System.out.println("TLS hybrid server received client certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = Certificate.getInstance(chain[i].getEncoded()); + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + + boolean isEmpty = (clientCertificate == null || clientCertificate.isEmpty()); + + if (isEmpty) + { + return; + } + + String[] trustedCertResources = new String[]{ "x509-client-dsa.pem", "x509-client-ecdh.pem", + "x509-client-ecdsa.pem", "x509-client-ed25519.pem", "x509-client-ed448.pem", "x509-client-ml_dsa_44.pem", + "x509-client-ml_dsa_65.pem", "x509-client-ml_dsa_87.pem", "x509-client-rsa_pss_256.pem", + "x509-client-rsa_pss_384.pem", "x509-client-rsa_pss_512.pem", "x509-client-rsa.pem" }; + + TlsCertificate[] certPath = TlsTestUtils.getTrustedCertPath(context.getCrypto(), chain[0], + trustedCertResources); + + if (null == certPath) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + + TlsUtils.checkPeerSigAlgs(context, certPath); + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + SecurityParameters securityParameters = context.getSecurityParametersConnection(); + + ProtocolName protocolName = securityParameters.getApplicationProtocol(); + if (protocolName != null) + { + System.out.println("Server ALPN: " + protocolName.getUtf8Decoding()); + } + + int negotiatedGroup = securityParameters.getNegotiatedGroup(); + if (negotiatedGroup >= 0) + { + System.out.println("Server negotiated group: " + NamedGroup.getText(negotiatedGroup)); + } + + byte[] tlsServerEndPoint = context.exportChannelBinding(ChannelBinding.tls_server_end_point); + System.out.println("Server 'tls-server-end-point': " + hex(tlsServerEndPoint)); + + byte[] tlsUnique = context.exportChannelBinding(ChannelBinding.tls_unique); + System.out.println("Server 'tls-unique': " + hex(tlsUnique)); + + byte[] tlsExporter = context.exportChannelBinding(ChannelBinding.tls_exporter); + System.out.println("Server 'tls-exporter': " + hex(tlsExporter)); + } + + public void processClientExtensions(Hashtable clientExtensions) throws IOException + { + if (context.getSecurityParametersHandshake().getClientRandom() == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + super.processClientExtensions(clientExtensions); + } + + public Hashtable getServerExtensions() throws IOException + { + if (context.getSecurityParametersHandshake().getServerRandom() == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + return super.getServerExtensions(); + } + + public void getServerExtensionsForConnection(Hashtable serverExtensions) throws IOException + { + if (context.getSecurityParametersHandshake().getServerRandom() == null) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + super.getServerExtensionsForConnection(serverExtensions); + } + + protected TlsCredentialedDecryptor getRSAEncryptionCredentials() throws IOException + { + return TlsTestUtils.loadEncryptionCredentials(context, new String[]{ "x509-server-rsa-enc.pem", "x509-ca-rsa.pem" }, + "x509-server-key-rsa-enc.pem"); + } + + protected TlsCredentialedSigner getRSASignerCredentials() throws IOException + { + Vector clientSigAlgs = context.getSecurityParametersHandshake().getClientSigAlgs(); + return TlsTestUtils.loadSignerCredentialsServer(context, clientSigAlgs, SignatureAlgorithm.rsa); + } + + protected String hex(byte[] data) + { + return data == null ? "(null)" : Hex.toHexString(data); + } +} diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKemClient.java b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKemClient.java index 6e799c9511..76e9b830d1 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKemClient.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKemClient.java @@ -17,6 +17,7 @@ import org.bouncycastle.tls.NamedGroupRole; import org.bouncycastle.tls.ProtocolName; import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SecurityParameters; import org.bouncycastle.tls.SignatureAlgorithm; import org.bouncycastle.tls.TlsAuthentication; import org.bouncycastle.tls.TlsCredentials; @@ -27,7 +28,6 @@ import org.bouncycastle.tls.TlsUtils; import org.bouncycastle.tls.crypto.TlsCertificate; import org.bouncycastle.tls.crypto.TlsCrypto; -import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Integers; import org.bouncycastle.util.encoders.Hex; @@ -44,9 +44,9 @@ class MockTlsKemClient NamedGroup.MLKEM1024, }; - MockTlsKemClient(TlsSession session) + MockTlsKemClient(TlsCrypto crypto, TlsSession session) { - super(new BcTlsCrypto()); + super(crypto); this.session = session; } @@ -125,7 +125,7 @@ public void notifyServerVersion(ProtocolVersion serverVersion) throws IOExceptio { super.notifyServerVersion(serverVersion); - System.out.println("TLS KEM client negotiated " + serverVersion); + System.out.println("TLS KEM client negotiated version " + serverVersion); } public TlsAuthentication getAuthentication() throws IOException @@ -155,6 +155,7 @@ public void notifyServerCertificate(TlsServerCertificate serverCertificate) thro String[] trustedCertResources = new String[]{ "x509-server-dsa.pem", "x509-server-ecdh.pem", "x509-server-ecdsa.pem", "x509-server-ed25519.pem", "x509-server-ed448.pem", + "x509-server-ml_dsa_44.pem", "x509-server-ml_dsa_65.pem", "x509-server-ml_dsa_87.pem", "x509-server-rsa_pss_256.pem", "x509-server-rsa_pss_384.pem", "x509-server-rsa_pss_512.pem", "x509-server-rsa-enc.pem", "x509-server-rsa-sign.pem" }; @@ -187,12 +188,20 @@ public void notifyHandshakeComplete() throws IOException { super.notifyHandshakeComplete(); - ProtocolName protocolName = context.getSecurityParametersConnection().getApplicationProtocol(); + SecurityParameters securityParameters = context.getSecurityParametersConnection(); + + ProtocolName protocolName = securityParameters.getApplicationProtocol(); if (protocolName != null) { System.out.println("Client ALPN: " + protocolName.getUtf8Decoding()); } + int negotiatedGroup = securityParameters.getNegotiatedGroup(); + if (negotiatedGroup >= 0) + { + System.out.println("Client negotiated group: " + NamedGroup.getText(negotiatedGroup)); + } + TlsSession newSession = context.getSession(); if (newSession != null) { diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKemServer.java b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKemServer.java index 5a41afd9fe..d341b1a09d 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKemServer.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKemServer.java @@ -16,6 +16,7 @@ import org.bouncycastle.tls.NamedGroup; import org.bouncycastle.tls.ProtocolName; import org.bouncycastle.tls.ProtocolVersion; +import org.bouncycastle.tls.SecurityParameters; import org.bouncycastle.tls.SignatureAlgorithm; import org.bouncycastle.tls.TlsCredentialedDecryptor; import org.bouncycastle.tls.TlsCredentialedSigner; @@ -23,7 +24,7 @@ import org.bouncycastle.tls.TlsFatalAlert; import org.bouncycastle.tls.TlsUtils; import org.bouncycastle.tls.crypto.TlsCertificate; -import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.tls.crypto.TlsCrypto; import org.bouncycastle.util.encoders.Hex; class MockTlsKemServer @@ -37,9 +38,9 @@ class MockTlsKemServer NamedGroup.x25519, }; - MockTlsKemServer() + MockTlsKemServer(TlsCrypto crypto) { - super(new BcTlsCrypto()); + super(crypto); } protected Vector getProtocolNames() @@ -100,7 +101,7 @@ public ProtocolVersion getServerVersion() throws IOException { ProtocolVersion serverVersion = super.getServerVersion(); - System.out.println("TLS KEM server negotiated " + serverVersion); + System.out.println("TLS KEM server negotiated version " + serverVersion); return serverVersion; } @@ -162,7 +163,8 @@ public void notifyClientCertificate(org.bouncycastle.tls.Certificate clientCerti } String[] trustedCertResources = new String[]{ "x509-client-dsa.pem", "x509-client-ecdh.pem", - "x509-client-ecdsa.pem", "x509-client-ed25519.pem", "x509-client-ed448.pem", "x509-client-rsa_pss_256.pem", + "x509-client-ecdsa.pem", "x509-client-ed25519.pem", "x509-client-ed448.pem", "x509-client-ml_dsa_44.pem", + "x509-client-ml_dsa_65.pem", "x509-client-ml_dsa_87.pem", "x509-client-rsa_pss_256.pem", "x509-client-rsa_pss_384.pem", "x509-client-rsa_pss_512.pem", "x509-client-rsa.pem" }; TlsCertificate[] certPath = TlsTestUtils.getTrustedCertPath(context.getCrypto(), chain[0], @@ -180,12 +182,20 @@ public void notifyHandshakeComplete() throws IOException { super.notifyHandshakeComplete(); - ProtocolName protocolName = context.getSecurityParametersConnection().getApplicationProtocol(); + SecurityParameters securityParameters = context.getSecurityParametersConnection(); + + ProtocolName protocolName = securityParameters.getApplicationProtocol(); if (protocolName != null) { System.out.println("Server ALPN: " + protocolName.getUtf8Decoding()); } + int negotiatedGroup = securityParameters.getNegotiatedGroup(); + if (negotiatedGroup >= 0) + { + System.out.println("Server negotiated group: " + NamedGroup.getText(negotiatedGroup)); + } + byte[] tlsServerEndPoint = context.exportChannelBinding(ChannelBinding.tls_server_end_point); System.out.println("Server 'tls-server-end-point': " + hex(tlsServerEndPoint)); diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsServer.java b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsServer.java index a60001980b..3ae70d2151 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsServer.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsServer.java @@ -81,7 +81,7 @@ public ProtocolVersion getServerVersion() throws IOException { ProtocolVersion serverVersion = super.getServerVersion(); - System.out.println("TLS server negotiated " + serverVersion); + System.out.println("TLS server negotiated version " + serverVersion); return serverVersion; } @@ -143,7 +143,8 @@ public void notifyClientCertificate(org.bouncycastle.tls.Certificate clientCerti } String[] trustedCertResources = new String[]{ "x509-client-dsa.pem", "x509-client-ecdh.pem", - "x509-client-ecdsa.pem", "x509-client-ed25519.pem", "x509-client-ed448.pem", "x509-client-rsa_pss_256.pem", + "x509-client-ecdsa.pem", "x509-client-ed25519.pem", "x509-client-ed448.pem", "x509-client-ml_dsa_44.pem", + "x509-client-ml_dsa_65.pem", "x509-client-ml_dsa_87.pem", "x509-client-rsa_pss_256.pem", "x509-client-rsa_pss_384.pem", "x509-client-rsa_pss_512.pem", "x509-client-rsa.pem" }; TlsCertificate[] certPath = TlsTestUtils.getTrustedCertPath(context.getCrypto(), chain[0], diff --git a/tls/src/test/java/org/bouncycastle/tls/test/PSKTlsClientTest.java b/tls/src/test/java/org/bouncycastle/tls/test/PSKTlsClientTest.java index c8eb43ffab..b93a428757 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/PSKTlsClientTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/PSKTlsClientTest.java @@ -11,6 +11,7 @@ import org.bouncycastle.tls.BasicTlsPSKIdentity; import org.bouncycastle.tls.TlsClient; import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsPSKIdentity; import org.bouncycastle.util.Strings; /** @@ -38,12 +39,10 @@ public static void main(String[] args) throws Exception */ // String psk_identity = "Client_identity"; // byte[] psk = new byte[]{ 0x61, 0x61, 0x61, 0x61, 0x61 }; +// TlsPSKIdentity pskIdentity = new BasicTlsPSKIdentity(psk_identity, psk); - // These correspond to the configuration of MockPSKTlsServer - String psk_identity = "client"; - byte[] psk = Strings.toUTF8ByteArray("TLS_TEST_PSK"); - - BasicTlsPSKIdentity pskIdentity = new BasicTlsPSKIdentity(psk_identity, psk); + // This corresponds to the configuration of MockPskTlsServer + TlsPSKIdentity pskIdentity = TlsTestUtils.createDefaultPSKIdentity(false); MockPSKTlsClient client = new MockPSKTlsClient(null, pskIdentity); TlsClientProtocol protocol = openTlsConnection(address, port, client); diff --git a/tls/src/test/java/org/bouncycastle/tls/test/Tls13PSKProtocolTest.java b/tls/src/test/java/org/bouncycastle/tls/test/Tls13PSKProtocolTest.java index 924e7f12d3..6919861963 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/Tls13PSKProtocolTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/Tls13PSKProtocolTest.java @@ -4,7 +4,10 @@ import java.io.PipedInputStream; import java.io.PipedOutputStream; +import org.bouncycastle.tls.AlertDescription; import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsFatalAlertReceived; +import org.bouncycastle.tls.TlsServer; import org.bouncycastle.tls.TlsServerProtocol; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.io.Streams; @@ -14,8 +17,27 @@ public class Tls13PSKProtocolTest extends TestCase { + public void testBadClientKey() throws Exception + { + MockPSKTls13Client client = new MockPSKTls13Client(true); + MockPSKTls13Server server = new MockPSKTls13Server(); + + implTestKeyMismatch(client, server); + } + + public void testBadServerKey() throws Exception + { + MockPSKTls13Client client = new MockPSKTls13Client(); + MockPSKTls13Server server = new MockPSKTls13Server(true); + + implTestKeyMismatch(client, server); + } + public void testClientServer() throws Exception { + MockPSKTls13Client client = new MockPSKTls13Client(); + MockPSKTls13Server server = new MockPSKTls13Server(); + PipedInputStream clientRead = TlsTestUtils.createPipedInputStream(); PipedInputStream serverRead = TlsTestUtils.createPipedInputStream(); PipedOutputStream clientWrite = new PipedOutputStream(serverRead); @@ -24,10 +46,9 @@ public void testClientServer() throws Exception TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite); TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite); - ServerThread serverThread = new ServerThread(serverProtocol); + ServerThread serverThread = new ServerThread(serverProtocol, server); serverThread.start(); - MockPSKTls13Client client = new MockPSKTls13Client(); clientProtocol.connect(client); // NOTE: Because we write-all before we read-any, this length can't be more than the pipe capacity @@ -50,28 +71,67 @@ public void testClientServer() throws Exception serverThread.join(); } + private void implTestKeyMismatch(MockPSKTls13Client client, MockPSKTls13Server server) throws Exception + { + PipedInputStream clientRead = TlsTestUtils.createPipedInputStream(); + PipedInputStream serverRead = TlsTestUtils.createPipedInputStream(); + PipedOutputStream clientWrite = new PipedOutputStream(serverRead); + PipedOutputStream serverWrite = new PipedOutputStream(clientRead); + + TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite); + TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite); + + ServerThread serverThread = new ServerThread(serverProtocol, server); + serverThread.start(); + + boolean correctException = false; + short alertDescription = -1; + + try + { + clientProtocol.connect(client); + } + catch (TlsFatalAlertReceived e) + { + correctException = true; + alertDescription = e.getAlertDescription(); + } + catch (Exception e) + { + } + finally + { + clientProtocol.close(); + } + + serverThread.join(); + + assertTrue(correctException); + assertEquals(AlertDescription.decrypt_error, alertDescription); + } + static class ServerThread extends Thread { private final TlsServerProtocol serverProtocol; + private final TlsServer server; - ServerThread(TlsServerProtocol serverProtocol) + ServerThread(TlsServerProtocol serverProtocol, TlsServer server) { this.serverProtocol = serverProtocol; + this.server = server; } public void run() { try { - MockPSKTls13Server server = new MockPSKTls13Server(); serverProtocol.accept(server); Streams.pipeAll(serverProtocol.getInputStream(), serverProtocol.getOutputStream()); serverProtocol.close(); } catch (Exception e) { -// throw new RuntimeException(e); } } } diff --git a/tls/src/test/java/org/bouncycastle/tls/test/TlsPSKProtocolTest.java b/tls/src/test/java/org/bouncycastle/tls/test/TlsPSKProtocolTest.java index 1a3d42496f..1f407474d6 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/TlsPSKProtocolTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/TlsPSKProtocolTest.java @@ -4,7 +4,10 @@ import java.io.PipedInputStream; import java.io.PipedOutputStream; +import org.bouncycastle.tls.AlertDescription; import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsFatalAlertReceived; +import org.bouncycastle.tls.TlsServer; import org.bouncycastle.tls.TlsServerProtocol; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.io.Streams; @@ -14,8 +17,27 @@ public class TlsPSKProtocolTest extends TestCase { + public void testBadClientKey() throws Exception + { + MockPSKTlsClient client = new MockPSKTlsClient(null, true); + MockPSKTlsServer server = new MockPSKTlsServer(); + + implTestKeyMismatch(client, server); + } + + public void testBadServerKey() throws Exception + { + MockPSKTlsClient client = new MockPSKTlsClient(null); + MockPSKTlsServer server = new MockPSKTlsServer(true); + + implTestKeyMismatch(client, server); + } + public void testClientServer() throws Exception { + MockPSKTlsClient client = new MockPSKTlsClient(null); + MockPSKTlsServer server = new MockPSKTlsServer(); + PipedInputStream clientRead = TlsTestUtils.createPipedInputStream(); PipedInputStream serverRead = TlsTestUtils.createPipedInputStream(); PipedOutputStream clientWrite = new PipedOutputStream(serverRead); @@ -24,10 +46,9 @@ public void testClientServer() throws Exception TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite); TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite); - ServerThread serverThread = new ServerThread(serverProtocol); + ServerThread serverThread = new ServerThread(serverProtocol, server); serverThread.start(); - MockPSKTlsClient client = new MockPSKTlsClient(null); clientProtocol.connect(client); // NOTE: Because we write-all before we read-any, this length can't be more than the pipe capacity @@ -50,28 +71,67 @@ public void testClientServer() throws Exception serverThread.join(); } + private void implTestKeyMismatch(MockPSKTlsClient client, MockPSKTlsServer server) throws Exception + { + PipedInputStream clientRead = TlsTestUtils.createPipedInputStream(); + PipedInputStream serverRead = TlsTestUtils.createPipedInputStream(); + PipedOutputStream clientWrite = new PipedOutputStream(serverRead); + PipedOutputStream serverWrite = new PipedOutputStream(clientRead); + + TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite); + TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite); + + ServerThread serverThread = new ServerThread(serverProtocol, server); + serverThread.start(); + + boolean correctException = false; + short alertDescription = -1; + + try + { + clientProtocol.connect(client); + } + catch (TlsFatalAlertReceived e) + { + correctException = true; + alertDescription = e.getAlertDescription(); + } + catch (Exception e) + { + } + finally + { + clientProtocol.close(); + } + + serverThread.join(); + + assertTrue(correctException); + assertEquals(AlertDescription.bad_record_mac, alertDescription); + } + static class ServerThread extends Thread { private final TlsServerProtocol serverProtocol; + private final TlsServer server; - ServerThread(TlsServerProtocol serverProtocol) + ServerThread(TlsServerProtocol serverProtocol, TlsServer server) { this.serverProtocol = serverProtocol; + this.server = server; } public void run() { try { - MockPSKTlsServer server = new MockPSKTlsServer(); serverProtocol.accept(server); Streams.pipeAll(serverProtocol.getInputStream(), serverProtocol.getOutputStream()); serverProtocol.close(); } catch (Exception e) { -// throw new RuntimeException(e); } } } diff --git a/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolHybridTest.java b/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolHybridTest.java new file mode 100644 index 0000000000..9a72104854 --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolHybridTest.java @@ -0,0 +1,170 @@ +package org.bouncycastle.tls.test; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; + +import org.bouncycastle.tls.NamedGroup; +import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsServer; +import org.bouncycastle.tls.TlsServerProtocol; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.io.Streams; + +import junit.framework.TestCase; + +public abstract class TlsProtocolHybridTest + extends TestCase +{ + protected final TlsCrypto crypto; + + protected TlsProtocolHybridTest(TlsCrypto crypto) + { + this.crypto = crypto; + } + + // mismatched hybrid groups w/o non-hybrids + public void testMismatchedGroups() throws Exception + { + PipedInputStream clientRead = TlsTestUtils.createPipedInputStream(); + PipedInputStream serverRead = TlsTestUtils.createPipedInputStream(); + PipedOutputStream clientWrite = new PipedOutputStream(serverRead); + PipedOutputStream serverWrite = new PipedOutputStream(clientRead); + + TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite); + TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite); + + MockTlsHybridClient client = new MockTlsHybridClient(crypto, null); + MockTlsHybridServer server = new MockTlsHybridServer(crypto); + + client.setNamedGroups(new int[]{ NamedGroup.SecP256r1MLKEM768 }); + server.setNamedGroups(new int[]{ NamedGroup.X25519MLKEM768 }); + + ServerThread serverThread = new ServerThread(serverProtocol, server, true); + try + { + serverThread.start(); + } + catch (Exception ignored) + { + } + + try + { + clientProtocol.connect(client); + fail(); + } + catch (Exception ignored) + { + } + + serverThread.join(); + } + + public void testCurveSM2MLKEM768() throws Exception + { + implTestClientServer(NamedGroup.curveSM2MLKEM768); + } + + public void testSecP256r1MLKEM768() throws Exception + { + implTestClientServer(NamedGroup.SecP256r1MLKEM768); + } + + public void testSecP384r1MLKEM1024() throws Exception + { + implTestClientServer(NamedGroup.SecP384r1MLKEM1024); + } + + public void testX25519MLKEM768() throws Exception + { + implTestClientServer(NamedGroup.X25519MLKEM768); + } + + private void implTestClientServer(int hybridGroup) throws Exception + { + PipedInputStream clientRead = TlsTestUtils.createPipedInputStream(); + PipedInputStream serverRead = TlsTestUtils.createPipedInputStream(); + PipedOutputStream clientWrite = new PipedOutputStream(serverRead); + PipedOutputStream serverWrite = new PipedOutputStream(clientRead); + + TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite); + TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite); + + MockTlsHybridClient client = new MockTlsHybridClient(crypto, null); + MockTlsHybridServer server = new MockTlsHybridServer(crypto); + + client.setNamedGroups(new int[]{ hybridGroup }); + server.setNamedGroups(new int[]{ hybridGroup }); + + ServerThread serverThread = new ServerThread(serverProtocol, server, false); + serverThread.start(); + + clientProtocol.connect(client); + + // NOTE: Because we write-all before we read-any, this length can't be more than the pipe capacity + int length = 1000; + + byte[] data = new byte[length]; + client.getCrypto().getSecureRandom().nextBytes(data); + + OutputStream output = clientProtocol.getOutputStream(); + output.write(data); + + byte[] echo = new byte[data.length]; + int count = Streams.readFully(clientProtocol.getInputStream(), echo); + + assertEquals(count, data.length); + assertTrue(Arrays.areEqual(data, echo)); + + output.close(); + + serverThread.join(); + } + + static class ServerThread + extends Thread + { + private final TlsServerProtocol serverProtocol; + private final TlsServer server; + private final boolean shouldFail; + + ServerThread(TlsServerProtocol serverProtocol, TlsServer server, boolean shouldFail) + { + this.serverProtocol = serverProtocol; + this.server = server; + this.shouldFail = shouldFail; + } + + public void run() + { + try + { + try + { + serverProtocol.accept(server); + if (shouldFail) + { + fail(); + } + + Streams.pipeAll(serverProtocol.getInputStream(), serverProtocol.getOutputStream()); + } + catch (IOException ignored) + { + if (!shouldFail) + { + fail(); + } + } + + serverProtocol.close(); + } + catch (Exception e) + { + } + } + } +} diff --git a/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKemTest.java b/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKemTest.java index 2f0d8dc9d5..366008cc1d 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKemTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKemTest.java @@ -7,17 +7,26 @@ import org.bouncycastle.tls.NamedGroup; import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsServer; import org.bouncycastle.tls.TlsServerProtocol; +import org.bouncycastle.tls.crypto.TlsCrypto; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.io.Streams; import junit.framework.TestCase; -public class TlsProtocolKemTest +public abstract class TlsProtocolKemTest extends TestCase { - // mismatched ML-KEM strengths w/o classical crypto - public void testMismatchStrength() throws Exception + protected final TlsCrypto crypto; + + protected TlsProtocolKemTest(TlsCrypto crypto) + { + this.crypto = crypto; + } + + // mismatched ML-KEM groups w/o classical crypto + public void testMismatchedGroups() throws Exception { PipedInputStream clientRead = TlsTestUtils.createPipedInputStream(); PipedInputStream serverRead = TlsTestUtils.createPipedInputStream(); @@ -27,7 +36,13 @@ public void testMismatchStrength() throws Exception TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite); TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite); - ServerThread serverThread = new ServerThread(serverProtocol, new int[]{ NamedGroup.MLKEM768 }, true); + MockTlsKemClient client = new MockTlsKemClient(crypto, null); + MockTlsKemServer server = new MockTlsKemServer(crypto); + + client.setNamedGroups(new int[]{ NamedGroup.MLKEM512 }); + server.setNamedGroups(new int[]{ NamedGroup.MLKEM768 }); + + ServerThread serverThread = new ServerThread(serverProtocol, server, true); try { serverThread.start(); @@ -35,8 +50,7 @@ public void testMismatchStrength() throws Exception catch (Exception ignored) { } - MockTlsKemClient client = new MockTlsKemClient(null); - client.setNamedGroups(new int[]{ NamedGroup.MLKEM512 }); + try { clientProtocol.connect(client); @@ -49,7 +63,22 @@ public void testMismatchStrength() throws Exception serverThread.join(); } - public void testClientServer() throws Exception + public void testMLKEM512() throws Exception + { + implTestClientServer(NamedGroup.MLKEM512); + } + + public void testMLKEM768() throws Exception + { + implTestClientServer(NamedGroup.MLKEM768); + } + + public void testMLKEM1024() throws Exception + { + implTestClientServer(NamedGroup.MLKEM1024); + } + + private void implTestClientServer(int kemGroup) throws Exception { PipedInputStream clientRead = TlsTestUtils.createPipedInputStream(); PipedInputStream serverRead = TlsTestUtils.createPipedInputStream(); @@ -59,10 +88,15 @@ public void testClientServer() throws Exception TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite); TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite); - ServerThread serverThread = new ServerThread(serverProtocol, null, false); + MockTlsKemClient client = new MockTlsKemClient(crypto, null); + MockTlsKemServer server = new MockTlsKemServer(crypto); + + client.setNamedGroups(new int[]{ kemGroup }); + server.setNamedGroups(new int[]{ kemGroup }); + + ServerThread serverThread = new ServerThread(serverProtocol, server, false); serverThread.start(); - MockTlsKemClient client = new MockTlsKemClient(null); clientProtocol.connect(client); // NOTE: Because we write-all before we read-any, this length can't be more than the pipe capacity @@ -89,13 +123,13 @@ static class ServerThread extends Thread { private final TlsServerProtocol serverProtocol; - private final int[] namedGroups; - private boolean shouldFail = false; + private final TlsServer server; + private final boolean shouldFail; - ServerThread(TlsServerProtocol serverProtocol, int[] namedGroups, boolean shouldFail) + ServerThread(TlsServerProtocol serverProtocol, TlsServer server, boolean shouldFail) { this.serverProtocol = serverProtocol; - this.namedGroups = namedGroups; + this.server = server; this.shouldFail = shouldFail; } @@ -103,12 +137,6 @@ public void run() { try { - MockTlsKemServer server = new MockTlsKemServer(); - if (namedGroups != null) - { - server.setNamedGroups(namedGroups); - } - try { serverProtocol.accept(server); @@ -116,6 +144,8 @@ public void run() { fail(); } + + Streams.pipeAll(serverProtocol.getInputStream(), serverProtocol.getOutputStream()); } catch (IOException ignored) { @@ -125,12 +155,10 @@ public void run() } } - Streams.pipeAll(serverProtocol.getInputStream(), serverProtocol.getOutputStream()); serverProtocol.close(); } catch (Exception e) { -// throw new RuntimeException(e); } } } diff --git a/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolTest.java b/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolTest.java index ad8c87426c..f7d884df49 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolTest.java @@ -5,6 +5,7 @@ import java.io.PipedOutputStream; import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsServer; import org.bouncycastle.tls.TlsServerProtocol; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.io.Streams; @@ -24,10 +25,12 @@ public void testClientServer() throws Exception TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite); TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite); - ServerThread serverThread = new ServerThread(serverProtocol); + MockTlsClient client = new MockTlsClient(null); + MockTlsServer server = new MockTlsServer(); + + ServerThread serverThread = new ServerThread(serverProtocol, server); serverThread.start(); - MockTlsClient client = new MockTlsClient(null); clientProtocol.connect(client); // NOTE: Because we write-all before we read-any, this length can't be more than the pipe capacity @@ -54,17 +57,18 @@ static class ServerThread extends Thread { private final TlsServerProtocol serverProtocol; + private final TlsServer server; - ServerThread(TlsServerProtocol serverProtocol) + ServerThread(TlsServerProtocol serverProtocol, TlsServer server) { this.serverProtocol = serverProtocol; + this.server = server; } public void run() { try { - MockTlsServer server = new MockTlsServer(); serverProtocol.accept(server); Streams.pipeAll(serverProtocol.getInputStream(), serverProtocol.getOutputStream()); serverProtocol.close(); diff --git a/tls/src/test/java/org/bouncycastle/tls/test/TlsSRPProtocolTest.java b/tls/src/test/java/org/bouncycastle/tls/test/TlsSRPProtocolTest.java index 373f862d50..d280335c12 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/TlsSRPProtocolTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/TlsSRPProtocolTest.java @@ -5,6 +5,7 @@ import java.io.PipedOutputStream; import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsServer; import org.bouncycastle.tls.TlsServerProtocol; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.io.Streams; @@ -24,10 +25,12 @@ public void testClientServer() throws Exception TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite); TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite); - ServerThread serverThread = new ServerThread(serverProtocol); + MockSRPTlsClient client = new MockSRPTlsClient(null, MockSRPTlsServer.TEST_SRP_IDENTITY); + MockSRPTlsServer server = new MockSRPTlsServer(); + + ServerThread serverThread = new ServerThread(serverProtocol, server); serverThread.start(); - MockSRPTlsClient client = new MockSRPTlsClient(null, MockSRPTlsServer.TEST_SRP_IDENTITY); clientProtocol.connect(client); // NOTE: Because we write-all before we read-any, this length can't be more than the pipe capacity @@ -54,17 +57,18 @@ static class ServerThread extends Thread { private final TlsServerProtocol serverProtocol; + private final TlsServer server; - ServerThread(TlsServerProtocol serverProtocol) + ServerThread(TlsServerProtocol serverProtocol, TlsServer server) { this.serverProtocol = serverProtocol; + this.server = server; } public void run() { try { - MockSRPTlsServer server = new MockSRPTlsServer(); serverProtocol.accept(server); Streams.pipeAll(serverProtocol.getInputStream(), serverProtocol.getOutputStream()); serverProtocol.close(); diff --git a/tls/src/test/java/org/bouncycastle/tls/test/TlsTestClientImpl.java b/tls/src/test/java/org/bouncycastle/tls/test/TlsTestClientImpl.java index 13a6882a14..d00fc08ecd 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/TlsTestClientImpl.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/TlsTestClientImpl.java @@ -21,6 +21,7 @@ import org.bouncycastle.tls.ClientCertificateType; import org.bouncycastle.tls.ConnectionEnd; import org.bouncycastle.tls.DefaultTlsClient; +import org.bouncycastle.tls.NamedGroup; import org.bouncycastle.tls.ProtocolVersion; import org.bouncycastle.tls.SecurityParameters; import org.bouncycastle.tls.SignatureAlgorithm; @@ -201,6 +202,12 @@ public void notifyHandshakeComplete() throws IOException if (TlsTestConfig.DEBUG) { + int negotiatedGroup = securityParameters.getNegotiatedGroup(); + if (negotiatedGroup >= 0) + { + System.out.println("TLS client negotiated group: " + NamedGroup.getText(negotiatedGroup)); + } + System.out.println("TLS client reports 'tls-server-end-point' = " + hex(tlsServerEndPoint)); System.out.println("TLS client reports 'tls-unique' = " + hex(tlsUnique)); } @@ -214,7 +221,7 @@ public void notifyServerVersion(ProtocolVersion serverVersion) throws IOExceptio if (TlsTestConfig.DEBUG) { - System.out.println("TLS client negotiated " + serverVersion); + System.out.println("TLS client negotiated version " + serverVersion); } } @@ -250,6 +257,7 @@ public void notifyServerCertificate(TlsServerCertificate serverCertificate) String[] trustedCertResources = new String[]{ "x509-server-dsa.pem", "x509-server-ecdh.pem", "x509-server-ecdsa.pem", "x509-server-ed25519.pem", "x509-server-ed448.pem", + "x509-server-ml_dsa_44.pem", "x509-server-ml_dsa_65.pem", "x509-server-ml_dsa_87.pem", "x509-server-rsa_pss_256.pem", "x509-server-rsa_pss_384.pem", "x509-server-rsa_pss_512.pem", "x509-server-rsa-enc.pem", "x509-server-rsa-sign.pem" }; diff --git a/tls/src/test/java/org/bouncycastle/tls/test/TlsTestServerImpl.java b/tls/src/test/java/org/bouncycastle/tls/test/TlsTestServerImpl.java index b68a665a6f..4b9c418808 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/TlsTestServerImpl.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/TlsTestServerImpl.java @@ -15,6 +15,7 @@ import org.bouncycastle.tls.ClientCertificateType; import org.bouncycastle.tls.ConnectionEnd; import org.bouncycastle.tls.DefaultTlsServer; +import org.bouncycastle.tls.NamedGroup; import org.bouncycastle.tls.ProtocolVersion; import org.bouncycastle.tls.SecurityParameters; import org.bouncycastle.tls.SignatureAlgorithm; @@ -160,6 +161,12 @@ public void notifyHandshakeComplete() throws IOException if (TlsTestConfig.DEBUG) { + int negotiatedGroup = securityParameters.getNegotiatedGroup(); + if (negotiatedGroup >= 0) + { + System.out.println("TLS server negotiated group: " + NamedGroup.getText(negotiatedGroup)); + } + System.out.println("TLS server reports 'tls-server-end-point' = " + hex(tlsServerEndPoint)); System.out.println("TLS server reports 'tls-unique' = " + hex(tlsUnique)); } @@ -173,7 +180,7 @@ public ProtocolVersion getServerVersion() throws IOException if (TlsTestConfig.DEBUG) { - System.out.println("TLS server negotiated " + serverVersion); + System.out.println("TLS server negotiated version " + serverVersion); } return serverVersion; @@ -262,7 +269,8 @@ public void notifyClientCertificate(org.bouncycastle.tls.Certificate clientCerti } String[] trustedCertResources = new String[]{ "x509-client-dsa.pem", "x509-client-ecdh.pem", - "x509-client-ecdsa.pem", "x509-client-ed25519.pem", "x509-client-ed448.pem", "x509-client-rsa_pss_256.pem", + "x509-client-ecdsa.pem", "x509-client-ed25519.pem", "x509-client-ed448.pem", "x509-client-ml_dsa_44.pem", + "x509-client-ml_dsa_65.pem", "x509-client-ml_dsa_87.pem", "x509-client-rsa_pss_256.pem", "x509-client-rsa_pss_384.pem", "x509-client-rsa_pss_512.pem", "x509-client-rsa.pem" }; TlsCertificate[] certPath = TlsTestUtils.getTrustedCertPath(context.getCrypto(), chain[0], diff --git a/tls/src/test/java/org/bouncycastle/tls/test/TlsTestUtils.java b/tls/src/test/java/org/bouncycastle/tls/test/TlsTestUtils.java index 918983da2a..0052100a51 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/TlsTestUtils.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/TlsTestUtils.java @@ -29,17 +29,22 @@ import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; import org.bouncycastle.crypto.util.PrivateKeyFactory; +import org.bouncycastle.test.TestResourceFinder; import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.BasicTlsPSKIdentity; import org.bouncycastle.tls.Certificate; import org.bouncycastle.tls.CertificateEntry; import org.bouncycastle.tls.ProtocolVersion; import org.bouncycastle.tls.SignatureAlgorithm; import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.SignatureScheme; import org.bouncycastle.tls.TlsContext; import org.bouncycastle.tls.TlsCredentialedAgreement; import org.bouncycastle.tls.TlsCredentialedDecryptor; import org.bouncycastle.tls.TlsCredentialedSigner; import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsPSKIdentity; +import org.bouncycastle.tls.TlsServerCertificate; import org.bouncycastle.tls.TlsUtils; import org.bouncycastle.tls.crypto.TlsCertificate; import org.bouncycastle.tls.crypto.TlsCrypto; @@ -53,6 +58,7 @@ import org.bouncycastle.tls.crypto.impl.jcajce.JceDefaultTlsCredentialedAgreement; import org.bouncycastle.tls.crypto.impl.jcajce.JceDefaultTlsCredentialedDecryptor; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.io.pem.PemObject; @@ -82,6 +88,11 @@ public class TlsTestUtils + "0lAQH/BAgwBgYEVR0lADAcBgNVHREBAf8EEjAQgQ50ZXN0QHRlc3QudGVzdDANBgkqhkiG9w0BAQQFAANBAJg55PBS" + "weg6obRUKF4FF6fCrWFi6oCYSQ99LWcAeupc5BofW5MstFMhCOaEucuGVqunwT5G7/DweazzCIrSzB0="); + static TlsPSKIdentity createDefaultPSKIdentity(boolean badKey) + { + return new BasicTlsPSKIdentity("client", getPSKPasswordUTF8(badKey)); + } + static String fingerprint(org.bouncycastle.asn1.x509.Certificate c) throws IOException { @@ -143,17 +154,87 @@ static String getCACertResource(String eeCertResource) throws IOException if ("ed25519".equalsIgnoreCase(eeCertResource)) { - return getCACertResource(SignatureAlgorithm.ed25519); + return getCACertResource13(SignatureScheme.ed25519); } - if ("ed448".equalsIgnoreCase(eeCertResource)) { - return getCACertResource(SignatureAlgorithm.ed448); + return getCACertResource13(SignatureScheme.ed448); + } + + if (eeCertResource.startsWith("ml_dsa_")) + { + if ("ml_dsa_44".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.mldsa44); + } + if ("ml_dsa_65".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.mldsa65); + } + if ("ml_dsa_87".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.mldsa87); + } + } + + if (eeCertResource.startsWith("slh_dsa_sha2_")) + { + if ("slh_dsa_sha2_128s".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.DRAFT_slhdsa_sha2_128s); + } + if ("slh_dsa_sha2_128f".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.DRAFT_slhdsa_sha2_128f); + } + if ("slh_dsa_sha2_192s".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.DRAFT_slhdsa_sha2_192s); + } + if ("slh_dsa_sha2_192f".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.DRAFT_slhdsa_sha2_192f); + } + if ("slh_dsa_sha2_256s".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.DRAFT_slhdsa_sha2_256s); + } + if ("slh_dsa_sha2_256f".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.DRAFT_slhdsa_sha2_256f); + } + } + if (eeCertResource.startsWith("slh_dsa_shake_")) + { + if ("slh_dsa_shake_128s".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.DRAFT_slhdsa_shake_128s); + } + if ("slh_dsa_shake_128f".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.DRAFT_slhdsa_shake_128f); + } + if ("slh_dsa_shake_192s".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.DRAFT_slhdsa_shake_192s); + } + if ("slh_dsa_shake_192f".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.DRAFT_slhdsa_shake_192f); + } + if ("slh_dsa_shake_256s".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.DRAFT_slhdsa_shake_256s); + } + if ("slh_dsa_shake_256f".equalsIgnoreCase(eeCertResource)) + { + return getCACertResource13(SignatureScheme.DRAFT_slhdsa_shake_256f); + } } - if ("rsa".equalsIgnoreCase(eeCertResource) - || "rsa-enc".equalsIgnoreCase(eeCertResource) - || "rsa-sign".equalsIgnoreCase(eeCertResource)) + if ("rsa".equalsIgnoreCase(eeCertResource) || + "rsa-enc".equalsIgnoreCase(eeCertResource) || + "rsa-sign".equalsIgnoreCase(eeCertResource)) { return getCACertResource(SignatureAlgorithm.rsa); } @@ -174,6 +255,21 @@ static String getCACertResource(String eeCertResource) throws IOException throw new TlsFatalAlert(AlertDescription.internal_error); } + static String getCACertResource13(int signatureScheme) throws IOException + { + return "x509-ca-" + getResourceName13(signatureScheme) + ".pem"; + } + + static String getPSKPassword(boolean badKey) + { + return badKey ? "TLS_TEST_PSK_BAD" : "TLS_TEST_PSK"; + } + + static byte[] getPSKPasswordUTF8(boolean badKey) + { + return Strings.toUTF8ByteArray(getPSKPassword(badKey)); + } + static String getResourceName(short signatureAlgorithm) throws IOException { switch (signatureAlgorithm) @@ -207,6 +303,49 @@ static String getResourceName(short signatureAlgorithm) throws IOException } } + static String getResourceName13(int signatureScheme) throws IOException + { + switch (signatureScheme) + { + case SignatureScheme.ed25519: + return "ed25519"; + case SignatureScheme.ed448: + return "ed448"; + case SignatureScheme.mldsa44: + return "ml_dsa_44"; + case SignatureScheme.mldsa65: + return "ml_dsa_65"; + case SignatureScheme.mldsa87: + return "ml_dsa_87"; + case SignatureScheme.DRAFT_slhdsa_sha2_128s: + return "slh_dsa_sha2_128s"; + case SignatureScheme.DRAFT_slhdsa_sha2_128f: + return "slh_dsa_sha2_128f"; + case SignatureScheme.DRAFT_slhdsa_sha2_192s: + return "slh_dsa_sha2_192s"; + case SignatureScheme.DRAFT_slhdsa_sha2_192f: + return "slh_dsa_sha2_192f"; + case SignatureScheme.DRAFT_slhdsa_sha2_256s: + return "slh_dsa_sha2_256s"; + case SignatureScheme.DRAFT_slhdsa_sha2_256f: + return "slh_dsa_sha2_256f"; + case SignatureScheme.DRAFT_slhdsa_shake_128s: + return "slh_dsa_shake_128s"; + case SignatureScheme.DRAFT_slhdsa_shake_128f: + return "slh_dsa_shake_128f"; + case SignatureScheme.DRAFT_slhdsa_shake_192s: + return "slh_dsa_shake_192s"; + case SignatureScheme.DRAFT_slhdsa_shake_192f: + return "slh_dsa_shake_192f"; + case SignatureScheme.DRAFT_slhdsa_shake_256s: + return "slh_dsa_shake_256s"; + case SignatureScheme.DRAFT_slhdsa_shake_256f: + return "slh_dsa_shake_256f"; + default: + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + static TlsCredentialedAgreement loadAgreementCredentials(TlsContext context, String[] certResources, String keyResource) throws IOException { @@ -398,7 +537,16 @@ static AsymmetricKeyParameter loadBcPrivateKeyResource(String resource) PemObject pem = loadPemResource(resource); if (pem.getType().equals("PRIVATE KEY")) { - return PrivateKeyFactory.createKey(pem.getContent()); + AsymmetricKeyParameter kp; + try + { + kp = PrivateKeyFactory.createKey(pem.getContent()); + } + catch (Exception e) + { + kp = org.bouncycastle.pqc.crypto.util.PrivateKeyFactory.createKey(pem.getContent()); + } + return kp; } if (pem.getType().equals("ENCRYPTED PRIVATE KEY")) { @@ -493,7 +641,7 @@ else if (EdECObjectIdentifiers.id_Ed448.equals(oid)) static PemObject loadPemResource(String resource) throws IOException { - InputStream s = TlsTestUtils.class.getResourceAsStream(resource); + InputStream s = TestResourceFinder.findTestResource("tls/credentials", resource); PemReader p = new PemReader(new InputStreamReader(s)); PemObject o = p.readPemObject(); p.close(); diff --git a/tls/src/test/jdk1.4/org/bouncycastle/tls/test/TlsTestUtils.java b/tls/src/test/jdk1.4/org/bouncycastle/tls/test/TlsTestUtils.java index 761a06d9b0..e171c65f96 100644 --- a/tls/src/test/jdk1.4/org/bouncycastle/tls/test/TlsTestUtils.java +++ b/tls/src/test/jdk1.4/org/bouncycastle/tls/test/TlsTestUtils.java @@ -29,17 +29,22 @@ import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; import org.bouncycastle.crypto.util.PrivateKeyFactory; +import org.bouncycastle.test.TestResourceFinder; import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.BasicTlsPSKIdentity; import org.bouncycastle.tls.Certificate; import org.bouncycastle.tls.CertificateEntry; import org.bouncycastle.tls.ProtocolVersion; import org.bouncycastle.tls.SignatureAlgorithm; import org.bouncycastle.tls.SignatureAndHashAlgorithm; +import org.bouncycastle.tls.SignatureScheme; import org.bouncycastle.tls.TlsContext; import org.bouncycastle.tls.TlsCredentialedAgreement; import org.bouncycastle.tls.TlsCredentialedDecryptor; import org.bouncycastle.tls.TlsCredentialedSigner; import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsPSKIdentity; +import org.bouncycastle.tls.TlsServerCertificate; import org.bouncycastle.tls.TlsUtils; import org.bouncycastle.tls.crypto.TlsCertificate; import org.bouncycastle.tls.crypto.TlsCrypto; @@ -53,6 +58,7 @@ import org.bouncycastle.tls.crypto.impl.jcajce.JceDefaultTlsCredentialedAgreement; import org.bouncycastle.tls.crypto.impl.jcajce.JceDefaultTlsCredentialedDecryptor; import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; import org.bouncycastle.util.io.pem.PemObject; @@ -82,6 +88,11 @@ public class TlsTestUtils + "0lAQH/BAgwBgYEVR0lADAcBgNVHREBAf8EEjAQgQ50ZXN0QHRlc3QudGVzdDANBgkqhkiG9w0BAQQFAANBAJg55PBS" + "weg6obRUKF4FF6fCrWFi6oCYSQ99LWcAeupc5BofW5MstFMhCOaEucuGVqunwT5G7/DweazzCIrSzB0="); + static TlsPSKIdentity createDefaultPSKIdentity(boolean badKey) + { + return new BasicTlsPSKIdentity("client", getPSKPasswordUTF8(badKey)); + } + static String fingerprint(org.bouncycastle.asn1.x509.Certificate c) throws IOException { @@ -174,6 +185,16 @@ static String getCACertResource(String eeCertResource) throws IOException throw new TlsFatalAlert(AlertDescription.internal_error); } + static String getPSKPassword(boolean badKey) + { + return badKey ? "TLS_TEST_PSK_BAD" : "TLS_TEST_PSK"; + } + + static byte[] getPSKPasswordUTF8(boolean badKey) + { + return Strings.toUTF8ByteArray(getPSKPassword(badKey)); + } + static String getResourceName(short signatureAlgorithm) throws IOException { switch (signatureAlgorithm) @@ -488,7 +509,7 @@ else if (EdECObjectIdentifiers.id_Ed448.equals(oid)) static PemObject loadPemResource(String resource) throws IOException { - InputStream s = TlsTestUtils.class.getResourceAsStream(resource); + InputStream s = TestResourceFinder.findTestResource("tls/credentials", resource); PemReader p = new PemReader(new InputStreamReader(s)); PemObject o = p.readPemObject(); p.close(); diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/README.txt b/tls/src/test/resources/org/bouncycastle/tls/test/README.txt deleted file mode 100755 index 538325645f..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/README.txt +++ /dev/null @@ -1,181 +0,0 @@ -# The key and certificate .pem files here were generated using GnuTLS certtool and the accompanying -# template files. (Note that the ed25519 files needed GnuTLS 3.6+, 3.6.12+ for ed448) - -# CA (signing) credentials: - - certtool --generate-privkey --outfile x509-ca-key-dsa.pem \ - --pkcs8 --password '' --dsa --bits 2048 - certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-dsa.pem \ - --load-privkey x509-ca-key-dsa.pem --hash sha256 - - certtool --generate-privkey --outfile x509-ca-key-ecdsa.pem \ - --pkcs8 --password '' --ecdsa --curve secp256r1 - certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-ecdsa.pem \ - --load-privkey x509-ca-key-ecdsa.pem --hash sha256 - - certtool --generate-privkey --outfile x509-ca-key-ed25519.pem \ - --pkcs8 --password '' --key-type=ed25519 - certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-ed25519.pem \ - --load-privkey x509-ca-key-ed25519.pem - - certtool --generate-privkey --outfile x509-ca-key-ed448.pem \ - --pkcs8 --password '' --key-type=ed448 - certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-ed448.pem \ - --load-privkey x509-ca-key-ed448.pem - - certtool --generate-privkey --outfile x509-ca-key-rsa.pem \ - --pkcs8 --password '' --rsa --bits 2048 - certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-rsa.pem \ - --load-privkey x509-ca-key-rsa.pem --hash sha256 - - certtool --generate-privkey --outfile x509-ca-key-rsa_pss_256.pem \ - --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha256 --salt-size=32 - certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-rsa_pss_256.pem \ - --load-privkey x509-ca-key-rsa_pss_256.pem - - certtool --generate-privkey --outfile x509-ca-key-rsa_pss_384.pem \ - --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha384 --salt-size=48 - certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-rsa_pss_384.pem \ - --load-privkey x509-ca-key-rsa_pss_384.pem - - certtool --generate-privkey --outfile x509-ca-key-rsa_pss_512.pem \ - --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha512 --salt-size=64 - certtool --generate-self-signed --template ca.tmpl --outfile x509-ca-rsa_pss_512.pem \ - --load-privkey x509-ca-key-rsa_pss_512.pem - -# Client agreement credentials: - - certtool --generate-privkey --outfile x509-client-key-ecdh.pem \ - --pkcs8 --password '' --ecc --curve secp256r1 - certtool --generate-certificate --template client_agree.tmpl --outfile x509-client-ecdh.pem \ - --load-privkey x509-client-key-ecdh.pem --hash sha256 \ - --load-ca-privkey x509-ca-key-ecdsa.pem --load-ca-certificate x509-ca-ecdsa.pem - -# Client signing credentials: - - certtool --generate-privkey --outfile x509-client-key-dsa.pem \ - --pkcs8 --password '' --dsa --bits 2048 - certtool --generate-certificate --template client_sign.tmpl --outfile x509-client-dsa.pem \ - --load-privkey x509-client-key-dsa.pem --hash sha256 \ - --load-ca-privkey x509-ca-key-dsa.pem --load-ca-certificate x509-ca-dsa.pem - - certtool --generate-privkey --outfile x509-client-key-ecdsa.pem \ - --pkcs8 --password '' --ecdsa --curve secp256r1 - certtool --generate-certificate --template client_sign.tmpl --outfile x509-client-ecdsa.pem \ - --load-privkey x509-client-key-ecdsa.pem --hash sha256 \ - --load-ca-privkey x509-ca-key-ecdsa.pem --load-ca-certificate x509-ca-ecdsa.pem - - certtool --generate-privkey --outfile x509-client-key-ed25519.pem \ - --pkcs8 --password '' --key-type=ed25519 - certtool --generate-certificate --template client_sign.tmpl --outfile x509-client-ed25519.pem \ - --load-privkey x509-client-key-ed25519.pem \ - --load-ca-privkey x509-ca-key-ed25519.pem --load-ca-certificate x509-ca-ed25519.pem - - certtool --generate-privkey --outfile x509-client-key-ed448.pem \ - --pkcs8 --password '' --key-type=ed448 - certtool --generate-certificate --template client_sign.tmpl --outfile x509-client-ed448.pem \ - --load-privkey x509-client-key-ed448.pem \ - --load-ca-privkey x509-ca-key-ed448.pem --load-ca-certificate x509-ca-ed448.pem - - certtool --generate-privkey --outfile x509-client-key-rsa.pem \ - --pkcs8 --password '' --rsa --bits 2048 - certtool --generate-certificate --template client_sign.tmpl --outfile x509-client-rsa.pem \ - --load-privkey x509-client-key-rsa.pem --hash sha256 \ - --load-ca-privkey x509-ca-key-rsa.pem --load-ca-certificate x509-ca-rsa.pem - - certtool --generate-privkey --outfile x509-client-key-rsa_pss_256.pem \ - --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha256 --salt-size=32 - certtool --generate-certificate --template client_sign.tmpl \ - --outfile x509-client-rsa_pss_256.pem \ - --load-privkey x509-client-key-rsa_pss_256.pem \ - --load-ca-privkey x509-ca-key-rsa_pss_256.pem \ - --load-ca-certificate x509-ca-rsa_pss_256.pem - - certtool --generate-privkey --outfile x509-client-key-rsa_pss_384.pem \ - --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha384 --salt-size=48 - certtool --generate-certificate --template client_sign.tmpl \ - --outfile x509-client-rsa_pss_384.pem \ - --load-privkey x509-client-key-rsa_pss_384.pem \ - --load-ca-privkey x509-ca-key-rsa_pss_384.pem \ - --load-ca-certificate x509-ca-rsa_pss_384.pem - - certtool --generate-privkey --outfile x509-client-key-rsa_pss_512.pem \ - --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha512 --salt-size=64 - certtool --generate-certificate --template client_sign.tmpl \ - --outfile x509-client-rsa_pss_512.pem \ - --load-privkey x509-client-key-rsa_pss_512.pem \ - --load-ca-privkey x509-ca-key-rsa_pss_512.pem \ - --load-ca-certificate x509-ca-rsa_pss_512.pem - -# Server agreement credentials: - - certtool --generate-privkey --outfile x509-server-key-ecdh.pem \ - --pkcs8 --password '' --ecc --curve secp256r1 - certtool --generate-certificate --template server_agree.tmpl --outfile x509-server-ecdh.pem \ - --load-privkey x509-server-key-ecdh.pem --hash sha256 \ - --load-ca-privkey x509-ca-key-ecdsa.pem --load-ca-certificate x509-ca-ecdsa.pem - -# Server encryption credentials: - - certtool --generate-privkey --outfile x509-server-key-rsa-enc.pem \ - --pkcs8 --password '' --rsa --bits 2048 - certtool --generate-certificate --outfile x509-server-rsa-enc.pem \ - --load-privkey x509-server-key-rsa-enc.pem --template server_enc.tmpl \ - --load-ca-privkey x509-ca-key-rsa.pem --load-ca-certificate x509-ca-rsa.pem \ - --hash sha256 - -# Server signing credentials: - - certtool --generate-privkey --outfile x509-server-key-dsa.pem \ - --pkcs8 --password '' --dsa --bits 2048 - certtool --generate-certificate --template server_sign.tmpl --outfile x509-server-dsa.pem \ - --load-privkey x509-server-key-dsa.pem --hash sha256 \ - --load-ca-privkey x509-ca-key-dsa.pem --load-ca-certificate x509-ca-dsa.pem - - certtool --generate-privkey --outfile x509-server-key-ecdsa.pem \ - --pkcs8 --password '' --ecdsa --curve secp256r1 - certtool --generate-certificate --template server_sign.tmpl --outfile x509-server-ecdsa.pem \ - --load-privkey x509-server-key-ecdsa.pem --hash sha256 \ - --load-ca-privkey x509-ca-key-ecdsa.pem --load-ca-certificate x509-ca-ecdsa.pem - - certtool --generate-privkey --outfile x509-server-key-ed25519.pem \ - --pkcs8 --password '' --key-type=ed25519 - certtool --generate-certificate --template server_sign.tmpl --outfile x509-server-ed25519.pem \ - --load-privkey x509-server-key-ed25519.pem \ - --load-ca-privkey x509-ca-key-ed25519.pem --load-ca-certificate x509-ca-ed25519.pem - - certtool --generate-privkey --outfile x509-server-key-ed448.pem \ - --pkcs8 --password '' --key-type=ed448 - certtool --generate-certificate --template server_sign.tmpl --outfile x509-server-ed448.pem \ - --load-privkey x509-server-key-ed448.pem \ - --load-ca-privkey x509-ca-key-ed448.pem --load-ca-certificate x509-ca-ed448.pem - - certtool --generate-privkey --outfile x509-server-key-rsa-sign.pem \ - --pkcs8 --password '' --rsa --bits 2048 - certtool --generate-certificate --template server_sign.tmpl --outfile x509-server-rsa-sign.pem \ - --load-privkey x509-server-key-rsa-sign.pem --hash sha256 \ - --load-ca-privkey x509-ca-key-rsa.pem --load-ca-certificate x509-ca-rsa.pem - - certtool --generate-privkey --outfile x509-server-key-rsa_pss_256.pem \ - --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha256 --salt-size=32 - certtool --generate-certificate --template server_sign.tmpl \ - --outfile x509-server-rsa_pss_256.pem \ - --load-privkey x509-server-key-rsa_pss_256.pem \ - --load-ca-privkey x509-ca-key-rsa_pss_256.pem \ - --load-ca-certificate x509-ca-rsa_pss_256.pem - - certtool --generate-privkey --outfile x509-server-key-rsa_pss_384.pem \ - --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha384 --salt-size=48 - certtool --generate-certificate --template server_sign.tmpl \ - --outfile x509-server-rsa_pss_384.pem \ - --load-privkey x509-server-key-rsa_pss_384.pem \ - --load-ca-privkey x509-ca-key-rsa_pss_384.pem \ - --load-ca-certificate x509-ca-rsa_pss_384.pem - - certtool --generate-privkey --outfile x509-server-key-rsa_pss_512.pem \ - --pkcs8 --password '' --key-type='rsa-pss' --bits=2048 --hash=sha512 --salt-size=64 - certtool --generate-certificate --template server_sign.tmpl \ - --outfile x509-server-rsa_pss_512.pem \ - --load-privkey x509-server-key-rsa_pss_512.pem \ - --load-ca-privkey x509-ca-key-rsa_pss_512.pem \ - --load-ca-certificate x509-ca-rsa_pss_512.pem diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/ca.tmpl b/tls/src/test/resources/org/bouncycastle/tls/test/ca.tmpl deleted file mode 100644 index 72e41e69ee..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/ca.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -cn = BouncyCastle TLS Test CA -ca -cert_signing_key -expiration_days = 7301 diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/client_agree.tmpl b/tls/src/test/resources/org/bouncycastle/tls/test/client_agree.tmpl deleted file mode 100644 index 1718041888..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/client_agree.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -cn = BouncyCastle Test Client -tls_www_client -key_agreement -expiration_days = 7300 diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/client_enc.tmpl b/tls/src/test/resources/org/bouncycastle/tls/test/client_enc.tmpl deleted file mode 100644 index 1a6f2efd8d..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/client_enc.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -cn = BouncyCastle Test Client -tls_www_client -encryption_key -expiration_days = 7300 diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/client_sign.tmpl b/tls/src/test/resources/org/bouncycastle/tls/test/client_sign.tmpl deleted file mode 100644 index 5a320b1113..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/client_sign.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -cn = BouncyCastle Test Client -tls_www_client -signing_key -expiration_days = 7300 diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/server_agree.tmpl b/tls/src/test/resources/org/bouncycastle/tls/test/server_agree.tmpl deleted file mode 100644 index 44f12f6509..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/server_agree.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -cn = BouncyCastle Test Server -tls_www_server -key_agreement -expiration_days = 7300 diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/server_enc.tmpl b/tls/src/test/resources/org/bouncycastle/tls/test/server_enc.tmpl deleted file mode 100644 index 4bfc58e073..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/server_enc.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -cn = BouncyCastle Test Server -tls_www_server -encryption_key -expiration_days = 7300 diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/server_sign.tmpl b/tls/src/test/resources/org/bouncycastle/tls/test/server_sign.tmpl deleted file mode 100644 index 1d12addabc..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/server_sign.tmpl +++ /dev/null @@ -1,4 +0,0 @@ -cn = BouncyCastle Test Server -tls_www_server -signing_key -expiration_days = 7300 diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-dsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-dsa.pem deleted file mode 100644 index d9cb013a2a..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-dsa.pem +++ /dev/null @@ -1,26 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEdDCCBBqgAwIBAgIMWYGU7zZX3YAzRZ8VMAsGCWCGSAFlAwQDAjAjMSEwHwYD -VQQDExhCb3VuY3lDYXN0bGUgVExTIFRlc3QgQ0EwHhcNMTcwODAyMDkwMTM1WhcN -MzcwNzI5MDkwMTM1WjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVExTIFRlc3Qg -Q0EwggNHMIICOQYHKoZIzjgEATCCAiwCggEBAO5dNk+YfyPOeIK54F9Wg6Zl5+cu -80tSk1fZBSQE1nFBblnGifl39LTmwkHL7XNZmUUFtrScY7Qlk0/cRsEqsl647fAy -XNhqpZAOMPJs4NBx6nzQvKlprxU9JYO5kvTIoJNBR4GCUDxX/DWLffFqvwbBmrZ3 -BgNAHhAHj/wDm0sfxKDXHgfUwmVJgBOne7xwh86SJJojw+MN33ILuSfNFePv2AeQ -kw+bY93tPpouyfskyBLdWs7DeGXmjftFSmpS68j36RAL0+4QZVwDyX/aIwK1bxAH -XLgRnono7NfGxzqlPiQXfb5ewUmZPyjJ3P06WMU3kgj6ZMoyfmJOHCSwjAECIQCg -NiET6OM1ljsc4tvOXtDSyXXqQ4YtRT5o41Gal8kv+QKCAQAbvM2Az1+PzOhrySA5 -PATwWWDMIXlxFx3U1gXIczu4lGGRaoVzfmSGsDZ6A/0j+/ZtmpjGH3B+jb0Rab0n -yZBDUzK+39w+YI7s+K6yGkKlSuyhpB/UokDP0h5Pf6MEVAU2bIcuuWTLMJmleWLw -zHKJTjUDnrC6txeVAbsW+O4l04jMHLTZMXg2OTk9urUtJzeJNkEEMNA8sv7h+yrA -oX2FqvhfDg/oLdfwXQULkKJc/ec6IQaXrtHm+oYwDQxsr9ap4FlET1nz91MMAXon -hB2Yfl7dRKJtKMUKGWGbCliTnJAPUHI1URltnEg387G/YbnnEBUnZlNBJeDrpZFg -+v2ZA4IBBgACggEBAJQi1dv4plwRKrP2fU/76FLcx++60cA4oajNm0f4Vyyaz2xF -7hPiFNj2H0nLNJAtPtdn/wC7KHNWmDx0OiUFIseAqPPoQvfaSrFun1F2iUJhlrKU -FOJ3RC2URoD+M7IbR1SXAyuWOVenhoYyky1mausApUhUjoLO3mMOyBDdXMGWMq7p -SHfyziAnySzwZ2bwOrVz4XL41w4cPbjdEzd4MLIfpPaqqW43y4MNlgLLspm9vBO5 -6Fbq9c0bDUa18jkSi7DU7uH43S9tq3HrPQh127XZ5SstNPU2uV0o+ZXAS8V9sBOM -LGZMjkiQ8bozYtUVAlhLFBnzMB/BOCWxe2yJGSyjQzBBMA8GA1UdEwEB/wQFMAMB -Af8wDwYDVR0PAQH/BAUDAwcEADAdBgNVHQ4EFgQUAOVmarDrz1YtyjvnX4C9cDcX -lagwCwYJYIZIAWUDBAMCA0cAMEQCIFEz1ogza6zKwImQS9tKVlPNjU4QSDEfPjZP -aSwIVMCyAiB+TcGoJvBEAdkzIeQQDdQLldrR+tO/WbayMeqPZHG6ww== ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ecdsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ecdsa.pem deleted file mode 100644 index 019ada2707..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ecdsa.pem +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBgzCCASmgAwIBAgIMWYGU7zek17Bcz64zMAoGCCqGSM49BAMCMCMxITAfBgNV -BAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzVaFw0z -NzA3MjkwOTAxMzVaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBD -QTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDOjvFecZj9RsxsIZSygfmv/GX9M -oJkQeMk+sI6QRVv7YbzL7QUxKa4gRb2x2e3iKPi+Mi2x2wGAPJajJO6nj8ujQzBB -MA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcEADAdBgNVHQ4EFgQU0ma/ -FGcW5gGlL//B26Xmj0JISecwCgYIKoZIzj0EAwIDSAAwRQIhAJPFYIENHNONgDNy -1565P/2N0TMAkcENL2zyCEDnYVG4AiBiA3BuThR1Rgnvn1qRGaivzoIiMvDVRQb7 -p76OkZ8Igw== ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ed25519.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ed25519.pem deleted file mode 100644 index c117a2649f..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ed25519.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBSjCB/aADAgECAhQ4EsBmtAbEpUqx/8m96XRPinrybTAFBgMrZXAwIzEhMB8G -A1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MDgyMzA5Mjk0N1oX -DTM4MDgxOTA5Mjk0N1owIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0 -IENBMCowBQYDK2VwAyEA8ZleePPCqzYeCARxwHP10sYfQhcCQ4YXjyOxrb53I0qj -QzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcEADAdBgNVHQ4EFgQU -6nm+PvoHITBuh26gdYBbNqOczWYwBQYDK2VwA0EAoUgBYkz0bcLAC+kTmbwE05ga -u2SmQtPaiXGykqY+3RhoZVthxQyEzWT0N5KJ322l6mjs0CZRat0ai4hR1Yj7BA== ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ed448.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ed448.pem deleted file mode 100644 index e72fcc6d98..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-ed448.pem +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBljCCARagAwIBAgIUWxqMqdy/tO71K3Iz4GYJiWrc42wwBQYDK2VxMCMxITAf -BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0yMDAyMTMwNzMzMDJa -Fw00MDAyMDkwNzMzMDJaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVz -dCBDQTBDMAUGAytlcQM6AKSetNrq+LCrx62FFnDlmUG/gZUa6LkaIHnfVM3w7/Wl -c1RONMpgGRUeNMqM8YBlgDzUrHjVkHfOAKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAP -BgNVHQ8BAf8EBQMDBwQAMB0GA1UdDgQWBBS+BSv++BEWlTJ53q6rwnDLVnR5JTAF -BgMrZXEDcwCFAtJNOZDtSYHm/Mf/L2PEbXNDDNrieJGWbixz/QXYoXjNBFB0D521 -IGH0o6Gdh0ZaQvdktpXc9wDs9xAbzh/w6+hLROTj8UvxyvPuZbGgVYH/tvE++NH/ -H0EQMi0FnLI/iBGv/bEPm8VJ1e24qEiEAAA= ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-dsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-dsa.pem deleted file mode 100644 index 4c378da7a6..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-dsa.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICZQIBADCCAjkGByqGSM44BAEwggIsAoIBAQDuXTZPmH8jzniCueBfVoOmZefn -LvNLUpNX2QUkBNZxQW5Zxon5d/S05sJBy+1zWZlFBba0nGO0JZNP3EbBKrJeuO3w -MlzYaqWQDjDybODQcep80Lypaa8VPSWDuZL0yKCTQUeBglA8V/w1i33xar8GwZq2 -dwYDQB4QB4/8A5tLH8Sg1x4H1MJlSYATp3u8cIfOkiSaI8PjDd9yC7knzRXj79gH -kJMPm2Pd7T6aLsn7JMgS3VrOw3hl5o37RUpqUuvI9+kQC9PuEGVcA8l/2iMCtW8Q -B1y4EZ6J6OzXxsc6pT4kF32+XsFJmT8oydz9OljFN5II+mTKMn5iThwksIwBAiEA -oDYhE+jjNZY7HOLbzl7Q0sl16kOGLUU+aONRmpfJL/kCggEAG7zNgM9fj8zoa8kg -OTwE8FlgzCF5cRcd1NYFyHM7uJRhkWqFc35khrA2egP9I/v2bZqYxh9wfo29EWm9 -J8mQQ1Myvt/cPmCO7PiushpCpUrsoaQf1KJAz9IeT3+jBFQFNmyHLrlkyzCZpXli -8MxyiU41A56wurcXlQG7FvjuJdOIzBy02TF4Njk5Pbq1LSc3iTZBBDDQPLL+4fsq -wKF9har4Xw4P6C3X8F0FC5CiXP3nOiEGl67R5vqGMA0MbK/WqeBZRE9Z8/dTDAF6 -J4QdmH5e3USibSjFChlhmwpYk5yQD1ByNVEZbZxIN/Oxv2G55xAVJ2ZTQSXg66WR -YPr9mQQjAiEAnZYHGZPTcKWTzPTfMa5UQkZgqKU1jqyOOWWtHc50fPE= ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ecdsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ecdsa.pem deleted file mode 100644 index 42132d48f5..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ecdsa.pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgXP0gFZhM/8/F0imI -9EPD/er+bEFS8m2nY9JzJlricXigCgYIKoZIzj0DAQehRANCAAQzo7xXnGY/UbMb -CGUsoH5r/xl/TKCZEHjJPrCOkEVb+2G8y+0FMSmuIEW9sdnt4ij4vjItsdsBgDyW -oyTup4/L ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ed25519.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ed25519.pem deleted file mode 100644 index 027bb835ea..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ed25519.pem +++ /dev/null @@ -1,25 +0,0 @@ -Public Key Info: - Public Key Algorithm: EdDSA (Ed25519) - Key Security Level: High (256 bits) - -curve: Ed25519 -private key: - a9:19:76:8a:f7:cf:95:c7:e3:94:3c:ce:3c:71:59:44 - 89:08:34:e5:49:0b:0a:44:56:d6:1d:05:f4:af:5d:85 - - -x: - f1:99:5e:78:f3:c2:ab:36:1e:08:04:71:c0:73:f5:d2 - c6:1f:42:17:02:43:86:17:8f:23:b1:ad:be:77:23:4a - - - -Public Key PIN: - pin-sha256:XFgN/8/bw68mn6K+U4zDmMa+HSGjXI0bejzTOxFQf0U= -Public Key ID: - sha256:5c580dffcfdbc3af269fa2be538cc398c6be1d21a35c8d1b7a3cd33b11507f45 - sha1:ea79be3efa0721306e876ea075805b36a39ccd66 - ------BEGIN PRIVATE KEY----- -MC4CAQAwBQYDK2VwBCIEIKkZdor3z5XH45Q8zjxxWUSJCDTlSQsKRFbWHQX0r12F ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ed448.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ed448.pem deleted file mode 100644 index 6974289736..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-ed448.pem +++ /dev/null @@ -1,28 +0,0 @@ -Public Key Info: - Public Key Algorithm: EdDSA (Ed448) - Key Security Level: Ultra (456 bits) - -curve: Ed448 -private key: - d8:36:a1:a6:12:8b:25:7a:86:eb:8a:b2:93:4a:71:df - 44:b7:9e:be:59:09:61:58:43:d2:3f:80:04:59:7b:37 - 89:cc:d9:6b:84:26:ae:b9:75:3c:b7:6d:eb:4b:c9:d8 - 36:94:5e:63:44:7b:7f:4b:e0: - -x: - a4:9e:b4:da:ea:f8:b0:ab:c7:ad:85:16:70:e5:99:41 - bf:81:95:1a:e8:b9:1a:20:79:df:54:cd:f0:ef:f5:a5 - 73:54:4e:34:ca:60:19:15:1e:34:ca:8c:f1:80:65:80 - 3c:d4:ac:78:d5:90:77:ce:00: - - -Public Key PIN: - pin-sha256:fnp0p/r6DXkqUgGSXDJih9BAOy/+ImGTT5dCbfH6H4w= -Public Key ID: - sha256:7e7a74a7fafa0d792a5201925c326287d0403b2ffe2261934f97426df1fa1f8c - sha1:be052bfef81116953279deaeabc270cb56747925 - ------BEGIN PRIVATE KEY----- -MEcCAQAwBQYDK2VxBDsEOdg2oaYSiyV6huuKspNKcd9Et56+WQlhWEPSP4AEWXs3 -iczZa4Qmrrl1PLdt60vJ2DaUXmNEe39L4A== ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa.pem deleted file mode 100644 index 9b51726a1a..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDjLlJpiydqUOH2 -IxH7iI9dUzJxvHaknGqXP8lPcxwg5+Q0CRjmv1+Y2KCV+JNj215OW23JNnGguCe/ -xlkboBnOCnDlSLQJp8W1cyarabHUa1VL086nL2kmTRxIElj+91ppQAl+sSB0cgba -/j8KYoO93mZDlXBjrG7FpYn31UNH9H8/wBrGIeSFgTZSHwTlsDhAQyWr5bGK1RgM -NTLl8ZJ8m7I1xUashTTxOkoXd1t3rXqPhTr0LMqKZl+hXD/hDmhUMUkO8kfsTbK3 -gssYuNIT37MDuk4oTfYS3VbdwvjhwycNsEdsTPksLFvB7uIxIttbmpEJfOOs/l3Y -FaPg9793AgMBAAECggEBANR2XtacMFmKmTijZc7y0Pk7tKKP2flq23jmS7QE+FqB -5HcRxvsOIS6F8fEvz1AFObZYZV1XkH75mxsMOgvO+DMsqpaUHuQkxo9CyPhoWcpK -MzQ+Ozc57MHIPdndZuPUmvZx0C9vIeYlOeoW+wgQSBsK4mL0YG6nNdWcUmK4TTr9 -V62ZvqDYoZjtTsAoLkUVJAgByN3XNzc70RQKN5OyCC8iib0JpLEeLdOkGgxWE7/n -KNLZ/9tbK9O4Mn3BWwZsTt8Hve0m/G9CbjlriEz9PYRBEg+JP6FmQIB5l0mjyRMQ -F5uRqiZt6r1uUGwUifNDOqNyJzSolj32u+OG3m8/6qkCgYEA+Tof5Wtuq9Oc5zCF -oVzm3cT1DZy3kJdGZWlMekLC9NMXhnA2huuNkln8Ph2qRx5pxmomRvX8ThaHNUdg -IRjzUomTQ0IWPkn+7TT6CmeSIEOoT4Tyw/xVvBHKm/yHKxHsCkcSIzt1cXS1SGU7 -Dfsy2C+FBjkcW6UBHkNKUMxce/0CgYEA6VrShFfora0fUOibaas/YG7XnqQzFyvw -mcBpqAbUXTneFdyssZDyfmQpE44KCywfPczz+34zIRkjnBX6mLyWx5rINE0KpOBK -uwS2ob1g6J1x6I6btBzIhhgR+Zj9zxhD5f+jYmmBCU3yTvWMXL4c5YsaWvlG8doq -bNo40cQykYMCgYEAmK8pV03n8VClMWWimGbn8Tl2v64hL23d7McD2WsJMSAZq30X -irTIeL60MAHQjd1uA+aIKLUOq3BVySg/FkfI2en61BuqsOJ4US5BeRpWhXmtpXnX -mIYAqEVmEQY2cQZ7yxgbXoZQvv83CHEsKraYQaVrI5Ldcq+17apf3vw0NKkCgYBH -u6WPDT73dIp14qszlnLLAAfEOpGCA/3YJa/U+RR6+/jrG4TyqK4CcGO4ISexO4T3 -CHPP0YGCISozJwZ7wS1QeqIkgbJN8KzIRLCnk4GgwBVt+bifa2Gw5uFPqtoKuVjV -8PmWnPwPkih0YUMel0pmvZYCdTJ70ibMg2CICxnIZQKBgQC7aMgcL5ORB/8fgOdy -g0at1fmz5kKKbv0Z9cmk7trKW67NDM5kwVyFdUuc5Vp7alkRyW4SZPtwpOG+d5Xt -M0DM77Qvom+sIYq5C5eSHPU6py2Ipn5HZzkHRnAM8qw3OrL6+iFklQUKEBXeqVEq -6MfsH8P1/RIRfvcOMhPrNEzpTg== ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_256.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_256.pem deleted file mode 100644 index 9243a1e32a..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_256.pem +++ /dev/null @@ -1,138 +0,0 @@ -Public Key Info: - Public Key Algorithm: RSA-PSS - Hash Algorithm: SHA256 - Salt Length: 32 - Key Security Level: Medium (2048 bits) - -modulus: - 00:b7:b4:9a:4d:2d:3f:08:b8:1e:55:d6:b0:b2:b7:d0 - 33:cc:bb:de:56:24:04:1d:73:ac:6a:32:db:af:26:4f - ef:b1:d6:10:90:79:dc:89:ac:60:e3:94:54:19:04:54 - 17:ea:18:0e:d9:46:be:60:9f:e6:33:ff:6e:60:6a:35 - c6:2d:dd:06:82:d5:80:c9:88:07:2f:27:4b:04:13:ba - 4b:69:92:ce:bc:00:be:42:2c:e2:35:8d:60:11:66:3c - 24:f8:3a:13:ad:49:e7:12:ca:c6:2a:52:84:ed:3d:7d - 1e:06:de:a4:64:d6:17:14:b1:19:63:a0:e1:7c:49:d3 - 41:73:29:f8:b5:75:e0:93:fa:e3:df:3b:82:77:5e:83 - cb:da:52:26:eb:c3:20:13:11:6d:e9:aa:a5:d7:b6:c3 - a1:a5:04:fa:6e:ee:4f:39:52:4d:18:f9:ab:87:4a:4e - d9:34:a7:c4:df:f5:1b:b6:57:71:7f:c3:c8:4f:2c:00 - c0:6e:e8:74:35:e2:71:1f:ef:c6:c1:62:7a:65:e7:c9 - c7:42:14:5f:16:c1:ab:4d:32:e5:e2:7c:38:a2:21:02 - 69:a3:81:f4:c8:78:48:58:0a:5d:99:85:f5:e6:2a:37 - be:23:e5:ff:15:ba:39:42:ac:9d:d0:11:7e:e4:2b:55 - db: - -public exponent: - 01:00:01: - -private exponent: - 00:9a:2e:3e:02:e0:22:b3:52:b4:43:1e:f9:16:46:27 - bc:11:ec:eb:62:28:c0:3b:67:c6:21:2b:a6:2d:8e:5e - 30:b2:75:13:59:ee:ad:25:ef:43:32:3e:5f:86:cf:97 - 34:ab:08:9e:0d:c5:ce:2a:92:89:46:c2:ef:04:84:9f - b5:40:f0:ec:72:0a:77:18:ad:ce:39:c9:24:b0:bb:4d - f3:d5:1b:9d:df:34:50:7a:81:e9:29:41:0a:8c:0f:de - 12:b9:33:25:28:9f:8a:0c:bf:9b:2a:12:2f:f6:5d:51 - 11:4e:7a:b6:46:db:58:6b:c9:67:a1:b2:79:0d:33:78 - d5:5d:69:38:91:d9:f0:37:28:da:67:56:96:dd:77:d4 - f0:cd:33:9a:a3:7d:cc:6a:5c:44:c1:bd:e3:d3:34:71 - 70:b1:ed:67:56:cc:02:28:3b:e2:2b:6d:d0:eb:69:9b - e5:d9:27:e8:fc:2a:03:14:e1:f7:76:3f:b7:a7:87:1c - 78:84:9e:17:60:71:84:b7:67:83:c5:41:27:40:18:96 - 3c:c5:13:9f:ff:fd:3f:ac:30:cd:e5:f7:b5:cb:ac:16 - 39:85:05:c1:59:46:ce:df:e8:67:9a:a2:56:88:73:a8 - 34:23:b2:54:2d:18:2c:c9:16:0c:d0:f6:46:55:9f:2a - 01: - -prime1: - 00:e1:11:b3:58:64:b9:77:3c:b9:f2:95:df:bb:0b:66 - f6:81:31:03:22:cb:eb:5a:a9:38:63:31:ff:f2:75:46 - 9a:dd:be:a7:d0:d4:c8:30:18:bf:6f:bf:c0:01:ba:27 - 0e:34:b2:7f:75:f0:aa:05:69:71:68:03:41:9b:47:5b - 6a:7b:89:ef:f4:e0:84:c0:01:67:5c:46:c6:29:40:3d - 55:15:48:d6:19:e9:22:d2:fd:88:1d:f6:cd:7e:9c:04 - c6:b0:d7:3d:1d:ea:42:44:8c:10:a8:6c:8a:d2:70:6d - b6:fb:9b:1f:ce:d9:ec:3e:1a:3f:ee:02:17:e3:37:74 - 9b: - -prime2: - 00:d0:f3:a9:3a:80:a3:ac:1f:e9:d8:29:f4:2f:1a:7c - d6:61:77:c8:82:cb:fa:64:a0:ce:ef:ec:5c:e9:97:a0 - 1d:28:a6:49:5d:34:59:92:96:c1:b2:c2:14:f5:02:a2 - 2e:b9:ab:df:a7:79:e6:b3:fa:5c:3e:bd:50:b2:e4:c1 - ee:d3:b5:5d:38:a4:f6:d0:81:8a:e1:5a:45:da:19:06 - a3:fa:6a:84:8f:04:f4:56:2a:00:13:2b:76:8d:c1:c8 - d4:eb:42:c0:02:d5:c5:b4:83:7f:36:32:27:93:fc:49 - 11:f4:a3:4d:7d:bd:03:61:e7:40:28:15:10:ad:8f:97 - c1: - -coefficient: - 00:d6:d9:e8:05:2e:4f:3c:27:59:e4:3a:5a:1a:15:59 - 0c:b7:fd:fa:23:ad:c1:64:07:e4:22:ae:35:9b:ac:e8 - 95:34:46:be:38:ba:99:07:4b:52:0f:f2:f9:cd:32:e7 - 99:2d:66:15:f1:f3:51:b5:4e:4a:d5:49:8f:a3:97:43 - ad:60:31:c7:c7:a7:4a:e0:2f:07:fe:40:24:22:5a:4e - 76:ee:ef:df:95:85:e4:5a:81:7a:ab:61:e9:da:51:7e - 2f:dd:d7:83:46:b2:76:13:ef:18:3a:64:45:31:e1:4f - af:6e:f0:6e:34:d2:cf:59:e3:ee:88:f2:22:1e:c8:06 - f6: - -exp1: - 00:96:25:00:c7:cf:2a:0a:e9:70:02:ed:08:bb:f6:f7 - 51:2b:0e:4f:51:3f:48:5a:ca:d8:db:13:d7:f3:1f:59 - 62:a6:db:31:88:96:ea:95:6b:6d:0a:57:98:f7:8d:ff - cf:f2:47:c1:d0:24:24:c8:47:77:68:34:03:e8:5a:ca - 19:57:20:c5:fb:4e:6c:40:ca:ae:f1:58:25:8a:0f:58 - db:11:bf:ed:54:8b:ba:b7:96:7a:df:c2:6d:84:31:00 - de:ab:ca:6a:f3:31:fb:d3:4e:bd:2e:1e:7a:dd:b8:32 - f9:07:10:8d:3f:a9:11:78:bc:7a:39:85:1b:fa:70:5c - 51: - -exp2: - 42:c5:ca:cb:8e:36:3f:98:07:33:73:dc:bb:7c:bc:6e - 09:c1:ac:8a:d7:c2:51:8b:ed:f5:4f:d4:35:35:a6:0e - 0b:62:70:49:5f:a4:4c:2a:ef:05:3f:ee:50:89:a1:e8 - 4a:9f:39:1e:9c:de:f3:9e:cb:01:a5:9f:f7:3b:11:1a - 4f:ff:42:26:0a:d9:70:b2:24:fe:74:c9:a3:b3:a1:a2 - 9f:30:90:e1:df:54:71:80:84:7b:9b:c5:0b:f1:e4:4a - de:4f:7b:6a:ac:83:bc:76:d5:1d:2d:93:e6:3f:95:de - 2e:0e:4d:82:23:f7:c3:be:91:8a:fd:88:51:de:74:41 - - - -Public Key PIN: - pin-sha256:O4J2O7fbEdphitrCWZG7Jyi8t5S4daRsB8YQZknFYWk= -Public Key ID: - sha256:3b82763bb7db11da618adac25991bb2728bcb794b875a46c07c6106649c56169 - sha1:211a88b6de03c00180aadb708899a68f17ceaa6c - ------BEGIN PRIVATE KEY----- -MIIE7wIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3 -DQEBCDALBglghkgBZQMEAgGiAwIBIASCBKkwggSlAgEAAoIBAQC3tJpNLT8IuB5V -1rCyt9AzzLveViQEHXOsajLbryZP77HWEJB53ImsYOOUVBkEVBfqGA7ZRr5gn+Yz -/25gajXGLd0GgtWAyYgHLydLBBO6S2mSzrwAvkIs4jWNYBFmPCT4OhOtSecSysYq -UoTtPX0eBt6kZNYXFLEZY6DhfEnTQXMp+LV14JP64987gndeg8vaUibrwyATEW3p -qqXXtsOhpQT6bu5POVJNGPmrh0pO2TSnxN/1G7ZXcX/DyE8sAMBu6HQ14nEf78bB -Ynpl58nHQhRfFsGrTTLl4nw4oiECaaOB9Mh4SFgKXZmF9eYqN74j5f8VujlCrJ3Q -EX7kK1XbAgMBAAECggEBAJouPgLgIrNStEMe+RZGJ7wR7OtiKMA7Z8YhK6Ytjl4w -snUTWe6tJe9DMj5fhs+XNKsIng3FziqSiUbC7wSEn7VA8OxyCncYrc45ySSwu03z -1Rud3zRQeoHpKUEKjA/eErkzJSifigy/myoSL/ZdURFOerZG21hryWehsnkNM3jV -XWk4kdnwNyjaZ1aW3XfU8M0zmqN9zGpcRMG949M0cXCx7WdWzAIoO+IrbdDraZvl -2Sfo/CoDFOH3dj+3p4cceISeF2BxhLdng8VBJ0AYljzFE5///T+sMM3l97XLrBY5 -hQXBWUbO3+hnmqJWiHOoNCOyVC0YLMkWDND2RlWfKgECgYEA4RGzWGS5dzy58pXf -uwtm9oExAyLL61qpOGMx//J1RprdvqfQ1MgwGL9vv8ABuicONLJ/dfCqBWlxaANB -m0dbanuJ7/TghMABZ1xGxilAPVUVSNYZ6SLS/Ygd9s1+nATGsNc9HepCRIwQqGyK -0nBttvubH87Z7D4aP+4CF+M3dJsCgYEA0POpOoCjrB/p2Cn0Lxp81mF3yILL+mSg -zu/sXOmXoB0opkldNFmSlsGywhT1AqIuuavfp3nms/pcPr1QsuTB7tO1XTik9tCB -iuFaRdoZBqP6aoSPBPRWKgATK3aNwcjU60LAAtXFtIN/NjInk/xJEfSjTX29A2Hn -QCgVEK2Pl8ECgYEAliUAx88qCulwAu0Iu/b3USsOT1E/SFrK2NsT1/MfWWKm2zGI -luqVa20KV5j3jf/P8kfB0CQkyEd3aDQD6FrKGVcgxftObEDKrvFYJYoPWNsRv+1U -i7q3lnrfwm2EMQDeq8pq8zH70069Lh563bgy+QcQjT+pEXi8ejmFG/pwXFECgYBC -xcrLjjY/mAczc9y7fLxuCcGsitfCUYvt9U/UNTWmDgticElfpEwq7wU/7lCJoehK -nzkenN7znssBpZ/3OxEaT/9CJgrZcLIk/nTJo7Ohop8wkOHfVHGAhHubxQvx5Ere -T3tqrIO8dtUdLZPmP5XeLg5NgiP3w76Riv2IUd50QQKBgQDW2egFLk88J1nkOloa -FVkMt/36I63BZAfkIq41m6zolTRGvji6mQdLUg/y+c0y55ktZhXx81G1TkrVSY+j -l0OtYDHHx6dK4C8H/kAkIlpOdu7v35WF5FqBeqth6dpRfi/d14NGsnYT7xg6ZEUx -4U+vbvBuNNLPWePuiPIiHsgG9g== ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_384.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_384.pem deleted file mode 100644 index b83a1059cf..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_384.pem +++ /dev/null @@ -1,138 +0,0 @@ -Public Key Info: - Public Key Algorithm: RSA-PSS - Hash Algorithm: SHA384 - Salt Length: 48 - Key Security Level: Medium (2048 bits) - -modulus: - 00:ee:6d:c0:c9:44:dd:94:f8:40:af:9a:f4:43:3e:78 - 45:61:5f:6a:15:23:42:f4:f8:a0:c2:eb:6a:0a:ae:0c - 43:a7:dc:e9:ac:ce:42:c4:c8:f5:4c:de:6c:52:4b:e5 - d3:2b:42:b8:f9:e5:5c:5f:5c:53:2f:0f:f7:f5:3d:04 - ed:2b:50:c9:ab:6b:74:2d:4b:42:71:57:7a:04:83:38 - 97:fa:5b:22:4a:14:d2:0d:dd:5c:66:c9:25:7d:e3:ff - 05:84:02:ea:3c:82:97:45:0f:7c:b3:71:8e:7f:31:8d - b5:eb:5e:b6:0d:91:9b:5d:51:bc:f7:e2:81:a2:5f:46 - 35:cf:9e:64:c4:3c:65:63:f6:ff:15:b0:e7:11:49:fa - c1:cc:d9:54:9b:f8:13:3d:95:ce:f4:7f:58:66:23:cd - bc:11:af:e1:3f:af:d8:5e:16:85:cd:7d:b7:7f:59:fa - ff:29:e6:ef:4f:6e:6b:ef:b0:91:ef:81:63:6f:b2:0c - 2b:47:a6:21:f7:1f:4b:fb:1d:e7:6f:f8:6f:0e:6a:8f - 8a:54:5f:4b:a2:6d:36:20:bb:ba:11:87:06:f3:8d:95 - 6a:10:b7:27:8e:1d:02:b4:ce:1e:c2:09:73:c4:b6:5d - c7:5f:e2:26:bd:4f:cd:7a:b0:c5:c0:d6:82:1f:d4:2e - 59: - -public exponent: - 01:00:01: - -private exponent: - 6a:cf:72:10:f8:2f:c7:9f:9a:e2:d0:28:e2:c2:e6:80 - 36:49:d7:2d:16:f9:d4:e2:58:aa:59:69:cc:d5:01:9b - 81:64:9e:ae:12:4c:a8:f9:59:a2:90:f5:b7:bc:56:7d - ce:20:7a:db:40:1b:ac:80:a0:a7:31:a1:24:14:ac:d3 - 4e:97:47:70:ea:97:45:ff:34:09:b0:65:72:06:12:e1 - 4a:7f:6f:11:fe:d7:c6:ec:46:8b:a9:4a:89:66:0d:05 - bc:88:cd:c4:43:c0:5e:68:bc:b5:6a:86:aa:86:59:74 - 88:b7:8a:18:f4:04:c4:be:6c:48:24:09:6c:e2:ff:81 - 18:5f:a8:85:db:79:b0:14:66:1c:fb:f7:8f:a8:29:79 - 83:79:aa:65:45:05:5a:0f:03:30:e5:75:43:23:23:e1 - eb:09:5d:e6:be:0a:10:bd:34:4a:02:d5:60:f6:51:90 - 30:b5:2d:95:37:0e:aa:fb:8e:f3:4f:b4:2f:54:a4:c1 - 8c:a8:5a:46:0c:85:f0:d5:94:d0:ee:71:a2:c6:d7:b0 - de:81:04:66:43:4c:10:ba:ba:ec:91:57:93:bd:74:4f - d4:ea:96:3b:53:a1:0c:0f:be:7d:70:9c:c2:ae:b2:13 - 4b:2b:c3:c9:8a:56:12:a0:ab:55:e4:4e:90:df:0c:01 - - -prime1: - 00:f8:f5:75:8a:5e:fb:0f:2a:09:42:dc:eb:1e:0d:c9 - 97:6f:30:c9:55:28:af:15:4e:4a:db:9e:cd:17:6a:7f - d1:be:1e:53:2b:79:d9:83:de:96:c9:9b:1f:7e:93:ce - 02:f3:fb:9d:56:a2:19:cf:f2:d0:f2:3b:80:5f:b5:7b - cb:df:d6:26:fb:e8:ba:2b:db:e5:c1:47:98:1d:2e:57 - 5d:26:19:72:2f:48:77:00:1d:8d:72:f6:48:68:97:62 - 0f:5d:30:e0:95:a4:00:34:e4:77:b9:47:81:30:63:48 - 29:64:a0:2f:4f:c0:42:4b:bb:a2:60:7b:ba:e4:79:6b - 81: - -prime2: - 00:f5:2c:0d:7a:8c:17:59:ac:95:20:ca:29:3e:45:23 - 23:6f:25:fe:a3:56:df:23:74:47:cd:38:47:a3:4d:06 - 0e:66:7a:9f:74:cc:86:3e:86:e3:c8:4b:45:09:93:2b - 81:d3:fc:56:a2:29:b3:52:4d:f1:45:69:e2:d3:a3:b1 - 4e:1a:25:bd:1a:6c:2b:57:8a:93:11:b9:e9:6d:11:43 - 2c:aa:22:e9:20:10:bf:e4:fe:a6:c5:30:ec:42:5a:5c - d9:3d:1d:e9:18:7e:10:5b:9d:59:cd:7f:7e:51:5c:c8 - 65:63:8b:4a:54:e8:c1:fa:5c:e9:36:23:20:20:87:0e - d9: - -coefficient: - 00:9f:a9:37:76:c0:24:33:8e:18:92:c5:4c:1e:05:fd - 82:39:d9:40:4d:15:95:7e:92:59:44:1a:99:81:4b:0f - 16:e0:16:99:23:45:91:04:76:f0:98:d7:f5:92:e4:af - 39:3b:6f:49:0b:8f:22:02:aa:3a:da:72:04:9c:a4:cb - 11:1a:44:f4:47:19:ed:a0:9c:94:58:06:cd:ca:b1:ff - 48:7f:bf:2e:23:66:63:0e:cd:0b:a5:43:ee:23:75:32 - d5:93:08:23:51:e3:9e:d2:82:be:9b:c4:6d:53:a9:50 - 66:74:af:11:dd:f2:d5:a6:9f:6e:ca:11:ac:6d:a6:ca - 0b: - -exp1: - 00:ba:47:87:9c:72:77:2e:20:88:ef:73:b7:a5:34:31 - cb:d2:91:d1:83:9b:be:6d:95:b8:63:5e:0e:1d:60:3d - a5:a5:b8:b1:08:8d:d2:d8:5d:db:bb:9c:0b:53:bd:aa - 5f:01:4a:1a:af:30:f9:59:64:59:3d:76:92:16:8b:07 - c7:43:83:cc:85:9e:dc:76:66:c2:21:fd:bc:ee:d0:b6 - e3:e6:d7:11:5e:19:bd:98:e3:83:ec:2a:25:81:c5:0b - c5:6d:38:5e:42:f9:84:82:0f:15:1a:18:4b:ac:f6:0c - 8f:94:50:5b:36:34:28:26:dc:8d:a1:dd:d2:b8:93:b5 - 81: - -exp2: - 5c:07:25:28:12:dd:d0:f3:4f:26:f7:bb:73:7c:50:2c - 44:d4:66:38:b9:ab:18:8b:d5:47:db:10:48:e3:e8:9a - 0f:2d:88:1d:37:88:4c:80:25:90:51:70:a0:9f:75:7d - 4e:2d:31:f7:bc:df:6a:cd:86:fb:1f:3b:dd:65:5c:70 - 8c:b0:0d:c3:95:46:cf:9d:5c:87:12:d9:e3:ee:ce:e0 - 3d:1c:cd:95:13:b4:74:28:82:41:12:94:1c:73:fe:d6 - 2c:72:c5:c4:43:cd:b0:15:e8:57:92:bb:bf:9e:ac:3a - 22:9b:6e:53:60:eb:2f:27:21:03:09:3c:4d:f9:64:41 - - - -Public Key PIN: - pin-sha256:wv5nADHzPA1LzmxBzNO9BTLNYGb9g0W8L55XearJ5C8= -Public Key ID: - sha256:c2fe670031f33c0d4bce6c41ccd3bd0532cd6066fd8345bc2f9e5779aac9e42f - sha1:a9f05d6f61a0f001e874b25a7ed411431c2a89e7 - ------BEGIN PRIVATE KEY----- -MIIE7gIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEaMBgGCSqGSIb3 -DQEBCDALBglghkgBZQMEAgKiAwIBMASCBKgwggSkAgEAAoIBAQDubcDJRN2U+ECv -mvRDPnhFYV9qFSNC9PigwutqCq4MQ6fc6azOQsTI9UzebFJL5dMrQrj55VxfXFMv -D/f1PQTtK1DJq2t0LUtCcVd6BIM4l/pbIkoU0g3dXGbJJX3j/wWEAuo8gpdFD3yz -cY5/MY216162DZGbXVG89+KBol9GNc+eZMQ8ZWP2/xWw5xFJ+sHM2VSb+BM9lc70 -f1hmI828Ea/hP6/YXhaFzX23f1n6/ynm709ua++wke+BY2+yDCtHpiH3H0v7Hedv -+G8Oao+KVF9Lom02ILu6EYcG842VahC3J44dArTOHsIJc8S2Xcdf4ia9T816sMXA -1oIf1C5ZAgMBAAECggEAas9yEPgvx5+a4tAo4sLmgDZJ1y0W+dTiWKpZaczVAZuB -ZJ6uEkyo+VmikPW3vFZ9ziB620AbrICgpzGhJBSs006XR3Dql0X/NAmwZXIGEuFK -f28R/tfG7EaLqUqJZg0FvIjNxEPAXmi8tWqGqoZZdIi3ihj0BMS+bEgkCWzi/4EY -X6iF23mwFGYc+/ePqCl5g3mqZUUFWg8DMOV1QyMj4esJXea+ChC9NEoC1WD2UZAw -tS2VNw6q+47zT7QvVKTBjKhaRgyF8NWU0O5xosbXsN6BBGZDTBC6uuyRV5O9dE/U -6pY7U6EMD759cJzCrrITSyvDyYpWEqCrVeROkN8MAQKBgQD49XWKXvsPKglC3Ose -DcmXbzDJVSivFU5K257NF2p/0b4eUyt52YPelsmbH36TzgLz+51WohnP8tDyO4Bf -tXvL39Ym++i6K9vlwUeYHS5XXSYZci9IdwAdjXL2SGiXYg9dMOCVpAA05He5R4Ew -Y0gpZKAvT8BCS7uiYHu65HlrgQKBgQD1LA16jBdZrJUgyik+RSMjbyX+o1bfI3RH -zThHo00GDmZ6n3TMhj6G48hLRQmTK4HT/FaiKbNSTfFFaeLTo7FOGiW9GmwrV4qT -EbnpbRFDLKoi6SAQv+T+psUw7EJaXNk9HekYfhBbnVnNf35RXMhlY4tKVOjB+lzp -NiMgIIcO2QKBgQC6R4eccncuIIjvc7elNDHL0pHRg5u+bZW4Y14OHWA9paW4sQiN -0thd27ucC1O9ql8BShqvMPlZZFk9dpIWiwfHQ4PMhZ7cdmbCIf287tC24+bXEV4Z -vZjjg+wqJYHFC8VtOF5C+YSCDxUaGEus9gyPlFBbNjQoJtyNod3SuJO1gQKBgFwH -JSgS3dDzTyb3u3N8UCxE1GY4uasYi9VH2xBI4+iaDy2IHTeITIAlkFFwoJ91fU4t -Mfe832rNhvsfO91lXHCMsA3DlUbPnVyHEtnj7s7gPRzNlRO0dCiCQRKUHHP+1ixy -xcRDzbAV6FeSu7+erDoim25TYOsvJyEDCTxN+WRBAoGBAJ+pN3bAJDOOGJLFTB4F -/YI52UBNFZV+kllEGpmBSw8W4BaZI0WRBHbwmNf1kuSvOTtvSQuPIgKqOtpyBJyk -yxEaRPRHGe2gnJRYBs3Ksf9If78uI2ZjDs0LpUPuI3Uy1ZMII1HjntKCvpvEbVOp -UGZ0rxHd8tWmn27KEaxtpsoL ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_512.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_512.pem deleted file mode 100644 index 1bd1bcfc95..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-rsa_pss_512.pem +++ /dev/null @@ -1,138 +0,0 @@ -Public Key Info: - Public Key Algorithm: RSA-PSS - Hash Algorithm: SHA512 - Salt Length: 64 - Key Security Level: Medium (2048 bits) - -modulus: - 00:ea:1f:fc:30:5f:ff:19:db:9a:30:46:1b:fa:34:de - 6b:56:44:ff:a1:06:d1:5c:6a:a7:b9:f8:7d:ac:bc:0f - 2b:9c:d8:9b:90:2d:31:a0:41:c7:74:73:01:ba:ea:e4 - c6:9e:bf:9b:41:62:07:54:b4:53:cb:a2:d7:8b:df:3a - a4:6d:b6:95:71:32:21:ee:3c:9a:9d:9b:9b:4d:d5:ef - d3:70:84:ba:c2:0e:a7:2f:07:aa:29:69:20:46:f8:da - 87:49:e0:cf:00:d3:c0:26:a0:71:35:00:06:45:56:56 - 8f:93:60:75:42:f5:78:61:ee:ad:fb:d2:38:de:79:2d - 9b:5b:07:e6:2b:be:b5:a8:a7:95:df:9f:2a:1a:9f:62 - 55:26:35:53:88:33:8c:1c:f9:93:e6:ea:45:39:3c:09 - 7a:e1:4a:41:de:a6:38:fd:56:e4:d5:0d:ee:ff:28:81 - dc:b0:ca:a9:84:42:5f:7a:68:72:32:1e:05:4f:07:36 - 58:71:76:a4:c8:b3:d2:18:3e:c8:3d:7b:2e:18:44:8c - dc:df:b4:53:54:72:ee:78:11:68:94:92:f6:de:41:5b - 1c:e8:dc:1b:41:fe:8f:b4:7d:8d:59:56:ed:07:96:20 - bd:0b:18:cb:3f:40:d3:02:62:7a:50:2e:52:66:68:ab - a1: - -public exponent: - 01:00:01: - -private exponent: - 33:87:46:a1:fe:fe:ce:5a:1e:dd:71:10:c7:48:cb:8b - 24:39:9b:69:7d:6e:a6:c0:72:99:e3:af:05:4d:7e:a9 - 42:a4:09:d8:f9:99:6a:84:0f:b9:f9:75:f0:05:b2:c4 - 64:3c:17:97:94:53:b8:b8:d7:98:82:06:9e:aa:4a:e5 - d5:9f:d1:d4:50:0c:57:ba:ce:ec:d1:4a:a5:1e:e8:e1 - c8:69:ee:10:b7:d8:e3:e8:f3:f2:99:48:99:56:3c:02 - 7a:a8:17:e7:3e:b3:93:cc:cc:1d:b6:1b:ab:37:0d:66 - 1c:31:a6:9d:4e:19:68:b4:77:66:6d:26:47:10:b4:90 - 88:f9:af:65:d3:16:07:f2:6b:59:6e:ba:03:20:ba:a5 - 80:87:75:ae:92:42:bd:64:e1:5a:48:7b:73:33:c3:70 - 74:cc:14:05:c0:d2:42:01:7f:82:4e:e0:8b:f9:2b:12 - 4d:71:4f:55:86:fd:28:0a:8f:a6:ad:66:32:4b:5e:f3 - 22:58:b1:09:51:1f:77:b5:d8:76:e9:80:ea:25:24:09 - 2d:70:ef:5d:89:20:7d:49:4b:52:c1:26:36:c4:c3:95 - 38:80:ef:6d:15:43:5e:dc:bd:5e:06:56:42:6a:59:00 - 13:e3:99:3f:b1:c0:a6:e3:d5:fc:72:38:d1:ea:0d:61 - - -prime1: - 00:f1:54:7d:6d:25:84:c2:37:16:bc:18:04:8b:a2:5e - 09:bd:cc:98:4c:44:ef:8a:9f:b4:6a:72:ac:cf:c8:2f - b4:6b:a6:fd:e9:df:6e:98:42:6c:b4:95:b5:72:21:e0 - 21:e9:71:99:c6:8a:66:f5:06:96:35:9f:15:87:46:7a - 66:cd:3d:ba:1e:96:28:35:ab:fd:07:fd:ab:11:31:50 - 93:a6:6c:67:5e:dd:b6:a9:87:f0:9c:c6:46:cb:7d:83 - 5e:58:c6:16:81:03:64:f5:c6:01:a6:e2:54:7c:be:93 - 65:02:66:89:86:e8:c8:56:bd:cb:d0:bc:7e:df:cb:9c - f7: - -prime2: - 00:f8:5b:5f:19:24:20:60:41:4c:86:07:70:c7:2a:7d - dd:98:bc:f5:e8:ba:c3:7b:5b:2c:50:b3:fa:be:17:04 - 27:6e:75:3f:61:4f:3d:11:aa:f2:73:6a:f8:2f:da:59 - 65:b8:60:13:74:0e:d1:7e:01:07:d6:7e:fd:fb:f9:ca - 4f:9c:e9:c5:49:62:a7:99:36:ed:0f:1e:86:cb:e6:d3 - 87:d0:2c:93:3e:d6:b5:59:a6:b4:f3:2d:38:85:dc:ca - 5c:cd:e1:e9:3e:69:c4:04:25:5e:12:16:86:7f:30:3b - 84:63:80:78:77:d4:45:dd:f7:f0:cc:d2:b5:7e:53:ce - 27: - -coefficient: - 54:6b:6a:51:c7:7e:e2:d9:0b:b8:7e:ea:c8:1b:1b:a8 - 97:06:67:87:da:6a:f7:b2:15:7c:ae:91:4a:46:4a:bd - 79:3b:3a:d7:80:c6:95:2d:e7:92:97:76:cf:24:04:09 - e3:5c:11:68:77:0a:67:21:5a:82:57:80:d1:66:42:d5 - a7:03:1a:20:56:90:c2:e6:97:31:21:3e:a0:4f:41:43 - f8:07:41:92:48:39:ac:1c:8d:c1:a6:0d:be:5d:45:96 - 65:4b:b7:31:0c:c8:2d:f0:72:ca:ba:0e:f0:5a:7c:1a - 7e:23:20:98:1e:c0:55:72:f2:18:b3:22:de:ec:47:21 - - -exp1: - 00:90:e0:d8:2b:9e:4a:85:0d:ed:68:1e:43:1c:50:ed - 83:8b:9e:38:10:11:92:7c:f6:43:a9:64:0e:ba:ee:c3 - 34:dd:2b:f3:63:63:ef:51:19:0f:89:9a:16:c3:dd:f2 - 60:69:74:f9:8c:67:aa:47:8f:1c:be:34:33:08:73:17 - 28:80:2e:7e:7d:be:47:85:71:2b:06:91:13:11:cf:39 - 40:6a:b8:c9:95:fa:24:9e:c2:2d:80:f0:c7:af:82:3a - 4b:79:9f:f2:02:a1:b7:0a:95:44:88:9b:77:7d:2c:2b - f0:87:f0:66:bf:c7:1f:fe:73:12:d8:cd:50:9d:a9:ef - 21: - -exp2: - 2f:9e:a5:6f:56:a3:f6:90:ce:b1:6c:3f:cd:90:72:2d - c9:19:82:35:2b:8a:4b:de:c1:72:7f:ef:f5:fe:c7:c7 - 1f:c0:cf:74:43:13:3c:8e:00:8a:ec:d9:c5:a3:22:3d - 04:cb:37:2f:ab:9f:b3:7f:53:17:67:a6:1f:68:57:c8 - 48:17:f2:c2:0d:6e:81:4c:2c:cc:17:58:55:44:5f:0e - cd:75:9e:8e:0f:f1:19:cd:83:28:95:65:1f:15:a4:9f - 82:c2:6c:4c:91:4f:0a:54:77:e3:13:fa:99:ec:8f:9c - e4:cf:3f:4a:0a:a3:92:d9:f5:8b:f0:62:e8:63:fd:45 - - - -Public Key PIN: - pin-sha256:rS98yeSr3aoarf12o4jbIXeADc53+k2lu/+TB71kG0w= -Public Key ID: - sha256:ad2f7cc9e4abddaa1aadfd76a388db2177800dce77fa4da5bbff9307bd641b4c - sha1:a558e1b80dd69fbc34e5e83dd8fa0ca583b1c045 - ------BEGIN PRIVATE KEY----- -MIIE7QIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCA6EaMBgGCSqGSIb3 -DQEBCDALBglghkgBZQMEAgOiAwIBQASCBKcwggSjAgEAAoIBAQDqH/wwX/8Z25ow -Rhv6NN5rVkT/oQbRXGqnufh9rLwPK5zYm5AtMaBBx3RzAbrq5Maev5tBYgdUtFPL -oteL3zqkbbaVcTIh7jyanZubTdXv03CEusIOpy8HqilpIEb42odJ4M8A08AmoHE1 -AAZFVlaPk2B1QvV4Ye6t+9I43nktm1sH5iu+tainld+fKhqfYlUmNVOIM4wc+ZPm -6kU5PAl64UpB3qY4/Vbk1Q3u/yiB3LDKqYRCX3pocjIeBU8HNlhxdqTIs9IYPsg9 -ey4YRIzc37RTVHLueBFolJL23kFbHOjcG0H+j7R9jVlW7QeWIL0LGMs/QNMCYnpQ -LlJmaKuhAgMBAAECggEAM4dGof7+zloe3XEQx0jLiyQ5m2l9bqbAcpnjrwVNfqlC -pAnY+ZlqhA+5+XXwBbLEZDwXl5RTuLjXmIIGnqpK5dWf0dRQDFe6zuzRSqUe6OHI -ae4Qt9jj6PPymUiZVjwCeqgX5z6zk8zMHbYbqzcNZhwxpp1OGWi0d2ZtJkcQtJCI -+a9l0xYH8mtZbroDILqlgId1rpJCvWThWkh7czPDcHTMFAXA0kIBf4JO4Iv5KxJN -cU9Vhv0oCo+mrWYyS17zIlixCVEfd7XYdumA6iUkCS1w712JIH1JS1LBJjbEw5U4 -gO9tFUNe3L1eBlZCalkAE+OZP7HApuPV/HI40eoNYQKBgQDxVH1tJYTCNxa8GASL -ol4JvcyYTETvip+0anKsz8gvtGum/enfbphCbLSVtXIh4CHpcZnGimb1BpY1nxWH -RnpmzT26HpYoNav9B/2rETFQk6ZsZ17dtqmH8JzGRst9g15YxhaBA2T1xgGm4lR8 -vpNlAmaJhujIVr3L0Lx+38uc9wKBgQD4W18ZJCBgQUyGB3DHKn3dmLz16LrDe1ss -ULP6vhcEJ251P2FPPRGq8nNq+C/aWWW4YBN0DtF+AQfWfv37+cpPnOnFSWKnmTbt -Dx6Gy+bTh9Askz7WtVmmtPMtOIXcylzN4ek+acQEJV4SFoZ/MDuEY4B4d9RF3ffw -zNK1flPOJwKBgQCQ4NgrnkqFDe1oHkMcUO2Di544EBGSfPZDqWQOuu7DNN0r82Nj -71EZD4maFsPd8mBpdPmMZ6pHjxy+NDMIcxcogC5+fb5HhXErBpETEc85QGq4yZX6 -JJ7CLYDwx6+COkt5n/ICobcKlUSIm3d9LCvwh/Bmv8cf/nMS2M1QnanvIQKBgC+e -pW9Wo/aQzrFsP82Qci3JGYI1K4pL3sFyf+/1/sfHH8DPdEMTPI4AiuzZxaMiPQTL -Ny+rn7N/Uxdnph9oV8hIF/LCDW6BTCzMF1hVRF8OzXWejg/xGc2DKJVlHxWkn4LC -bEyRTwpUd+MT+pnsj5zkzz9KCqOS2fWL8GLoY/1FAoGAVGtqUcd+4tkLuH7qyBsb -qJcGZ4faaveyFXyukUpGSr15OzrXgMaVLeeSl3bPJAQJ41wRaHcKZyFagleA0WZC -1acDGiBWkMLmlzEhPqBPQUP4B0GSSDmsHI3Bpg2+XUWWZUu3MQzILfByyroO8Fp8 -Gn4jIJgewFVy8hizIt7sRyE= ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa.pem deleted file mode 100644 index ffda4f2e40..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDDzCCAfegAwIBAgIMWYGU7zoymvg+Z63iMA0GCSqGSIb3DQEBCwUAMCMxITAf -BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzVa -Fw0zNzA3MjkwOTAxMzVaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVz -dCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOMuUmmLJ2pQ4fYj -EfuIj11TMnG8dqScapc/yU9zHCDn5DQJGOa/X5jYoJX4k2PbXk5bbck2caC4J7/G -WRugGc4KcOVItAmnxbVzJqtpsdRrVUvTzqcvaSZNHEgSWP73WmlACX6xIHRyBtr+ -Pwpig73eZkOVcGOsbsWliffVQ0f0fz/AGsYh5IWBNlIfBOWwOEBDJavlsYrVGAw1 -MuXxknybsjXFRqyFNPE6Shd3W3eteo+FOvQsyopmX6FcP+EOaFQxSQ7yR+xNsreC -yxi40hPfswO6TihN9hLdVt3C+OHDJw2wR2xM+SwsW8Hu4jEi21uakQl846z+XdgV -o+D3v3cCAwEAAaNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwQA -MB0GA1UdDgQWBBQrQlWadXqqzBV+2iw7BZXrvFHaQjANBgkqhkiG9w0BAQsFAAOC -AQEArUVXn2oI5hgSkDwDrhQFijHBT3d37SX0eji//lkLPTHSEXHv+6kAoxVKmSnG -hAAxuLKxtAjNlXi4FAxSpQPX17/199JHUd/Ue63Tetc8DfaFc6MaFNxWkNrY6LUX -bEhbI/vB1kBu7sc8SW7N694WSpe/OmD/lB6GYW6ZV68hrTB0gfmfB6SfcGbQ69ss -YUsNU7Yo1GZnJTz0FZzybjx/T85NnVvpfVqjjaGRFeSva9GAU+5uO5DdbSpbkCcw -6QFFfvcJ7VD6qFqtLG1TfcdOuCaUB8cmDhDtTB/Ax96wGdJvp6ca3YaboZag9HOZ -4csuzHIJQyd5HT6xLbUBeskgWw== ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_256.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_256.pem deleted file mode 100644 index 0e5966a77c..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_256.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDpzCCAl+gAwIBAgIUIyISxx5PRQREJEmN08CNp74twmcwPQYJKoZIhvcNAQEK -MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC -ASAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy -NDA2MDY0MloXDTM4MTAyMDA2MDY0MlowIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl -IFRMUyBUZXN0IENBMIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEa -MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIBIAOCAQ8AMIIBCgKCAQEAt7Sa -TS0/CLgeVdawsrfQM8y73lYkBB1zrGoy268mT++x1hCQedyJrGDjlFQZBFQX6hgO -2Ua+YJ/mM/9uYGo1xi3dBoLVgMmIBy8nSwQTuktpks68AL5CLOI1jWARZjwk+DoT -rUnnEsrGKlKE7T19HgbepGTWFxSxGWOg4XxJ00FzKfi1deCT+uPfO4J3XoPL2lIm -68MgExFt6aql17bDoaUE+m7uTzlSTRj5q4dKTtk0p8Tf9Ru2V3F/w8hPLADAbuh0 -NeJxH+/GwWJ6ZefJx0IUXxbBq00y5eJ8OKIhAmmjgfTIeEhYCl2ZhfXmKje+I+X/ -Fbo5Qqyd0BF+5CtV2wIDAQABo0MwQTAPBgNVHRMBAf8EBTADAQH/MA8GA1UdDwEB -/wQFAwMHBAAwHQYDVR0OBBYEFCEaiLbeA8ABgKrbcIiZpo8XzqpsMD0GCSqGSIb3 -DQEBCjAwoA0wCwYJYIZIAWUDBAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQC -AaIDAgEgA4IBAQCpl2XsRpIAR5cD0YRWOg2hNg1+oMNAj1wtuBOiaD84doN07sFl -ta3lnweoA1rZZNLtAOUu5Fs7FwetzhuA5+iHVRAU8qqoSojP5fZgTriOFK/7rEUu -ZTxL1IzXEuiQO2iCkTXslg5HP5QAsYV4iqGe6erSAgzD5tP2mpgQJudUiuvCdWGz -lgroWjDAklQHIXITCrLgnMieYIbILZXXMZLfIrMfZOPCd7IDPTjb8/k1j3N4Wuld -qZWSPeNhuUUTKniXy4GVBE1obMDyBRarR4jkeeKdsuYbdf0oSTMK/rcuZMrZfjAR -uH3sqZ1Ovw4rbYzjk/ET4QlolFnFexgZ5QcH ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_384.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_384.pem deleted file mode 100644 index 5e8bb89007..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_384.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDpzCCAl+gAwIBAgIUWplyXkxgG/630tCmc0xgpFKshNYwPQYJKoZIhvcNAQEK -MDCgDTALBglghkgBZQMEAgKhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAICogMC -ATAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy -NDA2MDY0MloXDTM4MTAyMDA2MDY0MlowIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl -IFRMUyBUZXN0IENBMIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEa -MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgKiAwIBMAOCAQ8AMIIBCgKCAQEA7m3A -yUTdlPhAr5r0Qz54RWFfahUjQvT4oMLragquDEOn3OmszkLEyPVM3mxSS+XTK0K4 -+eVcX1xTLw/39T0E7StQyatrdC1LQnFXegSDOJf6WyJKFNIN3VxmySV94/8FhALq -PIKXRQ98s3GOfzGNtetetg2Rm11RvPfigaJfRjXPnmTEPGVj9v8VsOcRSfrBzNlU -m/gTPZXO9H9YZiPNvBGv4T+v2F4Whc19t39Z+v8p5u9PbmvvsJHvgWNvsgwrR6Yh -9x9L+x3nb/hvDmqPilRfS6JtNiC7uhGHBvONlWoQtyeOHQK0zh7CCXPEtl3HX+Im -vU/NerDFwNaCH9QuWQIDAQABo0MwQTAPBgNVHRMBAf8EBTADAQH/MA8GA1UdDwEB -/wQFAwMHBAAwHQYDVR0OBBYEFKnwXW9hoPAB6HSyWn7UEUMcKonnMD0GCSqGSIb3 -DQEBCjAwoA0wCwYJYIZIAWUDBAICoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQC -AqIDAgEwA4IBAQAwyVTh4HCTN1FnLLY3iUSEWHNqYNCdAmP/qMYDgwZAdS3hRHEt -9mE0a0/52bYEY9QMol4eGIGKjiXuxZpJKjK2WBgnUvyV7fEDcKy8UqB+ULFGNRxR -9tR3MRMSFrQl+W6q2ABPwmqvAtJHSiIRA30ZuwxSyX4ulzxThRYnkfp2eSKKHp2x -J6xUEnN5vnoXvpa1sFccKorPITF0r8OWzIi+GGzHz4Wq0Fqov4TOhnU/u6Xqw0xX -CXshQ0pN6+XWT0Ea0OuZk1/cKy2nyk+oHSmo/HhKJ8lGc3P2dLgCV9jjbM2WYCHs -O2rKlDWMxkd1Zx/I0ZzUI3Km+Qb8a+88KOtg ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_512.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_512.pem deleted file mode 100644 index 690d25654a..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-rsa_pss_512.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDpzCCAl+gAwIBAgIUJ6gfVYLgx1UAxuxNNmuo6mUQP/gwPQYJKoZIhvcNAQEK -MDCgDTALBglghkgBZQMEAgOhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIDogMC -AUAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy -NDA2MDY0M1oXDTM4MTAyMDA2MDY0M1owIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl -IFRMUyBUZXN0IENBMIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCA6Ea -MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgOiAwIBQAOCAQ8AMIIBCgKCAQEA6h/8 -MF//GduaMEYb+jTea1ZE/6EG0Vxqp7n4fay8Dyuc2JuQLTGgQcd0cwG66uTGnr+b -QWIHVLRTy6LXi986pG22lXEyIe48mp2bm03V79NwhLrCDqcvB6opaSBG+NqHSeDP -ANPAJqBxNQAGRVZWj5NgdUL1eGHurfvSON55LZtbB+YrvrWop5Xfnyoan2JVJjVT -iDOMHPmT5upFOTwJeuFKQd6mOP1W5NUN7v8ogdywyqmEQl96aHIyHgVPBzZYcXak -yLPSGD7IPXsuGESM3N+0U1Ry7ngRaJSS9t5BWxzo3BtB/o+0fY1ZVu0HliC9CxjL -P0DTAmJ6UC5SZmiroQIDAQABo0MwQTAPBgNVHRMBAf8EBTADAQH/MA8GA1UdDwEB -/wQFAwMHBAAwHQYDVR0OBBYEFKVY4bgN1p+8NOXoPdj6DKWDscBFMD0GCSqGSIb3 -DQEBCjAwoA0wCwYJYIZIAWUDBAIDoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQC -A6IDAgFAA4IBAQAIi+3zyTk8NR5w5a109GHz4wpACxafirJkr6wkAIzzU95OKLiw -fogX/ECW9UaIfJMHrnEADhKcMSRd7HcNpDg/E8GKr4IhtbkFhNjAjE10Ham6fLzw -SgvN34QpDT6iVP83Cx+SzlSDQLjq4es8diZXP39C0T2a9iskDXMF+ZcaZMwd1TLe -MI7HMIiLCoyVP7LOI39e6E0ho0W0FRrMtZuXIIvZjwkb+SGhAmlJiATmpLmtzuoK -oI/UE1gNglJFjA6HWHStHd7hEJrtGHNa061G130kOFGIJhGf8fHiGaWvWYfZ5/jc -egUo5t7rA6wg6KPwA2JjH2jxUp3NUzTRzV72 ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-dsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-dsa.pem deleted file mode 100644 index 782fe4ef98..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-dsa.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEpzCCBE2gAwIBAgIMWYGU8Awsp0jsH7C+MAsGCWCGSAFlAwQDAjAjMSEwHwYD -VQQDExhCb3VuY3lDYXN0bGUgVExTIFRlc3QgQ0EwHhcNMTcwODAyMDkwMTM2WhcN -MzcwNzI4MDkwMTM2WjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVGVzdCBDbGll -bnQwggNHMIICOQYHKoZIzjgEATCCAiwCggEBANIzNyBmt0q+w79byPcXWN5ETG80 -4OJFYhOAdUl5gv90ACofvnojmLaOu2AnbwEUVMlV5xBdeuanPl0ESmH+yFoDwwwA -3uNhPutZ91Yml5PPpks48Fj8IV8Mnnp+0LGC1Ug9IgeXkPSrGm1aIJjMNvK3xc7q -MGI8aeL//pFSoH4vNvRqi+QzZBW/FaXeWdRvkT0c1YACvdl0rnF3SPbi7bn45ceG -GEenq6dFjbZZG1e+bZyzd8/UGO01BLZxftG0IiWWqKi1BlP1Lgc8LyUIrza+Ie1a -vLk0jbjuhhQsYebpvnO84uhDOdavpxnHCqcEm8sElRctIFYY1xB3PD3bG8ECIQCI -pXijcj1zNsncR7roSHNeer5B3c1N92F2hTLedYbzwQKCAQB7PCrFF3u7oJq/64EL -8EMlnv81vgWnet/Ux5zzY2OEdtDOOR4YnrWXcs/rsjio/blHTf/CeMX3pTVV8GE3 -f0C4+Hx6mWb+okL7UgEPmen8dGHD//yn3e6wYBG7aqd8DtBkicmgd9eKlY+xgbww -rDN8dz9RbJ9oAOXbzASw1GvLbZ6UWsMTZ7WWoAbLOf+0gfiA+eRjC9x0HbaN0jLy -ztQJhEvWqGSynNfkB2xopRtoyYCvtEVDtQEC9H6PtIG9oKyiwLAtVOmbj6pf1/V3 -ZJJEPiFfKD8CHcS8Z87JXMbjTolIf1A+/Bjn+FKOS2zdIQ+rAOFdptUyU68CWkAV -6trbA4IBBgACggEBAKprryuOBKnrY00s9y+HM6UMvS/exCjzmQrlQ9rQMuwVG+lz -GKKWFu7shIQqneaNNUuNAXRK0NABkPjIBLfvdDmkXweU4/oi2mZQaIUPEWceHrmL -FliI3+VtqC3rPvXzVGvbBdUvqSCJrYD84EK6Ahs3LGIB0OC1Wldi6x8FtKewbn7B -23twnAsvNx4QzFt7W6j05EorWCvs+cwbTttptRiruNcPYLQweMIrcNvzApq+sgoW -traZdTS7rBklrgfi7/4JJNN+jV21XqDQYGugN8PnbORyuETGHEf1wk4HFL7eweHO -4KzTpaNeqsJfilOe9PV1SgDhv9oyKj6957xK1WSjdjB0MAwGA1UdEwEB/wQCMAAw -EwYDVR0lBAwwCgYIKwYBBQUHAwIwDwYDVR0PAQH/BAUDAweAADAdBgNVHQ4EFgQU -iU8ApXTLLe07mPDvg7O9CsNwS0EwHwYDVR0jBBgwFoAUAOVmarDrz1YtyjvnX4C9 -cDcXlagwCwYJYIZIAWUDBAMCA0cAMEQCIGlXUYEccybo2azMk3f6Zl6bpxERr/FU -+/2k+mbBeo7TAiA9/aIWf0bdED8AH0KNKFfcpKMsvnJHTCOPr7fBPU84lQ== ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdh.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdh.pem deleted file mode 100644 index a3b1b346b9..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdh.pem +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBtTCCAVygAwIBAgIMWYGU7ztLkMAhmmRDMAoGCCqGSM49BAMCMCMxITAfBgNV -BAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzVaFw0z -NzA3MjgwOTAxMzVaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IENsaWVu -dDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLRekMsBjYf7GXhy7ZqnX9lAvXyL -sC9VfMUIcfGNluSN2C3O9fjqN5FMary/eU49ij6L2mRUjZz6kQK0ZM68pL6jdjB0 -MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDwYDVR0PAQH/BAUD -AweIADAdBgNVHQ4EFgQU7ZRZoI8czdH0szeb+t3EwaXNUG8wHwYDVR0jBBgwFoAU -0ma/FGcW5gGlL//B26Xmj0JISecwCgYIKoZIzj0EAwIDRwAwRAIgVij5xSPQrUgo -VsbOgVdLGLJeiHo065dtdt87PSCJtusCID+c1QShYOgBkI/Bv3gotVhTP4mtjhp2 -2v442jTclSfT ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdsa.pem deleted file mode 100644 index 261db1ce00..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ecdsa.pem +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBtTCCAVygAwIBAgIMWYGU8A09KQDW+svJMAoGCCqGSM49BAMCMCMxITAfBgNV -BAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzZaFw0z -NzA3MjgwOTAxMzZaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IENsaWVu -dDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLenUtWqfkGp0iFncfdsvBsfaXHv -Ne5gV7U/zUO0OQ71V1c8WpOx9f0rhpOSCN9GCqQNL3yd+nWf+pu40JMMrZKjdjB0 -MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDwYDVR0PAQH/BAUD -AweAADAdBgNVHQ4EFgQUtK5VEuBZJUDbU8gN9dleZeXDf2swHwYDVR0jBBgwFoAU -0ma/FGcW5gGlL//B26Xmj0JISecwCgYIKoZIzj0EAwIDRwAwRAIgNnj/nlAbCd0R -fCG6n5s5Sdsh4dR7KRhncCj8wjGYZMYCICUXU05FIr3bM9bELX2We3rv1ookK9rC -7ZVjCgt7YbHi ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ed25519.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ed25519.pem deleted file mode 100644 index e419a7b32a..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ed25519.pem +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBfjCCATCgAwIBAgIUO1XUdvEupfCQwrrPHXE28BoO+TswBQYDK2VwMCMxITAf -BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xODA4MjMwOTI5NDda -Fw0zODA4MTgwOTI5NDdaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IENs -aWVudDAqMAUGAytlcAMhAJe53GEkXEVP7L7FbVZ1BCGvvIZac+6k41CncucJ3BJ2 -o3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA8GA1UdDwEB -/wQFAwMHgAAwHQYDVR0OBBYEFNo2OYJ4FLTBdu5lozbqL2aAXsqzMB8GA1UdIwQY -MBaAFOp5vj76ByEwboduoHWAWzajnM1mMAUGAytlcANBAJrgAof3yetck8DDLNTG -dwLQdCNjEg5/xgvKVcTPuUC4rirgCoYtPY36lfPhd0v5Ev8v1Jjrxshyi/yVCsLb -mQ8= ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ed448.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ed448.pem deleted file mode 100644 index e7442fce53..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-ed448.pem +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIByTCCAUmgAwIBAgIUbl3fESW+2UIW9SzaxnhuhiGygLIwBQYDK2VxMCMxITAf -BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0yMDAyMTMwNzMzMDJa -Fw00MDAyMDgwNzMzMDJaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IENs -aWVudDBDMAUGAytlcQM6AFbp8qV7nVhmDWZUsXTfqU8aOaP4XSmGUnKqdlQPR5O4 -3lMlUukbrclV5v5+b4Z8Qy4Abe+PZU+AgKN2MHQwDAYDVR0TAQH/BAIwADATBgNV -HSUEDDAKBggrBgEFBQcDAjAPBgNVHQ8BAf8EBQMDB4AAMB0GA1UdDgQWBBSlCh5L -f6BeaHQxiEe5B9ZjbbCKODAfBgNVHSMEGDAWgBS+BSv++BEWlTJ53q6rwnDLVnR5 -JTAFBgMrZXEDcwAC3Tugpa+pS0ExsLdh/6GsVAVvhYICLc+tWGExM+f3gzFU7yvO -uM7xwRR78ItbQyRkfLeL+6GYGgDzhjwQ6XzilwGibLtGuooLAMo3uOgW8N4mQslf -GqEW2V3VocPjmNYanAMJnTd68t5Wc0ow153cNgA= ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-dsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-dsa.pem deleted file mode 100644 index fd1a45b906..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-dsa.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICZAIBADCCAjkGByqGSM44BAEwggIsAoIBAQDSMzcgZrdKvsO/W8j3F1jeRExv -NODiRWITgHVJeYL/dAAqH756I5i2jrtgJ28BFFTJVecQXXrmpz5dBEph/shaA8MM -AN7jYT7rWfdWJpeTz6ZLOPBY/CFfDJ56ftCxgtVIPSIHl5D0qxptWiCYzDbyt8XO -6jBiPGni//6RUqB+Lzb0aovkM2QVvxWl3lnUb5E9HNWAAr3ZdK5xd0j24u25+OXH -hhhHp6unRY22WRtXvm2cs3fP1BjtNQS2cX7RtCIllqiotQZT9S4HPC8lCK82viHt -Wry5NI247oYULGHm6b5zvOLoQznWr6cZxwqnBJvLBJUXLSBWGNcQdzw92xvBAiEA -iKV4o3I9czbJ3Ee66EhzXnq+Qd3NTfdhdoUy3nWG88ECggEAezwqxRd7u6Cav+uB -C/BDJZ7/Nb4Fp3rf1Mec82NjhHbQzjkeGJ61l3LP67I4qP25R03/wnjF96U1VfBh -N39AuPh8eplm/qJC+1IBD5np/HRhw//8p93usGARu2qnfA7QZInJoHfXipWPsYG8 -MKwzfHc/UWyfaADl28wEsNRry22elFrDE2e1lqAGyzn/tIH4gPnkYwvcdB22jdIy -8s7UCYRL1qhkspzX5AdsaKUbaMmAr7RFQ7UBAvR+j7SBvaCsosCwLVTpm4+qX9f1 -d2SSRD4hXyg/Ah3EvGfOyVzG406JSH9QPvwY5/hSjkts3SEPqwDhXabVMlOvAlpA -Fera2wQiAiAFTXpu+duj6u8P3wMsd7fOOStBEV6hPUh+RLdOjGslXw== ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdh.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdh.pem deleted file mode 100644 index 2a28a9f102..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdh.pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgAuAT+3hSra1qS+XA -iAUT+W6MSZ2rnoeQGjFe6FX7z8qgCgYIKoZIzj0DAQehRANCAAS0XpDLAY2H+xl4 -cu2ap1/ZQL18i7AvVXzFCHHxjZbkjdgtzvX46jeRTGq8v3lOPYo+i9pkVI2c+pEC -tGTOvKS+ ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdsa.pem deleted file mode 100644 index d9aceb301e..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ecdsa.pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGUAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHoweAIBAQQhAJxpy2FD0ePz3c9j -6fVPTSpHAmdiRIqnskVP0PjiBAEvoAoGCCqGSM49AwEHoUQDQgAEt6dS1ap+QanS -IWdx92y8Gx9pce817mBXtT/NQ7Q5DvVXVzxak7H1/SuGk5II30YKpA0vfJ36dZ/6 -m7jQkwytkg== ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ed25519.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ed25519.pem deleted file mode 100644 index a08f3c44a8..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ed25519.pem +++ /dev/null @@ -1,25 +0,0 @@ -Public Key Info: - Public Key Algorithm: EdDSA (Ed25519) - Key Security Level: High (256 bits) - -curve: Ed25519 -private key: - b6:9d:94:c8:9d:c9:7a:5d:b3:58:92:af:67:8e:c2:bd - 63:c1:81:55:3d:b2:5c:e0:c8:91:f1:40:34:5a:6d:b9 - - -x: - 97:b9:dc:61:24:5c:45:4f:ec:be:c5:6d:56:75:04:21 - af:bc:86:5a:73:ee:a4:e3:50:a7:72:e7:09:dc:12:76 - - - -Public Key PIN: - pin-sha256:aWaJiTGI21SUAEt2VgTiRGAnczFMD8axA/4hrKMpfno= -Public Key ID: - sha256:696689893188db5494004b765604e244602773314c0fc6b103fe21aca3297e7a - sha1:da3639827814b4c176ee65a336ea2f66805ecab3 - ------BEGIN PRIVATE KEY----- -MC4CAQAwBQYDK2VwBCIEILadlMidyXpds1iSr2eOwr1jwYFVPbJc4MiR8UA0Wm25 ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ed448.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ed448.pem deleted file mode 100644 index be3c8638b2..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-ed448.pem +++ /dev/null @@ -1,28 +0,0 @@ -Public Key Info: - Public Key Algorithm: EdDSA (Ed448) - Key Security Level: Ultra (456 bits) - -curve: Ed448 -private key: - b1:9c:73:a3:54:a0:33:05:b1:b0:ad:6f:1f:c0:ad:14 - db:d4:55:bb:eb:fa:d4:33:8c:e5:bc:68:03:d1:ca:25 - 19:75:0f:94:4f:e3:fd:3a:62:b5:77:23:d7:b0:d6:75 - 92:9c:98:86:2a:08:c5:b2:6e: - -x: - 56:e9:f2:a5:7b:9d:58:66:0d:66:54:b1:74:df:a9:4f - 1a:39:a3:f8:5d:29:86:52:72:aa:76:54:0f:47:93:b8 - de:53:25:52:e9:1b:ad:c9:55:e6:fe:7e:6f:86:7c:43 - 2e:00:6d:ef:8f:65:4f:80:80: - - -Public Key PIN: - pin-sha256:4r2UflhSms9yYj4SMc7tE9lkFxXR/ziPw1bhZGfI/qw= -Public Key ID: - sha256:e2bd947e58529acf72623e1231ceed13d9641715d1ff388fc356e16467c8feac - sha1:a50a1e4b7fa05e6874318847b907d6636db08a38 - ------BEGIN PRIVATE KEY----- -MEcCAQAwBQYDK2VxBDsEObGcc6NUoDMFsbCtbx/ArRTb1FW76/rUM4zlvGgD0col -GXUPlE/j/TpitXcj17DWdZKcmIYqCMWybg== ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa.pem deleted file mode 100644 index d2d19bf0eb..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDP8Yo5l5ez1W2c -EgROodwNqRLL+ALvOorSEuKm+xiTbzmdqcMdtvwDhq/yb7GBhpzrFcUOt5hPcQc9 -pYz7Khg4UHiw+wqbV2QHMGGupNs+kvdUndBgjToD7hYlyhV7fUovNrjQeNq+5Bxt -OHsZmO7ilHTKdSMVG2eO5XgZk+1uSOuZStmnMZM0Sum3TxK5zRs2beLf5OhNDqMH -+hJVH9FL4bF9LaxQfTvMrwnIqgEKBlMO29cs1gPW1otQEFD4MefHhjK0YEF3xZ7r -hnnx6lPv5wFQLeaRx1NBqgdPY3L9ZSUkKQzLQgWubbKK1b8vDookicdebSMjTrVX -HPcv6B93AgMBAAECggEAQZZe0cGFwNwdoW9xWlflL43Xduw4CLq/VHlOcfqbCs23 -L4p/F11C6d3Omzotk7wgvGl2aSjxaoUtEn2oFQR29TQ0jSXxd4O98iKJfOtUl80F -I/RO6FVDKkArTioKUpP3FSM+ccrcu/75FF4PPcil+GN43u7JbPvi0wh/tBmbdwAJ -aK2wskjaJAbQz8lnIEVZkz3uYLc32BD2FoCC+HyIPAYFbryus1m+TsXWVk3rDKst -85x4jadS7g3a1OvsDXqj8lHlom9dlxcMqTtSaJr1XJgMwztnc0FVuMOqs0MZpa2U -Mu/0EJQYLW98a1bDkXbLtbXjx2gWpO64gZqQn6aYAQKBgQDfgA2xVv7nmVuOkojJ -rJTS4muPG1BhXY7/MD13eopmjPk8rpVZt97RHfMHp3CCzuQVy9g398kBvCBtO9Ba -3/ab9ZrNMN3Rwm7vwUa4TBOvN17bRSeIPUenJJ42SDM2fmN4m8c91iiSyb9AVPmk -zSksQYtZr/8m9mQ0VOguzOxcAQKBgQDuLmDFSYDl4DO4cOZANpDYk1MkCtrW37xM -IUS6vnPFkRg3t57Og9tddj81VoMNeakGRvWmcDA1yuVdo52pqjlSXzQuSYAh7ZTC -KMzesLt1uilXQW2MNNvmZMjltgkHMiuY1cIvQLFC0o4AI5DLR5+5/w/lm/Qe9pfU -++B3XVVbdwKBgF5Yfu86ixYW/bg8kTOY/6XZ4I+jdxXy2ZdNtNTHzL6nidqc0/zw -ikV6QAoeG3eMgGnXB+nwVlC+Km4SDs0dt8t0LSmrFCgkzJG24/SOYMzZMdib46k2 -PRYIdiTx63R4e+MA12V6DtyP/4TXmh6AYH4HGRz+F1ZKMliI8w42gRwBAoGAN9sG -dJ21LbNzTZikVoC1XSTHhZdKFMPpO409ufF54uYQ4Ngd1N5VLkjRr+d22k0il0dC -ymJa2/KV8WyyR5yUzr1m1kgEVXCKxzGcQcj+XTBoC39belrXCuOtvTkASwC3+qJ+ -ZGhuaXZJOL0ecp18Vrj6+GSnTi+UEa1zyWpI3ycCgYAxJgHa3CGaGqbdzgkRTnWd -FMptvqaNd4POyy/TJ1Jf0ydZwgRpRMZTv8hJKZHh4lUkSOF6bE0qDhrxzUjpI9GT -SGYYX27pfVThoM421S7bvgVmneeLSz1S50Hg0jawHA2ixjne/7kQcMjQzYjjMfDy -FgVOrBIQnpUddGEpu1z5pw== ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_256.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_256.pem deleted file mode 100644 index 86f66f7d25..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_256.pem +++ /dev/null @@ -1,138 +0,0 @@ -Public Key Info: - Public Key Algorithm: RSA-PSS - Hash Algorithm: SHA256 - Salt Length: 32 - Key Security Level: Medium (2048 bits) - -modulus: - 00:d7:7a:3a:01:8b:5e:59:0f:10:7d:95:5c:ce:c6:ea - c8:29:2e:75:6e:fe:6c:f9:83:d5:3e:72:6c:fc:56:95 - 43:d4:62:34:df:05:7c:b3:b3:a6:4a:37:ca:b6:e0:23 - 44:19:fc:2c:ea:cf:fc:f9:26:1a:ac:5a:8d:83:f8:4f - d9:0b:ae:fc:e9:9d:75:37:2d:a4:93:02:5d:69:10:df - b7:7a:4c:b6:05:64:73:46:45:b2:fe:a4:b3:33:9e:68 - 6b:14:35:8e:ee:df:bb:e0:77:23:76:b8:6e:fd:fc:f2 - dd:02:59:5e:dc:a1:b3:5d:93:c6:2c:e2:4a:85:21:7f - ca:59:36:e8:77:dd:fe:cd:fe:f6:b0:96:fe:14:6a:5c - 68:4c:cf:bc:fd:fe:ec:e3:2f:51:10:cf:46:db:1d:3a - 3d:cd:87:ec:67:4a:7d:20:5e:79:6c:ea:d3:24:d3:82 - 05:bc:d9:79:e5:cd:df:6a:bb:62:9b:20:b3:35:34:61 - ae:69:a9:ab:b9:b6:27:ac:7b:33:f5:be:df:9a:b4:12 - 68:06:55:79:b3:ba:52:f0:91:90:69:b1:f1:5a:11:e3 - 8b:de:dd:f1:99:ca:5a:ad:87:ba:65:52:27:a6:07:12 - 60:10:24:93:4b:df:12:db:49:0f:fc:21:ff:9f:e6:92 - 75: - -public exponent: - 01:00:01: - -private exponent: - 3f:9d:f9:84:3d:36:84:ca:ba:ce:a9:0b:76:8d:2a:02 - 20:8e:73:e3:6a:40:98:46:40:ee:27:f0:5f:6b:dc:b3 - e2:ff:7f:a6:9c:c3:1d:77:1b:d0:6b:ba:70:d5:a9:f3 - d0:4c:30:a2:be:f7:6c:43:c0:ba:44:1d:e5:e9:a9:01 - 66:be:aa:32:fa:e7:01:7c:7b:4b:5f:f6:5e:2f:ba:2d - 3c:71:6b:88:1a:09:22:a5:2f:5c:99:19:c3:52:b0:77 - 74:c6:ff:45:2d:4f:15:cd:76:ed:f5:33:e7:cf:07:91 - 12:c1:7a:0d:5f:bc:4a:13:77:fe:06:6d:83:f2:c8:fc - 55:3b:f2:3f:9d:48:4b:b5:1b:22:ad:a5:7f:c6:29:b0 - 05:b8:e2:82:5c:b9:66:48:8e:05:d1:5a:ea:3d:63:c7 - 94:81:0e:c3:0a:33:d2:a8:a5:2f:a2:83:26:59:19:1b - 89:bc:8d:02:e1:c7:0c:53:64:6b:a2:d1:8b:ef:70:d6 - d5:94:bb:df:5b:49:4b:a5:cf:d4:df:0c:0c:ac:ed:8a - 39:61:b8:15:cb:64:b6:02:6f:21:e2:46:d6:c9:d1:d8 - 62:ca:1b:f6:3f:3b:74:c0:5a:ca:cb:a5:c5:aa:80:89 - e2:66:a8:7a:57:61:5e:5d:e3:0c:b2:4f:48:01:18:21 - - -prime1: - 00:e8:cf:45:ff:39:35:03:62:2f:2a:63:b6:14:95:22 - e7:30:6f:a1:d3:65:f1:8c:0e:13:a3:67:a2:1a:86:24 - 70:1c:97:64:15:9b:12:1b:59:66:de:05:42:6e:fe:ee - 77:a0:bd:1e:8c:5b:de:45:c7:4b:05:ff:ce:39:45:ee - 96:15:4b:96:df:b3:20:62:0c:90:bd:f8:1d:0a:ac:83 - 47:34:cb:63:0e:cf:1a:b9:20:62:59:1c:7b:a2:52:b0 - 4d:d7:c3:d5:90:32:9a:a5:3f:26:d6:66:f9:45:16:7d - a4:4f:2e:4d:87:4c:d3:8b:b4:00:5e:d8:5b:29:cc:a3 - 3d: - -prime2: - 00:ec:f0:f9:c9:43:a9:c5:fd:56:bc:57:d2:6d:18:9d - 90:bb:17:74:19:80:1f:e2:21:b9:b6:13:6b:b5:02:62 - b3:51:97:4d:29:dc:85:ee:bf:15:98:f8:21:78:00:0f - 3d:78:94:23:27:2f:52:a8:35:82:02:73:44:21:07:c6 - ab:61:fc:d1:1f:67:8f:43:5a:33:fd:ee:fe:d8:5c:a1 - 1e:b0:7d:6f:0b:6f:d6:47:25:1d:71:5f:b8:77:2f:8f - 4c:6a:0f:8e:03:ce:f3:cd:dc:02:fc:21:c6:ce:10:07 - 0d:ee:1f:d1:82:94:21:41:10:9a:76:62:80:cc:f1:3f - 99: - -coefficient: - 4b:89:17:37:c2:77:4d:99:ec:95:4d:d7:7f:c7:0b:8a - fc:67:ee:59:0d:66:7d:5c:33:36:6d:90:00:6e:3b:d4 - 79:9e:94:05:61:e6:e5:8d:f9:70:3d:7b:4d:be:7d:7f - 0f:ef:e8:e3:93:1e:42:da:d1:9f:12:6b:51:d9:7c:ef - 5b:c6:f1:e9:ab:9f:87:6f:d6:eb:29:4d:51:2b:f9:0d - b7:e5:96:fb:c9:4a:21:a4:b0:4a:af:b3:2b:3c:41:45 - 19:d5:3d:cb:fe:15:4a:f7:a4:52:e6:d6:0c:c9:cc:5b - 62:fd:b0:1d:ed:98:13:0f:9a:27:92:5e:a8:6b:bc:b8 - - -exp1: - 00:8a:f6:c6:32:5d:24:5e:bb:a9:a9:a4:d1:17:a2:19 - ae:64:04:0e:55:50:21:89:57:11:b3:d4:f5:36:dd:e1 - 3c:26:64:db:71:e6:19:3d:c7:f4:96:0c:0f:a6:8f:77 - 2a:63:00:e0:0e:29:fc:18:2c:a8:84:91:37:b8:8a:1c - aa:eb:55:2e:5e:a2:de:6e:88:4f:91:85:5b:58:76:b6 - f9:b6:f2:bc:53:27:9e:2c:e8:be:ab:b0:4b:c0:0d:99 - 7d:2d:90:90:96:bd:0e:00:1b:1d:04:97:7c:ad:17:8a - b1:9c:2d:e8:4b:1d:b9:9c:47:3a:7d:62:a9:af:de:9d - 85: - -exp2: - 6c:52:0a:4f:b9:b0:3e:c4:7f:c7:a0:fa:a1:47:74:99 - 3a:ff:10:e3:ab:90:67:e7:f5:27:c9:1f:1f:64:54:cd - 17:ca:ec:ca:eb:77:0b:5b:ae:3a:fd:8d:07:78:37:7f - 69:c5:87:80:9d:80:d3:47:8b:05:25:bf:0a:be:ac:53 - a3:7b:59:fb:5a:73:c3:5d:d4:91:0d:96:d2:41:1e:a3 - 92:19:f6:0f:2b:74:b1:97:c5:2b:14:90:97:64:55:c5 - a0:63:36:10:85:a7:2e:00:9c:18:ba:34:51:f6:3f:d3 - 5d:7e:8c:60:7e:e9:e8:fd:f7:2f:91:fe:c2:32:b4:59 - - - -Public Key PIN: - pin-sha256:V1OZkBgmgMWlbg+RZ0Dx3sw/b4WHbrN4NHttN6QbsGM= -Public Key ID: - sha256:57539990182680c5a56e0f916740f1decc3f6f85876eb378347b6d37a41bb063 - sha1:028b616b894849cbca9103fcf919fdda20ca101e - ------BEGIN PRIVATE KEY----- -MIIE7QIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3 -DQEBCDALBglghkgBZQMEAgGiAwIBIASCBKcwggSjAgEAAoIBAQDXejoBi15ZDxB9 -lVzOxurIKS51bv5s+YPVPnJs/FaVQ9RiNN8FfLOzpko3yrbgI0QZ/Czqz/z5Jhqs -Wo2D+E/ZC6786Z11Ny2kkwJdaRDft3pMtgVkc0ZFsv6kszOeaGsUNY7u37vgdyN2 -uG79/PLdAlle3KGzXZPGLOJKhSF/ylk26Hfd/s3+9rCW/hRqXGhMz7z9/uzjL1EQ -z0bbHTo9zYfsZ0p9IF55bOrTJNOCBbzZeeXN32q7YpsgszU0Ya5pqau5tiesezP1 -vt+atBJoBlV5s7pS8JGQabHxWhHji97d8ZnKWq2HumVSJ6YHEmAQJJNL3xLbSQ/8 -If+f5pJ1AgMBAAECggEAP535hD02hMq6zqkLdo0qAiCOc+NqQJhGQO4n8F9r3LPi -/3+mnMMddxvQa7pw1anz0Ewwor73bEPAukQd5empAWa+qjL65wF8e0tf9l4vui08 -cWuIGgkipS9cmRnDUrB3dMb/RS1PFc127fUz588HkRLBeg1fvEoTd/4GbYPyyPxV -O/I/nUhLtRsiraV/ximwBbjigly5ZkiOBdFa6j1jx5SBDsMKM9KopS+igyZZGRuJ -vI0C4ccMU2RrotGL73DW1ZS731tJS6XP1N8MDKztijlhuBXLZLYCbyHiRtbJ0dhi -yhv2Pzt0wFrKy6XFqoCJ4maoeldhXl3jDLJPSAEYIQKBgQDoz0X/OTUDYi8qY7YU -lSLnMG+h02XxjA4To2eiGoYkcByXZBWbEhtZZt4FQm7+7negvR6MW95Fx0sF/845 -Re6WFUuW37MgYgyQvfgdCqyDRzTLYw7PGrkgYlkce6JSsE3Xw9WQMpqlPybWZvlF -Fn2kTy5Nh0zTi7QAXthbKcyjPQKBgQDs8PnJQ6nF/Va8V9JtGJ2Quxd0GYAf4iG5 -thNrtQJis1GXTSnche6/FZj4IXgADz14lCMnL1KoNYICc0QhB8arYfzRH2ePQ1oz -/e7+2FyhHrB9bwtv1kclHXFfuHcvj0xqD44DzvPN3AL8IcbOEAcN7h/RgpQhQRCa -dmKAzPE/mQKBgQCK9sYyXSReu6mppNEXohmuZAQOVVAhiVcRs9T1Nt3hPCZk23Hm -GT3H9JYMD6aPdypjAOAOKfwYLKiEkTe4ihyq61UuXqLebohPkYVbWHa2+bbyvFMn -nizovquwS8ANmX0tkJCWvQ4AGx0El3ytF4qxnC3oSx25nEc6fWKpr96dhQKBgGxS -Ck+5sD7Ef8eg+qFHdJk6/xDjq5Bn5/UnyR8fZFTNF8rsyut3C1uuOv2NB3g3f2nF -h4CdgNNHiwUlvwq+rFOje1n7WnPDXdSRDZbSQR6jkhn2Dyt0sZfFKxSQl2RVxaBj -NhCFpy4AnBi6NFH2P9Ndfoxgfuno/fcvkf7CMrRZAoGAS4kXN8J3TZnslU3Xf8cL -ivxn7lkNZn1cMzZtkABuO9R5npQFYebljflwPXtNvn1/D+/o45MeQtrRnxJrUdl8 -71vG8emrn4dv1uspTVEr+Q235Zb7yUohpLBKr7MrPEFFGdU9y/4VSvekUubWDMnM -W2L9sB3tmBMPmieSXqhrvLg= ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_384.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_384.pem deleted file mode 100644 index 5cdedc5ad2..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_384.pem +++ /dev/null @@ -1,138 +0,0 @@ -Public Key Info: - Public Key Algorithm: RSA-PSS - Hash Algorithm: SHA384 - Salt Length: 48 - Key Security Level: Medium (2048 bits) - -modulus: - 00:dd:07:da:a8:65:55:09:ee:be:0b:c6:9d:95:05:28 - f6:d6:0b:d6:dd:31:7f:e9:b4:3c:53:0b:2d:ef:f1:bf - 92:13:14:9f:09:11:08:a1:d4:49:ff:8a:51:5e:45:62 - e0:63:7e:9d:18:68:bd:93:fe:42:a5:46:de:5b:06:d6 - 90:28:98:10:fd:ef:5d:0b:f9:a4:7c:f9:ce:68:2a:6c - 5d:78:5a:11:a7:d3:77:3a:49:c9:01:73:80:40:50:56 - df:1e:e6:21:d7:7b:9b:14:0b:00:fc:09:f7:97:9a:39 - 50:6d:ea:e9:c1:b1:47:ca:1a:c5:49:79:8e:42:2a:74 - e9:51:81:14:07:f2:51:59:72:b1:de:5a:09:72:de:77 - 90:62:e0:f7:96:64:07:7f:6d:83:c0:ed:82:6f:61:20 - 65:2a:09:ef:bd:8a:66:74:4c:2a:60:63:b9:91:6f:f7 - 55:aa:bd:d4:a0:a1:d5:a2:2f:20:8f:f8:19:45:60:93 - ba:19:2d:b4:eb:cf:8c:ea:1d:3b:2e:1f:99:82:66:79 - cb:c8:1b:1c:b2:a9:1d:bd:67:a0:39:e4:a2:59:14:67 - 69:0e:62:45:53:e2:8b:63:9f:38:cf:c0:dd:d1:c6:76 - b8:a2:87:78:08:31:38:28:e9:cc:25:98:69:fa:20:c8 - f1: - -public exponent: - 01:00:01: - -private exponent: - 54:12:88:b9:44:d1:f3:d5:3b:b4:7e:f7:b1:97:24:dd - be:cd:02:0d:60:a6:a6:de:47:93:ce:cc:ca:57:c9:e6 - 66:1b:91:e2:80:f8:27:95:f8:0f:9b:2d:18:0e:8c:6d - 8d:6a:bb:96:6d:40:ae:ea:27:af:76:25:5d:ba:5c:22 - b9:4e:1e:28:78:c3:8b:aa:89:46:80:3e:62:a0:c0:57 - 4d:4f:f5:27:40:e8:38:e3:97:f1:55:5d:93:18:fb:f2 - 22:6e:a6:b0:af:f3:6c:cc:42:b3:9b:96:f1:b3:57:d9 - 9f:f5:9a:b4:72:1a:3c:65:b2:65:20:37:5c:33:8a:03 - ff:ee:a7:73:42:38:40:0f:3e:af:73:c0:38:b0:21:c0 - 24:30:04:85:d5:01:0e:4e:4b:98:db:19:fb:88:39:de - c1:b0:ca:94:1a:f6:be:8d:c3:bb:b7:10:34:6f:53:c3 - 77:b8:ed:f2:b1:66:8f:f6:6e:a8:b4:d2:70:51:8c:b2 - 27:59:5e:01:9e:7e:b2:4d:a4:2a:7a:09:2f:cb:e7:f7 - d8:dd:a1:f7:97:61:cb:17:2c:5f:02:19:84:1c:54:c8 - 31:e3:50:b0:26:26:4f:7a:d9:c0:fe:4e:7b:b6:7d:b5 - bb:86:d9:67:10:47:7d:62:7b:e4:b4:9a:5e:c9:aa:01 - - -prime1: - 00:dd:5c:98:01:6c:e3:b1:f0:37:8b:d1:37:78:77:9b - 1a:f2:26:c2:b5:8a:58:9b:f0:f2:bb:cc:66:23:ea:8a - 9c:50:62:e6:d6:ea:11:ba:f3:ee:84:fd:9d:45:3e:ca - 55:65:11:46:46:1e:03:58:23:54:44:03:d9:85:50:43 - ac:97:27:bf:e1:5e:a9:17:a9:43:cf:e4:6e:d3:09:0c - 6c:11:74:8c:7d:dd:ed:be:96:bb:5b:d3:b9:c1:83:b3 - a3:70:52:d4:74:1c:d5:78:31:73:2b:1b:c0:dc:28:f8 - 51:55:4a:cf:16:b3:03:b1:58:d2:b7:df:bc:cb:6f:5f - bd: - -prime2: - 00:ff:9e:00:1d:18:dd:09:08:e6:20:10:b5:ea:c9:d5 - b8:17:2c:ce:c7:9c:d1:08:22:95:e0:41:1f:59:3e:2b - 91:07:80:21:7f:61:73:ae:74:24:c1:7d:a6:33:e0:e8 - 20:07:ed:e4:fd:d9:55:65:ae:7b:76:a3:c9:10:35:26 - 47:78:0b:d1:45:a1:31:dc:d7:a3:52:17:24:ff:55:4b - d0:c0:9e:12:73:f5:51:d1:89:ab:75:6a:0b:08:b7:8d - 9a:d3:d6:3b:c3:ee:e3:0c:47:8e:7a:01:4c:57:d2:cc - 7d:b7:bf:3d:02:cf:8e:0a:b0:43:4b:b4:15:d0:aa:17 - 45: - -coefficient: - 00:d2:c8:fc:3a:8c:28:d3:15:6f:0b:7b:51:7f:a9:8b - 3c:f5:ed:f5:6b:d1:d7:e4:e9:c8:46:16:80:1c:f8:78 - fc:10:bf:55:13:67:5a:a2:e6:2b:51:86:ca:d1:53:20 - 1e:e4:f8:82:ca:cd:4a:56:ba:bc:7a:dc:16:ba:16:43 - ca:66:21:f2:73:1b:ca:de:60:95:d1:b8:7b:ad:e1:1d - d5:48:2f:87:83:40:00:a4:ea:ac:2e:4b:a6:c8:b1:4a - 90:16:aa:e5:9c:91:a9:ee:57:ec:5d:13:b6:6d:bc:a6 - ef:b9:1b:b5:7c:44:21:24:06:c7:08:97:16:57:22:5f - d3: - -exp1: - 35:1f:b3:9b:23:f6:c1:0d:55:47:48:be:77:3a:bd:0e - 8a:6e:a2:eb:ce:77:d5:74:cd:cc:24:11:9f:2c:fa:76 - e9:13:d3:32:60:9a:40:b3:a9:da:60:c3:0d:8b:34:23 - aa:4d:aa:ff:c8:d4:24:a2:d5:e6:3c:c6:47:28:2c:15 - 8f:71:0a:ab:9b:7c:19:21:96:14:9e:4d:ba:77:c1:73 - 6d:fc:fa:7a:7a:78:43:f5:08:a1:d0:fe:13:62:f8:09 - 91:3b:4f:a1:4e:0a:2c:fe:31:15:77:63:a1:72:73:a5 - 91:42:92:d0:6f:c5:c3:19:fd:f8:02:c9:dc:48:ae:41 - - -exp2: - 00:b4:33:35:8f:4d:ac:dd:26:a9:dc:a7:0b:28:06:bb - a4:b8:a9:bc:e8:59:b3:be:d1:6a:e9:19:df:b8:b1:2c - 53:64:7f:3e:9e:27:1c:3f:3a:df:82:8c:4a:b3:bd:f4 - c6:47:f0:bc:82:fc:48:c8:92:f5:b4:d0:87:f8:e6:0f - 23:49:0c:c3:ae:1b:92:24:46:dc:7b:0d:97:e6:6c:c2 - 32:da:e7:54:c8:ec:83:8e:7d:48:23:50:eb:90:6c:9d - e6:2d:3a:95:0d:6e:86:1f:6c:fe:93:22:01:28:d4:91 - 96:7b:07:d5:41:fb:01:fe:a4:fd:fc:0b:6b:69:9b:cf - 25: - - -Public Key PIN: - pin-sha256:KV163ICyMOUr6z/cxe1yQ1x2GIwCrmZAG9iOyW244lg= -Public Key ID: - sha256:295d7adc80b230e52beb3fdcc5ed72435c76188c02ae66401bd88ec96db8e258 - sha1:0c3cb2bad4f2115a013b50d9cb9f7ddf183e6012 - ------BEGIN PRIVATE KEY----- -MIIE7gIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEaMBgGCSqGSIb3 -DQEBCDALBglghkgBZQMEAgKiAwIBMASCBKgwggSkAgEAAoIBAQDdB9qoZVUJ7r4L -xp2VBSj21gvW3TF/6bQ8Uwst7/G/khMUnwkRCKHUSf+KUV5FYuBjfp0YaL2T/kKl -Rt5bBtaQKJgQ/e9dC/mkfPnOaCpsXXhaEafTdzpJyQFzgEBQVt8e5iHXe5sUCwD8 -CfeXmjlQberpwbFHyhrFSXmOQip06VGBFAfyUVlysd5aCXLed5Bi4PeWZAd/bYPA -7YJvYSBlKgnvvYpmdEwqYGO5kW/3Vaq91KCh1aIvII/4GUVgk7oZLbTrz4zqHTsu -H5mCZnnLyBscsqkdvWegOeSiWRRnaQ5iRVPii2OfOM/A3dHGdriih3gIMTgo6cwl -mGn6IMjxAgMBAAECggEAVBKIuUTR89U7tH73sZck3b7NAg1gpqbeR5POzMpXyeZm -G5HigPgnlfgPmy0YDoxtjWq7lm1Aruonr3YlXbpcIrlOHih4w4uqiUaAPmKgwFdN -T/UnQOg445fxVV2TGPvyIm6msK/zbMxCs5uW8bNX2Z/1mrRyGjxlsmUgN1wzigP/ -7qdzQjhADz6vc8A4sCHAJDAEhdUBDk5LmNsZ+4g53sGwypQa9r6Nw7u3EDRvU8N3 -uO3ysWaP9m6otNJwUYyyJ1leAZ5+sk2kKnoJL8vn99jdofeXYcsXLF8CGYQcVMgx -41CwJiZPetnA/k57tn21u4bZZxBHfWJ75LSaXsmqAQKBgQDdXJgBbOOx8DeL0Td4 -d5sa8ibCtYpYm/Dyu8xmI+qKnFBi5tbqEbrz7oT9nUU+ylVlEUZGHgNYI1REA9mF -UEOslye/4V6pF6lDz+Ru0wkMbBF0jH3d7b6Wu1vTucGDs6NwUtR0HNV4MXMrG8Dc -KPhRVUrPFrMDsVjSt9+8y29fvQKBgQD/ngAdGN0JCOYgELXqydW4FyzOx5zRCCKV -4EEfWT4rkQeAIX9hc650JMF9pjPg6CAH7eT92VVlrnt2o8kQNSZHeAvRRaEx3Nej -Uhck/1VL0MCeEnP1UdGJq3VqCwi3jZrT1jvD7uMMR456AUxX0sx9t789As+OCrBD -S7QV0KoXRQKBgDUfs5sj9sENVUdIvnc6vQ6KbqLrznfVdM3MJBGfLPp26RPTMmCa -QLOp2mDDDYs0I6pNqv/I1CSi1eY8xkcoLBWPcQqrm3wZIZYUnk26d8Fzbfz6enp4 -Q/UIodD+E2L4CZE7T6FOCiz+MRV3Y6Fyc6WRQpLQb8XDGf34AsncSK5BAoGBALQz -NY9NrN0mqdynCygGu6S4qbzoWbO+0WrpGd+4sSxTZH8+niccPzrfgoxKs730xkfw -vIL8SMiS9bTQh/jmDyNJDMOuG5IkRtx7DZfmbMIy2udUyOyDjn1II1DrkGyd5i06 -lQ1uhh9s/pMiASjUkZZ7B9VB+wH+pP38C2tpm88lAoGBANLI/DqMKNMVbwt7UX+p -izz17fVr0dfk6chGFoAc+Hj8EL9VE2daouYrUYbK0VMgHuT4gsrNSla6vHrcFroW -Q8pmIfJzG8reYJXRuHut4R3VSC+Hg0AApOqsLkumyLFKkBaq5ZyRqe5X7F0Ttm28 -pu+5G7V8RCEkBscIlxZXIl/T ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_512.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_512.pem deleted file mode 100644 index 82ab5d95bb..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-key-rsa_pss_512.pem +++ /dev/null @@ -1,138 +0,0 @@ -Public Key Info: - Public Key Algorithm: RSA-PSS - Hash Algorithm: SHA512 - Salt Length: 64 - Key Security Level: Medium (2048 bits) - -modulus: - 00:d4:ed:b5:a7:85:5a:ba:9c:02:b8:fc:02:46:1e:e3 - 6c:54:34:72:3c:fc:56:eb:0b:ad:9d:95:83:a3:09:15 - 9d:f1:e7:1a:93:21:3e:b5:b3:64:7f:98:83:97:a2:b7 - ca:02:c4:48:a2:55:3f:29:b8:b1:87:61:6d:72:5f:7a - 9f:20:69:f4:82:2c:7e:48:0d:d6:57:40:92:2c:13:9f - e5:44:75:d4:ad:41:f6:c9:f4:74:c4:31:14:dd:44:8c - ec:25:5b:4f:07:51:bc:4e:21:bd:47:c9:e8:56:b2:1e - f1:5d:e0:56:36:c8:18:18:86:71:41:bb:c2:3c:06:ca - e4:71:f2:cd:ec:9f:09:a0:05:6e:b4:d9:32:65:53:9b - 5a:7a:b9:a2:30:7a:cd:06:a6:47:3f:f4:05:9e:87:b7 - 2f:b2:e0:fc:63:c5:ec:2c:19:ed:32:ad:ee:71:9c:37 - d1:34:f3:aa:1a:ba:ed:cf:40:28:82:43:11:54:83:74 - 42:db:70:f7:58:12:c5:11:af:1a:05:26:24:ef:81:8a - 26:ee:2c:f3:8a:c4:2c:0c:47:cc:76:2b:7a:ce:e0:bb - 80:d2:d0:5e:c8:8f:1d:03:c5:4c:47:1b:7b:90:c4:d3 - 0b:9f:8b:6e:29:bd:ab:25:cd:aa:1e:ad:72:19:02:c0 - 11: - -public exponent: - 01:00:01: - -private exponent: - 01:23:1b:db:3f:2d:12:de:0e:6d:aa:7a:e0:a0:fd:99 - f0:81:2f:33:00:2d:fe:a7:5b:50:02:22:67:d6:7e:95 - 0f:5b:aa:9a:aa:8c:c9:2f:a2:13:c4:5e:bf:8a:90:ec - b5:43:13:18:3a:d8:51:82:b8:ff:fe:17:35:8b:28:fe - 7c:8f:d4:4c:75:ac:5e:fa:23:f0:e7:59:60:7e:e2:55 - b9:1d:df:fa:e4:e5:4a:82:d1:b4:d2:86:48:00:3b:b8 - 6f:22:a3:b3:68:4e:57:24:7a:fc:4d:29:be:7c:c9:09 - 84:f4:d3:c1:0b:24:85:cd:02:01:d5:dc:dd:b1:33:98 - 2e:3c:e5:7c:69:e2:e7:e4:02:83:b5:e8:d0:05:c5:cd - 5b:8e:72:f7:ee:b2:d4:11:15:85:b3:b3:4f:ac:cf:77 - 81:73:68:a9:70:fc:b3:94:24:f9:77:f5:38:4f:af:ab - cb:4e:7f:c2:79:76:87:f9:0f:a3:3b:5c:95:61:64:11 - 3a:40:98:28:51:86:48:11:41:30:e2:1a:94:94:06:d0 - 0a:15:de:19:13:9f:f3:06:b8:03:68:8f:87:b2:3a:4f - f3:75:bc:f7:5a:e4:1e:b4:49:29:09:da:57:e4:43:ea - 96:bd:74:e3:f3:38:5a:bd:b3:da:cc:09:99:f6:09:19 - - -prime1: - 00:f0:d9:0a:ee:11:50:da:c9:01:1f:5c:3d:c8:82:3b - 1c:0c:27:17:80:69:fa:d1:9d:ca:d2:7f:12:90:e9:a8 - e5:36:f0:b7:8f:8e:90:f0:0a:78:53:0f:93:51:f0:f4 - 72:a3:1a:de:ea:0f:5e:8f:84:c3:57:39:38:93:73:cf - 94:6e:1a:56:ef:36:d9:22:39:75:76:5b:4e:f6:54:e7 - 02:32:9f:54:5f:1b:02:37:50:f0:49:1b:e0:e6:d1:bd - b8:07:9b:7f:15:fd:ea:53:08:59:e8:17:66:d5:10:e4 - a2:f1:3e:c3:c8:7e:68:a2:a1:5f:04:f1:7b:a6:c5:3c - 73: - -prime2: - 00:e2:53:03:dd:5d:f1:fc:27:a6:d7:01:b1:5e:f3:26 - 5d:9e:fc:f2:45:85:4b:10:86:97:a5:9d:2b:19:3b:35 - 8e:91:36:67:50:d0:da:16:de:c7:13:99:76:b8:9b:2f - 44:fc:6b:c3:29:ec:a7:11:38:05:de:3d:2e:85:1a:49 - 88:28:b6:e0:1b:8f:6a:0a:21:56:ec:ee:56:34:b5:20 - e6:a2:c0:b0:08:c1:48:13:60:e3:65:b1:4a:b9:6c:9b - a4:63:92:2f:5a:e6:6d:80:2a:c2:97:53:87:05:dd:08 - 1d:98:52:c9:88:a9:d3:5d:18:d7:2b:5e:0c:63:e0:94 - 6b: - -coefficient: - 00:8e:60:92:ac:a2:02:d9:67:c7:c5:70:13:d2:b6:2f - 5d:b2:a1:68:0e:46:db:33:f6:8a:a4:bd:06:07:db:5b - 39:62:14:e6:81:95:32:ca:89:b7:dd:87:60:bd:98:33 - 5d:a8:21:25:d9:64:fb:5f:52:a5:28:e8:05:e2:7b:5d - 43:ae:fd:d2:98:fe:20:9e:4e:65:96:11:c4:ae:91:a7 - 36:cb:3d:8d:fe:29:7c:91:bf:8b:45:17:f6:7c:29:41 - 1a:4b:87:85:c2:95:96:d5:8d:c7:5b:7a:29:6e:c3:6a - c6:6f:38:55:f7:9f:aa:27:c4:a7:18:8c:42:f1:b2:94 - 9d: - -exp1: - 7c:76:ed:9b:11:ff:c2:d0:d5:6f:ab:6f:92:4b:1a:d8 - e7:be:db:fa:54:ca:75:c1:21:ab:9e:57:ad:e3:d2:90 - 81:cf:ec:4c:97:d4:76:f8:32:2e:5a:82:3b:7a:56:19 - 58:08:ee:e1:ee:87:63:8b:ac:97:4a:ce:de:04:9f:65 - 89:70:bb:34:6c:17:d2:03:f7:9b:ee:9b:e3:d9:04:78 - b2:48:7c:85:99:a3:8f:8a:98:62:6f:b1:ce:16:de:00 - 58:8e:17:22:fa:51:3a:0f:ba:c6:a2:31:56:32:a0:b5 - 44:0e:b7:86:c9:2c:b1:be:cb:27:f6:d3:7b:df:b9:d9 - - -exp2: - 32:88:88:9f:5f:bf:8d:26:a9:58:ee:76:d5:15:83:66 - 79:fe:4e:75:f9:5a:16:59:86:f8:a2:8c:21:f9:17:6f - 3a:bb:23:fc:66:75:9b:8f:a8:71:96:dd:6c:40:b2:20 - 3c:20:2f:96:67:d1:b1:c5:89:81:e2:b5:45:60:e6:34 - 31:ab:0b:84:fb:d3:98:69:73:48:39:bb:23:cf:a1:85 - fd:a6:fa:67:2a:08:d6:d2:d6:53:39:6f:ce:d1:12:3b - 75:44:09:b0:c9:2c:7f:e6:8c:46:4f:8f:21:5f:05:d5 - dd:d1:f6:4f:be:63:84:30:ec:b2:31:30:a1:08:5e:fb - - - -Public Key PIN: - pin-sha256:xZynWKbgc/clJ1vmaUuUrDqVNLkKBsbEVke+Uj4T30M= -Public Key ID: - sha256:c59ca758a6e073f725275be6694b94ac3a9534b90a06c6c45647be523e13df43 - sha1:c19f5569864001b25aad7ff9de9d200574d2b257 - ------BEGIN PRIVATE KEY----- -MIIE7QIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCA6EaMBgGCSqGSIb3 -DQEBCDALBglghkgBZQMEAgOiAwIBQASCBKcwggSjAgEAAoIBAQDU7bWnhVq6nAK4 -/AJGHuNsVDRyPPxW6wutnZWDowkVnfHnGpMhPrWzZH+Yg5eit8oCxEiiVT8puLGH -YW1yX3qfIGn0gix+SA3WV0CSLBOf5UR11K1B9sn0dMQxFN1EjOwlW08HUbxOIb1H -yehWsh7xXeBWNsgYGIZxQbvCPAbK5HHyzeyfCaAFbrTZMmVTm1p6uaIwes0Gpkc/ -9AWeh7cvsuD8Y8XsLBntMq3ucZw30TTzqhq67c9AKIJDEVSDdELbcPdYEsURrxoF -JiTvgYom7izzisQsDEfMdit6zuC7gNLQXsiPHQPFTEcbe5DE0wufi24pvaslzaoe -rXIZAsARAgMBAAECggEAASMb2z8tEt4Obap64KD9mfCBLzMALf6nW1ACImfWfpUP -W6qaqozJL6ITxF6/ipDstUMTGDrYUYK4//4XNYso/nyP1Ex1rF76I/DnWWB+4lW5 -Hd/65OVKgtG00oZIADu4byKjs2hOVyR6/E0pvnzJCYT008ELJIXNAgHV3N2xM5gu -POV8aeLn5AKDtejQBcXNW45y9+6y1BEVhbOzT6zPd4FzaKlw/LOUJPl39ThPr6vL -Tn/CeXaH+Q+jO1yVYWQROkCYKFGGSBFBMOIalJQG0AoV3hkTn/MGuANoj4eyOk/z -dbz3WuQetEkpCdpX5EPqlr104/M4Wr2z2swJmfYJGQKBgQDw2QruEVDayQEfXD3I -gjscDCcXgGn60Z3K0n8SkOmo5Tbwt4+OkPAKeFMPk1Hw9HKjGt7qD16PhMNXOTiT -c8+UbhpW7zbZIjl1dltO9lTnAjKfVF8bAjdQ8Ekb4ObRvbgHm38V/epTCFnoF2bV -EOSi8T7DyH5ooqFfBPF7psU8cwKBgQDiUwPdXfH8J6bXAbFe8yZdnvzyRYVLEIaX -pZ0rGTs1jpE2Z1DQ2hbexxOZdribL0T8a8Mp7KcROAXePS6FGkmIKLbgG49qCiFW -7O5WNLUg5qLAsAjBSBNg42WxSrlsm6Rjki9a5m2AKsKXU4cF3QgdmFLJiKnTXRjX -K14MY+CUawKBgHx27ZsR/8LQ1W+rb5JLGtjnvtv6VMp1wSGrnlet49KQgc/sTJfU -dvgyLlqCO3pWGVgI7uHuh2OLrJdKzt4En2WJcLs0bBfSA/eb7pvj2QR4skh8hZmj -j4qYYm+xzhbeAFiOFyL6UToPusaiMVYyoLVEDreGySyxvssn9tN737nZAoGAMoiI -n1+/jSapWO521RWDZnn+TnX5WhZZhviijCH5F286uyP8ZnWbj6hxlt1sQLIgPCAv -lmfRscWJgeK1RWDmNDGrC4T705hpc0g5uyPPoYX9pvpnKgjW0tZTOW/O0RI7dUQJ -sMksf+aMRk+PIV8F1d3R9k++Y4Qw7LIxMKEIXvsCgYEAjmCSrKIC2WfHxXAT0rYv -XbKhaA5G2zP2iqS9BgfbWzliFOaBlTLKibfdh2C9mDNdqCEl2WT7X1KlKOgF4ntd -Q6790pj+IJ5OZZYRxK6RpzbLPY3+KXyRv4tFF/Z8KUEaS4eFwpWW1Y3HW3opbsNq -xm84VfefqifEpxiMQvGylJ0= ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa.pem deleted file mode 100644 index d49498959c..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDQjCCAiqgAwIBAgIMWYGU8BDBJ3AgFnsvMA0GCSqGSIb3DQEBCwUAMCMxITAf -BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzZa -Fw0zNzA3MjgwOTAxMzZaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IENs -aWVudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM/xijmXl7PVbZwS -BE6h3A2pEsv4Au86itIS4qb7GJNvOZ2pwx22/AOGr/JvsYGGnOsVxQ63mE9xBz2l -jPsqGDhQeLD7CptXZAcwYa6k2z6S91Sd0GCNOgPuFiXKFXt9Si82uNB42r7kHG04 -exmY7uKUdMp1IxUbZ47leBmT7W5I65lK2acxkzRK6bdPErnNGzZt4t/k6E0Oowf6 -ElUf0UvhsX0trFB9O8yvCciqAQoGUw7b1yzWA9bWi1AQUPgx58eGMrRgQXfFnuuG -efHqU+/nAVAt5pHHU0GqB09jcv1lJSQpDMtCBa5tsorVvy8OiiSJx15tIyNOtVcc -9y/oH3cCAwEAAaN2MHQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcD -AjAPBgNVHQ8BAf8EBQMDB4AAMB0GA1UdDgQWBBSoiZsEL0tgug7IyLHTI1fA+tNH -OjAfBgNVHSMEGDAWgBQrQlWadXqqzBV+2iw7BZXrvFHaQjANBgkqhkiG9w0BAQsF -AAOCAQEAx3E9wM3ASFrxZ8Zw/036WHeJUjgOL+W9TM4Y4GZpQDkyMqKxs3pmyqcU -xuXWV+SmTCkOAvrH/kWhmgDxSs3eGrGBsRPEZcUolcedDWqPJpy0qZH6mv3Ge0+v -V+YOcd0qSVHaLpR1LQHrDnatASaVVRF4Ohk2IRSvjzYYJ158D3+erB79Txt4kqK2 -oDMp59uI2K4VwNiXeuWQgolaoKTEtPSrjuuKzetrwLN8ajii5rkiOKyuKlkZ2SyE -BYp/ye1hzmqXRHNrObbfMmggwimrShYWUSwHp0/gKMEhen+yqd9C2KEVj7dqm+oL -Jo+TGr6L77LBgZ5r7vfzj4tzL877mg== ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_256.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_256.pem deleted file mode 100644 index 77ec9737dd..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_256.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID2jCCApKgAwIBAgIUej61CoI5BANd5v/ceHNxIOtR8d0wPQYJKoZIhvcNAQEK -MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC -ASAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy -NDA2MDY0MloXDTM4MTAxOTA2MDY0MlowIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl -IFRlc3QgQ2xpZW50MIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEa -MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIBIAOCAQ8AMIIBCgKCAQEA13o6 -AYteWQ8QfZVczsbqyCkudW7+bPmD1T5ybPxWlUPUYjTfBXyzs6ZKN8q24CNEGfws -6s/8+SYarFqNg/hP2Quu/OmddTctpJMCXWkQ37d6TLYFZHNGRbL+pLMznmhrFDWO -7t+74Hcjdrhu/fzy3QJZXtyhs12TxiziSoUhf8pZNuh33f7N/vawlv4UalxoTM+8 -/f7s4y9REM9G2x06Pc2H7GdKfSBeeWzq0yTTggW82Xnlzd9qu2KbILM1NGGuaamr -ubYnrHsz9b7fmrQSaAZVebO6UvCRkGmx8VoR44ve3fGZylqth7plUiemBxJgECST -S98S20kP/CH/n+aSdQIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG -CCsGAQUFBwMCMA8GA1UdDwEB/wQFAwMHgAAwHQYDVR0OBBYEFAKLYWuJSEnLypED -/PkZ/dogyhAeMB8GA1UdIwQYMBaAFCEaiLbeA8ABgKrbcIiZpo8XzqpsMD0GCSqG -SIb3DQEBCjAwoA0wCwYJYIZIAWUDBAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFl -AwQCAaIDAgEgA4IBAQCFjsx2JQ+AtT2AD7harhhhuCH8ah9hTLz1n+ynkmq1lmYP -JCudOJfgWjMFlSv1ptzkvOst+Ig2BCCJrwX1akMX1cMsR/eoDUxxkqREU/irEYPj -ePvVk0+bd6C4+nCvs/J0bv5P/16z2NLmAq8BUidi4ULPyzVn/+nAAUpAVlYi/mHP -RQCy8UMj2ENACc4LIP1tek9cp+t5JMjsv2ogy+SPCXtq7VTMAFrckrALv9b1QLE6 -J06bp7+Q7GIkn0gTm+Z5AaddHH1ZDjqpYFcngx7wVuQCbZwTqnVJx5nQrKz+HQYt -87KWIhR2nbtygp2oZESXQg9huH395f/h+foYArPG ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_384.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_384.pem deleted file mode 100644 index dda273d859..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_384.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID2jCCApKgAwIBAgIUbdDLDIxL8QBkB4RFPZ3TaeInTUcwPQYJKoZIhvcNAQEK -MDCgDTALBglghkgBZQMEAgKhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAICogMC -ATAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy -NDA2MDY0MloXDTM4MTAxOTA2MDY0MlowIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl -IFRlc3QgQ2xpZW50MIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEa -MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgKiAwIBMAOCAQ8AMIIBCgKCAQEA3Qfa -qGVVCe6+C8adlQUo9tYL1t0xf+m0PFMLLe/xv5ITFJ8JEQih1En/ilFeRWLgY36d -GGi9k/5CpUbeWwbWkCiYEP3vXQv5pHz5zmgqbF14WhGn03c6SckBc4BAUFbfHuYh -13ubFAsA/An3l5o5UG3q6cGxR8oaxUl5jkIqdOlRgRQH8lFZcrHeWgly3neQYuD3 -lmQHf22DwO2Cb2EgZSoJ772KZnRMKmBjuZFv91WqvdSgodWiLyCP+BlFYJO6GS20 -68+M6h07Lh+ZgmZ5y8gbHLKpHb1noDnkolkUZ2kOYkVT4otjnzjPwN3Rxna4ood4 -CDE4KOnMJZhp+iDI8QIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG -CCsGAQUFBwMCMA8GA1UdDwEB/wQFAwMHgAAwHQYDVR0OBBYEFAw8srrU8hFaATtQ -2cuffd8YPmASMB8GA1UdIwQYMBaAFKnwXW9hoPAB6HSyWn7UEUMcKonnMD0GCSqG -SIb3DQEBCjAwoA0wCwYJYIZIAWUDBAICoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFl -AwQCAqIDAgEwA4IBAQAHS+4AoR5A0sNaCrhuB8rfDfI+kcO0SqwT98d5QTJnsiqu -/2OHecJbN7nkYKh9K+8ccWVCWncWV1dFP1fVnCibFpAF+750wLhSpb/RVfm8Gd8F -CLuZNC6i9w7ssQzus7SpBx2viY615zxRJ6kdhGhPSxc98tPAHkdkdWGWq0R8Q3u9 -hP/mj/oAxskhvF/Lofwk5uyYSNIcZ9w3YPmb70OUWDH1yreF7s0J3hOPZZiC7ZA4 -Nao6UPpwKk1IdZix63xHFwCN21AtQIHoL/aRcVSlHlol5VOgaWbetb1BTBqEoKux -s4hJIMFIslA++GDX/qj7JrYr+FJTOqFF2B+Rm7wO ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_512.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_512.pem deleted file mode 100644 index 2bc13ae96f..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-client-rsa_pss_512.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID2jCCApKgAwIBAgIUWlbiagMGpRhGjEwawdwRz964ObEwPQYJKoZIhvcNAQEK -MDCgDTALBglghkgBZQMEAgOhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIDogMC -AUAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy -NDA2MDY0M1oXDTM4MTAxOTA2MDY0M1owIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl -IFRlc3QgQ2xpZW50MIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCA6Ea -MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgOiAwIBQAOCAQ8AMIIBCgKCAQEA1O21 -p4VaupwCuPwCRh7jbFQ0cjz8VusLrZ2Vg6MJFZ3x5xqTIT61s2R/mIOXorfKAsRI -olU/Kbixh2Ftcl96nyBp9IIsfkgN1ldAkiwTn+VEddStQfbJ9HTEMRTdRIzsJVtP -B1G8TiG9R8noVrIe8V3gVjbIGBiGcUG7wjwGyuRx8s3snwmgBW602TJlU5taermi -MHrNBqZHP/QFnoe3L7Lg/GPF7CwZ7TKt7nGcN9E086oauu3PQCiCQxFUg3RC23D3 -WBLFEa8aBSYk74GKJu4s84rELAxHzHYres7gu4DS0F7Ijx0DxUxHG3uQxNMLn4tu -Kb2rJc2qHq1yGQLAEQIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG -CCsGAQUFBwMCMA8GA1UdDwEB/wQFAwMHgAAwHQYDVR0OBBYEFMGfVWmGQAGyWq1/ -+d6dIAV00rJXMB8GA1UdIwQYMBaAFKVY4bgN1p+8NOXoPdj6DKWDscBFMD0GCSqG -SIb3DQEBCjAwoA0wCwYJYIZIAWUDBAIDoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFl -AwQCA6IDAgFAA4IBAQBm9QAlG/xd8O6/TgJwnxmjKcSNhWgFHz4yY2uSMRP51VR/ -SzoXIY3drTWz3fuXSxbjAcVSlfmSX3KMVm1M6IKOw37PwUD8C5oVpLEY/NpwTjfb -WS5RR0XpAi2JJhPa9vJEO8PMdDV5C07u3fs5QvysNPZqJJvn+i2rU44JTeeJzBf8 -hesUVx4m+16C4cdU80prTnq9QYnZi08vIJ0iW0czxrsRikcqAnb+FEsrnbl1t3Wy -PcdYUq7SkQ3B3pnreOMRnRGGP0dq4YOPto6nKD2h70TQ2rH2JhSlDy7aPNx9jUKO -dwz0hfct7G7Wyoz2U+rI7ulHt3Mck4DyOam+TMEJ ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-dsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-dsa.pem deleted file mode 100644 index 029d88ac24..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-dsa.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEpjCCBEygAwIBAgIMWYGU8C09TIACbzDkMAsGCWCGSAFlAwQDAjAjMSEwHwYD -VQQDExhCb3VuY3lDYXN0bGUgVExTIFRlc3QgQ0EwHhcNMTcwODAyMDkwMTM2WhcN -MzcwNzI4MDkwMTM2WjAjMSEwHwYDVQQDExhCb3VuY3lDYXN0bGUgVGVzdCBTZXJ2 -ZXIwggNGMIICOQYHKoZIzjgEATCCAiwCggEBAKIJ4msqhhMj/QtISZhmqwZzwvxo -9G4/z6zraDROzwt4KfCM+4Iplzb54xi4iifAKFjzegL066KAYuZEu3c5oU+1t2WT -Uz4WaD/F8jpA/p8/iMp7d/Aj+qwHoIewZmtFN7OyTvIgPFUtzKShwsA/FGxQzDbw -XOtsQ77WFdLa7B+1ZjFC776KbzNzZG0iClfZL0NweKYAGjdkJ6GKDJsKwkzWJ/wV -2fKew8GzvUKiUVamMN6QXVx8x7odGETBu5FB0bP4wCKqnQKLarfHRspynA8rCNHF -mW5CMGDQm+zaehpcgIOnsJE8xb9C7bzzFmkWxEy5DJmYPtnKEBDWz6XjdmUCIQCn -T2W/xqEt+tix4k4f/a/0D3i7iawNewwccUb4C5RcYQKCAQAs4tv1yBjpGvsspRpL -rxdAcIXhCeBQCzoYMI4CFH3lSjotUT5T30h2fA3qi3bm0GhnuAw7a1s3H749MAKm -P9RgskHkeyFoWWKJ5rVqz+KOBXQkhRDkGND5hYdBgMq5YnnDQ7O0D0621AovPOex -UQFVl2/4bJ/FRCPZ3NL790XwZNL0v/XFTDU1eL5CcSOwsENTfCpPa+6nnO4K/Gtr -QV4mCpY8dwtQB9lTB6BuhuMQ5Bmu+JVaVaGDIP8pd1ZXxPg9WQcZY+sFRz5zkiBm -Fs/+rbTnUC6Lx5T3tMBGhWC7+VmJNeT3eVzvMU7tgGGIElsQC1/5xU6pzRAL4/It -ijN3A4IBBQACggEAYi/1HWMttEK5mU2B6IpU6pgUmkUleSVrQo3tdMViiSlGPtB6 -c+yoZc3GxruCUHIYbN+rFNIsdoJQ2k9Ah4VkX6mBytopd5eulwG63DDrXCRgxqMm -BHFNvcZ/OG1Lj8Upnf9x9GbJwzoV+4J/tF/al9XlUk9gJf2zfr7oq6NAqvHXsaHj -4oC3FQV0enQdfnC325wVie+BrV5hE/YUgcYF5m2R3a0o4UokGqyJzxDjxLlrtMHe -6Rn7JngDfq7oFNXN1BMu9RD0Ll2KwZFURzZMAzj5DNc8eAScTC7omVrk6/lsQ1TW -tnlOm7QXoBcRINwrA9hoTAgPh7iyqr8497M2yqN2MHQwDAYDVR0TAQH/BAIwADAT -BgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHQ8BAf8EBQMDB4AAMB0GA1UdDgQWBBQL -IkWyCawkb1V1BkwW61qMAd3TnTAfBgNVHSMEGDAWgBQA5WZqsOvPVi3KO+dfgL1w -NxeVqDALBglghkgBZQMEAwIDRwAwRAIgUHB/GqyakK8awZlbR6MsLGDz0UiCvfCR -eK2qrGSqsfICICKrf9+KyfiDh5HoB4pPZDOAAd5yQIEclw/aOD1yq0wT ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdh.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdh.pem deleted file mode 100644 index 7c8f044352..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdh.pem +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBtjCCAVygAwIBAgIMWYGU8BHdfIBy0aZkMAoGCCqGSM49BAMCMCMxITAfBgNV -BAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzZaFw0z -NzA3MjgwOTAxMzZaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IFNlcnZl -cjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABLWCgejCbKGDGpoTzBtYGeQt3OSZ -B3aPwiAaQog3VfsSsERXWAiUdogMibtR4lLl6s9QbWDorQWXhejIUi7woY2jdjB0 -MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0PAQH/BAUD -AweIADAdBgNVHQ4EFgQU0L5LXF6oiQE1eNyzRztmBOoHiR0wHwYDVR0jBBgwFoAU -0ma/FGcW5gGlL//B26Xmj0JISecwCgYIKoZIzj0EAwIDSAAwRQIhAM6F/DDKK7H9 -HbkqCcUsxTCTakQ1wcAkkRDMCI/lKLxCAiAUjBMndyVRzNlY6h4+2NP0A3RT2Q87 -2mnmiPSuW9Q4iw== ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdsa.pem deleted file mode 100644 index ffaa81e9f6..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ecdsa.pem +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBtjCCAVygAwIBAgIMWYGU8C5XSABmYVGJMAoGCCqGSM49BAMCMCMxITAfBgNV -BAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzZaFw0z -NzA3MjgwOTAxMzZaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IFNlcnZl -cjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKzro1Qhiu2IrXTK1X9xZ20T0eL0 -vxwmwTGcr7EvI9kRnhXDsV5Har9CmzInfIcOhL9VlS4K2WUhxNMuLYr5EIKjdjB0 -MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0PAQH/BAUD -AweAADAdBgNVHQ4EFgQUNjGYYKninT7GGg2A3pGsO2xPByIwHwYDVR0jBBgwFoAU -0ma/FGcW5gGlL//B26Xmj0JISecwCgYIKoZIzj0EAwIDSAAwRQIgWYw3r0KqlS60 -h4RON2Ycq7oH2qxf+b9mWaehP8sebHoCIQDJyu+qUegmitkVqbenVV2ypPL7x2nP -qvghAKPod/72bg== ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ed25519.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ed25519.pem deleted file mode 100644 index df3a379c4b..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ed25519.pem +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBfjCCATCgAwIBAgIUEOZLZhsVbmqCJUugm0oRFrWPO8swBQYDK2VwMCMxITAf -BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xODA4MjMwOTI5NDda -Fw0zODA4MTgwOTI5NDdaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IFNl -cnZlcjAqMAUGAytlcAMhAM2PquzCzWQdU5dEG7JMCCfvaaNyfRlcIhsCzF8RLWiw -o3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdDwEB -/wQFAwMHgAAwHQYDVR0OBBYEFFsSy04J6VkN2IiqBJKGV26iMRYyMB8GA1UdIwQY -MBaAFOp5vj76ByEwboduoHWAWzajnM1mMAUGAytlcANBAOhCpwpdClN4+DFhtwLf -br8//ymNpCOf8W4vE4pZACueKIooh2S4WnbkFwBloOntxX+4TXnD06SBlpcmoQg2 -NwY= ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ed448.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ed448.pem deleted file mode 100644 index 3ba371f662..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-ed448.pem +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIByTCCAUmgAwIBAgIUdWna0n25+zzo6pW93hOpSKLfU0swBQYDK2VxMCMxITAf -BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0yMDAyMTMwNzMzMDJa -Fw00MDAyMDgwNzMzMDJaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IFNl -cnZlcjBDMAUGAytlcQM6AETFuJ7D3g4EgZnNVbPW3j81X6VpJane2pY04n8bzYcs -kAvfb5lGogDBoczMsB9opnPMdSwZQs6CAKN2MHQwDAYDVR0TAQH/BAIwADATBgNV -HSUEDDAKBggrBgEFBQcDATAPBgNVHQ8BAf8EBQMDB4AAMB0GA1UdDgQWBBTHz9U/ -S0PulhuJNX8vOdBOjnLCqjAfBgNVHSMEGDAWgBS+BSv++BEWlTJ53q6rwnDLVnR5 -JTAFBgMrZXEDcwAp/84ZggkOUHT0qCL/8a3Qmj6HyXeb8NNVyPNSbBgW6HVQsn9c -wquAbara1d9VFJ+ucpSdQfYPs4DVfxADVcVfaunEGujBoL9U3q/9XIJ5IT70HL1O -+PUERelTyKywKQI8Y2YYKUH6UYsesLhcAQ8DBwA= ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-dsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-dsa.pem deleted file mode 100644 index 73247089ce..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-dsa.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICZAIBADCCAjkGByqGSM44BAEwggIsAoIBAQCiCeJrKoYTI/0LSEmYZqsGc8L8 -aPRuP8+s62g0Ts8LeCnwjPuCKZc2+eMYuIonwChY83oC9OuigGLmRLt3OaFPtbdl -k1M+Fmg/xfI6QP6fP4jKe3fwI/qsB6CHsGZrRTezsk7yIDxVLcykocLAPxRsUMw2 -8FzrbEO+1hXS2uwftWYxQu++im8zc2RtIgpX2S9DcHimABo3ZCehigybCsJM1if8 -FdnynsPBs71ColFWpjDekF1cfMe6HRhEwbuRQdGz+MAiqp0Ci2q3x0bKcpwPKwjR -xZluQjBg0Jvs2noaXICDp7CRPMW/Qu288xZpFsRMuQyZmD7ZyhAQ1s+l43ZlAiEA -p09lv8ahLfrYseJOH/2v9A94u4msDXsMHHFG+AuUXGECggEALOLb9cgY6Rr7LKUa -S68XQHCF4QngUAs6GDCOAhR95Uo6LVE+U99IdnwN6ot25tBoZ7gMO2tbNx++PTAC -pj/UYLJB5HshaFliiea1as/ijgV0JIUQ5BjQ+YWHQYDKuWJ5w0OztA9OttQKLzzn -sVEBVZdv+GyfxUQj2dzS+/dF8GTS9L/1xUw1NXi+QnEjsLBDU3wqT2vup5zuCvxr -a0FeJgqWPHcLUAfZUwegbobjEOQZrviVWlWhgyD/KXdWV8T4PVkHGWPrBUc+c5Ig -ZhbP/q2051Aui8eU97TARoVgu/lZiTXk93lc7zFO7YBhiBJbEAtf+cVOqc0QC+Py -LYozdwQiAiAxcsCPJCsRaG0j1eDW0xomfipUvAM3Ws9MZ38R8fxQ/A== ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdh.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdh.pem deleted file mode 100644 index 669fc5cd0d..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdh.pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGUAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHoweAIBAQQhAJsXqInsRDYS26zX -d4tHYu+WKbw2gyrnMvDOamsRyZg5oAoGCCqGSM49AwEHoUQDQgAEtYKB6MJsoYMa -mhPMG1gZ5C3c5JkHdo/CIBpCiDdV+xKwRFdYCJR2iAyJu1HiUuXqz1BtYOitBZeF -6MhSLvChjQ== ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdsa.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdsa.pem deleted file mode 100644 index ca898da2fe..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ecdsa.pem +++ /dev/null @@ -1,6 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgHJsLqw/ZeIlLMmMZ -u+LqjbxD7OY2VhD055Icbpp5HBmgCgYIKoZIzj0DAQehRANCAASs66NUIYrtiK10 -ytV/cWdtE9Hi9L8cJsExnK+xLyPZEZ4Vw7FeR2q/QpsyJ3yHDoS/VZUuCtllIcTT -Li2K+RCC ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ed25519.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ed25519.pem deleted file mode 100644 index e1784c5efd..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ed25519.pem +++ /dev/null @@ -1,25 +0,0 @@ -Public Key Info: - Public Key Algorithm: EdDSA (Ed25519) - Key Security Level: High (256 bits) - -curve: Ed25519 -private key: - f8:32:a1:54:10:e9:b2:b2:31:10:9d:05:c0:3b:58:c5 - 1d:1b:7a:67:d1:53:5e:6b:58:fe:85:1f:4a:4e:71:13 - - -x: - cd:8f:aa:ec:c2:cd:64:1d:53:97:44:1b:b2:4c:08:27 - ef:69:a3:72:7d:19:5c:22:1b:02:cc:5f:11:2d:68:b0 - - - -Public Key PIN: - pin-sha256:tt5u5+ynOHjlD3uadUUmN2V5yZLekOkkwyyk8sZH7cI= -Public Key ID: - sha256:b6de6ee7eca73878e50f7b9a754526376579c992de90e924c32ca4f2c647edc2 - sha1:5b12cb4e09e9590dd888aa049286576ea2311632 - ------BEGIN PRIVATE KEY----- -MC4CAQAwBQYDK2VwBCIEIPgyoVQQ6bKyMRCdBcA7WMUdG3pn0VNea1j+hR9KTnET ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ed448.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ed448.pem deleted file mode 100644 index 382cdd6189..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-ed448.pem +++ /dev/null @@ -1,28 +0,0 @@ -Public Key Info: - Public Key Algorithm: EdDSA (Ed448) - Key Security Level: Ultra (456 bits) - -curve: Ed448 -private key: - af:0f:44:88:c8:11:f7:e4:87:19:b2:e5:f2:17:a4:e5 - 0a:69:78:ed:1c:34:f1:dd:8a:b1:c6:92:92:64:26:94 - 8f:46:45:af:b6:58:d5:b1:20:ce:5e:d6:b7:8e:48:e9 - 0e:14:a7:94:56:d5:14:c8:9d: - -x: - 44:c5:b8:9e:c3:de:0e:04:81:99:cd:55:b3:d6:de:3f - 35:5f:a5:69:25:a9:de:da:96:34:e2:7f:1b:cd:87:2c - 90:0b:df:6f:99:46:a2:00:c1:a1:cc:cc:b0:1f:68:a6 - 73:cc:75:2c:19:42:ce:82:00: - - -Public Key PIN: - pin-sha256:un7RlIHaUdVuKc7nlN4TlmbH42dUsl+RH5jeVUKSyiA= -Public Key ID: - sha256:ba7ed19481da51d56e29cee794de139666c7e36754b25f911f98de554292ca20 - sha1:c7cfd53f4b43ee961b89357f2f39d04e8e72c2aa - ------BEGIN PRIVATE KEY----- -MEcCAQAwBQYDK2VxBDsEOa8PRIjIEffkhxmy5fIXpOUKaXjtHDTx3YqxxpKSZCaU -j0ZFr7ZY1bEgzl7Wt45I6Q4Up5RW1RTInQ== ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa-enc.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa-enc.pem deleted file mode 100644 index d1e835252a..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa-enc.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC3mOPbXv2BWujn -fNGxYw/JNbyW7qQTaKnZogE/aIh5m86hinj7agtV2UDsBXvaQSTrp8vXwKNr9IYX -VLEvT5lM8mj+GDlJ1jhKbo1ODbZPY7b1q5e1RtMUhNX3GgZDevrLL0Tt/g912KD4 -U7vTsS2TQ35hXOQ6bknN9VWNhat0lQ/L60q2QofPdk9PydFZV9CxkoGvwV1BqiTp -JiEloFAf3h07Gim/e3K6OlU2ci+Lb6/uvSDPiOIVYPBURmVjs49sLha2jDj51II4 -9KpPbJwNUT902VrvoRwhrWP8FxYO0QxG9J07IdsNLQLzVWBxz03qK3v+U/akO1QQ -uyrWmw69AgMBAAECggEBAJd3t2RgddymV8fDHmyuQXPKtY//ybWJf7dhBI5/ezh4 -5nw3daBV2Iw29GzECW4CmKcig/W3pBuIXKga4yMZFGx7AUvASGM2LLKbilB+142f -wm3j5wFTMQmYnb2C5u/9IbNHiCKgm7ipxAObcTYw0lzQLg+9Rz09h/43DSH4yX8f -ov1ANiERjkjTMYfaoMbdVrik3MrzBx3lNa0wShS3WebdLIBGv1pk6U2b0bCVJUPP -OJ9n9bs4+kzJBofDHad6N1UszQoHB+1xHthKC5YHyEbnkWlJoyiNWELcADCKYxWY -lsbH1b6zUXlQ+/IYe7uD9Y9nOa/6kXwmyPGuFVBXGgECgYEAwMvMRVkFArycrgd1 -mmYyewuGKQyOonj6qlKDjpuZ829CPwZ7xEpSBNQcKn1vHW52IxJizVh5fHWG/8ga -p2uVGdNUbtjlazrZXDm7xBEAYke+vxgrLHzwCvk3MxFF639nmN9khX+cceLkAaZm -AEye8thr6IN7TVMt43E4G7Bd5OECgYEA88kWgFRvY7rB3oRnMEuLKaTIAdJM81Tt -lQ3PQNTAdt9HenJE5E5y884xQsYCfmvkTGrd7bWHBzRgA0slJQExAaLBNrqm2evw -AshQRVY2mR4TUuKadrWVDV6IF9IDeGZpCEmz1A0RY5M77l2jJ+pAd8Pd8wM07QLV -KqjpDRLTCV0CgYA8xkGPPr+QnEo7pchRspOJLBnPiNDRsJc756Tm6HAAR/s3COEt -AEyYjxCN6FqFiZOd/Ka+mnw5WocCzF5yljw7Ft4PzzmKstNf+icRaFaZpIohjQnX -DU9R9juLUo+a69+JVipG1vJHCEHdr0mKIJ0ealChzAirWGQnxUHtoIwIoQKBgGH1 -JWN/ihrKymf9T/FqCYs8OVnyBRWpxKWmHOdyFbwuT+x1yhTrKOmqqsSoCAyAkgXa -0z5XOOC+PO5V3aEW73g2y+iP68eZNKIJl6ek0t+H5D/j6ilVIYVzvL/Flbtle0Ln -Sqkkbx5R5T0MxyicyjbVr3OckEHEZ59yq+Ki88XJAoGAIrVxwcg+b7FKvBhjrx68 -kBK0rFwTdcqq+82G5R5DGfK5nK9RON01aOM3ddZNy+q/xe5O0kzFPkEQhSsGXTJ2 -+O0cBtTSrQ8hMZKHH6Ol4y6rWjDObmhNZR5ms76l5Fi3EzUKcLbTcl1NXlihanmU -rmQcSs0PKSGpZdraqdH+YrU= ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa-sign.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa-sign.pem deleted file mode 100644 index 975638e550..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa-sign.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC8Xwb2eeVqVUHg -obVcnfjv7C7nhlZAZWFEbrJJXCwqnbYTOUEywVTDkNr7cVp2Q0h1iLz1Dwpz8UfC -LD77DPAVKkI8o9nfQnL7jTYMCjCM1ANdG0Cz0OumnNU+zFP9gOEfscSTeWTqeAfl -MBMDQHgFX0PV2V/h5JlQIyjyYkc5o3c6ALJUEdBecy9dYI5kvEk8GbiftjKVIdPV -RnRyfiwdQjVX5xMcD6kd8HdU0D1C12Tdw8fn9Ftu4JgOBkYrTLS5bQJY72cxrevs -YW8iiSYzJ0wVpcxRYj/4IKXD7PqtoVvYt7zwhOXjhnZGw51yYt2ogcWKUynkueMB -nPzpE7+VAgMBAAECggEBAJDChltL+d3pfyLdor52OCRI4RLTzdzXDBTG7QQrbVWi -tZW4Xj5fDIDuBRtOVTKlKj4Iww2gbWwEdBzoW84adzYMr7JiSMCmFC70qiA+hGj1 -VVBr7SFC4JW92LLV24XpURhGSMb8d20oqQicFUBeft3CBCOHVYQHZTqMip8an5nO -jWPEcxgp2hU5R1BzliMtpwtP3yLN8UD281CEdKy/nG5AfyI882mLbpiFtr0gymhw -CEqJd62vmK1mvSYDYA2QHy3ki9CxCNog0raQy/sOX4JtgCDhmy06FOOqzyo3LFcN -I7Ng2D3R+d7tCEJ8A3C7Z/HbET0MsZDolVljBoNEMlECgYEA+Kznpbm0Vd0Oew9S -5HRzXeZbCnc1fjTOhrtL8o+gyZsXiJQfDWUJ+Mlac2GFDK2FhQofnpfRHlyJRr0b -PSMzPMEB2nj/7Im0LpOUBt2TD69zK8INHIyFmu76ARgqE/rwyuxv+fyqDgUmQShP -8XC2joqejZchvvtX9REj6lQ650sCgYEAwetol/72hrrLNycaVntq7GMmLZCtqIc9 -YcLwQQVjFPkf2eiAHrsdZSnOUYXUJfvsRY4OZ7IkOQp0isU8FqED9CCoLwZ7B67c -DPhUYN6JgIqsH3CuxE9q/5sYb+d8HM9450pk8JrKHJDbBE3nwftLcay5iudkArjw -2hCi4CqzSJ8CgYAdqjKwGGkk3Qv/LiLLUgD5MKOnqfTdq1r/w5QZyXx60F+MUW8q -3+TCovKBVR7UFlcZOc3v01iE8LEHmUOIlYxlMPkRoOGWzA6Mh9pev0vt0RZCIBIE -V9cQVnXIb6OFYqga7P2mqrd2mLKpjy+KM9HzSyIC7gZ+i+lAON059PZZ5QKBgBbA -UMgscK4D8l2pJ8zns/bB9zO3WriADXKP1XI7eJF4XQVK4uU4HM3Gpt8nrWk7clAC -x6vg2aEbmerCEzewcm9M+Y5y2zJekJCw/e1TjpxXKLSTmt2LV8lfX/GZHhWfPdcd -AlS8RGQvlpKdtUgr/ID8u9QRK8mp+xAKjaFxQRGPAoGBALIBTZMU/kmvnO0PrzVL -eR3yojWI/+743kMFxPYfD2sPo/3Dd9qg8J7d1B6wu36vSP2rWVWVGShY6qxiDINi -RnLHzQILuztRbWnxRijP19KtmQctfw7/QIyUMkJ/Ur1bU2JpCjnRdoDVudk8nLvp -dAVR+0swGkDk8ffY+jwZ4gMM ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_256.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_256.pem deleted file mode 100644 index 40f795a162..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_256.pem +++ /dev/null @@ -1,138 +0,0 @@ -Public Key Info: - Public Key Algorithm: RSA-PSS - Hash Algorithm: SHA256 - Salt Length: 32 - Key Security Level: Medium (2048 bits) - -modulus: - 00:a1:d4:bd:d5:9f:ca:7e:e5:d4:7f:49:52:78:33:d6 - b0:2f:37:a4:a2:f8:4b:32:b5:ef:d5:29:9c:7d:2e:ac - 69:b0:b1:1a:09:7d:f1:92:3a:ae:c4:d1:29:63:1b:5d - 60:d3:4d:06:3f:bc:7f:46:c7:22:c2:98:e0:2c:32:fb - 9a:94:f1:ea:b9:3b:37:4b:44:8b:bf:60:28:13:6b:e9 - 31:a6:0f:e2:3d:82:60:9d:28:8b:d4:63:7f:e1:06:cf - d6:81:a1:24:ef:b4:a5:3a:05:95:16:e5:c6:9d:e1:6e - 31:56:92:13:16:c4:2b:53:20:73:57:96:9d:7a:4b:be - e8:f0:50:1a:55:18:1e:d9:69:f2:f6:b5:e5:3a:98:b6 - 77:7b:ff:30:74:9f:6d:81:55:50:b5:3e:81:8d:54:f6 - cc:17:3d:1b:10:bf:69:77:09:d1:d8:be:79:11:ac:3b - be:19:69:5c:b1:50:4d:ba:04:09:98:74:7a:e3:96:48 - 4d:fc:67:7a:34:73:76:48:5e:41:05:61:5a:68:59:39 - b3:86:aa:78:28:f4:a6:4a:db:6f:85:47:75:75:a2:24 - e9:21:3f:18:c9:46:87:91:80:1a:f5:fa:ed:2b:ab:03 - e8:ed:c3:dd:67:ad:46:eb:9b:7e:44:d2:5c:76:4b:3d - 5f: - -public exponent: - 01:00:01: - -private exponent: - 69:92:00:19:18:f9:9f:98:cc:ec:10:68:05:54:43:ec - 81:90:fa:0c:fa:8f:0b:d0:d6:59:27:a1:17:a4:d8:02 - c6:aa:72:02:d9:2f:3b:26:9f:16:74:20:5c:af:e0:55 - a6:e2:6b:7e:2e:b8:94:f2:99:81:7a:fb:5a:ba:13:9a - bf:29:a5:e7:1a:73:32:dd:cf:90:93:e8:f0:ea:87:a0 - c4:e5:3d:c0:c4:89:c4:5c:4c:03:cc:b9:02:92:50:09 - 6e:5d:32:5c:51:6b:2c:13:b2:33:d2:c7:a3:fd:08:c6 - 94:e4:0c:21:e0:ed:26:78:57:e6:3e:b2:12:b2:d1:21 - d8:93:90:f5:8f:2f:c8:97:6b:f0:e6:b0:2a:df:02:18 - 7e:ce:98:8b:63:0c:15:7c:21:39:f9:6c:e2:61:93:fc - 49:36:cd:9d:29:d8:a4:ed:65:12:6d:11:72:f8:13:47 - 6d:8e:20:d7:9f:01:29:3b:8f:dc:d5:b8:f5:58:6f:c1 - 5c:8b:36:40:c5:80:9c:1e:4b:9f:03:55:b5:ff:1c:46 - 1f:e3:b0:12:0c:44:f0:91:07:41:20:08:6a:99:5c:f2 - 11:50:30:4b:4a:84:8e:03:87:89:4e:60:5f:69:01:94 - 5f:82:41:1c:dc:7d:34:f9:02:02:ee:e0:e7:59:63:c9 - - -prime1: - 00:c0:9b:4b:2f:d6:57:df:59:31:87:2a:4c:42:fa:4c - 0c:f2:4d:17:07:90:9b:9c:db:8e:b4:aa:68:96:d1:16 - 01:27:92:e9:8a:26:d1:73:fd:68:21:c7:19:7c:46:f0 - 33:de:21:46:9c:0d:eb:84:8c:b9:6f:cb:47:d0:c5:b8 - 95:1a:e3:18:03:99:81:39:54:2f:c3:a1:14:74:c7:5f - 82:2c:e8:b9:a9:7f:4c:ff:ac:a7:4f:7f:39:20:ee:3d - b1:0f:83:33:fa:76:57:68:4d:8b:99:24:69:d2:08:1b - 1c:36:e7:c9:be:ea:db:1d:38:61:a4:4c:7a:44:e1:82 - 53: - -prime2: - 00:d7:18:59:39:b2:de:4d:0b:58:69:8c:33:af:51:ee - c1:e2:3b:64:b6:36:dd:31:c5:9d:33:39:e2:88:c4:35 - b0:93:8a:6a:b2:c2:8b:ca:c0:0b:21:94:69:90:ae:19 - ab:7b:b8:48:eb:f3:27:3b:96:5c:17:1e:71:89:e7:c5 - 14:d8:d7:de:2b:89:1e:58:f4:4f:1a:95:a7:34:65:48 - 6a:94:f2:bb:33:3c:90:d6:99:4d:36:48:8f:0b:30:d9 - 5f:59:26:60:f0:97:8e:3e:d0:31:99:6f:93:c9:c4:ea - 25:08:f9:48:2f:2a:77:57:93:03:d6:6a:22:fe:16:cf - 45: - -coefficient: - 5b:5d:58:5d:f8:be:1f:31:c4:e9:23:1e:34:41:60:1b - 2d:57:2b:d7:3f:39:74:5f:fa:d6:71:4e:46:02:2d:1a - cc:51:d5:96:7b:d7:0c:f1:8a:a9:31:e7:61:bd:0c:31 - 31:e3:5c:27:32:0b:bd:4a:67:ad:c0:31:db:91:a4:96 - b0:a4:9e:81:0e:75:2e:5f:0c:c5:9b:8e:4d:6c:b4:7e - 2c:44:53:2d:b7:d7:82:20:ba:59:38:df:ec:99:8d:63 - 5f:e9:24:d1:8e:6e:e0:5b:fa:f2:12:16:75:ad:f3:a7 - 2d:fd:8f:55:5f:09:a3:42:4b:44:d2:c8:c8:41:7c:c8 - - -exp1: - 7f:cc:4a:e6:31:e5:da:67:d7:4a:25:51:b6:bb:57:8c - db:95:35:2b:aa:d2:e6:10:74:af:01:c7:26:13:13:f3 - ae:2b:77:d4:58:0f:70:53:fb:2d:36:6b:7d:9f:a0:2f - fa:3a:c0:1c:39:cc:45:06:0e:e0:d3:d4:11:fd:af:8d - 17:eb:08:fb:12:76:c0:f0:50:45:10:f3:7e:cc:ef:5d - 73:a8:f3:d0:38:8c:81:b5:30:ca:b9:d2:d1:3b:e3:29 - 41:ee:bf:a5:77:b2:65:9d:d6:7b:c5:c2:85:3f:25:a5 - e1:f4:88:53:aa:87:ba:ea:b7:37:0a:1b:b2:ea:a2:cb - - -exp2: - 63:04:e8:7e:71:63:79:20:51:f1:35:03:ce:1f:ef:c3 - fd:bb:cd:df:3c:5e:93:bd:1f:63:27:b0:ab:b9:77:e5 - f3:e5:f2:bc:9c:66:f2:4d:7a:52:59:1a:47:ea:7e:12 - bd:7f:d6:c2:18:4b:e5:58:90:c8:6b:d1:64:e4:f7:8b - 63:4f:ed:0d:29:b0:78:ce:ef:63:93:a5:47:af:a0:a8 - c0:2d:06:14:ce:3a:f7:2f:d7:a5:b7:bd:72:2f:68:c2 - 46:2e:2e:ce:53:56:be:7f:e5:75:77:32:17:de:b8:d3 - 97:cf:fa:75:0c:1d:a8:89:1b:69:27:af:38:3d:93:e9 - - - -Public Key PIN: - pin-sha256:KBIg1VxV9p1XXyGsX+MwqaE2DenjfwcmJzw2z8jOeT4= -Public Key ID: - sha256:281220d55c55f69d575f21ac5fe330a9a1360de9e37f0726273c36cfc8ce793e - sha1:06c5f6d2f4f448fa67ba12fe955efbe15febd164 - ------BEGIN PRIVATE KEY----- -MIIE7AIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3 -DQEBCDALBglghkgBZQMEAgGiAwIBIASCBKYwggSiAgEAAoIBAQCh1L3Vn8p+5dR/ -SVJ4M9awLzekovhLMrXv1SmcfS6sabCxGgl98ZI6rsTRKWMbXWDTTQY/vH9GxyLC -mOAsMvualPHquTs3S0SLv2AoE2vpMaYP4j2CYJ0oi9Rjf+EGz9aBoSTvtKU6BZUW -5cad4W4xVpITFsQrUyBzV5adeku+6PBQGlUYHtlp8va15TqYtnd7/zB0n22BVVC1 -PoGNVPbMFz0bEL9pdwnR2L55Eaw7vhlpXLFQTboECZh0euOWSE38Z3o0c3ZIXkEF -YVpoWTmzhqp4KPSmSttvhUd1daIk6SE/GMlGh5GAGvX67SurA+jtw91nrUbrm35E -0lx2Sz1fAgMBAAECggEAaZIAGRj5n5jM7BBoBVRD7IGQ+gz6jwvQ1lknoRek2ALG -qnIC2S87Jp8WdCBcr+BVpuJrfi64lPKZgXr7WroTmr8ppecaczLdz5CT6PDqh6DE -5T3AxInEXEwDzLkCklAJbl0yXFFrLBOyM9LHo/0IxpTkDCHg7SZ4V+Y+shKy0SHY -k5D1jy/Il2vw5rAq3wIYfs6Yi2MMFXwhOfls4mGT/Ek2zZ0p2KTtZRJtEXL4E0dt -jiDXnwEpO4/c1bj1WG/BXIs2QMWAnB5LnwNVtf8cRh/jsBIMRPCRB0EgCGqZXPIR -UDBLSoSOA4eJTmBfaQGUX4JBHNx9NPkCAu7g51ljyQKBgQDAm0sv1lffWTGHKkxC -+kwM8k0XB5CbnNuOtKpoltEWASeS6Yom0XP9aCHHGXxG8DPeIUacDeuEjLlvy0fQ -xbiVGuMYA5mBOVQvw6EUdMdfgizoual/TP+sp09/OSDuPbEPgzP6dldoTYuZJGnS -CBscNufJvurbHThhpEx6ROGCUwKBgQDXGFk5st5NC1hpjDOvUe7B4jtktjbdMcWd -MzniiMQ1sJOKarLCi8rACyGUaZCuGat7uEjr8yc7llwXHnGJ58UU2NfeK4keWPRP -GpWnNGVIapTyuzM8kNaZTTZIjwsw2V9ZJmDwl44+0DGZb5PJxOolCPlILyp3V5MD -1moi/hbPRQKBgH/MSuYx5dpn10olUba7V4zblTUrqtLmEHSvAccmExPzrit31FgP -cFP7LTZrfZ+gL/o6wBw5zEUGDuDT1BH9r40X6wj7EnbA8FBFEPN+zO9dc6jz0DiM -gbUwyrnS0TvjKUHuv6V3smWd1nvFwoU/JaXh9IhTqoe66rc3Chuy6qLLAoGAYwTo -fnFjeSBR8TUDzh/vw/27zd88XpO9H2MnsKu5d+Xz5fK8nGbyTXpSWRpH6n4SvX/W -whhL5ViQyGvRZOT3i2NP7Q0psHjO72OTpUevoKjALQYUzjr3L9elt71yL2jCRi4u -zlNWvn/ldXcyF96405fP+nUMHaiJG2knrzg9k+kCgYBbXVhd+L4fMcTpIx40QWAb -LVcr1z85dF/61nFORgItGsxR1ZZ71wzxiqkx52G9DDEx41wnMgu9SmetwDHbkaSW -sKSegQ51Ll8MxZuOTWy0fixEUy2314Igulk43+yZjWNf6STRjm7gW/ryEhZ1rfOn -Lf2PVV8Jo0JLRNLIyEF8yA== ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_384.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_384.pem deleted file mode 100644 index 49f5ca8c5d..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_384.pem +++ /dev/null @@ -1,138 +0,0 @@ -Public Key Info: - Public Key Algorithm: RSA-PSS - Hash Algorithm: SHA384 - Salt Length: 48 - Key Security Level: Medium (2048 bits) - -modulus: - 00:e7:f5:99:8b:69:95:62:3a:54:80:b9:4c:21:a3:dc - 50:b9:ac:8d:50:a4:98:ea:da:87:55:82:2c:c6:68:e4 - 36:6c:7a:b8:1e:21:db:e6:fa:1f:c2:54:3a:c0:8d:2d - 94:ce:15:66:76:82:d3:27:39:ff:11:f8:19:99:95:6d - 63:7e:35:3d:17:b6:2d:59:3f:c2:b4:b3:73:75:b8:b2 - e7:9d:4d:7d:0d:98:e3:bb:da:e2:44:69:bd:15:52:0c - 45:eb:24:70:5d:47:55:79:67:56:1e:4f:2f:d5:e2:8e - c2:96:db:5f:2b:6e:c5:cf:4f:20:61:6f:22:50:05:8c - e5:ef:5d:e2:bb:e9:af:79:9d:89:ec:19:b4:ed:7d:e7 - f7:f7:20:b4:b0:7c:57:a2:c4:66:67:bb:e2:29:e3:9c - 07:9c:b0:df:30:36:40:b2:45:12:ed:53:5d:75:4d:a6 - 04:e4:2f:db:92:96:94:be:cb:e8:ac:ee:8d:28:5d:95 - a6:9f:9c:28:d3:c2:87:5e:7b:72:de:f1:ff:16:f8:49 - e4:9d:de:e7:7a:20:23:69:a4:9f:68:b2:db:b0:fc:fb - c2:77:0d:41:0a:ff:66:02:ea:9e:6b:c3:09:dd:7c:bc - 1f:47:66:66:8b:a3:72:e9:94:50:62:97:50:5a:5e:2e - d3: - -public exponent: - 01:00:01: - -private exponent: - 69:3a:96:ec:92:fa:8c:f4:4f:4f:92:40:42:66:96:d5 - 1c:56:76:49:66:52:65:00:bc:32:83:7a:92:8c:15:33 - c7:64:a8:d0:2a:a6:1b:13:cf:82:96:39:8d:0e:be:e5 - e9:d3:f5:86:bf:f4:d0:af:d3:d2:30:0e:55:09:5f:f5 - a9:d4:b7:21:61:a9:12:fb:04:f6:7b:0e:5f:12:6a:3e - fe:b2:9f:8f:a2:93:75:ae:67:c5:87:7e:9b:04:7c:c2 - df:58:c9:8c:d7:86:a4:2b:c7:fa:ba:0b:c6:69:20:40 - 90:b5:76:68:3a:b9:8c:41:a6:3b:ed:71:d0:81:a4:17 - f2:a1:1d:b8:b4:6b:01:6d:a2:e7:9a:6e:9f:b5:a1:14 - 61:7c:66:50:dc:e8:27:67:55:36:50:cc:19:d4:c7:71 - d5:8f:a7:5f:96:f1:74:90:a1:38:1c:8d:b6:37:04:23 - 81:70:24:29:62:b6:e4:85:8d:46:e9:4a:a0:26:12:0f - 40:69:42:25:eb:18:0a:97:93:dc:50:12:85:ff:74:6d - 71:31:d8:45:f8:94:74:ff:43:55:f6:fc:a3:ce:1e:cb - b9:d7:b8:2b:e5:c6:ab:d3:ab:77:60:9c:6b:4c:8e:c0 - 67:a2:37:41:a0:b8:ad:4a:bd:20:1c:29:c8:49:cc:69 - - -prime1: - 00:ed:49:8c:54:96:6b:fe:77:60:f1:93:dd:3d:bc:46 - b2:ec:9e:35:20:cc:8f:63:55:66:90:a4:1e:e3:50:b1 - 51:a3:a7:8b:b1:81:cd:93:cf:0d:4a:ac:c0:a1:81:49 - cb:71:0e:6b:4f:16:75:04:ae:89:53:c1:1d:ac:44:bc - ae:9d:85:85:e9:8c:aa:8e:b9:a8:3e:3d:86:28:b5:c3 - da:35:98:67:70:5a:8b:1f:c2:18:ed:b0:6a:0c:74:b9 - 33:6b:08:e5:93:87:39:b0:44:79:5c:eb:4c:f0:f1:db - c1:41:76:b0:12:46:38:4f:bd:68:db:70:53:13:e8:5f - 95: - -prime2: - 00:fa:40:7d:45:ec:7b:68:68:31:02:9a:ef:b7:a4:35 - a5:7d:d0:be:75:82:39:44:5f:31:98:4d:ff:3b:ec:76 - ce:c3:32:f9:d4:ce:bc:be:4c:3a:72:2f:1d:f6:2c:85 - 0d:15:50:2e:14:19:bb:cc:b5:ad:6c:bc:59:3f:a0:ba - 8b:82:e3:9d:36:93:40:b8:ec:d4:eb:15:59:da:ca:a7 - 10:1e:8e:de:22:c0:96:a5:cb:d3:37:37:4a:4b:58:aa - 13:76:84:58:21:0b:be:8a:b7:c9:04:fd:d9:99:0e:0c - 8a:28:52:50:23:9e:df:80:54:db:16:46:34:18:3b:da - c7: - -coefficient: - 7e:b9:c8:22:2e:b4:07:cd:a1:11:43:4d:48:79:e6:86 - a2:6d:3e:41:85:1e:01:3e:05:77:3d:88:2e:8c:a1:43 - b1:5c:03:3c:d9:37:d8:48:06:fa:bf:de:3e:ad:33:63 - b4:03:f7:84:02:26:22:95:66:03:1d:91:73:20:42:97 - 0e:5d:dd:37:1e:f3:60:80:1b:e4:19:0c:cb:75:bf:30 - fd:38:73:67:9c:c2:68:4c:ff:70:cb:78:6c:b7:5a:1c - a3:a2:cb:a1:f1:f4:17:06:9b:53:96:c3:19:0f:36:98 - 1e:11:f9:ba:a6:cb:5d:d5:82:ae:43:4f:cd:9e:e3:66 - - -exp1: - 2e:c1:d9:67:29:a4:ea:25:b7:f2:a2:82:6c:11:d7:94 - 96:4f:ae:84:62:0a:b7:36:32:d9:b9:9d:64:89:98:07 - 50:4a:49:9a:96:cb:5d:9e:e5:2d:9b:d0:f1:82:3a:7a - 5e:32:cb:2e:70:6c:6a:99:c1:f1:c1:12:09:ca:19:ac - 06:da:32:c3:0c:b6:e7:1c:ea:6c:29:4f:70:62:30:cf - a4:d3:fd:3e:04:79:79:ae:93:9e:f2:ae:52:fa:05:2c - 7e:a0:e8:2c:23:ef:58:2e:86:03:ab:52:24:00:64:9f - 36:39:1f:04:da:d5:69:d1:17:02:76:a5:c8:3c:77:e9 - - -exp2: - 00:84:d4:6a:2a:0d:45:cb:bb:52:18:51:e8:df:8e:d7 - b2:c9:bf:5c:f8:be:70:6b:2c:24:04:f5:91:7e:5b:1b - 0c:d0:6b:64:54:62:8f:a8:6a:89:b3:45:f3:1f:51:ae - 25:ad:a4:6b:70:db:df:e4:de:a1:f8:cf:58:87:ff:66 - 44:da:ea:b9:ed:d7:e7:48:c0:dc:9b:13:30:28:83:dc - 7d:1f:db:31:69:3c:d4:39:98:a0:b9:f4:2d:09:25:3c - d1:2b:dd:3f:71:fa:eb:de:71:82:cf:95:76:44:59:42 - aa:aa:90:56:5d:31:dc:ec:1f:1e:53:0a:5c:68:68:8c - cd: - - -Public Key PIN: - pin-sha256:ehI/YLeqtW2fBULTjESCxxpNnhvQYw9LOVxfrWzyV/g= -Public Key ID: - sha256:7a123f60b7aab56d9f0542d38c4482c71a4d9e1bd0630f4b395c5fad6cf257f8 - sha1:7ec2c93bfa8195429459015e334ef8d5735430b0 - ------BEGIN PRIVATE KEY----- -MIIE7QIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEaMBgGCSqGSIb3 -DQEBCDALBglghkgBZQMEAgKiAwIBMASCBKcwggSjAgEAAoIBAQDn9ZmLaZViOlSA -uUwho9xQuayNUKSY6tqHVYIsxmjkNmx6uB4h2+b6H8JUOsCNLZTOFWZ2gtMnOf8R -+BmZlW1jfjU9F7YtWT/CtLNzdbiy551NfQ2Y47va4kRpvRVSDEXrJHBdR1V5Z1Ye -Ty/V4o7ClttfK27Fz08gYW8iUAWM5e9d4rvpr3mdiewZtO195/f3ILSwfFeixGZn -u+Ip45wHnLDfMDZAskUS7VNddU2mBOQv25KWlL7L6KzujShdlaafnCjTwodee3Le -8f8W+Enknd7neiAjaaSfaLLbsPz7wncNQQr/ZgLqnmvDCd18vB9HZmaLo3LplFBi -l1BaXi7TAgMBAAECggEAaTqW7JL6jPRPT5JAQmaW1RxWdklmUmUAvDKDepKMFTPH -ZKjQKqYbE8+CljmNDr7l6dP1hr/00K/T0jAOVQlf9anUtyFhqRL7BPZ7Dl8Saj7+ -sp+PopN1rmfFh36bBHzC31jJjNeGpCvH+roLxmkgQJC1dmg6uYxBpjvtcdCBpBfy -oR24tGsBbaLnmm6ftaEUYXxmUNzoJ2dVNlDMGdTHcdWPp1+W8XSQoTgcjbY3BCOB -cCQpYrbkhY1G6UqgJhIPQGlCJesYCpeT3FAShf90bXEx2EX4lHT/Q1X2/KPOHsu5 -17gr5car06t3YJxrTI7AZ6I3QaC4rUq9IBwpyEnMaQKBgQDtSYxUlmv+d2Dxk909 -vEay7J41IMyPY1VmkKQe41CxUaOni7GBzZPPDUqswKGBSctxDmtPFnUErolTwR2s -RLyunYWF6YyqjrmoPj2GKLXD2jWYZ3Baix/CGO2wagx0uTNrCOWThzmwRHlc60zw -8dvBQXawEkY4T71o23BTE+hflQKBgQD6QH1F7HtoaDECmu+3pDWlfdC+dYI5RF8x -mE3/O+x2zsMy+dTOvL5MOnIvHfYshQ0VUC4UGbvMta1svFk/oLqLguOdNpNAuOzU -6xVZ2sqnEB6O3iLAlqXL0zc3SktYqhN2hFghC76Kt8kE/dmZDgyKKFJQI57fgFTb -FkY0GDvaxwKBgC7B2WcppOolt/KigmwR15SWT66EYgq3NjLZuZ1kiZgHUEpJmpbL -XZ7lLZvQ8YI6el4yyy5wbGqZwfHBEgnKGawG2jLDDLbnHOpsKU9wYjDPpNP9PgR5 -ea6TnvKuUvoFLH6g6Cwj71guhgOrUiQAZJ82OR8E2tVp0RcCdqXIPHfpAoGBAITU -aioNRcu7UhhR6N+O17LJv1z4vnBrLCQE9ZF+WxsM0GtkVGKPqGqJs0XzH1GuJa2k -a3Db3+TeofjPWIf/ZkTa6rnt1+dIwNybEzAog9x9H9sxaTzUOZigufQtCSU80Svd -P3H6695xgs+VdkRZQqqqkFZdMdzsHx5TClxoaIzNAoGAfrnIIi60B82hEUNNSHnm -hqJtPkGFHgE+BXc9iC6MoUOxXAM82TfYSAb6v94+rTNjtAP3hAImIpVmAx2RcyBC -lw5d3Tce82CAG+QZDMt1vzD9OHNnnMJoTP9wy3hst1oco6LLofH0FwabU5bDGQ82 -mB4R+bqmy13Vgq5DT82e42Y= ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_512.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_512.pem deleted file mode 100644 index 923f6f92ea..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-rsa_pss_512.pem +++ /dev/null @@ -1,138 +0,0 @@ -Public Key Info: - Public Key Algorithm: RSA-PSS - Hash Algorithm: SHA512 - Salt Length: 64 - Key Security Level: Medium (2048 bits) - -modulus: - 00:c2:ce:73:69:95:63:26:85:bd:a0:23:25:5c:94:41 - 04:11:84:78:6c:c9:a3:47:13:47:3b:c4:fe:f3:27:6c - eb:d7:41:a9:4c:e3:15:40:b8:bd:99:02:df:93:a9:bf - 07:de:a2:f1:d1:1e:49:39:2b:64:c7:5e:bb:c7:dd:30 - 07:3c:10:2c:c9:bd:d9:8f:1e:04:60:c1:92:72:44:e6 - 3c:6e:6d:7f:b7:6f:fa:ab:2f:e3:69:7b:0d:1c:31:d5 - 5e:dd:ab:99:0d:4e:80:69:53:3d:d3:63:04:1f:d6:83 - fa:d7:04:c9:3f:75:9c:95:bd:45:34:39:1d:a0:1d:d7 - 06:8e:60:17:a3:94:8f:e9:30:1e:d2:ee:05:42:a4:08 - 86:b7:93:c2:5c:c2:5e:bc:c0:26:5e:98:56:c3:76:87 - e9:9b:1a:3b:f6:bf:c1:6a:4f:f8:46:ba:0b:a8:3a:5e - bb:1d:af:e3:f3:9b:f1:b6:18:70:6d:af:30:62:5f:07 - a9:ff:7b:a2:dd:5f:7e:ff:33:19:80:a2:d7:f9:9e:c5 - a5:22:e7:79:3c:b7:ee:4a:33:c7:c4:72:e6:69:fd:ec - 43:8b:85:86:07:95:15:b9:fe:ed:1c:12:38:ca:ed:cc - 71:ef:9b:69:11:16:e5:1e:78:e0:b3:4d:4c:b4:79:ea - 9f: - -public exponent: - 01:00:01: - -private exponent: - 00:84:ed:bb:73:60:ac:b7:ac:ab:28:8a:d3:03:c9:66 - 54:10:60:04:8c:b7:4a:e3:45:14:66:84:96:33:f5:c3 - 2d:6b:45:32:f1:74:43:1c:56:f3:89:65:9c:8a:76:5a - 14:54:a7:7b:ba:e6:9f:b0:93:1b:c1:af:b3:13:3e:ab - 77:44:55:05:3a:e4:81:80:57:4b:45:7a:d1:23:88:40 - 53:1c:47:3b:cf:40:6a:1c:46:21:37:e8:ef:99:3d:a8 - 0b:83:d7:84:28:c0:58:7f:86:7d:b9:b0:e7:2f:92:81 - 9c:b8:fc:5b:17:22:7a:26:f3:70:35:a2:83:c4:ae:97 - fa:7e:c6:3f:d2:39:9b:fe:f1:e9:c6:d1:68:3e:ac:26 - b4:69:27:c6:1f:50:fc:ab:32:bb:3c:90:13:7e:5c:c0 - 52:0c:34:5d:f7:bd:dd:84:ca:7c:c7:fe:91:8d:60:fe - d7:a7:e3:95:46:b2:ce:a1:4b:af:ba:81:e5:52:7c:68 - 65:5b:9c:84:a5:b6:44:0c:28:b7:c4:19:aa:f5:f7:06 - 35:ac:92:fe:1b:12:f9:17:8f:28:b7:d0:66:3b:a8:5e - 91:6e:c1:06:65:69:97:4e:75:26:59:12:76:3a:3d:9e - ee:21:b4:df:1e:e5:c1:73:5f:cd:e7:4a:2b:66:d8:cc - 81: - -prime1: - 00:c8:9b:6c:7f:a0:08:ce:09:9b:2a:ea:f3:2c:62:d1 - ec:1e:61:7f:da:d1:3a:38:a8:31:4c:57:fa:b9:1c:d8 - 27:fc:ff:d7:79:82:f1:3b:3a:b6:93:f3:61:c8:17:e2 - 73:c8:bc:66:ff:98:9d:5e:31:4f:6b:d5:98:d3:1a:eb - cc:30:ab:f6:ed:1b:62:a4:24:6c:cd:eb:20:9e:d8:52 - 8e:49:b9:47:11:97:2d:0c:89:6c:01:0a:f2:0e:6f:cf - 57:57:7c:57:ce:06:4b:a2:d1:e4:97:91:b2:3b:ef:2a - 38:d1:64:ea:6e:b0:57:c0:93:ed:d6:27:ba:dd:9e:53 - 0b: - -prime2: - 00:f8:98:fc:b3:55:a0:27:40:a8:e2:62:3d:80:4b:13 - 10:1c:a7:22:af:3d:47:57:c4:34:8c:76:4e:95:d7:ff - e8:03:bb:cf:ac:9d:52:3a:c2:d0:91:5f:1c:1d:36:4a - 7e:9d:6d:81:4a:6e:00:f8:96:85:a1:ab:3f:54:d2:03 - ad:0e:d2:c8:c6:fc:b4:62:7e:ab:57:aa:b7:2c:6b:10 - 01:66:5d:ab:d0:5a:9e:02:5b:ad:e1:ab:be:6e:b4:b4 - d1:61:d1:5f:19:22:5c:f5:4e:9e:bd:25:ab:94:a6:be - 8c:a5:7a:2d:2f:f9:5f:55:d3:b8:d8:6d:e9:7c:b5:03 - 3d: - -coefficient: - 7a:dc:e4:d8:ed:ce:71:72:63:b3:a8:4d:c0:1d:fa:a2 - 8a:c4:9f:77:1e:5a:e1:17:d3:1a:f8:20:32:54:30:a7 - 0d:69:40:92:d7:d6:43:bf:b5:83:7e:d5:19:44:bd:3c - 8d:ff:31:ad:8b:bd:6d:ab:a7:34:d7:e3:75:57:02:85 - 8a:c0:78:2d:10:0f:6f:28:da:f7:22:69:40:f4:04:9f - a5:f9:e2:a9:0d:88:06:b4:f3:3c:5e:c6:8c:96:69:7e - f6:09:fa:9c:c6:87:de:a2:a5:9b:4d:22:2a:0b:27:7c - 25:31:26:60:b6:6d:0f:97:6f:48:f2:bf:88:dc:f3:83 - - -exp1: - 1a:20:e4:48:db:37:4a:5e:c5:ef:19:1b:03:34:fb:d2 - 9d:42:65:bc:c2:73:aa:dd:7d:4e:4c:47:43:c5:16:02 - 5f:59:93:5f:28:46:f3:47:fa:6f:da:cb:69:9c:72:ca - 51:e2:f8:27:62:61:5c:db:5f:54:d4:45:4b:79:be:2c - a2:4a:43:a7:2e:61:f2:af:2b:dc:c6:3b:41:75:3b:8b - 7c:de:bc:fa:f5:8d:d0:8c:35:9d:0d:27:e9:e9:76:40 - 12:0d:08:02:b5:9f:34:5d:d2:40:4b:a1:c3:5c:ab:4b - 2b:3a:d1:ae:09:19:e4:e3:5f:9e:fd:1d:c1:af:d5:71 - - -exp2: - 00:f0:6c:55:08:c3:a8:ee:0d:74:c7:ec:a6:fa:2a:a1 - 37:15:de:f6:86:70:47:4d:34:6e:75:e1:fd:42:a1:f1 - d6:db:b5:89:b5:b1:38:d3:a7:91:ba:e6:36:f4:71:8b - 3e:44:d6:a1:11:f0:ad:73:bd:6f:63:d9:90:98:61:bc - 38:64:7b:aa:bd:f7:ac:25:0d:c8:7c:32:98:90:96:c2 - 95:f8:00:63:a8:4f:db:3d:00:99:7c:05:73:58:f1:df - 66:18:aa:3a:c4:be:1d:15:09:82:2f:ff:fc:9e:f9:5c - 93:fd:7d:d9:b1:ea:05:2f:a6:61:c0:bf:1b:ef:05:c9 - 29: - - -Public Key PIN: - pin-sha256:ucGhof6fwEGIty3XlESZXFYnapJIa30Xc+yIYUtVbKY= -Public Key ID: - sha256:b9c1a1a1fe9fc04188b72dd79444995c56276a92486b7d1773ec88614b556ca6 - sha1:f0f7effab3260ffefd0c2c57c196d20d0fd4bd3b - ------BEGIN PRIVATE KEY----- -MIIE7gIBADA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCA6EaMBgGCSqGSIb3 -DQEBCDALBglghkgBZQMEAgOiAwIBQASCBKgwggSkAgEAAoIBAQDCznNplWMmhb2g -IyVclEEEEYR4bMmjRxNHO8T+8yds69dBqUzjFUC4vZkC35OpvwfeovHRHkk5K2TH -XrvH3TAHPBAsyb3Zjx4EYMGSckTmPG5tf7dv+qsv42l7DRwx1V7dq5kNToBpUz3T -YwQf1oP61wTJP3Wclb1FNDkdoB3XBo5gF6OUj+kwHtLuBUKkCIa3k8Jcwl68wCZe -mFbDdofpmxo79r/Bak/4RroLqDpeux2v4/Ob8bYYcG2vMGJfB6n/e6LdX37/MxmA -otf5nsWlIud5PLfuSjPHxHLmaf3sQ4uFhgeVFbn+7RwSOMrtzHHvm2kRFuUeeOCz -TUy0eeqfAgMBAAECggEBAITtu3NgrLesqyiK0wPJZlQQYASMt0rjRRRmhJYz9cMt -a0Uy8XRDHFbziWWcinZaFFSne7rmn7CTG8GvsxM+q3dEVQU65IGAV0tFetEjiEBT -HEc7z0BqHEYhN+jvmT2oC4PXhCjAWH+Gfbmw5y+SgZy4/FsXInom83A1ooPErpf6 -fsY/0jmb/vHpxtFoPqwmtGknxh9Q/KsyuzyQE35cwFIMNF33vd2EynzH/pGNYP7X -p+OVRrLOoUuvuoHlUnxoZVuchKW2RAwot8QZqvX3BjWskv4bEvkXjyi30GY7qF6R -bsEGZWmXTnUmWRJ2Oj2e7iG03x7lwXNfzedKK2bYzIECgYEAyJtsf6AIzgmbKurz -LGLR7B5hf9rROjioMUxX+rkc2Cf8/9d5gvE7OraT82HIF+JzyLxm/5idXjFPa9WY -0xrrzDCr9u0bYqQkbM3rIJ7YUo5JuUcRly0MiWwBCvIOb89XV3xXzgZLotHkl5Gy -O+8qONFk6m6wV8CT7dYnut2eUwsCgYEA+Jj8s1WgJ0Co4mI9gEsTEBynIq89R1fE -NIx2TpXX/+gDu8+snVI6wtCRXxwdNkp+nW2BSm4A+JaFoas/VNIDrQ7SyMb8tGJ+ -q1eqtyxrEAFmXavQWp4CW63hq75utLTRYdFfGSJc9U6evSWrlKa+jKV6LS/5X1XT -uNht6Xy1Az0CgYAaIORI2zdKXsXvGRsDNPvSnUJlvMJzqt19TkxHQ8UWAl9Zk18o -RvNH+m/ay2mccspR4vgnYmFc219U1EVLeb4sokpDpy5h8q8r3MY7QXU7i3zevPr1 -jdCMNZ0NJ+npdkASDQgCtZ80XdJAS6HDXKtLKzrRrgkZ5ONfnv0dwa/VcQKBgQDw -bFUIw6juDXTH7Kb6KqE3Fd72hnBHTTRudeH9QqHx1tu1ibWxONOnkbrmNvRxiz5E -1qER8K1zvW9j2ZCYYbw4ZHuqvfesJQ3IfDKYkJbClfgAY6hP2z0AmXwFc1jx32YY -qjrEvh0VCYIv//ye+VyT/X3ZseoFL6ZhwL8b7wXJKQKBgHrc5NjtznFyY7OoTcAd -+qKKxJ93HlrhF9Ma+CAyVDCnDWlAktfWQ7+1g37VGUS9PI3/Ma2LvW2rpzTX43VX -AoWKwHgtEA9vKNr3ImlA9ASfpfniqQ2IBrTzPF7GjJZpfvYJ+pzGh96ipZtNIioL -J3wlMSZgtm0Pl29I8r+I3POD ------END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa-enc.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa-enc.pem deleted file mode 100644 index bd4bee0a74..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa-enc.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDQjCCAiqgAwIBAgIMWYGU8Ba6TGDaJ+vVMA0GCSqGSIb3DQEBCwUAMCMxITAf -BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzZa -Fw0zNzA3MjgwOTAxMzZaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IFNl -cnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALeY49te/YFa6Od8 -0bFjD8k1vJbupBNoqdmiAT9oiHmbzqGKePtqC1XZQOwFe9pBJOuny9fAo2v0hhdU -sS9PmUzyaP4YOUnWOEpujU4Ntk9jtvWrl7VG0xSE1fcaBkN6+ssvRO3+D3XYoPhT -u9OxLZNDfmFc5DpuSc31VY2Fq3SVD8vrSrZCh892T0/J0VlX0LGSga/BXUGqJOkm -ISWgUB/eHTsaKb97cro6VTZyL4tvr+69IM+I4hVg8FRGZWOzj2wuFraMOPnUgjj0 -qk9snA1RP3TZWu+hHCGtY/wXFg7RDEb0nTsh2w0tAvNVYHHPTeore/5T9qQ7VBC7 -KtabDr0CAwEAAaN2MHQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcD -ATAPBgNVHQ8BAf8EBQMDByAAMB0GA1UdDgQWBBQwgymoaNHkuh20njTXz48/R+kl -yDAfBgNVHSMEGDAWgBQrQlWadXqqzBV+2iw7BZXrvFHaQjANBgkqhkiG9w0BAQsF -AAOCAQEA3kf9yAMYuPlBW2/y7UiKZGu6IVuxpmy+IFKeNIH6MNN9AsEHM1Yx4F1O -c4UGHxEPoKj5k1cEjiNH4hcaAR/Gukq7efHtf98WGlEp8E8ctjkK6Eu3+hOLHQ01 -YjV76BOkWzOI6DwFYNa71Jae44A8QUFhdq3c874KwwX2VkKcfenb7SzfWn/93DpR -L899PIzXWggADuRGb2S6L35DNk6sHQR8CwkT/HxZr/xqeAVP0qaXtkSPoPntVw6Z -MIUFcmC7XbDuyo1Or3iCMgdsuqP88KWDqP7vF2Bu8deES4wQeIGBSl4e6kweesbY -ASRKL9Qf3tPtKVGp0zvJbfSsOc+wig== ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa-sign.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa-sign.pem deleted file mode 100644 index 09818af868..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa-sign.pem +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDQjCCAiqgAwIBAgIMWYGU8DJRSWC13gO8MA0GCSqGSIb3DQEBCwUAMCMxITAf -BgNVBAMTGEJvdW5jeUNhc3RsZSBUTFMgVGVzdCBDQTAeFw0xNzA4MDIwOTAxMzZa -Fw0zNzA3MjgwOTAxMzZaMCMxITAfBgNVBAMTGEJvdW5jeUNhc3RsZSBUZXN0IFNl -cnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALxfBvZ55WpVQeCh -tVyd+O/sLueGVkBlYURusklcLCqdthM5QTLBVMOQ2vtxWnZDSHWIvPUPCnPxR8Is -PvsM8BUqQjyj2d9CcvuNNgwKMIzUA10bQLPQ66ac1T7MU/2A4R+xxJN5ZOp4B+Uw -EwNAeAVfQ9XZX+HkmVAjKPJiRzmjdzoAslQR0F5zL11gjmS8STwZuJ+2MpUh09VG -dHJ+LB1CNVfnExwPqR3wd1TQPULXZN3Dx+f0W27gmA4GRitMtLltAljvZzGt6+xh -byKJJjMnTBWlzFFiP/ggpcPs+q2hW9i3vPCE5eOGdkbDnXJi3aiBxYpTKeS54wGc -/OkTv5UCAwEAAaN2MHQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcD -ATAPBgNVHQ8BAf8EBQMDB4AAMB0GA1UdDgQWBBTXwO7kKzgzAOC9j607abavBMKy -aTAfBgNVHSMEGDAWgBQrQlWadXqqzBV+2iw7BZXrvFHaQjANBgkqhkiG9w0BAQsF -AAOCAQEAAYRsE0f2BkOlNWj1SNiwoWkw4Ic6WW1X43yh3L17c5hRLOGPupDngJBA -EYTmsEfq26XX4mGlKXKgKZW2ijcrIQSkHEjkXHYdU+OI+4xufeNtGMYLijcwVKXM -mmSe8ERWODdCfzDJSRdLx/NgLeWphMQLaym1TkK29lASyqIbCNATXGnMw3bcMLvU -cXnjHtNU1tlYtVNCStvm2buy+vdVEGIsusqk+aetniEttBlQcPwuRMvbYmIDuRJP -Bxsst/t32W+s8Eb2dqbSKm6TucOG5o7oXKH6l15d+ARRJJ3C3nODBvsYgSqg1Vtm -7H0K9I4dLZoMUb4tWjSA9ckNU0nuKQ== ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_256.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_256.pem deleted file mode 100644 index 0ebfa2e204..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_256.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID2jCCApKgAwIBAgIUODLkLENJ2mZJLwlk5OXY6ebyHp8wPQYJKoZIhvcNAQEK -MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC -ASAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy -NDA2MDY0MloXDTM4MTAxOTA2MDY0MlowIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl -IFRlc3QgU2VydmVyMIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEa -MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIBIAOCAQ8AMIIBCgKCAQEAodS9 -1Z/KfuXUf0lSeDPWsC83pKL4SzK179UpnH0urGmwsRoJffGSOq7E0SljG11g000G -P7x/RsciwpjgLDL7mpTx6rk7N0tEi79gKBNr6TGmD+I9gmCdKIvUY3/hBs/WgaEk -77SlOgWVFuXGneFuMVaSExbEK1Mgc1eWnXpLvujwUBpVGB7ZafL2teU6mLZ3e/8w -dJ9tgVVQtT6BjVT2zBc9GxC/aXcJ0di+eRGsO74ZaVyxUE26BAmYdHrjlkhN/Gd6 -NHN2SF5BBWFaaFk5s4aqeCj0pkrbb4VHdXWiJOkhPxjJRoeRgBr1+u0rqwPo7cPd -Z61G65t+RNJcdks9XwIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG -CCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHgAAwHQYDVR0OBBYEFAbF9tL09Ej6Z7oS -/pVe++Ff69FkMB8GA1UdIwQYMBaAFCEaiLbeA8ABgKrbcIiZpo8XzqpsMD0GCSqG -SIb3DQEBCjAwoA0wCwYJYIZIAWUDBAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFl -AwQCAaIDAgEgA4IBAQBQJnvKt+zUFenmqBo8zGAUQdNYcIp5JhmTP2JbgWlNjTkj -Tsc3i/rWKA0pxydWgQPL6VKBPiqFIQcuPEw6D9zQxRQpnOveRDTkDzcLbt/c5asO -6TpHYqlSujeW7TEH0WLBg0uAHuRUclKYB1/2gSU0MUVtG/sZkh213vEx56F56iqx -sXFDnt9pyu0tLE0nWWtY3dxGAYJpL1HGZ2ey//Tf0+lsS0t8iH0vAtUmssKJpA79 -76biXCHAVcL07O5jMwrF4v7ki/G7RQRQ+qrL03xBifAzKuczu4Ls++Wg7V4MUERj -mpw4pbRBam9Sz3uwc1qA+Ul0TCHzMDAFWyMod0ND ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_384.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_384.pem deleted file mode 100644 index 3506f48b27..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_384.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID2jCCApKgAwIBAgIUBSXp/i1JJIcj2ytjBNKJ0tbxKjYwPQYJKoZIhvcNAQEK -MDCgDTALBglghkgBZQMEAgKhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAICogMC -ATAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy -NDA3NTY0OVoXDTM4MTAxOTA3NTY0OVowIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl -IFRlc3QgU2VydmVyMIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAqEa -MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgKiAwIBMAOCAQ8AMIIBCgKCAQEA5/WZ -i2mVYjpUgLlMIaPcULmsjVCkmOrah1WCLMZo5DZsergeIdvm+h/CVDrAjS2UzhVm -doLTJzn/EfgZmZVtY341PRe2LVk/wrSzc3W4suedTX0NmOO72uJEab0VUgxF6yRw -XUdVeWdWHk8v1eKOwpbbXytuxc9PIGFvIlAFjOXvXeK76a95nYnsGbTtfef39yC0 -sHxXosRmZ7viKeOcB5yw3zA2QLJFEu1TXXVNpgTkL9uSlpS+y+is7o0oXZWmn5wo -08KHXnty3vH/FvhJ5J3e53ogI2mkn2iy27D8+8J3DUEK/2YC6p5rwwndfLwfR2Zm -i6Ny6ZRQYpdQWl4u0wIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG -CCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHgAAwHQYDVR0OBBYEFH7CyTv6gZVClFkB -XjNO+NVzVDCwMB8GA1UdIwQYMBaAFKnwXW9hoPAB6HSyWn7UEUMcKonnMD0GCSqG -SIb3DQEBCjAwoA0wCwYJYIZIAWUDBAICoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFl -AwQCAqIDAgEwA4IBAQAt1xrrBujilh2NVclsaRoqD+QJ7QhDdFVbS2zBJTVz7nds -TMu9iU/dXAp2zdsmpXi3mKStgYWS1yjSdyKyBy4v7EwGx5qHrcnMzyfX2BelGDk7 -OYCXGaFweAqRUh8SchYA1+Dlwg7ub+SpGkDnA76LgBcHFoC7AMozLOeY6GNT4qdq -64+jFvCFrDVC4xMvMB3+vwdlDIIyr9uY3z9Axw35IRPyVHJnyiLu/OIwD7Vw9A4n -11WrUXZ2fvqJUcSvwqdHRAy1kj9LsagfEXatJ79ZC2En2XhEs+PHTgtqw5UdPk16 -dVIlgPTQ/Te+ttubJPsKOpgKj8YOiNtnEZdzpJUP ------END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_512.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_512.pem deleted file mode 100644 index 51e323b43c..0000000000 --- a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-rsa_pss_512.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID2jCCApKgAwIBAgIUV12PGXPx0Jj7USRKsKNrWFqJRHEwPQYJKoZIhvcNAQEK -MDCgDTALBglghkgBZQMEAgOhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIDogMC -AUAwIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxlIFRMUyBUZXN0IENBMB4XDTE4MTAy -NDA2MDY0M1oXDTM4MTAxOTA2MDY0M1owIzEhMB8GA1UEAxMYQm91bmN5Q2FzdGxl -IFRlc3QgU2VydmVyMIIBUjA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCA6Ea -MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgOiAwIBQAOCAQ8AMIIBCgKCAQEAws5z -aZVjJoW9oCMlXJRBBBGEeGzJo0cTRzvE/vMnbOvXQalM4xVAuL2ZAt+Tqb8H3qLx -0R5JOStkx167x90wBzwQLMm92Y8eBGDBknJE5jxubX+3b/qrL+Npew0cMdVe3auZ -DU6AaVM902MEH9aD+tcEyT91nJW9RTQ5HaAd1waOYBejlI/pMB7S7gVCpAiGt5PC -XMJevMAmXphWw3aH6ZsaO/a/wWpP+Ea6C6g6Xrsdr+Pzm/G2GHBtrzBiXwep/3ui -3V9+/zMZgKLX+Z7FpSLneTy37kozx8Ry5mn97EOLhYYHlRW5/u0cEjjK7cxx75tp -ERblHnjgs01MtHnqnwIDAQABo3YwdDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG -CCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMHgAAwHQYDVR0OBBYEFPD37/qzJg/+/Qws -V8GW0g0P1L07MB8GA1UdIwQYMBaAFKVY4bgN1p+8NOXoPdj6DKWDscBFMD0GCSqG -SIb3DQEBCjAwoA0wCwYJYIZIAWUDBAIDoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFl -AwQCA6IDAgFAA4IBAQCVRYStZNCUKNzu+kBiHBVJn5Dbu97s3jHBw0ACphUp+M75 -O1ohoT+ny3wgIJx4sN1Fc80cT24o1V48nI4nJTlgAhYyjYjaMilHpwLP4oLclQX8 -OUoyoTPIIRfP4UNRmxAtH+2eEGieO1QDsYyqsGKR9DeWme4t4dc/NTuZ8/E3UW9C -m0VO0ev3m8ZGfWANRP0yyjnvke4I5awFur9ncGn3vwZYJLDlV9dwi3B68VUzt4Um -jz4yhgCU+kOqID/HXgWUCosreQGN+KqungUlENOVvBV4sTfQpnaAJaKpT4zkEYMP -sRkBrV12dCYh4NIpqDsnjSpWEuDlpT4F3hJx2BqU ------END CERTIFICATE----- diff --git a/util/build.gradle b/util/build.gradle index 60e3361bdc..e938c2e77b 100644 --- a/util/build.gradle +++ b/util/build.gradle @@ -1,6 +1,6 @@ plugins { - id "biz.aQute.bnd.builder" version "7.0.0" + id "biz.aQute.bnd.builder" version "7.1.0" } jar.archiveBaseName = "bcutil-$vmrange" @@ -66,6 +66,11 @@ jar { manifest.attributes('Export-Package': "${packages};version=${v},org.bouncycastle.oer.*;version=${v}") manifest.attributes('Import-Package': "java.*;resolution:=optional,javax.*;resolution:=optional,!${packages},!org.bouncycastle.oer.*,org.bouncycastle.*;version=\"[${v},${maxVersion})\"") manifest.attributes('Bundle-Version': "${v}") + manifest.attributes('Permissions': 'all-permissions') + manifest.attributes('Codebase': '*') + manifest.attributes('Application-Library-Allowable-Codebase': '*') + manifest.attributes('Caller-Allowable-Codebase': '*') + manifest.attributes('Trusted-Library': 'true') } jar.doLast { diff --git a/util/src/main/java/org/bouncycastle/asn1/bsi/BSIObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/bsi/BSIObjectIdentifiers.java index 290b3f2640..62d510ae6d 100644 --- a/util/src/main/java/org/bouncycastle/asn1/bsi/BSIObjectIdentifiers.java +++ b/util/src/main/java/org/bouncycastle/asn1/bsi/BSIObjectIdentifiers.java @@ -11,10 +11,10 @@ public interface BSIObjectIdentifiers /* 0.4.0.127.0.7.1.1 */ static final ASN1ObjectIdentifier id_ecc = bsi_de.branch("1.1"); - + /* 0.4.0.127.0.7.1.1.4.1 */ static final ASN1ObjectIdentifier ecdsa_plain_signatures = id_ecc.branch("4.1"); - + /* 0.4.0.127.0.7.1.1.4.1.1 */ static final ASN1ObjectIdentifier ecdsa_plain_SHA1 = ecdsa_plain_signatures.branch("1"); @@ -93,23 +93,23 @@ public interface BSIObjectIdentifiers static final ASN1ObjectIdentifier ecka_eg_SessionKDF_AES192 = ecka_eg_SessionKDF.branch("3"); static final ASN1ObjectIdentifier ecka_eg_SessionKDF_AES256 = ecka_eg_SessionKDF.branch("4"); - /** AES encryption (CBC) and authentication (CMAC) + /* AES encryption (CBC) and authentication (CMAC) * OID: 0.4.0.127.0.7.1.x */ //TODO: replace "1" with correct OID //static final ASN1ObjectIdentifier aes_cbc_cmac = algorithm.branch("1"); - /** AES encryption (CBC) and authentication (CMAC) with 128 bit + /* AES encryption (CBC) and authentication (CMAC) with 128 bit * OID: 0.4.0.127.0.7.1.x.y1 */ //TODO: replace "1" with correct OID //static final ASN1ObjectIdentifier id_aes128_CBC_CMAC = aes_cbc_cmac.branch("1"); - /** AES encryption (CBC) and authentication (CMAC) with 192 bit + /* AES encryption (CBC) and authentication (CMAC) with 192 bit * OID: 0.4.0.127.0.7.1.x.y2 */ //TODO: replace "1" with correct OID //static final ASN1ObjectIdentifier id_aes192_CBC_CMAC = aes_cbc_cmac.branch("1"); - /** AES encryption (CBC) and authentication (CMAC) with 256 bit + /* AES encryption (CBC) and authentication (CMAC) with 256 bit * OID: 0.4.0.127.0.7.1.x.y3 */ //TODO: replace "1" with correct OID //static final ASN1ObjectIdentifier id_aes256_CBC_CMAC = aes_cbc_cmac.branch("1"); diff --git a/util/src/main/java/org/bouncycastle/asn1/cmc/BodyPartID.java b/util/src/main/java/org/bouncycastle/asn1/cmc/BodyPartID.java index 5d09025677..21977681f7 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmc/BodyPartID.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmc/BodyPartID.java @@ -66,6 +66,6 @@ public long getID() public ASN1Primitive toASN1Primitive() { - return new ASN1Integer(id); + return ASN1Integer.valueOf(id); } } diff --git a/util/src/main/java/org/bouncycastle/asn1/cmc/CMCFailInfo.java b/util/src/main/java/org/bouncycastle/asn1/cmc/CMCFailInfo.java index b71dd14fa5..205688678a 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmc/CMCFailInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmc/CMCFailInfo.java @@ -30,20 +30,20 @@ public class CMCFailInfo extends ASN1Object { - public static final CMCFailInfo badAlg = new CMCFailInfo(new ASN1Integer(0)); - public static final CMCFailInfo badMessageCheck = new CMCFailInfo(new ASN1Integer(1)); - public static final CMCFailInfo badRequest = new CMCFailInfo(new ASN1Integer(2)); - public static final CMCFailInfo badTime = new CMCFailInfo(new ASN1Integer(3)); - public static final CMCFailInfo badCertId = new CMCFailInfo(new ASN1Integer(4)); - public static final CMCFailInfo unsupportedExt = new CMCFailInfo(new ASN1Integer(5)); - public static final CMCFailInfo mustArchiveKeys = new CMCFailInfo(new ASN1Integer(6)); - public static final CMCFailInfo badIdentity = new CMCFailInfo(new ASN1Integer(7)); - public static final CMCFailInfo popRequired = new CMCFailInfo(new ASN1Integer(8)); - public static final CMCFailInfo popFailed = new CMCFailInfo(new ASN1Integer(9)); - public static final CMCFailInfo noKeyReuse = new CMCFailInfo(new ASN1Integer(10)); - public static final CMCFailInfo internalCAError = new CMCFailInfo(new ASN1Integer(11)); - public static final CMCFailInfo tryLater = new CMCFailInfo(new ASN1Integer(12)); - public static final CMCFailInfo authDataFail = new CMCFailInfo(new ASN1Integer(13)); + public static final CMCFailInfo badAlg = new CMCFailInfo(ASN1Integer.valueOf(0)); + public static final CMCFailInfo badMessageCheck = new CMCFailInfo(ASN1Integer.valueOf(1)); + public static final CMCFailInfo badRequest = new CMCFailInfo(ASN1Integer.valueOf(2)); + public static final CMCFailInfo badTime = new CMCFailInfo(ASN1Integer.valueOf(3)); + public static final CMCFailInfo badCertId = new CMCFailInfo(ASN1Integer.valueOf(4)); + public static final CMCFailInfo unsupportedExt = new CMCFailInfo(ASN1Integer.valueOf(5)); + public static final CMCFailInfo mustArchiveKeys = new CMCFailInfo(ASN1Integer.valueOf(6)); + public static final CMCFailInfo badIdentity = new CMCFailInfo(ASN1Integer.valueOf(7)); + public static final CMCFailInfo popRequired = new CMCFailInfo(ASN1Integer.valueOf(8)); + public static final CMCFailInfo popFailed = new CMCFailInfo(ASN1Integer.valueOf(9)); + public static final CMCFailInfo noKeyReuse = new CMCFailInfo(ASN1Integer.valueOf(10)); + public static final CMCFailInfo internalCAError = new CMCFailInfo(ASN1Integer.valueOf(11)); + public static final CMCFailInfo tryLater = new CMCFailInfo(ASN1Integer.valueOf(12)); + public static final CMCFailInfo authDataFail = new CMCFailInfo(ASN1Integer.valueOf(13)); private static Map range = new HashMap(); diff --git a/util/src/main/java/org/bouncycastle/asn1/cmc/CMCObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/cmc/CMCObjectIdentifiers.java index 40731daf36..90ef2b46ae 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmc/CMCObjectIdentifiers.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmc/CMCObjectIdentifiers.java @@ -11,14 +11,14 @@ public interface CMCObjectIdentifiers // id_pkix OBJECT IDENTIFIER ::= { iso(1) identified_organization(3) // dod(6) internet(1) security(5) mechanisms(5) pkix(7) } ASN1ObjectIdentifier id_pkix = new ASN1ObjectIdentifier("1.3.6.1.5.5.7"); - + ASN1ObjectIdentifier id_cmc = id_pkix.branch("7"); // CMC controls ASN1ObjectIdentifier id_cct = id_pkix.branch("12"); // CMC content types ASN1ObjectIdentifier id_kp = id_pkix.branch("3"); // KP // The following controls have the type OCTET STRING - + ASN1ObjectIdentifier id_cmc_identityProof = id_cmc.branch("3"); ASN1ObjectIdentifier id_cmc_dataReturn = id_cmc.branch("4"); ASN1ObjectIdentifier id_cmc_regInfo = id_cmc.branch("18"); @@ -26,22 +26,22 @@ public interface CMCObjectIdentifiers ASN1ObjectIdentifier id_cmc_queryPending = id_cmc.branch("21"); ASN1ObjectIdentifier id_cmc_popLinkRandom = id_cmc.branch("22"); ASN1ObjectIdentifier id_cmc_popLinkWitness = id_cmc.branch("23"); - + // The following controls have the type UTF8String - + ASN1ObjectIdentifier id_cmc_identification = id_cmc.branch("2"); - + // The following controls have the type INTEGER - + ASN1ObjectIdentifier id_cmc_transactionId = id_cmc.branch("5"); - + // The following controls have the type OCTET STRING - + ASN1ObjectIdentifier id_cmc_senderNonce = id_cmc.branch("6"); ASN1ObjectIdentifier id_cmc_recipientNonce = id_cmc.branch("7"); - + // This is the content type used for a request message in the protocol - + ASN1ObjectIdentifier id_cct_PKIData = id_cct.branch("2"); // This defines the response message in the protocol @@ -99,7 +99,7 @@ public interface CMCObjectIdentifiers // Identity Proof control w/ algorithm agility ASN1ObjectIdentifier id_cmc_identityProofV2 = id_cmc.branch("34"); - + ASN1ObjectIdentifier id_cmc_popLinkWitnessV2 = id_cmc.branch("33"); // Extended key usage diff --git a/util/src/main/java/org/bouncycastle/asn1/cmc/CMCStatus.java b/util/src/main/java/org/bouncycastle/asn1/cmc/CMCStatus.java index 8aa8c85d88..8bef9655cc 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmc/CMCStatus.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmc/CMCStatus.java @@ -24,13 +24,13 @@ public class CMCStatus extends ASN1Object { - public static final CMCStatus success = new CMCStatus(new ASN1Integer(0)); - public static final CMCStatus failed = new CMCStatus(new ASN1Integer(2)); - public static final CMCStatus pending = new CMCStatus(new ASN1Integer(3)); - public static final CMCStatus noSupport = new CMCStatus(new ASN1Integer(4)); - public static final CMCStatus confirmRequired = new CMCStatus(new ASN1Integer(5)); - public static final CMCStatus popRequired = new CMCStatus(new ASN1Integer(6)); - public static final CMCStatus partial = new CMCStatus(new ASN1Integer(7)); + public static final CMCStatus success = new CMCStatus(ASN1Integer.valueOf(0)); + public static final CMCStatus failed = new CMCStatus(ASN1Integer.valueOf(2)); + public static final CMCStatus pending = new CMCStatus(ASN1Integer.valueOf(3)); + public static final CMCStatus noSupport = new CMCStatus(ASN1Integer.valueOf(4)); + public static final CMCStatus confirmRequired = new CMCStatus(ASN1Integer.valueOf(5)); + public static final CMCStatus popRequired = new CMCStatus(ASN1Integer.valueOf(6)); + public static final CMCStatus partial = new CMCStatus(ASN1Integer.valueOf(7)); private static Map range = new HashMap(); diff --git a/util/src/main/java/org/bouncycastle/asn1/cmc/CertificationRequest.java b/util/src/main/java/org/bouncycastle/asn1/cmc/CertificationRequest.java index 5b111ac646..09931b75bf 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmc/CertificationRequest.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmc/CertificationRequest.java @@ -35,8 +35,6 @@ public class CertificationRequest extends ASN1Object { - private static final ASN1Integer ZERO = new ASN1Integer(0); - private final CertificationRequestInfo certificationRequestInfo; private final AlgorithmIdentifier signatureAlgorithm; private final ASN1BitString signature; @@ -173,9 +171,9 @@ private CertificationRequestInfo( private CertificationRequestInfo(X500Name subject, AlgorithmIdentifier algorithm, ASN1BitString subjectPublicKey, ASN1Set attributes) { - this.version = ZERO; + this.version = ASN1Integer.ZERO; this.subject = subject; - this.subjectPublicKeyInfo = new DERSequence(new ASN1Encodable[] { algorithm, subjectPublicKey }); + this.subjectPublicKeyInfo = new DERSequence(algorithm, subjectPublicKey); this.attributes = attributes; } diff --git a/util/src/main/java/org/bouncycastle/asn1/cmc/IdentityProofV2.java b/util/src/main/java/org/bouncycastle/asn1/cmc/IdentityProofV2.java index 955d768fa1..0a0c486067 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmc/IdentityProofV2.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmc/IdentityProofV2.java @@ -26,14 +26,14 @@ public class IdentityProofV2 private final AlgorithmIdentifier proofAlgID; private final AlgorithmIdentifier macAlgId; private final byte[] witness; - + public IdentityProofV2(AlgorithmIdentifier proofAlgID, AlgorithmIdentifier macAlgId, byte[] witness) { this.proofAlgID = proofAlgID; this.macAlgId = macAlgId; this.witness = Arrays.clone(witness); } - + private IdentityProofV2(ASN1Sequence seq) { if (seq.size() != 3) @@ -59,7 +59,7 @@ public static IdentityProofV2 getInstance(Object o) return null; } - + public AlgorithmIdentifier getProofAlgID() { return proofAlgID; @@ -74,15 +74,15 @@ public byte[] getWitness() { return Arrays.clone(witness); } - + public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(3); - + v.add(proofAlgID); v.add(macAlgId); v.add(new DEROctetString(getWitness())); - + return new DERSequence(v); } } diff --git a/util/src/main/java/org/bouncycastle/asn1/cmc/OtherStatusInfo.java b/util/src/main/java/org/bouncycastle/asn1/cmc/OtherStatusInfo.java index 46ef16aff9..d596896bc8 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmc/OtherStatusInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmc/OtherStatusInfo.java @@ -61,7 +61,7 @@ else if (obj instanceof byte[]) { throw new IllegalArgumentException("parsing error: " + e.getMessage()); } - } + } throw new IllegalArgumentException("unknown object in getInstance(): " + obj.getClass().getName()); } diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/CMPCertificate.java b/util/src/main/java/org/bouncycastle/asn1/cmp/CMPCertificate.java index 012f2e06b3..10942312a1 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/CMPCertificate.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/CMPCertificate.java @@ -7,7 +7,6 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.x509.AttributeCertificate; import org.bouncycastle.asn1.x509.Certificate; @@ -97,7 +96,7 @@ public static CMPCertificate getInstance(Object o) if (o instanceof ASN1TaggedObject) { - ASN1TaggedObject taggedObject = ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC); + ASN1TaggedObject taggedObject = ASN1TaggedObject.getContextInstance(o); return new CMPCertificate(taggedObject.getTagNo(), taggedObject.getBaseObject()); } diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/CertAnnContent.java b/util/src/main/java/org/bouncycastle/asn1/cmp/CertAnnContent.java index 129752dee5..0ad6bd209d 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/CertAnnContent.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/CertAnnContent.java @@ -6,7 +6,6 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.x509.AttributeCertificate; import org.bouncycastle.asn1.x509.Certificate; @@ -92,7 +91,7 @@ public static CertAnnContent getInstance(Object o) if (o instanceof ASN1TaggedObject) { - ASN1TaggedObject taggedObject = ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC); + ASN1TaggedObject taggedObject = ASN1TaggedObject.getContextInstance(o); return new CertAnnContent(taggedObject.getTagNo(), taggedObject.getExplicitBaseObject()); } diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/CertOrEncCert.java b/util/src/main/java/org/bouncycastle/asn1/cmp/CertOrEncCert.java index b660cea49d..39e4b21c69 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/CertOrEncCert.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/CertOrEncCert.java @@ -5,7 +5,6 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.ASN1Util; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.crmf.EncryptedKey; import org.bouncycastle.asn1.crmf.EncryptedValue; @@ -78,7 +77,7 @@ public static CertOrEncCert getInstance(Object o) if (o instanceof ASN1TaggedObject) { - return new CertOrEncCert(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC)); + return new CertOrEncCert(ASN1TaggedObject.getContextInstance(o)); } return null; diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/CertifiedKeyPair.java b/util/src/main/java/org/bouncycastle/asn1/cmp/CertifiedKeyPair.java index f362082e8a..782820c4cc 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/CertifiedKeyPair.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/CertifiedKeyPair.java @@ -5,7 +5,6 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.crmf.EncryptedKey; @@ -37,7 +36,7 @@ private CertifiedKeyPair(ASN1Sequence seq) { if (seq.size() == 2) { - ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(seq.getObjectAt(1), BERTags.CONTEXT_SPECIFIC); + ASN1TaggedObject tagged = ASN1TaggedObject.getContextInstance(seq.getObjectAt(1)); if (tagged.getTagNo() == 0) { privateKey = EncryptedKey.getInstance(tagged.getExplicitBaseObject()); @@ -49,8 +48,8 @@ private CertifiedKeyPair(ASN1Sequence seq) } else { - privateKey = EncryptedKey.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(1), BERTags.CONTEXT_SPECIFIC).getExplicitBaseObject()); - publicationInfo = PKIPublicationInfo.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(2), BERTags.CONTEXT_SPECIFIC).getExplicitBaseObject()); + privateKey = EncryptedKey.getInstance(ASN1TaggedObject.getContextInstance(seq.getObjectAt(1)).getExplicitBaseObject()); + publicationInfo = PKIPublicationInfo.getInstance(ASN1TaggedObject.getContextInstance(seq.getObjectAt(2)).getExplicitBaseObject()); } } } diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/Challenge.java b/util/src/main/java/org/bouncycastle/asn1/cmp/Challenge.java index cf447017aa..97fe1411b2 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/Challenge.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/Challenge.java @@ -7,8 +7,11 @@ 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.asn1.cms.EnvelopedData; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.GeneralName; @@ -26,15 +29,15 @@ * -- the result of applying the one-way function (owf) to a * -- randomly-generated INTEGER, A. [Note that a different * -- INTEGER MUST be used for each Challenge.] - * challenge OCTET STRING + * challenge OCTET STRING -- deprecated * -- the encryption (under the public key for which the cert. - * -- request is being made) of Rand, where Rand is specified as - * -- Rand ::= SEQUENCE { - * -- int INTEGER, - * -- - the randomly-generated INTEGER A (above) - * -- sender GeneralName - * -- - the sender's name (as included in PKIHeader) - * -- } + * -- request is being made) of Rand + * encryptedRand [0] EnvelopedData OPTIONAL + * } + * + * Rand ::= SEQUENCE { + * int INTEGER, -- the randomly-generated INTEGER A (above) + * sender GeneralName -- the sender's name (as included in PKIHeader) * } * */ @@ -44,12 +47,13 @@ public class Challenge private final AlgorithmIdentifier owf; private final ASN1OctetString witness; private final ASN1OctetString challenge; + private final EnvelopedData encryptedRand; private Challenge(ASN1Sequence seq) { int index = 0; - if (seq.size() == 3) + if (seq.getObjectAt(0).toASN1Primitive() instanceof ASN1Sequence) { owf = AlgorithmIdentifier.getInstance(seq.getObjectAt(index++)); } @@ -59,7 +63,19 @@ private Challenge(ASN1Sequence seq) } witness = ASN1OctetString.getInstance(seq.getObjectAt(index++)); - challenge = ASN1OctetString.getInstance(seq.getObjectAt(index)); + challenge = ASN1OctetString.getInstance(seq.getObjectAt(index++)); + if (seq.size() > index) + { + if (challenge.getOctets().length != 0) + { + throw new IllegalArgumentException("ambigous challenge"); + } + encryptedRand = EnvelopedData.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(index)), true); + } + else + { + encryptedRand = null; + } } public Challenge(byte[] witness, byte[] challenge) @@ -67,11 +83,25 @@ public Challenge(byte[] witness, byte[] challenge) this(null, witness, challenge); } + public Challenge(byte[] witness, EnvelopedData encryptedRand) + { + this(null, witness, encryptedRand); + } + public Challenge(AlgorithmIdentifier owf, byte[] witness, byte[] challenge) { this.owf = owf; this.witness = new DEROctetString(witness); this.challenge = new DEROctetString(challenge); + this.encryptedRand = null; + } + + public Challenge(AlgorithmIdentifier owf, byte[] witness, EnvelopedData encryptedRand) + { + this.owf = owf; + this.witness = new DEROctetString(witness); + this.challenge = new DEROctetString(new byte[0]); + this.encryptedRand = encryptedRand; } public static Challenge getInstance(Object o) @@ -99,34 +129,44 @@ public byte[] getWitness() return witness.getOctets(); } + public boolean isEncryptedRand() + { + return encryptedRand != null; + } + public byte[] getChallenge() { return challenge.getOctets(); } + public EnvelopedData getEncryptedRand() + { + return encryptedRand; + } + /** *

                * Challenge ::= SEQUENCE {
          -     *                 owf                 AlgorithmIdentifier  OPTIONAL,
          +     *          owf                 AlgorithmIdentifier  OPTIONAL,
                *
          -     *                 -- MUST be present in the first Challenge; MAY be omitted in
          -     *                 -- any subsequent Challenge in POPODecKeyChallContent (if
          -     *                 -- omitted, then the owf used in the immediately preceding
          -     *                 -- Challenge is to be used).
          +     *          -- MUST be present in the first Challenge; MAY be omitted in
          +     *          -- any subsequent Challenge in POPODecKeyChallContent (if
          +     *          -- omitted, then the owf used in the immediately preceding
          +     *          -- Challenge is to be used).
                *
          -     *                 witness             OCTET STRING,
          -     *                 -- the result of applying the one-way function (owf) to a
          -     *                 -- randomly-generated INTEGER, A.  [Note that a different
          -     *                 -- INTEGER MUST be used for each Challenge.]
          -     *                 challenge           OCTET STRING
          -     *                 -- the encryption (under the public key for which the cert.
          -     *                 -- request is being made) of Rand, where Rand is specified as
          -     *                 --   Rand ::= SEQUENCE {
          -     *                 --      int      INTEGER,
          -     *                 --       - the randomly-generated INTEGER A (above)
          -     *                 --      sender   GeneralName
          -     *                 --       - the sender's name (as included in PKIHeader)
          -     *                 --   }
          +     *          witness             OCTET STRING,
          +     *          -- the result of applying the one-way function (owf) to a
          +     *          -- randomly-generated INTEGER, A.  [Note that a different
          +     *          -- INTEGER MUST be used for each Challenge.]
          +     *          challenge           OCTET STRING   -- deprecated
          +     *          -- the encryption (under the public key for which the cert.
          +     *          -- request is being made) of Rand
          +     *          encryptedRand [0] EnvelopedData OPTIONAL
          +     *     }
          +     *
          +     *     Rand ::= SEQUENCE {
          +     *           int      INTEGER, -- the randomly-generated INTEGER A (above)
          +     *           sender   GeneralName -- the sender's name (as included in PKIHeader)
                *      }
                * 
          * @@ -136,19 +176,15 @@ public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(3); - addOptional(v, owf); + v.addOptional(owf); v.add(witness); v.add(challenge); - - return new DERSequence(v); - } - - private void addOptional(ASN1EncodableVector v, ASN1Encodable obj) - { - if (obj != null) + if (encryptedRand != null) { - v.add(obj); + v.add(new DERTaggedObject(0, encryptedRand)); } + + return new DERSequence(v); } /** @@ -158,23 +194,28 @@ public static class Rand extends ASN1Object { - private final ASN1Integer _int; + private final ASN1Integer integer; private final GeneralName sender; - public Rand(ASN1Integer _int, GeneralName sender) + public Rand(byte[] integer, GeneralName sender) { - this._int = _int; + this(new ASN1Integer(integer), sender); + } + + public Rand(ASN1Integer integer, GeneralName sender) + { + this.integer = integer; this.sender = sender; } - public Rand(ASN1Sequence seq) + private Rand(ASN1Sequence seq) { if (seq.size() != 2) { throw new IllegalArgumentException("expected sequence size of 2"); } - this._int = ASN1Integer.getInstance(seq.getObjectAt(0)); + this.integer = ASN1Integer.getInstance(seq.getObjectAt(0)); this.sender = GeneralName.getInstance(seq.getObjectAt(1)); } @@ -195,7 +236,7 @@ public static Rand getInstance(Object o) public ASN1Integer getInt() { - return _int; + return integer; } public GeneralName getSender() @@ -205,8 +246,7 @@ public GeneralName getSender() public ASN1Primitive toASN1Primitive() { - return new DERSequence(new ASN1Encodable[]{_int, sender}); + return new DERSequence(new ASN1Encodable[]{integer, sender}); } } - } diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/KemBMParameter.java b/util/src/main/java/org/bouncycastle/asn1/cmp/KemBMParameter.java index 3a5705e280..2ca549ecc8 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/KemBMParameter.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/KemBMParameter.java @@ -51,7 +51,7 @@ public KemBMParameter( long len, AlgorithmIdentifier mac) { - this(kdf, new ASN1Integer(len), mac); + this(kdf, ASN1Integer.valueOf(len), mac); } public static KemBMParameter getInstance(Object o) diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/KemOtherInfo.java b/util/src/main/java/org/bouncycastle/asn1/cmp/KemOtherInfo.java index 5140a22ceb..e63e7bb57b 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/KemOtherInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/KemOtherInfo.java @@ -65,7 +65,7 @@ public KemOtherInfo( AlgorithmIdentifier mac, ASN1OctetString ct) { - this(transactionID, senderNonce, recipNonce, new ASN1Integer(len), mac, ct); + this(transactionID, senderNonce, recipNonce, ASN1Integer.valueOf(len), mac, ct); } private KemOtherInfo(ASN1Sequence seq) diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/KeyRecRepContent.java b/util/src/main/java/org/bouncycastle/asn1/cmp/KeyRecRepContent.java index 58870f63c1..76422e3259 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/KeyRecRepContent.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/KeyRecRepContent.java @@ -8,7 +8,6 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; @@ -38,7 +37,7 @@ private KeyRecRepContent(ASN1Sequence seq) while (en.hasMoreElements()) { - ASN1TaggedObject tObj = ASN1TaggedObject.getInstance(en.nextElement(), BERTags.CONTEXT_SPECIFIC); + ASN1TaggedObject tObj = ASN1TaggedObject.getContextInstance(en.nextElement()); switch (tObj.getTagNo()) { diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/OOBCert.java b/util/src/main/java/org/bouncycastle/asn1/cmp/OOBCert.java index 1963bb2f60..fbab86325e 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/OOBCert.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/OOBCert.java @@ -6,7 +6,6 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.x509.AttributeCertificate; import org.bouncycastle.asn1.x509.Certificate; @@ -87,7 +86,7 @@ public static OOBCert getInstance(Object o) if (o instanceof ASN1TaggedObject) { - ASN1TaggedObject taggedObject = ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC); + ASN1TaggedObject taggedObject = ASN1TaggedObject.getContextInstance(o); return new OOBCert(taggedObject.getTagNo(), taggedObject.getExplicitBaseObject()); } diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/PBMParameter.java b/util/src/main/java/org/bouncycastle/asn1/cmp/PBMParameter.java index 0b72b4bd06..b58550deb9 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/PBMParameter.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/PBMParameter.java @@ -49,8 +49,7 @@ public PBMParameter( int iterationCount, AlgorithmIdentifier mac) { - this(new DEROctetString(salt), owf, - new ASN1Integer(iterationCount), mac); + this(new DEROctetString(salt), owf, ASN1Integer.valueOf(iterationCount), mac); } public PBMParameter( diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/PKIBody.java b/util/src/main/java/org/bouncycastle/asn1/cmp/PKIBody.java index d4351c6858..b9568d9eb6 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/PKIBody.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/PKIBody.java @@ -88,7 +88,7 @@ private PKIBody(ASN1TaggedObject tagged) throw Exceptions.illegalArgumentException("malformed body found: " + e.getMessage(), e); } catch (IllegalArgumentException e) - { + { throw Exceptions.illegalArgumentException("malformed body found: " + e.getMessage(), e); } } diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/PKIHeader.java b/util/src/main/java/org/bouncycastle/asn1/cmp/PKIHeader.java index acd06f529c..19f3ca8934 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/PKIHeader.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/PKIHeader.java @@ -135,7 +135,7 @@ public PKIHeader( GeneralName sender, GeneralName recipient) { - this(new ASN1Integer(pvno), sender, recipient); + this(ASN1Integer.valueOf(pvno), sender, recipient); } private PKIHeader( diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/PKIHeaderBuilder.java b/util/src/main/java/org/bouncycastle/asn1/cmp/PKIHeaderBuilder.java index 53c0d83096..9e3b0e279f 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/PKIHeaderBuilder.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/PKIHeaderBuilder.java @@ -33,7 +33,7 @@ public PKIHeaderBuilder( GeneralName sender, GeneralName recipient) { - this(new ASN1Integer(pvno), sender, recipient); + this(ASN1Integer.valueOf(pvno), sender, recipient); } private PKIHeaderBuilder( diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/PKIStatus.java b/util/src/main/java/org/bouncycastle/asn1/cmp/PKIStatus.java index 8892020f98..87e3fb53e5 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/PKIStatus.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/PKIStatus.java @@ -54,7 +54,7 @@ public class PKIStatus private PKIStatus(int value) { - this(new ASN1Integer(value)); + this(ASN1Integer.valueOf(value)); } private PKIStatus(ASN1Integer value) diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/PKIStatusInfo.java b/util/src/main/java/org/bouncycastle/asn1/cmp/PKIStatusInfo.java index 7e656e0770..595e02934a 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/PKIStatusInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/PKIStatusInfo.java @@ -110,6 +110,11 @@ public BigInteger getStatus() return status.getValue(); } + public ASN1Integer getStatusObject() + { + return status; + } + public PKIFreeText getStatusString() { return statusString; diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/POPODecKeyChallContent.java b/util/src/main/java/org/bouncycastle/asn1/cmp/POPODecKeyChallContent.java index 7bf05751a2..0de17f48ca 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cmp/POPODecKeyChallContent.java +++ b/util/src/main/java/org/bouncycastle/asn1/cmp/POPODecKeyChallContent.java @@ -3,6 +3,7 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; /** * POPODecKeyChallContent ::= SEQUENCE OF Challenge @@ -34,6 +35,11 @@ public static POPODecKeyChallContent getInstance(Object o) return null; } + public POPODecKeyChallContent(Challenge... challenges) + { + content = new DERSequence(challenges); + } + public Challenge[] toChallengeArray() { Challenge[] result = new Challenge[content.size()]; diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/Attribute.java b/util/src/main/java/org/bouncycastle/asn1/cms/Attribute.java index ff4c42dad7..026862d24a 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/Attribute.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/Attribute.java @@ -17,7 +17,7 @@ * attrType OBJECT IDENTIFIER, * attrValues SET OF AttributeValue * } - * + * * AttributeValue ::= ANY * *

          @@ -55,7 +55,7 @@ public static Attribute getInstance( { return (Attribute)o; } - + if (o != null) { return new Attribute(ASN1Sequence.getInstance(o)); @@ -63,7 +63,7 @@ public static Attribute getInstance( return null; } - + private Attribute( ASN1Sequence seq) { @@ -83,7 +83,7 @@ public ASN1ObjectIdentifier getAttrType() { return attrType; } - + public ASN1Set getAttrValues() { return attrValues; @@ -94,7 +94,7 @@ public ASN1Encodable[] getAttributeValues() return attrValues.toArray(); } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java b/util/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java index 7550282a23..ed1ac1dc8f 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java @@ -62,7 +62,7 @@ private void addAttribute( Attribute a) { Object value = attributes.get(oid); - + if (value == null) { attributes.put(oid, a); @@ -70,28 +70,28 @@ private void addAttribute( else { Vector v; - + if (value instanceof Attribute) { v = new Vector(); - + v.addElement(value); v.addElement(a); } else { v = (Vector)value; - + v.addElement(a); } - + attributes.put(oid, v); } } /** * Return the first attribute matching the OBJECT IDENTIFIER oid. - * + * * @param oid type of attribute required. * @return first attribute found of type oid. */ @@ -99,19 +99,19 @@ public Attribute get( ASN1ObjectIdentifier oid) { Object value = attributes.get(oid); - + if (value instanceof Vector) { return (Attribute)((Vector)value).elementAt(0); } - + return (Attribute)value; } /** - * Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be + * Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be * empty if there are no attributes of the required type present. - * + * * @param oid type of attribute required. * @return a vector of all the attributes found of type oid. */ @@ -119,13 +119,13 @@ public ASN1EncodableVector getAll( ASN1ObjectIdentifier oid) { ASN1EncodableVector v = new ASN1EncodableVector(); - + Object value = attributes.get(oid); - + if (value instanceof Vector) { Enumeration e = ((Vector)value).elements(); - + while (e.hasMoreElements()) { v.add((Attribute)e.nextElement()); @@ -135,7 +135,7 @@ else if (value != null) { v.add((Attribute)value); } - + return v; } @@ -164,20 +164,20 @@ public Hashtable toHashtable() { return copyTable(attributes); } - + public ASN1EncodableVector toASN1EncodableVector() { ASN1EncodableVector v = new ASN1EncodableVector(); Enumeration e = attributes.elements(); - + while (e.hasMoreElements()) { Object value = e.nextElement(); - + if (value instanceof Vector) { Enumeration en = ((Vector)value).elements(); - + while (en.hasMoreElements()) { v.add(Attribute.getInstance(en.nextElement())); @@ -188,7 +188,7 @@ public ASN1EncodableVector toASN1EncodableVector() v.add(Attribute.getInstance(value)); } } - + return v; } @@ -202,14 +202,14 @@ private Hashtable copyTable( { Hashtable out = new Hashtable(); Enumeration e = in.keys(); - + while (e.hasMoreElements()) { Object key = e.nextElement(); - + out.put(key, in.get(key)); } - + return out; } diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/Attributes.java b/util/src/main/java/org/bouncycastle/asn1/cms/Attributes.java index 420372a059..02b2f5e2a2 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/Attributes.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/Attributes.java @@ -25,18 +25,6 @@ public class Attributes extends ASN1Object { - private ASN1Set attributes; - - private Attributes(ASN1Set set) - { - attributes = set; - } - - public Attributes(ASN1EncodableVector v) - { - attributes = new DLSet(v); - } - /** * Return an Attribute set object from the given object. *

          @@ -64,11 +52,26 @@ else if (obj != null) return null; } - public static Attributes getInstance( - ASN1TaggedObject obj, - boolean explicit) + public static Attributes getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return new Attributes(ASN1Set.getInstance(taggedObject, declaredExplicit)); + } + + public static Attributes getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return new Attributes(ASN1Set.getTagged(taggedObject, declaredExplicit)); + } + + private ASN1Set attributes; + + private Attributes(ASN1Set set) + { + attributes = set; + } + + public Attributes(ASN1EncodableVector v) { - return getInstance(ASN1Set.getInstance(obj, explicit)); + attributes = new DLSet(v); } public Attribute[] getAttributes() @@ -83,7 +86,7 @@ public Attribute[] getAttributes() return rv; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/AuthEnvelopedData.java b/util/src/main/java/org/bouncycastle/asn1/cms/AuthEnvelopedData.java index 2454c6197d..53bb621ed5 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/AuthEnvelopedData.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/AuthEnvelopedData.java @@ -52,7 +52,7 @@ public AuthEnvelopedData( ASN1Set unauthAttrs) { // "It MUST be set to 0." - this.version = new ASN1Integer(0); + this.version = ASN1Integer.ZERO; this.originatorInfo = originatorInfo; diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/AuthEnvelopedDataParser.java b/util/src/main/java/org/bouncycastle/asn1/cms/AuthEnvelopedDataParser.java index c162539abe..81830e39d7 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/AuthEnvelopedDataParser.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/AuthEnvelopedDataParser.java @@ -14,7 +14,7 @@ /** * Parse {@link AuthEnvelopedData} input stream. - * + * *

            * AuthEnvelopedData ::= SEQUENCE {
            *   version CMSVersion,
          diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/AuthenticatedData.java b/util/src/main/java/org/bouncycastle/asn1/cms/AuthenticatedData.java
          index 8883199e28..21bfcb4e2a 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/cms/AuthenticatedData.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/cms/AuthenticatedData.java
          @@ -67,8 +67,8 @@ public AuthenticatedData(
                       }
                   }
           
          -        version = new ASN1Integer(calculateVersion(originatorInfo));
          -        
          +        version = ASN1Integer.valueOf(calculateVersion(originatorInfo));
          +
                   this.originatorInfo = originatorInfo;
                   this.macAlgorithm = macAlgorithm;
                   this.digestAlgorithm = digestAlgorithm;
          @@ -116,7 +116,7 @@ private AuthenticatedData(
                   }
           
                   mac = ASN1OctetString.getInstance(tmp);
          -        
          +
                   if (seq.size() > index)
                   {
                       unauthAttrs = ASN1Set.getInstance((ASN1TaggedObject)seq.getObjectAt(index), false);
          diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/CCMParameters.java b/util/src/main/java/org/bouncycastle/asn1/cms/CCMParameters.java
          index b281d76303..a9c994c120 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/cms/CCMParameters.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/cms/CCMParameters.java
          @@ -94,7 +94,7 @@ public ASN1Primitive toASN1Primitive()
           
                   if (icvLen != 12)
                   {
          -            v.add(new ASN1Integer(icvLen));
          +            v.add(ASN1Integer.valueOf(icvLen));
                   }
           
                   return new DERSequence(v);
          diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/CMSORIforKEMOtherInfo.java b/util/src/main/java/org/bouncycastle/asn1/cms/CMSORIforKEMOtherInfo.java
          index 332a0c7630..9c483ad28f 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/cms/CMSORIforKEMOtherInfo.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/cms/CMSORIforKEMOtherInfo.java
          @@ -45,10 +45,10 @@ public CMSORIforKEMOtherInfo(AlgorithmIdentifier wrap, int kekLength, byte[] ukm
           
               public ASN1Primitive toASN1Primitive()
               {
          -        ASN1EncodableVector v = new ASN1EncodableVector();
          +        ASN1EncodableVector v = new ASN1EncodableVector(3);
           
                   v.add(wrap);
          -        v.add(new ASN1Integer(kekLength));
          +        v.add(ASN1Integer.valueOf(kekLength));
           
                   if (ukm != null)
                   {
          diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/CompressedData.java b/util/src/main/java/org/bouncycastle/asn1/cms/CompressedData.java
          index e62afdaccf..b5f9c5fda9 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/cms/CompressedData.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/cms/CompressedData.java
          @@ -9,9 +9,9 @@
           import org.bouncycastle.asn1.BERSequence;
           import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
           
          -/** 
          +/**
            * RFC 3274: CMS Compressed Data.
          - * 
          + *
            * 
            * CompressedData ::= SEQUENCE {
            *     version CMSVersion,
          @@ -31,11 +31,11 @@ public CompressedData(
                   AlgorithmIdentifier compressionAlgorithm,
                   ContentInfo         encapContentInfo)
               {
          -        this.version = new ASN1Integer(0);
          +        this.version = ASN1Integer.ZERO;
                   this.compressionAlgorithm = compressionAlgorithm;
                   this.encapContentInfo = encapContentInfo;
               }
          -    
          +
               private CompressedData(
                   ASN1Sequence seq)
               {
          @@ -59,7 +59,7 @@ public static CompressedData getInstance(
               {
                   return getInstance(ASN1Sequence.getInstance(ato, isExplicit));
               }
          -    
          +
               /**
                * Return a CompressedData object from the given object.
                * 

          diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java b/util/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java index 53c9347311..625128ddf5 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/ContentInfo.java @@ -1,7 +1,6 @@ package org.bouncycastle.asn1.cms; import org.bouncycastle.asn1.ASN1Encodable; -import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; @@ -9,7 +8,6 @@ import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.BERSequence; import org.bouncycastle.asn1.BERTaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DLSequence; @@ -52,8 +50,7 @@ public class ContentInfo * @param obj the object we want converted. * @exception IllegalArgumentException if the object cannot be converted. */ - public static ContentInfo getInstance( - Object obj) + public static ContentInfo getInstance(Object obj) { if (obj instanceof ContentInfo) { @@ -67,25 +64,30 @@ else if (obj != null) return null; } - public static ContentInfo getInstance( - ASN1TaggedObject obj, - boolean explicit) + public static ContentInfo getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - return new ContentInfo(ASN1Sequence.getInstance(obj, explicit)); + return new ContentInfo(ASN1Sequence.getInstance(taggedObject, declaredExplicit)); } - private ContentInfo( - ASN1Sequence seq) + public static ContentInfo getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - if (seq.size() < 1 || seq.size() > 2) + return new ContentInfo(ASN1Sequence.getTagged(taggedObject, declaredExplicit)); + } + + private ContentInfo(ASN1Sequence seq) + { + int count = seq.size(); + if (count < 1 || count > 2) { - throw new IllegalArgumentException("Bad sequence size: " + seq.size()); + throw new IllegalArgumentException("Bad sequence size: " + count); } - contentType = (ASN1ObjectIdentifier)seq.getObjectAt(0); - if (seq.size() > 1) + this.contentType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); + + ASN1Encodable content = null; + if (count > 1) { - ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(seq.getObjectAt(1), BERTags.CONTEXT_SPECIFIC); + ASN1TaggedObject tagged = ASN1TaggedObject.getContextInstance(seq.getObjectAt(1)); if (!tagged.isExplicit() || tagged.getTagNo() != 0) { throw new IllegalArgumentException("Bad tag for 'content'"); @@ -93,10 +95,8 @@ private ContentInfo( content = tagged.getExplicitBaseObject(); } - else - { - content = null; - } + this.content = content; + isDefiniteLength = !(seq instanceof BERSequence); } @@ -151,22 +151,15 @@ public boolean isDefiniteLength() */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(2); - - v.add(contentType); - - if (content != null) + if (isDefiniteLength) { - if (isDefiniteLength) - { - v.add(new DLTaggedObject(0, content)); - } - else - { - v.add(new BERTaggedObject(0, content)); - } + return content == null + ? new DLSequence(contentType) + : new DLSequence(contentType, new DLTaggedObject(0, content)); } - return isDefiniteLength ? (ASN1Primitive)new DLSequence(v) : (ASN1Primitive)new BERSequence(v); + return content == null + ? new BERSequence(contentType) + : new BERSequence(contentType, new BERTaggedObject(0, content)); } } diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/DigestedData.java b/util/src/main/java/org/bouncycastle/asn1/cms/DigestedData.java index 9011925e88..3b4c50a46c 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/DigestedData.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/DigestedData.java @@ -12,7 +12,7 @@ import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.util.Arrays; -/** +/** * RFC 5652 DigestedData object. *

            * DigestedData ::= SEQUENCE {
          @@ -35,7 +35,7 @@ public DigestedData(
                   ContentInfo encapContentInfo,
                   byte[]      digest)
               {
          -        this.version = new ASN1Integer(0);
          +        this.version = ASN1Integer.ZERO;
                   this.digestAlgorithm = digestAlgorithm;
                   this.encapContentInfo = encapContentInfo;
                   this.digest = new DEROctetString(Arrays.clone(digest));
          @@ -65,7 +65,7 @@ public static DigestedData getInstance(
               {
                   return getInstance(ASN1Sequence.getInstance(ato, isExplicit));
               }
          -    
          +
               /**
                * Return a DigestedData object from the given object.
                * 

          @@ -86,12 +86,12 @@ public static DigestedData getInstance( { return (DigestedData)obj; } - + if (obj != null) { return new DigestedData(ASN1Sequence.getInstance(obj)); } - + return null; } diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfo.java b/util/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfo.java index 1eaa9a715f..961e22541d 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfo.java @@ -18,7 +18,7 @@ * EncryptedContentInfo ::= SEQUENCE { * contentType ContentType, * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, - * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL + * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL * } *

          */ @@ -28,9 +28,9 @@ public class EncryptedContentInfo private ASN1ObjectIdentifier contentType; private AlgorithmIdentifier contentEncryptionAlgorithm; private ASN1OctetString encryptedContent; - + public EncryptedContentInfo( - ASN1ObjectIdentifier contentType, + ASN1ObjectIdentifier contentType, AlgorithmIdentifier contentEncryptionAlgorithm, ASN1OctetString encryptedContent) { @@ -38,7 +38,7 @@ public EncryptedContentInfo( this.contentEncryptionAlgorithm = contentEncryptionAlgorithm; this.encryptedContent = encryptedContent; } - + private EncryptedContentInfo( ASN1Sequence seq) { @@ -81,7 +81,7 @@ public static EncryptedContentInfo getInstance( { return new EncryptedContentInfo(ASN1Sequence.getInstance(obj)); } - + return null; } @@ -100,13 +100,13 @@ public ASN1OctetString getEncryptedContent() return encryptedContent; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(3); - + v.add(contentType); v.add(contentEncryptionAlgorithm); @@ -114,7 +114,7 @@ public ASN1Primitive toASN1Primitive() { v.add(new BERTaggedObject(false, 0, encryptedContent)); } - + return new BERSequence(v); } } diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfoParser.java b/util/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfoParser.java index 073051caf1..53e72edb1d 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfoParser.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/EncryptedContentInfoParser.java @@ -16,7 +16,7 @@ * EncryptedContentInfo ::= SEQUENCE { * contentType ContentType, * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, - * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL + * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL * } *
          */ @@ -27,26 +27,26 @@ public class EncryptedContentInfoParser private ASN1TaggedObjectParser _encryptedContent; public EncryptedContentInfoParser( - ASN1SequenceParser seq) + ASN1SequenceParser seq) throws IOException { _contentType = (ASN1ObjectIdentifier)seq.readObject(); _contentEncryptionAlgorithm = AlgorithmIdentifier.getInstance(seq.readObject().toASN1Primitive()); _encryptedContent = (ASN1TaggedObjectParser)seq.readObject(); } - + public ASN1ObjectIdentifier getContentType() { return _contentType; } - + public AlgorithmIdentifier getContentEncryptionAlgorithm() { return _contentEncryptionAlgorithm; } public ASN1Encodable getEncryptedContent( - int tag) + int tag) throws IOException { return ASN1Util.parseContextBaseUniversal(_encryptedContent, 0, false, tag); diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/EncryptedData.java b/util/src/main/java/org/bouncycastle/asn1/cms/EncryptedData.java index a1869749b5..9422ed6732 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/EncryptedData.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/EncryptedData.java @@ -62,7 +62,7 @@ public EncryptedData(EncryptedContentInfo encInfo) public EncryptedData(EncryptedContentInfo encInfo, ASN1Set unprotectedAttrs) { - this.version = new ASN1Integer((unprotectedAttrs == null) ? 0 : 2); + this.version = unprotectedAttrs == null ? ASN1Integer.ZERO : ASN1Integer.TWO; this.encryptedContentInfo = encInfo; this.unprotectedAttrs = unprotectedAttrs; } diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/EnvelopedData.java b/util/src/main/java/org/bouncycastle/asn1/cms/EnvelopedData.java index 29c4845111..2f9bc79710 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/EnvelopedData.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/EnvelopedData.java @@ -38,7 +38,7 @@ public EnvelopedData( EncryptedContentInfo encryptedContentInfo, ASN1Set unprotectedAttrs) { - version = new ASN1Integer(calculateVersion(originatorInfo, recipientInfos, unprotectedAttrs)); + version = ASN1Integer.valueOf(calculateVersion(originatorInfo, recipientInfos, unprotectedAttrs)); this.originatorInfo = originatorInfo; this.recipientInfos = recipientInfos; @@ -52,7 +52,7 @@ public EnvelopedData( EncryptedContentInfo encryptedContentInfo, Attributes unprotectedAttrs) { - version = new ASN1Integer(calculateVersion(originatorInfo, recipientInfos, ASN1Set.getInstance(unprotectedAttrs))); + version = ASN1Integer.valueOf(calculateVersion(originatorInfo, recipientInfos, ASN1Set.getInstance(unprotectedAttrs))); this.originatorInfo = originatorInfo; this.recipientInfos = recipientInfos; diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/EnvelopedDataParser.java b/util/src/main/java/org/bouncycastle/asn1/cms/EnvelopedDataParser.java index 275e7ea5a5..bb7de0a2f6 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/EnvelopedDataParser.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/EnvelopedDataParser.java @@ -10,7 +10,7 @@ import org.bouncycastle.asn1.ASN1Util; import org.bouncycastle.asn1.BERTags; -/** +/** * Parser of RFC 5652 {@link EnvelopedData} object. *

          *

          @@ -19,7 +19,7 @@
            *     originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL,
            *     recipientInfos RecipientInfos,
            *     encryptedContentInfo EncryptedContentInfo,
          - *     unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL 
          + *     unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL
            * }
            * 
          */ @@ -29,7 +29,7 @@ public class EnvelopedDataParser private ASN1Integer _version; private ASN1Encodable _nextObject; private boolean _originatorInfoCalled; - + public EnvelopedDataParser( ASN1SequenceParser seq) throws IOException @@ -43,11 +43,11 @@ public ASN1Integer getVersion() return _version; } - public OriginatorInfo getOriginatorInfo() + public OriginatorInfo getOriginatorInfo() throws IOException { - _originatorInfoCalled = true; - + _originatorInfoCalled = true; + if (_nextObject == null) { _nextObject = _seq.readObject(); @@ -66,7 +66,7 @@ public OriginatorInfo getOriginatorInfo() return null; } - + public ASN1SetParser getRecipientInfos() throws IOException { @@ -74,33 +74,33 @@ public ASN1SetParser getRecipientInfos() { getOriginatorInfo(); } - + if (_nextObject == null) { _nextObject = _seq.readObject(); } - + ASN1SetParser recipientInfos = (ASN1SetParser)_nextObject; _nextObject = null; return recipientInfos; } - public EncryptedContentInfoParser getEncryptedContentInfo() + public EncryptedContentInfoParser getEncryptedContentInfo() throws IOException { if (_nextObject == null) { _nextObject = _seq.readObject(); } - - + + if (_nextObject != null) { ASN1SequenceParser o = (ASN1SequenceParser) _nextObject; _nextObject = null; return new EncryptedContentInfoParser(o); } - + return null; } diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/Evidence.java b/util/src/main/java/org/bouncycastle/asn1/cms/Evidence.java index 474ac9b43d..a9408ed334 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/Evidence.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/Evidence.java @@ -5,7 +5,6 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.tsp.EvidenceRecord; @@ -79,7 +78,7 @@ public static Evidence getInstance(Object obj) } else if (obj instanceof ASN1TaggedObject) { - return new Evidence(ASN1TaggedObject.getInstance(obj, BERTags.CONTEXT_SPECIFIC)); + return new Evidence(ASN1TaggedObject.getContextInstance(obj)); } throw new IllegalArgumentException("unknown object in getInstance"); diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/GCMParameters.java b/util/src/main/java/org/bouncycastle/asn1/cms/GCMParameters.java index 76a98dc612..e8af959613 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/GCMParameters.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/GCMParameters.java @@ -94,7 +94,7 @@ public ASN1Primitive toASN1Primitive() if (icvLen != 12) { - v.add(new ASN1Integer(icvLen)); + v.add(ASN1Integer.valueOf(icvLen)); } return new DERSequence(v); diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/KEKIdentifier.java b/util/src/main/java/org/bouncycastle/asn1/cms/KEKIdentifier.java index 97fae7fe63..bd301f7c77 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/KEKIdentifier.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/KEKIdentifier.java @@ -18,7 +18,7 @@ * KEKIdentifier ::= SEQUENCE { * keyIdentifier OCTET STRING, * date GeneralizedTime OPTIONAL, - * other OtherKeyAttribute OPTIONAL + * other OtherKeyAttribute OPTIONAL * } *
          */ @@ -28,7 +28,7 @@ public class KEKIdentifier private ASN1OctetString keyIdentifier; private ASN1GeneralizedTime date; private OtherKeyAttribute other; - + public KEKIdentifier( byte[] keyIdentifier, ASN1GeneralizedTime date, @@ -38,12 +38,12 @@ public KEKIdentifier( this.date = date; this.other = other; } - + private KEKIdentifier( ASN1Sequence seq) { keyIdentifier = (ASN1OctetString)seq.getObjectAt(0); - + switch (seq.size()) { case 1: @@ -51,7 +51,7 @@ private KEKIdentifier( case 2: if (seq.getObjectAt(1) instanceof ASN1GeneralizedTime) { - date = (ASN1GeneralizedTime)seq.getObjectAt(1); + date = (ASN1GeneralizedTime)seq.getObjectAt(1); } else { @@ -82,7 +82,7 @@ public static KEKIdentifier getInstance( { return getInstance(ASN1Sequence.getInstance(obj, explicit)); } - + /** * Return a KEKIdentifier object from the given object. *

          @@ -103,12 +103,12 @@ public static KEKIdentifier getInstance( { return (KEKIdentifier)obj; } - + if (obj instanceof ASN1Sequence) { return new KEKIdentifier((ASN1Sequence)obj); } - + throw new IllegalArgumentException("Invalid KEKIdentifier: " + obj.getClass().getName()); } @@ -127,7 +127,7 @@ public OtherKeyAttribute getOther() return other; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() @@ -135,7 +135,7 @@ public ASN1Primitive toASN1Primitive() ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(keyIdentifier); - + if (date != null) { v.add(date); @@ -145,7 +145,7 @@ public ASN1Primitive toASN1Primitive() { v.add(other); } - + return new DERSequence(v); } } diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/KEKRecipientInfo.java b/util/src/main/java/org/bouncycastle/asn1/cms/KEKRecipientInfo.java index 75802f89f6..0a257c373b 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/KEKRecipientInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/KEKRecipientInfo.java @@ -19,7 +19,7 @@ * version CMSVersion, -- always set to 4 * kekid KEKIdentifier, * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, - * encryptedKey EncryptedKey + * encryptedKey EncryptedKey * } * */ @@ -36,12 +36,12 @@ public KEKRecipientInfo( AlgorithmIdentifier keyEncryptionAlgorithm, ASN1OctetString encryptedKey) { - this.version = new ASN1Integer(4); + this.version = ASN1Integer.FOUR; this.kekid = kekid; this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; this.encryptedKey = encryptedKey; } - + public KEKRecipientInfo( ASN1Sequence seq) { @@ -66,7 +66,7 @@ public static KEKRecipientInfo getInstance( { return getInstance(ASN1Sequence.getInstance(obj, explicit)); } - + /** * Return a KEKRecipientInfo object from the given object. *

          @@ -87,12 +87,12 @@ public static KEKRecipientInfo getInstance( { return (KEKRecipientInfo)obj; } - + if (obj != null) { return new KEKRecipientInfo(ASN1Sequence.getInstance(obj)); } - + return null; } @@ -100,7 +100,7 @@ public ASN1Integer getVersion() { return version; } - + public KEKIdentifier getKekid() { return kekid; @@ -116,7 +116,7 @@ public ASN1OctetString getEncryptedKey() return encryptedKey; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/KEMRecipientInfo.java b/util/src/main/java/org/bouncycastle/asn1/cms/KEMRecipientInfo.java index 7f8e8e462c..60c617042e 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/KEMRecipientInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/KEMRecipientInfo.java @@ -56,7 +56,7 @@ public KEMRecipientInfo(RecipientIdentifier rid, AlgorithmIdentifier kem, ASN1Oc { throw new IllegalArgumentException("kekLength must be <= 65535"); } - this.cmsVersion = new ASN1Integer(0); + this.cmsVersion = ASN1Integer.ZERO; this.rid = rid; this.kem = kem; this.kemct = kemct; @@ -169,7 +169,7 @@ public ASN1Primitive toASN1Primitive() } v.add(wrap); v.add(encryptedKey); - + return new DERSequence(v); } } diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientIdentifier.java b/util/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientIdentifier.java index 98ca19a504..c50c1bc1e9 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientIdentifier.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientIdentifier.java @@ -81,7 +81,7 @@ public static KeyAgreeRecipientIdentifier getInstance( } return new KeyAgreeRecipientIdentifier(IssuerAndSerialNumber.getInstance(obj)); - } + } public KeyAgreeRecipientIdentifier( IssuerAndSerialNumber issuerSerial) @@ -107,7 +107,7 @@ public RecipientKeyIdentifier getRKeyID() return rKeyID; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java b/util/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java index b308e396f6..f82a6ea1b7 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java @@ -21,7 +21,7 @@ * originator [0] EXPLICIT OriginatorIdentifierOrKey, * ukm [1] EXPLICIT UserKeyingMaterial OPTIONAL, * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, - * recipientEncryptedKeys RecipientEncryptedKeys + * recipientEncryptedKeys RecipientEncryptedKeys * } * * UserKeyingMaterial ::= OCTET STRING @@ -35,14 +35,14 @@ public class KeyAgreeRecipientInfo private ASN1OctetString ukm; private AlgorithmIdentifier keyEncryptionAlgorithm; private ASN1Sequence recipientEncryptedKeys; - + public KeyAgreeRecipientInfo( OriginatorIdentifierOrKey originator, ASN1OctetString ukm, AlgorithmIdentifier keyEncryptionAlgorithm, ASN1Sequence recipientEncryptedKeys) { - this.version = new ASN1Integer(3); + this.version = ASN1Integer.THREE; this.originator = originator; this.ukm = ukm; this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; @@ -53,7 +53,7 @@ private KeyAgreeRecipientInfo( ASN1Sequence seq) { int index = 0; - + version = (ASN1Integer)seq.getObjectAt(index++); originator = OriginatorIdentifierOrKey.getInstance( (ASN1TaggedObject)seq.getObjectAt(index++), true); @@ -69,7 +69,7 @@ private KeyAgreeRecipientInfo( recipientEncryptedKeys = (ASN1Sequence)seq.getObjectAt(index++); } - + /** * Return a KeyAgreeRecipientInfo object from a tagged object. * @@ -85,7 +85,7 @@ public static KeyAgreeRecipientInfo getInstance( { return getInstance(ASN1Sequence.getInstance(obj, explicit)); } - + /** * Return a KeyAgreeRecipientInfo object from the given object. *

          @@ -106,14 +106,14 @@ public static KeyAgreeRecipientInfo getInstance( { return (KeyAgreeRecipientInfo)obj; } - + if (obj != null) { return new KeyAgreeRecipientInfo(ASN1Sequence.getInstance(obj)); } - + return null; - } + } public ASN1Integer getVersion() { @@ -140,7 +140,7 @@ public ASN1Sequence getRecipientEncryptedKeys() return recipientEncryptedKeys; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() @@ -149,12 +149,12 @@ public ASN1Primitive toASN1Primitive() v.add(version); v.add(new DERTaggedObject(true, 0, originator)); - + if (ukm != null) { v.add(new DERTaggedObject(true, 1, ukm)); } - + v.add(keyEncryptionAlgorithm); v.add(recipientEncryptedKeys); diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java b/util/src/main/java/org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java index 8b3c19e485..813928df89 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java @@ -18,7 +18,7 @@ * version CMSVersion, -- always set to 0 or 2 * rid RecipientIdentifier, * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, - * encryptedKey EncryptedKey + * encryptedKey EncryptedKey * } * */ @@ -37,11 +37,11 @@ public KeyTransRecipientInfo( { if (rid.toASN1Primitive() instanceof ASN1TaggedObject) { - this.version = new ASN1Integer(2); + this.version = ASN1Integer.TWO; } else { - this.version = new ASN1Integer(0); + this.version = ASN1Integer.ZERO; } this.rid = rid; @@ -78,14 +78,14 @@ public static KeyTransRecipientInfo getInstance( { return (KeyTransRecipientInfo)obj; } - + if(obj != null) { return new KeyTransRecipientInfo(ASN1Sequence.getInstance(obj)); } - + return null; - } + } public ASN1Integer getVersion() { @@ -107,7 +107,7 @@ public ASN1OctetString getEncryptedKey() return encryptedKey; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/MetaData.java b/util/src/main/java/org/bouncycastle/asn1/cms/MetaData.java index 1dd7d84e26..aadd8a4b28 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/MetaData.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/MetaData.java @@ -111,7 +111,7 @@ public ASN1Primitive toASN1Primitive() { v.add(otherMetaData); } - + return new DERSequence(v); } diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/OriginatorIdentifierOrKey.java b/util/src/main/java/org/bouncycastle/asn1/cms/OriginatorIdentifierOrKey.java index de35fdb3df..d81da38d68 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/OriginatorIdentifierOrKey.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/OriginatorIdentifierOrKey.java @@ -18,7 +18,7 @@ * OriginatorIdentifierOrKey ::= CHOICE { * issuerAndSerialNumber IssuerAndSerialNumber, * subjectKeyIdentifier [0] SubjectKeyIdentifier, - * originatorKey [1] OriginatorPublicKey + * originatorKey [1] OriginatorPublicKey * } * * SubjectKeyIdentifier ::= OCTET STRING @@ -87,7 +87,7 @@ public static OriginatorIdentifierOrKey getInstance( return getInstance(o.getExplicitBaseObject()); } - + /** * Return an OriginatorIdentifierOrKey object from the given object. *

          @@ -154,30 +154,16 @@ public IssuerAndSerialNumber getIssuerAndSerialNumber() public SubjectKeyIdentifier getSubjectKeyIdentifier() { - if (id instanceof ASN1TaggedObject) - { - ASN1TaggedObject taggedObject = (ASN1TaggedObject)id; - if (taggedObject.hasContextTag(0)) - { - return SubjectKeyIdentifier.getInstance(taggedObject, false); - } - } + ASN1TaggedObject tag0 = ASN1TaggedObject.getContextOptional(id, 0); - return null; + return tag0 == null ? null : SubjectKeyIdentifier.getInstance(tag0, false); } public OriginatorPublicKey getOriginatorKey() { - if (id instanceof ASN1TaggedObject) - { - ASN1TaggedObject taggedObject = (ASN1TaggedObject)id; - if (taggedObject.hasContextTag(1)) - { - return OriginatorPublicKey.getInstance(taggedObject, false); - } - } + ASN1TaggedObject tag1 = ASN1TaggedObject.getContextOptional(id, 1); - return null; + return tag1 == null ? null : OriginatorPublicKey.getInstance(tag1, false); } /** diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/OriginatorInfo.java b/util/src/main/java/org/bouncycastle/asn1/cms/OriginatorInfo.java index 265893bf78..1c24d9bed5 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/OriginatorInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/OriginatorInfo.java @@ -16,7 +16,7 @@ * * OriginatorInfo ::= SEQUENCE { * certs [0] IMPLICIT CertificateSet OPTIONAL, - * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL + * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL * } * CertificateRevocationLists ::= SET OF CertificateList (from X.509) * @@ -44,7 +44,7 @@ public class OriginatorInfo { private ASN1Set certs; private ASN1Set crls; - + public OriginatorInfo( ASN1Set certs, ASN1Set crls) @@ -52,7 +52,7 @@ public OriginatorInfo( this.certs = certs; this.crls = crls; } - + private OriginatorInfo( ASN1Sequence seq) { @@ -82,7 +82,7 @@ private OriginatorInfo( throw new IllegalArgumentException("OriginatorInfo too big"); } } - + /** * Return an OriginatorInfo object from a tagged object. * @@ -98,7 +98,7 @@ public static OriginatorInfo getInstance( { return getInstance(ASN1Sequence.getInstance(obj, explicit)); } - + /** * Return an OriginatorInfo object from the given object. *

          @@ -126,7 +126,7 @@ else if (obj != null) return null; } - + public ASN1Set getCertificates() { return certs; @@ -137,7 +137,7 @@ public ASN1Set getCRLs() return crls; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() @@ -148,12 +148,12 @@ public ASN1Primitive toASN1Primitive() { v.add(new DERTaggedObject(false, 0, certs)); } - + if (crls != null) { v.add(new DERTaggedObject(false, 1, crls)); } - + return new DERSequence(v); } } diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/OriginatorPublicKey.java b/util/src/main/java/org/bouncycastle/asn1/cms/OriginatorPublicKey.java index 7719ef009c..a22f6f2c7e 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/OriginatorPublicKey.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/OriginatorPublicKey.java @@ -16,7 +16,7 @@ *

            * OriginatorPublicKey ::= SEQUENCE {
            *     algorithm AlgorithmIdentifier,
          - *     publicKey BIT STRING 
          + *     publicKey BIT STRING
            * }
            * 
          */ @@ -48,7 +48,7 @@ private OriginatorPublicKey( algorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); publicKey = (DERBitString)seq.getObjectAt(1); } - + /** * Return an OriginatorPublicKey object from a tagged object. * @@ -64,7 +64,7 @@ public static OriginatorPublicKey getInstance( { return new OriginatorPublicKey(ASN1Sequence.getInstance(obj, explicit)); } - + /** * Return an OriginatorPublicKey object from the given object. *

          @@ -85,14 +85,14 @@ public static OriginatorPublicKey getInstance( { return (OriginatorPublicKey)obj; } - + if (obj != null) { return new OriginatorPublicKey(ASN1Sequence.getInstance(obj)); } return null; - } + } public AlgorithmIdentifier getAlgorithm() { @@ -112,7 +112,7 @@ public ASN1BitString getPublicKeyData() return publicKey; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/OtherKeyAttribute.java b/util/src/main/java/org/bouncycastle/asn1/cms/OtherKeyAttribute.java index ca97ae7dc8..4d8c010d53 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/OtherKeyAttribute.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/OtherKeyAttribute.java @@ -44,7 +44,7 @@ public static OtherKeyAttribute getInstance( { return (OtherKeyAttribute)o; } - + if (o != null) { return new OtherKeyAttribute(ASN1Sequence.getInstance(o)); @@ -76,13 +76,13 @@ public ASN1ObjectIdentifier getKeyAttrId() { return keyAttrId; } - + public ASN1Encodable getKeyAttr() { return keyAttr; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/OtherRecipientInfo.java b/util/src/main/java/org/bouncycastle/asn1/cms/OtherRecipientInfo.java index 90db62699f..136db01697 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/OtherRecipientInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/OtherRecipientInfo.java @@ -30,7 +30,7 @@ public OtherRecipientInfo( this.oriType = oriType; this.oriValue = oriValue; } - + private OtherRecipientInfo( ASN1Sequence seq) { @@ -53,7 +53,7 @@ public static OtherRecipientInfo getInstance( { return getInstance(ASN1Sequence.getInstance(obj, explicit)); } - + /** * Return a OtherRecipientInfo object from the given object. *

          @@ -74,12 +74,12 @@ public static OtherRecipientInfo getInstance( { return (OtherRecipientInfo)obj; } - + if (obj != null) { return new OtherRecipientInfo(ASN1Sequence.getInstance(obj)); } - + return null; } @@ -93,7 +93,7 @@ public ASN1Encodable getValue() return oriValue; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/OtherRevocationInfoFormat.java b/util/src/main/java/org/bouncycastle/asn1/cms/OtherRevocationInfoFormat.java index c65daca9ca..6457b394d2 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/OtherRevocationInfoFormat.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/OtherRevocationInfoFormat.java @@ -53,7 +53,7 @@ public static OtherRevocationInfoFormat getInstance( { return getInstance(ASN1Sequence.getInstance(obj, explicit)); } - + /** * Return a OtherRevocationInfoFormat object from the given object. *

          @@ -74,12 +74,12 @@ public static OtherRevocationInfoFormat getInstance( { return (OtherRevocationInfoFormat)obj; } - + if (obj != null) { return new OtherRevocationInfoFormat(ASN1Sequence.getInstance(obj)); } - + return null; } @@ -93,7 +93,7 @@ public ASN1Encodable getInfo() return otherRevInfo; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/PasswordRecipientInfo.java b/util/src/main/java/org/bouncycastle/asn1/cms/PasswordRecipientInfo.java index fac02bb4a0..e44f1a0aba 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/PasswordRecipientInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/PasswordRecipientInfo.java @@ -35,17 +35,17 @@ public PasswordRecipientInfo( AlgorithmIdentifier keyEncryptionAlgorithm, ASN1OctetString encryptedKey) { - this.version = new ASN1Integer(0); + this.version = ASN1Integer.ZERO; this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; this.encryptedKey = encryptedKey; } - + public PasswordRecipientInfo( AlgorithmIdentifier keyDerivationAlgorithm, AlgorithmIdentifier keyEncryptionAlgorithm, ASN1OctetString encryptedKey) { - this.version = new ASN1Integer(0); + this.version = ASN1Integer.ZERO; this.keyDerivationAlgorithm = keyDerivationAlgorithm; this.keyEncryptionAlgorithm = keyEncryptionAlgorithm; this.encryptedKey = encryptedKey; @@ -83,7 +83,7 @@ public static PasswordRecipientInfo getInstance( { return getInstance(ASN1Sequence.getInstance(obj, explicit)); } - + /** * Return a PasswordRecipientInfo object from the given object. *

          @@ -104,12 +104,12 @@ public static PasswordRecipientInfo getInstance( { return (PasswordRecipientInfo)obj; } - + if (obj != null) { return new PasswordRecipientInfo(ASN1Sequence.getInstance(obj)); } - + return null; } @@ -133,7 +133,7 @@ public ASN1OctetString getEncryptedKey() return encryptedKey; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() @@ -141,7 +141,7 @@ public ASN1Primitive toASN1Primitive() ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(version); - + if (keyDerivationAlgorithm != null) { v.add(new DERTaggedObject(false, 0, keyDerivationAlgorithm)); diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/RecipientEncryptedKey.java b/util/src/main/java/org/bouncycastle/asn1/cms/RecipientEncryptedKey.java index 2e06e0b902..3abc309b33 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/RecipientEncryptedKey.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/RecipientEncryptedKey.java @@ -29,7 +29,7 @@ private RecipientEncryptedKey( identifier = KeyAgreeRecipientIdentifier.getInstance(seq.getObjectAt(0)); encryptedKey = (ASN1OctetString)seq.getObjectAt(1); } - + /** * Return an RecipientEncryptedKey object from a tagged object. * @@ -45,7 +45,7 @@ public static RecipientEncryptedKey getInstance( { return getInstance(ASN1Sequence.getInstance(obj, explicit)); } - + /** * Return a RecipientEncryptedKey object from the given object. *

          @@ -66,14 +66,14 @@ public static RecipientEncryptedKey getInstance( { return (RecipientEncryptedKey)obj; } - + if (obj != null) { return new RecipientEncryptedKey(ASN1Sequence.getInstance(obj)); } - + return null; - } + } public RecipientEncryptedKey( KeyAgreeRecipientIdentifier id, @@ -93,7 +93,7 @@ public ASN1OctetString getEncryptedKey() return encryptedKey; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/RecipientIdentifier.java b/util/src/main/java/org/bouncycastle/asn1/cms/RecipientIdentifier.java index 5a03d4c862..b7f0008c91 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/RecipientIdentifier.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/RecipientIdentifier.java @@ -14,7 +14,7 @@ *

            * RecipientIdentifier ::= CHOICE {
            *     issuerAndSerialNumber IssuerAndSerialNumber,
          - *     subjectKeyIdentifier [0] SubjectKeyIdentifier 
          + *     subjectKeyIdentifier [0] SubjectKeyIdentifier
            * }
            *
            * SubjectKeyIdentifier ::= OCTET STRING
          @@ -25,25 +25,25 @@ public class RecipientIdentifier
               implements ASN1Choice
           {
               private ASN1Encodable id;
          -    
          +
               public RecipientIdentifier(
                   IssuerAndSerialNumber id)
               {
                   this.id = id;
               }
          -    
          +
               public RecipientIdentifier(
                   ASN1OctetString id)
               {
                   this.id = new DERTaggedObject(false, 0, id);
               }
          -    
          +
               public RecipientIdentifier(
                   ASN1Primitive id)
               {
                   this.id = id;
               }
          -    
          +
               /**
                * Return a RecipientIdentifier object from the given object.
                * 

          @@ -66,25 +66,25 @@ public static RecipientIdentifier getInstance( { return (RecipientIdentifier)o; } - + if (o instanceof IssuerAndSerialNumber) { return new RecipientIdentifier((IssuerAndSerialNumber)o); } - + if (o instanceof ASN1OctetString) { return new RecipientIdentifier((ASN1OctetString)o); } - + if (o instanceof ASN1Primitive) { return new RecipientIdentifier((ASN1Primitive)o); } - + throw new IllegalArgumentException( "Illegal object in RecipientIdentifier: " + o.getClass().getName()); - } + } public boolean isTagged() { @@ -101,7 +101,7 @@ public ASN1Encodable getId() return IssuerAndSerialNumber.getInstance(id); } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/RecipientInfo.java b/util/src/main/java/org/bouncycastle/asn1/cms/RecipientInfo.java index 23f6c0a043..61fadc756f 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/RecipientInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/RecipientInfo.java @@ -118,7 +118,7 @@ public ASN1Integer getVersion() case 3: return PasswordRecipientInfo.getInstance(tagged, false).getVersion(); case 4: - return new ASN1Integer(0); // no syntax version for OtherRecipientInfo + return ASN1Integer.ZERO; // no syntax version for OtherRecipientInfo } } throw new IllegalStateException("unknown tag"); diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/RecipientKeyIdentifier.java b/util/src/main/java/org/bouncycastle/asn1/cms/RecipientKeyIdentifier.java index 9ae3163ea9..134c71b2c9 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/RecipientKeyIdentifier.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/RecipientKeyIdentifier.java @@ -18,7 +18,7 @@ * RecipientKeyIdentifier ::= SEQUENCE { * subjectKeyIdentifier SubjectKeyIdentifier, * date GeneralizedTime OPTIONAL, - * other OtherKeyAttribute OPTIONAL + * other OtherKeyAttribute OPTIONAL * } * * SubjectKeyIdentifier ::= OCTET STRING @@ -62,7 +62,7 @@ private RecipientKeyIdentifier( { subjectKeyIdentifier = ASN1OctetString.getInstance( seq.getObjectAt(0)); - + switch(seq.size()) { case 1: @@ -99,7 +99,7 @@ public static RecipientKeyIdentifier getInstance(ASN1TaggedObject ato, boolean i { return getInstance(ASN1Sequence.getInstance(ato, isExplicit)); } - + /** * Return a RecipientKeyIdentifier object from the given object. *

          @@ -119,14 +119,14 @@ public static RecipientKeyIdentifier getInstance(Object obj) { return (RecipientKeyIdentifier)obj; } - + if(obj != null) { return new RecipientKeyIdentifier(ASN1Sequence.getInstance(obj)); } - + return null; - } + } public ASN1OctetString getSubjectKeyIdentifier() { @@ -144,7 +144,7 @@ public OtherKeyAttribute getOtherKeyAttribute() } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() @@ -152,7 +152,7 @@ public ASN1Primitive toASN1Primitive() ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(subjectKeyIdentifier); - + if (date != null) { v.add(date); @@ -162,7 +162,7 @@ public ASN1Primitive toASN1Primitive() { v.add(other); } - + return new DERSequence(v); } } diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/SCVPReqRes.java b/util/src/main/java/org/bouncycastle/asn1/cms/SCVPReqRes.java index b1e4a370e6..2af1846e54 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/SCVPReqRes.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/SCVPReqRes.java @@ -1,6 +1,5 @@ package org.bouncycastle.asn1.cms; -import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; @@ -37,8 +36,7 @@ public class SCVPReqRes * @param obj the object we want converted. * @exception IllegalArgumentException if the object cannot be converted. */ - public static SCVPReqRes getInstance( - Object obj) + public static SCVPReqRes getInstance(Object obj) { if (obj instanceof SCVPReqRes) { @@ -52,29 +50,57 @@ else if (obj != null) return null; } - private SCVPReqRes( - ASN1Sequence seq) + public static SCVPReqRes getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) { - if (seq.getObjectAt(0) instanceof ASN1TaggedObject) + return new SCVPReqRes(ASN1Sequence.getInstance(taggedObject, declaredExplicit)); + } + + public static SCVPReqRes getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return new SCVPReqRes(ASN1Sequence.getTagged(taggedObject, declaredExplicit)); + } + + private SCVPReqRes(ASN1Sequence seq) + { + int count = seq.size(), pos = 0; + if (count < 1 || count > 2) + { + throw new IllegalArgumentException("Bad sequence size: " + count); + } + + // request [0] EXPLICIT ContentInfo OPTIONAL + ContentInfo request = null; + if (pos < count) { - this.request = ContentInfo.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(0)), true); - this.response = ContentInfo.getInstance(seq.getObjectAt(1)); + ASN1TaggedObject tag0 = ASN1TaggedObject.getContextOptional(seq.getObjectAt(pos), 0); + if (tag0 != null) + { + pos++; + request = ContentInfo.getTagged(tag0, true); + } } - else + this.request = request; + + this.response = ContentInfo.getInstance(seq.getObjectAt(pos++)); + + if (pos != count) { - this.request = null; - this.response = ContentInfo.getInstance(seq.getObjectAt(0)); + throw new IllegalArgumentException("Unexpected elements in sequence"); } } public SCVPReqRes(ContentInfo response) { - this.request = null; // use of this confuses earlier JDKs - this.response = response; + this(null, response); } public SCVPReqRes(ContentInfo request, ContentInfo response) { + if (response == null) + { + throw new NullPointerException("'response' cannot be null"); + } + this.request = request; this.response = response; } @@ -94,15 +120,11 @@ public ContentInfo getResponse() */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(2); - - if (request != null) + if (request == null) { - v.add(new DERTaggedObject(true, 0, request)); + return new DERSequence(response); } - v.add(response); - - return new DERSequence(v); + return new DERSequence(new DERTaggedObject(true, 0, request), response); } } diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/SignedData.java b/util/src/main/java/org/bouncycastle/asn1/cms/SignedData.java index b354c5649a..8f50ced510 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/SignedData.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/SignedData.java @@ -29,9 +29,9 @@ * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, * signerInfos SignerInfos * } - * + * * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier - * + * * SignerInfos ::= SET OF SignerInfo *

          *

          @@ -59,11 +59,6 @@ public class SignedData extends ASN1Object { - private static final ASN1Integer VERSION_1 = new ASN1Integer(1); - private static final ASN1Integer VERSION_3 = new ASN1Integer(3); - private static final ASN1Integer VERSION_4 = new ASN1Integer(4); - private static final ASN1Integer VERSION_5 = new ASN1Integer(5); - private final ASN1Integer version; private final ASN1Set digestAlgorithms; private final ContentInfo contentInfo; @@ -163,7 +158,7 @@ else if (tagged.getTagNo() == 3) if (otherCert) { - return new ASN1Integer(5); + return ASN1Integer.FIVE; } if (crls != null) // no need to check if otherCert is true @@ -180,30 +175,30 @@ else if (tagged.getTagNo() == 3) if (otherCrl) { - return VERSION_5; + return ASN1Integer.FIVE; } if (attrCertV2Found) { - return VERSION_4; + return ASN1Integer.FOUR; } if (attrCertV1Found) { - return VERSION_3; + return ASN1Integer.THREE; } if (checkForVersion3(signerInfs)) { - return VERSION_3; + return ASN1Integer.THREE; } if (!CMSObjectIdentifiers.data.equals(contentOid)) { - return VERSION_3; + return ASN1Integer.THREE; } - return VERSION_1; + return ASN1Integer.ONE; } private boolean checkForVersion3(ASN1Set signerInfs) @@ -344,7 +339,7 @@ public ASN1Primitive toASN1Primitive() } v.add(signerInfos); - + if (!contentInfo.isDefiniteLength() || digsBer || sigsBer || crlsBer || certsBer) { return new BERSequence(v); diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java b/util/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java index d5681483fc..49ef0b3950 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/SignerIdentifier.java @@ -17,7 +17,7 @@ *

            * SignerIdentifier ::= CHOICE {
            *     issuerAndSerialNumber IssuerAndSerialNumber,
          - *     subjectKeyIdentifier [0] SubjectKeyIdentifier 
          + *     subjectKeyIdentifier [0] SubjectKeyIdentifier
            * }
            *
            * SubjectKeyIdentifier ::= OCTET STRING
          @@ -28,25 +28,25 @@ public class SignerIdentifier
               implements ASN1Choice
           {
               private ASN1Encodable id;
          -    
          +
               public SignerIdentifier(
                   IssuerAndSerialNumber id)
               {
                   this.id = id;
               }
          -    
          +
               public SignerIdentifier(
                   ASN1OctetString id)
               {
                   this.id = new DERTaggedObject(false, 0, id);
               }
          -    
          +
               public SignerIdentifier(
                   ASN1Primitive id)
               {
                   this.id = id;
               }
          -    
          +
               /**
                * Return a SignerIdentifier object from the given object.
                * 

          @@ -69,25 +69,25 @@ public static SignerIdentifier getInstance( { return (SignerIdentifier)o; } - + if (o instanceof IssuerAndSerialNumber) { return new SignerIdentifier((IssuerAndSerialNumber)o); } - + if (o instanceof ASN1OctetString) { return new SignerIdentifier((ASN1OctetString)o); } - + if (o instanceof ASN1Primitive) { return new SignerIdentifier((ASN1Primitive)o); } - + throw new IllegalArgumentException( "Illegal object in SignerIdentifier: " + o.getClass().getName()); - } + } public boolean isTagged() { @@ -104,7 +104,7 @@ public ASN1Encodable getId() return id; } - /** + /** * Produce an object suitable for an ASN1OutputStream. */ public ASN1Primitive toASN1Primitive() diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java b/util/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java index 491bb91b20..f88ff37aec 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/SignerInfo.java @@ -62,13 +62,13 @@ * * SignedAttributes ::= SET SIZE (1..MAX) OF Attribute * UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute - * + * * {@link Attribute} ::= SEQUENCE { * attrType OBJECT IDENTIFIER, * attrValues SET OF AttributeValue } * * AttributeValue ::= ANY - * + * * SignatureValue ::= OCTET STRING *

          */ @@ -131,11 +131,11 @@ public SignerInfo( { if (sid.isTagged()) { - this.version = new ASN1Integer(3); + this.version = ASN1Integer.THREE; } else { - this.version = new ASN1Integer(1); + this.version = ASN1Integer.ONE; } this.sid = sid; @@ -165,11 +165,11 @@ public SignerInfo( { if (sid.isTagged()) { - this.version = new ASN1Integer(3); + this.version = ASN1Integer.THREE; } else { - this.version = new ASN1Integer(1); + this.version = ASN1Integer.ONE; } this.sid = sid; diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/Time.java b/util/src/main/java/org/bouncycastle/asn1/cms/Time.java index ecc9b199c6..b260b736a6 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/Time.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/Time.java @@ -59,7 +59,7 @@ private Time( throw new IllegalArgumentException("unknown object passed to Time"); } - this.time = time; + this.time = time; } /** diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/TimeStampedData.java b/util/src/main/java/org/bouncycastle/asn1/cms/TimeStampedData.java index 94ba67c568..5590d5dcbb 100644 --- a/util/src/main/java/org/bouncycastle/asn1/cms/TimeStampedData.java +++ b/util/src/main/java/org/bouncycastle/asn1/cms/TimeStampedData.java @@ -35,7 +35,7 @@ public class TimeStampedData public TimeStampedData(ASN1IA5String dataUri, MetaData metaData, ASN1OctetString content, Evidence temporalEvidence) { - this.version = new ASN1Integer(1); + this.version = ASN1Integer.ONE; this.dataUri = dataUri; this.metaData = metaData; this.content = content; diff --git a/util/src/main/java/org/bouncycastle/asn1/crmf/CertRequest.java b/util/src/main/java/org/bouncycastle/asn1/crmf/CertRequest.java index f7f0adf571..caeba6346c 100644 --- a/util/src/main/java/org/bouncycastle/asn1/crmf/CertRequest.java +++ b/util/src/main/java/org/bouncycastle/asn1/crmf/CertRequest.java @@ -43,7 +43,7 @@ public CertRequest( CertTemplate certTemplate, Controls controls) { - this(new ASN1Integer(certReqId), certTemplate, controls); + this(ASN1Integer.valueOf(certReqId), certTemplate, controls); } public CertRequest( diff --git a/util/src/main/java/org/bouncycastle/asn1/crmf/CertTemplateBuilder.java b/util/src/main/java/org/bouncycastle/asn1/crmf/CertTemplateBuilder.java index 305b6727da..256ba0648b 100644 --- a/util/src/main/java/org/bouncycastle/asn1/crmf/CertTemplateBuilder.java +++ b/util/src/main/java/org/bouncycastle/asn1/crmf/CertTemplateBuilder.java @@ -28,7 +28,7 @@ public class CertTemplateBuilder /** Sets the X.509 version. Note: for X509v3, use 2 here. */ public CertTemplateBuilder setVersion(int ver) { - version = new ASN1Integer(ver); + version = ASN1Integer.valueOf(ver); return this; } diff --git a/util/src/main/java/org/bouncycastle/asn1/crmf/EncKeyWithID.java b/util/src/main/java/org/bouncycastle/asn1/crmf/EncKeyWithID.java index 2e3ca95895..0320ca2d14 100644 --- a/util/src/main/java/org/bouncycastle/asn1/crmf/EncKeyWithID.java +++ b/util/src/main/java/org/bouncycastle/asn1/crmf/EncKeyWithID.java @@ -89,7 +89,7 @@ public ASN1Encodable getIdentifier() { return identifier; } - + /** *
                * EncKeyWithID ::= SEQUENCE {
          diff --git a/util/src/main/java/org/bouncycastle/asn1/crmf/OptionalValidity.java b/util/src/main/java/org/bouncycastle/asn1/crmf/OptionalValidity.java
          index bbc3124a41..62ddebd16e 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/crmf/OptionalValidity.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/crmf/OptionalValidity.java
          @@ -14,6 +14,31 @@
           public class OptionalValidity
               extends ASN1Object
           {
          +    public static OptionalValidity getInstance(Object o)
          +    {
          +        if (o instanceof OptionalValidity)
          +        {
          +            return (OptionalValidity)o;
          +        }
          +
          +        if (o != null)
          +        {
          +            return new OptionalValidity(ASN1Sequence.getInstance(o));
          +        }
          +
          +        return null;
          +    }
          +
          +    public static OptionalValidity getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit)
          +    {
          +        return new OptionalValidity(ASN1Sequence.getInstance(taggedObject, declaredExplicit));
          +    }
          +
          +    public static OptionalValidity getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit)
          +    {
          +        return new OptionalValidity(ASN1Sequence.getTagged(taggedObject, declaredExplicit));
          +    }
          +
               private Time notBefore;
               private Time notAfter;
           
          @@ -26,35 +51,22 @@ private OptionalValidity(ASN1Sequence seq)
           
                       if (tObj.getTagNo() == 0)
                       {
          -                notBefore = Time.getInstance(tObj, true);
          +                notBefore = Time.getInstance(tObj, true); // CHOICE
                       }
                       else
                       {
          -                notAfter = Time.getInstance(tObj, true);
          +                notAfter = Time.getInstance(tObj, true); // CHOICE
                       }
                   }
          -    }
           
          -    public static OptionalValidity getInstance(Object o)
          -    {
          -        if (o instanceof OptionalValidity)
          -        {
          -            return (OptionalValidity)o;
          -        }
          -
          -        if (o != null)
          -        {
          -            return new OptionalValidity(ASN1Sequence.getInstance(o));
          -        }
          -
          -        return null;
          +        // TODO[crmf] Validate the "at least one" rule after parsing?
               }
           
               public OptionalValidity(Time notBefore, Time notAfter)
               {
                   if (notBefore == null && notAfter == null)
                   {
          -            throw new IllegalArgumentException("at least one of notBefore/notAfter must not be null.");
          +            throw new IllegalArgumentException("at least one of notBefore/notAfter MUST be present.");
                   }
           
                   this.notBefore = notBefore;
          @@ -74,9 +86,12 @@ public Time getNotAfter()
               /**
                * 
                * OptionalValidity ::= SEQUENCE {
          -     *                        notBefore  [0] Time OPTIONAL,
          -     *                        notAfter   [1] Time OPTIONAL } --at least one MUST be present
          +     *     notBefore    [0] Time OPTIONAL,
          +     *     notAfter     [1] Time OPTIONAL } --at least one MUST be present
          +     *
          +     * Time ::= CHOICE { ... }
                * 
          + * * @return a basic ASN.1 object representation. */ public ASN1Primitive toASN1Primitive() @@ -85,12 +100,12 @@ public ASN1Primitive toASN1Primitive() if (notBefore != null) { - v.add(new DERTaggedObject(true, 0, notBefore)); + v.add(new DERTaggedObject(true, 0, notBefore)); // CHOICE } if (notAfter != null) { - v.add(new DERTaggedObject(true, 1, notAfter)); + v.add(new DERTaggedObject(true, 1, notAfter)); // CHOICE } return new DERSequence(v); diff --git a/util/src/main/java/org/bouncycastle/asn1/crmf/PKIArchiveOptions.java b/util/src/main/java/org/bouncycastle/asn1/crmf/PKIArchiveOptions.java index e97bcbea8a..17420cb130 100644 --- a/util/src/main/java/org/bouncycastle/asn1/crmf/PKIArchiveOptions.java +++ b/util/src/main/java/org/bouncycastle/asn1/crmf/PKIArchiveOptions.java @@ -7,7 +7,6 @@ import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERTaggedObject; public class PKIArchiveOptions @@ -28,7 +27,7 @@ public static PKIArchiveOptions getInstance(Object o) } else if (o instanceof ASN1TaggedObject) { - return new PKIArchiveOptions(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC)); + return new PKIArchiveOptions(ASN1TaggedObject.getContextInstance(o)); } throw new IllegalArgumentException("unknown object: " + o); @@ -86,7 +85,7 @@ public ASN1Encodable getValue() { return value; } - + /** *
                *  PKIArchiveOptions ::= CHOICE {
          diff --git a/util/src/main/java/org/bouncycastle/asn1/crmf/PKIPublicationInfo.java b/util/src/main/java/org/bouncycastle/asn1/crmf/PKIPublicationInfo.java
          index 5f597059de..352f891ec9 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/crmf/PKIPublicationInfo.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/crmf/PKIPublicationInfo.java
          @@ -24,8 +24,8 @@
           public class PKIPublicationInfo
               extends ASN1Object
           {
          -    public static final ASN1Integer dontPublish = new ASN1Integer(0);
          -    public static final ASN1Integer pleasePublish = new ASN1Integer(1);
          +    public static final ASN1Integer dontPublish = ASN1Integer.ZERO;
          +    public static final ASN1Integer pleasePublish = ASN1Integer.ONE;
           
               private ASN1Integer action;
               private ASN1Sequence pubInfos;
          diff --git a/util/src/main/java/org/bouncycastle/asn1/crmf/SinglePubInfo.java b/util/src/main/java/org/bouncycastle/asn1/crmf/SinglePubInfo.java
          index cf3dcd004c..5248316be9 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/crmf/SinglePubInfo.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/crmf/SinglePubInfo.java
          @@ -22,10 +22,10 @@
           public class SinglePubInfo
               extends ASN1Object
           {
          -    public static final ASN1Integer dontCare = new ASN1Integer(0);
          -    public static final ASN1Integer x500 = new ASN1Integer(1);
          -    public static final ASN1Integer web = new ASN1Integer(2);
          -    public static final ASN1Integer ldap = new ASN1Integer(3);
          +    public static final ASN1Integer dontCare = ASN1Integer.valueOf(0);
          +    public static final ASN1Integer x500 = ASN1Integer.valueOf(1);
          +    public static final ASN1Integer web = ASN1Integer.valueOf(2);
          +    public static final ASN1Integer ldap = ASN1Integer.valueOf(3);
           
               private ASN1Integer pubMethod;
               private GeneralName pubLocation;
          diff --git a/util/src/main/java/org/bouncycastle/asn1/crmf/SubsequentMessage.java b/util/src/main/java/org/bouncycastle/asn1/crmf/SubsequentMessage.java
          index 4691722855..743262f7ba 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/crmf/SubsequentMessage.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/crmf/SubsequentMessage.java
          @@ -7,7 +7,7 @@ public class SubsequentMessage
           {
               public static final SubsequentMessage encrCert = new SubsequentMessage(0);
               public static final SubsequentMessage challengeResp = new SubsequentMessage(1);
          -    
          +
               private SubsequentMessage(int value)
               {
                   super(value);
          diff --git a/util/src/main/java/org/bouncycastle/asn1/dvcs/CertEtcToken.java b/util/src/main/java/org/bouncycastle/asn1/dvcs/CertEtcToken.java
          index c54c03c185..75e2d7915b 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/dvcs/CertEtcToken.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/dvcs/CertEtcToken.java
          @@ -6,7 +6,6 @@
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1Sequence;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERTaggedObject;
           import org.bouncycastle.asn1.cmp.PKIStatusInfo;
           import org.bouncycastle.asn1.cms.ContentInfo;
          @@ -116,7 +115,7 @@ public static CertEtcToken getInstance(Object obj)
                   }
                   else if (obj instanceof ASN1TaggedObject)
                   {
          -            return new CertEtcToken(ASN1TaggedObject.getInstance(obj, BERTags.CONTEXT_SPECIFIC));
          +            return new CertEtcToken(ASN1TaggedObject.getContextInstance(obj));
                   }
                   else if (obj != null)
                   {
          diff --git a/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java b/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java
          index ce5ecd5ea1..42ab3bf0a7 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java
          @@ -158,7 +158,7 @@ public ASN1Primitive toASN1Primitive()
           
                   if (version != DEFAULT_VERSION)
                   {
          -            v.add(new ASN1Integer(version));
          +            v.add(ASN1Integer.valueOf(version));
                   }
                   v.add(dvReqInfo);
                   v.add(messageImprint);
          @@ -190,7 +190,7 @@ public ASN1Primitive toASN1Primitive()
           
               public String toString()
               {
          -        StringBuffer s = new StringBuffer();
          +        StringBuilder s = new StringBuilder();
           
                   s.append("DVCSCertInfo {\n");
           
          diff --git a/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfoBuilder.java b/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfoBuilder.java
          index ab4ab4ffd8..2d2e5df876 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfoBuilder.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSCertInfoBuilder.java
          @@ -67,7 +67,7 @@ public DVCSCertInfo build()
           
                   if (version != DEFAULT_VERSION)
                   {
          -            v.add(new ASN1Integer(version));
          +            v.add(ASN1Integer.valueOf(version));
                   }
                   v.add(dvReqInfo);
                   v.add(messageImprint);
          diff --git a/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java b/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java
          index e0026cba21..645bb2e121 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java
          @@ -142,7 +142,7 @@ public ASN1Primitive toASN1Primitive()
           
                   if (version != DEFAULT_VERSION)
                   {
          -            v.add(new ASN1Integer(version));
          +            v.add(ASN1Integer.valueOf(version));
                   }
                   v.add(service);
                   if (nonce != null)
          @@ -184,7 +184,7 @@ public ASN1Primitive toASN1Primitive()
               public String toString()
               {
           
          -        StringBuffer s = new StringBuffer();
          +        StringBuilder s = new StringBuilder();
           
                   s.append("DVCSRequestInformation {\n");
           
          diff --git a/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformationBuilder.java b/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformationBuilder.java
          index dafb58f6a7..d4efbc19d1 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformationBuilder.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSRequestInformationBuilder.java
          @@ -73,7 +73,7 @@ public DVCSRequestInformation build()
           
                   if (version != DEFAULT_VERSION)
                   {
          -            v.add(new ASN1Integer(version));
          +            v.add(ASN1Integer.valueOf(version));
                   }
                   v.add(service);
                   if (nonce != null)
          diff --git a/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSTime.java b/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSTime.java
          index 2ad99baeb6..3ae2a98909 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSTime.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/dvcs/DVCSTime.java
          @@ -7,7 +7,6 @@
           import org.bouncycastle.asn1.ASN1Object;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.cms.ContentInfo;
           
           /**
          @@ -71,7 +70,7 @@ public static DVCSTime getInstance(
                       throw new IllegalArgumentException("choice item must be explicitly tagged");
                   }
           
          -        return getInstance(ASN1TaggedObject.getInstance(obj, BERTags.CONTEXT_SPECIFIC).getExplicitBaseObject()); // must be explicitly tagged
          +        return getInstance(ASN1TaggedObject.getContextInstance(obj).getExplicitBaseObject()); // must be explicitly tagged
               }
           
           
          diff --git a/util/src/main/java/org/bouncycastle/asn1/dvcs/PathProcInput.java b/util/src/main/java/org/bouncycastle/asn1/dvcs/PathProcInput.java
          index 4301fdb5d7..e0868c8b36 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/dvcs/PathProcInput.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/dvcs/PathProcInput.java
          @@ -119,7 +119,7 @@ public ASN1Primitive toASN1Primitive()
                       {
                           pV.add(acceptablePolicySet[i]);
                       }
          -    
          +
                       v.add(new DERSequence(pV));
                   }
           
          diff --git a/util/src/main/java/org/bouncycastle/asn1/dvcs/TargetEtcChain.java b/util/src/main/java/org/bouncycastle/asn1/dvcs/TargetEtcChain.java
          index cbe8ab934c..94228e20cb 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/dvcs/TargetEtcChain.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/dvcs/TargetEtcChain.java
          @@ -131,7 +131,7 @@ public ASN1Primitive toASN1Primitive()
           
               public String toString()
               {
          -        StringBuffer s = new StringBuffer();
          +        StringBuilder s = new StringBuilder();
                   s.append("TargetEtcChain {\n");
                   s.append("target: " + target + "\n");
                   if (chain != null)
          diff --git a/util/src/main/java/org/bouncycastle/asn1/eac/ECDSAPublicKey.java b/util/src/main/java/org/bouncycastle/asn1/eac/ECDSAPublicKey.java
          index 5b016b6a92..4acec9f496 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/eac/ECDSAPublicKey.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/eac/ECDSAPublicKey.java
          @@ -59,7 +59,7 @@ public class ECDSAPublicKey
                   while (en.hasMoreElements())
                   {
                       Object obj = en.nextElement();
          -            
          +
                       if (obj instanceof ASN1TaggedObject)
                       {
                           ASN1TaggedObject to = (ASN1TaggedObject)obj;
          diff --git a/util/src/main/java/org/bouncycastle/asn1/eac/Flags.java b/util/src/main/java/org/bouncycastle/asn1/eac/Flags.java
          index e8dfbbec51..0cff9df6b3 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/eac/Flags.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/eac/Flags.java
          @@ -67,7 +67,7 @@ private static class StringJoiner
           
                   String mSeparator;
                   boolean First = true;
          -        StringBuffer b = new StringBuffer();
          +        StringBuilder b = new StringBuilder();
           
                   public StringJoiner(String separator)
                   {
          diff --git a/util/src/main/java/org/bouncycastle/asn1/eac/PackedDate.java b/util/src/main/java/org/bouncycastle/asn1/eac/PackedDate.java
          index 143040ba86..05e619466a 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/eac/PackedDate.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/eac/PackedDate.java
          @@ -105,7 +105,7 @@ public boolean equals(Object o)
                   return Arrays.areEqual(time, other.time);
               }
           
          -    public String toString() 
          +    public String toString()
               {
                   char[]  dateC = new char[time.length];
           
          diff --git a/util/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIndication.java b/util/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIndication.java
          index 2bb9c60c21..95ddaa6d4d 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIndication.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeIndication.java
          @@ -12,7 +12,7 @@ public class CommitmentTypeIndication
           {
               private ASN1ObjectIdentifier   commitmentTypeId;
               private ASN1Sequence          commitmentTypeQualifier;
          -    
          +
               private CommitmentTypeIndication(
                   ASN1Sequence seq)
               {
          @@ -53,12 +53,12 @@ public ASN1ObjectIdentifier getCommitmentTypeId()
               {
                   return commitmentTypeId;
               }
          -    
          +
               public ASN1Sequence getCommitmentTypeQualifier()
               {
                   return commitmentTypeQualifier;
               }
          -    
          +
               /**
                * 
                * CommitmentTypeIndication ::= SEQUENCE {
          @@ -66,18 +66,18 @@ public ASN1Sequence getCommitmentTypeQualifier()
                *      commitmentTypeQualifier   SEQUENCE SIZE (1..MAX) OF
                *              CommitmentTypeQualifier OPTIONAL }
                * 
          - */ + */ public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(2); - + v.add(commitmentTypeId); if (commitmentTypeQualifier != null) { v.add(commitmentTypeQualifier); } - + return new DERSequence(v); } } diff --git a/util/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeQualifier.java b/util/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeQualifier.java index f826bb035f..bc08e6a73d 100644 --- a/util/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeQualifier.java +++ b/util/src/main/java/org/bouncycastle/asn1/esf/CommitmentTypeQualifier.java @@ -10,7 +10,7 @@ /** * Commitment type qualifiers, used in the Commitment-Type-Indication attribute (RFC3126). - * + * *
            *   CommitmentTypeQualifier ::= SEQUENCE {
            *       commitmentTypeIdentifier  CommitmentTypeIdentifier,
          @@ -33,7 +33,7 @@ public CommitmentTypeQualifier(
               {
                   this(commitmentTypeIdentifier, null);
               }
          -    
          +
              /**
               * Creates a new CommitmentTypeQualifier instance.
               *
          @@ -52,13 +52,13 @@ public CommitmentTypeQualifier(
                * Creates a new CommitmentTypeQualifier instance.
                *
                * @param as CommitmentTypeQualifier structure
          -     * encoded as an ASN1Sequence. 
          +     * encoded as an ASN1Sequence.
                */
               private CommitmentTypeQualifier(
                   ASN1Sequence as)
               {
                   commitmentTypeIdentifier = (ASN1ObjectIdentifier)as.getObjectAt(0);
          -        
          +
                   if (as.size() > 1)
                   {
                       qualifier = as.getObjectAt(1);
          @@ -83,14 +83,14 @@ public ASN1ObjectIdentifier getCommitmentTypeIdentifier()
               {
                   return commitmentTypeIdentifier;
               }
          -    
          +
               public ASN1Encodable getQualifier()
               {
                   return qualifier;
               }
           
              /**
          -    * Returns a DER-encodable representation of this instance. 
          +    * Returns a DER-encodable representation of this instance.
               *
               * @return a ASN1Primitive value
               */
          diff --git a/util/src/main/java/org/bouncycastle/asn1/esf/CrlIdentifier.java b/util/src/main/java/org/bouncycastle/asn1/esf/CrlIdentifier.java
          index 99d5fdbd4d..276152d818 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/esf/CrlIdentifier.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/esf/CrlIdentifier.java
          @@ -13,7 +13,7 @@
           
           /**
            * 
          - *  CrlIdentifier ::= SEQUENCE 
          + *  CrlIdentifier ::= SEQUENCE
            * {
            *   crlissuer    Name,
            *   crlIssuedTime  UTCTime,
          diff --git a/util/src/main/java/org/bouncycastle/asn1/esf/CrlOcspRef.java b/util/src/main/java/org/bouncycastle/asn1/esf/CrlOcspRef.java
          index b81dc6176a..4af28ed6da 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/esf/CrlOcspRef.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/esf/CrlOcspRef.java
          @@ -7,7 +7,6 @@
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1Sequence;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERSequence;
           import org.bouncycastle.asn1.DERTaggedObject;
           
          @@ -47,7 +46,7 @@ private CrlOcspRef(ASN1Sequence seq)
                   Enumeration e = seq.getObjects();
                   while (e.hasMoreElements())
                   {
          -            ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement(), BERTags.CONTEXT_SPECIFIC);
          +            ASN1TaggedObject o = ASN1TaggedObject.getContextInstance(e.nextElement());
                       switch (o.getTagNo())
                       {
                           case 0:
          diff --git a/util/src/main/java/org/bouncycastle/asn1/esf/RevocationValues.java b/util/src/main/java/org/bouncycastle/asn1/esf/RevocationValues.java
          index 7196a38bf6..82335b1590 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/esf/RevocationValues.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/esf/RevocationValues.java
          @@ -7,7 +7,6 @@
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1Sequence;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERSequence;
           import org.bouncycastle.asn1.DERTaggedObject;
           import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
          @@ -53,7 +52,7 @@ private RevocationValues(ASN1Sequence seq)
                   Enumeration e = seq.getObjects();
                   while (e.hasMoreElements())
                   {
          -            ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement(), BERTags.CONTEXT_SPECIFIC);
          +            ASN1TaggedObject o = ASN1TaggedObject.getContextInstance(e.nextElement());
                       switch (o.getTagNo())
                       {
                           case 0:
          diff --git a/util/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java b/util/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java
          index 1a2132446f..cad7edae37 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/esf/SignerLocation.java
          @@ -8,7 +8,6 @@
           import org.bouncycastle.asn1.ASN1Sequence;
           import org.bouncycastle.asn1.ASN1TaggedObject;
           import org.bouncycastle.asn1.ASN1UTF8String;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERSequence;
           import org.bouncycastle.asn1.DERTaggedObject;
           import org.bouncycastle.asn1.DERUTF8String;
          @@ -16,7 +15,7 @@
           
           /**
            * Signer-Location attribute (RFC3126).
          - * 
          + *
            * 
            *   SignerLocation ::= SEQUENCE {
            *       countryName        [0] DirectoryString OPTIONAL,
          @@ -32,7 +31,7 @@ public class SignerLocation
               private DirectoryString   countryName;
               private DirectoryString   localityName;
               private ASN1Sequence      postalAddress;
          -    
          +
               private SignerLocation(
                   ASN1Sequence seq)
               {
          @@ -40,7 +39,7 @@ private SignerLocation(
           
                   while (e.hasMoreElements())
                   {
          -            ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement(), BERTags.CONTEXT_SPECIFIC);
          +            ASN1TaggedObject o = ASN1TaggedObject.getContextInstance(e.nextElement());
           
                       switch (o.getTagNo())
                       {
          @@ -190,7 +189,7 @@ public ASN1Sequence getPostalAddress()
                *       postalAddress      [2] PostalAddress OPTIONAL }
                *
                *   PostalAddress ::= SEQUENCE SIZE(1..6) OF DirectoryString
          -     *   
          +     *
                *   DirectoryString ::= CHOICE {
                *         teletexString           TeletexString (SIZE (1..MAX)),
                *         printableString         PrintableString (SIZE (1..MAX)),
          diff --git a/util/src/main/java/org/bouncycastle/asn1/esf/package-info.java b/util/src/main/java/org/bouncycastle/asn1/esf/package-info.java
          index ebbdcc0d61..9d55e4f7fc 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/esf/package-info.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/esf/package-info.java
          @@ -1,5 +1,5 @@
           /**
          - * Support classes useful for encoding and supporting [ESF] RFC3126 
          + * Support classes useful for encoding and supporting [ESF] RFC3126
            * Electronic Signature Formats for long term electronic signatures.
            */
           package org.bouncycastle.asn1.esf;
          diff --git a/util/src/main/java/org/bouncycastle/asn1/ess/ContentIdentifier.java b/util/src/main/java/org/bouncycastle/asn1/ess/ContentIdentifier.java
          index 37064c4e20..4781795de8 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/ess/ContentIdentifier.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/ess/ContentIdentifier.java
          @@ -41,7 +41,7 @@ public ContentIdentifier(
               {
                   this(new DEROctetString(value));
               }
          -    
          +
               public ASN1OctetString getValue()
               {
                   return value;
          diff --git a/util/src/main/java/org/bouncycastle/asn1/ess/ESSCertID.java b/util/src/main/java/org/bouncycastle/asn1/ess/ESSCertID.java
          index ec09ba01f2..2bb78394a9 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/ess/ESSCertID.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/ess/ESSCertID.java
          @@ -42,7 +42,7 @@ private ESSCertID(ASN1Sequence seq)
                   }
           
                   certHash = ASN1OctetString.getInstance(seq.getObjectAt(0));
          - 
          +
                   if (seq.size() > 1)
                   {
                       issuerSerial = IssuerSerial.getInstance(seq.getObjectAt(1));
          @@ -92,16 +92,16 @@ public IssuerSerial getIssuerSerial()
               /**
                * 
                * ESSCertID ::= SEQUENCE {
          -     *     certHash Hash, 
          +     *     certHash Hash,
                *     issuerSerial IssuerSerial OPTIONAL }
                * 
          */ public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(2); - + v.add(certHash); - + if (issuerSerial != null) { v.add(issuerSerial); diff --git a/util/src/main/java/org/bouncycastle/asn1/ess/SigningCertificate.java b/util/src/main/java/org/bouncycastle/asn1/ess/SigningCertificate.java index d5388c51a4..a867ec17b9 100644 --- a/util/src/main/java/org/bouncycastle/asn1/ess/SigningCertificate.java +++ b/util/src/main/java/org/bouncycastle/asn1/ess/SigningCertificate.java @@ -39,7 +39,7 @@ private SigningCertificate(ASN1Sequence seq) + seq.size()); } this.certs = ASN1Sequence.getInstance(seq.getObjectAt(0)); - + if (seq.size() > 1) { this.policies = ASN1Sequence.getInstance(seq.getObjectAt(1)); @@ -55,32 +55,32 @@ public SigningCertificate( public ESSCertID[] getCerts() { ESSCertID[] cs = new ESSCertID[certs.size()]; - + for (int i = 0; i != certs.size(); i++) { cs[i] = ESSCertID.getInstance(certs.getObjectAt(i)); } - + return cs; } - + public PolicyInformation[] getPolicies() { if (policies == null) { return null; } - + PolicyInformation[] ps = new PolicyInformation[policies.size()]; - + for (int i = 0; i != policies.size(); i++) { ps[i] = PolicyInformation.getInstance(policies.getObjectAt(i)); } - + return ps; } - + /** * The definition of SigningCertificate is *
          @@ -98,12 +98,12 @@ public ASN1Primitive toASN1Primitive()
                   ASN1EncodableVector v = new ASN1EncodableVector(2);
           
                   v.add(certs);
          -        
          +
                   if (policies != null)
                   {
                       v.add(policies);
                   }
          -        
          +
                   return new DERSequence(v);
               }
           }
          diff --git a/util/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
          index 5bfdbab891..79ecd27f3e 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
          @@ -10,51 +10,101 @@ public interface IANAObjectIdentifiers
           {
           
               /** { iso(1) identifier-organization(3) dod(6) internet(1) } == IETF defined things */
          -    static final ASN1ObjectIdentifier   internet       = new ASN1ObjectIdentifier("1.3.6.1");
          +    ASN1ObjectIdentifier   internet       = new ASN1ObjectIdentifier("1.3.6.1");
               /** 1.3.6.1.1: Internet directory: X.500 */
          -    static final ASN1ObjectIdentifier   directory      = internet.branch("1");
          +    ASN1ObjectIdentifier   directory      = internet.branch("1");
               /** 1.3.6.1.2: Internet management */
          -    static final ASN1ObjectIdentifier   mgmt           = internet.branch("2");
          +    ASN1ObjectIdentifier   mgmt           = internet.branch("2");
               /** 1.3.6.1.3: */
          -    static final ASN1ObjectIdentifier   experimental   = internet.branch("3");
          +    ASN1ObjectIdentifier   experimental   = internet.branch("3");
               /** 1.3.6.1.4: */
          -    static final ASN1ObjectIdentifier   _private       = internet.branch("4");
          +    ASN1ObjectIdentifier   _private       = internet.branch("4");
               /** 1.3.6.1.5: Security services */
          -    static final ASN1ObjectIdentifier   security       = internet.branch("5");
          +    ASN1ObjectIdentifier   security       = internet.branch("5");
               /** 1.3.6.1.6: SNMPv2 -- never really used */
          -    static final ASN1ObjectIdentifier   SNMPv2         = internet.branch("6");
          +    ASN1ObjectIdentifier   SNMPv2         = internet.branch("6");
               /** 1.3.6.1.7: mail -- never really used */
          -    static final ASN1ObjectIdentifier   mail           = internet.branch("7");
          +    ASN1ObjectIdentifier   mail           = internet.branch("7");
           
           
          -    // id-SHA1 OBJECT IDENTIFIER ::=    
          +    // id-SHA1 OBJECT IDENTIFIER ::=
               // {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)}
               //
           
           
               /** IANA security mechanisms; 1.3.6.1.5.5 */
          -    static final ASN1ObjectIdentifier    security_mechanisms  = security.branch("5");
          +    ASN1ObjectIdentifier    security_mechanisms  = security.branch("5");
               /** IANA security nametypes;  1.3.6.1.5.6 */
          -    static final ASN1ObjectIdentifier    security_nametypes   = security.branch("6");
          +    ASN1ObjectIdentifier    security_nametypes   = security.branch("6");
           
          -    /** PKIX base OID:            1.3.6.1.5.6.6 */
          -    static final ASN1ObjectIdentifier    pkix                 = security_mechanisms.branch("6");
          +    /** PKIX base OID:            1.3.6.1.5.5.7 */
          +    ASN1ObjectIdentifier    pkix                 = security_mechanisms.branch("7");
           
           
               /** IPSEC base OID:                        1.3.6.1.5.5.8 */
          -    static final ASN1ObjectIdentifier    ipsec                = security_mechanisms.branch("8");
          +    ASN1ObjectIdentifier    ipsec                = security_mechanisms.branch("8");
               /** IPSEC ISAKMP-Oakley OID:               1.3.6.1.5.5.8.1 */
          -    static final ASN1ObjectIdentifier    isakmpOakley         = ipsec.branch("1");
          +    ASN1ObjectIdentifier    isakmpOakley         = ipsec.branch("1");
           
               /** IPSEC ISAKMP-Oakley hmacMD5 OID:       1.3.6.1.5.5.8.1.1 */
          -    static final ASN1ObjectIdentifier    hmacMD5              = isakmpOakley.branch("1");
          +    ASN1ObjectIdentifier    hmacMD5              = isakmpOakley.branch("1");
               /** IPSEC ISAKMP-Oakley hmacSHA1 OID:      1.3.6.1.5.5.8.1.2 */
          -    static final ASN1ObjectIdentifier    hmacSHA1             = isakmpOakley.branch("2");
          -    
          +    ASN1ObjectIdentifier    hmacSHA1             = isakmpOakley.branch("2");
          +
               /** IPSEC ISAKMP-Oakley hmacTIGER OID:     1.3.6.1.5.5.8.1.3 */
          -    static final ASN1ObjectIdentifier    hmacTIGER            = isakmpOakley.branch("3");
          -    
          +    ASN1ObjectIdentifier    hmacTIGER            = isakmpOakley.branch("3");
          +
               /** IPSEC ISAKMP-Oakley hmacRIPEMD160 OID: 1.3.6.1.5.5.8.1.4 */
          -    static final ASN1ObjectIdentifier    hmacRIPEMD160        = isakmpOakley.branch("4");
          +    ASN1ObjectIdentifier    hmacRIPEMD160        = isakmpOakley.branch("4");
          +
          +    /** 1.3.6.1.5.5.7.6 */
          +    ASN1ObjectIdentifier id_alg  = internet.branch("5.5.7.6");
          +
          +    ASN1ObjectIdentifier id_RSASSA_PSS_SHAKE128 = id_alg.branch("30");
          +
          +    ASN1ObjectIdentifier id_RSASSA_PSS_SHAKE256 = id_alg.branch("31");
          +
          +    ASN1ObjectIdentifier id_ecdsa_with_shake128 = id_alg.branch("32");
          +
          +    ASN1ObjectIdentifier id_ecdsa_with_shake256 = id_alg.branch("33");
          +
          +    ASN1ObjectIdentifier id_alg_unsigned = id_alg.branch("36");
          +
          +    /** 1.3.6.1.5.5.7.6.37 id-MLDSA44-RSA2048-PSS-SHA256 */
          +    ASN1ObjectIdentifier id_MLDSA44_RSA2048_PSS_SHA256 = id_alg.branch("37");
          +    /** 1.3.6.1.5.5.7.6.38 id-MLDSA44-RSA2048-PKCS15-SHA256 */
          +    ASN1ObjectIdentifier id_MLDSA44_RSA2048_PKCS15_SHA256 = id_alg.branch("38");
          +    /** 1.3.6.1.5.5.7.6.39 id-MLDSA44-Ed25519-SHA512 */
          +    ASN1ObjectIdentifier id_MLDSA44_Ed25519_SHA512 = id_alg.branch("39");
          +    /** 1.3.6.1.5.5.7.6.40 id-MLDSA44-ECDSA-P256-SHA256 */
          +    ASN1ObjectIdentifier id_MLDSA44_ECDSA_P256_SHA256 = id_alg.branch("40");
          +    /** 1.3.6.1.5.5.7.6.41 id-MLDSA65-RSA3072-PSS-SHA512 */
          +    ASN1ObjectIdentifier id_MLDSA65_RSA3072_PSS_SHA512 = id_alg.branch("41");
          +    /** 1.3.6.1.5.5.7.6.42 id-MLDSA65-RSA3072-PKCS15-SHA512 */
          +    ASN1ObjectIdentifier id_MLDSA65_RSA3072_PKCS15_SHA512 = id_alg.branch("42");
          +    /** 1.3.6.1.5.5.7.6.43 id-MLDSA65-RSA4096-PSS-SHA512 */
          +    ASN1ObjectIdentifier id_MLDSA65_RSA4096_PSS_SHA512 = id_alg.branch("43");
          +    /** 1.3.6.1.5.5.7.6.44 id-MLDSA65-RSA4096-PKCS15-SHA512 */
          +    ASN1ObjectIdentifier id_MLDSA65_RSA4096_PKCS15_SHA512 = id_alg.branch("44");
          +    /** 1.3.6.1.5.5.7.6.45 id-MLDSA65-ECDSA-P256-SHA512 */
          +    ASN1ObjectIdentifier id_MLDSA65_ECDSA_P256_SHA512 = id_alg.branch("45");
          +    /** 1.3.6.1.5.5.7.6.46 id-MLDSA65-ECDSA-P384-SHA512 */
          +    ASN1ObjectIdentifier id_MLDSA65_ECDSA_P384_SHA512 = id_alg.branch("46");
          +    /** 1.3.6.1.5.5.7.6.47 id-MLDSA65-ECDSA-brainpoolP256r1-SHA512 */
          +    ASN1ObjectIdentifier id_MLDSA65_ECDSA_brainpoolP256r1_SHA512 = id_alg.branch("47");
          +    /** 1.3.6.1.5.5.7.6.48 id-MLDSA65-Ed25519-SHA512 */
          +    ASN1ObjectIdentifier id_MLDSA65_Ed25519_SHA512 = id_alg.branch("48");
          +    /** 1.3.6.1.5.5.7.6.49 id-MLDSA87-ECDSA-P384-SHA512 */
          +    ASN1ObjectIdentifier id_MLDSA87_ECDSA_P384_SHA512 = id_alg.branch("49");
          +    /** 1.3.6.1.5.5.7.6.50 id-MLDSA87-ECDSA-brainpoolP384r1-SHA512 */
          +    ASN1ObjectIdentifier id_MLDSA87_ECDSA_brainpoolP384r1_SHA512 = id_alg.branch("50");
          +    /** 1.3.6.1.5.5.7.6.51 id-MLDSA87-Ed448-SHAKE256 */
          +    ASN1ObjectIdentifier id_MLDSA87_Ed448_SHAKE256 = id_alg.branch("51");
          +    /** 1.3.6.1.5.5.7.6.52 id-MLDSA87-RSA3072-PSS-SHA512 */
          +    ASN1ObjectIdentifier id_MLDSA87_RSA3072_PSS_SHA512 = id_alg.branch("52");
          +    /** 1.3.6.1.5.5.7.6.53 id-MLDSA87-RSA4096-PSS-SHA512 */
          +    ASN1ObjectIdentifier id_MLDSA87_RSA4096_PSS_SHA512 = id_alg.branch("53");
          +    /** 1.3.6.1.5.5.7.6.54 id-MLDSA87-ECDSA-P521-SHA512 */
          +    ASN1ObjectIdentifier id_MLDSA87_ECDSA_P521_SHA512 = id_alg.branch("54");
           
           }
          diff --git a/util/src/main/java/org/bouncycastle/asn1/icao/CscaMasterList.java b/util/src/main/java/org/bouncycastle/asn1/icao/CscaMasterList.java
          index 50f8351f36..636992e875 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/icao/CscaMasterList.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/icao/CscaMasterList.java
          @@ -25,7 +25,7 @@
           public class CscaMasterList
               extends ASN1Object
           {
          -    private ASN1Integer version = new ASN1Integer(0);
          +    private ASN1Integer version = ASN1Integer.ZERO;
               private Certificate[] certList;
           
               public static CscaMasterList getInstance(
          diff --git a/util/src/main/java/org/bouncycastle/asn1/icao/DataGroupHash.java b/util/src/main/java/org/bouncycastle/asn1/icao/DataGroupHash.java
          index ae86174364..64a4e9feaa 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/icao/DataGroupHash.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/icao/DataGroupHash.java
          @@ -15,7 +15,7 @@
            * DataGroupHash  ::=  SEQUENCE {
            *      dataGroupNumber         DataGroupNumber,
            *      dataGroupHashValue     OCTET STRING }
          - * 
          + *
            * DataGroupNumber ::= INTEGER {
            *         dataGroup1    (1),
            *         dataGroup1    (2),
          @@ -33,15 +33,15 @@
            *         dataGroup1    (14),
            *         dataGroup1    (15),
            *         dataGroup1    (16) }
          - * 
          + *
            * 
          */ -public class DataGroupHash +public class DataGroupHash extends ASN1Object { - ASN1Integer dataGroupNumber; + ASN1Integer dataGroupNumber; ASN1OctetString dataGroupHashValue; - + public static DataGroupHash getInstance( Object obj) { @@ -55,8 +55,8 @@ else if (obj != null) } return null; - } - + } + private DataGroupHash(ASN1Sequence seq) { Enumeration e = seq.getObjects(); @@ -64,27 +64,27 @@ private DataGroupHash(ASN1Sequence seq) // dataGroupNumber dataGroupNumber = ASN1Integer.getInstance(e.nextElement()); // dataGroupHashValue - dataGroupHashValue = ASN1OctetString.getInstance(e.nextElement()); + dataGroupHashValue = ASN1OctetString.getInstance(e.nextElement()); } - + public DataGroupHash( - int dataGroupNumber, + int dataGroupNumber, ASN1OctetString dataGroupHashValue) { - this.dataGroupNumber = new ASN1Integer(dataGroupNumber); - this.dataGroupHashValue = dataGroupHashValue; - } + this.dataGroupNumber = ASN1Integer.valueOf(dataGroupNumber); + this.dataGroupHashValue = dataGroupHashValue; + } public int getDataGroupNumber() { return dataGroupNumber.intValueExact(); } - + public ASN1OctetString getDataGroupHashValue() { return dataGroupHashValue; - } - + } + public ASN1Primitive toASN1Primitive() { return new DERSequence(dataGroupNumber, dataGroupHashValue); diff --git a/util/src/main/java/org/bouncycastle/asn1/icao/LDSSecurityObject.java b/util/src/main/java/org/bouncycastle/asn1/icao/LDSSecurityObject.java index 89baf0a430..378229f7d7 100644 --- a/util/src/main/java/org/bouncycastle/asn1/icao/LDSSecurityObject.java +++ b/util/src/main/java/org/bouncycastle/asn1/icao/LDSSecurityObject.java @@ -31,7 +31,7 @@ public class LDSSecurityObject { public static final int ub_DataGroups = 16; - private ASN1Integer version = new ASN1Integer(0); + private ASN1Integer version = ASN1Integer.ZERO; private AlgorithmIdentifier digestAlgorithmIdentifier; private DataGroupHash[] datagroupHash; private LDSVersionInfo versionInfo; @@ -86,7 +86,7 @@ public LDSSecurityObject( AlgorithmIdentifier digestAlgorithmIdentifier, DataGroupHash[] datagroupHash) { - this.version = new ASN1Integer(0); + this.version = ASN1Integer.ZERO; this.digestAlgorithmIdentifier = digestAlgorithmIdentifier; this.datagroupHash = copy(datagroupHash); @@ -98,7 +98,7 @@ public LDSSecurityObject( DataGroupHash[] datagroupHash, LDSVersionInfo versionInfo) { - this.version = new ASN1Integer(1); + this.version = ASN1Integer.ONE; this.digestAlgorithmIdentifier = digestAlgorithmIdentifier; this.datagroupHash = copy(datagroupHash); this.versionInfo = versionInfo; diff --git a/util/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java index 6b75fde631..d9369734d2 100644 --- a/util/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java +++ b/util/src/main/java/org/bouncycastle/asn1/isismtt/ISISMTTObjectIdentifiers.java @@ -103,7 +103,7 @@ public interface ISISMTTObjectIdentifiers *
          *

          * OID: 1.3.36.8.3.8 - * + * * @see org.bouncycastle.asn1.isismtt.x509.Restriction */ static final ASN1ObjectIdentifier id_isismtt_at_restriction = id_isismtt_at.branch("8"); @@ -129,7 +129,7 @@ public interface ISISMTTObjectIdentifiers * returned in this extension. *

          * OID: 1.3.36.8.3.10 - * + * * @see org.bouncycastle.asn1.isismtt.ocsp.RequestedCertificate */ static final ASN1ObjectIdentifier id_isismtt_at_requestedCertificate = id_isismtt_at.branch("10"); @@ -146,7 +146,7 @@ public interface ISISMTTObjectIdentifiers * in the directory and status information has become available. Currently, * accrediting authorities enforce that SigG-conforming OCSP servers include * this extension in the responses. - * + * *

                *    CertInDirSince ::= GeneralizedTime
                * 
          @@ -159,7 +159,7 @@ public interface ISISMTTObjectIdentifiers * Hash of a certificate in OCSP. *

          * OID: 1.3.36.8.3.13 - * + * * @see org.bouncycastle.asn1.isismtt.ocsp.CertHash */ static final ASN1ObjectIdentifier id_isismtt_at_certHash = id_isismtt_at.branch("13"); @@ -168,7 +168,7 @@ public interface ISISMTTObjectIdentifiers *

                *    NameAtBirth ::= DirectoryString(SIZE(1..64)
                * 
          - * + * * Used in * {@link org.bouncycastle.asn1.x509.SubjectDirectoryAttributes SubjectDirectoryAttributes} *

          @@ -180,13 +180,13 @@ public interface ISISMTTObjectIdentifiers * Some other information of non-restrictive nature regarding the usage of * this certificate. May be used as attribute in atribute certificate or as * extension in a certificate. - * + * *

                *    AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
                * 
          *

          * OID: 1.3.36.8.3.15 - * + * * @see org.bouncycastle.asn1.isismtt.x509.AdditionalInformationSyntax */ static final ASN1ObjectIdentifier id_isismtt_at_additionalInformation = id_isismtt_at.branch("15"); diff --git a/util/src/main/java/org/bouncycastle/asn1/isismtt/ocsp/RequestedCertificate.java b/util/src/main/java/org/bouncycastle/asn1/isismtt/ocsp/RequestedCertificate.java index 9237e9833e..b50981675e 100644 --- a/util/src/main/java/org/bouncycastle/asn1/isismtt/ocsp/RequestedCertificate.java +++ b/util/src/main/java/org/bouncycastle/asn1/isismtt/ocsp/RequestedCertificate.java @@ -152,7 +152,7 @@ public byte[] getCertificateBytes() } return Arrays.clone(attributeCert); } - + /** * Produce an object suitable for an ASN1OutputStream. *

          diff --git a/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/AdditionalInformationSyntax.java b/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/AdditionalInformationSyntax.java index 454100a716..243253a35f 100644 --- a/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/AdditionalInformationSyntax.java +++ b/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/AdditionalInformationSyntax.java @@ -7,7 +7,7 @@ /** * Some other information of non-restrictive nature regarding the usage of this * certificate. - * + * *

            *    AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
            * 
          diff --git a/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/Admissions.java b/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/Admissions.java index 3536638161..6099620de9 100644 --- a/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/Admissions.java +++ b/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/Admissions.java @@ -27,7 +27,7 @@ * @see org.bouncycastle.asn1.isismtt.x509.ProfessionInfo * @see org.bouncycastle.asn1.isismtt.x509.NamingAuthority */ -public class Admissions +public class Admissions extends ASN1Object { @@ -168,7 +168,7 @@ public ProfessionInfo[] getProfessionInfos() public ASN1Primitive toASN1Primitive() { ASN1EncodableVector vec = new ASN1EncodableVector(3); - + if (admissionAuthority != null) { vec.add(new DERTaggedObject(true, 0, admissionAuthority)); diff --git a/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/DeclarationOfMajority.java b/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/DeclarationOfMajority.java index f7eca1511b..a609f36398 100644 --- a/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/DeclarationOfMajority.java +++ b/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/DeclarationOfMajority.java @@ -8,7 +8,6 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERPrintableString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; @@ -44,7 +43,7 @@ public class DeclarationOfMajority public DeclarationOfMajority(int notYoungerThan) { - declaration = new DERTaggedObject(false, 0, new ASN1Integer(notYoungerThan)); + declaration = new DERTaggedObject(false, 0, ASN1Integer.valueOf(notYoungerThan)); } public DeclarationOfMajority(boolean fullAge, String country) @@ -80,7 +79,7 @@ public static DeclarationOfMajority getInstance(Object obj) if (obj instanceof ASN1TaggedObject) { - return new DeclarationOfMajority(ASN1TaggedObject.getInstance(obj, BERTags.CONTEXT_SPECIFIC)); + return new DeclarationOfMajority(ASN1TaggedObject.getContextInstance(obj)); } throw new IllegalArgumentException("illegal object in getInstance: " diff --git a/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/MonetaryLimit.java b/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/MonetaryLimit.java index fd8529d119..a537c940d5 100644 --- a/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/MonetaryLimit.java +++ b/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/MonetaryLimit.java @@ -82,8 +82,8 @@ private MonetaryLimit(ASN1Sequence seq) public MonetaryLimit(String currency, int amount, int exponent) { this.currency = new DERPrintableString(currency, true); - this.amount = new ASN1Integer(amount); - this.exponent = new ASN1Integer(exponent); + this.amount = ASN1Integer.valueOf(amount); + this.exponent = ASN1Integer.valueOf(exponent); } public String getCurrency() diff --git a/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/NamingAuthority.java b/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/NamingAuthority.java index 470897738d..fa49b8454d 100644 --- a/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/NamingAuthority.java +++ b/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/NamingAuthority.java @@ -19,9 +19,9 @@ /** * Names of authorities which are responsible for the administration of title * registers. - * + * *
          - *             NamingAuthority ::= SEQUENCE 
          + *             NamingAuthority ::= SEQUENCE
            *             {
            *               namingAuthorityId OBJECT IDENTIFIER OPTIONAL,
            *               namingAuthorityUrl IA5String OPTIONAL,
          @@ -29,7 +29,7 @@
            *             }
            * 
          * @see org.bouncycastle.asn1.isismtt.x509.AdmissionSyntax - * + * */ public class NamingAuthority extends ASN1Object diff --git a/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/ProcurationSyntax.java b/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/ProcurationSyntax.java index 88d809e5aa..564833274e 100644 --- a/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/ProcurationSyntax.java +++ b/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/ProcurationSyntax.java @@ -9,7 +9,6 @@ import org.bouncycastle.asn1.ASN1PrintableString; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERPrintableString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; @@ -34,21 +33,21 @@ * stateOrProvincename, localityName, postalAddress) and - SubjectDirectoryName * attributes (title, dateOfBirth, placeOfBirth, gender, countryOfCitizenship, * countryOfResidence and NameAtBirth). - * + * *
            *               ProcurationSyntax ::= SEQUENCE {
            *                 country [1] EXPLICIT PrintableString(SIZE(2)) OPTIONAL,
            *                 typeOfSubstitution [2] EXPLICIT DirectoryString (SIZE(1..128)) OPTIONAL,
          - *                 signingFor [3] EXPLICIT SigningFor 
          + *                 signingFor [3] EXPLICIT SigningFor
            *               }
          - *               
          - *               SigningFor ::= CHOICE 
          - *               { 
          + *
          + *               SigningFor ::= CHOICE
          + *               {
            *                 thirdPerson GeneralName,
          - *                 certRef IssuerSerial 
          + *                 certRef IssuerSerial
            *               }
            * 
          - * + * */ public class ProcurationSyntax extends ASN1Object @@ -105,7 +104,7 @@ private ProcurationSyntax(ASN1Sequence seq) while (e.hasMoreElements()) { - ASN1TaggedObject o = ASN1TaggedObject.getInstance(e.nextElement(), BERTags.CONTEXT_SPECIFIC); + ASN1TaggedObject o = ASN1TaggedObject.getContextInstance(e.nextElement()); switch (o.getTagNo()) { case 1: diff --git a/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/ProfessionInfo.java b/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/ProfessionInfo.java index b987c5f4f2..811e60533c 100644 --- a/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/ProfessionInfo.java +++ b/util/src/main/java/org/bouncycastle/asn1/isismtt/x509/ProfessionInfo.java @@ -19,21 +19,21 @@ /** * Professions, specializations, disciplines, fields of activity, etc. - * + * *
          - *               ProfessionInfo ::= SEQUENCE 
          + *               ProfessionInfo ::= SEQUENCE
            *               {
            *                 namingAuthority [0] EXPLICIT NamingAuthority OPTIONAL,
            *                 professionItems SEQUENCE OF DirectoryString (SIZE(1..128)),
            *                 professionOIDs SEQUENCE OF OBJECT IDENTIFIER OPTIONAL,
            *                 registrationNumber PrintableString(SIZE(1..128)) OPTIONAL,
          - *                 addProfessionInfo OCTET STRING OPTIONAL 
          + *                 addProfessionInfo OCTET STRING OPTIONAL
            *               }
            * 
          - * + * * @see org.bouncycastle.asn1.isismtt.x509.AdmissionSyntax */ -public class ProfessionInfo +public class ProfessionInfo extends ASN1Object { diff --git a/util/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java index a4611333f0..1cdb668bba 100644 --- a/util/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java +++ b/util/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java @@ -25,7 +25,4 @@ public interface KISAObjectIdentifiers /** RFC 4010: id-npki-app-cmsSeed-wrap; OID 1.2.410.200004.7.1.1.1 */ static final ASN1ObjectIdentifier id_npki_app_cmsSeed_wrap = new ASN1ObjectIdentifier("1.2.410.200004.7.1.1.1"); - - /** RFC 4010: SeedEncryptionAlgorithmInCMS; OID 1.2.840.113549.1.9.16.0.24 */ - static final ASN1ObjectIdentifier id_mod_cms_seed = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.0.24"); } diff --git a/util/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java b/util/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java index 1137eda46e..62caf1a568 100644 --- a/util/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java +++ b/util/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java @@ -35,7 +35,7 @@ public CAST5CBCParameters( int keyLength) { this.iv = new DEROctetString(Arrays.clone(iv)); - this.keyLength = new ASN1Integer(keyLength); + this.keyLength = ASN1Integer.valueOf(keyLength); } private CAST5CBCParameters( diff --git a/util/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java index 5dc5517b54..89242d416d 100644 --- a/util/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java +++ b/util/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java @@ -162,7 +162,7 @@ public interface MiscObjectIdentifiers // Algorithm(80) Composite(4) CompositeKey(1) ASN1ObjectIdentifier id_composite_key = new ASN1ObjectIdentifier("2.16.840.1.114027.80.4.1"); - ASN1ObjectIdentifier id_oracle_pkcs12_trusted_key_usage = new ASN1ObjectIdentifier("2.16.840.1.113894.746875.1.1"); + ASN1ObjectIdentifier id_oracle_PKCS12_trusted_key_usage = new ASN1ObjectIdentifier("2.16.840.1.113894.746875.1.1"); // COMPOSITE SIGNATURES START @@ -170,17 +170,12 @@ public interface MiscObjectIdentifiers // Composite signature related OIDs. Based https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html // The current OIDs are EXPERIMENTAL and are going to change. ASN1ObjectIdentifier id_composite_signatures = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1"); - ASN1ObjectIdentifier id_MLDSA44_RSA2048_PSS_SHA256 = id_composite_signatures.branch("21"); - ASN1ObjectIdentifier id_MLDSA44_RSA2048_PKCS15_SHA256 = id_composite_signatures.branch("22"); - ASN1ObjectIdentifier id_MLDSA44_Ed25519_SHA512 = id_composite_signatures.branch("23"); - ASN1ObjectIdentifier id_MLDSA44_ECDSA_P256_SHA256 = id_composite_signatures.branch("24"); ASN1ObjectIdentifier id_MLDSA65_RSA3072_PSS_SHA256 = id_composite_signatures.branch("26"); ASN1ObjectIdentifier id_MLDSA65_RSA3072_PKCS15_SHA256 = id_composite_signatures.branch("27"); ASN1ObjectIdentifier id_MLDSA65_RSA4096_PSS_SHA384 = id_composite_signatures.branch("34"); ASN1ObjectIdentifier id_MLDSA65_RSA4096_PKCS15_SHA384 = id_composite_signatures.branch("35"); ASN1ObjectIdentifier id_MLDSA65_ECDSA_P384_SHA384 = id_composite_signatures.branch("28"); ASN1ObjectIdentifier id_MLDSA65_ECDSA_brainpoolP256r1_SHA256 = id_composite_signatures.branch("29"); - ASN1ObjectIdentifier id_MLDSA65_Ed25519_SHA512 = id_composite_signatures.branch("30"); ASN1ObjectIdentifier id_MLDSA87_ECDSA_P384_SHA384 = id_composite_signatures.branch("31"); ASN1ObjectIdentifier id_MLDSA87_ECDSA_brainpoolP384r1_SHA384 = id_composite_signatures.branch("32"); ASN1ObjectIdentifier id_MLDSA87_Ed448_SHA512 = id_composite_signatures.branch("33"); @@ -199,5 +194,43 @@ public interface MiscObjectIdentifiers ASN1ObjectIdentifier id_HashMLDSA87_ECDSA_P384_SHA512 = id_composite_signatures.branch("51"); ASN1ObjectIdentifier id_HashMLDSA87_ECDSA_brainpoolP384r1_SHA512 = id_composite_signatures.branch("52"); ASN1ObjectIdentifier id_HashMLDSA87_Ed448_SHA512 = id_composite_signatures.branch("53"); + + ASN1ObjectIdentifier id_MLDSA_COMPSIG = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1"); + /** 2.16.840.1.114027.80.9.1.0 id-MLDSA44-RSA2048-PSS-SHA256 */ + ASN1ObjectIdentifier id_MLDSA44_RSA2048_PSS_SHA256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.0"); + /** 2.16.840.1.114027.80.9.1.1 id-MLDSA44-RSA2048-PKCS15-SHA256 */ + ASN1ObjectIdentifier id_MLDSA44_RSA2048_PKCS15_SHA256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.1"); + /** 2.16.840.1.114027.80.9.1.2 id-MLDSA44-Ed25519-SHA512 */ + ASN1ObjectIdentifier id_MLDSA44_Ed25519_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.2"); + /** 2.16.840.1.114027.80.9.1.3 id-MLDSA44-ECDSA-P256-SHA256 */ + ASN1ObjectIdentifier id_MLDSA44_ECDSA_P256_SHA256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.3"); + /** 2.16.840.1.114027.80.9.1.4 id-MLDSA65-RSA3072-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA3072_PSS_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.4"); + /** 2.16.840.1.114027.80.9.1.5 id-MLDSA65-RSA3072-PKCS15-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA3072_PKCS15_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.5"); + /** 2.16.840.1.114027.80.9.1.6 id-MLDSA65-RSA4096-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA4096_PSS_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.6"); + /** 2.16.840.1.114027.80.9.1.7 id-MLDSA65-RSA4096-PKCS15-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_RSA4096_PKCS15_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.7"); + /** 2.16.840.1.114027.80.9.1.8 id-MLDSA65-ECDSA-P256-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_ECDSA_P256_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.8"); + /** 2.16.840.1.114027.80.9.1.9 id-MLDSA65-ECDSA-P384-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_ECDSA_P384_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.9"); + /** 2.16.840.1.114027.80.9.1.10 id-MLDSA65-ECDSA-brainpoolP256r1-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_ECDSA_brainpoolP256r1_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.10"); + /** 2.16.840.1.114027.80.9.1.11 id-MLDSA65-Ed25519-SHA512 */ + ASN1ObjectIdentifier id_MLDSA65_Ed25519_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.11"); + /** 2.16.840.1.114027.80.9.1.12 id-MLDSA87-ECDSA-P384-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_ECDSA_P384_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.12"); + /** 2.16.840.1.114027.80.9.1.13 id-MLDSA87-ECDSA-brainpoolP384r1-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_ECDSA_brainpoolP384r1_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.13"); + /** 2.16.840.1.114027.80.9.1.14 id-MLDSA87-Ed448-SHAKE256 */ + ASN1ObjectIdentifier id_MLDSA87_Ed448_SHAKE256 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.14"); + /** 2.16.840.1.114027.80.9.1.15 id-MLDSA87-RSA3072-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_RSA3072_PSS_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.15"); + /** 2.16.840.1.114027.80.9.1.16 id-MLDSA87-RSA4096-PSS-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_RSA4096_PSS_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.16"); + /** 2.16.840.1.114027.80.9.1.17 id-MLDSA87-ECDSA-P521-SHA512 */ + ASN1ObjectIdentifier id_MLDSA87_ECDSA_P521_SHA512 = new ASN1ObjectIdentifier("2.16.840.1.114027.80.9.1.17"); // COMPOSITE SIGNATURES END } diff --git a/util/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java b/util/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java index 761b4c4aae..ed9f4a8023 100644 --- a/util/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java +++ b/util/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java @@ -20,7 +20,7 @@ public class NetscapeCertType extends DERBitString { - public static final int sslClient = (1 << 7); + public static final int sslClient = (1 << 7); public static final int sslServer = (1 << 6); public static final int smime = (1 << 5); public static final int objectSigning = (1 << 4); @@ -31,7 +31,7 @@ public class NetscapeCertType /** * Basic constructor. - * + * * @param usage - the bitwise OR of the Key Usage flags giving the * allowed uses for the key. * e.g. (X509NetscapeCertType.sslCA | X509NetscapeCertType.smimeCA) diff --git a/util/src/main/java/org/bouncycastle/asn1/misc/ScryptParams.java b/util/src/main/java/org/bouncycastle/asn1/misc/ScryptParams.java index 6b11b7bcb5..42062029d3 100644 --- a/util/src/main/java/org/bouncycastle/asn1/misc/ScryptParams.java +++ b/util/src/main/java/org/bouncycastle/asn1/misc/ScryptParams.java @@ -43,7 +43,7 @@ public ScryptParams(byte[] salt, int costParameter, int blockSize, int paralleli { this(salt, BigInteger.valueOf(costParameter), BigInteger.valueOf(blockSize), BigInteger.valueOf(parallelizationParameter), BigInteger.valueOf(keyLength)); } - + /** * Base constructor. * diff --git a/util/src/main/java/org/bouncycastle/asn1/mod/ModObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/mod/ModObjectIdentifiers.java new file mode 100644 index 0000000000..0b58e1528f --- /dev/null +++ b/util/src/main/java/org/bouncycastle/asn1/mod/ModObjectIdentifiers.java @@ -0,0 +1,22 @@ +package org.bouncycastle.asn1.mod; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public interface ModObjectIdentifiers +{ + //TODO: add more from RFC 6268, RFC 5911 + + // id_mod OBJECT IDENTIFIER ::= { iso(1) identified_organization(3) + // dod(6) internet(1) security(5) mechanisms(5) pkix(7) mod(0) } + ASN1ObjectIdentifier id_mod = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.0"); + + /** + * PUBLIC-KEY, SIGNATURE-ALGORITHM, SMIME-CAPS + * FROM AlgorithmInformation-2009 -- RFC 5911 [CMSASN1] + * { iso(1) identified-organization(3) dod(6) internet(1) + * security(5) mechanisms(5) pkix(7) id-mod(0) + * id-mod-algorithmInformation-02(58) } ; + * 1.3.6.1.5.5.7.0.58 + */ + ASN1ObjectIdentifier id_mod_algorithmInformation_02 = id_mod.branch("58"); +} diff --git a/util/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java index c169c1692d..7b6c3ce86e 100644 --- a/util/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java +++ b/util/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java @@ -5,7 +5,7 @@ /** * OIW organization's OIDs: *

          - * id-SHA1 OBJECT IDENTIFIER ::= + * id-SHA1 OBJECT IDENTIFIER ::= * {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } */ public interface OIWObjectIdentifiers @@ -16,7 +16,7 @@ public interface OIWObjectIdentifiers static final ASN1ObjectIdentifier md5WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.3"); /** OID: 1.3.14.3.2.4 */ static final ASN1ObjectIdentifier md4WithRSAEncryption = new ASN1ObjectIdentifier("1.3.14.3.2.4"); - + /** OID: 1.3.14.3.2.6 */ static final ASN1ObjectIdentifier desECB = new ASN1ObjectIdentifier("1.3.14.3.2.6"); /** OID: 1.3.14.3.2.7 */ @@ -28,7 +28,7 @@ public interface OIWObjectIdentifiers /** OID: 1.3.14.3.2.17 */ static final ASN1ObjectIdentifier desEDE = new ASN1ObjectIdentifier("1.3.14.3.2.17"); - + /** OID: 1.3.14.3.2.26 */ static final ASN1ObjectIdentifier idSHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.26"); @@ -37,10 +37,10 @@ public interface OIWObjectIdentifiers /** OID: 1.3.14.3.2.29 */ static final ASN1ObjectIdentifier sha1WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.29"); - + /** *

          -     * ElGamal Algorithm OBJECT IDENTIFIER ::=    
          +     * ElGamal Algorithm OBJECT IDENTIFIER ::=
                *   {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 }
                * 
          * OID: 1.3.14.7.2.1.1 diff --git a/util/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilities.java b/util/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilities.java index 9c7fba4718..aaa28fe67e 100644 --- a/util/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilities.java +++ b/util/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilities.java @@ -35,7 +35,7 @@ public class SMIMECapabilities public static final ASN1ObjectIdentifier dES_CBC = new ASN1ObjectIdentifier("1.3.14.3.2.7"); public static final ASN1ObjectIdentifier dES_EDE3_CBC = PKCSObjectIdentifiers.des_EDE3_CBC; public static final ASN1ObjectIdentifier rC2_CBC = PKCSObjectIdentifiers.RC2_CBC; - + private ASN1Sequence capabilities; /** @@ -51,7 +51,7 @@ public static SMIMECapabilities getInstance( { return (SMIMECapabilities)o; } - + if (o instanceof ASN1Sequence) { return new SMIMECapabilities((ASN1Sequence)o); @@ -65,7 +65,7 @@ public static SMIMECapabilities getInstance( throw new IllegalArgumentException("unknown object in factory: " + o.getClass().getName()); } - + public SMIMECapabilities( ASN1Sequence seq) { @@ -108,7 +108,7 @@ public Vector getCapabilities( return list; } - /** + /** * Produce an object suitable for an ASN1OutputStream. *
                * SMIMECapabilities ::= SEQUENCE OF SMIMECapability
          diff --git a/util/src/main/java/org/bouncycastle/asn1/smime/SMIMECapability.java b/util/src/main/java/org/bouncycastle/asn1/smime/SMIMECapability.java
          index 0b762af1d4..9df494f9d3 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/smime/SMIMECapability.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/smime/SMIMECapability.java
          @@ -29,7 +29,7 @@ public class SMIMECapability
               public static final ASN1ObjectIdentifier aES128_CBC = NISTObjectIdentifiers.id_aes128_CBC;
               public static final ASN1ObjectIdentifier aES192_CBC = NISTObjectIdentifiers.id_aes192_CBC;
               public static final ASN1ObjectIdentifier aES256_CBC = NISTObjectIdentifiers.id_aes256_CBC;
          -    
          +
               private ASN1ObjectIdentifier capabilityID;
               private ASN1Encodable        parameters;
           
          @@ -51,7 +51,7 @@ public SMIMECapability(
                   this.capabilityID = capabilityID;
                   this.parameters = parameters;
               }
          -    
          +
               public static SMIMECapability getInstance(
                   Object obj)
               {
          @@ -59,14 +59,14 @@ public static SMIMECapability getInstance(
                   {
                       return (SMIMECapability)obj;
                   }
          -        
          +
                   if (obj instanceof ASN1Sequence)
                   {
                       return new SMIMECapability((ASN1Sequence)obj);
                   }
          -        
          +
                   throw new IllegalArgumentException("Invalid SMIMECapability");
          -    } 
          +    }
           
               public ASN1ObjectIdentifier getCapabilityID()
               {
          @@ -80,10 +80,10 @@ public ASN1Encodable getParameters()
           
               /**
                * Produce an object suitable for an ASN1OutputStream.
          -     * 
           
          +     * 
                * SMIMECapability ::= SEQUENCE {
                *     capabilityID OBJECT IDENTIFIER,
          -     *     parameters ANY DEFINED BY capabilityID OPTIONAL 
          +     *     parameters ANY DEFINED BY capabilityID OPTIONAL
                * }
                * 
          */ @@ -92,12 +92,12 @@ public ASN1Primitive toASN1Primitive() ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(capabilityID); - + if (parameters != null) { v.add(parameters); } - + return new DERSequence(v); } } diff --git a/util/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilityVector.java b/util/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilityVector.java index 673a745e4e..b15889c430 100644 --- a/util/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilityVector.java +++ b/util/src/main/java/org/bouncycastle/asn1/smime/SMIMECapabilityVector.java @@ -23,7 +23,7 @@ public void addCapability( ASN1ObjectIdentifier capability, int value) { - capabilities.add(new DERSequence(capability, new ASN1Integer(value))); + capabilities.add(new DERSequence(capability, ASN1Integer.valueOf(value))); } public void addCapability( diff --git a/util/src/main/java/org/bouncycastle/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.java b/util/src/main/java/org/bouncycastle/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.java index 1e5b5396c6..9ff8ae8ff2 100644 --- a/util/src/main/java/org/bouncycastle/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.java +++ b/util/src/main/java/org/bouncycastle/asn1/smime/SMIMEEncryptionKeyPreferenceAttribute.java @@ -26,15 +26,15 @@ public SMIMEEncryptionKeyPreferenceAttribute( super(SMIMEAttributes.encrypKeyPref, new DERSet(new DERTaggedObject(false, 0, issAndSer))); } - + public SMIMEEncryptionKeyPreferenceAttribute( RecipientKeyIdentifier rKeyId) { - super(SMIMEAttributes.encrypKeyPref, + super(SMIMEAttributes.encrypKeyPref, new DERSet(new DERTaggedObject(false, 1, rKeyId))); } - + /** * @param sKeyId the subjectKeyIdentifier value (normally the X.509 one) */ diff --git a/util/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java b/util/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java index 254fa78731..b8db9ef54f 100644 --- a/util/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java +++ b/util/src/main/java/org/bouncycastle/asn1/tsp/Accuracy.java @@ -1,5 +1,6 @@ package org.bouncycastle.asn1.tsp; +import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Object; @@ -9,111 +10,111 @@ import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; - public class Accuracy extends ASN1Object { - ASN1Integer seconds; - - ASN1Integer millis; - - ASN1Integer micros; - - // constantes protected static final int MIN_MILLIS = 1; - protected static final int MAX_MILLIS = 999; - protected static final int MIN_MICROS = 1; - protected static final int MAX_MICROS = 999; - protected Accuracy() - { - } - - public Accuracy( - ASN1Integer seconds, - ASN1Integer millis, - ASN1Integer micros) + public static Accuracy getInstance(Object obj) { - if (null != millis) + if (obj instanceof Accuracy) { - int millisValue = millis.intValueExact(); - if (millisValue < MIN_MILLIS || millisValue > MAX_MILLIS) - { - throw new IllegalArgumentException("Invalid millis field : not in (1..999)"); - } + return (Accuracy)obj; } - if (null != micros) + if (obj != null) { - int microsValue = micros.intValueExact(); - if (microsValue < MIN_MICROS || microsValue > MAX_MICROS) - { - throw new IllegalArgumentException("Invalid micros field : not in (1..999)"); - } + return new Accuracy(ASN1Sequence.getInstance(obj)); } + return null; + } - this.seconds = seconds; - this.millis = millis; - this.micros = micros; + public static Accuracy getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return new Accuracy(ASN1Sequence.getInstance(taggedObject, declaredExplicit)); } - private Accuracy(ASN1Sequence seq) + public static Accuracy getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return new Accuracy(ASN1Sequence.getTagged(taggedObject, declaredExplicit)); + } + + private final ASN1Integer seconds; + private final ASN1Integer millis; + private final ASN1Integer micros; + + /** @deprecated Will be removed */ + protected Accuracy() { seconds = null; millis = null; micros = null; + } + + private Accuracy(ASN1Sequence seq) + { + int count = seq.size(), pos = 0; + if (count < 0 || count > 3) + { + throw new IllegalArgumentException("Bad sequence size: " + count); + } - for (int i = 0; i < seq.size(); i++) + // seconds INTEGER OPTIONAL + ASN1Integer seconds = null; + if (pos < count) { - // seconds - if (seq.getObjectAt(i) instanceof ASN1Integer) + ASN1Encodable element = seq.getObjectAt(pos); + if (element instanceof ASN1Integer) { - seconds = (ASN1Integer) seq.getObjectAt(i); + pos++; + seconds = (ASN1Integer)element; } - else if (seq.getObjectAt(i) instanceof ASN1TaggedObject) + } + this.seconds = seconds; + + // millis [0] INTEGER (1..999) OPTIONAL + ASN1Integer millis = null; + if (pos < count) + { + ASN1TaggedObject tag0 = ASN1TaggedObject.getContextOptional(seq.getObjectAt(pos), 0); + if (tag0 != null) { - ASN1TaggedObject extra = (ASN1TaggedObject)seq.getObjectAt(i); - - switch (extra.getTagNo()) - { - case 0: - millis = ASN1Integer.getInstance(extra, false); - int millisValue = millis.intValueExact(); - if (millisValue < MIN_MILLIS || millisValue > MAX_MILLIS) - { - throw new IllegalArgumentException("Invalid millis field : not in (1..999)"); - } - break; - case 1: - micros = ASN1Integer.getInstance(extra, false); - int microsValue = micros.intValueExact(); - if (microsValue < MIN_MICROS || microsValue > MAX_MICROS) - { - throw new IllegalArgumentException("Invalid micros field : not in (1..999)"); - } - break; - default: - throw new IllegalArgumentException("Invalid tag number"); - } + pos++; + millis = ASN1Integer.getInstance(tag0, false); } } - } + this.millis = millis; - public static Accuracy getInstance(Object o) - { - if (o instanceof Accuracy) + // micros [1] INTEGER (1..999) OPTIONAL + ASN1Integer micros = null; + if (pos < count) { - return (Accuracy) o; + ASN1TaggedObject tag1 = ASN1TaggedObject.getContextOptional(seq.getObjectAt(pos), 1); + if (tag1 != null) + { + pos++; + micros = ASN1Integer.getInstance(tag1, false); + } } + this.micros = micros; - if (o != null) + if (pos != count) { - return new Accuracy(ASN1Sequence.getInstance(o)); + throw new IllegalArgumentException("Unexpected elements in sequence"); } - return null; + validate(); + } + + public Accuracy(ASN1Integer seconds, ASN1Integer millis, ASN1Integer micros) + { + this.seconds = seconds; + this.millis = millis; + this.micros = micros; + + validate(); } public ASN1Integer getSeconds() @@ -143,17 +144,17 @@ public ASN1Integer getMicros() public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(3); - + if (seconds != null) { v.add(seconds); } - + if (millis != null) { v.add(new DERTaggedObject(false, 0, millis)); } - + if (micros != null) { v.add(new DERTaggedObject(false, 1, micros)); @@ -161,4 +162,24 @@ public ASN1Primitive toASN1Primitive() return new DERSequence(v); } + + private void validate() + { + if (millis != null) + { + int millisValue = millis.intValueExact(); + if (millisValue < MIN_MILLIS || millisValue > MAX_MILLIS) + { + throw new IllegalArgumentException("Invalid millis field : not in (1..999)"); + } + } + if (micros != null) + { + int microsValue = micros.intValueExact(); + if (microsValue < MIN_MICROS || microsValue > MAX_MICROS) + { + throw new IllegalArgumentException("Invalid micros field : not in (1..999)"); + } + } + } } diff --git a/util/src/main/java/org/bouncycastle/asn1/tsp/ArchiveTimeStamp.java b/util/src/main/java/org/bouncycastle/asn1/tsp/ArchiveTimeStamp.java index 90e404e266..929553bfb5 100644 --- a/util/src/main/java/org/bouncycastle/asn1/tsp/ArchiveTimeStamp.java +++ b/util/src/main/java/org/bouncycastle/asn1/tsp/ArchiveTimeStamp.java @@ -34,11 +34,6 @@ public class ArchiveTimeStamp extends ASN1Object { - private final AlgorithmIdentifier digestAlgorithm; - private final Attributes attributes; - private final ASN1Sequence reducedHashTree; - private final ContentInfo timeStamp; - /** * Return an ArchiveTimestamp from the given object. * @@ -46,7 +41,7 @@ public class ArchiveTimeStamp * @return an ArchiveTimestamp instance, or null. * @throws IllegalArgumentException if the object cannot be converted. */ - public static ArchiveTimeStamp getInstance(final Object obj) + public static ArchiveTimeStamp getInstance(Object obj) { if (obj instanceof ArchiveTimeStamp) { @@ -60,6 +55,21 @@ else if (obj != null) return null; } + public static ArchiveTimeStamp getInstance(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return new ArchiveTimeStamp(ASN1Sequence.getInstance(taggedObject, declaredExplicit)); + } + + public static ArchiveTimeStamp getTagged(ASN1TaggedObject taggedObject, boolean declaredExplicit) + { + return new ArchiveTimeStamp(ASN1Sequence.getTagged(taggedObject, declaredExplicit)); + } + + private final AlgorithmIdentifier digestAlgorithm; + private final Attributes attributes; + private final ASN1Sequence reducedHashTree; + private final ContentInfo timeStamp; + public ArchiveTimeStamp( AlgorithmIdentifier digestAlgorithm, PartialHashtree[] reducedHashTree, @@ -80,59 +90,71 @@ public ArchiveTimeStamp( PartialHashtree[] reducedHashTree, ContentInfo timeStamp) { - this.digestAlgorithm = digestAlgorithm; - this.attributes = attributes; - if (reducedHashTree != null) - { - this.reducedHashTree = new DERSequence(reducedHashTree); - } - else + if (timeStamp == null) { - this.reducedHashTree = null; + throw new NullPointerException("'timeStamp' cannot be null"); } + + this.digestAlgorithm = digestAlgorithm; + this.attributes = attributes; + this.reducedHashTree = DERSequence.fromElementsOptional(reducedHashTree); this.timeStamp = timeStamp; } - private ArchiveTimeStamp(final ASN1Sequence sequence) + private ArchiveTimeStamp(ASN1Sequence seq) { - if (sequence.size() < 1 || sequence.size() > 4) + int count = seq.size(), pos = 0; + if (count < 1 || count > 4) + { + throw new IllegalArgumentException("Bad sequence size: " + count); + } + + // digestAlgorithm [Ø] AlgorithmIdentifier OPTIONAL + AlgorithmIdentifier digestAlgorithm = null; + if (pos < count) { - throw new IllegalArgumentException("wrong sequence size in constructor: " + sequence.size()); + ASN1TaggedObject tag0 = ASN1TaggedObject.getContextOptional(seq.getObjectAt(pos), 0); + if (tag0 != null) + { + pos++; + digestAlgorithm = AlgorithmIdentifier.getTagged(tag0, false); + } } + this.digestAlgorithm = digestAlgorithm; - AlgorithmIdentifier digAlg = null; - Attributes attrs = null; - ASN1Sequence rHashTree = null; - for (int i = 0; i < sequence.size() - 1; i++) + // attributes [1] Attributes OPTIONAL + Attributes attributes = null; + if (pos < count) { - Object obj = sequence.getObjectAt(i); + ASN1TaggedObject tag1 = ASN1TaggedObject.getContextOptional(seq.getObjectAt(pos), 1); + if (tag1 != null) + { + pos++; + attributes = Attributes.getTagged(tag1, false); + } + } + this.attributes = attributes; - if (obj instanceof ASN1TaggedObject) + // reducedHashtree [2] SEQUENCE OF PartialHashtree OPTIONAL + ASN1Sequence reducedHashTree = null; + if (pos < count) + { + ASN1TaggedObject tag2 = ASN1TaggedObject.getContextOptional(seq.getObjectAt(pos), 2); + if (tag2 != null) { - ASN1TaggedObject taggedObject = ASN1TaggedObject.getInstance(obj); - - switch (taggedObject.getTagNo()) - { - case 0: - digAlg = AlgorithmIdentifier.getInstance(taggedObject, false); - break; - case 1: - attrs = Attributes.getInstance(taggedObject, false); - break; - case 2: - rHashTree = ASN1Sequence.getInstance(taggedObject, false); - break; - default: - throw new IllegalArgumentException("invalid tag no in constructor: " - + taggedObject.getTagNo()); - } + pos++; + reducedHashTree = ASN1Sequence.getInstance(tag2, false); } } + this.reducedHashTree = reducedHashTree; + + // timeStamp ContentInfo + timeStamp = ContentInfo.getInstance(seq.getObjectAt(pos++)); - digestAlgorithm = digAlg; - attributes = attrs; - reducedHashTree = rHashTree; - timeStamp = ContentInfo.getInstance(sequence.getObjectAt(sequence.size() - 1)); + if (pos != count) + { + throw new IllegalArgumentException("Unexpected elements in sequence"); + } } public AlgorithmIdentifier getDigestAlgorithmIdentifier() @@ -141,10 +163,8 @@ public AlgorithmIdentifier getDigestAlgorithmIdentifier() { return digestAlgorithm; } - else - { - return getTimeStampInfo().getMessageImprint().getHashAlgorithm(); - } + + return getTimeStampInfo().getMessageImprint().getHashAlgorithm(); } public byte[] getTimeStampDigestValue() @@ -154,25 +174,22 @@ public byte[] getTimeStampDigestValue() private TSTInfo getTimeStampInfo() { - if (timeStamp.getContentType().equals(CMSObjectIdentifiers.signedData)) + if (!CMSObjectIdentifiers.signedData.equals(timeStamp.getContentType())) { - SignedData tsData = SignedData.getInstance(timeStamp.getContent()); - if (tsData.getEncapContentInfo().getContentType().equals(PKCSObjectIdentifiers.id_ct_TSTInfo)) - { - TSTInfo tstData = TSTInfo.getInstance( - ASN1OctetString.getInstance(tsData.getEncapContentInfo().getContent()).getOctets()); - - return tstData; - } - else - { - throw new IllegalStateException("cannot parse time stamp"); - } + throw new IllegalStateException("cannot identify algorithm identifier for digest"); } - else + + SignedData tsData = SignedData.getInstance(timeStamp.getContent()); + ContentInfo encapContentInfo = tsData.getEncapContentInfo(); + + if (!PKCSObjectIdentifiers.id_ct_TSTInfo.equals(encapContentInfo.getContentType())) { - throw new IllegalStateException("cannot identify algorithm identifier for digest"); + throw new IllegalStateException("cannot parse time stamp"); } + + ASN1OctetString encapContent = ASN1OctetString.getInstance(encapContentInfo.getContent()); + + return TSTInfo.getInstance(encapContent.getOctets()); } /** @@ -194,10 +211,10 @@ public PartialHashtree getHashTreeLeaf() { if (reducedHashTree == null) { - return null; + return null; } - return PartialHashtree.getInstance(reducedHashTree.getObjectAt(0)); + return PartialHashtree.getInstance(reducedHashTree.getObjectAt(0)); } public PartialHashtree[] getReducedHashTree() @@ -221,7 +238,7 @@ public ContentInfo getTimeStamp() { return timeStamp; } - + public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(4); @@ -245,4 +262,4 @@ public ASN1Primitive toASN1Primitive() return new DERSequence(v); } -} \ No newline at end of file +} diff --git a/util/src/main/java/org/bouncycastle/asn1/tsp/EvidenceRecord.java b/util/src/main/java/org/bouncycastle/asn1/tsp/EvidenceRecord.java index fdf046e5d5..5494aa0547 100644 --- a/util/src/main/java/org/bouncycastle/asn1/tsp/EvidenceRecord.java +++ b/util/src/main/java/org/bouncycastle/asn1/tsp/EvidenceRecord.java @@ -40,7 +40,7 @@ public class EvidenceRecord */ private static final ASN1ObjectIdentifier OID = new ASN1ObjectIdentifier("1.3.6.1.5.5.11.0.2.1"); - private ASN1Integer version = new ASN1Integer(1); + private ASN1Integer version = ASN1Integer.ONE; private ASN1Sequence digestAlgorithms; private CryptoInfos cryptoInfos; private EncryptionInfo encryptionInfo; @@ -123,7 +123,7 @@ private EvidenceRecord( /** * Build a basic evidence record from an initial * ArchiveTimeStamp. - * + * * @param cryptoInfos * @param encryptionInfo * @param archiveTimeStamp @@ -226,7 +226,7 @@ public EvidenceRecord addArchiveTimeStamp(final ArchiveTimeStamp ats, final bool if (newChain) { ArchiveTimeStampChain chain = new ArchiveTimeStampChain(ats); - + return new EvidenceRecord(this, archiveTimeStampSequence.append(chain), ats); } else diff --git a/util/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java b/util/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java index 891abde318..62daaf2acd 100644 --- a/util/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java +++ b/util/src/main/java/org/bouncycastle/asn1/tsp/MessageImprint.java @@ -14,10 +14,10 @@ public class MessageImprint { AlgorithmIdentifier hashAlgorithm; byte[] hashedMessage; - + /** * Return an instance of MessageImprint, or null, based on o. - * + * * @param o the object to be converted. * @return a MessageImprint object. */ @@ -35,7 +35,7 @@ public static MessageImprint getInstance(Object o) return null; } - + private MessageImprint( ASN1Sequence seq) { @@ -49,7 +49,7 @@ private MessageImprint( throw new IllegalArgumentException("sequence has wrong number of elements"); } } - + public MessageImprint( AlgorithmIdentifier hashAlgorithm, byte[] hashedMessage) @@ -57,17 +57,22 @@ public MessageImprint( this.hashAlgorithm = hashAlgorithm; this.hashedMessage = Arrays.clone(hashedMessage); } - + public AlgorithmIdentifier getHashAlgorithm() { return hashAlgorithm; } - + public byte[] getHashedMessage() { return Arrays.clone(hashedMessage); } - + + public int getHashedMessageLength() + { + return hashedMessage.length; + } + /** *
                *    MessageImprint ::= SEQUENCE  {
          diff --git a/util/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java b/util/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java
          index 51314d69fb..00e569d191 100644
          --- a/util/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java
          +++ b/util/src/main/java/org/bouncycastle/asn1/tsp/TSTInfo.java
          @@ -65,7 +65,7 @@ private TSTInfo(ASN1Sequence seq)
           
                   // default for ordering
                   ordering = ASN1Boolean.getInstance(false);
          -        
          +
                   while (e.hasMoreElements())
                   {
                       ASN1Object o = (ASN1Object) e.nextElement();
          @@ -107,7 +107,7 @@ public TSTInfo(ASN1ObjectIdentifier tsaPolicyId, MessageImprint messageImprint,
                       Accuracy accuracy, ASN1Boolean ordering, ASN1Integer nonce,
                       GeneralName tsa, Extensions extensions)
               {
          -        version = new ASN1Integer(1);
          +        version = ASN1Integer.ONE;
                   this.tsaPolicyId = tsaPolicyId;
                   this.messageImprint = messageImprint;
                   this.serialNumber = serialNumber;
          @@ -172,7 +172,7 @@ public Extensions getExtensions()
           
               /**
                * 
          -     * 
          +     *
                *     TSTInfo ::= SEQUENCE  {
                *        version                      INTEGER  { v1(1) },
                *        policy                       TSAPolicyId,
          @@ -190,7 +190,7 @@ public Extensions getExtensions()
                *          -- in TimeStampReq.  In that case it MUST have the same value.
                *        tsa                          [0] GeneralName          OPTIONAL,
                *        extensions                   [1] IMPLICIT Extensions   OPTIONAL  }
          -     * 
          +     *
                * 
          */ public ASN1Primitive toASN1Primitive() @@ -207,22 +207,22 @@ public ASN1Primitive toASN1Primitive() { seq.add(accuracy); } - + if (ordering != null && ordering.isTrue()) { seq.add(ordering); } - + if (nonce != null) { seq.add(nonce); } - + if (tsa != null) { seq.add(new DERTaggedObject(true, 0, tsa)); } - + if (extensions != null) { seq.add(new DERTaggedObject(false, 1, extensions)); diff --git a/util/src/main/java/org/bouncycastle/asn1/tsp/TimeStampReq.java b/util/src/main/java/org/bouncycastle/asn1/tsp/TimeStampReq.java index 4165abb720..0c53fac43e 100644 --- a/util/src/main/java/org/bouncycastle/asn1/tsp/TimeStampReq.java +++ b/util/src/main/java/org/bouncycastle/asn1/tsp/TimeStampReq.java @@ -110,7 +110,7 @@ public TimeStampReq( Extensions extensions) { // default - version = new ASN1Integer(1); + version = ASN1Integer.ONE; this.messageImprint = messageImprint; this.tsaPolicy = tsaPolicy; @@ -170,25 +170,25 @@ public Extensions getExtensions() public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(6); - + v.add(version); v.add(messageImprint); - + if (tsaPolicy != null) { v.add(tsaPolicy); } - + if (nonce != null) { v.add(nonce); } - + if (certReq != null && certReq.isTrue()) { v.add(certReq); } - + if (extensions != null) { v.add(new DERTaggedObject(false, 0, extensions)); diff --git a/util/src/main/java/org/bouncycastle/asn1/tsp/TimeStampResp.java b/util/src/main/java/org/bouncycastle/asn1/tsp/TimeStampResp.java index bdfc47cb94..4bdf6a6c9c 100644 --- a/util/src/main/java/org/bouncycastle/asn1/tsp/TimeStampResp.java +++ b/util/src/main/java/org/bouncycastle/asn1/tsp/TimeStampResp.java @@ -72,7 +72,7 @@ public ContentInfo getTimeStampToken() public ASN1Primitive toASN1Primitive() { ASN1EncodableVector v = new ASN1EncodableVector(2); - + v.add(pkiStatusInfo); if (timeStampToken != null) { diff --git a/util/src/main/java/org/bouncycastle/oer/OERDefinition.java b/util/src/main/java/org/bouncycastle/oer/OERDefinition.java index fee99d1020..1f87cdf7f6 100644 --- a/util/src/main/java/org/bouncycastle/oer/OERDefinition.java +++ b/util/src/main/java/org/bouncycastle/oer/OERDefinition.java @@ -40,7 +40,7 @@ public static Builder integer() public static Builder integer(long val) { - return new Builder(BaseType.INT).defaultValue(new ASN1Integer(val)); + return new Builder(BaseType.INT).defaultValue(ASN1Integer.valueOf(val)); } public static Builder bitString(long len) diff --git a/util/src/main/java/org/bouncycastle/oer/its/etsi102941/CtlCommand.java b/util/src/main/java/org/bouncycastle/oer/its/etsi102941/CtlCommand.java index b5659bbed2..7cca29a16e 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/etsi102941/CtlCommand.java +++ b/util/src/main/java/org/bouncycastle/oer/its/etsi102941/CtlCommand.java @@ -5,7 +5,6 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERTaggedObject; /** @@ -57,7 +56,7 @@ public static CtlCommand getInstance(Object o) if (o != null) { - return new CtlCommand(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC)); + return new CtlCommand(ASN1TaggedObject.getContextInstance(o)); } return null; diff --git a/util/src/main/java/org/bouncycastle/oer/its/etsi102941/CtlDelete.java b/util/src/main/java/org/bouncycastle/oer/its/etsi102941/CtlDelete.java index 11c987ac2a..28d4167633 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/etsi102941/CtlDelete.java +++ b/util/src/main/java/org/bouncycastle/oer/its/etsi102941/CtlDelete.java @@ -5,7 +5,6 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.oer.its.ieee1609dot2.basetypes.HashedId8; @@ -67,7 +66,7 @@ public static CtlDelete getInstance(Object o) if (o != null) { - return new CtlDelete(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC)); + return new CtlDelete(ASN1TaggedObject.getContextInstance(o)); } return null; } diff --git a/util/src/main/java/org/bouncycastle/oer/its/etsi102941/CtlEntry.java b/util/src/main/java/org/bouncycastle/oer/its/etsi102941/CtlEntry.java index cf8b2aaed5..7e9bc279df 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/etsi102941/CtlEntry.java +++ b/util/src/main/java/org/bouncycastle/oer/its/etsi102941/CtlEntry.java @@ -5,7 +5,6 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERTaggedObject; /** @@ -74,7 +73,7 @@ public static CtlEntry getInstance(Object o) if (o != null) { - return new CtlEntry(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC)); + return new CtlEntry(ASN1TaggedObject.getContextInstance(o)); } return null; } diff --git a/util/src/main/java/org/bouncycastle/oer/its/etsi102941/EtsiTs102941DataContent.java b/util/src/main/java/org/bouncycastle/oer/its/etsi102941/EtsiTs102941DataContent.java index 441f467e9d..d64752d7eb 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/etsi102941/EtsiTs102941DataContent.java +++ b/util/src/main/java/org/bouncycastle/oer/its/etsi102941/EtsiTs102941DataContent.java @@ -5,7 +5,6 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERTaggedObject; /** @@ -120,7 +119,7 @@ public static EtsiTs102941DataContent getInstance(Object o) if (o != null) { - return new EtsiTs102941DataContent(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC)); + return new EtsiTs102941DataContent(ASN1TaggedObject.getContextInstance(o)); } return null; diff --git a/util/src/main/java/org/bouncycastle/oer/its/etsi102941/basetypes/CertificateFormat.java b/util/src/main/java/org/bouncycastle/oer/its/etsi102941/basetypes/CertificateFormat.java index 416d396292..a9a93c9744 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/etsi102941/basetypes/CertificateFormat.java +++ b/util/src/main/java/org/bouncycastle/oer/its/etsi102941/basetypes/CertificateFormat.java @@ -53,6 +53,6 @@ public static CertificateFormat getInstance(Object o) public ASN1Primitive toASN1Primitive() { - return new ASN1Integer(format); + return ASN1Integer.valueOf(format); } } diff --git a/util/src/main/java/org/bouncycastle/oer/its/etsi102941/basetypes/EcSignature.java b/util/src/main/java/org/bouncycastle/oer/its/etsi102941/basetypes/EcSignature.java index e875b26a49..e495108feb 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/etsi102941/basetypes/EcSignature.java +++ b/util/src/main/java/org/bouncycastle/oer/its/etsi102941/basetypes/EcSignature.java @@ -5,7 +5,6 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.oer.its.etsi103097.EtsiTs103097DataEncrypted; import org.bouncycastle.oer.its.etsi103097.EtsiTs103097DataSignedExternalPayload; @@ -59,7 +58,7 @@ public static EcSignature getInstance(Object o) } if (o != null) { - return new EcSignature(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC)); + return new EcSignature(ASN1TaggedObject.getContextInstance(o)); } return null; diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/AesCcmCiphertext.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/AesCcmCiphertext.java index 4af39768c7..156c77a7e3 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/AesCcmCiphertext.java +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/AesCcmCiphertext.java @@ -92,7 +92,7 @@ public Builder setNonce(byte[] nonce) { return setNonce(new DEROctetString(Arrays.clone(nonce))); } - + public Builder setCcmCiphertext(Opaque opaque) { this.opaque = opaque; @@ -109,4 +109,4 @@ public AesCcmCiphertext createAesCcmCiphertext() return new AesCcmCiphertext(nonce, opaque); } } -} \ No newline at end of file +} diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/CertificateId.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/CertificateId.java index c914942850..897dadde84 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/CertificateId.java +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/CertificateId.java @@ -7,7 +7,6 @@ import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERTaggedObject; @@ -98,7 +97,7 @@ public static CertificateId getInstance(Object o) if (o != null) { - return new CertificateId(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC)); + return new CertificateId(ASN1TaggedObject.getContextInstance(o)); } return null; diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/EncryptedDataEncryptionKey.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/EncryptedDataEncryptionKey.java index 3242efed94..c666c92439 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/EncryptedDataEncryptionKey.java +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/EncryptedDataEncryptionKey.java @@ -5,7 +5,6 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.oer.its.ieee1609dot2.basetypes.EciesP256EncryptedKey; @@ -56,7 +55,7 @@ public static EncryptedDataEncryptionKey getInstance(Object o) if (o != null) { - return new EncryptedDataEncryptionKey(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC)); + return new EncryptedDataEncryptionKey(ASN1TaggedObject.getContextInstance(o)); } return null; diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/HashedData.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/HashedData.java index 4c108e1b24..6ab6ded38c 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/HashedData.java +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/HashedData.java @@ -6,7 +6,6 @@ import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.util.Arrays; @@ -93,7 +92,7 @@ public static HashedData getInstance(Object o) if (o != null) { - return new HashedData(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC)); + return new HashedData(ASN1TaggedObject.getContextInstance(o)); } return null; diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/HeaderInfo.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/HeaderInfo.java index 2ed30c2f79..49e77c0012 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/HeaderInfo.java +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/HeaderInfo.java @@ -308,4 +308,4 @@ public HeaderInfo createHeaderInfo() } -} \ No newline at end of file +} diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/Ieee1609Dot2Content.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/Ieee1609Dot2Content.java index 3e21cecc41..401cfb498f 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/Ieee1609Dot2Content.java +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/Ieee1609Dot2Content.java @@ -5,7 +5,6 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.util.Arrays; @@ -103,7 +102,7 @@ public static Ieee1609Dot2Content getInstance(Object src) if (src != null) { - return new Ieee1609Dot2Content(ASN1TaggedObject.getInstance(src, BERTags.CONTEXT_SPECIFIC)); + return new Ieee1609Dot2Content(ASN1TaggedObject.getContextInstance(src)); } return null; } diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/IssuerIdentifier.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/IssuerIdentifier.java index e30df5f265..3f28112d44 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/IssuerIdentifier.java +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/IssuerIdentifier.java @@ -5,7 +5,6 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.oer.its.ieee1609dot2.basetypes.HashAlgorithm; import org.bouncycastle.oer.its.ieee1609dot2.basetypes.HashedId8; @@ -83,7 +82,7 @@ public static IssuerIdentifier getInstance(Object choice) if (choice != null) { - return new IssuerIdentifier(ASN1TaggedObject.getInstance(choice, BERTags.CONTEXT_SPECIFIC)); + return new IssuerIdentifier(ASN1TaggedObject.getContextInstance(choice)); } return null; diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/PsidGroupPermissions.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/PsidGroupPermissions.java index 2cb8843c12..8fdefcdbdf 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/PsidGroupPermissions.java +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/PsidGroupPermissions.java @@ -123,7 +123,7 @@ public Builder setMinChainLength(BigInteger minChainLength) public Builder setMinChainLength(long minChainLength) { - this.minChainLength = new ASN1Integer(minChainLength); + this.minChainLength = ASN1Integer.valueOf(minChainLength); return this; } @@ -147,7 +147,7 @@ public Builder setChainLengthRange(BigInteger chainLengthRange) public Builder setChainLengthRange(long chainLengthRange) { - this.chainLengthRange = new ASN1Integer(chainLengthRange); + this.chainLengthRange = ASN1Integer.valueOf(chainLengthRange); return this; } diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/RecipientInfo.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/RecipientInfo.java index eb11b5969b..f606e48c12 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/RecipientInfo.java +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/RecipientInfo.java @@ -5,7 +5,6 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERTaggedObject; /** @@ -70,7 +69,7 @@ public static RecipientInfo getInstance(Object object) if (object != null) { - return new RecipientInfo(ASN1TaggedObject.getInstance(object, BERTags.CONTEXT_SPECIFIC)); + return new RecipientInfo(ASN1TaggedObject.getContextInstance(object)); } return null; diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SequenceOfPsidGroupPermissions.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SequenceOfPsidGroupPermissions.java index c0ce16c3b1..4e687c999e 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SequenceOfPsidGroupPermissions.java +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SequenceOfPsidGroupPermissions.java @@ -90,4 +90,4 @@ public SequenceOfPsidGroupPermissions createSequenceOfPsidGroupPermissions() } } -} \ No newline at end of file +} diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SignedData.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SignedData.java index 8714fcead4..73761417d0 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SignedData.java +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SignedData.java @@ -131,4 +131,4 @@ public SignedData createSignedData() } -} \ No newline at end of file +} diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SignerIdentifier.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SignerIdentifier.java index 8ae0765b34..2df9f39043 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SignerIdentifier.java +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SignerIdentifier.java @@ -5,7 +5,6 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.oer.its.ieee1609dot2.basetypes.HashedId8; @@ -121,7 +120,7 @@ public static SignerIdentifier getInstance(Object src) if (src != null) { - return new SignerIdentifier(ASN1TaggedObject.getInstance(src, BERTags.CONTEXT_SPECIFIC)); + return new SignerIdentifier(ASN1TaggedObject.getContextInstance(src)); } return null; diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SubjectPermissions.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SubjectPermissions.java index 4752294792..3fe976c72f 100644 --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SubjectPermissions.java +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SubjectPermissions.java @@ -6,12 +6,10 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERNull; import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.oer.its.ieee1609dot2.basetypes.SequenceOfPsidSspRange; - /** *
            *     SubjectPermissions ::= CHOICE {
          @@ -77,7 +75,7 @@ public static SubjectPermissions getInstance(Object src)
           
                   if (src != null)
                   {
          -            return new SubjectPermissions(ASN1TaggedObject.getInstance(src, BERTags.CONTEXT_SPECIFIC));
          +            return new SubjectPermissions(ASN1TaggedObject.getContextInstance(src));
                   }
                   return null;
               }
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SymmetricCiphertext.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SymmetricCiphertext.java
          index e568675684..9ed7ed22db 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SymmetricCiphertext.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/SymmetricCiphertext.java
          @@ -5,7 +5,6 @@
           import org.bouncycastle.asn1.ASN1Object;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERTaggedObject;
           
           /**
          @@ -59,7 +58,7 @@ public static SymmetricCiphertext getInstance(Object o)
           
                   if (o != null)
                   {
          -            return new SymmetricCiphertext(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC));
          +            return new SymmetricCiphertext(ASN1TaggedObject.getContextInstance(o));
                   }
           
                   return null;
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/ToBeSignedData.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/ToBeSignedData.java
          index c4c52b7632..fc4ef8324f 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/ToBeSignedData.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/ToBeSignedData.java
          @@ -96,4 +96,4 @@ public ToBeSignedData createToBeSignedData()
                   }
               }
           
          -}
          \ No newline at end of file
          +}
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/VerificationKeyIndicator.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/VerificationKeyIndicator.java
          index 1550334920..dae186254a 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/VerificationKeyIndicator.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/VerificationKeyIndicator.java
          @@ -5,7 +5,6 @@
           import org.bouncycastle.asn1.ASN1Object;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERTaggedObject;
           import org.bouncycastle.oer.its.ieee1609dot2.basetypes.EccP256CurvePoint;
           import org.bouncycastle.oer.its.ieee1609dot2.basetypes.PublicVerificationKey;
          @@ -74,7 +73,7 @@ public static VerificationKeyIndicator getInstance(Object src)
           
                   if (src != null)
                   {
          -            return new VerificationKeyIndicator(ASN1TaggedObject.getInstance(src, BERTags.CONTEXT_SPECIFIC));
          +            return new VerificationKeyIndicator(ASN1TaggedObject.getContextInstance(src));
                   }
           
                   return null;
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/BasePublicEncryptionKey.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/BasePublicEncryptionKey.java
          index 75e0921b94..f7a09476f2 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/BasePublicEncryptionKey.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/BasePublicEncryptionKey.java
          @@ -5,7 +5,6 @@
           import org.bouncycastle.asn1.ASN1Object;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERTaggedObject;
           
           /**
          @@ -54,7 +53,7 @@ public static BasePublicEncryptionKey getInstance(Object objectAt)
           
                   if (objectAt != null)
                   {
          -            return new BasePublicEncryptionKey(ASN1TaggedObject.getInstance(objectAt, BERTags.CONTEXT_SPECIFIC));
          +            return new BasePublicEncryptionKey(ASN1TaggedObject.getContextInstance(objectAt));
                   }
                   return null;
               }
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/CircularRegion.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/CircularRegion.java
          index 189b9f9352..dd030e9b3c 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/CircularRegion.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/CircularRegion.java
          @@ -95,4 +95,4 @@ public CircularRegion createCircularRegion()
                       return new CircularRegion(center, radius);
                   }
               }
          -}
          \ No newline at end of file
          +}
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/Duration.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/Duration.java
          index f619199e6c..3e2a56efa1 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/Duration.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/Duration.java
          @@ -4,7 +4,6 @@
           import org.bouncycastle.asn1.ASN1Object;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERTaggedObject;
           
           /**
          @@ -76,7 +75,7 @@ public static Duration getInstance(Object o)
           
                   if (o != null)
                   {
          -            return new Duration(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC));
          +            return new Duration(ASN1TaggedObject.getContextInstance(o));
                   }
           
                   return null;
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EccP256CurvePoint.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EccP256CurvePoint.java
          index fa6e4205e4..63ec117d94 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EccP256CurvePoint.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EccP256CurvePoint.java
          @@ -8,7 +8,6 @@
           import org.bouncycastle.asn1.ASN1OctetString;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERNull;
           import org.bouncycastle.asn1.DEROctetString;
           import org.bouncycastle.asn1.DERTaggedObject;
          @@ -178,7 +177,7 @@ public static EccP256CurvePoint getInstance(Object object)
           
                   if (object != null)
                   {
          -            return new EccP256CurvePoint(ASN1TaggedObject.getInstance(object, BERTags.CONTEXT_SPECIFIC));
          +            return new EccP256CurvePoint(ASN1TaggedObject.getContextInstance(object));
                   }
           
                   return null;
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EccP384CurvePoint.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EccP384CurvePoint.java
          index 9e50905198..272041382c 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EccP384CurvePoint.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EccP384CurvePoint.java
          @@ -7,7 +7,6 @@
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1Sequence;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERNull;
           import org.bouncycastle.asn1.DEROctetString;
           import org.bouncycastle.asn1.DERTaggedObject;
          @@ -76,7 +75,7 @@ public static EccP384CurvePoint getInstance(Object object)
           
                   if (object != null)
                   {
          -            return new EccP384CurvePoint(ASN1TaggedObject.getInstance(object, BERTags.CONTEXT_SPECIFIC));
          +            return new EccP384CurvePoint(ASN1TaggedObject.getContextInstance(object));
                   }
           
                   return null;
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EncryptionKey.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EncryptionKey.java
          index 630f1660ca..aa68ddee15 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EncryptionKey.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EncryptionKey.java
          @@ -5,7 +5,6 @@
           import org.bouncycastle.asn1.ASN1Object;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERTaggedObject;
           
           /**
          @@ -34,7 +33,7 @@ public static EncryptionKey getInstance(Object o)
                   }
                   if (o != null)
                   {
          -            return new EncryptionKey(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC));
          +            return new EncryptionKey(ASN1TaggedObject.getContextInstance(o));
                   }
                   return null;
               }
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/GeographicRegion.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/GeographicRegion.java
          index 0cb46dacd6..6fa1f8dddd 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/GeographicRegion.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/GeographicRegion.java
          @@ -5,7 +5,6 @@
           import org.bouncycastle.asn1.ASN1Object;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERTaggedObject;
           
           /**
          @@ -91,7 +90,7 @@ public static GeographicRegion getInstance(Object o)
                   }
                   if (o != null)
                   {
          -            return new GeographicRegion(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC));
          +            return new GeographicRegion(ASN1TaggedObject.getContextInstance(o));
                   }
           
                   return null;
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/IdentifiedRegion.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/IdentifiedRegion.java
          index 9ebfd332ae..7bdf5f7ef3 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/IdentifiedRegion.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/IdentifiedRegion.java
          @@ -5,10 +5,8 @@
           import org.bouncycastle.asn1.ASN1Object;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERTaggedObject;
           
          -
           /**
            * IdentifiedRegion ::= CHOICE {
            * countryOnly           CountryOnly,
          @@ -79,7 +77,7 @@ public static IdentifiedRegion getInstance(Object o)
                   }
                   if (o != null)
                   {
          -            return new IdentifiedRegion(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC));
          +            return new IdentifiedRegion(ASN1TaggedObject.getContextInstance(o));
                   }
           
                   return null;
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/PublicVerificationKey.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/PublicVerificationKey.java
          index f5a733b8c9..a6da63d689 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/PublicVerificationKey.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/PublicVerificationKey.java
          @@ -5,7 +5,6 @@
           import org.bouncycastle.asn1.ASN1Object;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DEROctetString;
           import org.bouncycastle.asn1.DERTaggedObject;
           
          @@ -79,7 +78,7 @@ public static PublicVerificationKey getInstance(Object object)
           
                   if (object != null)
                   {
          -            return new PublicVerificationKey(ASN1TaggedObject.getInstance(object, BERTags.CONTEXT_SPECIFIC));
          +            return new PublicVerificationKey(ASN1TaggedObject.getContextInstance(object));
                   }
                   return null;
               }
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/RectangularRegion.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/RectangularRegion.java
          index 65647ae7cb..a3893d2824 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/RectangularRegion.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/RectangularRegion.java
          @@ -99,4 +99,4 @@ public RectangularRegion createRectangularRegion()
                   }
               }
           
          -}
          \ No newline at end of file
          +}
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/ServiceSpecificPermissions.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/ServiceSpecificPermissions.java
          index e49fdb26db..8d9b7f99e2 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/ServiceSpecificPermissions.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/ServiceSpecificPermissions.java
          @@ -6,7 +6,6 @@
           import org.bouncycastle.asn1.ASN1OctetString;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DEROctetString;
           import org.bouncycastle.asn1.DERTaggedObject;
           import org.bouncycastle.oer.its.ieee1609dot2.Opaque;
          @@ -61,7 +60,7 @@ public static ServiceSpecificPermissions getInstance(Object o)
           
                   if (o != null)
                   {
          -            return new ServiceSpecificPermissions(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC));
          +            return new ServiceSpecificPermissions(ASN1TaggedObject.getContextInstance(o));
                   }
           
                   return null;
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/Signature.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/Signature.java
          index cdd54e9d1d..2d3f103fb6 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/Signature.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/Signature.java
          @@ -5,7 +5,6 @@
           import org.bouncycastle.asn1.ASN1Object;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERTaggedObject;
           
           /**
          @@ -79,7 +78,7 @@ public static Signature getInstance(Object objectAt)
           
                   if (objectAt != null)
                   {
          -            return new Signature(ASN1TaggedObject.getInstance(objectAt, BERTags.CONTEXT_SPECIFIC));
          +            return new Signature(ASN1TaggedObject.getContextInstance(objectAt));
                   }
           
                   return null;
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/SspRange.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/SspRange.java
          index 65c31cdb53..9dd4593b62 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/SspRange.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/SspRange.java
          @@ -5,7 +5,6 @@
           import org.bouncycastle.asn1.ASN1Object;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERNull;
           import org.bouncycastle.asn1.DERTaggedObject;
           
          @@ -82,7 +81,7 @@ public static SspRange getInstance(Object src)
           
                   if (src != null)
                   {
          -            return new SspRange(ASN1TaggedObject.getInstance(src, BERTags.CONTEXT_SPECIFIC));
          +            return new SspRange(ASN1TaggedObject.getContextInstance(src));
                   }
           
                   return null;
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/SymmetricEncryptionKey.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/SymmetricEncryptionKey.java
          index c573c01488..be7d0c8761 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/SymmetricEncryptionKey.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/SymmetricEncryptionKey.java
          @@ -6,7 +6,6 @@
           import org.bouncycastle.asn1.ASN1OctetString;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DEROctetString;
           import org.bouncycastle.asn1.DERTaggedObject;
           
          @@ -59,7 +58,7 @@ public static SymmetricEncryptionKey getInstance(Object o)
                   }
                   if (o != null)
                   {
          -            return new SymmetricEncryptionKey(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC));
          +            return new SymmetricEncryptionKey(ASN1TaggedObject.getContextInstance(o));
                   }
           
                   return null;
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2dot1/AdditionalParams.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2dot1/AdditionalParams.java
          index 79eb52733e..2bab58de0d 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2dot1/AdditionalParams.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2dot1/AdditionalParams.java
          @@ -5,7 +5,6 @@
           import org.bouncycastle.asn1.ASN1Object;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DERTaggedObject;
           import org.bouncycastle.oer.its.ieee1609dot2.basetypes.PublicEncryptionKey;
           
          @@ -68,7 +67,7 @@ public static AdditionalParams getInstance(Object o)
           
                   if (o != null)
                   {
          -            return new AdditionalParams(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC));
          +            return new AdditionalParams(ASN1TaggedObject.getContextInstance(o));
                   }
           
                   return null;
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2dot1/ButterflyExpansion.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2dot1/ButterflyExpansion.java
          index 45e614c0cc..db45276208 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2dot1/ButterflyExpansion.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2dot1/ButterflyExpansion.java
          @@ -6,11 +6,9 @@
           import org.bouncycastle.asn1.ASN1OctetString;
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.DEROctetString;
           import org.bouncycastle.asn1.DERTaggedObject;
           
          -
           /**
            * ButterflyExpansion ::= CHOICE {
            * aes128      OCTET STRING (SIZE(16)),
          @@ -55,7 +53,7 @@ public static ButterflyExpansion getInstance(Object o)
           
                   if (o != null)
                   {
          -            return new ButterflyExpansion(ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC));
          +            return new ButterflyExpansion(ASN1TaggedObject.getContextInstance(o));
                   }
           
                   return null;
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/template/etsi103097/extension/EtsiTs103097ExtensionModule.java b/util/src/main/java/org/bouncycastle/oer/its/template/etsi103097/extension/EtsiTs103097ExtensionModule.java
          index 333008cbe4..bbd32ff273 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/template/etsi103097/extension/EtsiTs103097ExtensionModule.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/template/etsi103097/extension/EtsiTs103097ExtensionModule.java
          @@ -17,8 +17,8 @@
           public class EtsiTs103097ExtensionModule
           {
           
          -    public static final ASN1Integer etsiTs102941CrlRequestId = new ASN1Integer(1);
          -    public static final ASN1Integer etsiTs102941DeltaCtlRequestId = new ASN1Integer(2);
          +    public static final ASN1Integer etsiTs102941CrlRequestId = ASN1Integer.ONE;
          +    public static final ASN1Integer etsiTs102941DeltaCtlRequestId = ASN1Integer.TWO;
               private static final ASN1Encodable[] extensionKeys = new ASN1Encodable[]{etsiTs102941CrlRequestId, etsiTs102941DeltaCtlRequestId};
           
               /**
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2/IEEE1609dot2.java b/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2/IEEE1609dot2.java
          index fc36d74429..3e3987add3 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2/IEEE1609dot2.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2/IEEE1609dot2.java
          @@ -259,7 +259,8 @@ public Element result(SwitchIndexer indexer)
                * EndEntityType ::= BIT STRING {app (0), enrol (1) } (SIZE (8))
                */
               public static final OERDefinition.Builder EndEntityType =
          -        OERDefinition.bitString(8).defaultValue(new DERBitString(new byte[]{0}, 0))
          +        OERDefinition.bitString(8)
          +                .defaultValue(new DERBitString(org.bouncycastle.oer.its.ieee1609dot2.EndEntityType.app))
                       .typeName("EndEntityType");
           
               /**
          @@ -623,7 +624,7 @@ public Element build()
                * }
                */
               public static final OERDefinition.Builder Ieee1609Dot2Data = OERDefinition.seq(
          -        Ieee1609Dot2BaseTypes.UINT8.validSwitchValue(new ASN1Integer(3)).label("protocolVersion"),
          +        Ieee1609Dot2BaseTypes.UINT8.validSwitchValue(ASN1Integer.THREE).label("protocolVersion"),
                   Ieee1609Dot2Content.label("content")).typeName("Ieee1609Dot2Data");
               /**
                * SignedDataPayload ::= SEQUENCE {
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2/basetypes/Ieee1609Dot2BaseTypes.java b/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2/basetypes/Ieee1609Dot2BaseTypes.java
          index 7b87b10605..e7ad1f3bce 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2/basetypes/Ieee1609Dot2BaseTypes.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2/basetypes/Ieee1609Dot2BaseTypes.java
          @@ -497,7 +497,7 @@ public class Ieee1609Dot2BaseTypes
                */
               public static final OERDefinition.Builder OneEightyDegreeInt = OERDefinition.integer(-1799999999, 1800000001).typeName("OneEightyDegreeInt");
               public static final OERDefinition.Builder KnownLongitude = OneEightyDegreeInt.copy().typeName("KnownLongitude");
          -    public static final OERDefinition.Builder UnknownLongitude = OERDefinition.integer().validSwitchValue(new ASN1Integer(1800000001)).typeName("UnknownLongitude");
          +    public static final OERDefinition.Builder UnknownLongitude = OERDefinition.integer().validSwitchValue(ASN1Integer.valueOf(1800000001)).typeName("UnknownLongitude");
               /**
                * NinetyDegreeInt ::= INTEGER {
                * min         (-900000000),
          @@ -510,7 +510,7 @@ public class Ieee1609Dot2BaseTypes
               //
               // PSID / ITS-AID
               //
          -    public static final OERDefinition.Builder UnknownLatitude = OERDefinition.integer().validSwitchValue(new ASN1Integer(900000001)).typeName("UnknownLatitude");
          +    public static final OERDefinition.Builder UnknownLatitude = OERDefinition.integer().validSwitchValue(ASN1Integer.valueOf(900000001)).typeName("UnknownLatitude");
               public static final OERDefinition.Builder Elevation = UINT16.typeName("Elevation");
               public static final OERDefinition.Builder Longitude = OneEightyDegreeInt.copy().typeName("Longitude");
               public static final OERDefinition.Builder Latitude = NinetyDegreeInt.copy().typeName("Latitude");
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2dot1/Ieee1609Dot2Dot1EcaEeInterface.java b/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2dot1/Ieee1609Dot2Dot1EcaEeInterface.java
          index e47d6ed305..716857f271 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2dot1/Ieee1609Dot2Dot1EcaEeInterface.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2dot1/Ieee1609Dot2Dot1EcaEeInterface.java
          @@ -33,7 +33,7 @@ public class Ieee1609Dot2Dot1EcaEeInterface
                * }
                */
               public static final OERDefinition.Builder EeEcaCertRequest = OERDefinition.seq(
          -        Ieee1609Dot2BaseTypes.UINT8.label("version").validSwitchValue(new ASN1Integer(2)),
          +        Ieee1609Dot2BaseTypes.UINT8.label("version").validSwitchValue(ASN1Integer.TWO),
                   Ieee1609Dot2BaseTypes.Time32.label("generationTime"),
                   IEEE1609dot2.CertificateType.label("type"),
                   IEEE1609dot2.ToBeSignedCertificate.label("tbsCert"),
          diff --git a/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2dot1/Ieee1609Dot2Dot1EeRaInterface.java b/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2dot1/Ieee1609Dot2Dot1EeRaInterface.java
          index 4f757019cf..60344867d8 100644
          --- a/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2dot1/Ieee1609Dot2Dot1EeRaInterface.java
          +++ b/util/src/main/java/org/bouncycastle/oer/its/template/ieee1609dot2dot1/Ieee1609Dot2Dot1EeRaInterface.java
          @@ -72,7 +72,7 @@ public class Ieee1609Dot2Dot1EeRaInterface
                * }
                */
               public static final OERDefinition.Builder EeRaCertRequest = OERDefinition.seq(
          -        Ieee1609Dot2BaseTypes.UINT8.label("version").validSwitchValue(new ASN1Integer(2)),
          +        Ieee1609Dot2BaseTypes.UINT8.label("version").validSwitchValue(ASN1Integer.TWO),
                   Ieee1609Dot2BaseTypes.Time32.label("generationTime"),
                   IEEE1609dot2.CertificateType.label("type"),
                   IEEE1609dot2.ToBeSignedCertificate.label("tbsCert"),
          diff --git a/util/src/main/jdk1.4/org/bouncycastle/asn1/cmp/CertAnnContent.java b/util/src/main/jdk1.4/org/bouncycastle/asn1/cmp/CertAnnContent.java
          index 24cfcc801c..a73f84fa7d 100644
          --- a/util/src/main/jdk1.4/org/bouncycastle/asn1/cmp/CertAnnContent.java
          +++ b/util/src/main/jdk1.4/org/bouncycastle/asn1/cmp/CertAnnContent.java
          @@ -6,7 +6,6 @@
           import org.bouncycastle.asn1.ASN1Primitive;
           import org.bouncycastle.asn1.ASN1Sequence;
           import org.bouncycastle.asn1.ASN1TaggedObject;
          -import org.bouncycastle.asn1.BERTags;
           import org.bouncycastle.asn1.x509.AttributeCertificate;
           import org.bouncycastle.asn1.x509.Certificate;
           
          @@ -92,7 +91,7 @@ public static CMPCertificate getInstance(Object o)
           
                   if (o instanceof ASN1TaggedObject)
                   {
          -            ASN1TaggedObject taggedObject = ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC);
          +            ASN1TaggedObject taggedObject = ASN1TaggedObject.getContextInstance(o);
           
                       return new CertAnnContent(taggedObject.getTagNo(), taggedObject.getExplicitBaseObject());
                   }
          diff --git a/util/src/main/jdk1.4/org/bouncycastle/asn1/cmp/OOBCert.java b/util/src/main/jdk1.4/org/bouncycastle/asn1/cmp/OOBCert.java
          index 30f0f7641a..4324d935bd 100644
          --- a/util/src/main/jdk1.4/org/bouncycastle/asn1/cmp/OOBCert.java
          +++ b/util/src/main/jdk1.4/org/bouncycastle/asn1/cmp/OOBCert.java
          @@ -87,7 +87,7 @@ public static CMPCertificate getInstance(Object o)
           
                   if (o instanceof ASN1TaggedObject)
                   {
          -            ASN1TaggedObject taggedObject = ASN1TaggedObject.getInstance(o, BERTags.CONTEXT_SPECIFIC);
          +            ASN1TaggedObject taggedObject = ASN1TaggedObject.getContextInstance(o);
           
                       return new OOBCert(taggedObject.getTagNo(), taggedObject.getExplicitBaseObject());
                   }
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/CMCFailInfoTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/CMCFailInfoTest.java
          index 774a4e2b2b..206aefd80b 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/CMCFailInfoTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/CMCFailInfoTest.java
          @@ -73,7 +73,7 @@ public void performTest()
                   for (Iterator typeKeys = typesMap.keySet().iterator(); typeKeys.hasNext(); )
                   {
                       Object j = typeKeys.next();
          -            if (!range.containsKey(new ASN1Integer(((Long)j).longValue())))
          +            if (!range.containsKey(ASN1Integer.valueOf(((Long)j).longValue())))
                       {
                           fail("The 'typesMap' map in CMCFailInfoTest contains a value not in the CMCFailInfo ('range') map, value was: " + j.toString());
                       }
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/CMCStatusTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/CMCStatusTest.java
          index 683a4db298..9f8aa78308 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/CMCStatusTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/CMCStatusTest.java
          @@ -77,7 +77,7 @@ public void performTest()
                   for (Iterator typeKeys = typesMap.keySet().iterator(); typeKeys.hasNext(); )
                   {
                       Object j = typeKeys.next();
          -            if (!range.containsKey(new ASN1Integer(((Long)j).longValue())))
          +            if (!range.containsKey(ASN1Integer.valueOf(((Long)j).longValue())))
                       {
                           fail("The 'typesMap' map in CMCStatusTest contains a value not in the CMCStatus ('range') map, value was: " + j.toString());
                       }
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/CMCUnsignedDataTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/CMCUnsignedDataTest.java
          index b9548afd76..64cb5f1b3e 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/CMCUnsignedDataTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/CMCUnsignedDataTest.java
          @@ -41,7 +41,7 @@ public void performTest()
           
                   try
                   {
          -            CMCUnsignedData.getInstance(new DERSequence(new ASN1Integer(10)));
          +            CMCUnsignedData.getInstance(new DERSequence(ASN1Integer.valueOf(10)));
                       fail("Must fail, sequence must be 3");
                   }
                   catch (Exception ex)
          @@ -51,7 +51,7 @@ public void performTest()
           
                   try
                   {
          -            CMCUnsignedData.getInstance(new DERSequence(new ASN1Encodable[]{new ASN1Integer(10), new ASN1Integer(10), new ASN1Integer(10), new ASN1Integer(10)}));
          +            CMCUnsignedData.getInstance(new DERSequence(new ASN1Encodable[]{ASN1Integer.valueOf(10), ASN1Integer.valueOf(10), ASN1Integer.valueOf(10), ASN1Integer.valueOf(10)}));
                       fail("Must fail, sequence must be 3");
                   }
                   catch (Exception ex)
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/ControlsProcessedTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/ControlsProcessedTest.java
          index 413144447d..60ac9427ac 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/ControlsProcessedTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/ControlsProcessedTest.java
          @@ -1,6 +1,5 @@
           package org.bouncycastle.asn1.cmc.test;
           
          -import org.bouncycastle.asn1.ASN1Encodable;
           import org.bouncycastle.asn1.ASN1Integer;
           import org.bouncycastle.asn1.DERSequence;
           import org.bouncycastle.asn1.DERUTF8String;
          @@ -38,9 +37,7 @@ public void performTest()
           
                   try
                   {
          -            ControlsProcessed.getInstance(new DERSequence(
          -                new ASN1Encodable[]{new ASN1Integer(12L), new DERUTF8String("Monkeys")
          -                }));
          +            ControlsProcessed.getInstance(new DERSequence(ASN1Integer.valueOf(12), new DERUTF8String("Monkeys")));
                       fail("Must accept only sequence length of 1");
                   }
                   catch (Throwable t)
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/EncryptedPOPTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/EncryptedPOPTest.java
          index 074c1ad699..8597763135 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/EncryptedPOPTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/EncryptedPOPTest.java
          @@ -34,7 +34,7 @@ public void performTest()
               {
                   // All Object Identifiers are not real!
                   TaggedRequest taggedRequest = new TaggedRequest(new TaggedCertificationRequest(new BodyPartID(10L), CertificationRequest.getInstance(req1)));
          -        ContentInfo cms = new ContentInfo(new ASN1ObjectIdentifier("1.2.3"), new ASN1Integer(12L));
          +        ContentInfo cms = new ContentInfo(new ASN1ObjectIdentifier("1.2.3"), ASN1Integer.valueOf(12));
                   AlgorithmIdentifier thePopID = new AlgorithmIdentifier(new ASN1ObjectIdentifier("2.2.5.2"));
                   AlgorithmIdentifier whitenessID = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.5.2.5"));
                   byte[] whiteness = "Fish and Chips".getBytes();
          @@ -53,7 +53,7 @@ public void performTest()
           
                   try
                   {
          -            EncryptedPOP.getInstance(new DERSequence(new ASN1Integer(1L)));
          +            EncryptedPOP.getInstance(new DERSequence(ASN1Integer.ONE));
                       fail("Sequence must be 5 items long.");
                   }
                   catch (Throwable t)
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/ExtendedFailInfoTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/ExtendedFailInfoTest.java
          index bd947fc411..762388b13d 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/ExtendedFailInfoTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/ExtendedFailInfoTest.java
          @@ -27,7 +27,7 @@ public void performTest()
                   // OID not real
                   ExtendedFailInfo extendedFailInfo = new ExtendedFailInfo(
                       new ASN1ObjectIdentifier("1.2.3.2"),
          -            new ASN1Integer(10L));
          +            ASN1Integer.valueOf(10));
                   byte[] b = extendedFailInfo.getEncoded();
                   ExtendedFailInfo extendedFailInfoResult = ExtendedFailInfo.getInstance(b);
           
          @@ -36,7 +36,7 @@ public void performTest()
           
                   try
                   {
          -            ExtendedFailInfo.getInstance(new DERSequence(new ASN1Integer(10L)));
          +            ExtendedFailInfo.getInstance(new DERSequence(ASN1Integer.valueOf(10)));
                       fail("Sequence must be 2 elements.");
                   }
                   catch (Throwable t)
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/GetCRLTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/GetCRLTest.java
          index 68eed5ae78..ba8fa51a33 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/GetCRLTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/GetCRLTest.java
          @@ -64,8 +64,8 @@ public void performTest()
           
                       try
                       {
          -                GetCRL.getInstance(new DERSequence(new ASN1Encodable[]
          -                    { new ASN1Integer(1), new ASN1Integer(2), new ASN1Integer(3), new ASN1Integer(4), new ASN1Integer(5)}));
          +                GetCRL.getInstance(new DERSequence(new ASN1Encodable[]{
          +                    ASN1Integer.ONE, ASN1Integer.TWO, ASN1Integer.THREE, ASN1Integer.FOUR, ASN1Integer.FIVE}));
                           fail("Must not accept sequence larger than 5");
                       }
                       catch (Throwable t)
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/GetCertTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/GetCertTest.java
          index 0a03e6da0b..e0a41f94de 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/GetCertTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/GetCertTest.java
          @@ -34,7 +34,7 @@ public void performTest()
           
                   try
                   {
          -            GetCert.getInstance(new DERSequence(new ASN1Integer(1L)));
          +            GetCert.getInstance(new DERSequence(ASN1Integer.ONE));
                       fail("Sequence must be length of 2");
                   }
                   catch (Throwable t)
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/IdentityProofV2Test.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/IdentityProofV2Test.java
          index 83d161f14d..96b3a952b7 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/IdentityProofV2Test.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/IdentityProofV2Test.java
          @@ -26,8 +26,8 @@ public void performTest()
                   throws Exception
               {
                   IdentityProofV2 proofV2 = new IdentityProofV2(
          -            new AlgorithmIdentifier(PKCSObjectIdentifiers.encryptionAlgorithm, new ASN1Integer(10L)),
          -            new AlgorithmIdentifier(PKCSObjectIdentifiers.bagtypes, new ASN1Integer(10L)),
          +            new AlgorithmIdentifier(PKCSObjectIdentifiers.encryptionAlgorithm, ASN1Integer.valueOf(10)),
          +            new AlgorithmIdentifier(PKCSObjectIdentifiers.bagtypes, ASN1Integer.valueOf(10)),
                       "Cats".getBytes()
                   );
           
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/LraPopWitnessTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/LraPopWitnessTest.java
          index b0c881618c..9674dc18b1 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/LraPopWitnessTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/LraPopWitnessTest.java
          @@ -25,7 +25,7 @@ public String getName()
               public void performTest()
                   throws Exception
               {
          -        LraPopWitness popWitness = new LraPopWitness(new BodyPartID(10L), new DERSequence(new ASN1Integer(20L)));
          +        LraPopWitness popWitness = new LraPopWitness(new BodyPartID(10L), new DERSequence(ASN1Integer.valueOf(20)));
                   byte[] b = popWitness.getEncoded();
                   LraPopWitness popWitnessResult = LraPopWitness.getInstance(b);
           
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/ModCertTemplateTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/ModCertTemplateTest.java
          index 3706368562..4bd5017748 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/ModCertTemplateTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/ModCertTemplateTest.java
          @@ -33,7 +33,7 @@ public void performTest()
                   BodyPartPath pkiDataReference = new BodyPartPath(new BodyPartID(10L));
                   BodyPartList certReferences = new BodyPartList(new BodyPartID(12L));
                   boolean replace = false;
          -        CertTemplate certTemplate = CertTemplate.getInstance(new DLSequence(new DERTaggedObject(false, 1, new ASN1Integer(34L))));
          +        CertTemplate certTemplate = CertTemplate.getInstance(new DLSequence(new DERTaggedObject(false, 1, ASN1Integer.valueOf(34))));
                   {
                       ModCertTemplate modCertTemplate = new ModCertTemplate(
                           pkiDataReference,
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/OtherStatusInfoTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/OtherStatusInfoTest.java
          index 3e4640413b..1a8bbc3108 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/OtherStatusInfoTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/OtherStatusInfoTest.java
          @@ -54,7 +54,7 @@ public void performTest()
           
                   {
                       OtherStatusInfo ose = OtherStatusInfo.getInstance(
          -                new ExtendedFailInfo(PKCSObjectIdentifiers.canNotDecryptAny, new ASN1Integer(10L)));
          +                new ExtendedFailInfo(PKCSObjectIdentifiers.canNotDecryptAny, ASN1Integer.valueOf(10)));
                       byte[] b = ose.getEncoded();
                       OtherStatusInfo oseResult = OtherStatusInfo.getInstance(b);
           
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/PKIDataTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/PKIDataTest.java
          index f987a0eae0..f16135f3df 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/PKIDataTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/PKIDataTest.java
          @@ -46,8 +46,8 @@ public void performTest()
                   PKIData pkiData = new PKIData(
                       new TaggedAttribute[]{new TaggedAttribute(new BodyPartID(10L), PKCSObjectIdentifiers.id_aa, new DERSet())},
                       new TaggedRequest[]{new TaggedRequest(new TaggedCertificationRequest(new BodyPartID(10L), CertificationRequest.getInstance(req1)))},
          -            new TaggedContentInfo[]{new TaggedContentInfo(new BodyPartID(10L), new ContentInfo(PKCSObjectIdentifiers.id_aa_ets_commitmentType, new ASN1Integer(10L)))},
          -            new OtherMsg[]{new OtherMsg(new BodyPartID(10L), PKCSObjectIdentifiers.pkcs_9, new ASN1Integer(10L))});
          +            new TaggedContentInfo[]{new TaggedContentInfo(new BodyPartID(10L), new ContentInfo(PKCSObjectIdentifiers.id_aa_ets_commitmentType, ASN1Integer.valueOf(10)))},
          +            new OtherMsg[]{new OtherMsg(new BodyPartID(10L), PKCSObjectIdentifiers.pkcs_9, ASN1Integer.valueOf(10))});
           
           
                   byte[] b = pkiData.getEncoded();
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/PKIResponseTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/PKIResponseTest.java
          index 17d3064a28..58f1b15a72 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/PKIResponseTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/PKIResponseTest.java
          @@ -33,7 +33,7 @@ public void performTest()
               {
                   PKIResponse pkiResponse = PKIResponse.getInstance(new DERSequence(new ASN1Encodable[]{
                       new DERSequence(new TaggedAttribute(new BodyPartID(10L), PKCSObjectIdentifiers.bagtypes, new DERSet())),
          -            new DERSequence(new TaggedContentInfo(new BodyPartID(12L), new ContentInfo(PKCSObjectIdentifiers.id_aa, new ASN1Integer(10L)))),
          +            new DERSequence(new TaggedContentInfo(new BodyPartID(12L), new ContentInfo(PKCSObjectIdentifiers.id_aa, ASN1Integer.valueOf(10)))),
                       new DERSequence(new OtherMsg(new BodyPartID(12), PKCSObjectIdentifiers.id_aa_msgSigDigest, new DERUTF8String("foo")))
                   }));
           
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/PopLinkWitnessV2Test.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/PopLinkWitnessV2Test.java
          index aaa16765d6..e136d7fbc9 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/PopLinkWitnessV2Test.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/PopLinkWitnessV2Test.java
          @@ -26,8 +26,8 @@ public void performTest()
               {
                   // Object identifiers real but not correct in this context.
                   PopLinkWitnessV2 popLinkWitnessV2 = new PopLinkWitnessV2(
          -            new AlgorithmIdentifier(PKCSObjectIdentifiers.bagtypes, new ASN1Integer(10L)),
          -            new AlgorithmIdentifier(PKCSObjectIdentifiers.crlTypes, new ASN1Integer(12L)),
          +            new AlgorithmIdentifier(PKCSObjectIdentifiers.bagtypes, ASN1Integer.valueOf(10)),
          +            new AlgorithmIdentifier(PKCSObjectIdentifiers.crlTypes, ASN1Integer.valueOf(12)),
                       "cats".getBytes()
                   );
           
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/PublishTrustAnchorsTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/PublishTrustAnchorsTest.java
          index 0f7fe4557e..fad4ee9b05 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/PublishTrustAnchorsTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/PublishTrustAnchorsTest.java
          @@ -27,8 +27,9 @@ public void performTest()
                   throws Exception
               {
                   PublishTrustAnchors publishTrustAnchors = new PublishTrustAnchors(
          -            new BigInteger("10"), new AlgorithmIdentifier(PKCSObjectIdentifiers.crlTypes,
          -            new ASN1Integer(5L)), new byte[][]{"cats".getBytes()});
          +            BigInteger.valueOf(10),
          +            new AlgorithmIdentifier(PKCSObjectIdentifiers.crlTypes, ASN1Integer.FIVE),
          +            new byte[][]{"cats".getBytes()});
           
                   byte[] b = publishTrustAnchors.getEncoded();
           
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/RevokeRequestTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/RevokeRequestTest.java
          index 3d4baefa57..bf5596a308 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/RevokeRequestTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/RevokeRequestTest.java
          @@ -63,7 +63,7 @@ public void performTest()
           
                       RevokeRequest rr = new RevokeRequest(
                           name,
          -                new ASN1Integer(12L),
          +                ASN1Integer.valueOf(12),
                           CRLReason.getInstance(new ASN1Enumerated(CRLReason.certificateHold)),
                           invalidityDate,
                           passphrase,
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/TaggedAttributeTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/TaggedAttributeTest.java
          index f400bd4da6..edb02fef8e 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/TaggedAttributeTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/TaggedAttributeTest.java
          @@ -48,7 +48,7 @@ public void performTest()
                   //
                   try
                   {
          -            ASN1Sequence seq = new DERSequence(new ASN1Encodable[] { new BodyPartID(10) });
          +            ASN1Sequence seq = new DERSequence(new BodyPartID(10));
           
                       TaggedAttribute.getInstance(seq);
                       fail("no exception");
          @@ -63,7 +63,8 @@ public void performTest()
                   //
                   try
                   {
          -            ASN1Sequence seq = new DERSequence(new ASN1Encodable[] { ta.getBodyPartID(), ta.getAttrType(), ta.getAttrValues(), new ASN1Integer(0)});
          +            ASN1Sequence seq = new DERSequence(new ASN1Encodable[]{
          +                ta.getBodyPartID(), ta.getAttrType(), ta.getAttrValues(), ASN1Integer.ZERO });
           
                       TaggedAttribute.getInstance(seq);
                       fail("no exception");
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cmc/test/TaggedRequestTest.java b/util/src/test/java/org/bouncycastle/asn1/cmc/test/TaggedRequestTest.java
          index e98113c724..7ea48482cf 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cmc/test/TaggedRequestTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cmc/test/TaggedRequestTest.java
          @@ -67,12 +67,11 @@ public void performTest()
           
                       POPOSigningKeyInput pski = new POPOSigningKeyInput(
                           new GeneralName(GeneralName.rfc822Name, "fish"),
          -                new SubjectPublicKeyInfo(new AlgorithmIdentifier(
          -                    PKCSObjectIdentifiers.certBag,
          -                    new ASN1Integer(5L)), new ASN1Integer(4L)
          -                ));
          +                new SubjectPublicKeyInfo(
          +                    new AlgorithmIdentifier(PKCSObjectIdentifiers.certBag, ASN1Integer.FIVE),
          +                    ASN1Integer.FOUR));
           
          -            AlgorithmIdentifier aid = new AlgorithmIdentifier(PKCSObjectIdentifiers.crlTypes, new ASN1Integer(1L));
          +            AlgorithmIdentifier aid = new AlgorithmIdentifier(PKCSObjectIdentifiers.crlTypes, ASN1Integer.ONE);
                       DERBitString dbi = new DERBitString(2);
           
                       POPOSigningKey popoSigningKey = new POPOSigningKey(pski, aid, dbi);
          @@ -80,12 +79,11 @@ public void performTest()
           
                       TaggedRequest tr = new TaggedRequest(
                           new CertReqMsg(new CertRequest(
          -                    new ASN1Integer(1L),
          -                    CertTemplate.getInstance(new DERSequence(new DERTaggedObject(false, 0, new ASN1Integer(3L)))),
          -                    new Controls(new AttributeTypeAndValue(PKCSObjectIdentifiers.pkcs_9,new ASN1Integer(3)))),
          +                    ASN1Integer.ONE,
          +                    CertTemplate.getInstance(new DERSequence(new DERTaggedObject(false, 0, ASN1Integer.THREE))),
          +                    new Controls(new AttributeTypeAndValue(PKCSObjectIdentifiers.pkcs_9, ASN1Integer.THREE))),
                               proofOfPossession,
          -                    new AttributeTypeAndValue[0])
          -            );
          +                    new AttributeTypeAndValue[0]));
                       byte[] b = tr.getEncoded();
                       TaggedRequest trResult = TaggedRequest.getInstance(b);
                       isEquals("Tag", tr.getTagNo(), trResult.getTagNo());
          @@ -95,11 +93,8 @@ public void performTest()
           
           
                   { // ORM
          -            TaggedRequest tr = TaggedRequest.getInstance( new DERTaggedObject(false, TaggedRequest.ORM, new DERSequence(new ASN1Encodable[]{
          -                new BodyPartID(1L),
          -                PKCSObjectIdentifiers.data,
          -                new DERSet(new ASN1Encodable[]{new ASN1Integer(5L)})
          -            })));
          +            TaggedRequest tr = TaggedRequest.getInstance(new DERTaggedObject(false, TaggedRequest.ORM,
          +                new DERSequence(new ASN1Encodable[]{new BodyPartID(1L), PKCSObjectIdentifiers.data, new DERSet(ASN1Integer.FIVE)})));
                       byte[] b = tr.getEncoded();
                       TaggedRequest trResult = TaggedRequest.getInstance(b);
                       isEquals("Tag", tr.getTagNo(), trResult.getTagNo());
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cms/test/KEMRecipientInfoTest.java b/util/src/test/java/org/bouncycastle/asn1/cms/test/KEMRecipientInfoTest.java
          index acb796978b..ab8feb2359 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cms/test/KEMRecipientInfoTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cms/test/KEMRecipientInfoTest.java
          @@ -28,7 +28,7 @@ public void testOutOfRange()
                           new AlgorithmIdentifier(NISTObjectIdentifiers.id_alg_ml_kem_512),
                           new DEROctetString(new byte[0]),
                           new AlgorithmIdentifier(X9ObjectIdentifiers.id_kdf_kdf3),
          -                new ASN1Integer(700000), new DEROctetString(new byte[0]),
          +                ASN1Integer.valueOf(700000), new DEROctetString(new byte[0]),
                           new AlgorithmIdentifier(NISTObjectIdentifiers.id_aes256_wrap_pad),
                           new DEROctetString(new byte[0]));
                       fail("no exception");
          @@ -59,7 +59,7 @@ public void testNullWrap()
                           new AlgorithmIdentifier(NISTObjectIdentifiers.id_alg_ml_kem_512),
                           new DEROctetString(new byte[0]),
                           new AlgorithmIdentifier(X9ObjectIdentifiers.id_kdf_kdf3),
          -                new ASN1Integer(7000), new DEROctetString(new byte[0]),
          +                ASN1Integer.valueOf(7000), new DEROctetString(new byte[0]),
                           null,
                           new DEROctetString(new byte[0]));
                       fail("no exception");
          @@ -80,7 +80,7 @@ public void testNullKem()
                           null,
                           new DEROctetString(new byte[0]),
                           new AlgorithmIdentifier(X9ObjectIdentifiers.id_kdf_kdf3),
          -                new ASN1Integer(7000), new DEROctetString(new byte[0]),
          +                ASN1Integer.valueOf(7000), new DEROctetString(new byte[0]),
                           new AlgorithmIdentifier(NISTObjectIdentifiers.id_aes256_wrap_pad),
                           new DEROctetString(new byte[0]));
                       fail("no exception");
          @@ -109,7 +109,7 @@ public void testSequenceSize()
                       ASN1Encodable[] elements = new ASN1Encodable[10];
                       for (int i = 0; i != elements.length; i++)
                       {
          -                elements[i] = new ASN1Integer(1);
          +                elements[i] = ASN1Integer.ONE;
                       }
                       KEMRecipientInfo.getInstance(new DERSequence(elements));
                       fail("no exception");
          diff --git a/util/src/test/java/org/bouncycastle/asn1/cms/test/OctetStringTest.java b/util/src/test/java/org/bouncycastle/asn1/cms/test/OctetStringTest.java
          index bb5daf1ace..3fd472d265 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/cms/test/OctetStringTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/cms/test/OctetStringTest.java
          @@ -156,12 +156,12 @@ public void testNestedStructure()
                   ByteArrayOutputStream bOut = new ByteArrayOutputStream();
                   
                   BERSequenceGenerator sGen = new BERSequenceGenerator(bOut);
          -        
          -        sGen.addObject(new ASN1ObjectIdentifier(CMSObjectIdentifiers.compressedData.getId()));
          -        
          +
          +        sGen.addObject(CMSObjectIdentifiers.compressedData);
          +
                   BERSequenceGenerator cGen = new BERSequenceGenerator(sGen.getRawOutputStream(), 0, true);
                   
          -        cGen.addObject(new ASN1Integer(0));
          +        cGen.addObject(ASN1Integer.ZERO);
                   
                   //
                   // AlgorithmIdentifier
          diff --git a/util/src/test/java/org/bouncycastle/asn1/ess/test/OtherCertIDUnitTest.java b/util/src/test/java/org/bouncycastle/asn1/ess/test/OtherCertIDUnitTest.java
          index 467bfac382..450d6ab8cb 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/ess/test/OtherCertIDUnitTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/ess/test/OtherCertIDUnitTest.java
          @@ -27,7 +27,7 @@ public void performTest()
               {
                   AlgorithmIdentifier algId = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.2.3"));
                   byte[]              digest = new byte[20];
          -        IssuerSerial        issuerSerial = new IssuerSerial(new GeneralNames(new GeneralName(new X500Name("CN=test"))), new ASN1Integer(1));
          +        IssuerSerial        issuerSerial = new IssuerSerial(new GeneralNames(new GeneralName(new X500Name("CN=test"))), ASN1Integer.ONE);
           
                   OtherCertID certID = new OtherCertID(algId, digest);
           
          diff --git a/util/src/test/java/org/bouncycastle/asn1/isismtt/test/ProcurationSyntaxUnitTest.java b/util/src/test/java/org/bouncycastle/asn1/isismtt/test/ProcurationSyntaxUnitTest.java
          index e3eeddceb7..bd57b2c116 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/isismtt/test/ProcurationSyntaxUnitTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/isismtt/test/ProcurationSyntaxUnitTest.java
          @@ -27,7 +27,7 @@ public void performTest()
                   String country = "AU";
                   DirectoryString  typeOfSubstitution = new DirectoryString("substitution");
                   GeneralName thirdPerson = new GeneralName(new X500Name("CN=thirdPerson"));
          -        IssuerSerial certRef = new IssuerSerial(new GeneralNames(new GeneralName(new X500Name("CN=test"))), new ASN1Integer(1));
          +        IssuerSerial certRef = new IssuerSerial(new GeneralNames(new GeneralName(new X500Name("CN=test"))), ASN1Integer.ONE);
           
                   ProcurationSyntax procuration = new ProcurationSyntax(country, typeOfSubstitution, thirdPerson);
           
          diff --git a/util/src/test/java/org/bouncycastle/asn1/misc/test/CMPUpdates16Test.java b/util/src/test/java/org/bouncycastle/asn1/misc/test/CMPUpdates16Test.java
          index 4e760e1792..7e1ebafeb0 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/misc/test/CMPUpdates16Test.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/misc/test/CMPUpdates16Test.java
          @@ -61,7 +61,7 @@ public void testCRLSource()
                   }
                   catch (IllegalArgumentException ilex)
                   {
          -            assertEquals("unknown tag 3", ilex.getMessage());
          +            assertEquals("unknown tag [CONTEXT 3]", ilex.getMessage());
                   }
           
                   // Check that both values are not set at construction
          diff --git a/util/src/test/java/org/bouncycastle/asn1/misc/test/GetInstanceTest.java b/util/src/test/java/org/bouncycastle/asn1/misc/test/GetInstanceTest.java
          index d13cc6cd4f..e14e670752 100644
          --- a/util/src/test/java/org/bouncycastle/asn1/misc/test/GetInstanceTest.java
          +++ b/util/src/test/java/org/bouncycastle/asn1/misc/test/GetInstanceTest.java
          @@ -492,7 +492,7 @@ public void testGetInstance()
                   doFullGetInstanceTest(DERT61String.class, new DERT61String("hello world"));
                   doFullGetInstanceTest(DERVisibleString.class, new DERVisibleString("hello world"));
           
          -        doFullGetInstanceTest(ASN1Integer.class, new ASN1Integer(1));
          +        doFullGetInstanceTest(ASN1Integer.class, ASN1Integer.ONE);
                   doFullGetInstanceTest(ASN1GeneralizedTime.class, new ASN1GeneralizedTime(new Date()));
                   doFullGetInstanceTest(ASN1UTCTime.class, new ASN1UTCTime(new Date()));
                   doFullGetInstanceTest(ASN1Enumerated.class, new ASN1Enumerated(1));
          @@ -507,13 +507,13 @@ public void testGetInstance()
                   CertifiedKeyPair.getInstance(null);
                   CertOrEncCert.getInstance(null);
                   CertRepMessage.getInstance(null);
          -        doFullGetInstanceTest(CertResponse.class, new CertResponse(new ASN1Integer(1), new PKIStatusInfo(PKIStatus.granted)));
          +        doFullGetInstanceTest(CertResponse.class, new CertResponse(ASN1Integer.ONE, new PKIStatusInfo(PKIStatus.granted)));
                   doFullGetInstanceTest(org.bouncycastle.asn1.cmp.CertStatus.class, new org.bouncycastle.asn1.cmp.CertStatus(new byte[10], BigInteger.valueOf(1), new PKIStatusInfo(PKIStatus.granted), new AlgorithmIdentifier(new ASN1ObjectIdentifier("0.0"))));
                   doFullGetInstanceTest(Challenge.class, new Challenge(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE), new byte[10], new byte[10]));
           
                   doFullGetInstanceTest(CMPCertificate.class, cmpCert);
                   doFullGetInstanceTest(CRLAnnContent.class, new CRLAnnContent(crl));
          -        doFullGetInstanceTest(ErrorMsgContent.class, new ErrorMsgContent(new PKIStatusInfo(PKIStatus.granted), new ASN1Integer(1), new PKIFreeText("fred")));
          +        doFullGetInstanceTest(ErrorMsgContent.class, new ErrorMsgContent(new PKIStatusInfo(PKIStatus.granted), ASN1Integer.ONE, new PKIFreeText("fred")));
                   GenMsgContent.getInstance(null);
                   GenRepContent.getInstance(null);
                   InfoTypeAndValue.getInstance(null);
          @@ -695,7 +695,7 @@ public void testGetInstance()
                   BasicOCSPResponse.getInstance(null);
                   BasicOCSPResponse.getInstance(null);
           
          -        doFullGetInstanceTest(CertID.class, new CertID(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE), new DEROctetString(new byte[1]), new DEROctetString(new byte[1]), new ASN1Integer(1)));
          +        doFullGetInstanceTest(CertID.class, new CertID(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE), new DEROctetString(new byte[1]), new DEROctetString(new byte[1]), ASN1Integer.ONE));
           
                   CertStatus.getInstance(null);
                   CertStatus.getInstance(null);
          @@ -895,14 +895,11 @@ public void testGetInstance()
                   PersonalData.getInstance(null);
           
                   doFullGetInstanceTest(CertReqTemplateContent.class, new DERSequence(
          -            new ASN1Encodable[]{
          -                CertTemplate.getInstance(new DLSequence(new DERTaggedObject(false, 1, new ASN1Integer(34L)))),
          -                new DERSequence(new ASN1Encodable[]{new AttributeTypeAndValue(CMPObjectIdentifiers.id_regCtrl_algId, new DERUTF8String("test"))})
          -            }));
          +            CertTemplate.getInstance(new DLSequence(new DERTaggedObject(false, 1, ASN1Integer.valueOf(34)))),
          +            new DERSequence(new AttributeTypeAndValue(CMPObjectIdentifiers.id_regCtrl_algId, new DERUTF8String("test")))));
           
                   doFullGetInstanceTest(CertReqTemplateContent.class, new DERSequence(
          -            new ASN1Encodable[]{
          -                CertTemplate.getInstance(new DLSequence(new DERTaggedObject(false, 1, new ASN1Integer(34L))))}));
          +            CertTemplate.getInstance(new DLSequence(new DERTaggedObject(false, 1, ASN1Integer.valueOf(34))))));
           
                   doFullGetInstanceTest(CRLSource.class,
                       new DERTaggedObject(true, 0, new DistributionPointName(new GeneralNames(new GeneralName(GeneralName.dNSName, new DERIA5String("cats"))))));
          diff --git a/util/src/test/java/org/bouncycastle/oer/test/ExtensionTest.java b/util/src/test/java/org/bouncycastle/oer/test/ExtensionTest.java
          index 319e9c06ca..0ca3c9f62a 100644
          --- a/util/src/test/java/org/bouncycastle/oer/test/ExtensionTest.java
          +++ b/util/src/test/java/org/bouncycastle/oer/test/ExtensionTest.java
          @@ -39,7 +39,7 @@ public void performTest()
               private void exerciseEtsiTs102941DeltaCtlRequestId()
                   throws Exception
               {
          -        ASN1Integer ctlSequence = new ASN1Integer(10);
          +        ASN1Integer ctlSequence = ASN1Integer.valueOf(10);
           
                   Extension extension = new Extension(
                       Extension.etsiTs102941DeltaCtlRequestId,
          diff --git a/util/src/test/java/org/bouncycastle/oer/test/OERExpander.java b/util/src/test/java/org/bouncycastle/oer/test/OERExpander.java
          index 94cc3ded37..7f560a0ade 100644
          --- a/util/src/test/java/org/bouncycastle/oer/test/OERExpander.java
          +++ b/util/src/test/java/org/bouncycastle/oer/test/OERExpander.java
          @@ -687,7 +687,7 @@ public IntPopulate(Element def)
           
                           if (def.getLowerBound() == null && def.getUpperBound() == null)
                           {
          -                    script.add(new ASN1Integer(10)); // Unbounded so pick a value.
          +                    script.add(ASN1Integer.valueOf(10)); // Unbounded so pick a value.
                           }
                       }
           
          diff --git a/util/src/test/java/org/bouncycastle/oer/test/OERExtensionTest.java b/util/src/test/java/org/bouncycastle/oer/test/OERExtensionTest.java
          index ed40328bfa..9dff8c97b0 100644
          --- a/util/src/test/java/org/bouncycastle/oer/test/OERExtensionTest.java
          +++ b/util/src/test/java/org/bouncycastle/oer/test/OERExtensionTest.java
          @@ -36,7 +36,7 @@ public void testWithoutExtensionValue()
                   Element ele = defBuilder.build();
           
                   // Only has the non extension part populated
          -        ASN1Encodable withOutExtension = new DERSequence(new ASN1Encodable[]{new ASN1Integer(1)});
          +        ASN1Encodable withOutExtension = new DERSequence(ASN1Integer.ONE);
           
                   byte[] raw = OEREncoder.toByteArray(withOutExtension, ele);
                   TestCase.assertTrue((raw[0] & 0x80) == 0); // Extension present bit must be zero
          @@ -53,7 +53,7 @@ public void testWithOneExtensionValue()
                   Element ele = defBuilder.build();
                   {
                       // Only has the non extension part populated
          -            ASN1Encodable withOutExtension = new DERSequence(new ASN1Encodable[]{new ASN1Integer(1), new DERUTF8String("cats")});
          +            ASN1Encodable withOutExtension = new DERSequence(ASN1Integer.ONE, new DERUTF8String("cats"));
           
                       byte[] raw = OEREncoder.toByteArray(withOutExtension, ele);
                       TestCase.assertTrue((raw[0] & 0x80) != 0); // Extension present bit must be zero
          @@ -66,7 +66,7 @@ public void testWithOneExtensionValue()
                   //
           
                   {
          -            ASN1Encodable withOutExtension = new DERSequence(new ASN1Encodable[]{new ASN1Integer(1), OEROptional.ABSENT, new ASN1Integer(10)});
          +            ASN1Encodable withOutExtension = new DERSequence(new ASN1Encodable[]{ASN1Integer.ONE, OEROptional.ABSENT, ASN1Integer.valueOf(10)});
           
                       byte[] raw = OEREncoder.toByteArray(withOutExtension, ele);
                       TestCase.assertTrue((raw[0] & 0x80) != 0); // Extension present bit must be zero
          @@ -115,14 +115,13 @@ public void testSequenceWithUndefinedExtensions()
                   Element writeElement = writeBuilder.build();
           
           
          -        ASN1Encodable enc = new DERSequence(new ASN1Encodable[]{
          +        ASN1Encodable enc = new DERSequence(
                       new DERSequence(new ASN1Encodable[]{
                           new DERUTF8String("cats"),
                           OEROptional.ABSENT, // this and the one below are actually extension values.
                           new DERUTF8String("other")
                       }),
          -            new ASN1Integer(10)
          -        });
          +            ASN1Integer.valueOf(10));
           
                   byte[] value = OEREncoder.toByteArray(enc, writeElement);